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 <[email protected]>
---
v2:
fix failed testcases, as dump-meters format changes
---
include/openvswitch/ofp-meter.h | 6 +++
lib/ofp-meter.c | 94 ++++++++++++++++++++++++++++++++-
tests/dpif-netdev.at | 6 +--
tests/ofp-print.at | 13 ++---
tests/ofproto-dpif.at | 3 +-
tests/ofproto.at | 3 +-
utilities/ovs-ofctl.c | 86 +++++++++++++++++++++++-------
utilities/ovs-save | 8 +++
8 files changed, 182 insertions(+), 37 deletions(-)
diff --git a/include/openvswitch/ofp-meter.h b/include/openvswitch/ofp-meter.h
index 6776eae87..34ecbfdb2 100644
--- a/include/openvswitch/ofp-meter.h
+++ b/include/openvswitch/ofp-meter.h
@@ -79,6 +79,12 @@ 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/lib/ofp-meter.c b/lib/ofp-meter.c
index 9ea40a0bf..5fb780ba3 100644
--- a/lib/ofp-meter.c
+++ b/lib/ofp-meter.c
@@ -15,6 +15,7 @@
*/
#include <config.h>
+#include <errno.h>
#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");
@@ -578,6 +579,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 +625,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) {
@@ -807,3 +831,71 @@ ofputil_format_meter_mod(struct ds *s, const struct
ofputil_meter_mod *mm)
ofputil_format_meter_config(s, &mm->meter);
}
+
+/* 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/tests/dpif-netdev.at b/tests/dpif-netdev.at
index a79ebdb61..98c474d20 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -291,11 +291,9 @@ ovs-appctl time/stop
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0], [0], [dnl
OFPST_METER_CONFIG reply (OF1.3) (xid=0x2):
-meter=1 pktps burst stats bands=
-type=drop rate=1 burst_size=1
+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=2 kbps burst stats bands= type=drop rate=1 burst_size=2
])
ovs-appctl time/warp 5000
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 2c7e163bd..36ebccefc 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -2371,8 +2371,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
04 1d 00 20 00 00 00 02 00 00 00 0d 00 00 00 05 \
00 01 00 10 00 00 04 00 00 00 00 80 00 00 00 00 \
"], [0], [dnl
-OFPT_METER_MOD (OF1.3) (xid=0x2): ADD meter=5 kbps burst stats bands=
-type=drop rate=1024 burst_size=128
+OFPT_METER_MOD (OF1.3) (xid=0x2): ADD meter=5 kbps burst stats bands=
type=drop rate=1024 burst_size=128
])
AT_CLEANUP
@@ -2455,12 +2454,9 @@ AT_CHECK([ovs-ofctl ofp-print "\
00 01 00 10 00 02 00 00 00 00 00 00 00 00 00 00 \
"], [0], [dnl
OFPST_METER_CONFIG reply (OF1.3) (xid=0x2):
-meter=1 kbps burst bands=
-type=drop rate=65536 burst_size=1280
-type=dscp_remark rate=1048576 burst_size=61440 prec_level=0
+meter=1 kbps burst bands= type=drop rate=65536 burst_size=1280
type=dscp_remark rate=1048576 burst_size=61440 prec_level=0
-meter=2 kbps stats bands=
-type=drop rate=131072
+meter=2 kbps stats bands= type=drop rate=131072
])
AT_CLEANUP
@@ -3071,8 +3067,7 @@ dnl inner msg copied and pasted from the valid OFPT_METER_MOD OF1.3 test:
04 1d 00 20 00 00 00 02 00 00 00 0d 00 00 00 05 \
00 01 00 10 00 00 04 00 00 00 00 80 00 00 00 00 \
"], [0], [dnl
-ONFT_REQUESTFORWARD (OF1.3) (xid=0x2): reason=meter_mod ADD meter=5 kbps burst
stats bands=
-type=drop rate=1024 burst_size=128
+ONFT_REQUESTFORWARD (OF1.3) (xid=0x2): reason=meter_mod ADD meter=5 kbps burst
stats bands= type=drop rate=1024 burst_size=128
])
AT_CLEANUP
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 912f3a1da..52cb49774 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -9834,8 +9834,7 @@ ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1
packet=50540000000a50540000000
# Check that vswitchd hasn't crashed by dumping the meter added above
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0 | ofctl_strip], [0], [dnl
OFPST_METER_CONFIG reply (OF1.3):
-meter=1 pktps bands=
-type=drop rate=1
+meter=1 pktps bands= type=drop rate=1
])
OVS_VSWITCHD_STOP
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 156d3e058..a6a61d24c 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -6412,8 +6412,7 @@ OFPST_GROUP_DESC reply (OF1.1) (xid=0x2):
])
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0], [0], [dnl
OFPST_METER_CONFIG reply (OF1.3) (xid=0x2):
-meter=1 pktps burst stats bands=
-type=drop rate=1 burst_size=1
+meter=1 pktps burst stats bands= type=drop rate=1 burst_size=1
])
}
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index ede7f1e61..152836276 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -474,6 +474,7 @@ 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"
@@ -4012,32 +4013,70 @@ 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 ofputil_meter_mod *mm;
struct vconn *vconn;
enum ofputil_protocol protocol;
- enum ofputil_protocol usable_protocols;
enum ofp_version version;
+ struct ofpbuf *request;
+ 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);
+ 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
@@ -4074,19 +4113,26 @@ ofctl_meter_request__(const char *bridge, const char
*str,
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
@@ -5000,9 +5046,11 @@ 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 },
diff --git a/utilities/ovs-save b/utilities/ovs-save
index fb2025b76..e3551b9f9 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" | \
+ 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' \