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

Reply via email to