xref: /dpdk/drivers/net/failsafe/failsafe_flow.c (revision fb8fd96d4251f615a0e7acdb3af8b4546f900b4d)
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 
6b737a1eeSGaetan Rivet #include <sys/queue.h>
7b737a1eeSGaetan Rivet 
8b737a1eeSGaetan Rivet #include <rte_malloc.h>
9b737a1eeSGaetan Rivet #include <rte_tailq.h>
10b737a1eeSGaetan Rivet #include <rte_flow.h>
11b737a1eeSGaetan Rivet #include <rte_flow_driver.h>
12b737a1eeSGaetan Rivet 
13b737a1eeSGaetan Rivet #include "failsafe_private.h"
14b737a1eeSGaetan Rivet 
15b737a1eeSGaetan Rivet static struct rte_flow *
16b737a1eeSGaetan Rivet fs_flow_allocate(const struct rte_flow_attr *attr,
17b737a1eeSGaetan Rivet 		 const struct rte_flow_item *items,
18b737a1eeSGaetan Rivet 		 const struct rte_flow_action *actions)
19b737a1eeSGaetan Rivet {
20b737a1eeSGaetan Rivet 	struct rte_flow *flow;
21b737a1eeSGaetan Rivet 	size_t fdsz;
22b737a1eeSGaetan Rivet 
23b737a1eeSGaetan Rivet 	fdsz = rte_flow_copy(NULL, 0, attr, items, actions);
24b737a1eeSGaetan Rivet 	flow = rte_zmalloc(NULL,
25b737a1eeSGaetan Rivet 			   sizeof(struct rte_flow) + fdsz,
26b737a1eeSGaetan Rivet 			   RTE_CACHE_LINE_SIZE);
27b737a1eeSGaetan Rivet 	if (flow == NULL) {
28b737a1eeSGaetan Rivet 		ERROR("Could not allocate new flow");
29b737a1eeSGaetan Rivet 		return NULL;
30b737a1eeSGaetan Rivet 	}
31b737a1eeSGaetan Rivet 	flow->fd = (void *)((uintptr_t)flow + sizeof(*flow));
32b737a1eeSGaetan Rivet 	if (rte_flow_copy(flow->fd, fdsz, attr, items, actions) != fdsz) {
33b737a1eeSGaetan Rivet 		ERROR("Failed to copy flow description");
34b737a1eeSGaetan Rivet 		rte_free(flow);
35b737a1eeSGaetan Rivet 		return NULL;
36b737a1eeSGaetan Rivet 	}
37b737a1eeSGaetan Rivet 	return flow;
38b737a1eeSGaetan Rivet }
39b737a1eeSGaetan Rivet 
40b737a1eeSGaetan Rivet static void
41b737a1eeSGaetan Rivet fs_flow_release(struct rte_flow **flow)
42b737a1eeSGaetan Rivet {
43b737a1eeSGaetan Rivet 	rte_free(*flow);
44b737a1eeSGaetan Rivet 	*flow = NULL;
45b737a1eeSGaetan Rivet }
46b737a1eeSGaetan Rivet 
47b737a1eeSGaetan Rivet static int
48b737a1eeSGaetan Rivet fs_flow_validate(struct rte_eth_dev *dev,
49b737a1eeSGaetan Rivet 		 const struct rte_flow_attr *attr,
50b737a1eeSGaetan Rivet 		 const struct rte_flow_item patterns[],
51b737a1eeSGaetan Rivet 		 const struct rte_flow_action actions[],
52b737a1eeSGaetan Rivet 		 struct rte_flow_error *error)
53b737a1eeSGaetan Rivet {
54b737a1eeSGaetan Rivet 	struct sub_device *sdev;
55b737a1eeSGaetan Rivet 	uint8_t i;
56b737a1eeSGaetan Rivet 	int ret;
57b737a1eeSGaetan Rivet 
58655fcd68SMatan Azrad 	fs_lock(dev, 0);
59b737a1eeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
60b737a1eeSGaetan Rivet 		DEBUG("Calling rte_flow_validate on sub_device %d", i);
61b737a1eeSGaetan Rivet 		ret = rte_flow_validate(PORT_ID(sdev),
62b737a1eeSGaetan Rivet 				attr, patterns, actions, error);
63ae80146cSMatan Azrad 		if ((ret = fs_err(sdev, ret))) {
64b737a1eeSGaetan Rivet 			ERROR("Operation rte_flow_validate failed for sub_device %d"
65b737a1eeSGaetan Rivet 			      " with error %d", i, ret);
66655fcd68SMatan Azrad 			fs_unlock(dev, 0);
67b737a1eeSGaetan Rivet 			return ret;
68b737a1eeSGaetan Rivet 		}
69b737a1eeSGaetan Rivet 	}
70655fcd68SMatan Azrad 	fs_unlock(dev, 0);
71b737a1eeSGaetan Rivet 	return 0;
72b737a1eeSGaetan Rivet }
73b737a1eeSGaetan Rivet 
74b737a1eeSGaetan Rivet static struct rte_flow *
75b737a1eeSGaetan Rivet fs_flow_create(struct rte_eth_dev *dev,
76b737a1eeSGaetan Rivet 	       const struct rte_flow_attr *attr,
77b737a1eeSGaetan Rivet 	       const struct rte_flow_item patterns[],
78b737a1eeSGaetan Rivet 	       const struct rte_flow_action actions[],
79b737a1eeSGaetan Rivet 	       struct rte_flow_error *error)
80b737a1eeSGaetan Rivet {
81b737a1eeSGaetan Rivet 	struct sub_device *sdev;
82b737a1eeSGaetan Rivet 	struct rte_flow *flow;
83b737a1eeSGaetan Rivet 	uint8_t i;
84b737a1eeSGaetan Rivet 
85655fcd68SMatan Azrad 	fs_lock(dev, 0);
86b737a1eeSGaetan Rivet 	flow = fs_flow_allocate(attr, patterns, actions);
87b737a1eeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
88b737a1eeSGaetan Rivet 		flow->flows[i] = rte_flow_create(PORT_ID(sdev),
89b737a1eeSGaetan Rivet 				attr, patterns, actions, error);
90ae80146cSMatan Azrad 		if (flow->flows[i] == NULL && fs_err(sdev, -rte_errno)) {
91b737a1eeSGaetan Rivet 			ERROR("Failed to create flow on sub_device %d",
92b737a1eeSGaetan Rivet 				i);
93b737a1eeSGaetan Rivet 			goto err;
94b737a1eeSGaetan Rivet 		}
95b737a1eeSGaetan Rivet 	}
96b737a1eeSGaetan Rivet 	TAILQ_INSERT_TAIL(&PRIV(dev)->flow_list, flow, next);
97655fcd68SMatan Azrad 	fs_unlock(dev, 0);
98b737a1eeSGaetan Rivet 	return flow;
99b737a1eeSGaetan Rivet err:
100b737a1eeSGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
101b737a1eeSGaetan Rivet 		if (flow->flows[i] != NULL)
102b737a1eeSGaetan Rivet 			rte_flow_destroy(PORT_ID(sdev),
103b737a1eeSGaetan Rivet 				flow->flows[i], error);
104b737a1eeSGaetan Rivet 	}
105b737a1eeSGaetan Rivet 	fs_flow_release(&flow);
106655fcd68SMatan Azrad 	fs_unlock(dev, 0);
107b737a1eeSGaetan Rivet 	return NULL;
108b737a1eeSGaetan Rivet }
109b737a1eeSGaetan Rivet 
110b737a1eeSGaetan Rivet static int
111b737a1eeSGaetan Rivet fs_flow_destroy(struct rte_eth_dev *dev,
112b737a1eeSGaetan Rivet 		struct rte_flow *flow,
113b737a1eeSGaetan Rivet 		struct rte_flow_error *error)
114b737a1eeSGaetan Rivet {
115b737a1eeSGaetan Rivet 	struct sub_device *sdev;
116b737a1eeSGaetan Rivet 	uint8_t i;
117b737a1eeSGaetan Rivet 	int ret;
118b737a1eeSGaetan Rivet 
119b737a1eeSGaetan Rivet 	if (flow == NULL) {
120b737a1eeSGaetan Rivet 		ERROR("Invalid flow");
121b737a1eeSGaetan Rivet 		return -EINVAL;
122b737a1eeSGaetan Rivet 	}
123b737a1eeSGaetan Rivet 	ret = 0;
124655fcd68SMatan Azrad 	fs_lock(dev, 0);
125b737a1eeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
126b737a1eeSGaetan Rivet 		int local_ret;
127b737a1eeSGaetan Rivet 
128b737a1eeSGaetan Rivet 		if (flow->flows[i] == NULL)
129b737a1eeSGaetan Rivet 			continue;
130b737a1eeSGaetan Rivet 		local_ret = rte_flow_destroy(PORT_ID(sdev),
131b737a1eeSGaetan Rivet 				flow->flows[i], error);
132ae80146cSMatan Azrad 		if ((local_ret = fs_err(sdev, local_ret))) {
133b737a1eeSGaetan Rivet 			ERROR("Failed to destroy flow on sub_device %d: %d",
134b737a1eeSGaetan Rivet 					i, local_ret);
135b737a1eeSGaetan Rivet 			if (ret == 0)
136b737a1eeSGaetan Rivet 				ret = local_ret;
137b737a1eeSGaetan Rivet 		}
138b737a1eeSGaetan Rivet 	}
139b737a1eeSGaetan Rivet 	TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);
140b737a1eeSGaetan Rivet 	fs_flow_release(&flow);
141655fcd68SMatan Azrad 	fs_unlock(dev, 0);
142b737a1eeSGaetan Rivet 	return ret;
143b737a1eeSGaetan Rivet }
144b737a1eeSGaetan Rivet 
145b737a1eeSGaetan Rivet static int
146b737a1eeSGaetan Rivet fs_flow_flush(struct rte_eth_dev *dev,
147b737a1eeSGaetan Rivet 	      struct rte_flow_error *error)
148b737a1eeSGaetan Rivet {
149b737a1eeSGaetan Rivet 	struct sub_device *sdev;
150b737a1eeSGaetan Rivet 	struct rte_flow *flow;
151b737a1eeSGaetan Rivet 	void *tmp;
152b737a1eeSGaetan Rivet 	uint8_t i;
153b737a1eeSGaetan Rivet 	int ret;
154b737a1eeSGaetan Rivet 
155655fcd68SMatan Azrad 	fs_lock(dev, 0);
156b737a1eeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
157b737a1eeSGaetan Rivet 		DEBUG("Calling rte_flow_flush on sub_device %d", i);
158b737a1eeSGaetan Rivet 		ret = rte_flow_flush(PORT_ID(sdev), error);
159ae80146cSMatan Azrad 		if ((ret = fs_err(sdev, ret))) {
160b737a1eeSGaetan Rivet 			ERROR("Operation rte_flow_flush failed for sub_device %d"
161b737a1eeSGaetan Rivet 			      " with error %d", i, ret);
162655fcd68SMatan Azrad 			fs_unlock(dev, 0);
163b737a1eeSGaetan Rivet 			return ret;
164b737a1eeSGaetan Rivet 		}
165b737a1eeSGaetan Rivet 	}
166b737a1eeSGaetan Rivet 	TAILQ_FOREACH_SAFE(flow, &PRIV(dev)->flow_list, next, tmp) {
167b737a1eeSGaetan Rivet 		TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);
168b737a1eeSGaetan Rivet 		fs_flow_release(&flow);
169b737a1eeSGaetan Rivet 	}
170655fcd68SMatan Azrad 	fs_unlock(dev, 0);
171b737a1eeSGaetan Rivet 	return 0;
172b737a1eeSGaetan Rivet }
173b737a1eeSGaetan Rivet 
174b737a1eeSGaetan Rivet static int
175b737a1eeSGaetan Rivet fs_flow_query(struct rte_eth_dev *dev,
176b737a1eeSGaetan Rivet 	      struct rte_flow *flow,
177*fb8fd96dSDeclan Doherty 	      const struct rte_flow_action *action,
178b737a1eeSGaetan Rivet 	      void *arg,
179b737a1eeSGaetan Rivet 	      struct rte_flow_error *error)
180b737a1eeSGaetan Rivet {
181b737a1eeSGaetan Rivet 	struct sub_device *sdev;
182b737a1eeSGaetan Rivet 
183655fcd68SMatan Azrad 	fs_lock(dev, 0);
184b737a1eeSGaetan Rivet 	sdev = TX_SUBDEV(dev);
185b737a1eeSGaetan Rivet 	if (sdev != NULL) {
186ae80146cSMatan Azrad 		int ret = rte_flow_query(PORT_ID(sdev),
187ae80146cSMatan Azrad 					 flow->flows[SUB_ID(sdev)],
188*fb8fd96dSDeclan Doherty 					 action, arg, error);
189ae80146cSMatan Azrad 
190655fcd68SMatan Azrad 		if ((ret = fs_err(sdev, ret))) {
191655fcd68SMatan Azrad 			fs_unlock(dev, 0);
192ae80146cSMatan Azrad 			return ret;
193b737a1eeSGaetan Rivet 		}
194655fcd68SMatan Azrad 	}
195655fcd68SMatan Azrad 	fs_unlock(dev, 0);
196b737a1eeSGaetan Rivet 	WARN("No active sub_device to query about its flow");
197b737a1eeSGaetan Rivet 	return -1;
198b737a1eeSGaetan Rivet }
199b737a1eeSGaetan Rivet 
2002cc52cd7SGaetan Rivet static int
2012cc52cd7SGaetan Rivet fs_flow_isolate(struct rte_eth_dev *dev,
2022cc52cd7SGaetan Rivet 		int set,
2032cc52cd7SGaetan Rivet 		struct rte_flow_error *error)
2042cc52cd7SGaetan Rivet {
2052cc52cd7SGaetan Rivet 	struct sub_device *sdev;
2062cc52cd7SGaetan Rivet 	uint8_t i;
2072cc52cd7SGaetan Rivet 	int ret;
2082cc52cd7SGaetan Rivet 
209655fcd68SMatan Azrad 	fs_lock(dev, 0);
2102cc52cd7SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
2112cc52cd7SGaetan Rivet 		if (sdev->state < DEV_PROBED)
2122cc52cd7SGaetan Rivet 			continue;
2132cc52cd7SGaetan Rivet 		DEBUG("Calling rte_flow_isolate on sub_device %d", i);
2142cc52cd7SGaetan Rivet 		if (PRIV(dev)->flow_isolated != sdev->flow_isolated)
2152cc52cd7SGaetan Rivet 			WARN("flow isolation mode of sub_device %d in incoherent state.",
2162cc52cd7SGaetan Rivet 				i);
2172cc52cd7SGaetan Rivet 		ret = rte_flow_isolate(PORT_ID(sdev), set, error);
218ae80146cSMatan Azrad 		if ((ret = fs_err(sdev, ret))) {
2192cc52cd7SGaetan Rivet 			ERROR("Operation rte_flow_isolate failed for sub_device %d"
2202cc52cd7SGaetan Rivet 			      " with error %d", i, ret);
221655fcd68SMatan Azrad 			fs_unlock(dev, 0);
2222cc52cd7SGaetan Rivet 			return ret;
2232cc52cd7SGaetan Rivet 		}
2242cc52cd7SGaetan Rivet 		sdev->flow_isolated = set;
2252cc52cd7SGaetan Rivet 	}
2262cc52cd7SGaetan Rivet 	PRIV(dev)->flow_isolated = set;
227655fcd68SMatan Azrad 	fs_unlock(dev, 0);
2282cc52cd7SGaetan Rivet 	return 0;
2292cc52cd7SGaetan Rivet }
2302cc52cd7SGaetan Rivet 
231b737a1eeSGaetan Rivet const struct rte_flow_ops fs_flow_ops = {
232b737a1eeSGaetan Rivet 	.validate = fs_flow_validate,
233b737a1eeSGaetan Rivet 	.create = fs_flow_create,
234b737a1eeSGaetan Rivet 	.destroy = fs_flow_destroy,
235b737a1eeSGaetan Rivet 	.flush = fs_flow_flush,
236b737a1eeSGaetan Rivet 	.query = fs_flow_query,
2372cc52cd7SGaetan Rivet 	.isolate = fs_flow_isolate,
238b737a1eeSGaetan Rivet };
239