[ovs-dev] [Single DP 10/15] ofproto-dpif: Add ovs-appctl commands for ovs-dpctl functions.

Justin Pettit jpettit at nicira.com
Thu Oct 18 19:51:55 UTC 2012


These commands will be useful in a future commit that makes multiple
bridges share a single backing datapath.  The ovs-dpctl commands will
show information about the backing datapath, so it will be difficult to
determine which information belongs to which bridge.  The new "dpif/*"
ovs-appctl commands return information about the bridge--regardless of
how the backing datapath is configured.

Signed-off-by: Justin Pettit <jpettit at nicira.com>
---
 NEWS                             |    3 +
 manpages.mk                      |    2 +
 ofproto/automake.mk              |    2 +-
 ofproto/ofproto-dpif-unixctl.man |   33 ++++++
 ofproto/ofproto-dpif.c           |  200 ++++++++++++++++++++++++++++++++++++++
 tests/ofproto-dpif.at            |  100 +++++++++++++++++++
 tests/ofproto-macros.at          |    1 +
 vswitchd/ovs-vswitchd.8.in       |    2 +
 8 files changed, 342 insertions(+), 1 deletions(-)
 create mode 100644 ofproto/ofproto-dpif-unixctl.man

diff --git a/NEWS b/NEWS
index 99e239a..97097dd 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,9 @@ post-v1.8.0
     - ovs-dpctl:
       - Support requesting the port number with the "port_no" option in
         the "add-if" command.
+    - ovs-appctl:
+      - New "dpif/dump-dps", "dpif/show", and "dpif/dump-flows" command
+        that mimic the equivalent ovs-dpctl commands.
     - ovs-pki: The "online PKI" features have been removed, along with
       the ovs-pki-cgi program that facilitated it, because of some
       alarmist insecurity claims.  We do not believe that these claims
diff --git a/manpages.mk b/manpages.mk
index 01700c3..c878144 100644
--- a/manpages.mk
+++ b/manpages.mk
@@ -241,6 +241,7 @@ vswitchd/ovs-vswitchd.8: \
 	lib/stress-unixctl.man \
 	lib/vlog-unixctl.man \
 	lib/vlog.man \
+	ofproto/ofproto-dpif-unixctl.man \
 	ofproto/ofproto-unixctl.man \
 	ovsdb/remote-active.man \
 	ovsdb/remote-passive.man
@@ -254,6 +255,7 @@ lib/ssl.man:
 lib/stress-unixctl.man:
 lib/vlog-unixctl.man:
 lib/vlog.man:
+ofproto/ofproto-dpif-unixctl.man:
 ofproto/ofproto-unixctl.man:
 ovsdb/remote-active.man:
 ovsdb/remote-passive.man:
diff --git a/ofproto/automake.mk b/ofproto/automake.mk
index ab889af..9088292 100644
--- a/ofproto/automake.mk
+++ b/ofproto/automake.mk
@@ -31,4 +31,4 @@ ofproto_libofproto_a_SOURCES = \
 	ofproto/pinsched.c \
 	ofproto/pinsched.h
 
-MAN_FRAGMENTS += ofproto/ofproto-unixctl.man
+MAN_FRAGMENTS += ofproto/ofproto-unixctl.man ofproto/ofproto-dpif-unixctl.man
diff --git a/ofproto/ofproto-dpif-unixctl.man b/ofproto/ofproto-dpif-unixctl.man
new file mode 100644
index 0000000..1d9054d
--- /dev/null
+++ b/ofproto/ofproto-dpif-unixctl.man
@@ -0,0 +1,33 @@
+.SS "DATAPATH COMMANDS"
+These commands manage logical datapaths.  They are are similar to the
+equivalent \fBovs\-dpctl\fR commands.
+.
+.IP "\fBdpif/dump\-dps\fR"
+Prints the name of each configured datapath on a separate line.
+.
+.IP "\fBdpif/show\fR [\fIdp\fR]"
+Prints a summary of configured datapaths, including statistics and a
+list of connected ports.  The port information includes the OpenFlow
+port number, datapath port number, and the type.  (The local port is
+identified as OpenFlow port 65534.)
+.IP
+If datapath \fIdp\fR is specified, information on only that datapath is
+displayed.  Otherwise, information about all configured datapaths are
+shown.
+.
+.IP "\fBdpif/dump\-flows \fIdp\fR"
+Prints to the console all flow entries in datapath \fIdp\fR's
+flow table.
+.IP
+This command is primarily useful for debugging Open vSwitch.  The flow
+table entries that it displays are not OpenFlow flow entries.  Instead,
+they are different and considerably simpler flows maintained by the
+datapath module.
+.
+.IP "\fBdpif/del\-flows \fIdp\fR"
+Deletes all flow entries from datapath \fIdp\fR's flow table and
+underlying datapath implementation (e.g., kernel datapath module).
+.IP
+This command is primarily useful for debugging Open vSwitch.  As
+discussed in \fBdpif/dump\-flows\fR, these entries are
+not OpenFlow flow entries.
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index ab9e56f..0c0202b 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -49,6 +49,7 @@
 #include "ofproto-dpif-sflow.h"
 #include "poll-loop.h"
 #include "simap.h"
