Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2023 Corigine, Inc.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "nfp_net_flow.h"
7 : :
8 : : #include <rte_flow_driver.h>
9 : : #include <rte_hash.h>
10 : : #include <rte_jhash.h>
11 : : #include <rte_malloc.h>
12 : :
13 : : #include "nfp_logs.h"
14 : : #include "nfp_net_cmsg.h"
15 : :
16 : : /* Static initializer for a list of subsequent item types */
17 : : #define NEXT_ITEM(...) \
18 : : ((const enum rte_flow_item_type []){ \
19 : : __VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \
20 : : })
21 : :
22 : : /* Process structure associated with a flow item */
23 : : struct nfp_net_flow_item_proc {
24 : : /* Bit-mask for fields supported by this PMD. */
25 : : const void *mask_support;
26 : : /* Bit-mask to use when @p item->mask is not provided. */
27 : : const void *mask_default;
28 : : /* Size in bytes for @p mask_support and @p mask_default. */
29 : : const uint32_t mask_sz;
30 : : /* Merge a pattern item into a flow rule handle. */
31 : : int (*merge)(struct rte_flow *nfp_flow,
32 : : const struct rte_flow_item *item,
33 : : const struct nfp_net_flow_item_proc *proc);
34 : : /* List of possible subsequent items. */
35 : : const enum rte_flow_item_type *const next_item;
36 : : };
37 : :
38 : : static int
39 : 0 : nfp_net_flow_table_add(struct nfp_net_priv *priv,
40 : : struct rte_flow *nfp_flow)
41 : : {
42 : : int ret;
43 : :
44 : 0 : ret = rte_hash_add_key_data(priv->flow_table, &nfp_flow->hash_key, nfp_flow);
45 [ # # ]: 0 : if (ret != 0) {
46 : 0 : PMD_DRV_LOG(ERR, "Add to flow table failed.");
47 : 0 : return ret;
48 : : }
49 : :
50 : : return 0;
51 : : }
52 : :
53 : : static int
54 : 0 : nfp_net_flow_table_delete(struct nfp_net_priv *priv,
55 : : struct rte_flow *nfp_flow)
56 : : {
57 : : int ret;
58 : :
59 : 0 : ret = rte_hash_del_key(priv->flow_table, &nfp_flow->hash_key);
60 [ # # ]: 0 : if (ret < 0) {
61 : 0 : PMD_DRV_LOG(ERR, "Delete from flow table failed.");
62 : 0 : return ret;
63 : : }
64 : :
65 : : return 0;
66 : : }
67 : :
68 : : static struct rte_flow *
69 : 0 : nfp_net_flow_table_search(struct nfp_net_priv *priv,
70 : : struct rte_flow *nfp_flow)
71 : : {
72 : : int index;
73 : : struct rte_flow *flow_find;
74 : :
75 : 0 : index = rte_hash_lookup_data(priv->flow_table, &nfp_flow->hash_key,
76 : : (void **)&flow_find);
77 [ # # ]: 0 : if (index < 0) {
78 : 0 : PMD_DRV_LOG(DEBUG, "Data NOT found in the flow table.");
79 : 0 : return NULL;
80 : : }
81 : :
82 : 0 : return flow_find;
83 : : }
84 : :
85 : : static int
86 : 0 : nfp_net_flow_position_acquire(struct nfp_net_priv *priv,
87 : : uint32_t priority,
88 : : struct rte_flow *nfp_flow)
89 : : {
90 : : uint32_t i;
91 : :
92 [ # # ]: 0 : if (priority != 0) {
93 : 0 : i = NFP_NET_FLOW_LIMIT - priority - 1;
94 : :
95 [ # # ]: 0 : if (priv->flow_position[i]) {
96 : 0 : PMD_DRV_LOG(ERR, "There is already a flow rule in this place.");
97 : 0 : return -EAGAIN;
98 : : }
99 : :
100 : 0 : priv->flow_position[i] = true;
101 : 0 : nfp_flow->position = priority;
102 : 0 : return 0;
103 : : }
104 : :
105 [ # # ]: 0 : for (i = 0; i < NFP_NET_FLOW_LIMIT; i++) {
106 [ # # ]: 0 : if (!priv->flow_position[i]) {
107 : 0 : priv->flow_position[i] = true;
108 : 0 : break;
109 : : }
110 : : }
111 : :
112 [ # # ]: 0 : if (i == NFP_NET_FLOW_LIMIT) {
113 : 0 : PMD_DRV_LOG(ERR, "The limited flow number is reach.");
114 : 0 : return -ERANGE;
115 : : }
116 : :
117 : 0 : nfp_flow->position = NFP_NET_FLOW_LIMIT - i - 1;
118 : :
119 : 0 : return 0;
120 : : }
121 : :
122 : : static void
123 : : nfp_net_flow_position_free(struct nfp_net_priv *priv,
124 : : struct rte_flow *nfp_flow)
125 : : {
126 : 0 : priv->flow_position[nfp_flow->position] = false;
127 : : }
128 : :
129 : : static struct rte_flow *
130 : 0 : nfp_net_flow_alloc(struct nfp_net_priv *priv,
131 : : uint32_t priority,
132 : : uint32_t match_len,
133 : : uint32_t action_len,
134 : : uint32_t port_id)
135 : : {
136 : : int ret;
137 : : char *data;
138 : : struct rte_flow *nfp_flow;
139 : : struct nfp_net_flow_payload *payload;
140 : :
141 : 0 : nfp_flow = rte_zmalloc("nfp_flow", sizeof(struct rte_flow), 0);
142 [ # # ]: 0 : if (nfp_flow == NULL)
143 : : return NULL;
144 : :
145 : 0 : data = rte_zmalloc("nfp_flow_payload", match_len + action_len, 0);
146 [ # # ]: 0 : if (data == NULL)
147 : 0 : goto free_flow;
148 : :
149 : 0 : ret = nfp_net_flow_position_acquire(priv, priority, nfp_flow);
150 [ # # ]: 0 : if (ret != 0)
151 : 0 : goto free_payload;
152 : :
153 : 0 : nfp_flow->port_id = port_id;
154 : : payload = &nfp_flow->payload;
155 : 0 : payload->match_len = match_len;
156 : 0 : payload->action_len = action_len;
157 : 0 : payload->match_data = data;
158 : 0 : payload->action_data = data + match_len;
159 : :
160 : 0 : return nfp_flow;
161 : :
162 : : free_payload:
163 : 0 : rte_free(data);
164 : 0 : free_flow:
165 : 0 : rte_free(nfp_flow);
166 : :
167 : 0 : return NULL;
168 : : }
169 : :
170 : : static void
171 : : nfp_net_flow_free(struct nfp_net_priv *priv,
172 : : struct rte_flow *nfp_flow)
173 : : {
174 : : nfp_net_flow_position_free(priv, nfp_flow);
175 : 0 : rte_free(nfp_flow->payload.match_data);
176 : 0 : rte_free(nfp_flow);
177 : : }
178 : :
179 : : static int
180 : 0 : nfp_net_flow_calculate_items(const struct rte_flow_item items[],
181 : : uint32_t *match_len)
182 : : {
183 : : int ret = -EINVAL;
184 : : const struct rte_flow_item *item;
185 : :
186 [ # # ]: 0 : for (item = items; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {
187 [ # # # # ]: 0 : switch (item->type) {
188 : 0 : case RTE_FLOW_ITEM_TYPE_ETH:
189 : 0 : PMD_DRV_LOG(DEBUG, "RTE_FLOW_ITEM_TYPE_ETH detected");
190 : 0 : *match_len = sizeof(struct nfp_net_cmsg_match_eth);
191 : : ret = 0;
192 : : break;
193 : 0 : case RTE_FLOW_ITEM_TYPE_IPV4:
194 : 0 : PMD_DRV_LOG(DEBUG, "RTE_FLOW_ITEM_TYPE_IPV4 detected");
195 : 0 : *match_len = sizeof(struct nfp_net_cmsg_match_v4);
196 : 0 : return 0;
197 : 0 : case RTE_FLOW_ITEM_TYPE_IPV6:
198 : 0 : PMD_DRV_LOG(DEBUG, "RTE_FLOW_ITEM_TYPE_IPV6 detected");
199 : 0 : *match_len = sizeof(struct nfp_net_cmsg_match_v6);
200 : 0 : return 0;
201 : 0 : default:
202 : 0 : PMD_DRV_LOG(ERR, "Can't calculate match length");
203 : 0 : *match_len = 0;
204 : 0 : return -ENOTSUP;
205 : : }
206 : : }
207 : :
208 : : return ret;
209 : : }
210 : :
211 : : static int
212 : 0 : nfp_net_flow_merge_eth(__rte_unused struct rte_flow *nfp_flow,
213 : : const struct rte_flow_item *item,
214 : : __rte_unused const struct nfp_net_flow_item_proc *proc)
215 : : {
216 : : struct nfp_net_cmsg_match_eth *eth;
217 : : const struct rte_flow_item_eth *spec;
218 : :
219 : 0 : spec = item->spec;
220 [ # # ]: 0 : if (spec == NULL) {
221 : 0 : PMD_DRV_LOG(ERR, "NFP flow merge eth: no item->spec!");
222 : 0 : return -EINVAL;
223 : : }
224 : :
225 : 0 : nfp_flow->payload.cmsg_type = NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE;
226 : :
227 : 0 : eth = (struct nfp_net_cmsg_match_eth *)nfp_flow->payload.match_data;
228 [ # # ]: 0 : eth->ether_type = rte_be_to_cpu_16(spec->type);
229 : :
230 : 0 : return 0;
231 : : }
232 : :
233 : : static int
234 : 0 : nfp_net_flow_merge_ipv4(struct rte_flow *nfp_flow,
235 : : const struct rte_flow_item *item,
236 : : const struct nfp_net_flow_item_proc *proc)
237 : : {
238 : : struct nfp_net_cmsg_match_v4 *ipv4;
239 : : const struct rte_flow_item_ipv4 *mask;
240 : : const struct rte_flow_item_ipv4 *spec;
241 : :
242 : 0 : nfp_flow->payload.cmsg_type = NFP_NET_CFG_MBOX_CMD_FS_ADD_V4;
243 : :
244 : 0 : spec = item->spec;
245 [ # # ]: 0 : if (spec == NULL) {
246 : 0 : PMD_DRV_LOG(DEBUG, "NFP flow merge ipv4: no item->spec!");
247 : 0 : return 0;
248 : : }
249 : :
250 [ # # ]: 0 : mask = (item->mask != NULL) ? item->mask : proc->mask_default;
251 : :
252 : 0 : ipv4 = (struct nfp_net_cmsg_match_v4 *)nfp_flow->payload.match_data;
253 : :
254 : 0 : ipv4->l4_protocol_mask = mask->hdr.next_proto_id;
255 [ # # ]: 0 : ipv4->src_ipv4_mask = rte_be_to_cpu_32(mask->hdr.src_addr);
256 [ # # ]: 0 : ipv4->dst_ipv4_mask = rte_be_to_cpu_32(mask->hdr.dst_addr);
257 : :
258 : 0 : ipv4->l4_protocol = spec->hdr.next_proto_id;
259 [ # # ]: 0 : ipv4->src_ipv4 = rte_be_to_cpu_32(spec->hdr.src_addr);
260 [ # # ]: 0 : ipv4->dst_ipv4 = rte_be_to_cpu_32(spec->hdr.dst_addr);
261 : :
262 : 0 : return 0;
263 : : }
264 : :
265 : : static int
266 : 0 : nfp_net_flow_merge_ipv6(struct rte_flow *nfp_flow,
267 : : const struct rte_flow_item *item,
268 : : const struct nfp_net_flow_item_proc *proc)
269 : : {
270 : : uint32_t i;
271 : : struct nfp_net_cmsg_match_v6 *ipv6;
272 : : const struct rte_flow_item_ipv6 *mask;
273 : : const struct rte_flow_item_ipv6 *spec;
274 : :
275 : 0 : nfp_flow->payload.cmsg_type = NFP_NET_CFG_MBOX_CMD_FS_ADD_V6;
276 : :
277 : 0 : spec = item->spec;
278 [ # # ]: 0 : if (spec == NULL) {
279 : 0 : PMD_DRV_LOG(DEBUG, "NFP flow merge ipv6: no item->spec!");
280 : 0 : return 0;
281 : : }
282 : :
283 [ # # ]: 0 : mask = (item->mask != NULL) ? item->mask : proc->mask_default;
284 : :
285 : 0 : ipv6 = (struct nfp_net_cmsg_match_v6 *)nfp_flow->payload.match_data;
286 : :
287 : 0 : ipv6->l4_protocol_mask = mask->hdr.proto;
288 [ # # ]: 0 : for (i = 0; i < sizeof(ipv6->src_ipv6); i += 4) {
289 : 0 : ipv6->src_ipv6_mask[i] = mask->hdr.src_addr[i + 3];
290 : 0 : ipv6->src_ipv6_mask[i + 1] = mask->hdr.src_addr[i + 2];
291 : 0 : ipv6->src_ipv6_mask[i + 2] = mask->hdr.src_addr[i + 1];
292 : 0 : ipv6->src_ipv6_mask[i + 3] = mask->hdr.src_addr[i];
293 : :
294 : 0 : ipv6->dst_ipv6_mask[i] = mask->hdr.dst_addr[i + 3];
295 : 0 : ipv6->dst_ipv6_mask[i + 1] = mask->hdr.dst_addr[i + 2];
296 : 0 : ipv6->dst_ipv6_mask[i + 2] = mask->hdr.dst_addr[i + 1];
297 : 0 : ipv6->dst_ipv6_mask[i + 3] = mask->hdr.dst_addr[i];
298 : : }
299 : :
300 : 0 : ipv6->l4_protocol = spec->hdr.proto;
301 [ # # ]: 0 : for (i = 0; i < sizeof(ipv6->src_ipv6); i += 4) {
302 : 0 : ipv6->src_ipv6[i] = spec->hdr.src_addr[i + 3];
303 : 0 : ipv6->src_ipv6[i + 1] = spec->hdr.src_addr[i + 2];
304 : 0 : ipv6->src_ipv6[i + 2] = spec->hdr.src_addr[i + 1];
305 : 0 : ipv6->src_ipv6[i + 3] = spec->hdr.src_addr[i];
306 : :
307 : 0 : ipv6->dst_ipv6[i] = spec->hdr.dst_addr[i + 3];
308 : 0 : ipv6->dst_ipv6[i + 1] = spec->hdr.dst_addr[i + 2];
309 : 0 : ipv6->dst_ipv6[i + 2] = spec->hdr.dst_addr[i + 1];
310 : 0 : ipv6->dst_ipv6[i + 3] = spec->hdr.dst_addr[i];
311 : : }
312 : :
313 : : return 0;
314 : : }
315 : :
316 : : static int
317 : 0 : nfp_flow_merge_l4(struct rte_flow *nfp_flow,
318 : : const struct rte_flow_item *item,
319 : : const struct nfp_net_flow_item_proc *proc)
320 : : {
321 : : const struct rte_flow_item_tcp *mask;
322 : : const struct rte_flow_item_tcp *spec;
323 : : struct nfp_net_cmsg_match_v4 *ipv4 = NULL;
324 : : struct nfp_net_cmsg_match_v6 *ipv6 = NULL;
325 : :
326 : 0 : spec = item->spec;
327 [ # # ]: 0 : if (spec == NULL) {
328 : 0 : PMD_DRV_LOG(ERR, "NFP flow merge tcp: no item->spec!");
329 : 0 : return -EINVAL;
330 : : }
331 : :
332 [ # # ]: 0 : mask = (item->mask != NULL) ? item->mask : proc->mask_default;
333 : :
334 [ # # # ]: 0 : switch (nfp_flow->payload.cmsg_type) {
335 : 0 : case NFP_NET_CFG_MBOX_CMD_FS_ADD_V4:
336 : 0 : ipv4 = (struct nfp_net_cmsg_match_v4 *)nfp_flow->payload.match_data;
337 : : break;
338 : 0 : case NFP_NET_CFG_MBOX_CMD_FS_ADD_V6:
339 : 0 : ipv6 = (struct nfp_net_cmsg_match_v6 *)nfp_flow->payload.match_data;
340 : : break;
341 : 0 : default:
342 : 0 : PMD_DRV_LOG(ERR, "L3 layer neither IPv4 nor IPv6.");
343 : 0 : return -EINVAL;
344 : : }
345 : :
346 [ # # ]: 0 : if (ipv4 != NULL) {
347 [ # # ]: 0 : ipv4->src_port_mask = rte_be_to_cpu_16(mask->hdr.src_port);
348 [ # # ]: 0 : ipv4->dst_port_mask = rte_be_to_cpu_16(mask->hdr.dst_port);
349 : :
350 [ # # ]: 0 : ipv4->src_port = rte_be_to_cpu_16(spec->hdr.src_port);
351 [ # # ]: 0 : ipv4->dst_port = rte_be_to_cpu_16(spec->hdr.dst_port);
352 [ # # ]: 0 : } else if (ipv6 != NULL) {
353 [ # # ]: 0 : ipv6->src_port_mask = rte_be_to_cpu_16(mask->hdr.src_port);
354 [ # # ]: 0 : ipv6->dst_port_mask = rte_be_to_cpu_16(mask->hdr.dst_port);
355 : :
356 [ # # ]: 0 : ipv6->src_port = rte_be_to_cpu_16(spec->hdr.src_port);
357 [ # # ]: 0 : ipv6->dst_port = rte_be_to_cpu_16(spec->hdr.dst_port);
358 : : } else {
359 : 0 : PMD_DRV_LOG(ERR, "No valid L3 layer pointer.");
360 : 0 : return -EINVAL;
361 : : }
362 : :
363 : : return 0;
364 : : }
365 : :
366 : : /* Graph of supported items and associated process function */
367 : : static const struct nfp_net_flow_item_proc nfp_net_flow_item_proc_list[] = {
368 : : [RTE_FLOW_ITEM_TYPE_END] = {
369 : : .next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_ETH,
370 : : RTE_FLOW_ITEM_TYPE_IPV4,
371 : : RTE_FLOW_ITEM_TYPE_IPV6),
372 : : },
373 : : [RTE_FLOW_ITEM_TYPE_ETH] = {
374 : : .merge = nfp_net_flow_merge_eth,
375 : : },
376 : : [RTE_FLOW_ITEM_TYPE_IPV4] = {
377 : : .next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_TCP,
378 : : RTE_FLOW_ITEM_TYPE_UDP,
379 : : RTE_FLOW_ITEM_TYPE_SCTP),
380 : : .mask_support = &(const struct rte_flow_item_ipv4){
381 : : .hdr = {
382 : : .next_proto_id = 0xff,
383 : : .src_addr = RTE_BE32(0xffffffff),
384 : : .dst_addr = RTE_BE32(0xffffffff),
385 : : },
386 : : },
387 : : .mask_default = &rte_flow_item_ipv4_mask,
388 : : .mask_sz = sizeof(struct rte_flow_item_ipv4),
389 : : .merge = nfp_net_flow_merge_ipv4,
390 : : },
391 : : [RTE_FLOW_ITEM_TYPE_IPV6] = {
392 : : .next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_TCP,
393 : : RTE_FLOW_ITEM_TYPE_UDP,
394 : : RTE_FLOW_ITEM_TYPE_SCTP),
395 : : .mask_support = &(const struct rte_flow_item_ipv6){
396 : : .hdr = {
397 : : .proto = 0xff,
398 : : .src_addr = "\xff\xff\xff\xff\xff\xff\xff\xff"
399 : : "\xff\xff\xff\xff\xff\xff\xff\xff",
400 : : .dst_addr = "\xff\xff\xff\xff\xff\xff\xff\xff"
401 : : "\xff\xff\xff\xff\xff\xff\xff\xff",
402 : : },
403 : : },
404 : : .mask_default = &rte_flow_item_ipv6_mask,
405 : : .mask_sz = sizeof(struct rte_flow_item_ipv6),
406 : : .merge = nfp_net_flow_merge_ipv6,
407 : : },
408 : : [RTE_FLOW_ITEM_TYPE_TCP] = {
409 : : .mask_support = &(const struct rte_flow_item_tcp){
410 : : .hdr = {
411 : : .src_port = RTE_BE16(0xffff),
412 : : .dst_port = RTE_BE16(0xffff),
413 : : },
414 : : },
415 : : .mask_default = &rte_flow_item_tcp_mask,
416 : : .mask_sz = sizeof(struct rte_flow_item_tcp),
417 : : .merge = nfp_flow_merge_l4,
418 : : },
419 : : [RTE_FLOW_ITEM_TYPE_UDP] = {
420 : : .mask_support = &(const struct rte_flow_item_udp){
421 : : .hdr = {
422 : : .src_port = RTE_BE16(0xffff),
423 : : .dst_port = RTE_BE16(0xffff),
424 : : },
425 : : },
426 : : .mask_default = &rte_flow_item_udp_mask,
427 : : .mask_sz = sizeof(struct rte_flow_item_udp),
428 : : .merge = nfp_flow_merge_l4,
429 : : },
430 : : [RTE_FLOW_ITEM_TYPE_SCTP] = {
431 : : .mask_support = &(const struct rte_flow_item_sctp){
432 : : .hdr = {
433 : : .src_port = RTE_BE16(0xffff),
434 : : .dst_port = RTE_BE16(0xffff),
435 : : },
436 : : },
437 : : .mask_default = &rte_flow_item_sctp_mask,
438 : : .mask_sz = sizeof(struct rte_flow_item_sctp),
439 : : .merge = nfp_flow_merge_l4,
440 : : },
441 : : };
442 : :
443 : : static int
444 : 0 : nfp_net_flow_item_check(const struct rte_flow_item *item,
445 : : const struct nfp_net_flow_item_proc *proc)
446 : : {
447 : : uint32_t i;
448 : : int ret = 0;
449 : : const uint8_t *mask;
450 : :
451 : : /* item->last and item->mask cannot exist without item->spec. */
452 [ # # ]: 0 : if (item->spec == NULL) {
453 [ # # # # ]: 0 : if (item->mask || item->last) {
454 : 0 : PMD_DRV_LOG(ERR, "'mask' or 'last' field provided"
455 : : " without a corresponding 'spec'.");
456 : 0 : return -EINVAL;
457 : : }
458 : :
459 : : /* No spec, no mask, no problem. */
460 : : return 0;
461 : : }
462 : :
463 [ # # ]: 0 : mask = (item->mask != NULL) ? item->mask : proc->mask_default;
464 : :
465 : : /*
466 : : * Single-pass check to make sure that:
467 : : * - Mask is supported, no bits are set outside proc->mask_support.
468 : : * - Both item->spec and item->last are included in mask.
469 : : */
470 [ # # ]: 0 : for (i = 0; i != proc->mask_sz; ++i) {
471 [ # # ]: 0 : if (mask[i] == 0)
472 : 0 : continue;
473 : :
474 [ # # ]: 0 : if ((mask[i] | ((const uint8_t *)proc->mask_support)[i]) !=
475 : : ((const uint8_t *)proc->mask_support)[i]) {
476 : 0 : PMD_DRV_LOG(ERR, "Unsupported field found in 'mask'.");
477 : : ret = -EINVAL;
478 : 0 : break;
479 : : }
480 : :
481 [ # # ]: 0 : if (item->last != NULL &&
482 : 0 : (((const uint8_t *)item->spec)[i] & mask[i]) !=
483 [ # # ]: 0 : (((const uint8_t *)item->last)[i] & mask[i])) {
484 : 0 : PMD_DRV_LOG(ERR, "Range between 'spec' and 'last'"
485 : : " is larger than 'mask'.");
486 : : ret = -ERANGE;
487 : 0 : break;
488 : : }
489 : : }
490 : :
491 : : return ret;
492 : : }
493 : :
494 : : static int
495 : 0 : nfp_net_flow_compile_items(const struct rte_flow_item items[],
496 : : struct rte_flow *nfp_flow)
497 : : {
498 : : uint32_t i;
499 : : int ret = 0;
500 : : const struct rte_flow_item *item;
501 : : const struct nfp_net_flow_item_proc *proc_list;
502 : :
503 : : proc_list = nfp_net_flow_item_proc_list;
504 : :
505 [ # # ]: 0 : for (item = items; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {
506 : : const struct nfp_net_flow_item_proc *proc = NULL;
507 : :
508 [ # # ]: 0 : for (i = 0; (proc_list->next_item != NULL) &&
509 [ # # ]: 0 : (proc_list->next_item[i] != RTE_FLOW_ITEM_TYPE_END); ++i) {
510 [ # # ]: 0 : if (proc_list->next_item[i] == item->type) {
511 : 0 : proc = &nfp_net_flow_item_proc_list[item->type];
512 : 0 : break;
513 : : }
514 : : }
515 : :
516 [ # # ]: 0 : if (proc == NULL) {
517 : 0 : PMD_DRV_LOG(ERR, "No next item provided for %d", item->type);
518 : : ret = -ENOTSUP;
519 : 0 : break;
520 : : }
521 : :
522 : : /* Perform basic sanity checks */
523 : 0 : ret = nfp_net_flow_item_check(item, proc);
524 [ # # ]: 0 : if (ret != 0) {
525 : 0 : PMD_DRV_LOG(ERR, "NFP flow item %d check failed", item->type);
526 : : ret = -EINVAL;
527 : 0 : break;
528 : : }
529 : :
530 [ # # ]: 0 : if (proc->merge == NULL) {
531 : 0 : PMD_DRV_LOG(ERR, "NFP flow item %d no proc function", item->type);
532 : : ret = -ENOTSUP;
533 : 0 : break;
534 : : }
535 : :
536 : 0 : ret = proc->merge(nfp_flow, item, proc);
537 [ # # ]: 0 : if (ret != 0) {
538 : 0 : PMD_DRV_LOG(ERR, "NFP flow item %d exact merge failed", item->type);
539 : 0 : break;
540 : : }
541 : :
542 : : proc_list = proc;
543 : : }
544 : :
545 : 0 : return ret;
546 : : }
547 : :
548 : : static void
549 : : nfp_net_flow_action_drop(struct rte_flow *nfp_flow)
550 : : {
551 : : struct nfp_net_cmsg_action *action_data;
552 : :
553 : 0 : action_data = (struct nfp_net_cmsg_action *)nfp_flow->payload.action_data;
554 : :
555 : 0 : action_data->action = NFP_NET_CMSG_ACTION_DROP;
556 : : }
557 : :
558 : : static void
559 : : nfp_net_flow_action_mark(struct rte_flow *nfp_flow,
560 : : const struct rte_flow_action *action)
561 : : {
562 : : struct nfp_net_cmsg_action *action_data;
563 : : const struct rte_flow_action_mark *mark;
564 : :
565 : 0 : action_data = (struct nfp_net_cmsg_action *)nfp_flow->payload.action_data;
566 : 0 : mark = action->conf;
567 : :
568 : 0 : action_data->action |= NFP_NET_CMSG_ACTION_MARK;
569 : 0 : action_data->mark_id = mark->id;
570 : 0 : }
571 : :
572 : : static int
573 : 0 : nfp_net_flow_action_queue(struct rte_eth_dev *dev,
574 : : struct rte_flow *nfp_flow,
575 : : const struct rte_flow_action *action)
576 : : {
577 : : struct nfp_net_cmsg_action *action_data;
578 : : const struct rte_flow_action_queue *queue;
579 : :
580 : 0 : action_data = (struct nfp_net_cmsg_action *)nfp_flow->payload.action_data;
581 : 0 : queue = action->conf;
582 [ # # ]: 0 : if (queue->index >= dev->data->nb_rx_queues ||
583 [ # # ]: 0 : dev->data->rx_queues[queue->index] == NULL) {
584 : 0 : PMD_DRV_LOG(ERR, "Queue index is illegal");
585 : 0 : return -EINVAL;
586 : : }
587 : :
588 : 0 : action_data->action |= NFP_NET_CMSG_ACTION_QUEUE;
589 : 0 : action_data->queue = queue->index;
590 : :
591 : 0 : return 0;
592 : : }
593 : :
594 : : static int
595 : 0 : nfp_net_flow_compile_actions(struct rte_eth_dev *dev,
596 : : const struct rte_flow_action actions[],
597 : : struct rte_flow *nfp_flow)
598 : : {
599 : : int ret = 0;
600 : : const struct rte_flow_action *action;
601 : :
602 [ # # ]: 0 : for (action = actions; action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
603 [ # # # # ]: 0 : switch (action->type) {
604 : 0 : case RTE_FLOW_ACTION_TYPE_DROP:
605 : 0 : PMD_DRV_LOG(DEBUG, "Process RTE_FLOW_ACTION_TYPE_DROP");
606 : : nfp_net_flow_action_drop(nfp_flow);
607 : 0 : return 0;
608 : 0 : case RTE_FLOW_ACTION_TYPE_MARK:
609 : 0 : PMD_DRV_LOG(DEBUG, "Process RTE_FLOW_ACTION_TYPE_MARK");
610 : : nfp_net_flow_action_mark(nfp_flow, action);
611 : : break;
612 : 0 : case RTE_FLOW_ACTION_TYPE_QUEUE:
613 : 0 : PMD_DRV_LOG(DEBUG, "Process RTE_FLOW_ACTION_TYPE_QUEUE");
614 : 0 : ret = nfp_net_flow_action_queue(dev, nfp_flow, action);
615 : 0 : break;
616 : 0 : default:
617 : 0 : PMD_DRV_LOG(ERR, "Unsupported action type: %d", action->type);
618 : 0 : return -ENOTSUP;
619 : : }
620 : : }
621 : :
622 : : return ret;
623 : : }
624 : :
625 : : static void
626 : : nfp_net_flow_process_priority(struct rte_flow *nfp_flow,
627 : : uint32_t match_len)
628 : : {
629 : : struct nfp_net_cmsg_match_v4 *ipv4;
630 : : struct nfp_net_cmsg_match_v6 *ipv6;
631 : :
632 : 0 : switch (match_len) {
633 : 0 : case sizeof(struct nfp_net_cmsg_match_v4):
634 : 0 : ipv4 = (struct nfp_net_cmsg_match_v4 *)nfp_flow->payload.match_data;
635 : 0 : ipv4->position = nfp_flow->position;
636 : 0 : break;
637 : 0 : case sizeof(struct nfp_net_cmsg_match_v6):
638 : 0 : ipv6 = (struct nfp_net_cmsg_match_v6 *)nfp_flow->payload.match_data;
639 : 0 : ipv6->position = nfp_flow->position;
640 : 0 : break;
641 : : default:
642 : : break;
643 : : }
644 : : }
645 : :
646 : : static struct rte_flow *
647 : 0 : nfp_net_flow_setup(struct rte_eth_dev *dev,
648 : : const struct rte_flow_attr *attr,
649 : : const struct rte_flow_item items[],
650 : : const struct rte_flow_action actions[])
651 : : {
652 : : int ret;
653 : : char *hash_data;
654 : : uint32_t port_id;
655 : : uint32_t action_len;
656 : : struct nfp_net_hw *hw;
657 : 0 : uint32_t match_len = 0;
658 : : struct nfp_net_priv *priv;
659 : : struct rte_flow *nfp_flow;
660 : : struct rte_flow *flow_find;
661 : : struct nfp_app_fw_nic *app_fw_nic;
662 : :
663 : 0 : hw = dev->data->dev_private;
664 : 0 : app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw->pf_dev->app_fw_priv);
665 : 0 : priv = app_fw_nic->ports[hw->idx]->priv;
666 : :
667 : 0 : ret = nfp_net_flow_calculate_items(items, &match_len);
668 [ # # ]: 0 : if (ret != 0) {
669 : 0 : PMD_DRV_LOG(ERR, "Key layers calculate failed.");
670 : 0 : return NULL;
671 : : }
672 : :
673 : : action_len = sizeof(struct nfp_net_cmsg_action);
674 : 0 : port_id = ((struct nfp_net_hw *)dev->data->dev_private)->nfp_idx;
675 : :
676 : 0 : nfp_flow = nfp_net_flow_alloc(priv, attr->priority, match_len, action_len, port_id);
677 [ # # ]: 0 : if (nfp_flow == NULL) {
678 : 0 : PMD_DRV_LOG(ERR, "Alloc nfp flow failed.");
679 : 0 : return NULL;
680 : : }
681 : :
682 : 0 : ret = nfp_net_flow_compile_items(items, nfp_flow);
683 [ # # ]: 0 : if (ret != 0) {
684 : 0 : PMD_DRV_LOG(ERR, "NFP flow item process failed.");
685 : 0 : goto free_flow;
686 : : }
687 : :
688 : 0 : ret = nfp_net_flow_compile_actions(dev, actions, nfp_flow);
689 [ # # ]: 0 : if (ret != 0) {
690 : 0 : PMD_DRV_LOG(ERR, "NFP flow action process failed.");
691 : 0 : goto free_flow;
692 : : }
693 : :
694 : : /* Calculate and store the hash_key for later use */
695 : 0 : hash_data = nfp_flow->payload.match_data;
696 : 0 : nfp_flow->hash_key = rte_jhash(hash_data, match_len + action_len,
697 : : priv->hash_seed);
698 : :
699 : : /* Find the flow in hash table */
700 : 0 : flow_find = nfp_net_flow_table_search(priv, nfp_flow);
701 [ # # ]: 0 : if (flow_find != NULL) {
702 : 0 : PMD_DRV_LOG(ERR, "This flow is already exist.");
703 : 0 : goto free_flow;
704 : : }
705 : :
706 [ # # # ]: 0 : priv->flow_count++;
707 : :
708 : : nfp_net_flow_process_priority(nfp_flow, match_len);
709 : :
710 : : return nfp_flow;
711 : :
712 : 0 : free_flow:
713 : : nfp_net_flow_free(priv, nfp_flow);
714 : :
715 : 0 : return NULL;
716 : : }
717 : :
718 : : static int
719 : : nfp_net_flow_teardown(struct nfp_net_priv *priv,
720 : : __rte_unused struct rte_flow *nfp_flow)
721 : : {
722 : 0 : priv->flow_count--;
723 : :
724 : : return 0;
725 : : }
726 : :
727 : : static int
728 : 0 : nfp_net_flow_offload(struct nfp_net_hw *hw,
729 : : struct rte_flow *flow,
730 : : bool delete_flag)
731 : : {
732 : : int ret;
733 : : char *tmp;
734 : : uint32_t msg_size;
735 : : struct nfp_net_cmsg *cmsg;
736 : :
737 : 0 : msg_size = sizeof(uint32_t) + flow->payload.match_len +
738 : 0 : flow->payload.action_len;
739 : 0 : cmsg = nfp_net_cmsg_alloc(msg_size);
740 [ # # ]: 0 : if (cmsg == NULL) {
741 : 0 : PMD_DRV_LOG(ERR, "Alloc cmsg failed.");
742 : 0 : return -ENOMEM;
743 : : }
744 : :
745 : 0 : cmsg->cmd = flow->payload.cmsg_type;
746 [ # # ]: 0 : if (delete_flag)
747 : 0 : cmsg->cmd++;
748 : :
749 : 0 : tmp = (char *)cmsg->data;
750 [ # # ]: 0 : rte_memcpy(tmp, flow->payload.match_data, flow->payload.match_len);
751 : 0 : tmp += flow->payload.match_len;
752 [ # # ]: 0 : rte_memcpy(tmp, flow->payload.action_data, flow->payload.action_len);
753 : :
754 : 0 : ret = nfp_net_cmsg_xmit(hw, cmsg, msg_size);
755 [ # # ]: 0 : if (ret != 0) {
756 : 0 : PMD_DRV_LOG(ERR, "Send cmsg failed.");
757 : : ret = -EINVAL;
758 : 0 : goto free_cmsg;
759 : : }
760 : :
761 : 0 : free_cmsg:
762 : 0 : nfp_net_cmsg_free(cmsg);
763 : :
764 : 0 : return ret;
765 : : }
766 : :
767 : : static int
768 : 0 : nfp_net_flow_validate(struct rte_eth_dev *dev,
769 : : const struct rte_flow_attr *attr,
770 : : const struct rte_flow_item items[],
771 : : const struct rte_flow_action actions[],
772 : : struct rte_flow_error *error)
773 : : {
774 : : int ret;
775 : : struct nfp_net_hw *hw;
776 : : struct rte_flow *nfp_flow;
777 : : struct nfp_net_priv *priv;
778 : : struct nfp_app_fw_nic *app_fw_nic;
779 : :
780 : 0 : hw = dev->data->dev_private;
781 : 0 : app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw->pf_dev->app_fw_priv);
782 : 0 : priv = app_fw_nic->ports[hw->idx]->priv;
783 : :
784 : 0 : nfp_flow = nfp_net_flow_setup(dev, attr, items, actions);
785 [ # # ]: 0 : if (nfp_flow == NULL) {
786 : 0 : return rte_flow_error_set(error, ENOTSUP,
787 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
788 : : NULL, "This flow can not be offloaded.");
789 : : }
790 : :
791 : : ret = nfp_net_flow_teardown(priv, nfp_flow);
792 : : if (ret != 0) {
793 : : return rte_flow_error_set(error, EINVAL,
794 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
795 : : NULL, "Flow resource free failed.");
796 : : }
797 : :
798 : : nfp_net_flow_free(priv, nfp_flow);
799 : :
800 : 0 : return 0;
801 : : }
802 : :
803 : : static struct rte_flow *
804 : 0 : nfp_net_flow_create(struct rte_eth_dev *dev,
805 : : const struct rte_flow_attr *attr,
806 : : const struct rte_flow_item items[],
807 : : const struct rte_flow_action actions[],
808 : : struct rte_flow_error *error)
809 : : {
810 : : int ret;
811 : : struct nfp_net_hw *hw;
812 : : struct rte_flow *nfp_flow;
813 : : struct nfp_net_priv *priv;
814 : : struct nfp_app_fw_nic *app_fw_nic;
815 : :
816 : 0 : hw = dev->data->dev_private;
817 : 0 : app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw->pf_dev->app_fw_priv);
818 : 0 : priv = app_fw_nic->ports[hw->idx]->priv;
819 : :
820 : 0 : nfp_flow = nfp_net_flow_setup(dev, attr, items, actions);
821 [ # # ]: 0 : if (nfp_flow == NULL) {
822 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
823 : : NULL, "This flow can not be offloaded.");
824 : 0 : return NULL;
825 : : }
826 : :
827 : : /* Add the flow to flow hash table */
828 : 0 : ret = nfp_net_flow_table_add(priv, nfp_flow);
829 [ # # ]: 0 : if (ret != 0) {
830 : 0 : rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
831 : : NULL, "Add flow to the flow table failed.");
832 : 0 : goto flow_teardown;
833 : : }
834 : :
835 : : /* Add the flow to hardware */
836 : 0 : ret = nfp_net_flow_offload(hw, nfp_flow, false);
837 [ # # ]: 0 : if (ret != 0) {
838 : 0 : rte_flow_error_set(error, EINVAL,
839 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
840 : : NULL, "Add flow to firmware failed.");
841 : 0 : goto table_delete;
842 : : }
843 : :
844 : : return nfp_flow;
845 : :
846 : : table_delete:
847 : 0 : nfp_net_flow_table_delete(priv, nfp_flow);
848 : 0 : flow_teardown:
849 : : nfp_net_flow_teardown(priv, nfp_flow);
850 : : nfp_net_flow_free(priv, nfp_flow);
851 : :
852 : 0 : return NULL;
853 : : }
854 : :
855 : : static int
856 : 0 : nfp_net_flow_destroy(struct rte_eth_dev *dev,
857 : : struct rte_flow *nfp_flow,
858 : : struct rte_flow_error *error)
859 : : {
860 : : int ret;
861 : : struct nfp_net_hw *hw;
862 : : struct nfp_net_priv *priv;
863 : : struct rte_flow *flow_find;
864 : : struct nfp_app_fw_nic *app_fw_nic;
865 : :
866 : 0 : hw = dev->data->dev_private;
867 : 0 : app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw->pf_dev->app_fw_priv);
868 : 0 : priv = app_fw_nic->ports[hw->idx]->priv;
869 : :
870 : : /* Find the flow in flow hash table */
871 : 0 : flow_find = nfp_net_flow_table_search(priv, nfp_flow);
872 [ # # ]: 0 : if (flow_find == NULL) {
873 : 0 : rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
874 : : NULL, "Flow does not exist.");
875 : : ret = -EINVAL;
876 : 0 : goto exit;
877 : : }
878 : :
879 : : /* Delete the flow from hardware */
880 : 0 : ret = nfp_net_flow_offload(hw, nfp_flow, true);
881 [ # # ]: 0 : if (ret != 0) {
882 : 0 : rte_flow_error_set(error, EINVAL,
883 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
884 : : NULL, "Delete flow from firmware failed.");
885 : : ret = -EINVAL;
886 : 0 : goto exit;
887 : : }
888 : :
889 : : /* Delete the flow from flow hash table */
890 : 0 : ret = nfp_net_flow_table_delete(priv, nfp_flow);
891 [ # # ]: 0 : if (ret != 0) {
892 : 0 : rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
893 : : NULL, "Delete flow from the flow table failed.");
894 : : ret = -EINVAL;
895 : 0 : goto exit;
896 : : }
897 : :
898 : : ret = nfp_net_flow_teardown(priv, nfp_flow);
899 : : if (ret != 0) {
900 : : rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
901 : : NULL, "Flow teardown failed.");
902 : : ret = -EINVAL;
903 : : goto exit;
904 : : }
905 : :
906 : 0 : exit:
907 : : nfp_net_flow_free(priv, nfp_flow);
908 : :
909 : 0 : return ret;
910 : : }
911 : :
912 : : static int
913 : 0 : nfp_net_flow_flush(struct rte_eth_dev *dev,
914 : : struct rte_flow_error *error)
915 : : {
916 : : int ret = 0;
917 : : void *next_data;
918 : 0 : uint32_t iter = 0;
919 : : const void *next_key;
920 : : struct nfp_net_hw *hw;
921 : : struct rte_flow *nfp_flow;
922 : : struct rte_hash *flow_table;
923 : : struct nfp_app_fw_nic *app_fw_nic;
924 : :
925 : 0 : hw = dev->data->dev_private;
926 : 0 : app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw->pf_dev->app_fw_priv);
927 : 0 : flow_table = app_fw_nic->ports[hw->idx]->priv->flow_table;
928 : :
929 [ # # ]: 0 : while (rte_hash_iterate(flow_table, &next_key, &next_data, &iter) >= 0) {
930 : 0 : nfp_flow = next_data;
931 : 0 : ret = nfp_net_flow_destroy(dev, nfp_flow, error);
932 [ # # ]: 0 : if (ret != 0)
933 : : break;
934 : : }
935 : :
936 : 0 : return ret;
937 : : }
938 : :
939 : : static const struct rte_flow_ops nfp_net_flow_ops = {
940 : : .validate = nfp_net_flow_validate,
941 : : .create = nfp_net_flow_create,
942 : : .destroy = nfp_net_flow_destroy,
943 : : .flush = nfp_net_flow_flush,
944 : : };
945 : :
946 : : int
947 [ # # ]: 0 : nfp_net_flow_ops_get(struct rte_eth_dev *dev,
948 : : const struct rte_flow_ops **ops)
949 : : {
950 : : struct nfp_net_hw *hw;
951 : :
952 [ # # ]: 0 : if (rte_eth_dev_is_repr(dev)) {
953 : 0 : *ops = NULL;
954 : 0 : PMD_DRV_LOG(ERR, "Port is a representor.");
955 : 0 : return -EINVAL;
956 : : }
957 : :
958 : 0 : hw = dev->data->dev_private;
959 [ # # ]: 0 : if ((hw->super.ctrl_ext & NFP_NET_CFG_CTRL_FLOW_STEER) == 0) {
960 : 0 : *ops = NULL;
961 : 0 : return 0;
962 : : }
963 : :
964 : 0 : *ops = &nfp_net_flow_ops;
965 : :
966 : 0 : return 0;
967 : : }
968 : :
969 : : int
970 : 0 : nfp_net_flow_priv_init(struct nfp_pf_dev *pf_dev,
971 : : uint16_t port)
972 : : {
973 : : int ret = 0;
974 : : struct nfp_net_priv *priv;
975 : : char flow_name[RTE_HASH_NAMESIZE];
976 : : struct nfp_app_fw_nic *app_fw_nic;
977 : 0 : const char *pci_name = strchr(pf_dev->pci_dev->name, ':') + 1;
978 : :
979 : 0 : snprintf(flow_name, sizeof(flow_name), "%s_fl_%u", pci_name, port);
980 : :
981 : 0 : struct rte_hash_parameters flow_hash_params = {
982 : : .name = flow_name,
983 : : .entries = NFP_NET_FLOW_LIMIT,
984 : : .hash_func = rte_jhash,
985 : 0 : .socket_id = rte_socket_id(),
986 : : .key_len = sizeof(uint32_t),
987 : : .extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY,
988 : : };
989 : :
990 : 0 : priv = rte_zmalloc("nfp_app_nic_priv", sizeof(struct nfp_net_priv), 0);
991 [ # # ]: 0 : if (priv == NULL) {
992 : 0 : PMD_INIT_LOG(ERR, "NFP app nic priv creation failed");
993 : : ret = -ENOMEM;
994 : 0 : goto exit;
995 : : }
996 : :
997 : 0 : app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
998 : 0 : app_fw_nic->ports[port]->priv = priv;
999 : 0 : priv->hash_seed = (uint32_t)rte_rand();
1000 : :
1001 : : /* Flow table */
1002 : 0 : flow_hash_params.hash_func_init_val = priv->hash_seed;
1003 : 0 : priv->flow_table = rte_hash_create(&flow_hash_params);
1004 [ # # ]: 0 : if (priv->flow_table == NULL) {
1005 : 0 : PMD_INIT_LOG(ERR, "flow hash table creation failed");
1006 : : ret = -ENOMEM;
1007 : 0 : goto free_priv;
1008 : : }
1009 : :
1010 : : return 0;
1011 : :
1012 : : free_priv:
1013 : 0 : rte_free(priv);
1014 : : exit:
1015 : : return ret;
1016 : : }
1017 : :
1018 : : void
1019 : 0 : nfp_net_flow_priv_uninit(struct nfp_pf_dev *pf_dev,
1020 : : uint16_t port)
1021 : : {
1022 : : struct nfp_net_priv *priv;
1023 : : struct nfp_app_fw_nic *app_fw_nic;
1024 : :
1025 [ # # ]: 0 : if (pf_dev == NULL)
1026 : : return;
1027 : :
1028 : 0 : app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
1029 : 0 : priv = app_fw_nic->ports[port]->priv;
1030 [ # # ]: 0 : if (priv != NULL)
1031 : 0 : rte_hash_free(priv->flow_table);
1032 : :
1033 : 0 : rte_free(priv);
1034 : : }
|