diff mbox

[ovs-dev,ovs,V6,21/24] dpctl: Add an option to dump only certain kinds of flows

Message ID 1490791414-11875-22-git-send-email-roid@mellanox.com
State Changes Requested
Headers show

Commit Message

Roi Dayan March 29, 2017, 12:43 p.m. UTC
From: Paul Blakey <paulb@mellanox.com>

Usage:
    # to dump all datapath flows (default):
    ovs-dpctl dump-flows

    # to dump only flows that in kernel datapath:
    ovs-dpctl dump-flows type=ovs

    # to dump only flows that are offloaded:
    ovs-dpctl dump-flows type=offloaded

Signed-off-by: Paul Blakey <paulb@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
---
 lib/dpctl.c                   | 21 ++++++++++-----
 lib/dpctl.man                 |  7 ++++-
 lib/dpif-netdev.c             |  3 ++-
 lib/dpif-netlink.c            | 62 ++++++++++++++++++++++++++++++++++---------
 lib/dpif-provider.h           |  6 +++--
 lib/dpif.c                    |  4 +--
 lib/dpif.h                    |  3 ++-
 ofproto/ofproto-dpif-upcall.c |  3 ++-
 ofproto/ofproto-dpif.c        |  2 +-
 9 files changed, 84 insertions(+), 27 deletions(-)
diff mbox

Patch

diff --git a/lib/dpctl.c b/lib/dpctl.c
index 11be857..f534de2 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -762,6 +762,7 @@  dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
     char *name;
 
     char *filter = NULL;
+    char *type = NULL;
     struct flow flow_filter;
     struct flow_wildcards wc_filter;
 
@@ -774,22 +775,29 @@  dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
     struct dpif_flow_dump *flow_dump;
     struct dpif_flow f;
     int pmd_id = PMD_ID_NULL;
+    int lastargc = 0;
     int error;
 
