[ovs-dev] [PATCH] ovs-ofctl: New option "--no-stats" for "ovs-ofctl dump-flows".

Ben Pfaff blp at ovn.org
Wed Jun 14 00:09:05 UTC 2017


It's pretty common to want to omit statistics from output, to make it
easier to read.  This commit adds an ovs-ofctl option to make that easy.

A lot of the OVS internal tests could use this, too, in place of
ofctl_strip.  This commit adopts it for a subset.

CC: Aaron Conole <aconole at redhat.com>
Signed-off-by: Ben Pfaff <blp at ovn.org>
---
 NEWS                            |  8 +++---
 include/openvswitch/ofp-print.h |  2 +-
 lib/ofp-print.c                 | 50 ++++++++++++++++++++++------------
 ovn/utilities/ovn-sbctl.c       |  6 ++---
 ovn/utilities/ovn-trace.c       | 10 +++----
 tests/bundle.at                 |  3 +--
 tests/learn.at                  | 59 ++++++++++++++---------------------------
 utilities/ovs-ofctl.8.in        | 14 ++++++++--
 utilities/ovs-ofctl.c           | 12 ++++++---
 9 files changed, 87 insertions(+), 77 deletions(-)

diff --git a/NEWS b/NEWS
index b526646810f8..bc39aab5c4d7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,10 @@
 Post-v2.7.0
 ---------------------
-   - ovs-ofctl can now accept and display port names in place of numbers.  By
-     default it always accepts names and in interactive use it displays them;
-     use --names or --no-names to override.  See ovs-ofctl(8) for details.
+   - ovs-ofctl:
+     * ovs-ofctl can now accept and display port names in place of numbers.  By
+       default it always accepts names and in interactive use it displays them;
+       use --names or --no-names to override.  See ovs-ofctl(8) for details.
+     * "ovs-ofctl dump-flows" now accepts --no-stats to omit flow statistics.
    - Tunnels:
      * Added support to set packet mark for tunnel endpoint using
        `egress_pkt_mark` OVSDB option.
diff --git a/include/openvswitch/ofp-print.h b/include/openvswitch/ofp-print.h
index 4893d44b4b48..20f049a37f65 100644
--- a/include/openvswitch/ofp-print.h
+++ b/include/openvswitch/ofp-print.h
@@ -61,7 +61,7 @@ void ofp_print_table_features(
     const struct ofputil_table_stats *prev_stats);
 
 void ofp_print_flow_stats(struct ds *, const struct ofputil_flow_stats *,
-                          const struct ofputil_port_map *);
+                          const struct ofputil_port_map *, bool show_stats);
 
 #ifdef  __cplusplus
 }
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 423df31027d9..b1c412ea4c21 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -1682,21 +1682,34 @@ ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh,
     match_format(&fsr.match, port_map, string, OFP_DEFAULT_PRIORITY);
 }
 