+#include "smap.h"
 #include "timer.h"
 #include "unaligned.h"
 #include "unixctl.h"
@@ -7024,6 +7025,197 @@ ofproto_dpif_self_check(struct unixctl_conn *conn,
 }
 
 static void
+ofproto_unixctl_dpif_dump_dps(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                              const char *argv[] OVS_UNUSED,
+                              void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    const struct ofproto_dpif *ofproto;
+    struct shash ofproto_shash = SHASH_INITIALIZER(&ofproto_shash);
+    const struct shash_node **sorted_ofprotos;
+    int i;
+
+    HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+        shash_add(&ofproto_shash, ofproto->up.name, ofproto);
+    }
+
+    sorted_ofprotos = shash_sort(&ofproto_shash);
+    for (i = 0; i < shash_count(&ofproto_shash); i++) {
+        const struct shash_node *node = sorted_ofprotos[i];
+
+        ofproto = node->data;
+        ds_put_format(&ds, "%s@%s\n", ofproto->up.type, ofproto->up.name);
+    }
+
+    shash_destroy(&ofproto_shash);
+    free(sorted_ofprotos);
+
+    unixctl_command_reply(conn, ds_cstr(&ds));
+    ds_destroy(&ds);
+}
+
+static void
+show_dp_format(const struct ofproto_dpif *ofproto, struct ds *ds)
+{
+    struct dpif_dp_stats s;
+    const struct shash_node **ports;
+    int i;
+
+    dpif_get_dp_stats(ofproto->dpif, &s);
+
+    ds_put_format(ds, "%s@%s\n", ofproto->up.type, ofproto->up.name);
+    ds_put_format(ds,
+                  "\tlookups: hit:%"PRIu64" missed:%"PRIu64" lost:%"PRIu64"\n",
+                  s.n_hit, s.n_missed, s.n_lost);
+    ds_put_format(ds, "\tflows: %"PRIu64"\n", s.n_flows);
+
+    ports = shash_sort(&ofproto->up.port_by_name);
+    for (i = 0; i < shash_count(&ofproto->up.port_by_name); i++) {
+        const struct shash_node *node = ports[i];
+        struct ofport *ofport = node->data;
+        const char *name = netdev_get_name(ofport->netdev);
+        const char *type = netdev_get_type(ofport->netdev);
+
+        ds_put_format(ds, "\t%s %u/%u:", name, ofport->ofp_port,
+                      ofp_port_to_odp_port(ofproto, ofport->ofp_port));
+        if (strcmp(type, "system")) {
+            struct netdev *netdev;
+            int error;
+
+            ds_put_format(ds, " (%s", type);
+
+            error = netdev_open(name, type, &netdev);
+            if (!error) {
+                struct smap config;
+
+                smap_init(&config);
+                error = netdev_get_config(netdev, &config);
+                if (!error) {
+                    const struct smap_node **nodes;
+                    size_t i;
+
+                    nodes = smap_sort(&config);
+                    for (i = 0; i < smap_count(&config); i++) {
+                        const struct smap_node *node = nodes[i];
+                        ds_put_format(ds, "%c %s=%s", i ? ',' : ':',
+                                      node->key, node->value);
+                    }
+                    free(nodes);
+                }
+                smap_destroy(&config);
+
+                netdev_close(netdev);
+            }
+            ds_put_char(ds, ')');
+        }
+        ds_put_char(ds, '\n');
+    }
+    free(ports);
+}
+
+static void
+ofproto_unixctl_dpif_show(struct unixctl_conn *conn, int argc,
+                          const char *argv[], void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    const struct ofproto_dpif *ofproto;
+
+    if (argc > 1) {
+        ofproto = ofproto_dpif_lookup(argv[1]);
+        if (!ofproto) {
+            unixctl_command_reply_error(conn, "Unknown bridge (use "
+                                        "dpif/dump-dps for help)");
+            return;
+        }
+        show_dp_format(ofproto, &ds);
+    } else {
+        struct shash ofproto_shash = SHASH_INITIALIZER(&ofproto_shash);
+        const struct shash_node **sorted_ofprotos;
+        int i;
+
+        HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+            shash_add(&ofproto_shash, ofproto->up.name, ofproto);
+        }
+
+        sorted_ofprotos = shash_sort(&ofproto_shash);
+        for (i = 0; i < shash_count(&ofproto_shash); i++) {
+            const struct shash_node *node = sorted_ofprotos[i];
+            show_dp_format(node->data, &ds);
+        }
+
+        shash_destroy(&ofproto_shash);
+        free(sorted_ofprotos);
+    }
+
+    unixctl_command_reply(conn, ds_cstr(&ds));
+    ds_destroy(&ds);
+}
+
+static void
+ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
+                                int argc OVS_UNUSED, const char *argv[],
+                                void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    const struct ofproto_dpif *ofproto;
+    struct subfacet *subfacet;
+
+    ofproto = ofproto_dpif_lookup(argv[1]);
+    if (!ofproto) {
+        unixctl_command_reply_error(conn, "no such bridge");
+        return;
+    }
+
+    HMAP_FOR_EACH (subfacet, hmap_node, &ofproto->subfacets) {
+        struct odputil_keybuf keybuf;
+        struct ofpbuf key;
+
+        subfacet_get_key(subfacet, &keybuf, &key);
+        odp_flow_key_format(key.data, key.size, &ds);
+
+        ds_put_format(&ds, ", packets:%"PRIu64", bytes:%"PRIu64", used:",
+                      subfacet->dp_packet_count, subfacet->dp_byte_count);
+        if (subfacet->used) {
+            ds_put_format(&ds, "%.3fs",
+                          (time_msec() - subfacet->used) / 1000.0);
+        } else {
+            ds_put_format(&ds, "never");
+        }
+        if (subfacet->facet->tcp_flags) {
+            ds_put_cstr(&ds, ", flags:");
+            packet_format_tcp_flags(&ds, subfacet->facet->tcp_flags);
+        }
+
+        ds_put_cstr(&ds, ", actions:");
+        format_odp_actions(&ds, subfacet->actions, subfacet->actions_len);
+        ds_put_char(&ds, '\n');
+    }
+
+    unixctl_command_reply(conn, ds_cstr(&ds));
+    ds_destroy(&ds);
+}
+
+static void
+ofproto_unixctl_dpif_del_flows(struct unixctl_conn *conn,
+                               int argc OVS_UNUSED, const char *argv[],
+                               void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    struct ofproto_dpif *ofproto;
+
+    ofproto = ofproto_dpif_lookup(argv[1]);
+    if (!ofproto) {
+        unixctl_command_reply_error(conn, "no such bridge");
+        return;
+    }
+
+    flush(&ofproto->up);
+
+    unixctl_command_reply(conn, ds_cstr(&ds));
+    ds_destroy(&ds);
+}
+
+static void
 ofproto_dpif_unixctl_init(void)
 {
     static bool registered;
@@ -7046,6 +7238,14 @@ ofproto_dpif_unixctl_init(void)
                              ofproto_dpif_unclog, NULL);
     unixctl_command_register("ofproto/self-check", "[bridge]", 0, 1,
                              ofproto_dpif_self_check, NULL);
