@@ -113,6 +113,9 @@ struct rte_flow_drop {
RTE_FLOW_ACTION_TYPE_DROP,
RTE_FLOW_ACTION_TYPE_QUEUE,
RTE_FLOW_ACTION_TYPE_RSS,
+#ifdef HAVE_VERBS_IBV_EXP_FLOW_SPEC_ACTION_COUNT
+ RTE_FLOW_ACTION_TYPE_COUNT,
+#endif
RTE_FLOW_ACTION_TYPE_END,
};
@@ -575,6 +578,7 @@ struct rte_flow_drop {
struct mlx4_flow_action action = {
.queue = 0,
.drop = 0,
+ .count = 0,
};
(void)priv;
@@ -743,6 +747,12 @@ struct rte_flow_drop {
action.queues_n = rss->num;
for (i = 0; i < rss->num; ++i)
action.queues[i] = rss->queue[i];
+ } else if(actions->type == RTE_FLOW_ACTION_TYPE_COUNT) {
+#ifdef HAVE_VERBS_IBV_EXP_FLOW_SPEC_ACTION_COUNT
+ action.count = 1;
+#else
+ goto exit_action_not_supported;
+#endif
} else {
goto exit_action_not_supported;
}
@@ -1085,6 +1095,7 @@ struct rte_flow_drop {
action = (struct mlx4_flow_action){
.queue = 0,
.drop = 0,
+ .count = 0,
};
for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
@@ -1107,6 +1118,8 @@ struct rte_flow_drop {
action.queues_n = rss->num;
for (i = 0; i < rss->num; ++i)
action.queues[i] = rss->queue[i];
+ } else if (actions->type == RTE_FLOW_ACTION_TYPE_COUNT) {
+ action.count = 1;
} else {
rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION,
@@ -1318,3 +1331,91 @@ struct rte_flow *
}
return 0;
}
+
+/**
+ * Internal function to read the counter.
+ *
+ * @param priv
+ * Pointer to private structure.
+ * @param counter_set
+ * Pointer to the counter_set structure.
+ * @param res
+ * Pointer to rte_flow_query_count struct
+ * used to return the values from the counters
+ * @param error
+ * returns the error
+ *
+ * @return
+ * 0 on success, -1 otherwise.
+ */
+#ifdef HAVE_VERBS_IBV_EXP_FLOW_SPEC_ACTION_COUNT
+static int
+priv_flow_query_counter(struct priv *priv,
+ struct ibv_counter_set *counter_set,
+ struct rte_flow_query_count *res,
+ struct rte_flow_error *error)
+{
+ int res_value = 0;
+ uint64_t counters[2];
+ struct ibv_counter_set_description description;
+ struct ibv_query_counter_set_attr attr = { .counter_set = counter_set};
+
+ res_value = ibv_query_counter_set(attr, counters);
+ if(res_value < 0) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Error while querying counter set");
+
+ }
+ res->hits_set = 1;
+ res->hits = counters[0];
+ res->bytes_set = 1;
+ res->bytes = counters[1];
+}
+#endif
+
+/**
+ * Query an existing flow rule.
+ *
+ * @see rte_flow_query()
+ * @see rte_flow_ops
+ */
+int mlx4_flow_query(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ enum rte_flow_action_type type,
+ void *res,
+ struct rte_flow_error *error)
+{
+ int res_value = 0;
+
+ switch (type) {
+ case RTE_FLOW_ACTION_TYPE_COUNT:
+#ifdef HAVE_VERBS_IBV_EXP_FLOW_SPEC_ACTION_COUNT
+ if(!flow->counter) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "No counter is set for this flow");
+ }
+
+ res_value = priv_flow_query_counter(mlx4_get_priv(dev),
+ (struct rte_flow_query_count*)res,
+ error);
+#else
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "Flow count unsupported");
+ (void)dev;
+ (void)flow;
+ (void)type;
+ (void)res;
+ (void)error;
+ return -1;
+#endif
+ break;
+ default:
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "Type not supported");
+ }
+ return res_value;
+}
@@ -80,6 +80,12 @@ struct rte_flow *
struct rte_flow *flow,
struct rte_flow_error *error);
+int mlx4_flow_query(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ enum rte_flow_action_type type,
+ void *res,
+ struct rte_flow_error *error);
+
int
mlx4_flow_flush(struct rte_eth_dev *dev,
struct rte_flow_error *error);
@@ -98,6 +104,7 @@ struct mlx4_flow {
struct mlx4_flow_action {
uint32_t drop:1; /**< Target is a drop queue. */
uint32_t queue:1; /**< Target is a receive queue. */
+ uint32_t count:1; /**< Count action is present in the flow. */
uint16_t queues[RTE_MAX_QUEUES_PER_PORT]; /**< Queue indices to use. */
uint16_t queues_n; /**< Number of entries in queue[] */
};