dpctl: Add 'get-flow' command.
authorJoe Stringer <joestringer@nicira.com>
Fri, 5 Dec 2014 22:45:51 +0000 (14:45 -0800)
committerJoe Stringer <joestringer@nicira.com>
Fri, 19 Dec 2014 21:11:47 +0000 (13:11 -0800)
This allows users to fetch a flow by giving a particular UFID.

Usage: 'ovs-dpctl get-flow ufid:<ufid>'
Usage: 'ovs-appctl dpctl/get-flow ufid:<ufid>'

Signed-off-by: Joe Stringer <joestringer@nicira.com>
Acked-by: Andy Zhou <azhou@nicira.com>
lib/dpctl.c
lib/dpctl.man
tests/ofproto-dpif.at
utilities/ovs-dpctl.c

index d3d4b7f..8eec944 100644 (file)
@@ -689,6 +689,27 @@ dpctl_dump_dps(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
     return lasterror;
 }
 
+static void
+format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports,
+                 struct dpctl_params *dpctl_p)
+{
+    if (dpctl_p->verbosity) {
+        if (f->ufid_present) {
+            odp_format_ufid(&f->ufid, ds);
+            ds_put_cstr(ds, ", ");
+        } else {
+            ds_put_cstr(ds, "ufid:<empty>, ");
+        }
+    }
+    odp_flow_format(f->key, f->key_len, f->mask, f->mask_len, ports, ds,
+                    dpctl_p->verbosity);
+    ds_put_cstr(ds, ", ");
+
+    dpif_flow_stats_format(&f->stats, ds);
+    ds_put_cstr(ds, ", actions:");
+    format_odp_actions(ds, f->actions, f->actions_len);
+}
+
 static int
 dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
 {
@@ -771,21 +792,7 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
             minimatch_destroy(&minimatch);
         }
         ds_clear(&ds);
-        if (dpctl_p->verbosity) {
-            if (f.ufid_present) {
-                odp_format_ufid(&f.ufid, &ds);
-                ds_put_cstr(&ds, ", ");
-            } else {
-                ds_put_cstr(&ds, "ufid:<empty>, ");
-            }
-        }
-        odp_flow_format(f.key, f.key_len, f.mask, f.mask_len,
-                        &portno_names, &ds, dpctl_p->verbosity);
-        ds_put_cstr(&ds, ", ");
-
-        dpif_flow_stats_format(&f.stats, &ds);
-        ds_put_cstr(&ds, ", actions:");
-        format_odp_actions(&ds, f.actions, f.actions_len);
+        format_dpif_flow(&ds, &f, &portno_names, dpctl_p);
         dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
     }
     dpif_flow_dump_thread_destroy(flow_dump_thread);
@@ -918,6 +925,64 @@ dpctl_mod_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
     return dpctl_put_flow(argc, argv, flags, dpctl_p);
 }
 