+/* Appends a textual form of 'fs' to 'string', translating port numbers to
+ * names using 'port_map' (if provided).  If 'show_stats' is true, the output
+ * includes the flow duration, packet and byte counts, and its idle and hard
+ * ages, otherwise they are omitted. */
 void
 ofp_print_flow_stats(struct ds *string, const struct ofputil_flow_stats *fs,
-                     const struct ofputil_port_map *port_map)
+                     const struct ofputil_port_map *port_map, bool show_stats)
 {
-    ds_put_format(string, " %scookie=%s0x%"PRIx64", %sduration=%s",
-                  colors.param, colors.end, ntohll(fs->cookie),
-                  colors.param, colors.end);
-
-    ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
-    ds_put_format(string, ", %stable=%s%"PRIu8", ",
-                  colors.special, colors.end, fs->table_id);
-    ds_put_format(string, "%sn_packets=%s%"PRIu64", ",
-                  colors.param, colors.end, fs->packet_count);
-    ds_put_format(string, "%sn_bytes=%s%"PRIu64", ",
-                  colors.param, colors.end, fs->byte_count);
+    if (show_stats || fs->cookie) {
+        ds_put_format(string, "%scookie=%s0x%"PRIx64", ",
+                      colors.param, colors.end, ntohll(fs->cookie));
+    }
+    if (show_stats) {
+        ds_put_format(string, "%sduration=%s", colors.param, colors.end);
+        ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
+        ds_put_cstr(string, ", ");
+    }
+
+    if (show_stats || fs->table_id) {
+        ds_put_format(string, "%stable=%s%"PRIu8", ",
+                      colors.special, colors.end, fs->table_id);
+    }
+    if (show_stats) {
+        ds_put_format(string, "%sn_packets=%s%"PRIu64", ",
+                      colors.param, colors.end, fs->packet_count);
+        ds_put_format(string, "%sn_bytes=%s%"PRIu64", ",
+                      colors.param, colors.end, fs->byte_count);
+    }
     if (fs->idle_timeout != OFP_FLOW_PERMANENT) {
         ds_put_format(string, "%sidle_timeout=%s%"PRIu16", ",
                       colors.param, colors.end, fs->idle_timeout);
@@ -1712,17 +1725,20 @@ ofp_print_flow_stats(struct ds *string, const struct ofputil_flow_stats *fs,
         ds_put_format(string, "%simportance=%s%"PRIu16", ",
                       colors.param, colors.end, fs->importance);
     }
-    if (fs->idle_age >= 0) {
+    if (show_stats && fs->idle_age >= 0) {
         ds_put_format(string, "%sidle_age=%s%d, ",
                       colors.param, colors.end, fs->idle_age);
     }
-    if (fs->hard_age >= 0 && fs->hard_age != fs->duration_sec) {
+    if (show_stats && fs->hard_age >= 0 && fs->hard_age != fs->duration_sec) {
         ds_put_format(string, "%shard_age=%s%d, ",
                       colors.param, colors.end, fs->hard_age);
     }
 
+    /* Print the match, followed by a space (but omit the space if the match
+     * was an empty string). */
+    size_t length = string->length;
     match_format(&fs->match, port_map, string, fs->priority);
-    if (string->string[string->length - 1] != ' ') {
+    if (string->length != length) {
         ds_put_char(string, ' ');
     }
 
@@ -1749,8 +1765,8 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh,
             }
             break;
         }
-        ds_put_char(string, '\n');
-        ofp_print_flow_stats(string, &fs, port_map);
+        ds_put_cstr(string, "\n ");
+        ofp_print_flow_stats(string, &fs, port_map, true);
      }
     ofpbuf_uninit(&ofpacts);
 }
diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c
index e28a966e6dd7..fc9f8e5fd9f6 100644
--- a/ovn/utilities/ovn-sbctl.c
+++ b/ovn/utilities/ovn-sbctl.c
@@ -793,9 +793,9 @@ sbctl_dump_openflow(struct vconn *vconn, const struct uuid *uuid, bool stats)
 
             ds_clear(&s);
             if (stats) {
-                ofp_print_flow_stats(&s, fs, NULL);
+                ofp_print_flow_stats(&s, fs, NULL, true);
             } else {
-                ds_put_format(&s, " %stable=%s%"PRIu8" ",
+                ds_put_format(&s, "%stable=%s%"PRIu8" ",
                               colors.special, colors.end, fs->table_id);
                 match_format(&fs->match, NULL, &s, OFP_DEFAULT_PRIORITY);
                 if (ds_last(&s) != ' ') {
@@ -805,7 +805,7 @@ sbctl_dump_openflow(struct vconn *vconn, const struct uuid *uuid, bool stats)
                 ds_put_format(&s, "%sactions=%s", colors.actions, colors.end);
                 ofpacts_format(fs->ofpacts, fs->ofpacts_len, NULL, &s);
             }
-            printf("   %s\n", ds_cstr(&s));
+            printf("    %s\n", ds_cstr(&s));
         }
         ds_destroy(&s);
     }
diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
index ae42814de702..8bdb7d8a304d 100644
--- a/ovn/utilities/ovn-trace.c
+++ b/ovn/utilities/ovn-trace.c
@@ -1878,13 +1878,9 @@ trace_openflow(const struct ovntrace_flow *f, struct ovs_list *super)
         struct ds s = DS_EMPTY_INITIALIZER;
         for (size_t i = 0; i < n_fses; i++) {
             ds_clear(&s);
-            ofp_print_flow_stats(&s, &fses[i], NULL);
-
-            /* ofp_print_flow_stats() indents its output with a space.
-             * Omit it. */
-            const char *p = ds_cstr(&s);
-            p += strspn(p, " ");
-            ovntrace_node_append(super, OVNTRACE_NODE_ACTION, "%s", p);
+            ofp_print_flow_stats(&s, &fses[i], NULL, true);
+            ovntrace_node_append(super, OVNTRACE_NODE_ACTION,
+                                 "%s", ds_cstr(&s));
         }
         ds_destroy(&s);
     } else {
diff --git a/tests/bundle.at b/tests/bundle.at
index 0b6a19222ba5..40dfbea37e03 100644
--- a/tests/bundle.at
+++ b/tests/bundle.at
@@ -212,9 +212,8 @@ AT_SETUP([bundle action with many ports])
 AT_KEYWORDS([bundle_action])
 OVS_VSWITCHD_START
 AT_CHECK([ovs-ofctl add-flow br0 'actions=set_field:0x1->metadata,set_field:0x2->metadata,set_field:0x3->metadata,set_field:0x4->metadata,bundle(symmetric_l4,0,hrw,ofport,slaves:[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]])'])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats], [0], [dnl
  actions=load:0x1->OXM_OF_METADATA[[]],load:0x2->OXM_OF_METADATA[[]],load:0x3->OXM_OF_METADATA[[]],load:0x4->OXM_OF_METADATA[[]],bundle(symmetric_l4,0,hrw,ofport,slaves:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40)
-NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
diff --git a/tests/learn.at b/tests/learn.at
index 7dd4ca0e0ecc..72e22c4bf348 100644
--- a/tests/learn.at
+++ b/tests/learn.at
@@ -132,10 +132,9 @@ mv stdout expout
 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
 
 # Check for the MAC learning entry.
-AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
- table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 --no-stats --sort], [0], [dnl
  table=1, priority=0 actions=FLOOD
-NXST_FLOW reply:
+ table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
 ])
 
 # Trace a packet arrival destined for the learned MAC.
