Ben, thanks for rebasing. I will review it soon.
On Mon, Jul 27, 2015 at 1:56 PM, Ben Pfaff <b...@nicira.com> wrote: > I spent some time recently looking at the results of "ovs-ofctl > dump-table-features". It was really distressing because of the volume of > information. Every table yielded well over 100 lines of output and for 253 > (visible) tables that meant over 25,300 lines of output total, which is > basically unusable. > > This commit cuts the volume of output greatly by eliminating most of the > duplication from one table to the next. The command now prints the full > output only for table 0, and for each subsequent table prints only the > parts that differ. That reduces the output volume for tables after the > first to only 9 lines each (one of which is blank), for a total of more > like 2,400 lines, which is still not short but reasonably manageable. > > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > v1->v2: Rebase. > > lib/ofp-print.c | 166 +++++++++++++++++++++++++++++++---------- > lib/ofp-print.h | 9 ++- > tests/ofp-print.at | 29 ++++---- > tests/ofproto-dpif.at | 69 +++++++++-------- > tests/ofproto.at | 202 > ++++++++++++++++++++++++++++++++------------------ > utilities/ovs-ofctl.c | 68 ++++++++++++++++- > 6 files changed, 378 insertions(+), 165 deletions(-) > > diff --git a/lib/ofp-print.c b/lib/ofp-print.c > index 6db32d1..44f3115 100644 > --- a/lib/ofp-print.c > +++ b/lib/ofp-print.c > @@ -53,7 +53,4 @@ > static void ofp_print_queue_name(struct ds *string, uint32_t port); > static void ofp_print_error(struct ds *, enum ofperr); > -static void ofp_print_table_features(struct ds *, > - const struct ofputil_table_features *, > - const struct ofputil_table_stats *); > > /* Returns a string that represents the contents of the Ethernet frame in the > @@ -1622,5 +1619,7 @@ ofp_print_table_stats_reply(struct ds *string, const > struct ofp_header *oh) > ofpraw_pull_assert(&b); > > - for (;;) { > + struct ofputil_table_features prev_features; > + struct ofputil_table_stats prev_stats; > + for (int i = 0;; i++) { > struct ofputil_table_features features; > struct ofputil_table_stats stats; > @@ -1635,5 +1634,10 @@ ofp_print_table_stats_reply(struct ds *string, const > struct ofp_header *oh) > } > > - ofp_print_table_features(string, &features, &stats); > + ds_put_char(string, '\n'); > + ofp_print_table_features(string, > + &features, i ? &prev_features : NULL, > + &stats, i ? &prev_stats : NULL); > + prev_features = features; > + prev_stats = stats; > } > } > @@ -2616,5 +2620,7 @@ table_action_features_empty(const struct > ofputil_table_action_features *taf) > static void > print_table_instruction_features( > - struct ds *s, const struct ofputil_table_instruction_features *tif) > + struct ds *s, > + const struct ofputil_table_instruction_features *tif, > + const struct ofputil_table_instruction_features *prev_tif) > { > int start, end; > @@ -2639,17 +2645,26 @@ print_table_instruction_features( > > if (tif->instructions) { > - ds_put_cstr(s, " instructions: "); > - int i; > + if (prev_tif && tif->instructions == prev_tif->instructions) { > + ds_put_cstr(s, " (same instructions)\n"); > + } else { > + ds_put_cstr(s, " instructions: "); > + int i; > > - for (i = 0; i < 32; i++) { > - if (tif->instructions & (1u << i)) { > - ds_put_format(s, "%s,", ovs_instruction_name_from_type(i)); > + for (i = 0; i < 32; i++) { > + if (tif->instructions & (1u << i)) { > + ds_put_format(s, "%s,", > ovs_instruction_name_from_type(i)); > + } > } > + ds_chomp(s, ','); > + ds_put_char(s, '\n'); > } > - ds_chomp(s, ','); > - ds_put_char(s, '\n'); > } > > - if (!table_action_features_equal(&tif->write, &tif->apply)) { > + if (prev_tif > + && table_action_features_equal(&tif->write, &prev_tif->write) > + && table_action_features_equal(&tif->apply, &prev_tif->apply) > + && !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) { > + ds_put_cstr(s, " (same actions)\n"); > + } else if (!table_action_features_equal(&tif->write, &tif->apply)) { > ds_put_cstr(s, " Write-Actions features:\n"); > print_table_action_features(s, &tif->write); > @@ -2684,16 +2699,65 @@ table_instruction_features_empty( > } > > -static void > +static bool > +table_features_equal(const struct ofputil_table_features *a, > + const struct ofputil_table_features *b) > +{ > + return (a->metadata_match == b->metadata_match > + && a->metadata_write == b->metadata_write > + && a->miss_config == b->miss_config > + && a->supports_eviction == b->supports_eviction > + && a->supports_vacancy_events == b->supports_vacancy_events > + && a->max_entries == b->max_entries > + && table_instruction_features_equal(&a->nonmiss, &b->nonmiss) > + && table_instruction_features_equal(&a->miss, &b->miss) > + && bitmap_equal(a->match.bm, b->match.bm, MFF_N_IDS)); > +} > + > +static bool > +table_features_empty(const struct ofputil_table_features *tf) > +{ > + return (!tf->metadata_match > + && !tf->metadata_write > + && tf->miss_config == OFPUTIL_TABLE_MISS_DEFAULT > + && tf->supports_eviction < 0 > + && tf->supports_vacancy_events < 0 > + && !tf->max_entries > + && table_instruction_features_empty(&tf->nonmiss) > + && table_instruction_features_empty(&tf->miss) > + && bitmap_is_all_zeros(tf->match.bm, MFF_N_IDS)); > +} > + > +static bool > +table_stats_equal(const struct ofputil_table_stats *a, > + const struct ofputil_table_stats *b) > +{ > + return (a->active_count == b->active_count > + && a->lookup_count == b->lookup_count > + && a->matched_count == b->matched_count); > +} > + > +void > ofp_print_table_features(struct ds *s, > const struct ofputil_table_features *features, > - const struct ofputil_table_stats *stats) > + const struct ofputil_table_features *prev_features, > + const struct ofputil_table_stats *stats, > + const struct ofputil_table_stats *prev_stats) > { > int i; > > - ds_put_format(s, "\n table %"PRIu8, features->table_id); > + ds_put_format(s, " table %"PRIu8, features->table_id); > if (features->name[0]) { > ds_put_format(s, " (\"%s\")", features->name); > } > - ds_put_cstr(s, ":\n"); > + ds_put_char(s, ':'); > + > + bool same_stats = prev_stats && table_stats_equal(stats, prev_stats); > + bool same_features = prev_features && table_features_equal(features, > + > prev_features); > + if ((!stats || same_stats) && (!features || same_features)) { > + ds_put_cstr(s, " ditto"); > + return; > + } > + ds_put_char(s, '\n'); > if (stats) { > ds_put_format(s, " active=%"PRIu32", ", stats->active_count); > @@ -2701,5 +2765,11 @@ ofp_print_table_features(struct ds *s, > ds_put_format(s, "matched=%"PRIu64"\n", stats->matched_count); > } > - if (features->metadata_match || features->metadata_match) { > + if (same_features) { > + if (!table_features_empty(features)) { > + ds_put_cstr(s, " (same features)\n"); > + } > + return; > + } > + if (features->metadata_match || features->metadata_write) { > ds_put_format(s, " metadata: match=%#"PRIx64" write=%#"PRIx64"\n", > ntohll(features->metadata_match), > @@ -2727,27 +2797,43 @@ ofp_print_table_features(struct ds *s, > } > > - if (!table_instruction_features_equal(&features->nonmiss, > - &features->miss)) { > + const struct ofputil_table_instruction_features *prev_nonmiss > + = prev_features ? &prev_features->nonmiss : NULL; > + const struct ofputil_table_instruction_features *prev_miss > + = prev_features ? &prev_features->miss : NULL; > + if (prev_features > + && table_instruction_features_equal(&features->nonmiss, prev_nonmiss) > + && table_instruction_features_equal(&features->miss, prev_miss)) { > + if (!table_instruction_features_empty(&features->nonmiss)) { > + ds_put_cstr(s, " (same instructions)\n"); > + } > + } else if (!table_instruction_features_equal(&features->nonmiss, > + &features->miss)) { > ds_put_cstr(s, " instructions (other than table miss):\n"); > - print_table_instruction_features(s, &features->nonmiss); > + print_table_instruction_features(s, &features->nonmiss, > prev_nonmiss); > ds_put_cstr(s, " instructions (table miss):\n"); > - print_table_instruction_features(s, &features->miss); > + print_table_instruction_features(s, &features->miss, prev_miss); > } else if (!table_instruction_features_empty(&features->nonmiss)) { > ds_put_cstr(s, " instructions (table miss and others):\n"); > - print_table_instruction_features(s, &features->nonmiss); > + print_table_instruction_features(s, &features->nonmiss, > prev_nonmiss); > } > > - if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)){ > - ds_put_cstr(s, " matching:\n"); > - BITMAP_FOR_EACH_1 (i, MFF_N_IDS, features->match.bm) { > - const struct mf_field *f = mf_from_id(i); > - bool mask = bitmap_is_set(features->mask.bm, i); > - bool wildcard = bitmap_is_set(features->wildcard.bm, i); > - > - ds_put_format(s, " %s: %s\n", > - f->name, > - (mask ? "arbitrary mask" > - : wildcard ? "exact match or wildcard" > - : "must exact match")); > + if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)) { > + if (prev_features > + && bitmap_equal(features->match.bm, prev_features->match.bm, > + MFF_N_IDS)) { > + ds_put_cstr(s, " (same matching)\n"); > + } else { > + ds_put_cstr(s, " matching:\n"); > + BITMAP_FOR_EACH_1 (i, MFF_N_IDS, features->match.bm) { > + const struct mf_field *f = mf_from_id(i); > + bool mask = bitmap_is_set(features->mask.bm, i); > + bool wildcard = bitmap_is_set(features->wildcard.bm, i); > + > + ds_put_format(s, " %s: %s\n", > + f->name, > + (mask ? "arbitrary mask" > + : wildcard ? "exact match or wildcard" > + : "must exact match")); > + } > } > } > @@ -2761,5 +2847,6 @@ ofp_print_table_features_reply(struct ds *s, const > struct ofp_header *oh) > ofpbuf_use_const(&b, oh, ntohs(oh->length)); > > - for (;;) { > + struct ofputil_table_features prev; > + for (int i = 0; ; i++) { > struct ofputil_table_features tf; > int retval; > @@ -2772,5 +2859,8 @@ ofp_print_table_features_reply(struct ds *s, const > struct ofp_header *oh) > return; > } > - ofp_print_table_features(s, &tf, NULL); > + > + ds_put_char(s, '\n'); > + ofp_print_table_features(s, &tf, i ? &prev : NULL, NULL, NULL); > + prev = tf; > } > } > diff --git a/lib/ofp-print.h b/lib/ofp-print.h > index 825e139..bbac18b 100644 > --- a/lib/ofp-print.h > +++ b/lib/ofp-print.h > @@ -1,4 +1,4 @@ > /* > - * Copyright (c) 2008, 2009, 2011, 2012 Nicira, Inc. > + * Copyright (c) 2008, 2009, 2011, 2012, 2015 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > @@ -28,4 +28,6 @@ struct ofp_flow_mod; > struct ofp_header; > struct ofputil_flow_stats; > +struct ofputil_table_features; > +struct ofputil_table_stats; > > #ifdef __cplusplus > @@ -44,4 +46,9 @@ char *ofp_packet_to_string(const void *data, size_t len); > void ofp_print_flow_stats(struct ds *, struct ofputil_flow_stats *); > void ofp_print_version(const struct ofp_header *, struct ds *); > +void ofp_print_table_features( > + struct ds *, const struct ofputil_table_features *features, > + const struct ofputil_table_features *prev_features, > + const struct ofputil_table_stats *stats, > + const struct ofputil_table_stats *prev_stats); > > #ifdef __cplusplus > diff --git a/tests/ofp-print.at b/tests/ofp-print.at > index 127bcf1..3b4a4e8 100644 > --- a/tests/ofp-print.at > +++ b/tests/ofp-print.at > @@ -1467,5 +1467,7 @@ AT_CLEANUP > AT_SETUP([OFPST_TABLE reply - OF1.2]) > AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) > -(tail=" > +(echo 'OFPST_TABLE reply (OF1.2) (xid=0x2): > + table 0 ("classifier"): > + active=1, lookup=74614, matched=106024 > config=controller > max_entries=1000000 > @@ -1509,19 +1511,16 @@ AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) > nd_target: exact match or wildcard > nd_sll: exact match or wildcard > - nd_tll: exact match or wildcard" > - echo "OFPST_TABLE reply (OF1.2) (xid=0x2): > - table 0 (\"classifier\"): > - active=1, lookup=74614, matched=106024$tail" > - x=1 > - while test $x -lt 254; do > - printf " > - table %d (\"%s\"): > - active=0, lookup=0, matched=0$tail > -" $x table$x > - x=`expr $x + 1` > + nd_tll: exact match or wildcard > + > + table 1 ("table1"): > + active=0, lookup=0, matched=0 > + (same features) > +' > + for i in `seq 2 253`; do > + printf ' table %d ("table%d"): ditto\n' $i $i > done > - echo " > - table 254 (\"table254\"): > - active=2, lookup=0, matched=0$tail") > expout > + echo ' table 254 ("table254"): > + active=2, lookup=0, matched=0 > + (same features)') > expout > > (pad32="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index cfe7294..6322d70 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -6726,11 +6726,11 @@ NXST_FLOW reply: > (echo "OFPST_TABLE reply (OF1.3) (xid=0x2): > table 0: > - active=1, lookup=0, matched=0" > - x=1 > - while test $x -lt 254; do > - echo " > - table $x: > - active=0, lookup=0, matched=0" > - x=`expr $x + 1` > + active=1, lookup=0, matched=0 > + > + table 1: > + active=0, lookup=0, matched=0 > +" > + for i in `seq 2 253`; do > + printf ' table %d: ditto\n' $i > done) > expout > AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) > @@ -6770,11 +6770,10 @@ > vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 > ]) > > -(printf "OFPST_TABLE reply (OF1.3) (xid=0x2):" > - x=0 > - while test $x -lt 254; do > - echo " > - table $x: > - active=0, lookup=0, matched=0" > - x=`expr $x + 1` > +(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): > + table 0: > + active=0, lookup=0, matched=0 > +" > + for i in `seq 1 253`; do > + printf ' table %d: ditto\n' $i > done) > expout > AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) > @@ -6782,11 +6781,11 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], > [0], [expout]) > (echo "OFPST_TABLE reply (OF1.3) (xid=0x2): > table 0: > - active=0, lookup=3, matched=0" > - x=1 > - while test $x -lt 254; do > - echo " > - table $x: > - active=0, lookup=0, matched=0" > - x=`expr $x + 1` > + active=0, lookup=3, matched=0 > + > + table 1: > + active=0, lookup=0, matched=0 > +" > + for i in `seq 2 253`; do > + printf ' table %d: ditto\n' $i > done) > expout > AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br1 ], [0], [expout]) > @@ -6837,12 +6836,10 @@ OFPST_FLOW reply (OF1.3): > active=1, lookup=3, matched=3 > > - table 1: > - active=1, lookup=3, matched=3" > - x=2 > - while test $x -lt 254; do > - echo " > - table $x: > - active=0, lookup=0, matched=0" > - x=`expr $x + 1` > + table 1: ditto > + table 2: > + active=0, lookup=0, matched=0 > +" > + for i in `seq 3 253`; do > + printf ' table %d: ditto\n' $i > done) > expout > AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) > @@ -6890,11 +6887,11 @@ OFPST_FLOW reply (OF1.1): > > table 1: > - active=1, lookup=3, matched=3" > - x=2 > - while test $x -lt 254; do > - echo " > - table $x: > - active=0, lookup=0, matched=0" > - x=`expr $x + 1` > + active=1, lookup=3, matched=3 > + > + table 2: > + active=0, lookup=0, matched=0 > +" > + for i in `seq 3 253`; do > + printf ' table %d: ditto\n' $i > done) > expout > AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) > diff --git a/tests/ofproto.at b/tests/ofproto.at > index cf5ab9f..e3f08a8 100644 > --- a/tests/ofproto.at > +++ b/tests/ofproto.at > @@ -1308,10 +1308,7 @@ AT_SETUP([ofproto - flow table configuration (OpenFlow > 1.0)]) > OVS_VSWITCHD_START > # Check the default configuration. > -(printf "OFPST_TABLE reply (xid=0x2):" > - x=0 > - name=classifier > - while test $x -lt 254; do > - printf " > - table %d (\"%s\"): > +head_table() { > + printf 'OFPST_TABLE reply (xid=0x2): > + table 0 ("%s"): > active=0, lookup=0, matched=0 > max_entries=1000000 > @@ -1329,8 +1326,13 @@ OVS_VSWITCHD_START > tcp_src: exact match or wildcard > tcp_dst: exact match or wildcard > -" $x $name > - x=`expr $x + 1` > - name=table$x > - done) > expout > + > +' $1 > +} > +ditto() { > + for i in `seq $1 $2`; do > + printf ' table %d ("table%d"): ditto\n' $i $i > + done > +} > +(head_table classifier; ditto 1 253) > expout > AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout]) > # Change the configuration. > @@ -1345,7 +1347,14 @@ AT_CHECK( > ]) > # Check that the configuration was updated. > -mv expout orig-expout > -sed -e 's/classifier/main/ > -21s/1000000/1024/' orig-expout > expout > +(head_table main; echo ' table 1 ("table1"): > + active=0, lookup=0, matched=0 > + max_entries=1024 > + (same matching) > + > + table 2 ("table2"): > + active=0, lookup=0, matched=0 > + max_entries=1000000 > + (same matching) > +'; ditto 3 253) > expout > AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout]) > OVS_VSWITCHD_STOP > @@ -1375,10 +1384,7 @@ AT_CHECK([test `grep '240\.0\.0\.1' stdout | grep -v > table_id= | wc -l` -gt 0]) > > # Check that dump-tables doesn't count the hidden flows. > -(printf "OFPST_TABLE reply (xid=0x2):" > - x=0 > - name=classifier > - while test $x -lt 254; do > - printf " > - table %d (\"%s\"): > +head_table() { > + printf 'OFPST_TABLE reply (xid=0x2): > + table 0 ("%s"): > active=0, lookup=0, matched=0 > max_entries=1000000 > @@ -1396,8 +1402,13 @@ AT_CHECK([test `grep '240\.0\.0\.1' stdout | grep -v > table_id= | wc -l` -gt 0]) > tcp_src: exact match or wildcard > tcp_dst: exact match or wildcard > -" $x $name > - x=`expr $x + 1` > - name=table$x > - done) > expout > + > +' $1 > +} > +ditto() { > + for i in `seq $1 $2`; do > + printf ' table %d ("table%d"): ditto\n' $i $i > + done > +} > +(head_table classifier; ditto 1 253) > expout > AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout]) > OVS_VSWITCHD_STOP(["/cannot find route for controller/d"]) > @@ -1407,15 +1418,7 @@ AT_SETUP([ofproto - flow table configuration (OpenFlow > 1.2)]) > OVS_VSWITCHD_START > # Check the default configuration. > -(printf "OFPST_TABLE reply (OF1.2) (xid=0x2):" > - x=0 > - name=classifier > - while test $x -lt 254; do > - if test $x = 253; then > - goto= > - else > - goto=,goto_table > - fi > - echo " > - table $x (\"$name\"): > +head_table() { > + printf 'OFPST_TABLE reply (OF1.2) (xid=0x2): > + table 0 ("%s"): > active=0, lookup=0, matched=0 > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > @@ -1423,5 +1426,5 @@ OVS_VSWITCHD_START > max_entries=1000000 > instructions (table miss and others): > - instructions: > apply_actions,clear_actions,write_actions,write_metadata$goto > + instructions: > apply_actions,clear_actions,write_actions,write_metadata,goto_table > Write-Actions and Apply-Actions features: > actions: output group set_field strip_vlan push_vlan mod_nw_ttl > dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue > @@ -1462,8 +1465,26 @@ OVS_VSWITCHD_START > nd_target: exact match or wildcard > nd_sll: exact match or wildcard > - nd_tll: exact match or wildcard" > - x=`expr $x + 1` > - name=table$x > - done) > expout > + nd_tll: exact match or wildcard > + > +' $1 > +} > +ditto() { > + for i in `seq $1 $2`; do > + printf ' table %d ("table%d"): ditto\n' $i $i > + done > +} > +tail_table() { > + printf ' table 253 ("table253"): > + active=0, lookup=0, matched=0 > + metadata: match=0xffffffffffffffff write=0xffffffffffffffff > + config=controller > + max_entries=1000000 > + instructions (table miss and others): > + instructions: apply_actions,clear_actions,write_actions,write_metadata > + (same actions) > + (same matching) > +' > +} > +(head_table classifier; ditto 1 252; tail_table) > expout > AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout]) > # Change the configuration. > @@ -1478,7 +1499,20 @@ AT_CHECK( > ]) > # Check that the configuration was updated. > -mv expout orig-expout > -sed 's/classifier/main/ > -53s/1000000/1024/' < orig-expout > expout > +(head_table main; echo ' table 1 ("table1"): > + active=0, lookup=0, matched=0 > + metadata: match=0xffffffffffffffff write=0xffffffffffffffff > + config=controller > + max_entries=1024 > + (same instructions) > + (same matching) > + > + table 2 ("table2"): > + active=0, lookup=0, matched=0 > + metadata: match=0xffffffffffffffff write=0xffffffffffffffff > + config=controller > + max_entries=1000000 > + (same instructions) > + (same matching) > +'; ditto 3 252; tail_table) > expout > AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout]) > OVS_VSWITCHD_STOP > @@ -1487,26 +1521,11 @@ AT_CLEANUP > AT_SETUP([ofproto - table features (OpenFlow 1.3)]) > OVS_VSWITCHD_START > -(x=0 > - name=classifier > - while test $x -lt 254; do > - y=`expr $x + 1` > - if test $x = 253; then > - next= > - goto= > - else > - goto=,goto_table > - if test $x = 252; then > - next=' > - next tables: 253' > - else > - next=" > - next tables: $y-253" > - fi > - fi > - echo " table $x (\"$name\"): > +head_table () { > + printf ' table 0 ("%s"): > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > max_entries=1000000 > - instructions (table miss and others):$next > - instructions: > meter,apply_actions,clear_actions,write_actions,write_metadata$goto > + instructions (table miss and others): > + next tables: 1-253 > + instructions: > meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table > Write-Actions and Apply-Actions features: > actions: output group set_field strip_vlan push_vlan mod_nw_ttl > dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue > @@ -1641,10 +1660,45 @@ OVS_VSWITCHD_START > nd_target: arbitrary mask > nd_sll: arbitrary mask > - nd_tll: arbitrary mask" > - x=$y > - name=table$x > - done) > expout > -AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d > -/^OFPST_TABLE_FEATURES/d'], [0], [expout]) > + nd_tll: arbitrary mask > + > +' $1 > +} > +ditto() { > + printf ' table %d ("%s"): > + metadata: match=0xffffffffffffffff write=0xffffffffffffffff > + max_entries=%d > + instructions (table miss and others): > + next tables: %d-253 > + (same instructions) > + (same actions) > + (same matching) > + > +' $1 $2 $3 `expr $1 + 1` > +} > +tail_tables() { > +echo ' table 252 ("table252"): > + metadata: match=0xffffffffffffffff write=0xffffffffffffffff > + max_entries=1000000 > + instructions (table miss and others): > + next tables: 253 > + (same instructions) > + (same actions) > + (same matching) > + > + table 253 ("table253"): > + metadata: match=0xffffffffffffffff write=0xffffffffffffffff > + max_entries=1000000 > + instructions (table miss and others): > + instructions: > meter,apply_actions,clear_actions,write_actions,write_metadata > + (same actions) > + (same matching) > +' > +} > +(head_table classifier > + for i in `seq 1 251`; do > + ditto $i table$i 1000000 > + done > + tail_tables) > expout > +AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout]) > # Change the configuration. > AT_CHECK( > @@ -1658,9 +1712,11 @@ AT_CHECK( > ]) > # Check that the configuration was updated. > -mv expout orig-expout > -sed 's/classifier/main/ > -142s/1000000/1024/' < orig-expout > expout > -AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d > -/^OFPST_TABLE_FEATURES/d'], [0], [expout]) > +(head_table main > + ditto 1 table1 1024 > + for i in `seq 2 251`; do > + ditto $i table$i 1000000 > + done > + tail_tables) > expout > +AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout]) > OVS_VSWITCHD_STOP > AT_CLEANUP > diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c > index 0bc7089..6ec7151 100644 > --- a/utilities/ovs-ofctl.c > +++ b/utilities/ovs-ofctl.c > @@ -732,6 +732,70 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx) > open_vconn(ctx->argv[1], &vconn); > request = > ofputil_encode_table_features_request(vconn_get_version(vconn)); > - if (request) { > - dump_stats_transaction(vconn, request); > + > + /* The following is similar to dump_trivial_stats_transaction(), but it > + * maintains the previous 'ofputil_table_features' from one stats reply > + * message to the next, which allows duplication to be eliminated in the > + * output across messages. Otherwise the output is much larger and > harder > + * to read, because only 17 or so ofputil_table_features elements fit in > a > + * single 64 kB OpenFlow message and therefore you get a ton of > repetition > + * (every 17th element is printed in full instead of abbreviated). */ > + > + const struct ofp_header *request_oh = request->data; > + ovs_be32 send_xid = request_oh->xid; > + bool done = false; > + > + struct ofputil_table_features prev; > + int n = 0; > + > + send_openflow_buffer(vconn, request); > + while (!done) { > + ovs_be32 recv_xid; > + struct ofpbuf *reply; > + > + run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive > failed"); > + recv_xid = ((struct ofp_header *) reply->data)->xid; > + if (send_xid == recv_xid) { > + enum ofptype type; > + enum ofperr error; > + error = ofptype_decode(&type, reply->data); > + if (error) { > + ovs_fatal(0, "decode error: %s", ofperr_get_name(error)); > + } else if (type == OFPTYPE_ERROR) { > + ofp_print(stdout, reply->data, reply->size, verbosity + 1); > + done = true; > + } else if (type == OFPTYPE_TABLE_FEATURES_STATS_REPLY) { > + done = !ofpmp_more(reply->data); > + for (;;) { > + struct ofputil_table_features tf; > + int retval; > + > + retval = ofputil_decode_table_features(reply, &tf, true); > + if (retval) { > + if (retval != EOF) { > + ovs_fatal(0, "decode error: %s", > + ofperr_get_name(retval)); > + } > + break; > + } > + > + struct ds s = DS_EMPTY_INITIALIZER; > + ofp_print_table_features(&s, &tf, n ? &prev : NULL, > + NULL, NULL); > + puts(ds_cstr(&s)); > + ds_destroy(&s); > + > + prev = tf; > + n++; > + } > + } else { > + ovs_fatal(0, "received bad reply: %s", > + ofp_to_string(reply->data, reply->size, > + verbosity + 1)); > + } > + } else { > + VLOG_DBG("received reply with xid %08"PRIx32" " > + "!= expected %08"PRIx32, recv_xid, send_xid); > + } > + ofpbuf_delete(reply); > } > > -- > 2.1.3 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev