xref: /dpdk/drivers/net/bonding/rte_eth_bond_flow.c (revision 02a2accb5f54183d448edf35902b71023ab908ac)
149dad902SMatan Azrad /* SPDX-License-Identifier: BSD-3-Clause
249dad902SMatan Azrad  * Copyright 2018 Mellanox Technologies, Ltd
349dad902SMatan Azrad  */
449dad902SMatan Azrad 
581b750c7SAdrien Mazarguil #include <stddef.h>
681b750c7SAdrien Mazarguil #include <string.h>
749dad902SMatan Azrad #include <sys/queue.h>
849dad902SMatan Azrad 
981b750c7SAdrien Mazarguil #include <rte_errno.h>
1049dad902SMatan Azrad #include <rte_malloc.h>
1149dad902SMatan Azrad #include <rte_tailq.h>
1249dad902SMatan Azrad #include <rte_flow.h>
1349dad902SMatan Azrad 
14b28f28aeSDharmik Thakkar #include "eth_bond_private.h"
1549dad902SMatan Azrad 
1649dad902SMatan Azrad static struct rte_flow *
bond_flow_alloc(int numa_node,const struct rte_flow_attr * attr,const struct rte_flow_item * items,const struct rte_flow_action * actions)1749dad902SMatan Azrad bond_flow_alloc(int numa_node, const struct rte_flow_attr *attr,
1849dad902SMatan Azrad 		   const struct rte_flow_item *items,
1949dad902SMatan Azrad 		   const struct rte_flow_action *actions)
2049dad902SMatan Azrad {
2149dad902SMatan Azrad 	struct rte_flow *flow;
2281b750c7SAdrien Mazarguil 	const struct rte_flow_conv_rule rule = {
2381b750c7SAdrien Mazarguil 		.attr_ro = attr,
2481b750c7SAdrien Mazarguil 		.pattern_ro = items,
2581b750c7SAdrien Mazarguil 		.actions_ro = actions,
2681b750c7SAdrien Mazarguil 	};
2781b750c7SAdrien Mazarguil 	struct rte_flow_error error;
2881b750c7SAdrien Mazarguil 	int ret;
2949dad902SMatan Azrad 
3081b750c7SAdrien Mazarguil 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, &error);
3181b750c7SAdrien Mazarguil 	if (ret < 0) {
3281b750c7SAdrien Mazarguil 		RTE_BOND_LOG(ERR, "Unable to process flow rule (%s): %s",
3381b750c7SAdrien Mazarguil 			     error.message ? error.message : "unspecified",
3481b750c7SAdrien Mazarguil 			     strerror(rte_errno));
3581b750c7SAdrien Mazarguil 		return NULL;
3681b750c7SAdrien Mazarguil 	}
3781b750c7SAdrien Mazarguil 	flow = rte_zmalloc_socket(NULL, offsetof(struct rte_flow, rule) + ret,
3849dad902SMatan Azrad 				  RTE_CACHE_LINE_SIZE, numa_node);
3949dad902SMatan Azrad 	if (unlikely(flow == NULL)) {
4049dad902SMatan Azrad 		RTE_BOND_LOG(ERR, "Could not allocate new flow");
4149dad902SMatan Azrad 		return NULL;
4249dad902SMatan Azrad 	}
4381b750c7SAdrien Mazarguil 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &flow->rule, ret, &rule,
4481b750c7SAdrien Mazarguil 			    &error);
4581b750c7SAdrien Mazarguil 	if (ret < 0) {
4681b750c7SAdrien Mazarguil 		RTE_BOND_LOG(ERR, "Failed to copy flow rule (%s): %s",
4781b750c7SAdrien Mazarguil 			     error.message ? error.message : "unspecified",
4881b750c7SAdrien Mazarguil 			     strerror(rte_errno));
4949dad902SMatan Azrad 		rte_free(flow);
5049dad902SMatan Azrad 		return NULL;
5149dad902SMatan Azrad 	}
5249dad902SMatan Azrad 	return flow;
5349dad902SMatan Azrad }
5449dad902SMatan Azrad 
5549dad902SMatan Azrad static void
bond_flow_release(struct rte_flow ** flow)5649dad902SMatan Azrad bond_flow_release(struct rte_flow **flow)
5749dad902SMatan Azrad {
5849dad902SMatan Azrad 	rte_free(*flow);
5949dad902SMatan Azrad 	*flow = NULL;
6049dad902SMatan Azrad }
6149dad902SMatan Azrad 
6249dad902SMatan Azrad static int
bond_flow_validate(struct rte_eth_dev * dev,const struct rte_flow_attr * attr,const struct rte_flow_item patterns[],const struct rte_flow_action actions[],struct rte_flow_error * err)6349dad902SMatan Azrad bond_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
6449dad902SMatan Azrad 		   const struct rte_flow_item patterns[],
6549dad902SMatan Azrad 		   const struct rte_flow_action actions[],
6649dad902SMatan Azrad 		   struct rte_flow_error *err)
6749dad902SMatan Azrad {
6849dad902SMatan Azrad 	struct bond_dev_private *internals = dev->data->dev_private;
6949dad902SMatan Azrad 	int i;
7049dad902SMatan Azrad 	int ret;
7149dad902SMatan Azrad 
7215e34522SLong Wu 	for (i = 0; i < internals->member_count; i++) {
7315e34522SLong Wu 		ret = rte_flow_validate(internals->members[i].port_id, attr,
7449dad902SMatan Azrad 					patterns, actions, err);
7549dad902SMatan Azrad 		if (ret) {
7649dad902SMatan Azrad 			RTE_BOND_LOG(ERR, "Operation rte_flow_validate failed"
7715e34522SLong Wu 				     " for member %d with error %d", i, ret);
7849dad902SMatan Azrad 			return ret;
7949dad902SMatan Azrad 		}
8049dad902SMatan Azrad 	}
8149dad902SMatan Azrad 	return 0;
8249dad902SMatan Azrad }
8349dad902SMatan Azrad 
8449dad902SMatan Azrad static struct rte_flow *
bond_flow_create(struct rte_eth_dev * dev,const struct rte_flow_attr * attr,const struct rte_flow_item patterns[],const struct rte_flow_action actions[],struct rte_flow_error * err)8549dad902SMatan Azrad bond_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
8649dad902SMatan Azrad 		 const struct rte_flow_item patterns[],
8749dad902SMatan Azrad 		 const struct rte_flow_action actions[],
8849dad902SMatan Azrad 		 struct rte_flow_error *err)
8949dad902SMatan Azrad {
9049dad902SMatan Azrad 	struct bond_dev_private *internals = dev->data->dev_private;
9149dad902SMatan Azrad 	struct rte_flow *flow;
9249dad902SMatan Azrad 	int i;
9349dad902SMatan Azrad 
9449dad902SMatan Azrad 	flow = bond_flow_alloc(dev->data->numa_node, attr, patterns, actions);
9549dad902SMatan Azrad 	if (unlikely(flow == NULL)) {
9649dad902SMatan Azrad 		rte_flow_error_set(err, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9749dad902SMatan Azrad 				   NULL, rte_strerror(ENOMEM));
9849dad902SMatan Azrad 		return NULL;
9949dad902SMatan Azrad 	}
10015e34522SLong Wu 	for (i = 0; i < internals->member_count; i++) {
10115e34522SLong Wu 		flow->flows[i] = rte_flow_create(internals->members[i].port_id,
10249dad902SMatan Azrad 						 attr, patterns, actions, err);
10349dad902SMatan Azrad 		if (unlikely(flow->flows[i] == NULL)) {
10415e34522SLong Wu 			RTE_BOND_LOG(ERR, "Failed to create flow on member %d",
10549dad902SMatan Azrad 				     i);
10649dad902SMatan Azrad 			goto err;
10749dad902SMatan Azrad 		}
10849dad902SMatan Azrad 	}
10949dad902SMatan Azrad 	TAILQ_INSERT_TAIL(&internals->flow_list, flow, next);
11049dad902SMatan Azrad 	return flow;
11149dad902SMatan Azrad err:
11215e34522SLong Wu 	/* Destroy all members flows. */
11315e34522SLong Wu 	for (i = 0; i < internals->member_count; i++) {
11449dad902SMatan Azrad 		if (flow->flows[i] != NULL)
11515e34522SLong Wu 			rte_flow_destroy(internals->members[i].port_id,
11649dad902SMatan Azrad 					 flow->flows[i], err);
11749dad902SMatan Azrad 	}
11849dad902SMatan Azrad 	bond_flow_release(&flow);
11949dad902SMatan Azrad 	return NULL;
12049dad902SMatan Azrad }
12149dad902SMatan Azrad 
12249dad902SMatan Azrad static int
bond_flow_destroy(struct rte_eth_dev * dev,struct rte_flow * flow,struct rte_flow_error * err)12349dad902SMatan Azrad bond_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
12449dad902SMatan Azrad 		  struct rte_flow_error *err)
12549dad902SMatan Azrad {
12649dad902SMatan Azrad 	struct bond_dev_private *internals = dev->data->dev_private;
12749dad902SMatan Azrad 	int i;
12849dad902SMatan Azrad 	int ret = 0;
12949dad902SMatan Azrad 
13015e34522SLong Wu 	for (i = 0; i < internals->member_count; i++) {
13149dad902SMatan Azrad 		int lret;
13249dad902SMatan Azrad 
13349dad902SMatan Azrad 		if (unlikely(flow->flows[i] == NULL))
13449dad902SMatan Azrad 			continue;
13515e34522SLong Wu 		lret = rte_flow_destroy(internals->members[i].port_id,
13649dad902SMatan Azrad 					flow->flows[i], err);
13749dad902SMatan Azrad 		if (unlikely(lret != 0)) {
13815e34522SLong Wu 			RTE_BOND_LOG(ERR, "Failed to destroy flow on member %d:"
13949dad902SMatan Azrad 				     " %d", i, lret);
14049dad902SMatan Azrad 			ret = lret;
14149dad902SMatan Azrad 		}
14249dad902SMatan Azrad 	}
14349dad902SMatan Azrad 	TAILQ_REMOVE(&internals->flow_list, flow, next);
14449dad902SMatan Azrad 	bond_flow_release(&flow);
14549dad902SMatan Azrad 	return ret;
14649dad902SMatan Azrad }
14749dad902SMatan Azrad 
14849dad902SMatan Azrad static int
bond_flow_flush(struct rte_eth_dev * dev,struct rte_flow_error * err)14949dad902SMatan Azrad bond_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *err)
15049dad902SMatan Azrad {
15149dad902SMatan Azrad 	struct bond_dev_private *internals = dev->data->dev_private;
15249dad902SMatan Azrad 	struct rte_flow *flow;
15349dad902SMatan Azrad 	void *tmp;
15449dad902SMatan Azrad 	int ret = 0;
15549dad902SMatan Azrad 	int lret;
15649dad902SMatan Azrad 
15715e34522SLong Wu 	/* Destroy all bond flows from its members instead of flushing them to
15849dad902SMatan Azrad 	 * keep the LACP flow or any other external flows.
15949dad902SMatan Azrad 	 */
160f1f6ebc0SWilliam Tu 	RTE_TAILQ_FOREACH_SAFE(flow, &internals->flow_list, next, tmp) {
16149dad902SMatan Azrad 		lret = bond_flow_destroy(dev, flow, err);
16249dad902SMatan Azrad 		if (unlikely(lret != 0))
16349dad902SMatan Azrad 			ret = lret;
16449dad902SMatan Azrad 	}
16549dad902SMatan Azrad 	if (unlikely(ret != 0))
16615e34522SLong Wu 		RTE_BOND_LOG(ERR, "Failed to flush flow in all members");
16749dad902SMatan Azrad 	return ret;
16849dad902SMatan Azrad }
16949dad902SMatan Azrad 
17049dad902SMatan Azrad static int
bond_flow_query_count(struct rte_eth_dev * dev,struct rte_flow * flow,const struct rte_flow_action * action,struct rte_flow_query_count * count,struct rte_flow_error * err)17149dad902SMatan Azrad bond_flow_query_count(struct rte_eth_dev *dev, struct rte_flow *flow,
172fb8fd96dSDeclan Doherty 		      const struct rte_flow_action *action,
17349dad902SMatan Azrad 		      struct rte_flow_query_count *count,
17449dad902SMatan Azrad 		      struct rte_flow_error *err)
17549dad902SMatan Azrad {
17649dad902SMatan Azrad 	struct bond_dev_private *internals = dev->data->dev_private;
17715e34522SLong Wu 	struct rte_flow_query_count member_count;
17849dad902SMatan Azrad 	int i;
17949dad902SMatan Azrad 	int ret;
18049dad902SMatan Azrad 
18149dad902SMatan Azrad 	count->bytes = 0;
18249dad902SMatan Azrad 	count->hits = 0;
183*02a2accbSMário Kuka 	count->bytes_set = 0;
184*02a2accbSMário Kuka 	count->hits_set = 0;
18515e34522SLong Wu 	rte_memcpy(&member_count, count, sizeof(member_count));
18615e34522SLong Wu 	for (i = 0; i < internals->member_count; i++) {
18715e34522SLong Wu 		ret = rte_flow_query(internals->members[i].port_id,
188fb8fd96dSDeclan Doherty 				     flow->flows[i], action,
18915e34522SLong Wu 				     &member_count, err);
19049dad902SMatan Azrad 		if (unlikely(ret != 0)) {
19149dad902SMatan Azrad 			RTE_BOND_LOG(ERR, "Failed to query flow on"
19215e34522SLong Wu 				     " member %d: %d", i, ret);
19349dad902SMatan Azrad 			return ret;
19449dad902SMatan Azrad 		}
19515e34522SLong Wu 		count->bytes += member_count.bytes;
19615e34522SLong Wu 		count->hits += member_count.hits;
197*02a2accbSMário Kuka 		count->bytes_set |= member_count.bytes_set;
198*02a2accbSMário Kuka 		count->hits_set |= member_count.hits_set;
19915e34522SLong Wu 		member_count.bytes = 0;
20015e34522SLong Wu 		member_count.hits = 0;
201*02a2accbSMário Kuka 		member_count.bytes_set = 0;
202*02a2accbSMário Kuka 		member_count.hits_set = 0;
20349dad902SMatan Azrad 	}
20449dad902SMatan Azrad 	return 0;
20549dad902SMatan Azrad }
20649dad902SMatan Azrad 
20749dad902SMatan Azrad static int
bond_flow_query(struct rte_eth_dev * dev,struct rte_flow * flow,const struct rte_flow_action * action,void * arg,struct rte_flow_error * err)20849dad902SMatan Azrad bond_flow_query(struct rte_eth_dev *dev, struct rte_flow *flow,
209fb8fd96dSDeclan Doherty 		const struct rte_flow_action *action, void *arg,
21049dad902SMatan Azrad 		struct rte_flow_error *err)
21149dad902SMatan Azrad {
212fb8fd96dSDeclan Doherty 	switch (action->type) {
21349dad902SMatan Azrad 	case RTE_FLOW_ACTION_TYPE_COUNT:
214fb8fd96dSDeclan Doherty 		return bond_flow_query_count(dev, flow, action, arg, err);
21549dad902SMatan Azrad 	default:
21649dad902SMatan Azrad 		return rte_flow_error_set(err, ENOTSUP,
21749dad902SMatan Azrad 					  RTE_FLOW_ERROR_TYPE_ACTION, arg,
21849dad902SMatan Azrad 					  rte_strerror(ENOTSUP));
21949dad902SMatan Azrad 	}
22049dad902SMatan Azrad }
22149dad902SMatan Azrad 
22249dad902SMatan Azrad static int
bond_flow_isolate(struct rte_eth_dev * dev,int set,struct rte_flow_error * err)22349dad902SMatan Azrad bond_flow_isolate(struct rte_eth_dev *dev, int set,
22449dad902SMatan Azrad 		  struct rte_flow_error *err)
22549dad902SMatan Azrad {
22649dad902SMatan Azrad 	struct bond_dev_private *internals = dev->data->dev_private;
22749dad902SMatan Azrad 	int i;
22849dad902SMatan Azrad 	int ret;
22949dad902SMatan Azrad 
23015e34522SLong Wu 	for (i = 0; i < internals->member_count; i++) {
23115e34522SLong Wu 		ret = rte_flow_isolate(internals->members[i].port_id, set, err);
23249dad902SMatan Azrad 		if (unlikely(ret != 0)) {
23349dad902SMatan Azrad 			RTE_BOND_LOG(ERR, "Operation rte_flow_isolate failed"
23415e34522SLong Wu 				     " for member %d with error %d", i, ret);
23549dad902SMatan Azrad 			internals->flow_isolated_valid = 0;
23649dad902SMatan Azrad 			return ret;
23749dad902SMatan Azrad 		}
23849dad902SMatan Azrad 	}
23949dad902SMatan Azrad 	internals->flow_isolated = set;
24049dad902SMatan Azrad 	internals->flow_isolated_valid = 1;
24149dad902SMatan Azrad 	return 0;
24249dad902SMatan Azrad }
24349dad902SMatan Azrad 
24449dad902SMatan Azrad const struct rte_flow_ops bond_flow_ops = {
24549dad902SMatan Azrad 	.validate = bond_flow_validate,
24649dad902SMatan Azrad 	.create = bond_flow_create,
24749dad902SMatan Azrad 	.destroy = bond_flow_destroy,
24849dad902SMatan Azrad 	.flush = bond_flow_flush,
24949dad902SMatan Azrad 	.query = bond_flow_query,
25049dad902SMatan Azrad 	.isolate = bond_flow_isolate,
25149dad902SMatan Azrad };
252