@@ -145,11 +144,10 @@ AT_CHECK([tail -1 stdout], [0], [Datapath actions: 3
 ])
 
 # Check for both MAC learning entries.
-AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip |sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 --no-stats | sort], [0], [dnl
  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:3
  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
  table=1, priority=0 actions=FLOOD
-NXST_FLOW reply:
 ])
 
 # Trace a packet arrival that updates the first learned MAC entry.
@@ -163,11 +161,10 @@ mv stdout expout
 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
 
 # Check that the MAC learning entry was updated.
-AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 --no-stats | sort], [0], [dnl
  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:05 actions=output:2
  table=1, hard_timeout=60, vlan_tci=0x0000/0x0fff,dl_dst=50:54:00:00:00:06 actions=output:1
  table=1, priority=0 actions=FLOOD
-NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -204,10 +201,9 @@ mv stdout expout
 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
 
 # Check that the MAC learning entry appeared.
-AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 --no-stats | sort], [0], [dnl
  table=1, hard_timeout=10, dl_dst=50:54:00:00:00:07 actions=output:3
  table=1, priority=0 actions=FLOOD
-NXST_FLOW reply:
 ])
 
 # For 25 seconds, make sure that the MAC learning entry doesn't
@@ -239,9 +235,8 @@ done
 # Make sure that 15 seconds without refreshing makes the flow time out.
 ovs-appctl time/warp 15000 5000
 sleep 1
-AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 --no-stats | sort], [0], [dnl
  table=1, priority=0 actions=FLOOD
-NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -265,9 +260,8 @@ mv stdout expout
 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
 
 # Check for the learning entry.
-AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 --no-stats | sort], [0], [dnl
  table=1, hard_timeout=60, tcp,nw_src=192.168.0.1,nw_dst=192.168.0.2,tp_src=80,tp_dst=40000 actions=drop
-NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -293,10 +287,9 @@ mv stdout expout
 AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
 
 # Check for the learning entry.
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  table=1, hard_timeout=60, tcp6,ipv6_src=fec0::1,ipv6_dst=2001:db8:85a3::8a2e:370:7334,tp_src=80,tp_dst=40000 actions=load:0x13198a2e03707348->NXM_NX_IPV6_DST[[0..63]],load:0x20010db885a308d3->NXM_NX_IPV6_DST[[64..127]]
  tcp6 actions=learn(table=1,hard_timeout=60,eth_type=0x86dd,nw_proto=6,NXM_NX_IPV6_SRC[[]]=NXM_NX_IPV6_DST[[]],ipv6_dst=2001:db8:85a3::8a2e:370:7334,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],NXM_OF_TCP_DST[[]]=NXM_OF_TCP_SRC[[]],load:0x20010db885a308d313198a2e03707348->NXM_NX_IPV6_DST[[]]),FLOOD
-NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -508,9 +501,8 @@ OVS_VSWITCHD_START(
     [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
 AT_CHECK([[ovs-ofctl add-flow br0 'actions=learn(fin_hard_timeout=10, fin_idle_timeout=5, NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[])']])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)' -generate], [0], [ignore])
-AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip], [0],
-[NXST_FLOW reply:
- table=1, dl_dst=50:54:00:00:00:05 actions=fin_timeout(idle_timeout=5,hard_timeout=10),output:1
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 --no-stats], [0],
+[ table=1, dl_dst=50:54:00:00:00:05 actions=fin_timeout(idle_timeout=5,hard_timeout=10),output:1
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -528,65 +520,59 @@ cookie=0x123, table=2, reg0=0x5 actions=drop
 cookie=0x234, table=1, reg0=0x6 actions=drop
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  cookie=0x123, table=1, reg0=0x3 actions=drop
  cookie=0x123, table=1, reg0=0x4 actions=drop
  cookie=0x123, table=2, reg0=0x5 actions=drop
  cookie=0x234, table=1, reg0=0x6 actions=drop
  reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
-NXST_FLOW reply:
 ])
 
 # Delete one of the learn actions.  The learned flows should stay, since there
 # is another learn action with the identical target.
 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  cookie=0x123, table=1, reg0=0x3 actions=drop
  cookie=0x123, table=1, reg0=0x4 actions=drop
  cookie=0x123, table=2, reg0=0x5 actions=drop
  cookie=0x234, table=1, reg0=0x6 actions=drop
  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x123)
-NXST_FLOW reply:
 ])
 
 # Change the flow with the learn action by adding a second action.  The learned
 # flows should stay because the learn action is still there.
 AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=output:1,learn(delete_learned,cookie=0x123)'])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  cookie=0x123, table=1, reg0=0x3 actions=drop
  cookie=0x123, table=1, reg0=0x4 actions=drop
  cookie=0x123, table=2, reg0=0x5 actions=drop
  cookie=0x234, table=1, reg0=0x6 actions=drop
  reg0=0x2 actions=output:1,learn(table=1,delete_learned,cookie=0x123)
-NXST_FLOW reply:
 ])
 
 # Change the flow with the learn action by replacing its learn action by one
 # with a different target.  The (previous) learned flows disappear.
 AT_CHECK([ovs-ofctl mod-flows br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234)'])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  cookie=0x123, table=2, reg0=0x5 actions=drop
  cookie=0x234, table=1, reg0=0x6 actions=drop
  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234)
-NXST_FLOW reply:
 ])
 
 # Use add-flow to replace the flow with the learn action by one with the
 # same learn action and an extra action.  The (new) learned flow remains.
 AT_CHECK([ovs-ofctl add-flow br0 'table=0 reg0=2 actions=learn(delete_learned,cookie=0x234),output:2'])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  cookie=0x123, table=2, reg0=0x5 actions=drop
  cookie=0x234, table=1, reg0=0x6 actions=drop
  reg0=0x2 actions=learn(table=1,delete_learned,cookie=0x234),output:2
-NXST_FLOW reply:
 ])
 
 # Delete the flow with the learn action.  The learned flow disappears too.
 AT_CHECK([ovs-ofctl del-flows br0 table=0])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  cookie=0x123, table=2, reg0=0x5 actions=drop
-NXST_FLOW reply:
 ])
 
 # Add a new set of flows to check on a corner case: the learned flows
@@ -608,7 +594,7 @@ cookie=0x567, table=5, reg0=0x8 actions=drop
 ])
 AT_CHECK([ovs-ofctl del-flows br0])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  cookie=0x123, table=1, reg0=0x3 actions=learn(table=3,delete_learned,cookie=0x345)
  cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
  cookie=0x345, table=3, reg0=0x4 actions=learn(table=5,delete_learned,cookie=0x567)
@@ -618,28 +604,24 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
  cookie=0x567, table=5, reg0=0x8 actions=drop
  reg0=0x1 actions=learn(table=1,delete_learned,cookie=0x123)
  reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
-NXST_FLOW reply:
 ])
 
 # Deleting the flow with reg0=1 should cascade to delete a few levels
 # of learned flows, but the ones with cookie=0x567 stick around
 # because of the flow with cookie=0x456.
 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=1'])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort], [0], [dnl
  cookie=0x234, table=2, reg0=0x3 actions=learn(table=4,delete_learned,cookie=0x456)
  cookie=0x456, table=4, reg0=0x5 actions=learn(table=5,delete_learned,cookie=0x567)
  cookie=0x567, table=5, reg0=0x6 actions=drop
  cookie=0x567, table=5, reg0=0x7 actions=drop
  cookie=0x567, table=5, reg0=0x8 actions=drop
  reg0=0x2 actions=learn(table=2,delete_learned,cookie=0x234)
