xref: /dpdk/drivers/net/failsafe/failsafe_flow.c (revision 33fcf207164b9e2ef012b79d27e7a37a66c98c36)
1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
2b737a1eeSGaetan Rivet  * Copyright 2017 6WIND S.A.
35feecc57SShahaf Shuler  * Copyright 2017 Mellanox Technologies, Ltd
4b737a1eeSGaetan Rivet  */
5b737a1eeSGaetan Rivet 
6*33fcf207SAdrien Mazarguil #include <stddef.h>
7*33fcf207SAdrien Mazarguil #include <string.h>
8b737a1eeSGaetan Rivet #include <sys/queue.h>
9b737a1eeSGaetan Rivet 
10*33fcf207SAdrien Mazarguil #include <rte_errno.h>
11b737a1eeSGaetan Rivet #include <rte_malloc.h>
12b737a1eeSGaetan Rivet #include <rte_tailq.h>
13b737a1eeSGaetan Rivet #include <rte_flow.h>
14b737a1eeSGaetan Rivet #include <rte_flow_driver.h>
15b737a1eeSGaetan Rivet 
16b737a1eeSGaetan Rivet #include "failsafe_private.h"
17b737a1eeSGaetan Rivet 
18b737a1eeSGaetan Rivet static struct rte_flow *
19b737a1eeSGaetan Rivet fs_flow_allocate(const struct rte_flow_attr *attr,
20b737a1eeSGaetan Rivet 		 const struct rte_flow_item *items,
21b737a1eeSGaetan Rivet 		 const struct rte_flow_action *actions)
22b737a1eeSGaetan Rivet {
23b737a1eeSGaetan Rivet 	struct rte_flow *flow;
24*33fcf207SAdrien Mazarguil 	const struct rte_flow_conv_rule rule = {
25*33fcf207SAdrien Mazarguil 		.attr_ro = attr,
26*33fcf207SAdrien Mazarguil 		.pattern_ro = items,
27*33fcf207SAdrien Mazarguil 		.actions_ro = actions,
28*33fcf207SAdrien Mazarguil 	};
29*33fcf207SAdrien Mazarguil 	struct rte_flow_error error;
30*33fcf207SAdrien Mazarguil 	int ret;
31b737a1eeSGaetan Rivet 
32*33fcf207SAdrien Mazarguil 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, &error);
33*33fcf207SAdrien Mazarguil 	if (ret < 0) {
34*33fcf207SAdrien Mazarguil 		ERROR("Unable to process flow rule (%s): %s",
35*33fcf207SAdrien Mazarguil 		      error.message ? error.message : "unspecified",
36*33fcf207SAdrien Mazarguil 		      strerror(rte_errno));
37*33fcf207SAdrien Mazarguil 		return NULL;
38*33fcf207SAdrien Mazarguil 	}
39*33fcf207SAdrien Mazarguil 	flow = rte_zmalloc(NULL, offsetof(struct rte_flow, rule) + ret,
40b737a1eeSGaetan Rivet 			   RTE_CACHE_LINE_SIZE);
41b737a1eeSGaetan Rivet 	if (flow == NULL) {
42b737a1eeSGaetan Rivet 		ERROR("Could not allocate new flow");
43b737a1eeSGaetan Rivet 		return NULL;
44b737a1eeSGaetan Rivet 	}
45*33fcf207SAdrien Mazarguil 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &flow->rule, ret, &rule,
46*33fcf207SAdrien Mazarguil 			    &error);
47*33fcf207SAdrien Mazarguil 	if (ret < 0) {
48*33fcf207SAdrien Mazarguil 		ERROR("Failed to copy flow rule (%s): %s",
49*33fcf207SAdrien Mazarguil 		      error.message ? error.message : "unspecified",
50*33fcf207SAdrien Mazarguil 		      strerror(rte_errno));
51b737a1eeSGaetan Rivet 		rte_free(flow);
52b737a1eeSGaetan Rivet 		return NULL;
53b737a1eeSGaetan Rivet 	}
54b737a1eeSGaetan Rivet 	return flow;
55b737a1eeSGaetan Rivet }
56b737a1eeSGaetan Rivet 
57b737a1eeSGaetan Rivet static void
58b737a1eeSGaetan Rivet fs_flow_release(struct rte_flow **flow)
59b737a1eeSGaetan Rivet {
60b737a1eeSGaetan Rivet 	rte_free(*flow);
61b737a1eeSGaetan Rivet 	*flow = NULL;
62b737a1eeSGaetan Rivet }
63b737a1eeSGaetan Rivet 
64b737a1eeSGaetan Rivet static int
65b737a1eeSGaetan Rivet fs_flow_validate(struct rte_eth_dev *dev,
66b737a1eeSGaetan Rivet 		 const struct rte_flow_attr *attr,
67b737a1eeSGaetan Rivet 		 const struct rte_flow_item patterns[],
68b737a1eeSGaetan Rivet 		 const struct rte_flow_action actions[],
69b737a1eeSGaetan Rivet 		 struct rte_flow_error *error)
70b737a1eeSGaetan Rivet {
71b737a1eeSGaetan Rivet 	struct sub_device *sdev;
72b737a1eeSGaetan Rivet 	uint8_t i;
73b737a1eeSGaetan Rivet 	int ret;
74b737a1eeSGaetan Rivet 
75655fcd68SMatan Azrad 	fs_lock(dev, 0);
76b737a1eeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
77b737a1eeSGaetan Rivet 		DEBUG("Calling rte_flow_validate on sub_device %d", i);
78b737a1eeSGaetan Rivet 		ret = rte_flow_validate(PORT_ID(sdev),
79b737a1eeSGaetan Rivet 				attr, patterns, actions, error);
80ae80146cSMatan Azrad 		if ((ret = fs_err(sdev, ret))) {
81b737a1eeSGaetan Rivet 			ERROR("Operation rte_flow_validate failed for sub_device %d"
82b737a1eeSGaetan Rivet 			      " with error %d", i, ret);
83655fcd68SMatan Azrad 			fs_unlock(dev, 0);
84b737a1eeSGaetan Rivet 			return ret;
85b737a1eeSGaetan Rivet 		}
86b737a1eeSGaetan Rivet 	}
87655fcd68SMatan Azrad 	fs_unlock(dev, 0);
88b737a1eeSGaetan Rivet 	return 0;
89b737a1eeSGaetan Rivet }
90b737a1eeSGaetan Rivet 
91b737a1eeSGaetan Rivet static struct rte_flow *
92b737a1eeSGaetan Rivet fs_flow_create(struct rte_eth_dev *dev,
93b737a1eeSGaetan Rivet 	       const struct rte_flow_attr *attr,
94b737a1eeSGaetan Rivet 	       const struct rte_flow_item patterns[],
95b737a1eeSGaetan Rivet 	       const struct rte_flow_action actions[],
96b737a1eeSGaetan Rivet 	       struct rte_flow_error *error)
97b737a1eeSGaetan Rivet {
98b737a1eeSGaetan Rivet 	struct sub_device *sdev;
99b737a1eeSGaetan Rivet 	struct rte_flow *flow;
100b737a1eeSGaetan Rivet 	uint8_t i;
101b737a1eeSGaetan Rivet 
102655fcd68SMatan Azrad 	fs_lock(dev, 0);
103b737a1eeSGaetan Rivet 	flow = fs_flow_allocate(attr, patterns, actions);
104b737a1eeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
105b737a1eeSGaetan Rivet 		flow->flows[i] = rte_flow_create(PORT_ID(sdev),
106b737a1eeSGaetan Rivet 				attr, patterns, actions, error);
107ae80146cSMatan Azrad 		if (flow->flows[i] == NULL && fs_err(sdev, -rte_errno)) {
108b737a1eeSGaetan Rivet 			ERROR("Failed to create flow on sub_device %d",
109b737a1eeSGaetan Rivet 				i);
110b737a1eeSGaetan Rivet 			goto err;
111b737a1eeSGaetan Rivet 		}
112b737a1eeSGaetan Rivet 	}
113b737a1eeSGaetan Rivet 	TAILQ_INSERT_TAIL(&PRIV(dev)->flow_list, flow, next);
114655fcd68SMatan Azrad 	fs_unlock(dev, 0);
115b737a1eeSGaetan Rivet 	return flow;
116b737a1eeSGaetan Rivet err:
117b737a1eeSGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
118b737a1eeSGaetan Rivet 		if (flow->flows[i] != NULL)
119b737a1eeSGaetan Rivet 			rte_flow_destroy(PORT_ID(sdev),
120b737a1eeSGaetan Rivet 				flow->flows[i], error);
121b737a1eeSGaetan Rivet 	}
122b737a1eeSGaetan Rivet 	fs_flow_release(&flow);
123655fcd68SMatan Azrad 	fs_unlock(dev, 0);
124b737a1eeSGaetan Rivet 	return NULL;
125b737a1eeSGaetan Rivet }
126b737a1eeSGaetan Rivet 
127b737a1eeSGaetan Rivet static int
128b737a1eeSGaetan Rivet fs_flow_destroy(struct rte_eth_dev *dev,
129b737a1eeSGaetan Rivet 		struct rte_flow *flow,
130b737a1eeSGaetan Rivet 		struct rte_flow_error *error)
131b737a1eeSGaetan Rivet {
132b737a1eeSGaetan Rivet 	struct sub_device *sdev;
133b737a1eeSGaetan Rivet 	uint8_t i;
134b737a1eeSGaetan Rivet 	int ret;
135b737a1eeSGaetan Rivet 
136b737a1eeSGaetan Rivet 	if (flow == NULL) {
137b737a1eeSGaetan Rivet 		ERROR("Invalid flow");
138b737a1eeSGaetan Rivet 		return -EINVAL;
139b737a1eeSGaetan Rivet 	}
140b737a1eeSGaetan Rivet 	ret = 0;
141655fcd68SMatan Azrad 	fs_lock(dev, 0);
142b737a1eeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
143b737a1eeSGaetan Rivet 		int local_ret;
144b737a1eeSGaetan Rivet 
145b737a1eeSGaetan Rivet 		if (flow->flows[i] == NULL)
146b737a1eeSGaetan Rivet 			continue;
147b737a1eeSGaetan Rivet 		local_ret = rte_flow_destroy(PORT_ID(sdev),
148b737a1eeSGaetan Rivet 				flow->flows[i], error);
149ae80146cSMatan Azrad 		if ((local_ret = fs_err(sdev, local_ret))) {
150b737a1eeSGaetan Rivet 			ERROR("Failed to destroy flow on sub_device %d: %d",
151b737a1eeSGaetan Rivet 					i, local_ret);
152b737a1eeSGaetan Rivet 			if (ret == 0)
153b737a1eeSGaetan Rivet 				ret = local_ret;
154b737a1eeSGaetan Rivet 		}
155b737a1eeSGaetan Rivet 	}
156b737a1eeSGaetan Rivet 	TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);
157b737a1eeSGaetan Rivet 	fs_flow_release(&flow);
158655fcd68SMatan Azrad 	fs_unlock(dev, 0);
159b737a1eeSGaetan Rivet 	return ret;
160b737a1eeSGaetan Rivet }
161b737a1eeSGaetan Rivet 
162b737a1eeSGaetan Rivet static int
163b737a1eeSGaetan Rivet fs_flow_flush(struct rte_eth_dev *dev,
164b737a1eeSGaetan Rivet 	      struct rte_flow_error *error)
165b737a1eeSGaetan Rivet {
166b737a1eeSGaetan Rivet 	struct sub_device *sdev;
167b737a1eeSGaetan Rivet 	struct rte_flow *flow;
168b737a1eeSGaetan Rivet 	void *tmp;
169b737a1eeSGaetan Rivet 	uint8_t i;
170b737a1eeSGaetan Rivet 	int ret;
171b737a1eeSGaetan Rivet 
172655fcd68SMatan Azrad 	fs_lock(dev, 0);
173b737a1eeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
174b737a1eeSGaetan Rivet 		DEBUG("Calling rte_flow_flush on sub_device %d", i);
175b737a1eeSGaetan Rivet 		ret = rte_flow_flush(PORT_ID(sdev), error);
176ae80146cSMatan Azrad 		if ((ret = fs_err(sdev, ret))) {
177b737a1eeSGaetan Rivet 			ERROR("Operation rte_flow_flush failed for sub_device %d"
178b737a1eeSGaetan Rivet 			      " with error %d", i, ret);
179655fcd68SMatan Azrad 			fs_unlock(dev, 0);
180b737a1eeSGaetan Rivet 			return ret;
181b737a1eeSGaetan Rivet 		}
182b737a1eeSGaetan Rivet 	}
183b737a1eeSGaetan Rivet 	TAILQ_FOREACH_SAFE(flow, &PRIV(dev)->flow_list, next, tmp) {
184b737a1eeSGaetan Rivet 		TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);
185b737a1eeSGaetan Rivet 		fs_flow_release(&flow);
186b737a1eeSGaetan Rivet 	}
187655fcd68SMatan Azrad 	fs_unlock(dev, 0);
188b737a1eeSGaetan Rivet 	return 0;
189b737a1eeSGaetan Rivet }
190b737a1eeSGaetan Rivet 
191b737a1eeSGaetan Rivet static int
192b737a1eeSGaetan Rivet fs_flow_query(struct rte_eth_dev *dev,
193b737a1eeSGaetan Rivet 	      struct rte_flow *flow,
194fb8fd96dSDeclan Doherty 	      const struct rte_flow_action *action,
195b737a1eeSGaetan Rivet 	      void *arg,
196b737a1eeSGaetan Rivet 	      struct rte_flow_error *error)
197b737a1eeSGaetan Rivet {
198b737a1eeSGaetan Rivet 	struct sub_device *sdev;
199b737a1eeSGaetan Rivet 
200655fcd68SMatan Azrad 	fs_lock(dev, 0);
201b737a1eeSGaetan Rivet 	sdev = TX_SUBDEV(dev);
202b737a1eeSGaetan Rivet 	if (sdev != NULL) {
203ae80146cSMatan Azrad 		int ret = rte_flow_query(PORT_ID(sdev),
204ae80146cSMatan Azrad 					 flow->flows[SUB_ID(sdev)],
205fb8fd96dSDeclan Doherty 					 action, arg, error);
206ae80146cSMatan Azrad 
207655fcd68SMatan Azrad 		if ((ret = fs_err(sdev, ret))) {
208655fcd68SMatan Azrad 			fs_unlock(dev, 0);
209ae80146cSMatan Azrad 			return ret;
210b737a1eeSGaetan Rivet 		}
211655fcd68SMatan Azrad 	}
212655fcd68SMatan Azrad 	fs_unlock(dev, 0);
213b737a1eeSGaetan Rivet 	WARN("No active sub_device to query about its flow");
214b737a1eeSGaetan Rivet 	return -1;
215b737a1eeSGaetan Rivet }
216b737a1eeSGaetan Rivet 
2172cc52cd7SGaetan Rivet static int
2182cc52cd7SGaetan Rivet fs_flow_isolate(struct rte_eth_dev *dev,
2192cc52cd7SGaetan Rivet 		int set,
2202cc52cd7SGaetan Rivet 		struct rte_flow_error *error)
2212cc52cd7SGaetan Rivet {
2222cc52cd7SGaetan Rivet 	struct sub_device *sdev;
2232cc52cd7SGaetan Rivet 	uint8_t i;
2242cc52cd7SGaetan Rivet 	int ret;
2252cc52cd7SGaetan Rivet 
226655fcd68SMatan Azrad 	fs_lock(dev, 0);
2272cc52cd7SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
2282cc52cd7SGaetan Rivet 		if (sdev->state < DEV_PROBED)
2292cc52cd7SGaetan Rivet 			continue;
2302cc52cd7SGaetan Rivet 		DEBUG("Calling rte_flow_isolate on sub_device %d", i);
2312cc52cd7SGaetan Rivet 		if (PRIV(dev)->flow_isolated != sdev->flow_isolated)
2322cc52cd7SGaetan Rivet 			WARN("flow isolation mode of sub_device %d in incoherent state.",
2332cc52cd7SGaetan Rivet 				i);
2342cc52cd7SGaetan Rivet 		ret = rte_flow_isolate(PORT_ID(sdev), set, error);
235ae80146cSMatan Azrad 		if ((ret = fs_err(sdev, ret))) {
2362cc52cd7SGaetan Rivet 			ERROR("Operation rte_flow_isolate failed for sub_device %d"
2372cc52cd7SGaetan Rivet 			      " with error %d", i, ret);
238655fcd68SMatan Azrad 			fs_unlock(dev, 0);
2392cc52cd7SGaetan Rivet 			return ret;
2402cc52cd7SGaetan Rivet 		}
2412cc52cd7SGaetan Rivet 		sdev->flow_isolated = set;
2422cc52cd7SGaetan Rivet 	}
2432cc52cd7SGaetan Rivet 	PRIV(dev)->flow_isolated = set;
244655fcd68SMatan Azrad 	fs_unlock(dev, 0);
2452cc52cd7SGaetan Rivet 	return 0;
2462cc52cd7SGaetan Rivet }
2472cc52cd7SGaetan Rivet 
248b737a1eeSGaetan Rivet const struct rte_flow_ops fs_flow_ops = {
249b737a1eeSGaetan Rivet 	.validate = fs_flow_validate,
250b737a1eeSGaetan Rivet 	.create = fs_flow_create,
251b737a1eeSGaetan Rivet 	.destroy = fs_flow_destroy,
252b737a1eeSGaetan Rivet 	.flush = fs_flow_flush,
253b737a1eeSGaetan Rivet 	.query = fs_flow_query,
2542cc52cd7SGaetan Rivet 	.isolate = fs_flow_isolate,
255b737a1eeSGaetan Rivet };
256