@@ -5051,9 +5051,38 @@ netdev_dpdk_flow_del(struct netdev *netdev, const ovs_u128 *ufid,
return netdev_dpdk_destroy_rte_flow(netdev, ufid, rte_flow);
}
-#define DPDK_FLOW_OFFLOAD_API \
- .flow_put = netdev_dpdk_flow_put, \
- .flow_del = netdev_dpdk_flow_del
+static int
+netdev_dpdk_flow_stats_get(struct netdev *netdev, const ovs_u128 *ufid,
+ struct dpif_flow_stats *stats) {
+
+ int ret = 0;
+ struct rte_flow_error error;
+ struct rte_flow_query_count query;
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ struct rte_flow *rte_flow = ufid_to_rte_flow_find(ufid);
+ if (!rte_flow) {
+ return EINVAL;
+ }
+ const struct rte_flow_action action = {
+ .type = RTE_FLOW_ACTION_TYPE_COUNT
+ };
+ memset(&query, 0, sizeof(query));
+ ret = rte_flow_query(dev->port_id, rte_flow, &action, &query, &error);
+ if (ret) {
+ return -ret;
+ }
+
+ stats->n_packets = (query.hits_set) ? query.hits : 0;
+ stats->n_bytes = (query.bytes_set) ? query.bytes : 0;
+ stats->used = 0;
+ stats->tcp_flags = 0;
+ return ret;
+}
+
+#define DPDK_FLOW_OFFLOAD_API \
+ .flow_put = netdev_dpdk_flow_put, \
+ .flow_del = netdev_dpdk_flow_del, \
+ .flow_stats_get = netdev_dpdk_flow_stats_get
#define NETDEV_DPDK_CLASS_COMMON \
.is_pmd = true, \
@@ -881,6 +881,13 @@ struct netdev_class {
int (*flow_del)(struct netdev *, const ovs_u128 *ufid,
struct dpif_flow_stats *);
+ /* Get offloaded flow stats. When a flow is fully offloaded, reading the
+ * PMD stats will result is no updates. In order to reflect the actual
+ * stats the hardware must be querried.
+ * Return 0 if successful, otherwise returns a positive errno value. */
+ int (*flow_stats_get)(struct netdev *netdev, const ovs_u128 *ufid,
+ struct dpif_flow_stats *stats);
+
/* Initializies the netdev flow api.
* Return 0 if successful, otherwise returns a positive errno value. */
int (*init_flow_api)(struct netdev *);
@@ -2232,6 +2232,17 @@ netdev_flow_del(struct netdev *netdev, const ovs_u128 *ufid,
}
int
+netdev_flow_stats_get(struct netdev *netdev, const ovs_u128 *ufid,
+ struct dpif_flow_stats *stats)
+{
+ const struct netdev_class *class = netdev->netdev_class;
+
+ return (class->flow_stats_get
+ ? class->flow_stats_get(netdev, ufid, stats)
+ : EOPNOTSUPP);
+}
+
+int
netdev_init_flow_api(struct netdev *netdev)
{
const struct netdev_class *class = netdev->netdev_class;
@@ -226,6 +226,8 @@ int netdev_flow_get(struct netdev *, struct match *, struct nlattr **actions,
struct dpif_flow_attrs *, struct ofpbuf *wbuffer);
int netdev_flow_del(struct netdev *, const ovs_u128 *,
struct dpif_flow_stats *);
+int netdev_flow_stats_get(struct netdev *, const ovs_u128 *,
+ struct dpif_flow_stats *);
int netdev_init_flow_api(struct netdev *);
uint32_t netdev_get_block_id(struct netdev *);
int netdev_get_hw_info(struct netdev *, int);
This function gets the offloaded flow stats. When a flow is fully offloaded reading the PMD SW stats will result in no updates. In order to reflect the actual stats accounted for the flow, the hw must be queried. Signed-off-by: Ophir Munk <ophirmu@mellanox.com> --- lib/netdev-dpdk.c | 35 ++++++++++++++++++++++++++++++++--- lib/netdev-provider.h | 7 +++++++ lib/netdev.c | 11 +++++++++++ lib/netdev.h | 2 ++ 4 files changed, 52 insertions(+), 3 deletions(-)