-NXST_FLOW reply:
 ])
 
 # Deleting the flow with reg0=2 should cascade to delete all the rest:
 AT_CHECK([ovs-ofctl del-flows br0 'table=0 reg0=2'])
-AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
-NXST_FLOW reply:
-])
+AT_CHECK([ovs-ofctl dump-flows br0 --no-stats | sort])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
@@ -656,9 +638,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 
 OVS_WAIT_UNTIL([ovs-ofctl dump-ports br0 2 | grep -o 'tx pkts=2' >/dev/null])
 
-AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 --no-stats], [0], [dnl
  cookie=0x1, table=1, dl_dst=50:54:00:00:00:01 actions=drop
-NXST_FLOW reply:
 ])
 
 dnl Delete the learned flow
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 3b86c0d73c1c..65525908a7c7 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -222,8 +222,11 @@ syntax of \fIflows\fR.  The output format is described in
 .IP
 By default, \fBovs\-ofctl\fR prints flow entries in the same order
 that the switch sends them, which is unlikely to be intuitive or
-consistent.  See the description of \fB\-\-sort\fR and \fB\-\-rsort\fR,
-under \fBOPTIONS\fR below, to influence the display order.
+consistent.  Use \fB\-\-sort\fR and \fB\-\-rsort\fR to control display
+order.  The \fB\-\-names\fR/\fB\-\-no\-names\fR and
+\fB\-\-stats\fR/\fB\-\-no\-stats\fR options also affect output
+formatting.  See the descriptions of these options, under
+\fBOPTIONS\fR below, for more information
 .
 .TP
 \fBdump\-aggregate \fIswitch \fR[\fIflows\fR]
@@ -2222,6 +2225,13 @@ be the same; when a switch has two ports with the same (truncated)
 name, \fBovs\-ofctl\fR refuses to display or accept the name, using
 the number instead.
 .
+.IP "\fB\-\-stats\fR"
+.IQ "\fB\-\-no\-stats\fR"
+The \fBdump\-flows\fR command by default, or with \fB\-\-stats\fR,
+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\-\-read-only\fR"
 Do not execute read/write commands.
 .
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index dca9be3a5995..a4170a2c54e7 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -135,6 +135,9 @@ static const struct ofputil_port_map *ports_to_show(const char *vconn_name);
 static bool should_accept_ports(void);
 static bool should_show_ports(void);
 
+/* --stats, --no-stats: Show statistics in flow dumps? */
+static int show_stats = 1;
+
 static const struct ovs_cmdl_command *get_all_commands(void);
 
 OVS_NO_RETURN static void usage(void);
@@ -212,6 +215,8 @@ parse_options(int argc, char *argv[])
         {"rsort", optional_argument, NULL, OPT_RSORT},
         {"names", no_argument, &use_port_names, 1},
         {"no-names", no_argument, &use_port_names, 0},
+        {"stats", no_argument, &show_stats, 1},
+        {"no-stats", no_argument, &show_stats, 0},
         {"unixctl",     required_argument, NULL, OPT_UNIXCTL},
         {"help", no_argument, NULL, 'h'},
         {"option", no_argument, NULL, 'o'},
@@ -1355,7 +1360,7 @@ compare_flows(const void *afs_, const void *bfs_)
 static void
 ofctl_dump_flows(struct ovs_cmdl_context *ctx)
 {
-    if (!n_criteria && !should_show_ports()) {
+    if (!n_criteria && !should_show_ports() && show_stats) {
         ofctl_dump_flows__(ctx->argc, ctx->argv, false);
         return;
     } else {
@@ -1376,8 +1381,9 @@ ofctl_dump_flows(struct ovs_cmdl_context *ctx)
         struct ds s = DS_EMPTY_INITIALIZER;
         for (size_t i = 0; i < n_fses; i++) {
             ds_clear(&s);
-            ofp_print_flow_stats(&s, &fses[i], ports_to_show(ctx->argv[1]));
-            puts(ds_cstr(&s));
+            ofp_print_flow_stats(&s, &fses[i], ports_to_show(ctx->argv[1]),
+                                 show_stats);
+            printf(" %s\n", ds_cstr(&s));
         }
         ds_destroy(&s);
 
-- 
2.10.2



More information about the dev mailing list