+static int
+dpctl_get_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
+{
+    const char *key_s = argv[argc - 1];
+    struct dpif_flow flow;
+    struct dpif_port dpif_port;
+    struct dpif_port_dump port_dump;
+    struct dpif *dpif;
+    char *dp_name;
+    struct hmap portno_names;
+    ovs_u128 ufid;
+    struct ofpbuf buf;
+    uint64_t stub[DPIF_FLOW_BUFSIZE / 8];
+    struct ds ds;
+    int n, error;
+
+    dp_name = argc == 3 ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
+    if (!dp_name) {
+        return EINVAL;
+    }
+    error = parsed_dpif_open(dp_name, false, &dpif);
+    free(dp_name);
+    if (error) {
+        dpctl_error(dpctl_p, error, "opening datapath");
+        return error;
+    }
+
+    ofpbuf_use_stub(&buf, &stub, sizeof stub);
+    hmap_init(&portno_names);
+    DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
+        odp_portno_names_set(&portno_names, dpif_port.port_no, dpif_port.name);
+    }
+
+    n = odp_ufid_from_string(key_s, &ufid);
+    if (n <= 0) {
+        dpctl_error(dpctl_p, -n, "parsing flow ufid");
+        goto out;
+    }
+
+    error = dpif_flow_get(dpif, NULL, 0, &ufid, &buf, &flow);
+    if (error) {
+        dpctl_error(dpctl_p, error, "getting flow");
+        goto out;
+    }
+
+    ds_init(&ds);
+    format_dpif_flow(&ds, &flow, &portno_names, dpctl_p);
+    dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
+    ds_destroy(&ds);
+
+out:
+    odp_portno_names_destroy(&portno_names);
+    hmap_destroy(&portno_names);
+    ofpbuf_uninit(&buf);
+    dpif_close(dpif);
+    return error;
+}
+
 static int
 dpctl_del_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
 {
@@ -1339,6 +1404,7 @@ static const struct dpctl_command all_commands[] = {
     { "dump-flows", "[dp]", 0, 2, dpctl_dump_flows },
     { "add-flow", "add-flow [dp] flow actions", 2, 3, dpctl_add_flow },
     { "mod-flow", "mod-flow [dp] flow actions", 2, 3, dpctl_mod_flow },
+    { "get-flow", "get-flow [dp] ufid", 1, 2, dpctl_get_flow },
     { "del-flow", "del-flow [dp] flow", 1, 2, dpctl_del_flow },
     { "del-flows", "[dp]", 0, 1, dpctl_del_flows },
     { "help", "", 0, INT_MAX, dpctl_help },
index c678576..7fa7285 100644 (file)
@@ -143,5 +143,9 @@ Deletes the flow from \fIdp\fR's flow table that matches \fIflow\fR.
 If \fB\-s\fR or \fB\-\-statistics\fR is specified, then
 \fBmod\-flows\fR prints the deleted flow's statistics.
 .
+.IP "\*(DX\fBget\-flow\fR [\fIdp\fR] ufid:\fIufid\fR"
+Fetches the flow from \fIdp\fR's flow table with unique identifier \fIufid\fR.
+\fIufid\fR must be specified as a string of 32 hexadecimal characters.
+.
 .IP "\*(DX\fBdel\-flows\fR [\fIdp\fR]"
 Deletes all flow entries from datapath \fIdp\fR's flow table.
index 231c57f..54a5209 100644 (file)
@@ -5151,6 +5151,25 @@ skb_priority(0/0),skb_mark(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),eth(src=50
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - ovs-appctl dpif/get-flow])
+
+OVS_VSWITCHD_START([add-br br1 -- \
+                    set bridge br1 datapath-type=dummy fail-mode=secure -- \
+                    set Open_vSwitch . other_config:max-idle=10000])
+ADD_OF_PORTS([br0], [1], [2])
+
+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)'])
+ovs-appctl revalidator/wait
+AT_CHECK([ovs-appctl dpif/dump-flows -m br0], [0], [stdout])
+
+UFID=`sed -n 's/\(ufid:[[0-9a-fA-F]]*\).*/\1/p' stdout`
+AT_CHECK([ovs-appctl dpctl/get-flow $UFID], [0], [dnl
+recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - MPLS actions that result in a userspace action])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
index 404a428..9d279f0 100644 (file)
@@ -168,6 +168,7 @@ usage(void *userdata OVS_UNUSED)
            "  dump-flows [DP]          display flows in DP\n"
            "  add-flow [DP] FLOW ACTIONS add FLOW with ACTIONS to DP\n"
            "  mod-flow [DP] FLOW ACTIONS change FLOW actions to ACTIONS in DP\n"
+           "  get-flow [DP] ufid:UFID    fetch flow corresponding to UFID\n"
            "  del-flow [DP] FLOW         delete FLOW from DP\n"
            "  del-flows [DP]             delete all flows from DP\n"
            "Each IFACE on add-dp, add-if, and set-if may be followed by\n"