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