-    if (argc > 1 && !strncmp(argv[argc - 1], "filter=", 7)) {
-        filter = xstrdup(argv[--argc] + 7);
+    while (argc > 1 && lastargc != argc) {
+        lastargc = argc;
+        if (!strncmp(argv[argc - 1], "filter=", 7)) {
+            filter = xstrdup(argv[--argc] + 7);
+        } else if (!strncmp(argv[argc - 1], "type=", 5)) {
+            type = xstrdup(argv[--argc] + 5);
+        }
     }
+
     name = (argc == 2) ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
     if (!name) {
         error = EINVAL;
-        goto out_freefilter;
+        goto out_free;
     }
 
     error = parsed_dpif_open(name, false, &dpif);
     free(name);
     if (error) {
         dpctl_error(dpctl_p, error, "opening datapath");
-        goto out_freefilter;
+        goto out_free;
     }
 
 
@@ -818,7 +826,7 @@  dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
     BUILD_ASSERT(PMD_ID_NULL != NON_PMD_CORE_ID);
 
     ds_init(&ds);
-    flow_dump = dpif_flow_dump_create(dpif, false);
+    flow_dump = dpif_flow_dump_create(dpif, false, (type ? type : "dpctl"));
     flow_dump_thread = dpif_flow_dump_thread_create(flow_dump);
     while (dpif_flow_dump_next(flow_dump_thread, &f, 1)) {
         if (filter) {
@@ -870,8 +878,9 @@  out_dpifclose:
     simap_destroy(&names_portno);
     hmap_destroy(&portno_names);
     dpif_close(dpif);
-out_freefilter:
+out_free:
     free(filter);
+    free(type);
     return error;
 }
 
diff --git a/lib/dpctl.man b/lib/dpctl.man
index 2fcbc94..efd459f 100644
--- a/lib/dpctl.man
+++ b/lib/dpctl.man
@@ -99,7 +99,7 @@  default.  When multiple datapaths exist, then a datapath name is
 required.
 .
 .TP
-.DO "[\fB\-m \fR| \fB\-\-more\fR]" \*(DX\fBdump\-flows\fR "[\fIdp\fR] [\fBfilter=\fIfilter\fR]"
+.DO "[\fB\-m \fR| \fB\-\-more\fR]" \*(DX\fBdump\-flows\fR "[\fIdp\fR] [\fBfilter=\fIfilter\fR] [\fBtype=\fItype\fR]"
 Prints to the console all flow entries in datapath \fIdp\fR's flow
 table.  Without \fB\-m\fR or \fB\-\-more\fR, output omits match fields
 that a flow wildcards entirely; with \fB\-m\fR or \fB\-\-more\fR,
@@ -112,6 +112,11 @@  not an OpenFlow flow: besides other differences, it never contains wildcards.)
 The \fIfilter\fR is also useful to match wildcarded fields in the datapath
 flow. As an example, \fBfilter='tcp,tp_src=100'\fR will match the
 datapath flow containing '\fBtcp(src=80/0xff00,dst=8080/0xff)\fR'.
+.IP
+If \fBtype=\fItype\fR is specified, only displays flows of a specific type.
+\fItype\fR can be \fBoffloaded\fR to display only offloaded rules or \fBOVS\fR
+to display only non-offloaded rules.
+By default both offloaded and non-offloaded rules are displayed.
 .
 .IP "\*(DX\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR"
 .TP
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index a14a2eb..a70e3e1 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2612,7 +2612,8 @@  dpif_netdev_flow_dump_cast(struct dpif_flow_dump *dump)
 }
 
 static struct dpif_flow_dump *
-dpif_netdev_flow_dump_create(const struct dpif *dpif_, bool terse)
+dpif_netdev_flow_dump_create(const struct dpif *dpif_, bool terse,
+                             char *type OVS_UNUSED)
 {
     struct dpif_netdev_flow_dump *dump;
 
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index c53c46c..198bf7e 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -1374,6 +1374,16 @@  dpif_netlink_init_flow_del(struct dpif_netlink *dpif,
                                  del->ufid, del->terse, request);
 }
 
+enum {
+    DUMP_OVS_FLOWS_BIT       = 0,
+    DUMP_OFFLOADED_FLOWS_BIT = 1,
+};
+
+enum {
+    DUMP_OVS_FLOWS       = (1 << DUMP_OVS_FLOWS_BIT),
+    DUMP_OFFLOADED_FLOWS = (1 << DUMP_OFFLOADED_FLOWS_BIT),
+};
+
 struct dpif_netlink_flow_dump {
     struct dpif_flow_dump up;
     struct nl_dump nl_dump;
@@ -1382,6 +1392,7 @@  struct dpif_netlink_flow_dump {
     int netdev_dumps_num;                    /* Number of netdev_flow_dumps */
     struct ovs_mutex netdev_lock;            /* Guards the following. */
     int netdev_current_dump OVS_GUARDED;     /* Shared current dump */
+    int type;                                /* Type of dump */
 };
 
 static struct dpif_netlink_flow_dump *
@@ -1396,7 +1407,7 @@  start_netdev_dump(const struct dpif *dpif_,
 {
     ovs_mutex_init(&dump->netdev_lock);
 
-    if (!netdev_flow_api_enabled) {
+    if (!(dump->type & DUMP_OFFLOADED_FLOWS)) {
         dump->netdev_dumps_num = 0;
         dump->netdev_dumps = NULL;
         return;
@@ -1410,8 +1421,24 @@  start_netdev_dump(const struct dpif *dpif_,
     ovs_mutex_unlock(&dump->netdev_lock);
 }
 
+static int
+dpif_netlink_get_dump_type(char *str) {
+    int type = 0;
+
+    if (!str || !strcmp(str, "ovs") || !strcmp(str, "dpctl")) {
+        type |= DUMP_OVS_FLOWS;
+    }
+    if ((netdev_flow_api_enabled && !str)
+        || (str && (!strcmp(str, "offloaded") || !strcmp(str, "dpctl")))) {
+        type |= DUMP_OFFLOADED_FLOWS;
+    }
+
+    return type;
+}
+
 static struct dpif_flow_dump *
-dpif_netlink_flow_dump_create(const struct dpif *dpif_, bool terse)
+dpif_netlink_flow_dump_create(const struct dpif *dpif_, bool terse,
+                              char *type)
 {
     const struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
     struct dpif_netlink_flow_dump *dump;
@@ -1421,16 +1448,20 @@  dpif_netlink_flow_dump_create(const struct dpif *dpif_, bool terse)
     dump = xmalloc(sizeof *dump);
     dpif_flow_dump_init(&dump->up, dpif_);
 
-    dpif_netlink_flow_init(&request);
-    request.cmd = OVS_FLOW_CMD_GET;
-    request.dp_ifindex = dpif->dp_ifindex;
-    request.ufid_present = false;
-    request.ufid_terse = terse;
+    dump->type = dpif_netlink_get_dump_type(type);
 
-    buf = ofpbuf_new(1024);
-    dpif_netlink_flow_to_ofpbuf(&request, buf);
-    nl_dump_start(&dump->nl_dump, NETLINK_GENERIC, buf);
-    ofpbuf_delete(buf);
+    if (dump->type & DUMP_OVS_FLOWS) {
+        dpif_netlink_flow_init(&request);
+        request.cmd = OVS_FLOW_CMD_GET;
+        request.dp_ifindex = dpif->dp_ifindex;
+        request.ufid_present = false;
+        request.ufid_terse = terse;
+
+        buf = ofpbuf_new(1024);
+        dpif_netlink_flow_to_ofpbuf(&request, buf);
+        nl_dump_start(&dump->nl_dump, NETLINK_GENERIC, buf);
+        ofpbuf_delete(buf);
+    }
     atomic_init(&dump->status, 0);
     dump->up.terse = terse;
 
@@ -1443,9 +1474,12 @@  static int
 dpif_netlink_flow_dump_destroy(struct dpif_flow_dump *dump_)
 {
     struct dpif_netlink_flow_dump *dump = dpif_netlink_flow_dump_cast(dump_);
-    unsigned int nl_status = nl_dump_done(&dump->nl_dump);
+    unsigned int nl_status = 0;
     int dump_status;
 
+    if (dump->type & DUMP_OVS_FLOWS) {
+        nl_status = nl_dump_done(&dump->nl_dump);
+    }
     for (int i = 0; i < dump->netdev_dumps_num; i++) {
         int err = netdev_flow_dump_destroy(dump->netdev_dumps[i]);
         if (err != 0 && err != EOPNOTSUPP) {
@@ -1676,6 +1710,10 @@  dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
         }
     }
 
+    if (!(dump->type & DUMP_OVS_FLOWS)) {
+        return n_flows;
+    }
+
     while (!n_flows
            || (n_flows < flow_limit && thread->nl_flows.size)) {
         struct dpif_netlink_flow datapath_flow;
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index a4ed01a..64ac2e2 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -281,9 +281,11 @@  struct dpif_class {
      * dpif_flow_dump_thread_init(), respectively.
      *
      * If 'terse' is true, then only UID and statistics will
-     * be returned in the dump. Otherwise, all fields will be returned. */
+     * be returned in the dump. Otherwise, all fields will be returned.
+     *
+     * If 'type' isn't null, dumps only the flows of the given type. */
     struct dpif_flow_dump *(*flow_dump_create)(const struct dpif *dpif,
-                                               bool terse);
+                                               bool terse, char *type);
     int (*flow_dump_destroy)(struct dpif_flow_dump *dump);
 
     struct dpif_flow_dump_thread *(*flow_dump_thread_create)(
diff --git a/lib/dpif.c b/lib/dpif.c
index d45f21d..f5fcf47 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1054,9 +1054,9 @@  dpif_flow_del(struct dpif *dpif,
  * This function always successfully returns a dpif_flow_dump.  Error
  * reporting is deferred to dpif_flow_dump_destroy(). */
 struct dpif_flow_dump *
-dpif_flow_dump_create(const struct dpif *dpif, bool terse)
+dpif_flow_dump_create(const struct dpif *dpif, bool terse, char *type)
 {
-    return dpif->dpif_class->flow_dump_create(dpif, terse);
+    return dpif->dpif_class->flow_dump_create(dpif, terse, type);
 }
 
 /* Destroys 'dump', which must have been created with dpif_flow_dump_create().
diff --git a/lib/dpif.h b/lib/dpif.h
index 81376c0..b1f516e 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -569,7 +569,8 @@  int dpif_flow_get(struct dpif *,
  *
  * All error reporting is deferred to the call to dpif_flow_dump_destroy().
  */
-struct dpif_flow_dump *dpif_flow_dump_create(const struct dpif *, bool terse);
+struct dpif_flow_dump *dpif_flow_dump_create(const struct dpif *, bool terse,
+                                             char *type);
 int dpif_flow_dump_destroy(struct dpif_flow_dump *);
 
 struct dpif_flow_dump_thread *dpif_flow_dump_thread_create(
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 3b28f9a..d6a4cf6 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -885,7 +885,8 @@  udpif_revalidator(void *arg)
                 bool terse_dump;
 
                 terse_dump = udpif_use_ufid(udpif);
-                udpif->dump = dpif_flow_dump_create(udpif->dpif, terse_dump);
+                udpif->dump = dpif_flow_dump_create(udpif->dpif, terse_dump,
+                                                    NULL);
             }
         }
 
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 523adad..fa0fb19 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5107,7 +5107,7 @@  ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
     }
 
     ds_init(&ds);
-    flow_dump = dpif_flow_dump_create(ofproto->backer->dpif, false);
+    flow_dump = dpif_flow_dump_create(ofproto->backer->dpif, false, NULL);
     flow_dump_thread = dpif_flow_dump_thread_create(flow_dump);
     while (dpif_flow_dump_next(flow_dump_thread, &f, 1)) {
         struct flow flow;