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