Expose the number of flows present in a datapath to user-space
and to users via ovs-dpctl show.

e.g.:

ovs-dpctl show br3
system@br3:
        lookups: frags:0, hit:0, missed:0, lost:0
        flows: 0
        ...

Signed-off-by: Simon Horman <[email protected]>

---

This has proved quite useful while looking at ways
to increase the number of flows that can be handled.
I am unsure if it is generally useful or not to
warrant inclusion upstream.
---
 datapath/datapath.c                     |   13 +++++++++++++
 include/openvswitch/datapath-protocol.h |    3 +++
 lib/dpif-linux.c                        |   28 ++++++++++++++++++++++++++++
 lib/dpif-netdev.c                       |    1 +
 lib/dpif-provider.h                     |    3 +++
 lib/dpif.c                              |   14 ++++++++++++++
 lib/dpif.h                              |    1 +
 utilities/ovs-dpctl.c                   |    4 ++++
 8 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index a964c27..7353a7b 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -766,6 +766,13 @@ static void get_dp_stats(struct datapath *dp, struct 
odp_stats *stats)
        }
 }
 
+static void get_dp_flows(struct datapath *dp, u32 *n_flows)
+{
+       struct tbl *table = get_table_protected(dp);
+
+       *n_flows = tbl_count(table);
+}
+
 /* MTU of the dp pseudo-device: ETH_DATA_LEN or the minimum of the ports.
  * Called with RTNL lock.
  */
