1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2017 6WIND S.A.
3 * Copyright 2017 Mellanox Technologies, Ltd
4 */
5
6 #include <stddef.h>
7 #include <string.h>
8 #include <sys/queue.h>
9
10 #include <rte_errno.h>
11 #include <rte_malloc.h>
12 #include <rte_tailq.h>
13 #include <rte_flow.h>
14 #include <rte_flow_driver.h>
15
16 #include "failsafe_private.h"
17
18 static struct rte_flow *
fs_flow_allocate(const struct rte_flow_attr * attr,const struct rte_flow_item * items,const struct rte_flow_action * actions)19 fs_flow_allocate(const struct rte_flow_attr *attr,
20 const struct rte_flow_item *items,
21 const struct rte_flow_action *actions)
22 {
23 struct rte_flow *flow;
24 const struct rte_flow_conv_rule rule = {
25 .attr_ro = attr,
26 .pattern_ro = items,
27 .actions_ro = actions,
28 };
29 struct rte_flow_error error;
30 int ret;
31
32 ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, &error);
33 if (ret < 0) {
34 ERROR("Unable to process flow rule (%s): %s",
35 error.message ? error.message : "unspecified",
36 strerror(rte_errno));
37 return NULL;
38 }
39 flow = rte_zmalloc(NULL, offsetof(struct rte_flow, rule) + ret,
40 RTE_CACHE_LINE_SIZE);
41 if (flow == NULL) {
42 ERROR("Could not allocate new flow");
43 return NULL;
44 }
45 ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &flow->rule, ret, &rule,
46 &error);
47 if (ret < 0) {
48 ERROR("Failed to copy flow rule (%s): %s",
49 error.message ? error.message : "unspecified",
50 strerror(rte_errno));
51 rte_free(flow);
52 return NULL;
53 }
54 return flow;
55 }
56
57 static void
fs_flow_release(struct rte_flow ** flow)58 fs_flow_release(struct rte_flow **flow)
59 {
60 rte_free(*flow);
61 *flow = NULL;
62 }
63
64 static int
fs_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 * error)65 fs_flow_validate(struct rte_eth_dev *dev,
66 const struct rte_flow_attr *attr,
67 const struct rte_flow_item patterns[],
68 const struct rte_flow_action actions[],
69 struct rte_flow_error *error)
70 {
71 struct sub_device *sdev;
72 uint8_t i;
73 int ret;
74
75 fs_lock(dev, 0);
76 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
77 DEBUG("Calling rte_flow_validate on sub_device %d", i);
78 ret = rte_flow_validate(PORT_ID(sdev),
79 attr, patterns, actions, error);
80 if ((ret = fs_err(sdev, ret))) {
81 ERROR("Operation rte_flow_validate failed for sub_device %d"
82 " with error %d", i, ret);
83 fs_unlock(dev, 0);
84 return ret;
85 }
86 }
87 fs_unlock(dev, 0);
88 return 0;
89 }
90
91 static struct rte_flow *
fs_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 * error)92 fs_flow_create(struct rte_eth_dev *dev,
93 const struct rte_flow_attr *attr,
94 const struct rte_flow_item patterns[],
95 const struct rte_flow_action actions[],
96 struct rte_flow_error *error)
97 {
98 struct sub_device *sdev;
99 struct rte_flow *flow;
100 uint8_t i;
101
102 fs_lock(dev, 0);
103 flow = fs_flow_allocate(attr, patterns, actions);
104 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
105 flow->flows[i] = rte_flow_create(PORT_ID(sdev),
106 attr, patterns, actions, error);
107 if (flow->flows[i] == NULL && fs_err(sdev, -rte_errno)) {
108 ERROR("Failed to create flow on sub_device %d",
109 i);
110 goto err;
111 }
112 }
113 TAILQ_INSERT_TAIL(&PRIV(dev)->flow_list, flow, next);
114 fs_unlock(dev, 0);
115 return flow;
116 err:
117 FOREACH_SUBDEV(sdev, i, dev) {
118 if (flow->flows[i] != NULL)
119 rte_flow_destroy(PORT_ID(sdev),
120 flow->flows[i], error);
121 }
122 fs_flow_release(&flow);
123 fs_unlock(dev, 0);
124 return NULL;
125 }
126
127 static int
fs_flow_destroy(struct rte_eth_dev * dev,struct rte_flow * flow,struct rte_flow_error * error)128 fs_flow_destroy(struct rte_eth_dev *dev,
129 struct rte_flow *flow,
130 struct rte_flow_error *error)
131 {
132 struct sub_device *sdev;
133 uint8_t i;
134 int ret;
135
136 if (flow == NULL) {
137 ERROR("Invalid flow");
138 return -EINVAL;
139 }
140 ret = 0;
141 fs_lock(dev, 0);
142 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
143 int local_ret;
144
145 if (flow->flows[i] == NULL)
146 continue;
147 local_ret = rte_flow_destroy(PORT_ID(sdev),
148 flow->flows[i], error);
149 if ((local_ret = fs_err(sdev, local_ret))) {
150 ERROR("Failed to destroy flow on sub_device %d: %d",
151 i, local_ret);
152 if (ret == 0)
153 ret = local_ret;
154 }
155 }
156 TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);
157 fs_flow_release(&flow);
158 fs_unlock(dev, 0);
159 return ret;
160 }
161
162 static int
fs_flow_flush(struct rte_eth_dev * dev,struct rte_flow_error * error)163 fs_flow_flush(struct rte_eth_dev *dev,
164 struct rte_flow_error *error)
165 {
166 struct sub_device *sdev;
167 struct rte_flow *flow;
168 void *tmp;
169 uint8_t i;
170 int ret;
171
172 fs_lock(dev, 0);
173 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
174 DEBUG("Calling rte_flow_flush on sub_device %d", i);
175 ret = rte_flow_flush(PORT_ID(sdev), error);
176 if ((ret = fs_err(sdev, ret))) {
177 ERROR("Operation rte_flow_flush failed for sub_device %d"
178 " with error %d", i, ret);
179 fs_unlock(dev, 0);
180 return ret;
181 }
182 }
183 TAILQ_FOREACH_SAFE(flow, &PRIV(dev)->flow_list, next, tmp) {
184 TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);
185 fs_flow_release(&flow);
186 }
187 fs_unlock(dev, 0);
188 return 0;
189 }
190
191 static int
fs_flow_query(struct rte_eth_dev * dev,struct rte_flow * flow,const struct rte_flow_action * action,void * arg,struct rte_flow_error * error)192 fs_flow_query(struct rte_eth_dev *dev,
193 struct rte_flow *flow,
194 const struct rte_flow_action *action,
195 void *arg,
196 struct rte_flow_error *error)
197 {
198 struct sub_device *sdev;
199
200 fs_lock(dev, 0);
201 sdev = TX_SUBDEV(dev);
202 if (sdev != NULL) {
203 int ret = rte_flow_query(PORT_ID(sdev),
204 flow->flows[SUB_ID(sdev)],
205 action, arg, error);
206
207 if ((ret = fs_err(sdev, ret))) {
208 fs_unlock(dev, 0);
209 return ret;
210 }
211 }
212 fs_unlock(dev, 0);
213 WARN("No active sub_device to query about its flow");
214 return -1;
215 }
216
217 static int
fs_flow_isolate(struct rte_eth_dev * dev,int set,struct rte_flow_error * error)218 fs_flow_isolate(struct rte_eth_dev *dev,
219 int set,
220 struct rte_flow_error *error)
221 {
222 struct sub_device *sdev;
223 uint8_t i;
224 int ret;
225
226 fs_lock(dev, 0);
227 FOREACH_SUBDEV(sdev, i, dev) {
228 if (sdev->state < DEV_PROBED)
229 continue;
230 DEBUG("Calling rte_flow_isolate on sub_device %d", i);
231 if (PRIV(dev)->flow_isolated != sdev->flow_isolated)
232 WARN("flow isolation mode of sub_device %d in incoherent state.",
233 i);
234 ret = rte_flow_isolate(PORT_ID(sdev), set, error);
235 if ((ret = fs_err(sdev, ret))) {
236 ERROR("Operation rte_flow_isolate failed for sub_device %d"
237 " with error %d", i, ret);
238 fs_unlock(dev, 0);
239 return ret;
240 }
241 sdev->flow_isolated = set;
242 }
243 PRIV(dev)->flow_isolated = set;
244 fs_unlock(dev, 0);
245 return 0;
246 }
247
248 const struct rte_flow_ops fs_flow_ops = {
249 .validate = fs_flow_validate,
250 .create = fs_flow_create,
251 .destroy = fs_flow_destroy,
252 .flush = fs_flow_flush,
253 .query = fs_flow_query,
254 .isolate = fs_flow_isolate,
255 };
256