This allows users to fetch a flow by giving a particular UFID.

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

Signed-off-by: Joe Stringer <joestrin...@nicira.com>
---
 lib/dpctl.c           |   96 +++++++++++++++++++++++++++++++++++++++++--------
 lib/dpctl.man         |    4 +++
 utilities/ovs-dpctl.c |    1 +
 3 files changed, 86 insertions(+), 15 deletions(-)

diff --git a/lib/dpctl.c b/lib/dpctl.c
index d3d4b7f..8eec944 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -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);
@@ -919,6 +926,64 @@ dpctl_mod_flow(int argc, const char *argv[], struct 
dpctl_params *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)
 {
     const char *key_s = argv[argc - 1];
@@ -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 },
diff --git a/lib/dpctl.man b/lib/dpctl.man
index c678576..4e34630 100644
--- a/lib/dpctl.man
+++ b/lib/dpctl.man
@@ -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 hexadecimal characters.
+.
 .IP "\*(DX\fBdel\-flows\fR [\fIdp\fR]"
 Deletes all flow entries from datapath \fIdp\fR's flow table.
diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c
index 404a428..9d279f0 100644
--- a/utilities/ovs-dpctl.c
+++ b/utilities/ovs-dpctl.c
@@ -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"
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to