+    unixctl_command_register("dpif/dump-dps", "", 0, 0,
+                             ofproto_unixctl_dpif_dump_dps, NULL);
+    unixctl_command_register("dpif/show", "[bridge]", 0, 1,
+                             ofproto_unixctl_dpif_show, NULL);
+    unixctl_command_register("dpif/dump-flows", "bridge", 1, 1,
+                             ofproto_unixctl_dpif_dump_flows, NULL);
+    unixctl_command_register("dpif/del-flows", "bridge", 1, 1,
+                             ofproto_unixctl_dpif_del_flows, NULL);
 }
 
 /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index b695e16..05ba30a 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -1192,3 +1192,103 @@ AT_CHECK([ovs-ofctl dump-flows test-br0 | ofctl_strip], [0],
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - ovs-appctl dpif/dump-dps])
+OVS_VSWITCHD_START([add-br test-br1 -- set bridge test-br1 datapath-type=dummy])
+ADD_OF_PORTS([test-br0], [1], [2])
+ADD_OF_PORTS([test-br1], [3])
+
+AT_CHECK([ovs-appctl dpif/dump-dps], [0], [dnl
+dummy at test-br0
+dummy at test-br1
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - ovs-appctl dpif/show])
+OVS_VSWITCHD_START([add-br test-br1 -- set bridge test-br1 datapath-type=dummy])
+ADD_OF_PORTS([test-br0], [1], [2])
+ADD_OF_PORTS([test-br1], [3])
+
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+dummy at test-br0
+	lookups: hit:0 missed:0 lost:0
+	flows: 0
+	p1 1/1: (dummy)
+	p2 2/2: (dummy)
+	test-br0 65534/100: (dummy)
+dummy at test-br1
+	lookups: hit:0 missed:0 lost:0
+	flows: 0
+	p3 3/3: (dummy)
+	test-br1 65534/101: (dummy)
+])
+
+AT_CHECK([ovs-appctl dpif/show test-br0], [0], [dnl
+dummy at test-br0
+	lookups: hit:0 missed:0 lost:0
+	flows: 0
+	p1 1/1: (dummy)
+	p2 2/2: (dummy)
+	test-br0 65534/100: (dummy)
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - ovs-appctl dpif/dump-flows])
+OVS_VSWITCHD_START([add-br test-br1 -- \
+                    set bridge test-br1 datapath-type=dummy fail-mode=secure])
+ADD_OF_PORTS([test-br0], [1], [2])
+ADD_OF_PORTS([test-br1], [3])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
+])
+AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'], [0], [success
+])
+AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
+])
+
+AT_CHECK([ovs-appctl dpif/dump-flows test-br0 | sort | STRIP_USED], [0], [dnl
+in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+])
+
+AT_CHECK([ovs-appctl dpif/dump-flows test-br1 | sort | STRIP_USED], [0], [dnl
+in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - ovs-appctl dpif/del-flows])
+OVS_VSWITCHD_START([add-br test-br1 -- \
+                    set bridge test-br1 datapath-type=dummy fail-mode=secure])
+ADD_OF_PORTS([test-br0], [1], [2])
+ADD_OF_PORTS([test-br1], [3])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
+])
+AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'], [0], [success
+])
+AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
+])
+
+AT_CHECK([ovs-appctl dpif/dump-flows test-br0 | sort | STRIP_USED], [0], [dnl
+in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+])
+
+AT_CHECK([ovs-appctl dpif/dump-flows test-br1 | sort | STRIP_USED], [0], [dnl
+in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+])
+
+AT_CHECK([ovs-appctl dpif/del-flows test-br0])
+AT_CHECK([ovs-appctl dpif/dump-flows test-br0 | sort | STRIP_USED], [0], [dnl
+])
+
+AT_CHECK([ovs-appctl dpif/dump-flows test-br1 | sort | STRIP_USED], [0], [dnl
+in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
index 1fe8f8d..3c014d4 100644
--- a/tests/ofproto-macros.at
+++ b/tests/ofproto-macros.at
@@ -18,6 +18,7 @@ m4_divert_pop([PREPARE_TESTS])
 
 m4_define([STRIP_XIDS], [[sed 's/ (xid=0x[0-9a-fA-F]*)//']])
 m4_define([STRIP_DURATION], [[sed 's/\bduration=[0-9.]*s/duration=?s/']])
+m4_define([STRIP_USED], [[sed 's/used:[0-9]\.[0-9]*/used:0.0/']])
 m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m'])
 
 # OVS_VSWITCHD_START([vsctl-args], [vsctl-output])
diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in
index 5a959dd..7ddaf20 100644
--- a/vswitchd/ovs-vswitchd.8.in
+++ b/vswitchd/ovs-vswitchd.8.in
@@ -124,6 +124,7 @@ interfaces if none is given) to be \fIstatus\fR.  \fIstatus\fR can be
 Forces a topology change event on \fIbridge\fR if it's running STP.  This
 may cause it to send Topology Change Notifications to its peers and flush
 its MAC table..  If no \fIbridge\fR is given, forces a topology change
+.
 event on all bridges.
 .SS "BRIDGE COMMANDS"
 These commands manage bridges.
@@ -204,6 +205,7 @@ information, and partner information.  If \fIport\fR is not specified,
 then displays detailed information about all interfaces with CFM
 enabled.
 .
+.so ofproto/ofproto-dpif-unixctl.man
 .so ofproto/ofproto-unixctl.man
 .so lib/vlog-unixctl.man
 .so lib/memory-unixctl.man
-- 
1.7.5.4




More information about the dev mailing list