From patchwork Sat May 6 11:43:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wan Junjie X-Patchwork-Id: 1777979 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=bytedance.com header.i=@bytedance.com header.a=rsa-sha256 header.s=google header.b=LKrRaDev; dkim-atps=neutral Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QD5Kl0m0Jz20fl for ; Sat, 6 May 2023 21:43:37 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id E1E9780F0F; Sat, 6 May 2023 11:43:33 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org E1E9780F0F Authentication-Results: smtp1.osuosl.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.a=rsa-sha256 header.s=google header.b=LKrRaDev X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id oDFu2PEFXOBf; Sat, 6 May 2023 11:43:32 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 0C58080DB6; Sat, 6 May 2023 11:43:30 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 0C58080DB6 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BA244C0037; Sat, 6 May 2023 11:43:30 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 70D02C002A for ; Sat, 6 May 2023 11:43:28 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 3795C60784 for ; Sat, 6 May 2023 11:43:28 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 3795C60784 Authentication-Results: smtp3.osuosl.org; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.a=rsa-sha256 header.s=google header.b=LKrRaDev X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FAjb3Vho1peK for ; Sat, 6 May 2023 11:43:26 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 1C737605E8 Received: from mail-pl1-x629.google.com (mail-pl1-x629.google.com [IPv6:2607:f8b0:4864:20::629]) by smtp3.osuosl.org (Postfix) with ESMTPS id 1C737605E8 for ; Sat, 6 May 2023 11:43:25 +0000 (UTC) Received: by mail-pl1-x629.google.com with SMTP id d9443c01a7336-1aaf0bc8a07so5408905ad.0 for ; Sat, 06 May 2023 04:43:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1683373405; x=1685965405; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4uqldoq7slNAyt86ATeW8DTzj9ignRAgcN8+Brli2sw=; b=LKrRaDevlSIMMaXZIjDZicElHKhKTqptZrCDyQqCAaUJuP8xAMd7AuBxR8am6htOxA 7RDhDRcJ5rhk15+eNzC3+EQFEZKDoPKYw5HlTkkEPntStVyHbwf32/ehl4myKi0kMGpR TP2Dc3LRMIq+GZ8mghx3evSmTziDgU94rH5cGDxM7BV8xjNDRuzeY+TUmCoBO02JtWou yHzbloyJZf/Js+IyDmxWvheSQsKSalhTb+gsDykmMWVx1sKwTs+q4aIgvjYTOtqa3Sk6 NdmqrMlj94buDF4SXNK0z1P88q57e8kGCIluXPMyls9ikXVi2Tog68WES0qAJwxktXDc s+Ng== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683373405; x=1685965405; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4uqldoq7slNAyt86ATeW8DTzj9ignRAgcN8+Brli2sw=; b=IXEp1GJ+MGhxaHzEYYsEeoVnwlWWM8iNgzcYzeu/e4WH9jB2wfPQmTT66rc6tvoCcX nI+u8kklBizF3SWBotMBsq1sZs/42NURxChCCKJFoHASMgQHmm3jkNzjNrcHSHL1G2oY Q+pz/z1DR2w6jXxAE8KPzsKso69rRuFIa45YElJoTXiS8Tzw0Q6wB9/tEDiVuMlc1xkt Er53I46jpmju3FNa0hdeY1rYfzdQETP9Z9iQ139pit+4Wn6l351wMM6hxr015vXtE3ss SdjB3ovSiWdotUbfXs/70WEvxH0ohFkL/KN2qoT5ec4c5cyi2CsMF4ZhJxoKlSNcv04u 6pXw== X-Gm-Message-State: AC+VfDxLQocE+Vuam+P2yI4z0h7cUssAOZfMn3qiA1E8D9ERR5+FOp63 VrYmxuuvxSWQr0lk0LtN1LEeJefFkLf6yP1YjhNpqg== X-Google-Smtp-Source: ACHHUZ6a6SO0Je0oUiv86RBZTsreBp0rswCn6jgtTbLc3ggiJOW30yvo39prt8BTvfWaTB0/GQ8tzg== X-Received: by 2002:a17:903:2284:b0:1a9:4b42:a5a2 with SMTP id b4-20020a170903228400b001a94b42a5a2mr5269541plh.0.1683373404535; Sat, 06 May 2023 04:43:24 -0700 (PDT) Received: from C02Z10J4LVCK.bytedance.net ([139.177.225.246]) by smtp.gmail.com with ESMTPSA id d5-20020a170902854500b001ab2b415cadsm3408692plo.84.2023.05.06.04.43.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 06 May 2023 04:43:23 -0700 (PDT) To: dev@openvswitch.org Date: Sat, 6 May 2023 19:43:18 +0800 Message-Id: <20230506114318.755-1-wanjunjie@bytedance.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230411132543.45719-1-wanjunjie@bytedance.com> References: <20230411132543.45719-1-wanjunjie@bytedance.com> MIME-Version: 1.0 Cc: simon.horman@corigine.com, i.maximets@ovn.org Subject: [ovs-dev] [PATCH v11] utilities/ofctl: add-meters for save and restore X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Wan Junjie via dev From: Wan Junjie Reply-To: Wan Junjie Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" put dump-meters' result in one line so add-meters can handle. save and restore meters when restart ovs. bundle functions are not implemented in this patch. Signed-off-by: Wan Junjie --- v11: add OFP_ prefix to macro add testcases for meters v10: merge oneline to verbosity in parse_options ofp_to_string__ handle verbosity bits right v9: fix verbosity mask bits for testcase apologies for mess v8: fix missing code for testcase v7: typo in code v6: code style v5: merge oneline to verbosity higher bits remove duplicate dump_meters code v4: code refactor according to comments v3: add '--oneline' option for dump-meter(s) command v2: fix failed testcases, as dump-meters format changes --- include/openvswitch/ofp-meter.h | 9 +- include/openvswitch/ofp-print.h | 10 +++ lib/ofp-meter.c | 100 ++++++++++++++++++++++- lib/ofp-print.c | 20 +++-- tests/dpif-netdev.at | 44 ++++++++-- tests/ovs-ofctl.at | 70 ++++++++++++++++ utilities/ovs-ofctl.8.in | 25 +++++- utilities/ovs-ofctl.c | 140 ++++++++++++++++++++++++-------- utilities/ovs-save | 8 ++ 9 files changed, 374 insertions(+), 52 deletions(-) diff --git a/include/openvswitch/ofp-meter.h b/include/openvswitch/ofp-meter.h index 6776eae87..a8ee2d61d 100644 --- a/include/openvswitch/ofp-meter.h +++ b/include/openvswitch/ofp-meter.h @@ -17,6 +17,7 @@ #ifndef OPENVSWITCH_OFP_METER_H #define OPENVSWITCH_OFP_METER_H 1 +#include #include "openflow/openflow.h" #include "openvswitch/ofp-protocol.h" @@ -61,7 +62,8 @@ int ofputil_decode_meter_config(struct ofpbuf *, struct ofputil_meter_config *, struct ofpbuf *bands); void ofputil_format_meter_config(struct ds *, - const struct ofputil_meter_config *); + const struct ofputil_meter_config *, + bool oneline); struct ofputil_meter_mod { uint16_t command; @@ -79,6 +81,11 @@ char *parse_ofp_meter_mod_str(struct ofputil_meter_mod *, const char *string, OVS_WARN_UNUSED_RESULT; void ofputil_format_meter_mod(struct ds *, const struct ofputil_meter_mod *); +char *parse_ofp_meter_mod_file(const char *file_name, int command, + struct ofputil_meter_mod **mms, size_t *n_mms, + enum ofputil_protocol *usable_protocols) + OVS_WARN_UNUSED_RESULT; + struct ofputil_meter_stats { uint32_t meter_id; uint32_t flow_count; diff --git a/include/openvswitch/ofp-print.h b/include/openvswitch/ofp-print.h index d76f06872..fbaac2bea 100644 --- a/include/openvswitch/ofp-print.h +++ b/include/openvswitch/ofp-print.h @@ -38,6 +38,16 @@ struct dp_packet; extern "C" { #endif +/* manipulate higher bits in verbosity for other usage */ +#define OFP_ONELINE_BIT 7 +#define OFP_ONELINE_MASK (1 << OFP_ONELINE_BIT) +#define OFP_VERBOSITY_MASK (~OFP_ONELINE_MASK) + +#define OFP_VERBOSITY(verbosity) (verbosity & OFP_VERBOSITY_MASK) + +#define OFP_ONELINE_SET(verbosity) (verbosity | OFP_ONELINE_MASK) +#define OFP_ONELINE_GET(verbosity) (verbosity & OFP_ONELINE_MASK) + void ofp_print(FILE *, const void *, size_t, const struct ofputil_port_map *, const struct ofputil_table_map *, int verbosity); void ofp_print_packet(FILE *stream, const void *data, diff --git a/lib/ofp-meter.c b/lib/ofp-meter.c index 9ea40a0bf..6d760620d 100644 --- a/lib/ofp-meter.c +++ b/lib/ofp-meter.c @@ -15,6 +15,7 @@ */ #include +#include #include "openvswitch/ofp-meter.h" #include "byte-order.h" #include "nx-match.h" @@ -57,7 +58,7 @@ void ofputil_format_meter_band(struct ds *s, enum ofp13_meter_flags flags, const struct ofputil_meter_band *mb) { - ds_put_cstr(s, "\ntype="); + ds_put_cstr(s, "type="); switch (mb->type) { case OFPMBT13_DROP: ds_put_cstr(s, "drop"); @@ -343,7 +344,8 @@ ofp_print_meter_flags(struct ds *s, enum ofp13_meter_flags flags) void ofputil_format_meter_config(struct ds *s, - const struct ofputil_meter_config *mc) + const struct ofputil_meter_config *mc, + bool oneline) { uint16_t i; @@ -354,6 +356,7 @@ ofputil_format_meter_config(struct ds *s, ds_put_cstr(s, "bands="); for (i = 0; i < mc->n_bands; ++i) { + ds_put_cstr(s, oneline ? " ": "\n"); ofputil_format_meter_band(s, mc->flags, &mc->bands[i]); } ds_put_char(s, '\n'); @@ -578,6 +581,24 @@ parse_ofp_meter_mod_str__(struct ofputil_meter_mod *mm, char *string, /* Meters require at least OF 1.3. */ *usable_protocols = OFPUTIL_P_OF13_UP; + if (command == -2) { + size_t len; + + string += strspn(string, " \t\r\n"); /* Skip white space. */ + len = strcspn(string, ", \t\r\n"); /* Get length of the first token. */ + + if (!strncmp(string, "add", len)) { + command = OFPMC13_ADD; + } else if (!strncmp(string, "delete", len)) { + command = OFPMC13_DELETE; + } else if (!strncmp(string, "modify", len)) { + command = OFPMC13_MODIFY; + } else { + len = 0; + command = OFPMC13_ADD; + } + string += len; + } switch (command) { case -1: @@ -606,6 +627,11 @@ parse_ofp_meter_mod_str__(struct ofputil_meter_mod *mm, char *string, mm->meter.n_bands = 0; mm->meter.bands = NULL; + if (command == OFPMC13_DELETE && string[0] == '\0') { + mm->meter.meter_id = OFPM13_ALL; + return NULL; + } + if (fields & F_BANDS) { band_str = strstr(string, "band"); if (!band_str) { @@ -805,5 +831,73 @@ ofputil_format_meter_mod(struct ds *s, const struct ofputil_meter_mod *mm) ds_put_format(s, " cmd:%d ", mm->command); } - ofputil_format_meter_config(s, &mm->meter); + ofputil_format_meter_config(s, &mm->meter, false); +} + +/* If 'command' is given as -2, each line may start with a command name ("add", + * "modify", "delete"). A missing command name is treated as "add". + */ +char * OVS_WARN_UNUSED_RESULT +parse_ofp_meter_mod_file(const char *file_name, + int command, + struct ofputil_meter_mod **mms, size_t *n_mms, + enum ofputil_protocol *usable_protocols) +{ + size_t allocated_mms; + int line_number; + FILE *stream; + struct ds s; + + *mms = NULL; + *n_mms = 0; + + stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r"); + if (stream == NULL) { + return xasprintf("%s: open failed (%s)", + file_name, ovs_strerror(errno)); + } + + allocated_mms = *n_mms; + ds_init(&s); + line_number = 0; + *usable_protocols = OFPUTIL_P_ANY; + while (!ds_get_preprocessed_line(&s, stream, &line_number)) { + enum ofputil_protocol usable; + char *error; + + if (*n_mms >= allocated_mms) { + *mms = x2nrealloc(*mms, &allocated_mms, sizeof **mms); + } + error = parse_ofp_meter_mod_str(&(*mms)[*n_mms], ds_cstr(&s), command, + &usable); + if (error) { + size_t i; + + for (i = 0; i < *n_mms; i++) { + if (mms[i]->meter.bands) { + free(mms[i]->meter.bands); + } + } + free(*mms); + *mms = NULL; + *n_mms = 0; + + ds_destroy(&s); + if (stream != stdin) { + fclose(stream); + } + + char *ret = xasprintf("%s:%d: %s", file_name, line_number, error); + free(error); + return ret; + } + *usable_protocols &= usable; + *n_mms += 1; + } + + ds_destroy(&s); + if (stream != stdin) { + fclose(stream); + } + return NULL; } diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 874079b84..4d72748c2 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -54,6 +54,7 @@ #include "openvswitch/ofp-monitor.h" #include "openvswitch/ofp-msgs.h" #include "openvswitch/ofp-port.h" +#include "openvswitch/ofp-print.h" #include "openvswitch/ofp-queue.h" #include "openvswitch/ofp-switch.h" #include "openvswitch/ofp-table.h" @@ -365,12 +366,17 @@ ofp_print_meter_features_reply(struct ds *s, const struct ofp_header *oh) } static enum ofperr -ofp_print_meter_config_reply(struct ds *s, const struct ofp_header *oh) +ofp_print_meter_config_reply(struct ds *s, const struct ofp_header *oh, + bool oneline) { struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); struct ofpbuf bands; int retval; + if (oneline) { + ds_put_char(s, '\n'); + } + ofpbuf_init(&bands, 64); for (;;) { struct ofputil_meter_config mc; @@ -379,8 +385,10 @@ ofp_print_meter_config_reply(struct ds *s, const struct ofp_header *oh) if (retval) { break; } - ds_put_char(s, '\n'); - ofputil_format_meter_config(s, &mc); + if (!oneline) { + ds_put_char(s, '\n'); + } + ofputil_format_meter_config(s, &mc, oneline ? true : false); } ofpbuf_uninit(&bands); @@ -977,6 +985,8 @@ ofp_to_string__(const struct ofp_header *oh, ofp_print_stats(string, oh); } + bool oneline = !!OFP_ONELINE_GET(verbosity); + verbosity = OFP_VERBOSITY(verbosity); const void *msg = oh; enum ofptype type = ofptype_from_ofpraw(raw); switch (type) { @@ -1090,7 +1100,7 @@ ofp_to_string__(const struct ofp_header *oh, return ofp_print_meter_stats_reply(string, oh); case OFPTYPE_METER_CONFIG_STATS_REPLY: - return ofp_print_meter_config_reply(string, oh); + return ofp_print_meter_config_reply(string, oh, oneline); case OFPTYPE_METER_FEATURES_STATS_REPLY: return ofp_print_meter_features_reply(string, oh); @@ -1278,7 +1288,7 @@ ofp_to_string(const void *oh_, size_t len, ofp_print_error(&string, error); } - if (verbosity >= 5 || error) { + if (OFP_VERBOSITY(verbosity) >= 5 || error) { add_newline(&string); ds_put_hex_dump(&string, oh, len, 0, true); } diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at index baab60a22..cbfd02ea6 100644 --- a/tests/dpif-netdev.at +++ b/tests/dpif-netdev.at @@ -283,11 +283,6 @@ AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg]) AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=1 pktps burst stats bands=type=drop rate=1 burst_size=1']) AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=2 kbps burst stats bands=type=drop rate=1 burst_size=2']) -AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=1 action=meter:1,7']) -AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=7 action=meter:2,1']) -AT_CHECK([ovs-ofctl add-flow br1 'in_port=2 action=8']) -AT_CHECK([ovs-ofctl add-flow br1 'in_port=8 action=2']) -ovs-appctl time/stop AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0], [0], [dnl OFPST_METER_CONFIG reply (OF1.3) (xid=0x2): @@ -298,6 +293,45 @@ meter=2 kbps burst stats bands= type=drop rate=1 burst_size=2 ]) +AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0 --oneline], [0], [dnl +OFPST_METER_CONFIG reply (OF1.3) (xid=0x2): +meter=1 pktps burst stats bands= type=drop rate=1 burst_size=1 +meter=2 kbps burst stats bands= type=drop rate=1 burst_size=2 +]) + +AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0 meter=1 --oneline], [0], [dnl +OFPST_METER_CONFIG reply (OF1.3) (xid=0x2): +meter=1 pktps burst stats bands= type=drop rate=1 burst_size=1 +]) + +AT_CHECK([ovs-ofctl del-meters -O openflow13 br0]) +AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0], [0], [dnl +OFPST_METER_CONFIG reply (OF1.3) (xid=0x2): +]) + +AT_DATA([meters.txt], [dnl +meter=1 pktps burst stats bands= type=drop rate=1 burst_size=1 + +meter=2 kbps burst stats bands= type=drop rate=1 burst_size=2 +meter=3 kbps burst stats bands= type=drop rate=2 burst_size=3 +]) + +AT_CHECK([ovs-ofctl add-meters -O openflow13 br0 meters.txt]) +AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0 --oneline], [0], [dnl +OFPST_METER_CONFIG reply (OF1.3) (xid=0x2): +meter=1 pktps burst stats bands= type=drop rate=1 burst_size=1 +meter=2 kbps burst stats bands= type=drop rate=1 burst_size=2 +meter=3 kbps burst stats bands= type=drop rate=2 burst_size=3 +]) + +AT_CHECK([ovs-ofctl del-meters -O openflow13 br0 meter=3]) + +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=1 action=meter:1,7']) +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=7 action=meter:2,1']) +AT_CHECK([ovs-ofctl add-flow br1 'in_port=2 action=8']) +AT_CHECK([ovs-ofctl add-flow br1 'in_port=8 action=2']) +ovs-appctl time/stop + ovs-appctl time/warp 5000 for i in `seq 1 7`; do AT_CHECK( diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 8531b2e2e..0f6a9e22c 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -3309,3 +3309,73 @@ AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: " ovs-vswitchd.log]) OVS_VSWITCHD_STOP AT_CLEANUP + + +dnl This checks basic add_meter --oneline operations. +AT_SETUP([ofproto - add meters and dump meters with oneline option (OpenFlow 1.3)]) +OVS_VSWITCHD_START +AT_DATA([meters.txt], [dnl +meter=12 pktps burst stats bands=type=drop rate=1 burst_size=1 +meter=34 pktps burst stats bands=type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +meter=56 kbps burst stats bands=type=drop rate=1 burst_size=1 +meter=78 kbps burst stats bands=type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +]) +AT_CHECK([ovs-ofctl -O openflow13 -vwarn add-meters br0 meters.txt]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-meters br0 --oneline], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sort -f], [0], [dnl +meter=12 pktps burst stats bands= type=drop rate=1 burst_size=1 +meter=34 pktps burst stats bands= type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +meter=56 kbps burst stats bands= type=drop rate=1 burst_size=1 +meter=78 kbps burst stats bands= type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +OFPST_METER_CONFIG reply (OF1.3): +]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn del-meters br0 meter=12]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-meters br0 --oneline], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sort -f], [0], [dnl +meter=34 pktps burst stats bands= type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +meter=56 kbps burst stats bands= type=drop rate=1 burst_size=1 +meter=78 kbps burst stats bands= type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +OFPST_METER_CONFIG reply (OF1.3): +]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn del-meters br0 meter=34]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-meters br0 --oneline], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sort -f], [0], [dnl +meter=56 kbps burst stats bands= type=drop rate=1 burst_size=1 +meter=78 kbps burst stats bands= type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +OFPST_METER_CONFIG reply (OF1.3): +]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn del-meters br0], [0]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-meters br0 --oneline], [0], [stdout]) +AT_CHECK([strip_xids < stdout], [0], [dnl +OFPST_METER_CONFIG reply (OF1.3): +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + +dnl This checks basic meter operations in file. +AT_SETUP([ofproto - add modify and delete meter in files (OpenFlow 1.3)]) +OVS_VSWITCHD_START +AT_DATA([meters.txt], [dnl +add meter=12 pktps burst stats bands=type=drop rate=1 burst_size=1 +add meter=34 pktps burst stats bands=type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +add meter=56 pktps burst stats bands=type=drop rate=2 burst_size=2 type=drop rate=10 burst_size=10 +modify meter=12 kbps burst stats bands=type=drop rate=1 burst_size=1 +modify meter=34 kbps burst stats bands=type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +delete meter=56 +]) +AT_CHECK([ovs-ofctl -O openflow13 -vwarn add-meters br0 meters.txt]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-meters br0 --oneline], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sort -f], [0], [dnl +meter=12 kbps burst stats bands= type=drop rate=1 burst_size=1 +meter=34 kbps burst stats bands= type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +OFPST_METER_CONFIG reply (OF1.3): +]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn mod-meter br0 "meter=12 pktps burst stats bands=type=drop rate=2 burst_size=2"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-meters br0 --oneline], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sort -f], [0], [dnl +meter=12 pktps burst stats bands= type=drop rate=2 burst_size=2 +meter=34 kbps burst stats bands= type=drop rate=1 burst_size=1 type=drop rate=10 burst_size=10 +OFPST_METER_CONFIG reply (OF1.3): +]) +OVS_VSWITCHD_STOP +AT_CLEANUP \ No newline at end of file diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 0a611b2ee..c44091906 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -492,23 +492,35 @@ the \fBBridge\fR table). For more information, see ``Q: What versions of OpenFlow does Open vSwitch support?'' in the Open vSwitch FAQ. . .IP "\fBadd\-meter \fIswitch meter\fR" +.IQ "\fBadd\-meter \fIswitch - < file\fR" Add a meter entry to \fIswitch\fR's tables. The \fImeter\fR syntax is described in section \fBMeter Syntax\fR, below. . +.IP "\fBadd\-meters \fIswitch file\fR" +Add each meter entry to \fIswitch\fR's tables. Each meter specification +(each line in file) may start with \fBadd\fI, \fBmodify\fI or \fBdelete\fI +keyword to specify whether a meter is to be added, modified, or deleted. +For backwards compatibility a meter specification without one of these keywords +is treated as a meter add. The \fImeter\fR syntax is described in section +\fBMeter Syntax\fR, below. +. .IP "\fBmod\-meter \fIswitch meter\fR" +.IQ "\fBmod\-meter \fIswitch - < file\fR" Modify an existing meter. . .IP "\fBdel\-meters \fIswitch\fR [\fImeter\fR]" +.IQ "\fBdel\-meters \fIswitch\fR - < file" Delete entries from \fIswitch\fR's meter table. To delete only a -specific meter, specify its number as \fImeter\fR. Otherwise, if +specific meter, specify a meter syntax \fBmeter=\fIid\fR. Otherwise, if \fImeter\fR is omitted, or if it is specified as \fBall\fR, then all meters are deleted. . -.IP "\fBdump\-meters \fIswitch\fR [\fImeter\fR]" +.IP "[\fB\-\-oneline\fR] \fBdump\-meters \fIswitch\fR [\fImeter\fR]" Print entries from \fIswitch\fR's meter table. To print only a -specific meter, specify its number as \fImeter\fR. Otherwise, if +specific meter, specify a meter syntax \fBmeter=\fIid\fR. Otherwise, if \fImeter\fR is omitted, or if it is specified as \fBall\fR, then all -meters are printed. +meters are printed. With \fB\-\-oneline\fR, band information will be +combined into one line. . .IP "\fBmeter\-stats \fIswitch\fR [\fImeter\fR]" Print meter statistics. \fImeter\fR can specify a single meter with @@ -1342,6 +1354,11 @@ includes flow duration, packet and byte counts, and idle and hard age in its output. With \fB\-\-no\-stats\fR, it omits all of these, as well as cookie values and table IDs if they are zero. . +.IP "\fB\-\-oneline\fR" +The \fBdump\-meters\fR command prints each band in a separate line by +default. With \fB\-\-oneline\fR, all bands will be printed in a single +line. This is useful for dumping meters to a file and restoring them. +. .IP "\fB\-\-read-only\fR" Do not execute read/write commands. . diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 24d0941cf..a928af869 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -157,6 +157,9 @@ static int print_pcap = 0; /* --raw: Makes "ofp-print" read binary data from stdin. */ static int raw = 0; +/* --oneline: show meter config in a single line. */ +static bool oneline = false; + static const struct ovs_cmdl_command *get_all_commands(void); OVS_NO_RETURN static void usage(void); @@ -217,6 +220,7 @@ parse_options(int argc, char *argv[]) OPT_COLOR, OPT_MAY_CREATE, OPT_READ_ONLY, + OPT_ONELINE, DAEMON_OPTION_ENUMS, OFP_VERSION_OPTION_ENUMS, VLOG_OPTION_ENUMS, @@ -245,6 +249,7 @@ parse_options(int argc, char *argv[]) {"pcap", no_argument, &print_pcap, 1}, {"raw", no_argument, &raw, 1}, {"read-only", no_argument, NULL, OPT_READ_ONLY}, + {"oneline", no_argument, NULL, OPT_ONELINE}, DAEMON_LONG_OPTIONS, OFP_VERSION_LONG_OPTIONS, VLOG_LONG_OPTIONS, @@ -314,6 +319,10 @@ parse_options(int argc, char *argv[]) ovs_cmdl_print_options(long_options); exit(EXIT_SUCCESS); + case OPT_ONELINE: + oneline = true; + break; + case OPT_BUNDLE: bundle = true; break; @@ -390,6 +399,10 @@ parse_options(int argc, char *argv[]) } } + if (oneline) { + verbosity = OFP_ONELINE_SET(verbosity); + } + ctl_timeout_setup(timeout); if (n_criteria) { @@ -475,9 +488,10 @@ usage(void) " dump-group-stats SWITCH [GROUP] print group statistics\n" " queue-get-config SWITCH [PORT] print queue config for PORT\n" " add-meter SWITCH METER add meter described by METER\n" + " add-meters SWITCH FILE add meters from FILE\n" " mod-meter SWITCH METER modify specific METER\n" " del-meters SWITCH [METER] delete meters matching METER\n" - " dump-meters SWITCH [METER] print METER configuration\n" + " dump-meters SWITCH [METER] print METER entries\n" " meter-stats SWITCH [METER] print meter statistics\n" " meter-features SWITCH print meter features\n" " add-tlv-map SWITCH MAP add TLV option MAPpings\n" @@ -515,6 +529,7 @@ usage(void) " --rsort[=field] sort in descending order\n" " --names show port names instead of numbers\n" " --no-names show port numbers, but not names\n" + " --oneline show meter bands in a single line\n" " --unixctl=SOCKET set control socket name\n" " --color[=always|never|auto] control use of color in output\n" " -h, --help display this help message\n" @@ -1443,7 +1458,7 @@ set_protocol_for_flow_dump(struct vconn *vconn, if (usable_protocols & allowed_protocols) { ovs_fatal(0, "switch does not support any of the usable flow " "formats (%s)", usable_s); -} else { + } else { char *allowed_s = ofputil_protocols_to_string(allowed_protocols); ovs_fatal(0, "none of the usable flow formats (%s) is among the " "allowed flow formats (%s)", usable_s, allowed_s); @@ -4084,57 +4099,107 @@ ofctl_diff_flows(struct ovs_cmdl_context *ctx) } static void -ofctl_meter_mod__(const char *bridge, const char *str, int command) +ofctl_meter_mod__(const char *remote, struct ofputil_meter_mod *mms, + size_t n_mms, enum ofputil_protocol usable_protocols) { - struct ofputil_meter_mod mm; - struct vconn *vconn; enum ofputil_protocol protocol; - enum ofputil_protocol usable_protocols; + struct ofputil_meter_mod *mm; enum ofp_version version; + struct ofpbuf *request; + struct vconn *vconn; + size_t i; - memset(&mm, 0, sizeof mm); - if (str) { + protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); + version = ofputil_protocol_to_ofp_version(protocol); + + for (i = 0; i < n_mms; i++) { + mm = &mms[i]; + request = ofputil_encode_meter_mod(version, mm); + transact_noreply(vconn, request); + free(mm->meter.bands); + } + + vconn_close(vconn); +} + +static void +ofctl_meter_mod_file(int argc OVS_UNUSED, char *argv[], int command) +{ + enum ofputil_protocol usable_protocols; + struct ofputil_meter_mod *mms = NULL; + size_t n_mms = 0; + char *error; + + if (command == OFPMC13_ADD) { + /* Allow the file to specify a mix of commands. If none specified at + * the beginning of any given line, then the default is OFPMC13_ADD, so + * this is backwards compatible. */ + command = -2; + } + error = parse_ofp_meter_mod_file(argv[2], command, + &mms, &n_mms, &usable_protocols); + if (error) { + ovs_fatal(0, "%s", error); + } + ofctl_meter_mod__(argv[1], mms, n_mms, usable_protocols); + free(mms); +} + +static void +ofctl_meter_mod(int argc, char *argv[], uint16_t command) +{ + if (argc > 2 && !strcmp(argv[2], "-")) { + ofctl_meter_mod_file(argc, argv, command); + } else { + enum ofputil_protocol usable_protocols; + struct ofputil_meter_mod mm; char *error; - error = parse_ofp_meter_mod_str(&mm, str, command, &usable_protocols); + memset(&mm, 0, sizeof mm); + error = parse_ofp_meter_mod_str(&mm, argc > 2 ? argv[2] : "", command, + &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } - } else { - usable_protocols = OFPUTIL_P_OF13_UP; - mm.command = command; - mm.meter.meter_id = OFPM13_ALL; + ofctl_meter_mod__(argv[1], &mm, 1, usable_protocols); } - - protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols); - version = ofputil_protocol_to_ofp_version(protocol); - transact_noreply(vconn, ofputil_encode_meter_mod(version, &mm)); - free(mm.meter.bands); - vconn_close(vconn); } -static void -ofctl_meter_request__(const char *bridge, const char *str, - enum ofputil_meter_request_type type) +static struct vconn * +prepare_dump_meters(const char *bridge, const char *str, + struct ofputil_meter_mod *mm, + enum ofputil_protocol *protocolp) { - struct ofputil_meter_mod mm; struct vconn *vconn; enum ofputil_protocol usable_protocols; enum ofputil_protocol protocol; - enum ofp_version version; - memset(&mm, 0, sizeof mm); if (str) { char *error; - error = parse_ofp_meter_mod_str(&mm, str, -1, &usable_protocols); + error = parse_ofp_meter_mod_str(mm, str, -1, &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } } else { usable_protocols = OFPUTIL_P_OF13_UP; - mm.meter.meter_id = OFPM13_ALL; + mm->meter.meter_id = OFPM13_ALL; } - protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols); + protocol = open_vconn(bridge, &vconn); + *protocolp = set_protocol_for_flow_dump(vconn, protocol, usable_protocols); + return vconn; +} + +static void +ofctl_meter_request__(const char *bridge, const char *str, + enum ofputil_meter_request_type type) +{ + enum ofputil_protocol protocol; + struct ofputil_meter_mod mm; + enum ofp_version version; + struct vconn *vconn; + + memset(&mm, 0, sizeof mm); + vconn = prepare_dump_meters(bridge, str, &mm, &protocol); version = ofputil_protocol_to_ofp_version(protocol); dump_transaction(vconn, ofputil_encode_meter_request(version, type, mm.meter.meter_id)); @@ -4142,23 +4207,28 @@ ofctl_meter_request__(const char *bridge, const char *str, vconn_close(vconn); } - static void ofctl_add_meter(struct ovs_cmdl_context *ctx) { - ofctl_meter_mod__(ctx->argv[1], ctx->argv[2], OFPMC13_ADD); + ofctl_meter_mod(ctx->argc, ctx->argv, OFPMC13_ADD); +} + +static void +ofctl_add_meters(struct ovs_cmdl_context *ctx) +{ + ofctl_meter_mod_file(ctx->argc, ctx->argv, OFPMC13_ADD); } static void ofctl_mod_meter(struct ovs_cmdl_context *ctx) { - ofctl_meter_mod__(ctx->argv[1], ctx->argv[2], OFPMC13_MODIFY); + ofctl_meter_mod(ctx->argc, ctx->argv, OFPMC13_MODIFY); } static void ofctl_del_meters(struct ovs_cmdl_context *ctx) { - ofctl_meter_mod__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL, OFPMC13_DELETE); + ofctl_meter_mod(ctx->argc, ctx->argv, OFPMC13_DELETE); } static void @@ -5072,15 +5142,17 @@ static const struct ovs_cmdl_command all_commands[] = { 2, 2, ofctl_diff_flows, OVS_RW }, { "add-meter", "switch meter", 2, 2, ofctl_add_meter, OVS_RW }, + { "add-meters", "switch file", + 2, 2, ofctl_add_meters, OVS_RW }, { "mod-meter", "switch meter", 2, 2, ofctl_mod_meter, OVS_RW }, - { "del-meter", "switch meter", + { "del-meter", "switch [meter]", 1, 2, ofctl_del_meters, OVS_RW }, { "del-meters", "switch", 1, 2, ofctl_del_meters, OVS_RW }, { "dump-meter", "switch meter", 1, 2, ofctl_dump_meters, OVS_RO }, - { "dump-meters", "switch", + { "dump-meters", "switch [meter]", 1, 2, ofctl_dump_meters, OVS_RO }, { "meter-stats", "switch [meter]", 1, 2, ofctl_meter_stats, OVS_RO }, diff --git a/utilities/ovs-save b/utilities/ovs-save index 67092ecf7..d1baa3415 100755 --- a/utilities/ovs-save +++ b/utilities/ovs-save @@ -139,6 +139,9 @@ save_flows () { echo "ovs-ofctl -O $ofp_version add-groups ${bridge} \ \"$workdir/$bridge.groups.dump\" ${bundle}" + echo "ovs-ofctl -O $ofp_version add-meters ${bridge} \ + \"$workdir/$bridge.meters.dump\"" + echo "ovs-ofctl -O $ofp_version replace-flows ${bridge} \ \"$workdir/$bridge.flows.dump\" ${bundle}" @@ -147,6 +150,11 @@ save_flows () { -e '/^NXST_GROUP_DESC/d' > \ "$workdir/$bridge.groups.dump" + ovs-ofctl -O $ofp_version dump-meters "$bridge" --oneline | \ + sed -e '/^OFPST_METER_CONFIG/d' \ + -e '/^NXST_METER_CONFIG/d' > \ + "$workdir/$bridge.meters.dump" + ovs-ofctl -O $ofp_version dump-flows --no-names --no-stats "$bridge" | \ sed -e '/NXST_FLOW/d' \ -e '/OFPST_FLOW/d' \