@@ -1219,6 +1226,7 @@ static const struct nla_policy 
datapath_policy[ODP_DP_ATTR_MAX + 1] = {
 #endif
        [ODP_DP_ATTR_IPV4_FRAGS] = { .type = NLA_U32 },
        [ODP_DP_ATTR_SAMPLING] = { .type = NLA_U32 },
+       [ODP_DP_ATTR_FLOWS] = { .type = NLA_U32 },
 };
 
 static struct genl_family dp_datapath_genl_family = {
@@ -1258,6 +1266,11 @@ static int odp_dp_cmd_fill_info(struct datapath *dp, 
struct sk_buff *skb,
                goto nla_put_failure;
        get_dp_stats(dp, nla_data(nla));
 
+       nla = nla_reserve(skb, ODP_DP_ATTR_FLOWS, sizeof(u32));
+       if (!nla)
+               goto nla_put_failure;
+       get_dp_flows(dp, nla_data(nla));
+
        NLA_PUT_U32(skb, ODP_DP_ATTR_IPV4_FRAGS,
                    dp->drop_frags ? ODP_DP_FRAG_DROP : ODP_DP_FRAG_ZERO);
 
diff --git a/include/openvswitch/datapath-protocol.h 
b/include/openvswitch/datapath-protocol.h
index 0b755e8..238324a 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -99,6 +99,8 @@ struct odp_header {
  * attribute has a %ODP_PACKET_CMD_* type with a 32-bit value giving the
  * Generic Netlink multicast group number used for sending this datapath's
  * messages with that command type up to userspace.
+ * @ODP_DP_ATTR_FLOWS: Number of flows present in a bridge. May be present
+ * in notifications.  Ignored in requests.
  *
  * These attributes follow the &struct odp_header within the Generic Netlink
  * payload for %ODP_DP_* commands.
@@ -110,6 +112,7 @@ enum odp_datapath_attr {
        ODP_DP_ATTR_IPV4_FRAGS, /* 32-bit enum odp_frag_handling */
        ODP_DP_ATTR_SAMPLING,   /* 32-bit fraction of packets to sample. */
        ODP_DP_ATTR_MCGROUPS,   /* Nested attributes with multicast groups. */
+       ODP_DP_ATTR_FLOWS,      /* Unsigned 32-bit integer */
        __ODP_DP_ATTR_MAX
 };
 
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 0f6a140..3c6ae37 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -73,6 +73,10 @@ struct dpif_linux_dp {
     enum odp_frag_handling ipv4_frags; /* ODP_DP_ATTR_IPV4_FRAGS. */
     const uint32_t *sampling;          /* ODP_DP_ATTR_SAMPLING. */
     uint32_t mcgroups[DPIF_N_UC_TYPES]; /* ODP_DP_ATTR_MCGROUPS. */
+
+    uint32_t n_flows;                   /* ODP_DP_ATTR_FLOWS. */
+    bool has_n_flows;                   /* Seen ODP_DP_ATTR_FLOWS in
+                                         * response from datapath */
 };
 
 static void dpif_linux_dp_init(struct dpif_linux_dp *);
@@ -324,6 +328,24 @@ dpif_linux_get_stats(const struct dpif *dpif_, struct 
odp_stats *stats)
 }
 
 static int
+dpif_linux_get_flow_count(const struct dpif *dpif_, uint32_t *flows)
+{
+    struct dpif_linux_dp dp;
+    struct ofpbuf *buf;
+    int error;
+
+    error = dpif_linux_dp_get(dpif_, &dp, &buf);
+    if (!error) {
+       if (dp.has_n_flows)
+            *flows = dp.n_flows;
+       else
+           error = ENOENT;
+        ofpbuf_delete(buf);
+    }
+    return error;
+}
+
+static int
 dpif_linux_get_drop_frags(const struct dpif *dpif_, bool *drop_fragsp)
 {
     struct dpif_linux_dp dp;
@@ -1051,6 +1073,7 @@ const struct dpif_class dpif_linux_class = {
     NULL,                       /* run */
     NULL,                       /* wait */
     dpif_linux_get_stats,
+    dpif_linux_get_flow_count,
     dpif_linux_get_drop_frags,
     dpif_linux_set_drop_frags,
     dpif_linux_port_add,
@@ -1387,6 +1410,7 @@ dpif_linux_dp_from_ofpbuf(struct dpif_linux_dp *dp, const 
struct ofpbuf *buf)
         [ODP_DP_ATTR_IPV4_FRAGS] = { .type = NL_A_U32, .optional = true },
         [ODP_DP_ATTR_SAMPLING] = { .type = NL_A_U32, .optional = true },
         [ODP_DP_ATTR_MCGROUPS] = { .type = NL_A_NESTED, .optional = true },
+        [ODP_DP_ATTR_FLOWS] = { .type = NL_A_U32, .optional = true },
     };
 
     struct nlattr *a[ARRAY_SIZE(odp_datapath_policy)];
@@ -1423,6 +1447,10 @@ dpif_linux_dp_from_ofpbuf(struct dpif_linux_dp *dp, 
const struct ofpbuf *buf)
     if (a[ODP_DP_ATTR_SAMPLING]) {
         dp->sampling = nl_attr_get(a[ODP_DP_ATTR_SAMPLING]);
     }
+    if (a[ODP_DP_ATTR_FLOWS]) {
+        dp->n_flows = nl_attr_get_u32(a[ODP_DP_ATTR_FLOWS]);
+        dp->has_n_flows = true;
+    }
 
     if (a[ODP_DP_ATTR_MCGROUPS]) {
         static const struct nl_policy odp_mcgroup_policy[] = {
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index d48d7ae..232dd1a 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1347,6 +1347,7 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_run,
     dpif_netdev_wait,
     dpif_netdev_get_stats,
+    NULL,
     dpif_netdev_get_drop_frags,
     dpif_netdev_set_drop_frags,
     dpif_netdev_port_add,
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 58d2f0b..cf4e0dd 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -110,6 +110,9 @@ struct dpif_class {
     /* Retrieves statistics for 'dpif' into 'stats'. */
     int (*get_stats)(const struct dpif *dpif, struct odp_stats *stats);
 
+    /* Retrieves number of flows present for 'dpif' into 'flows'. */
+    int (*get_flow_count)(const struct dpif *dpif, uint32_t *flows);
+
     /* Retrieves 'dpif''s current treatment of IP fragments into '*drop_frags':
      * true indicates that fragments are dropped, false indicates that
      * fragments are treated in the same way as other IP packets (except that
diff --git a/lib/dpif.c b/lib/dpif.c
index 4e3788d..a940219 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -388,6 +388,20 @@ dpif_get_dp_stats(const struct dpif *dpif, struct 
odp_stats *stats)
     return error;
 }
 
+/* Retrieves flow count for 'dpif' into 'flows'.  Returns 0 if successful,
+ * otherwise a positive errno value. */
+int
+dpif_get_dp_flow_count(const struct dpif *dpif, uint32_t *flows)
+{
+    int error = ENOENT;
+    if (!dpif->dpif_class->get_flow_count ||
+        (error =  dpif->dpif_class->get_flow_count(dpif, flows))) {
+        flows = 0;
+    }
+    log_operation(dpif, "get_flow_count", error);
+    return error;
+}
+
 /* Retrieves the current IP fragment handling policy for 'dpif' into
  * '*drop_frags': true indicates that fragments are dropped, false indicates
  * that fragments are treated in the same way as other IP packets (except that
diff --git a/lib/dpif.h b/lib/dpif.h
index 4df2318..32f5fde 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -59,6 +59,7 @@ const char *dpif_base_name(const struct dpif *);
 int dpif_delete(struct dpif *);
 
 int dpif_get_dp_stats(const struct dpif *, struct odp_stats *);
+int dpif_get_dp_flow_count(const struct dpif *, uint32_t *);
 int dpif_get_drop_frags(const struct dpif *, bool *drop_frags);
 int dpif_set_drop_frags(struct dpif *, bool drop_frags);
 
diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c
index c7350e5..68b9760 100644
--- a/utilities/ovs-dpctl.c
+++ b/utilities/ovs-dpctl.c
@@ -361,6 +361,7 @@ show_dpif(struct dpif *dpif)
     struct dpif_port_dump dump;
     struct dpif_port dpif_port;
     struct odp_stats stats;
+    uint32_t flows;
 
     printf("%s:\n", dpif_name(dpif));
     if (!dpif_get_dp_stats(dpif, &stats)) {
@@ -370,6 +371,9 @@ show_dpif(struct dpif *dpif)
                (unsigned long long int) stats.n_missed,
                (unsigned long long int) stats.n_lost);
     }
+    if (!dpif_get_dp_flow_count(dpif, &flows)) {
+        printf("\tflows: %"PRIu32"\n", flows);
+    }
     DPIF_PORT_FOR_EACH (&dpif_port, &dump, dpif) {
         printf("\tport %u: %s", dpif_port.port_no, dpif_port.name);
 
-- 
1.7.5.4

_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev

Reply via email to