Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2018 Mellanox Technologies, Ltd
3 : : */
4 : :
5 : : #include <netinet/in.h>
6 : : #include <sys/queue.h>
7 : : #include <stdalign.h>
8 : : #include <stdint.h>
9 : : #include <string.h>
10 : :
11 : : #include <rte_common.h>
12 : : #include <rte_ether.h>
13 : : #include <ethdev_driver.h>
14 : : #include <rte_flow.h>
15 : : #include <rte_flow_driver.h>
16 : : #include <rte_malloc.h>
17 : : #include <rte_ip.h>
18 : :
19 : : #include <mlx5_glue.h>
20 : : #include <mlx5_prm.h>
21 : : #include <mlx5_malloc.h>
22 : :
23 : : #include "mlx5_defs.h"
24 : : #include "mlx5.h"
25 : : #include "mlx5_flow.h"
26 : : #include "mlx5_rx.h"
27 : : #include "mlx5_flow_os.h"
28 : :
29 : : #define VERBS_SPEC_INNER(item_flags) \
30 : : (!!((item_flags) & MLX5_FLOW_LAYER_TUNNEL) ? IBV_FLOW_SPEC_INNER : 0)
31 : :
32 : : /* Verbs specification header. */
33 : : struct ibv_spec_header {
34 : : enum ibv_flow_spec_type type;
35 : : uint16_t size;
36 : : };
37 : :
38 : : /**
39 : : * Discover the maximum number of priority available.
40 : : *
41 : : * @param[in] dev
42 : : * Pointer to the Ethernet device structure.
43 : : * @param[in] vprio
44 : : * Expected result variants.
45 : : * @param[in] vprio_n
46 : : * Number of entries in @p vprio array.
47 : : * @return
48 : : * Number of supported flow priority on success, a negative errno
49 : : * value otherwise and rte_errno is set.
50 : : */
51 : : static int
52 : 0 : flow_verbs_discover_priorities(struct rte_eth_dev *dev,
53 : : const uint16_t *vprio, int vprio_n)
54 : : {
55 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
56 : : struct {
57 : : struct ibv_flow_attr attr;
58 : : struct ibv_flow_spec_eth eth;
59 : : struct ibv_flow_spec_action_drop drop;
60 : : } flow_attr = {
61 : : .attr = {
62 : : .num_of_specs = 2,
63 : : .port = (uint8_t)priv->dev_port,
64 : : },
65 : : .eth = {
66 : : .type = IBV_FLOW_SPEC_ETH,
67 : : .size = sizeof(struct ibv_flow_spec_eth),
68 : : .val = {
69 : : .dst_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
70 : : .src_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
71 : : },
72 : : .mask = {
73 : : .dst_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
74 : : .src_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
75 : : },
76 : : },
77 : : .drop = {
78 : : .size = sizeof(struct ibv_flow_spec_action_drop),
79 : : .type = IBV_FLOW_SPEC_ACTION_DROP,
80 : : },
81 : : };
82 : : struct ibv_flow *flow;
83 : : struct mlx5_hrxq *drop = priv->drop_queue.hrxq;
84 : : int i;
85 : : int priority = 0;
86 : :
87 : : #if defined(HAVE_MLX5DV_DR_DEVX_PORT) || defined(HAVE_MLX5DV_DR_DEVX_PORT_V35)
88 : : /* If DevX supported, driver must support 16 verbs flow priorities. */
89 : : priority = 16;
90 : 0 : goto out;
91 : : #endif
92 : : if (!drop->qp) {
93 : : rte_errno = ENOTSUP;
94 : : return -rte_errno;
95 : : }
96 : : for (i = 0; i != vprio_n; i++) {
97 : : flow_attr.attr.priority = vprio[i] - 1;
98 : : flow = mlx5_glue->create_flow(drop->qp, &flow_attr.attr);
99 : : if (!flow)
100 : : break;
101 : : claim_zero(mlx5_glue->destroy_flow(flow));
102 : : priority = vprio[i];
103 : : }
104 : : #if defined(HAVE_MLX5DV_DR_DEVX_PORT) || defined(HAVE_MLX5DV_DR_DEVX_PORT_V35)
105 : : out:
106 : : #endif
107 : 0 : DRV_LOG(INFO, "port %u supported flow priorities:"
108 : : " 0-%d for ingress or egress root table,"
109 : : " 0-%d for non-root table or transfer root table.",
110 : : dev->data->port_id, priority - 2,
111 : : MLX5_NON_ROOT_FLOW_MAX_PRIO - 1);
112 : : return priority;
113 : : }
114 : :
115 : : /**
116 : : * Get Verbs flow counter by index.
117 : : *
118 : : * @param[in] dev
119 : : * Pointer to the Ethernet device structure.
120 : : * @param[in] idx
121 : : * mlx5 flow counter index in the container.
122 : : * @param[out] ppool
123 : : * mlx5 flow counter pool in the container,
124 : : *
125 : : * @return
126 : : * A pointer to the counter, NULL otherwise.
127 : : */
128 : : static struct mlx5_flow_counter *
129 : : flow_verbs_counter_get_by_idx(struct rte_eth_dev *dev,
130 : : uint32_t idx,
131 : : struct mlx5_flow_counter_pool **ppool)
132 : : {
133 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
134 : 0 : struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng;
135 : : struct mlx5_flow_counter_pool *pool;
136 : :
137 : 0 : idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
138 : 0 : pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
139 : : MLX5_ASSERT(pool);
140 : : if (ppool)
141 : : *ppool = pool;
142 [ # # ]: 0 : return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
143 : : }
144 : :
145 : : /**
146 : : * Create Verbs flow counter with Verbs library.
147 : : *
148 : : * @param[in] dev
149 : : * Pointer to the Ethernet device structure.
150 : : * @param[in, out] counter
151 : : * mlx5 flow counter object, contains the counter id,
152 : : * handle of created Verbs flow counter is returned
153 : : * in cs field (if counters are supported).
154 : : *
155 : : * @return
156 : : * 0 On success else a negative errno value is returned
157 : : * and rte_errno is set.
158 : : */
159 : : static int
160 : 0 : flow_verbs_counter_create(struct rte_eth_dev *dev,
161 : : struct mlx5_flow_counter *counter)
162 : : {
163 : : #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
164 : : struct mlx5_priv *priv = dev->data->dev_private;
165 : : struct ibv_context *ctx = priv->sh->cdev->ctx;
166 : : struct ibv_counter_set_init_attr init = {
167 : : .counter_set_id = counter->shared_info.id};
168 : :
169 : : counter->dcs_when_free = mlx5_glue->create_counter_set(ctx, &init);
170 : : if (!counter->dcs_when_free) {
171 : : rte_errno = ENOTSUP;
172 : : return -ENOTSUP;
173 : : }
174 : : return 0;
175 : : #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
176 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
177 : 0 : struct ibv_context *ctx = priv->sh->cdev->ctx;
178 : 0 : struct ibv_counters_init_attr init = {0};
179 : : struct ibv_counter_attach_attr attach;
180 : : int ret;
181 : :
182 : : memset(&attach, 0, sizeof(attach));
183 : 0 : counter->dcs_when_free = mlx5_glue->create_counters(ctx, &init);
184 [ # # ]: 0 : if (!counter->dcs_when_free) {
185 : 0 : rte_errno = ENOTSUP;
186 : 0 : return -ENOTSUP;
187 : : }
188 : 0 : attach.counter_desc = IBV_COUNTER_PACKETS;
189 : 0 : attach.index = 0;
190 : 0 : ret = mlx5_glue->attach_counters(counter->dcs_when_free, &attach, NULL);
191 [ # # ]: 0 : if (!ret) {
192 : 0 : attach.counter_desc = IBV_COUNTER_BYTES;
193 : 0 : attach.index = 1;
194 : 0 : ret = mlx5_glue->attach_counters
195 : 0 : (counter->dcs_when_free, &attach, NULL);
196 : : }
197 [ # # ]: 0 : if (ret) {
198 : 0 : claim_zero(mlx5_glue->destroy_counters(counter->dcs_when_free));
199 : 0 : counter->dcs_when_free = NULL;
200 : 0 : rte_errno = ret;
201 : 0 : return -ret;
202 : : }
203 : : return 0;
204 : : #else
205 : : (void)dev;
206 : : (void)counter;
207 : : rte_errno = ENOTSUP;
208 : : return -ENOTSUP;
209 : : #endif
210 : : }
211 : :
212 : : /**
213 : : * Get a flow counter.
214 : : *
215 : : * @param[in] dev
216 : : * Pointer to the Ethernet device structure.
217 : : * @param[in] id
218 : : * Counter identifier.
219 : : *
220 : : * @return
221 : : * Index to the counter, 0 otherwise and rte_errno is set.
222 : : */
223 : : static uint32_t
224 : 0 : flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t id __rte_unused)
225 : : {
226 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
227 : 0 : struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng;
228 : : struct mlx5_flow_counter_pool *pool = NULL;
229 : : struct mlx5_flow_counter *cnt = NULL;
230 : 0 : uint32_t n_valid = cmng->n_valid;
231 : : uint32_t pool_idx, cnt_idx;
232 : : uint32_t i;
233 : : int ret;
234 : :
235 [ # # ]: 0 : for (pool_idx = 0; pool_idx < n_valid; ++pool_idx) {
236 : 0 : pool = cmng->pools[pool_idx];
237 [ # # ]: 0 : if (!pool)
238 : 0 : continue;
239 : 0 : cnt = TAILQ_FIRST(&pool->counters[0]);
240 [ # # ]: 0 : if (cnt)
241 : : break;
242 : : }
243 [ # # ]: 0 : if (!cnt) {
244 : : uint32_t size;
245 : :
246 [ # # ]: 0 : if (n_valid == MLX5_COUNTER_POOLS_MAX_NUM) {
247 : 0 : DRV_LOG(ERR, "All counter is in used, try again later.");
248 : 0 : rte_errno = EAGAIN;
249 : 0 : return 0;
250 : : }
251 : : /* Allocate memory for new pool */
252 : : size = sizeof(*pool) + sizeof(*cnt) * MLX5_COUNTERS_PER_POOL;
253 : 0 : pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
254 [ # # ]: 0 : if (!pool)
255 : : return 0;
256 [ # # ]: 0 : for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) {
257 [ # # ]: 0 : cnt = MLX5_POOL_GET_CNT(pool, i);
258 [ # # ]: 0 : TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
259 : : }
260 : 0 : cnt = MLX5_POOL_GET_CNT(pool, 0);
261 : 0 : cmng->pools[n_valid] = pool;
262 : : pool_idx = n_valid;
263 : 0 : cmng->n_valid++;
264 : : }
265 [ # # ]: 0 : TAILQ_REMOVE(&pool->counters[0], cnt, next);
266 [ # # ]: 0 : i = MLX5_CNT_ARRAY_IDX(pool, cnt);
267 : 0 : cnt_idx = MLX5_MAKE_CNT_IDX(pool_idx, i);
268 : : /* Create counter with Verbs. */
269 : 0 : ret = flow_verbs_counter_create(dev, cnt);
270 [ # # ]: 0 : if (!ret) {
271 : 0 : cnt->dcs_when_active = cnt->dcs_when_free;
272 : 0 : cnt->hits = 0;
273 : 0 : cnt->bytes = 0;
274 : 0 : return cnt_idx;
275 : : }
276 [ # # ]: 0 : TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
277 : : /* Some error occurred in Verbs library. */
278 : 0 : rte_errno = -ret;
279 : 0 : return 0;
280 : : }
281 : :
282 : : /**
283 : : * Release a flow counter.
284 : : *
285 : : * @param[in] dev
286 : : * Pointer to the Ethernet device structure.
287 : : * @param[in] counter
288 : : * Index to the counter handler.
289 : : */
290 : : static void
291 [ # # ]: 0 : flow_verbs_counter_release(struct rte_eth_dev *dev, uint32_t counter)
292 : : {
293 : : struct mlx5_flow_counter_pool *pool;
294 : : struct mlx5_flow_counter *cnt;
295 : :
296 : : cnt = flow_verbs_counter_get_by_idx(dev, counter, &pool);
297 : : #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
298 : : claim_zero(mlx5_glue->destroy_counter_set
299 : : ((struct ibv_counter_set *)cnt->dcs_when_active));
300 : : #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
301 : 0 : claim_zero(mlx5_glue->destroy_counters
302 : : ((struct ibv_counters *)cnt->dcs_when_active));
303 : : #endif
304 [ # # ]: 0 : TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
305 : 0 : }
306 : :
307 : : /**
308 : : * Query a flow counter via Verbs library call.
309 : : *
310 : : * @see rte_flow_query()
311 : : * @see rte_flow_ops
312 : : */
313 : : static int
314 : 0 : flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused,
315 : : struct rte_flow *flow, void *data,
316 : : struct rte_flow_error *error)
317 : : {
318 : : #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
319 : : defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
320 [ # # ]: 0 : if (flow->counter) {
321 : : struct mlx5_flow_counter_pool *pool;
322 : : struct mlx5_flow_counter *cnt = flow_verbs_counter_get_by_idx
323 : : (dev, flow->counter, &pool);
324 : : struct rte_flow_query_count *qc = data;
325 : 0 : uint64_t counters[2] = {0, 0};
326 : : #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
327 : : struct ibv_query_counter_set_attr query_cs_attr = {
328 : : .dcs_when_free = (struct ibv_counter_set *)
329 : : cnt->dcs_when_active,
330 : : .query_flags = IBV_COUNTER_SET_FORCE_UPDATE,
331 : : };
332 : : struct ibv_counter_set_data query_out = {
333 : : .out = counters,
334 : : .outlen = 2 * sizeof(uint64_t),
335 : : };
336 : : int err = mlx5_glue->query_counter_set(&query_cs_attr,
337 : : &query_out);
338 : : #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
339 : 0 : int err = mlx5_glue->query_counters
340 : 0 : ((struct ibv_counters *)cnt->dcs_when_active, counters,
341 : : RTE_DIM(counters),
342 : : IBV_READ_COUNTERS_ATTR_PREFER_CACHED);
343 : : #endif
344 [ # # ]: 0 : if (err)
345 : 0 : return rte_flow_error_set
346 : : (error, err,
347 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
348 : : NULL,
349 : : "cannot read counter");
350 : 0 : qc->hits_set = 1;
351 : 0 : qc->bytes_set = 1;
352 : 0 : qc->hits = counters[0] - cnt->hits;
353 : 0 : qc->bytes = counters[1] - cnt->bytes;
354 [ # # ]: 0 : if (qc->reset) {
355 : 0 : cnt->hits = counters[0];
356 : 0 : cnt->bytes = counters[1];
357 : : }
358 : 0 : return 0;
359 : : }
360 : 0 : return rte_flow_error_set(error, EINVAL,
361 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
362 : : NULL,
363 : : "flow does not have counter");
364 : : #else
365 : : (void)flow;
366 : : (void)data;
367 : : return rte_flow_error_set(error, ENOTSUP,
368 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
369 : : NULL,
370 : : "counters are not available");
371 : : #endif
372 : : }
373 : :
374 : : /**
375 : : * Add a verbs item specification into @p verbs.
376 : : *
377 : : * @param[out] verbs
378 : : * Pointer to verbs structure.
379 : : * @param[in] src
380 : : * Create specification.
381 : : * @param[in] size
382 : : * Size in bytes of the specification to copy.
383 : : */
384 : : static void
385 : 0 : flow_verbs_spec_add(struct mlx5_flow_verbs_workspace *verbs,
386 : : void *src, unsigned int size)
387 : : {
388 : : void *dst;
389 : :
390 [ # # ]: 0 : if (!verbs)
391 : : return;
392 : : MLX5_ASSERT(verbs->specs);
393 : 0 : dst = (void *)(verbs->specs + verbs->size);
394 : 0 : memcpy(dst, src, size);
395 : 0 : ++verbs->attr.num_of_specs;
396 : 0 : verbs->size += size;
397 : : }
398 : :
399 : : /**
400 : : * Convert the @p item into a Verbs specification. This function assumes that
401 : : * the input is valid and that there is space to insert the requested item
402 : : * into the flow.
403 : : *
404 : : * @param[in, out] dev_flow
405 : : * Pointer to dev_flow structure.
406 : : * @param[in] item
407 : : * Item specification.
408 : : * @param[in] item_flags
409 : : * Parsed item flags.
410 : : */
411 : : static void
412 : 0 : flow_verbs_translate_item_eth(struct mlx5_flow *dev_flow,
413 : : const struct rte_flow_item *item,
414 : : uint64_t item_flags)
415 : : {
416 : 0 : const struct rte_flow_item_eth *spec = item->spec;
417 : 0 : const struct rte_flow_item_eth *mask = item->mask;
418 : : const unsigned int size = sizeof(struct ibv_flow_spec_eth);
419 : 0 : struct ibv_flow_spec_eth eth = {
420 [ # # ]: 0 : .type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags),
421 : : .size = size,
422 : : };
423 : :
424 [ # # ]: 0 : if (!mask)
425 : : mask = &rte_flow_item_eth_mask;
426 [ # # ]: 0 : if (spec) {
427 : : unsigned int i;
428 : :
429 : : memcpy(ð.val.dst_mac, spec->hdr.dst_addr.addr_bytes,
430 : : RTE_ETHER_ADDR_LEN);
431 : : memcpy(ð.val.src_mac, spec->hdr.src_addr.addr_bytes,
432 : : RTE_ETHER_ADDR_LEN);
433 : 0 : eth.val.ether_type = spec->hdr.ether_type;
434 : : memcpy(ð.mask.dst_mac, mask->hdr.dst_addr.addr_bytes,
435 : : RTE_ETHER_ADDR_LEN);
436 : : memcpy(ð.mask.src_mac, mask->hdr.src_addr.addr_bytes,
437 : : RTE_ETHER_ADDR_LEN);
438 : 0 : eth.mask.ether_type = mask->hdr.ether_type;
439 : : /* Remove unwanted bits from values. */
440 [ # # ]: 0 : for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i) {
441 : 0 : eth.val.dst_mac[i] &= eth.mask.dst_mac[i];
442 : 0 : eth.val.src_mac[i] &= eth.mask.src_mac[i];
443 : : }
444 : 0 : eth.val.ether_type &= eth.mask.ether_type;
445 : : }
446 : 0 : flow_verbs_spec_add(&dev_flow->verbs, ð, size);
447 : 0 : }
448 : :
449 : : /**
450 : : * Update the VLAN tag in the Verbs Ethernet specification.
451 : : * This function assumes that the input is valid and there is space to add
452 : : * the requested item.
453 : : *
454 : : * @param[in, out] attr
455 : : * Pointer to Verbs attributes structure.
456 : : * @param[in] eth
457 : : * Verbs structure containing the VLAN information to copy.
458 : : */
459 : : static void
460 : : flow_verbs_item_vlan_update(struct ibv_flow_attr *attr,
461 : : struct ibv_flow_spec_eth *eth)
462 : : {
463 : : unsigned int i;
464 : : const enum ibv_flow_spec_type search = eth->type;
465 : 0 : struct ibv_spec_header *hdr = (struct ibv_spec_header *)
466 : : ((uint8_t *)attr + sizeof(struct ibv_flow_attr));
467 : :
468 [ # # ]: 0 : for (i = 0; i != attr->num_of_specs; ++i) {
469 [ # # ]: 0 : if (hdr->type == search) {
470 : : struct ibv_flow_spec_eth *e =
471 : : (struct ibv_flow_spec_eth *)hdr;
472 : :
473 : 0 : e->val.vlan_tag = eth->val.vlan_tag;
474 : 0 : e->mask.vlan_tag = eth->mask.vlan_tag;
475 : 0 : e->val.ether_type = eth->val.ether_type;
476 : 0 : e->mask.ether_type = eth->mask.ether_type;
477 : 0 : break;
478 : : }
479 : 0 : hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
480 : : }
481 : : }
482 : :
483 : : /**
484 : : * Convert the @p item into a Verbs specification. This function assumes that
485 : : * the input is valid and that there is space to insert the requested item
486 : : * into the flow.
487 : : *
488 : : * @param[in, out] dev_flow
489 : : * Pointer to dev_flow structure.
490 : : * @param[in] item
491 : : * Item specification.
492 : : * @param[in] item_flags
493 : : * Parsed item flags.
494 : : */
495 : : static void
496 : 0 : flow_verbs_translate_item_vlan(struct mlx5_flow *dev_flow,
497 : : const struct rte_flow_item *item,
498 : : uint64_t item_flags)
499 : : {
500 : 0 : const struct rte_flow_item_vlan *spec = item->spec;
501 : 0 : const struct rte_flow_item_vlan *mask = item->mask;
502 : : unsigned int size = sizeof(struct ibv_flow_spec_eth);
503 : 0 : const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
504 : 0 : struct ibv_flow_spec_eth eth = {
505 [ # # ]: 0 : .type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags),
506 : : .size = size,
507 : : };
508 [ # # ]: 0 : const uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
509 : : MLX5_FLOW_LAYER_OUTER_L2;
510 : :
511 [ # # ]: 0 : if (!mask)
512 : : mask = &rte_flow_item_vlan_mask;
513 [ # # ]: 0 : if (spec) {
514 : 0 : eth.val.vlan_tag = spec->hdr.vlan_tci;
515 : 0 : eth.mask.vlan_tag = mask->hdr.vlan_tci;
516 : 0 : eth.val.vlan_tag &= eth.mask.vlan_tag;
517 : 0 : eth.val.ether_type = spec->hdr.eth_proto;
518 : 0 : eth.mask.ether_type = mask->hdr.eth_proto;
519 : 0 : eth.val.ether_type &= eth.mask.ether_type;
520 : : }
521 [ # # ]: 0 : if (!(item_flags & l2m))
522 : 0 : flow_verbs_spec_add(&dev_flow->verbs, ð, size);
523 : : else
524 : : flow_verbs_item_vlan_update(&dev_flow->verbs.attr, ð);
525 [ # # ]: 0 : if (!tunnel)
526 : 0 : dev_flow->handle->vf_vlan.tag =
527 [ # # ]: 0 : rte_be_to_cpu_16(spec->hdr.vlan_tci) & 0x0fff;
528 : 0 : }
529 : :
530 : : /**
531 : : * Convert the @p item into a Verbs specification. This function assumes that
532 : : * the input is valid and that there is space to insert the requested item
533 : : * into the flow.
534 : : *
535 : : * @param[in, out] dev_flow
536 : : * Pointer to dev_flow structure.
537 : : * @param[in] item
538 : : * Item specification.
539 : : * @param[in] item_flags
540 : : * Parsed item flags.
541 : : */
542 : : static void
543 : 0 : flow_verbs_translate_item_ipv4(struct mlx5_flow *dev_flow,
544 : : const struct rte_flow_item *item,
545 : : uint64_t item_flags)
546 : : {
547 : 0 : const struct rte_flow_item_ipv4 *spec = item->spec;
548 : 0 : const struct rte_flow_item_ipv4 *mask = item->mask;
549 : : unsigned int size = sizeof(struct ibv_flow_spec_ipv4_ext);
550 : 0 : struct ibv_flow_spec_ipv4_ext ipv4 = {
551 [ # # ]: 0 : .type = IBV_FLOW_SPEC_IPV4_EXT | VERBS_SPEC_INNER(item_flags),
552 : : .size = size,
553 : : };
554 : :
555 [ # # ]: 0 : if (!mask)
556 : : mask = &rte_flow_item_ipv4_mask;
557 [ # # ]: 0 : if (spec) {
558 : 0 : ipv4.val = (struct ibv_flow_ipv4_ext_filter){
559 : 0 : .src_ip = spec->hdr.src_addr,
560 : 0 : .dst_ip = spec->hdr.dst_addr,
561 : 0 : .proto = spec->hdr.next_proto_id,
562 : 0 : .tos = spec->hdr.type_of_service,
563 : : };
564 : 0 : ipv4.mask = (struct ibv_flow_ipv4_ext_filter){
565 : 0 : .src_ip = mask->hdr.src_addr,
566 : 0 : .dst_ip = mask->hdr.dst_addr,
567 : 0 : .proto = mask->hdr.next_proto_id,
568 : 0 : .tos = mask->hdr.type_of_service,
569 : : };
570 : : /* Remove unwanted bits from values. */
571 : 0 : ipv4.val.src_ip &= ipv4.mask.src_ip;
572 : 0 : ipv4.val.dst_ip &= ipv4.mask.dst_ip;
573 : 0 : ipv4.val.proto &= ipv4.mask.proto;
574 : 0 : ipv4.val.tos &= ipv4.mask.tos;
575 : : }
576 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &ipv4, size);
577 : 0 : }
578 : :
579 : : /**
580 : : * Convert the @p item into a Verbs specification. This function assumes that
581 : : * the input is valid and that there is space to insert the requested item
582 : : * into the flow.
583 : : *
584 : : * @param[in, out] dev_flow
585 : : * Pointer to dev_flow structure.
586 : : * @param[in] item
587 : : * Item specification.
588 : : * @param[in] item_flags
589 : : * Parsed item flags.
590 : : */
591 : : static void
592 : 0 : flow_verbs_translate_item_ipv6(struct mlx5_flow *dev_flow,
593 : : const struct rte_flow_item *item,
594 : : uint64_t item_flags)
595 : : {
596 : 0 : const struct rte_flow_item_ipv6 *spec = item->spec;
597 : 0 : const struct rte_flow_item_ipv6 *mask = item->mask;
598 : : unsigned int size = sizeof(struct ibv_flow_spec_ipv6);
599 : 0 : struct ibv_flow_spec_ipv6 ipv6 = {
600 [ # # ]: 0 : .type = IBV_FLOW_SPEC_IPV6 | VERBS_SPEC_INNER(item_flags),
601 : : .size = size,
602 : : };
603 : :
604 [ # # ]: 0 : if (!mask)
605 : : mask = &rte_flow_item_ipv6_mask;
606 [ # # ]: 0 : if (spec) {
607 : : unsigned int i;
608 : : uint32_t vtc_flow_val;
609 : : uint32_t vtc_flow_mask;
610 : :
611 : : memcpy(&ipv6.val.src_ip, &spec->hdr.src_addr,
612 : : RTE_DIM(ipv6.val.src_ip));
613 : : memcpy(&ipv6.val.dst_ip, &spec->hdr.dst_addr,
614 : : RTE_DIM(ipv6.val.dst_ip));
615 : : memcpy(&ipv6.mask.src_ip, &mask->hdr.src_addr,
616 : : RTE_DIM(ipv6.mask.src_ip));
617 : : memcpy(&ipv6.mask.dst_ip, &mask->hdr.dst_addr,
618 : : RTE_DIM(ipv6.mask.dst_ip));
619 [ # # ]: 0 : vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);
620 [ # # ]: 0 : vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);
621 : : ipv6.val.flow_label =
622 [ # # ]: 0 : rte_cpu_to_be_32((vtc_flow_val & RTE_IPV6_HDR_FL_MASK) >>
623 : : RTE_IPV6_HDR_FL_SHIFT);
624 : 0 : ipv6.val.traffic_class = (vtc_flow_val & RTE_IPV6_HDR_TC_MASK) >>
625 : : RTE_IPV6_HDR_TC_SHIFT;
626 : 0 : ipv6.val.next_hdr = spec->hdr.proto;
627 : 0 : ipv6.mask.flow_label =
628 [ # # ]: 0 : rte_cpu_to_be_32((vtc_flow_mask & RTE_IPV6_HDR_FL_MASK) >>
629 : : RTE_IPV6_HDR_FL_SHIFT);
630 : 0 : ipv6.mask.traffic_class = (vtc_flow_mask & RTE_IPV6_HDR_TC_MASK) >>
631 : : RTE_IPV6_HDR_TC_SHIFT;
632 : 0 : ipv6.mask.next_hdr = mask->hdr.proto;
633 : : /* Remove unwanted bits from values. */
634 [ # # ]: 0 : for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {
635 : 0 : ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];
636 : 0 : ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];
637 : : }
638 : 0 : ipv6.val.flow_label &= ipv6.mask.flow_label;
639 : 0 : ipv6.val.traffic_class &= ipv6.mask.traffic_class;
640 : 0 : ipv6.val.next_hdr &= ipv6.mask.next_hdr;
641 : : }
642 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &ipv6, size);
643 : 0 : }
644 : :
645 : : /**
646 : : * Convert the @p item into a Verbs specification. This function assumes that
647 : : * the input is valid and that there is space to insert the requested item
648 : : * into the flow.
649 : : *
650 : : * @param[in, out] dev_flow
651 : : * Pointer to dev_flow structure.
652 : : * @param[in] item
653 : : * Item specification.
654 : : * @param[in] item_flags
655 : : * Parsed item flags.
656 : : */
657 : : static void
658 : 0 : flow_verbs_translate_item_tcp(struct mlx5_flow *dev_flow,
659 : : const struct rte_flow_item *item,
660 : : uint64_t item_flags __rte_unused)
661 : : {
662 : 0 : const struct rte_flow_item_tcp *spec = item->spec;
663 : 0 : const struct rte_flow_item_tcp *mask = item->mask;
664 : : unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
665 : 0 : struct ibv_flow_spec_tcp_udp tcp = {
666 [ # # ]: 0 : .type = IBV_FLOW_SPEC_TCP | VERBS_SPEC_INNER(item_flags),
667 : : .size = size,
668 : : };
669 : :
670 [ # # ]: 0 : if (!mask)
671 : : mask = &rte_flow_item_tcp_mask;
672 [ # # ]: 0 : if (spec) {
673 : 0 : tcp.val.dst_port = spec->hdr.dst_port;
674 : 0 : tcp.val.src_port = spec->hdr.src_port;
675 : 0 : tcp.mask.dst_port = mask->hdr.dst_port;
676 : 0 : tcp.mask.src_port = mask->hdr.src_port;
677 : : /* Remove unwanted bits from values. */
678 : 0 : tcp.val.src_port &= tcp.mask.src_port;
679 : 0 : tcp.val.dst_port &= tcp.mask.dst_port;
680 : : }
681 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &tcp, size);
682 : 0 : }
683 : :
684 : : /**
685 : : * Convert the @p item into a Verbs specification. This function assumes that
686 : : * the input is valid and that there is space to insert the requested item
687 : : * into the flow.
688 : : *
689 : : * @param[in, out] dev_flow
690 : : * Pointer to dev_flow structure.
691 : : * @param[in] item
692 : : * Item specification.
693 : : * @param[in] item_flags
694 : : * Parsed item flags.
695 : : */
696 : : #ifdef HAVE_IBV_FLOW_SPEC_ESP
697 : : static void
698 : 0 : flow_verbs_translate_item_esp(struct mlx5_flow *dev_flow,
699 : : const struct rte_flow_item *item,
700 : : uint64_t item_flags __rte_unused)
701 : : {
702 : 0 : const struct rte_flow_item_esp *spec = item->spec;
703 : 0 : const struct rte_flow_item_esp *mask = item->mask;
704 : : unsigned int size = sizeof(struct ibv_flow_spec_esp);
705 : 0 : struct ibv_flow_spec_esp esp = {
706 [ # # ]: 0 : .type = IBV_FLOW_SPEC_ESP | VERBS_SPEC_INNER(item_flags),
707 : : .size = size,
708 : : };
709 : :
710 [ # # ]: 0 : if (!mask)
711 : : mask = &rte_flow_item_esp_mask;
712 [ # # ]: 0 : if (spec) {
713 : 0 : esp.val.spi = spec->hdr.spi & mask->hdr.spi;
714 : 0 : esp.mask.spi = mask->hdr.spi;
715 : : }
716 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &esp, size);
717 : 0 : }
718 : : #endif
719 : :
720 : : /**
721 : : * Convert the @p item into a Verbs specification. This function assumes that
722 : : * the input is valid and that there is space to insert the requested item
723 : : * into the flow.
724 : : *
725 : : * @param[in, out] dev_flow
726 : : * Pointer to dev_flow structure.
727 : : * @param[in] item
728 : : * Item specification.
729 : : * @param[in] item_flags
730 : : * Parsed item flags.
731 : : */
732 : : static void
733 : 0 : flow_verbs_translate_item_udp(struct mlx5_flow *dev_flow,
734 : : const struct rte_flow_item *item,
735 : : uint64_t item_flags __rte_unused)
736 : : {
737 : 0 : const struct rte_flow_item_udp *spec = item->spec;
738 : 0 : const struct rte_flow_item_udp *mask = item->mask;
739 : : unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
740 : 0 : struct ibv_flow_spec_tcp_udp udp = {
741 [ # # ]: 0 : .type = IBV_FLOW_SPEC_UDP | VERBS_SPEC_INNER(item_flags),
742 : : .size = size,
743 : : };
744 : :
745 [ # # ]: 0 : if (!mask)
746 : : mask = &rte_flow_item_udp_mask;
747 [ # # ]: 0 : if (spec) {
748 : 0 : udp.val.dst_port = spec->hdr.dst_port;
749 : 0 : udp.val.src_port = spec->hdr.src_port;
750 : 0 : udp.mask.dst_port = mask->hdr.dst_port;
751 : 0 : udp.mask.src_port = mask->hdr.src_port;
752 : : /* Remove unwanted bits from values. */
753 : 0 : udp.val.src_port &= udp.mask.src_port;
754 : 0 : udp.val.dst_port &= udp.mask.dst_port;
755 : : }
756 : 0 : item++;
757 [ # # ]: 0 : while (item->type == RTE_FLOW_ITEM_TYPE_VOID)
758 : 0 : item++;
759 [ # # ]: 0 : if (!(udp.val.dst_port & udp.mask.dst_port)) {
760 [ # # # # ]: 0 : switch ((item)->type) {
761 : : case RTE_FLOW_ITEM_TYPE_VXLAN:
762 : 0 : udp.val.dst_port = htons(MLX5_UDP_PORT_VXLAN);
763 : 0 : udp.mask.dst_port = 0xffff;
764 : 0 : break;
765 : : case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
766 : 0 : udp.val.dst_port = htons(MLX5_UDP_PORT_VXLAN_GPE);
767 : 0 : udp.mask.dst_port = 0xffff;
768 : 0 : break;
769 : : case RTE_FLOW_ITEM_TYPE_MPLS:
770 : 0 : udp.val.dst_port = htons(MLX5_UDP_PORT_MPLS);
771 : 0 : udp.mask.dst_port = 0xffff;
772 : 0 : break;
773 : : default:
774 : : break;
775 : : }
776 : : }
777 : :
778 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &udp, size);
779 : 0 : }
780 : :
781 : : /**
782 : : * Convert the @p item into a Verbs specification. This function assumes that
783 : : * the input is valid and that there is space to insert the requested item
784 : : * into the flow.
785 : : *
786 : : * @param[in, out] dev_flow
787 : : * Pointer to dev_flow structure.
788 : : * @param[in] item
789 : : * Item specification.
790 : : * @param[in] item_flags
791 : : * Parsed item flags.
792 : : */
793 : : static void
794 : 0 : flow_verbs_translate_item_vxlan(struct mlx5_flow *dev_flow,
795 : : const struct rte_flow_item *item,
796 : : uint64_t item_flags __rte_unused)
797 : : {
798 : 0 : const struct rte_flow_item_vxlan *spec = item->spec;
799 : 0 : const struct rte_flow_item_vxlan *mask = item->mask;
800 : : unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
801 : 0 : struct ibv_flow_spec_tunnel vxlan = {
802 : : .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
803 : : .size = size,
804 : : };
805 : : union vni {
806 : : uint32_t vlan_id;
807 : : uint8_t vni[4];
808 : 0 : } id = { .vlan_id = 0, };
809 : :
810 [ # # ]: 0 : if (!mask)
811 : : mask = &rte_flow_item_vxlan_mask;
812 [ # # ]: 0 : if (spec) {
813 : 0 : memcpy(&id.vni[1], spec->hdr.vni, 3);
814 : 0 : vxlan.val.tunnel_id = id.vlan_id;
815 : 0 : memcpy(&id.vni[1], mask->hdr.vni, 3);
816 : 0 : vxlan.mask.tunnel_id = id.vlan_id;
817 : : /* Remove unwanted bits from values. */
818 : 0 : vxlan.val.tunnel_id &= vxlan.mask.tunnel_id;
819 : : }
820 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &vxlan, size);
821 : 0 : }
822 : :
823 : : /**
824 : : * Convert the @p item into a Verbs specification. This function assumes that
825 : : * the input is valid and that there is space to insert the requested item
826 : : * into the flow.
827 : : *
828 : : * @param[in, out] dev_flow
829 : : * Pointer to dev_flow structure.
830 : : * @param[in] item
831 : : * Item specification.
832 : : * @param[in] item_flags
833 : : * Parsed item flags.
834 : : */
835 : : static void
836 : 0 : flow_verbs_translate_item_vxlan_gpe(struct mlx5_flow *dev_flow,
837 : : const struct rte_flow_item *item,
838 : : uint64_t item_flags __rte_unused)
839 : : {
840 : 0 : const struct rte_flow_item_vxlan_gpe *spec = item->spec;
841 : 0 : const struct rte_flow_item_vxlan_gpe *mask = item->mask;
842 : : unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
843 : 0 : struct ibv_flow_spec_tunnel vxlan_gpe = {
844 : : .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
845 : : .size = size,
846 : : };
847 : : union vni {
848 : : uint32_t vlan_id;
849 : : uint8_t vni[4];
850 : 0 : } id = { .vlan_id = 0, };
851 : :
852 [ # # ]: 0 : if (!mask)
853 : : mask = &rte_flow_item_vxlan_gpe_mask;
854 [ # # ]: 0 : if (spec) {
855 : 0 : memcpy(&id.vni[1], spec->hdr.vni, 3);
856 : 0 : vxlan_gpe.val.tunnel_id = id.vlan_id;
857 : 0 : memcpy(&id.vni[1], mask->hdr.vni, 3);
858 : 0 : vxlan_gpe.mask.tunnel_id = id.vlan_id;
859 : : /* Remove unwanted bits from values. */
860 : 0 : vxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id;
861 : : }
862 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &vxlan_gpe, size);
863 : 0 : }
864 : :
865 : : /**
866 : : * Update the protocol in Verbs IPv4/IPv6 spec.
867 : : *
868 : : * @param[in, out] attr
869 : : * Pointer to Verbs attributes structure.
870 : : * @param[in] search
871 : : * Specification type to search in order to update the IP protocol.
872 : : * @param[in] protocol
873 : : * Protocol value to set if none is present in the specification.
874 : : */
875 : : static void
876 : : flow_verbs_item_gre_ip_protocol_update(struct ibv_flow_attr *attr,
877 : : enum ibv_flow_spec_type search,
878 : : uint8_t protocol)
879 : : {
880 : : unsigned int i;
881 : 0 : struct ibv_spec_header *hdr = (struct ibv_spec_header *)
882 : : ((uint8_t *)attr + sizeof(struct ibv_flow_attr));
883 : :
884 : : if (!attr)
885 : : return;
886 [ # # # # ]: 0 : for (i = 0; i != attr->num_of_specs; ++i) {
887 [ # # # # ]: 0 : if (hdr->type == search) {
888 : : union {
889 : : struct ibv_flow_spec_ipv4_ext *ipv4;
890 : : struct ibv_flow_spec_ipv6 *ipv6;
891 : : } ip;
892 : :
893 : : switch (search) {
894 : : case IBV_FLOW_SPEC_IPV4_EXT:
895 : : ip.ipv4 = (struct ibv_flow_spec_ipv4_ext *)hdr;
896 [ # # ]: 0 : if (!ip.ipv4->val.proto) {
897 : 0 : ip.ipv4->val.proto = protocol;
898 : 0 : ip.ipv4->mask.proto = 0xff;
899 : : }
900 : : break;
901 : : case IBV_FLOW_SPEC_IPV6:
902 : : ip.ipv6 = (struct ibv_flow_spec_ipv6 *)hdr;
903 [ # # ]: 0 : if (!ip.ipv6->val.next_hdr) {
904 : 0 : ip.ipv6->val.next_hdr = protocol;
905 : 0 : ip.ipv6->mask.next_hdr = 0xff;
906 : : }
907 : : break;
908 : : default:
909 : : break;
910 : : }
911 : : break;
912 : : }
913 : 0 : hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
914 : : }
915 : : }
916 : :
917 : : /**
918 : : * Reserve space for GRE spec in spec buffer.
919 : : *
920 : : * @param[in,out] dev_flow
921 : : * Pointer to dev_flow structure.
922 : : *
923 : : * @return
924 : : * Pointer to reserved space in spec buffer.
925 : : */
926 : : static uint8_t *
927 : : flow_verbs_reserve_gre(struct mlx5_flow *dev_flow)
928 : : {
929 : : uint8_t *buffer;
930 : 0 : struct mlx5_flow_verbs_workspace *verbs = &dev_flow->verbs;
931 : : #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT
932 : : unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
933 : : struct ibv_flow_spec_tunnel tunnel = {
934 : : .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
935 : : .size = size,
936 : : };
937 : : #else
938 : : unsigned int size = sizeof(struct ibv_flow_spec_gre);
939 : 0 : struct ibv_flow_spec_gre tunnel = {
940 : : .type = IBV_FLOW_SPEC_GRE,
941 : : .size = size,
942 : : };
943 : : #endif
944 : :
945 : 0 : buffer = verbs->specs + verbs->size;
946 : 0 : flow_verbs_spec_add(verbs, &tunnel, size);
947 : : return buffer;
948 : : }
949 : :
950 : : /**
951 : : * Convert the @p item into a Verbs specification. This function assumes that
952 : : * the input is valid and that Verbs specification will be placed in
953 : : * the pre-reserved space.
954 : : *
955 : : * @param[in, out] dev_flow
956 : : * Pointer to dev_flow structure.
957 : : * @param[in, out] gre_spec
958 : : * Pointer to space reserved for GRE spec.
959 : : * @param[in] item
960 : : * Item specification.
961 : : * @param[in] item_flags
962 : : * Parsed item flags.
963 : : */
964 : : static void
965 : 0 : flow_verbs_translate_item_gre(struct mlx5_flow *dev_flow,
966 : : uint8_t *gre_spec,
967 : : const struct rte_flow_item *item __rte_unused,
968 : : uint64_t item_flags)
969 : : {
970 : : struct mlx5_flow_verbs_workspace *verbs = &dev_flow->verbs;
971 : : #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT
972 : : unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
973 : : struct ibv_flow_spec_tunnel tunnel = {
974 : : .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
975 : : .size = size,
976 : : };
977 : : #else
978 : : static const struct rte_flow_item_gre empty_gre = {0,};
979 : 0 : const struct rte_flow_item_gre *spec = item->spec;
980 : 0 : const struct rte_flow_item_gre *mask = item->mask;
981 : : unsigned int size = sizeof(struct ibv_flow_spec_gre);
982 : 0 : struct ibv_flow_spec_gre tunnel = {
983 : : .type = IBV_FLOW_SPEC_GRE,
984 : : .size = size,
985 : : };
986 : :
987 [ # # ]: 0 : if (!spec) {
988 : : spec = &empty_gre;
989 : : mask = &empty_gre;
990 : : } else {
991 [ # # ]: 0 : if (!mask)
992 : : mask = &rte_flow_item_gre_mask;
993 : : }
994 : 0 : tunnel.val.c_ks_res0_ver = spec->c_rsvd0_ver;
995 : 0 : tunnel.val.protocol = spec->protocol;
996 : 0 : tunnel.mask.c_ks_res0_ver = mask->c_rsvd0_ver;
997 : 0 : tunnel.mask.protocol = mask->protocol;
998 : : /* Remove unwanted bits from values. */
999 : 0 : tunnel.val.c_ks_res0_ver &= tunnel.mask.c_ks_res0_ver;
1000 : : tunnel.val.key &= tunnel.mask.key;
1001 [ # # ]: 0 : if (tunnel.mask.protocol) {
1002 : 0 : tunnel.val.protocol &= tunnel.mask.protocol;
1003 : : } else {
1004 : 0 : tunnel.val.protocol = mlx5_translate_tunnel_etypes(item_flags);
1005 [ # # ]: 0 : if (tunnel.val.protocol) {
1006 : 0 : tunnel.mask.protocol = 0xFFFF;
1007 : 0 : tunnel.val.protocol =
1008 [ # # ]: 0 : rte_cpu_to_be_16(tunnel.val.protocol);
1009 : : }
1010 : : }
1011 : : #endif
1012 [ # # ]: 0 : if (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
1013 : : flow_verbs_item_gre_ip_protocol_update(&verbs->attr,
1014 : : IBV_FLOW_SPEC_IPV4_EXT,
1015 : : IPPROTO_GRE);
1016 : : else
1017 : : flow_verbs_item_gre_ip_protocol_update(&verbs->attr,
1018 : : IBV_FLOW_SPEC_IPV6,
1019 : : IPPROTO_GRE);
1020 : : MLX5_ASSERT(gre_spec);
1021 : : memcpy(gre_spec, &tunnel, size);
1022 : 0 : }
1023 : :
1024 : : /**
1025 : : * Convert the @p action into a Verbs specification. This function assumes that
1026 : : * the input is valid and that there is space to insert the requested action
1027 : : * into the flow. This function also return the action that was added.
1028 : : *
1029 : : * @param[in, out] dev_flow
1030 : : * Pointer to dev_flow structure.
1031 : : * @param[in] item
1032 : : * Item specification.
1033 : : * @param[in] item_flags
1034 : : * Parsed item flags.
1035 : : */
1036 : : static void
1037 : 0 : flow_verbs_translate_item_mpls(struct mlx5_flow *dev_flow __rte_unused,
1038 : : const struct rte_flow_item *item __rte_unused,
1039 : : uint64_t item_flags __rte_unused)
1040 : : {
1041 : : #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
1042 : 0 : const struct rte_flow_item_mpls *spec = item->spec;
1043 : 0 : const struct rte_flow_item_mpls *mask = item->mask;
1044 : : unsigned int size = sizeof(struct ibv_flow_spec_mpls);
1045 : 0 : struct ibv_flow_spec_mpls mpls = {
1046 : : .type = IBV_FLOW_SPEC_MPLS,
1047 : : .size = size,
1048 : : };
1049 : :
1050 [ # # ]: 0 : if (!mask)
1051 : : mask = &rte_flow_item_mpls_mask;
1052 [ # # ]: 0 : if (spec) {
1053 : : memcpy(&mpls.val.label, spec, sizeof(mpls.val.label));
1054 : : memcpy(&mpls.mask.label, mask, sizeof(mpls.mask.label));
1055 : : /* Remove unwanted bits from values. */
1056 : 0 : mpls.val.label &= mpls.mask.label;
1057 : : }
1058 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &mpls, size);
1059 : : #endif
1060 : 0 : }
1061 : :
1062 : : /**
1063 : : * Convert the @p action into a Verbs specification. This function assumes that
1064 : : * the input is valid and that there is space to insert the requested action
1065 : : * into the flow.
1066 : : *
1067 : : * @param[in] dev_flow
1068 : : * Pointer to mlx5_flow.
1069 : : * @param[in] action
1070 : : * Action configuration.
1071 : : */
1072 : : static void
1073 : : flow_verbs_translate_action_drop
1074 : : (struct mlx5_flow *dev_flow,
1075 : : const struct rte_flow_action *action __rte_unused)
1076 : : {
1077 : : unsigned int size = sizeof(struct ibv_flow_spec_action_drop);
1078 : 0 : struct ibv_flow_spec_action_drop drop = {
1079 : : .type = IBV_FLOW_SPEC_ACTION_DROP,
1080 : : .size = size,
1081 : : };
1082 : :
1083 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &drop, size);
1084 : : }
1085 : :
1086 : : /**
1087 : : * Convert the @p action into a Verbs specification. This function assumes that
1088 : : * the input is valid and that there is space to insert the requested action
1089 : : * into the flow.
1090 : : *
1091 : : * @param[in] rss_desc
1092 : : * Pointer to mlx5_flow_rss_desc.
1093 : : * @param[in] action
1094 : : * Action configuration.
1095 : : */
1096 : : static void
1097 : : flow_verbs_translate_action_queue(struct mlx5_flow_rss_desc *rss_desc,
1098 : : const struct rte_flow_action *action)
1099 : : {
1100 : 0 : const struct rte_flow_action_queue *queue = action->conf;
1101 : :
1102 : 0 : rss_desc->queue[0] = queue->index;
1103 : 0 : rss_desc->queue_num = 1;
1104 : : }
1105 : :
1106 : : /**
1107 : : * Convert the @p action into a Verbs specification. This function assumes that
1108 : : * the input is valid and that there is space to insert the requested action
1109 : : * into the flow.
1110 : : *
1111 : : * @param[in] rss_desc
1112 : : * Pointer to mlx5_flow_rss_desc.
1113 : : * @param[in] action
1114 : : * Action configuration.
1115 : : */
1116 : : static void
1117 : 0 : flow_verbs_translate_action_rss(struct mlx5_flow_rss_desc *rss_desc,
1118 : : const struct rte_flow_action *action)
1119 : : {
1120 : 0 : const struct rte_flow_action_rss *rss = action->conf;
1121 : : const uint8_t *rss_key;
1122 : :
1123 [ # # ]: 0 : memcpy(rss_desc->queue, rss->queue, rss->queue_num * sizeof(uint16_t));
1124 : 0 : rss_desc->queue_num = rss->queue_num;
1125 : : /* NULL RSS key indicates default RSS key. */
1126 [ # # ]: 0 : rss_key = !rss->key ? mlx5_rss_hash_default_key : rss->key;
1127 : 0 : memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
1128 : : /*
1129 : : * rss->level and rss.types should be set in advance when expanding
1130 : : * items for RSS.
1131 : : */
1132 : 0 : }
1133 : :
1134 : : /**
1135 : : * Convert the @p action into a Verbs specification. This function assumes that
1136 : : * the input is valid and that there is space to insert the requested action
1137 : : * into the flow.
1138 : : *
1139 : : * @param[in] dev_flow
1140 : : * Pointer to mlx5_flow.
1141 : : * @param[in] action
1142 : : * Action configuration.
1143 : : */
1144 : : static void
1145 : : flow_verbs_translate_action_flag
1146 : : (struct mlx5_flow *dev_flow,
1147 : : const struct rte_flow_action *action __rte_unused)
1148 : : {
1149 : : unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
1150 : 0 : struct ibv_flow_spec_action_tag tag = {
1151 : : .type = IBV_FLOW_SPEC_ACTION_TAG,
1152 : : .size = size,
1153 : : .tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),
1154 : : };
1155 : :
1156 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &tag, size);
1157 : : }
1158 : :
1159 : : /**
1160 : : * Convert the @p action into a Verbs specification. This function assumes that
1161 : : * the input is valid and that there is space to insert the requested action
1162 : : * into the flow.
1163 : : *
1164 : : * @param[in] dev_flow
1165 : : * Pointer to mlx5_flow.
1166 : : * @param[in] action
1167 : : * Action configuration.
1168 : : */
1169 : : static void
1170 : 0 : flow_verbs_translate_action_mark(struct mlx5_flow *dev_flow,
1171 : : const struct rte_flow_action *action)
1172 : : {
1173 : 0 : const struct rte_flow_action_mark *mark = action->conf;
1174 : : unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
1175 : 0 : struct ibv_flow_spec_action_tag tag = {
1176 : : .type = IBV_FLOW_SPEC_ACTION_TAG,
1177 : : .size = size,
1178 [ # # ]: 0 : .tag_id = mlx5_flow_mark_set(mark->id),
1179 : : };
1180 : :
1181 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &tag, size);
1182 : 0 : }
1183 : :
1184 : : /**
1185 : : * Convert the @p action into a Verbs specification. This function assumes that
1186 : : * the input is valid and that there is space to insert the requested action
1187 : : * into the flow.
1188 : : *
1189 : : * @param[in] dev
1190 : : * Pointer to the Ethernet device structure.
1191 : : * @param[in] action
1192 : : * Action configuration.
1193 : : * @param[in] dev_flow
1194 : : * Pointer to mlx5_flow.
1195 : : * @param[out] error
1196 : : * Pointer to error structure.
1197 : : *
1198 : : * @return
1199 : : * 0 On success else a negative errno value is returned and rte_errno is set.
1200 : : */
1201 : : static int
1202 : 0 : flow_verbs_translate_action_count(struct mlx5_flow *dev_flow,
1203 : : const struct rte_flow_action *action,
1204 : : struct rte_eth_dev *dev,
1205 : : struct rte_flow_error *error)
1206 : : {
1207 : 0 : const struct rte_flow_action_count *count = action->conf;
1208 : 0 : struct rte_flow *flow = dev_flow->flow;
1209 : : #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
1210 : : defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1211 : : struct mlx5_flow_counter_pool *pool;
1212 : : struct mlx5_flow_counter *cnt = NULL;
1213 : : unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
1214 : 0 : struct ibv_flow_spec_counter_action counter = {
1215 : : .type = IBV_FLOW_SPEC_ACTION_COUNT,
1216 : : .size = size,
1217 : : };
1218 : : #endif
1219 : :
1220 [ # # ]: 0 : if (!flow->counter) {
1221 : 0 : flow->counter = flow_verbs_counter_new(dev, count->id);
1222 [ # # ]: 0 : if (!flow->counter)
1223 : 0 : return rte_flow_error_set(error, rte_errno,
1224 : : RTE_FLOW_ERROR_TYPE_ACTION,
1225 : : action,
1226 : : "cannot get counter"
1227 : : " context.");
1228 : : }
1229 : : #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
1230 : : cnt = flow_verbs_counter_get_by_idx(dev, flow->counter, &pool);
1231 : : counter.counter_set_handle =
1232 : : ((struct ibv_counter_set *)cnt->dcs_when_active)->handle;
1233 : : flow_verbs_spec_add(&dev_flow->verbs, &counter, size);
1234 : : #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1235 [ # # ]: 0 : cnt = flow_verbs_counter_get_by_idx(dev, flow->counter, &pool);
1236 : 0 : counter.counters = (struct ibv_counters *)cnt->dcs_when_active;
1237 : 0 : flow_verbs_spec_add(&dev_flow->verbs, &counter, size);
1238 : : #endif
1239 : 0 : return 0;
1240 : : }
1241 : :
1242 : : /**
1243 : : * Validates @p attributes of the flow rule.
1244 : : *
1245 : : * This function is used if and only if legacy Verbs flow engine is used.
1246 : : *
1247 : : * @param[in] dev
1248 : : * Pointer to the Ethernet device structure.
1249 : : * @param[in] attributes
1250 : : * Pointer to flow attributes
1251 : : * @param[out] error
1252 : : * Pointer to error structure.
1253 : : *
1254 : : * @return
1255 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1256 : : */
1257 : : static int
1258 : 0 : flow_verbs_validate_attributes(struct rte_eth_dev *dev,
1259 : : const struct rte_flow_attr *attributes,
1260 : : struct rte_flow_error *error)
1261 : : {
1262 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1263 : 0 : uint32_t priority_max = priv->sh->flow_max_priority - 1;
1264 : :
1265 [ # # ]: 0 : if (attributes->group)
1266 : 0 : return rte_flow_error_set(error, ENOTSUP,
1267 : : RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
1268 : : NULL, "groups is not supported");
1269 [ # # # # ]: 0 : if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
1270 : : attributes->priority >= priority_max)
1271 : 0 : return rte_flow_error_set(error, ENOTSUP,
1272 : : RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
1273 : : NULL, "priority out of range");
1274 [ # # ]: 0 : if (attributes->egress)
1275 : 0 : return rte_flow_error_set(error, ENOTSUP,
1276 : : RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL,
1277 : : "egress is not supported");
1278 [ # # ]: 0 : if (attributes->transfer)
1279 : 0 : return rte_flow_error_set(error, ENOTSUP,
1280 : : RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
1281 : : NULL, "transfer is not supported");
1282 [ # # ]: 0 : if (!attributes->ingress)
1283 : 0 : return rte_flow_error_set(error, EINVAL,
1284 : : RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
1285 : : NULL,
1286 : : "ingress attribute is mandatory");
1287 : : return 0;
1288 : : }
1289 : :
1290 : : /**
1291 : : * Internal validation function. For validating both actions and items.
1292 : : *
1293 : : * @param[in] dev
1294 : : * Pointer to the Ethernet device structure.
1295 : : * @param[in] attr
1296 : : * Pointer to the flow attributes.
1297 : : * @param[in] items
1298 : : * Pointer to the list of items.
1299 : : * @param[in] actions
1300 : : * Pointer to the list of actions.
1301 : : * @param[in] external
1302 : : * This flow rule is created by request external to PMD.
1303 : : * @param[in] hairpin
1304 : : * Number of hairpin TX actions, 0 means classic flow.
1305 : : * @param[out] error
1306 : : * Pointer to the error structure.
1307 : : *
1308 : : * @return
1309 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1310 : : */
1311 : : static int
1312 : 0 : flow_verbs_validate(struct rte_eth_dev *dev,
1313 : : const struct rte_flow_attr *attr,
1314 : : const struct rte_flow_item items[],
1315 : : const struct rte_flow_action actions[],
1316 : : bool external __rte_unused,
1317 : : int hairpin __rte_unused,
1318 : : struct rte_flow_error *error)
1319 : : {
1320 : : int ret;
1321 : : uint64_t action_flags = 0;
1322 : : uint64_t item_flags = 0;
1323 : : uint64_t last_item = 0;
1324 : : uint8_t next_protocol = 0xff;
1325 : : uint16_t ether_type = 0;
1326 : : bool is_empty_vlan = false;
1327 : : uint16_t udp_dport = 0;
1328 : : /* Verbs interface does not support groups higher than 0. */
1329 : : bool is_root = true;
1330 : :
1331 [ # # ]: 0 : if (items == NULL)
1332 : : return -1;
1333 : 0 : ret = flow_verbs_validate_attributes(dev, attr, error);
1334 [ # # ]: 0 : if (ret < 0)
1335 : : return ret;
1336 [ # # ]: 0 : for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1337 : 0 : int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
1338 : : int ret = 0;
1339 : :
1340 [ # # # # : 0 : switch (items->type) {
# # # # #
# # # #
# ]
1341 : : #ifdef HAVE_IBV_FLOW_SPEC_ESP
1342 : 0 : case RTE_FLOW_ITEM_TYPE_ESP:
1343 : 0 : ret = mlx5_flow_os_validate_item_esp(dev, items, item_flags,
1344 : : next_protocol, false, error);
1345 [ # # ]: 0 : if (ret < 0)
1346 : 0 : return ret;
1347 : : last_item = MLX5_FLOW_ITEM_ESP;
1348 : : break;
1349 : : #endif
1350 : : case RTE_FLOW_ITEM_TYPE_VOID:
1351 : : break;
1352 : 0 : case RTE_FLOW_ITEM_TYPE_ETH:
1353 : 0 : ret = mlx5_flow_validate_item_eth(dev, items, item_flags,
1354 : : false, error);
1355 [ # # ]: 0 : if (ret < 0)
1356 : 0 : return ret;
1357 [ # # ]: 0 : last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
1358 : : MLX5_FLOW_LAYER_OUTER_L2;
1359 [ # # # # ]: 0 : if (items->mask != NULL && items->spec != NULL) {
1360 : 0 : ether_type =
1361 : : ((const struct rte_flow_item_eth *)
1362 : : items->spec)->hdr.ether_type;
1363 : 0 : ether_type &=
1364 : : ((const struct rte_flow_item_eth *)
1365 : 0 : items->mask)->hdr.ether_type;
1366 [ # # ]: 0 : if (ether_type == RTE_BE16(RTE_ETHER_TYPE_VLAN))
1367 : : is_empty_vlan = true;
1368 [ # # ]: 0 : ether_type = rte_be_to_cpu_16(ether_type);
1369 : : } else {
1370 : : ether_type = 0;
1371 : : }
1372 : : break;
1373 : 0 : case RTE_FLOW_ITEM_TYPE_VLAN:
1374 : 0 : ret = mlx5_flow_validate_item_vlan(items, item_flags,
1375 : : dev, error);
1376 [ # # ]: 0 : if (ret < 0)
1377 : 0 : return ret;
1378 : : last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
1379 [ # # ]: 0 : MLX5_FLOW_LAYER_INNER_VLAN) :
1380 : : (MLX5_FLOW_LAYER_OUTER_L2 |
1381 : : MLX5_FLOW_LAYER_OUTER_VLAN);
1382 [ # # # # ]: 0 : if (items->mask != NULL && items->spec != NULL) {
1383 : 0 : ether_type =
1384 : : ((const struct rte_flow_item_vlan *)
1385 : : items->spec)->hdr.eth_proto;
1386 : 0 : ether_type &=
1387 : : ((const struct rte_flow_item_vlan *)
1388 : 0 : items->mask)->hdr.eth_proto;
1389 [ # # ]: 0 : ether_type = rte_be_to_cpu_16(ether_type);
1390 : : } else {
1391 : : ether_type = 0;
1392 : : }
1393 : : is_empty_vlan = false;
1394 : : break;
1395 : 0 : case RTE_FLOW_ITEM_TYPE_IPV4:
1396 : 0 : ret = mlx5_flow_validate_item_ipv4
1397 : : (dev, items, item_flags,
1398 : : last_item, ether_type, NULL,
1399 : : MLX5_ITEM_RANGE_NOT_ACCEPTED,
1400 : : error);
1401 [ # # ]: 0 : if (ret < 0)
1402 : 0 : return ret;
1403 [ # # ]: 0 : last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
1404 : : MLX5_FLOW_LAYER_OUTER_L3_IPV4;
1405 [ # # ]: 0 : if (items->mask != NULL &&
1406 : : ((const struct rte_flow_item_ipv4 *)
1407 [ # # ]: 0 : items->mask)->hdr.next_proto_id) {
1408 : 0 : next_protocol =
1409 : : ((const struct rte_flow_item_ipv4 *)
1410 : 0 : (items->spec))->hdr.next_proto_id;
1411 : 0 : next_protocol &=
1412 : : ((const struct rte_flow_item_ipv4 *)
1413 : : (items->mask))->hdr.next_proto_id;
1414 : : } else {
1415 : : /* Reset for inner layer. */
1416 : : next_protocol = 0xff;
1417 : : }
1418 : : break;
1419 : 0 : case RTE_FLOW_ITEM_TYPE_IPV6:
1420 : 0 : ret = mlx5_flow_validate_item_ipv6(dev, items,
1421 : : item_flags,
1422 : : last_item,
1423 : : ether_type, NULL,
1424 : : error);
1425 [ # # ]: 0 : if (ret < 0)
1426 : 0 : return ret;
1427 [ # # ]: 0 : last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
1428 : : MLX5_FLOW_LAYER_OUTER_L3_IPV6;
1429 [ # # ]: 0 : if (items->mask != NULL &&
1430 : : ((const struct rte_flow_item_ipv6 *)
1431 [ # # ]: 0 : items->mask)->hdr.proto) {
1432 : 0 : next_protocol =
1433 : : ((const struct rte_flow_item_ipv6 *)
1434 : 0 : items->spec)->hdr.proto;
1435 : 0 : next_protocol &=
1436 : : ((const struct rte_flow_item_ipv6 *)
1437 : : items->mask)->hdr.proto;
1438 : : } else {
1439 : : /* Reset for inner layer. */
1440 : : next_protocol = 0xff;
1441 : : }
1442 : : break;
1443 : 0 : case RTE_FLOW_ITEM_TYPE_UDP:
1444 : 0 : ret = mlx5_flow_validate_item_udp(dev, items,
1445 : : item_flags,
1446 : : next_protocol,
1447 : : error);
1448 : 0 : const struct rte_flow_item_udp *spec = items->spec;
1449 : 0 : const struct rte_flow_item_udp *mask = items->mask;
1450 [ # # ]: 0 : if (!mask)
1451 : : mask = &rte_flow_item_udp_mask;
1452 [ # # ]: 0 : if (spec != NULL)
1453 [ # # ]: 0 : udp_dport = rte_be_to_cpu_16
1454 : : (spec->hdr.dst_port &
1455 : : mask->hdr.dst_port);
1456 : :
1457 [ # # ]: 0 : if (ret < 0)
1458 : 0 : return ret;
1459 [ # # ]: 0 : last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
1460 : : MLX5_FLOW_LAYER_OUTER_L4_UDP;
1461 : : break;
1462 : 0 : case RTE_FLOW_ITEM_TYPE_TCP:
1463 : 0 : ret = mlx5_flow_validate_item_tcp
1464 : : (dev, items, item_flags,
1465 : : next_protocol,
1466 : : &rte_flow_item_tcp_mask,
1467 : : error);
1468 [ # # ]: 0 : if (ret < 0)
1469 : 0 : return ret;
1470 [ # # ]: 0 : last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
1471 : : MLX5_FLOW_LAYER_OUTER_L4_TCP;
1472 : : break;
1473 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN:
1474 : 0 : ret = mlx5_flow_validate_item_vxlan(dev, udp_dport,
1475 : : items, item_flags,
1476 : : is_root, error);
1477 [ # # ]: 0 : if (ret < 0)
1478 : 0 : return ret;
1479 : : last_item = MLX5_FLOW_LAYER_VXLAN;
1480 : : break;
1481 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1482 : 0 : ret = mlx5_flow_validate_item_vxlan_gpe(items,
1483 : : item_flags,
1484 : : dev, error);
1485 [ # # ]: 0 : if (ret < 0)
1486 : 0 : return ret;
1487 : : last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
1488 : : break;
1489 : 0 : case RTE_FLOW_ITEM_TYPE_GRE:
1490 : 0 : ret = mlx5_flow_validate_item_gre(dev, items, item_flags,
1491 : : next_protocol, error);
1492 [ # # ]: 0 : if (ret < 0)
1493 : 0 : return ret;
1494 : : last_item = MLX5_FLOW_LAYER_GRE;
1495 : : break;
1496 : 0 : case RTE_FLOW_ITEM_TYPE_MPLS:
1497 : 0 : ret = mlx5_flow_validate_item_mpls(dev, items,
1498 : : item_flags,
1499 : : last_item, error);
1500 [ # # ]: 0 : if (ret < 0)
1501 : 0 : return ret;
1502 : : last_item = MLX5_FLOW_LAYER_MPLS;
1503 : : break;
1504 : 0 : case RTE_FLOW_ITEM_TYPE_ICMP:
1505 : : case RTE_FLOW_ITEM_TYPE_ICMP6:
1506 : 0 : return rte_flow_error_set(error, ENOTSUP,
1507 : : RTE_FLOW_ERROR_TYPE_ITEM,
1508 : : NULL, "ICMP/ICMP6 "
1509 : : "item not supported");
1510 : 0 : default:
1511 : 0 : return rte_flow_error_set(error, ENOTSUP,
1512 : : RTE_FLOW_ERROR_TYPE_ITEM,
1513 : : NULL, "item not supported");
1514 : : }
1515 : 0 : item_flags |= last_item;
1516 : : }
1517 [ # # ]: 0 : if (is_empty_vlan)
1518 : 0 : return rte_flow_error_set(error, ENOTSUP,
1519 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1520 : : "VLAN matching without vid specification is not supported");
1521 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1522 [ # # # # : 0 : switch (actions->type) {
# # # # ]
1523 : : case RTE_FLOW_ACTION_TYPE_VOID:
1524 : : break;
1525 : 0 : case RTE_FLOW_ACTION_TYPE_FLAG:
1526 : 0 : ret = mlx5_flow_validate_action_flag(action_flags,
1527 : : attr,
1528 : : error);
1529 [ # # ]: 0 : if (ret < 0)
1530 : 0 : return ret;
1531 : 0 : action_flags |= MLX5_FLOW_ACTION_FLAG;
1532 : 0 : break;
1533 : 0 : case RTE_FLOW_ACTION_TYPE_MARK:
1534 : 0 : ret = mlx5_flow_validate_action_mark(dev, actions,
1535 : : action_flags,
1536 : : attr,
1537 : : error);
1538 [ # # ]: 0 : if (ret < 0)
1539 : 0 : return ret;
1540 : 0 : action_flags |= MLX5_FLOW_ACTION_MARK;
1541 : 0 : break;
1542 : 0 : case RTE_FLOW_ACTION_TYPE_DROP:
1543 : 0 : ret = mlx5_flow_validate_action_drop(dev,
1544 : : is_root,
1545 : : attr,
1546 : : error);
1547 [ # # ]: 0 : if (ret < 0)
1548 : 0 : return ret;
1549 : 0 : action_flags |= MLX5_FLOW_ACTION_DROP;
1550 : 0 : break;
1551 : 0 : case RTE_FLOW_ACTION_TYPE_QUEUE:
1552 : 0 : ret = mlx5_flow_validate_action_queue(actions,
1553 : : action_flags, dev,
1554 : : attr,
1555 : : error);
1556 [ # # ]: 0 : if (ret < 0)
1557 : 0 : return ret;
1558 : 0 : action_flags |= MLX5_FLOW_ACTION_QUEUE;
1559 : 0 : break;
1560 : 0 : case RTE_FLOW_ACTION_TYPE_RSS:
1561 : 0 : ret = mlx5_flow_validate_action_rss(actions,
1562 : : action_flags, dev,
1563 : : attr, item_flags,
1564 : : error);
1565 [ # # ]: 0 : if (ret < 0)
1566 : 0 : return ret;
1567 : 0 : action_flags |= MLX5_FLOW_ACTION_RSS;
1568 : 0 : break;
1569 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
1570 : 0 : ret = mlx5_flow_validate_action_count(dev, attr, error);
1571 [ # # ]: 0 : if (ret < 0)
1572 : 0 : return ret;
1573 : 0 : action_flags |= MLX5_FLOW_ACTION_COUNT;
1574 : 0 : break;
1575 : 0 : default:
1576 : 0 : return rte_flow_error_set(error, ENOTSUP,
1577 : : RTE_FLOW_ERROR_TYPE_ACTION,
1578 : : actions,
1579 : : "action not supported");
1580 : : }
1581 : : }
1582 : : /*
1583 : : * Validate the drop action mutual exclusion with other actions.
1584 : : * Drop action is mutually-exclusive with any other action, except for
1585 : : * Count action.
1586 : : */
1587 [ # # ]: 0 : if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
1588 [ # # ]: 0 : (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
1589 : 0 : return rte_flow_error_set(error, EINVAL,
1590 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1591 : : "Drop action is mutually-exclusive "
1592 : : "with any other action, except for "
1593 : : "Count action");
1594 [ # # ]: 0 : if (!(action_flags & MLX5_FLOW_FATE_ACTIONS))
1595 : 0 : return rte_flow_error_set(error, EINVAL,
1596 : : RTE_FLOW_ERROR_TYPE_ACTION, actions,
1597 : : "no fate action is found");
1598 : : return 0;
1599 : : }
1600 : :
1601 : : /**
1602 : : * Calculate the required bytes that are needed for the action part of the verbs
1603 : : * flow.
1604 : : *
1605 : : * @param[in] actions
1606 : : * Pointer to the list of actions.
1607 : : *
1608 : : * @return
1609 : : * The size of the memory needed for all actions.
1610 : : */
1611 : : static int
1612 : 0 : flow_verbs_get_actions_size(const struct rte_flow_action actions[])
1613 : : {
1614 : : int size = 0;
1615 : :
1616 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1617 [ # # # # : 0 : switch (actions->type) {
# ]
1618 : : case RTE_FLOW_ACTION_TYPE_VOID:
1619 : : break;
1620 : 0 : case RTE_FLOW_ACTION_TYPE_FLAG:
1621 : 0 : size += sizeof(struct ibv_flow_spec_action_tag);
1622 : 0 : break;
1623 : 0 : case RTE_FLOW_ACTION_TYPE_MARK:
1624 : 0 : size += sizeof(struct ibv_flow_spec_action_tag);
1625 : 0 : break;
1626 : 0 : case RTE_FLOW_ACTION_TYPE_DROP:
1627 : 0 : size += sizeof(struct ibv_flow_spec_action_drop);
1628 : 0 : break;
1629 : : case RTE_FLOW_ACTION_TYPE_QUEUE:
1630 : : break;
1631 : : case RTE_FLOW_ACTION_TYPE_RSS:
1632 : : break;
1633 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
1634 : : #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
1635 : : defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1636 : 0 : size += sizeof(struct ibv_flow_spec_counter_action);
1637 : : #endif
1638 : 0 : break;
1639 : : default:
1640 : : break;
1641 : : }
1642 : : }
1643 : 0 : return size;
1644 : : }
1645 : :
1646 : : /**
1647 : : * Calculate the required bytes that are needed for the item part of the verbs
1648 : : * flow.
1649 : : *
1650 : : * @param[in] items
1651 : : * Pointer to the list of items.
1652 : : *
1653 : : * @return
1654 : : * The size of the memory needed for all items.
1655 : : */
1656 : : static int
1657 : 0 : flow_verbs_get_items_size(const struct rte_flow_item items[])
1658 : : {
1659 : : int size = 0;
1660 : :
1661 [ # # ]: 0 : for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1662 [ # # # # : 0 : switch (items->type) {
# # # # #
# # ]
1663 : : case RTE_FLOW_ITEM_TYPE_VOID:
1664 : : break;
1665 : 0 : case RTE_FLOW_ITEM_TYPE_ETH:
1666 : 0 : size += sizeof(struct ibv_flow_spec_eth);
1667 : 0 : break;
1668 : 0 : case RTE_FLOW_ITEM_TYPE_VLAN:
1669 : 0 : size += sizeof(struct ibv_flow_spec_eth);
1670 : 0 : break;
1671 : 0 : case RTE_FLOW_ITEM_TYPE_IPV4:
1672 : 0 : size += sizeof(struct ibv_flow_spec_ipv4_ext);
1673 : 0 : break;
1674 : 0 : case RTE_FLOW_ITEM_TYPE_IPV6:
1675 : 0 : size += sizeof(struct ibv_flow_spec_ipv6);
1676 : 0 : break;
1677 : 0 : case RTE_FLOW_ITEM_TYPE_UDP:
1678 : 0 : size += sizeof(struct ibv_flow_spec_tcp_udp);
1679 : 0 : break;
1680 : 0 : case RTE_FLOW_ITEM_TYPE_TCP:
1681 : 0 : size += sizeof(struct ibv_flow_spec_tcp_udp);
1682 : 0 : break;
1683 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN:
1684 : 0 : size += sizeof(struct ibv_flow_spec_tunnel);
1685 : 0 : break;
1686 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1687 : 0 : size += sizeof(struct ibv_flow_spec_tunnel);
1688 : 0 : break;
1689 : : #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
1690 : 0 : case RTE_FLOW_ITEM_TYPE_GRE:
1691 : 0 : size += sizeof(struct ibv_flow_spec_gre);
1692 : 0 : break;
1693 : 0 : case RTE_FLOW_ITEM_TYPE_MPLS:
1694 : 0 : size += sizeof(struct ibv_flow_spec_mpls);
1695 : 0 : break;
1696 : : #else
1697 : : case RTE_FLOW_ITEM_TYPE_GRE:
1698 : : size += sizeof(struct ibv_flow_spec_tunnel);
1699 : : break;
1700 : : #endif
1701 : : default:
1702 : : break;
1703 : : }
1704 : : }
1705 : 0 : return size;
1706 : : }
1707 : :
1708 : : /**
1709 : : * Internal preparation function. Allocate mlx5_flow with the required size.
1710 : : * The required size is calculate based on the actions and items. This function
1711 : : * also returns the detected actions and items for later use.
1712 : : *
1713 : : * @param[in] dev
1714 : : * Pointer to Ethernet device.
1715 : : * @param[in] attr
1716 : : * Pointer to the flow attributes.
1717 : : * @param[in] items
1718 : : * Pointer to the list of items.
1719 : : * @param[in] actions
1720 : : * Pointer to the list of actions.
1721 : : * @param[out] error
1722 : : * Pointer to the error structure.
1723 : : *
1724 : : * @return
1725 : : * Pointer to mlx5_flow object on success, otherwise NULL and rte_errno
1726 : : * is set.
1727 : : */
1728 : : static struct mlx5_flow *
1729 : 0 : flow_verbs_prepare(struct rte_eth_dev *dev,
1730 : : const struct rte_flow_attr *attr __rte_unused,
1731 : : const struct rte_flow_item items[],
1732 : : const struct rte_flow_action actions[],
1733 : : struct rte_flow_error *error)
1734 : : {
1735 : : size_t size = 0;
1736 : 0 : uint32_t handle_idx = 0;
1737 : : struct mlx5_flow *dev_flow;
1738 : : struct mlx5_flow_handle *dev_handle;
1739 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1740 : 0 : struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
1741 : :
1742 : : MLX5_ASSERT(wks);
1743 : 0 : size += flow_verbs_get_actions_size(actions);
1744 : 0 : size += flow_verbs_get_items_size(items);
1745 [ # # ]: 0 : if (size > MLX5_VERBS_MAX_SPEC_ACT_SIZE) {
1746 : 0 : rte_flow_error_set(error, E2BIG,
1747 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1748 : : "Verbs spec/action size too large");
1749 : 0 : return NULL;
1750 : : }
1751 : : /* In case of corrupting the memory. */
1752 [ # # ]: 0 : if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
1753 : 0 : rte_flow_error_set(error, ENOSPC,
1754 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1755 : : "not free temporary device flow");
1756 : 0 : return NULL;
1757 : : }
1758 : 0 : dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
1759 : : &handle_idx);
1760 [ # # ]: 0 : if (!dev_handle) {
1761 : 0 : rte_flow_error_set(error, ENOMEM,
1762 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1763 : : "not enough memory to create flow handle");
1764 : 0 : return NULL;
1765 : : }
1766 : : MLX5_ASSERT(wks->flow_idx + 1 < RTE_DIM(wks->flows));
1767 : 0 : dev_flow = &wks->flows[wks->flow_idx++];
1768 : 0 : dev_flow->handle = dev_handle;
1769 : 0 : dev_flow->handle_idx = handle_idx;
1770 : : /* Memcpy is used, only size needs to be cleared to 0. */
1771 : 0 : dev_flow->verbs.size = 0;
1772 : 0 : dev_flow->verbs.attr.num_of_specs = 0;
1773 : 0 : dev_flow->ingress = attr->ingress;
1774 : 0 : dev_flow->hash_fields = 0;
1775 : : /* Need to set transfer attribute: not supported in Verbs mode. */
1776 : 0 : return dev_flow;
1777 : : }
1778 : :
1779 : : /**
1780 : : * Fill the flow with verb spec.
1781 : : *
1782 : : * @param[in] dev
1783 : : * Pointer to Ethernet device.
1784 : : * @param[in, out] dev_flow
1785 : : * Pointer to the mlx5 flow.
1786 : : * @param[in] attr
1787 : : * Pointer to the flow attributes.
1788 : : * @param[in] items
1789 : : * Pointer to the list of items.
1790 : : * @param[in] actions
1791 : : * Pointer to the list of actions.
1792 : : * @param[out] error
1793 : : * Pointer to the error structure.
1794 : : *
1795 : : * @return
1796 : : * 0 on success, else a negative errno value otherwise and rte_errno is set.
1797 : : */
1798 : : static int
1799 : 0 : flow_verbs_translate(struct rte_eth_dev *dev,
1800 : : struct mlx5_flow *dev_flow,
1801 : : const struct rte_flow_attr *attr,
1802 : : const struct rte_flow_item items[],
1803 : : const struct rte_flow_action actions[],
1804 : : struct rte_flow_error *error)
1805 : : {
1806 : : uint64_t item_flags = 0;
1807 : : uint64_t action_flags = 0;
1808 : 0 : uint64_t priority = attr->priority;
1809 : : uint32_t subpriority = 0;
1810 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1811 : 0 : struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
1812 : : struct mlx5_flow_rss_desc *rss_desc;
1813 : : const struct rte_flow_item *tunnel_item = NULL;
1814 : : uint8_t *gre_spec = NULL;
1815 : :
1816 : : MLX5_ASSERT(wks);
1817 : 0 : rss_desc = &wks->rss_desc;
1818 [ # # ]: 0 : if (priority == MLX5_FLOW_LOWEST_PRIO_INDICATOR)
1819 : 0 : priority = priv->sh->flow_max_priority - 1;
1820 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1821 : : int ret;
1822 : :
1823 [ # # # # : 0 : switch (actions->type) {
# # # # ]
1824 : : case RTE_FLOW_ACTION_TYPE_VOID:
1825 : : break;
1826 : : case RTE_FLOW_ACTION_TYPE_FLAG:
1827 : : flow_verbs_translate_action_flag(dev_flow, actions);
1828 : 0 : action_flags |= MLX5_FLOW_ACTION_FLAG;
1829 : 0 : wks->mark = 1;
1830 : 0 : break;
1831 : 0 : case RTE_FLOW_ACTION_TYPE_MARK:
1832 : 0 : flow_verbs_translate_action_mark(dev_flow, actions);
1833 : 0 : action_flags |= MLX5_FLOW_ACTION_MARK;
1834 : 0 : wks->mark = 1;
1835 : 0 : break;
1836 : : case RTE_FLOW_ACTION_TYPE_DROP:
1837 : : flow_verbs_translate_action_drop(dev_flow, actions);
1838 : 0 : action_flags |= MLX5_FLOW_ACTION_DROP;
1839 : 0 : dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
1840 : 0 : break;
1841 : : case RTE_FLOW_ACTION_TYPE_QUEUE:
1842 : : flow_verbs_translate_action_queue(rss_desc, actions);
1843 : 0 : action_flags |= MLX5_FLOW_ACTION_QUEUE;
1844 : 0 : dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
1845 : 0 : break;
1846 : 0 : case RTE_FLOW_ACTION_TYPE_RSS:
1847 : 0 : flow_verbs_translate_action_rss(rss_desc, actions);
1848 : 0 : action_flags |= MLX5_FLOW_ACTION_RSS;
1849 : 0 : dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
1850 : 0 : break;
1851 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
1852 : 0 : ret = flow_verbs_translate_action_count(dev_flow,
1853 : : actions,
1854 : : dev, error);
1855 [ # # ]: 0 : if (ret < 0)
1856 : 0 : return ret;
1857 : 0 : action_flags |= MLX5_FLOW_ACTION_COUNT;
1858 : 0 : break;
1859 : 0 : default:
1860 : 0 : return rte_flow_error_set(error, ENOTSUP,
1861 : : RTE_FLOW_ERROR_TYPE_ACTION,
1862 : : actions,
1863 : : "action not supported");
1864 : : }
1865 : : }
1866 : 0 : dev_flow->act_flags = action_flags;
1867 [ # # ]: 0 : for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1868 : 0 : int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
1869 : :
1870 [ # # # # : 0 : switch (items->type) {
# # # # #
# # # # ]
1871 : : case RTE_FLOW_ITEM_TYPE_VOID:
1872 : : break;
1873 : 0 : case RTE_FLOW_ITEM_TYPE_ETH:
1874 : 0 : flow_verbs_translate_item_eth(dev_flow, items,
1875 : : item_flags);
1876 : : subpriority = MLX5_PRIORITY_MAP_L2;
1877 [ # # ]: 0 : item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
1878 : : MLX5_FLOW_LAYER_OUTER_L2;
1879 : 0 : break;
1880 : 0 : case RTE_FLOW_ITEM_TYPE_VLAN:
1881 : 0 : flow_verbs_translate_item_vlan(dev_flow, items,
1882 : : item_flags);
1883 : : subpriority = MLX5_PRIORITY_MAP_L2;
1884 : 0 : item_flags |= tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
1885 [ # # ]: 0 : MLX5_FLOW_LAYER_INNER_VLAN) :
1886 : : (MLX5_FLOW_LAYER_OUTER_L2 |
1887 : : MLX5_FLOW_LAYER_OUTER_VLAN);
1888 : 0 : break;
1889 : 0 : case RTE_FLOW_ITEM_TYPE_IPV4:
1890 : 0 : flow_verbs_translate_item_ipv4(dev_flow, items,
1891 : : item_flags);
1892 : : subpriority = MLX5_PRIORITY_MAP_L3;
1893 : 0 : dev_flow->hash_fields |=
1894 : 0 : mlx5_flow_hashfields_adjust
1895 : : (rss_desc, tunnel,
1896 : : MLX5_IPV4_LAYER_TYPES,
1897 : : MLX5_IPV4_IBV_RX_HASH);
1898 [ # # ]: 0 : item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
1899 : : MLX5_FLOW_LAYER_OUTER_L3_IPV4;
1900 : 0 : break;
1901 : 0 : case RTE_FLOW_ITEM_TYPE_IPV6:
1902 : 0 : flow_verbs_translate_item_ipv6(dev_flow, items,
1903 : : item_flags);
1904 : : subpriority = MLX5_PRIORITY_MAP_L3;
1905 : 0 : dev_flow->hash_fields |=
1906 : 0 : mlx5_flow_hashfields_adjust
1907 : : (rss_desc, tunnel,
1908 : : MLX5_IPV6_LAYER_TYPES,
1909 : : MLX5_IPV6_IBV_RX_HASH);
1910 [ # # ]: 0 : item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
1911 : : MLX5_FLOW_LAYER_OUTER_L3_IPV6;
1912 : 0 : break;
1913 : 0 : case RTE_FLOW_ITEM_TYPE_TCP:
1914 : 0 : flow_verbs_translate_item_tcp(dev_flow, items,
1915 : : item_flags);
1916 : : subpriority = MLX5_PRIORITY_MAP_L4;
1917 [ # # ]: 0 : if (dev_flow->hash_fields != 0)
1918 : 0 : dev_flow->hash_fields |=
1919 : 0 : mlx5_flow_hashfields_adjust
1920 : : (rss_desc, tunnel, RTE_ETH_RSS_TCP,
1921 : : (IBV_RX_HASH_SRC_PORT_TCP |
1922 : : IBV_RX_HASH_DST_PORT_TCP));
1923 [ # # ]: 0 : item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
1924 : : MLX5_FLOW_LAYER_OUTER_L4_TCP;
1925 : 0 : break;
1926 : 0 : case RTE_FLOW_ITEM_TYPE_UDP:
1927 : 0 : flow_verbs_translate_item_udp(dev_flow, items,
1928 : : item_flags);
1929 : : subpriority = MLX5_PRIORITY_MAP_L4;
1930 [ # # ]: 0 : if (dev_flow->hash_fields != 0)
1931 : 0 : dev_flow->hash_fields |=
1932 : 0 : mlx5_flow_hashfields_adjust
1933 : : (rss_desc, tunnel, RTE_ETH_RSS_UDP,
1934 : : (IBV_RX_HASH_SRC_PORT_UDP |
1935 : : IBV_RX_HASH_DST_PORT_UDP));
1936 [ # # ]: 0 : item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
1937 : : MLX5_FLOW_LAYER_OUTER_L4_UDP;
1938 : 0 : break;
1939 : : #ifdef HAVE_IBV_FLOW_SPEC_ESP
1940 : 0 : case RTE_FLOW_ITEM_TYPE_ESP:
1941 : 0 : flow_verbs_translate_item_esp(dev_flow, items,
1942 : : item_flags);
1943 : 0 : dev_flow->hash_fields |=
1944 : 0 : mlx5_flow_hashfields_adjust
1945 : : (rss_desc, tunnel,
1946 : : RTE_ETH_RSS_ESP,
1947 : : IBV_RX_HASH_IPSEC_SPI);
1948 : 0 : item_flags |= MLX5_FLOW_ITEM_ESP;
1949 : 0 : break;
1950 : : #endif
1951 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN:
1952 : 0 : flow_verbs_translate_item_vxlan(dev_flow, items,
1953 : : item_flags);
1954 [ # # ]: 0 : subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
1955 : 0 : item_flags |= MLX5_FLOW_LAYER_VXLAN;
1956 : 0 : break;
1957 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1958 : 0 : flow_verbs_translate_item_vxlan_gpe(dev_flow, items,
1959 : : item_flags);
1960 [ # # ]: 0 : subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
1961 : 0 : item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;
1962 : 0 : break;
1963 : : case RTE_FLOW_ITEM_TYPE_GRE:
1964 : : gre_spec = flow_verbs_reserve_gre(dev_flow);
1965 [ # # ]: 0 : subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
1966 : 0 : item_flags |= MLX5_FLOW_LAYER_GRE;
1967 : : tunnel_item = items;
1968 : 0 : break;
1969 : 0 : case RTE_FLOW_ITEM_TYPE_MPLS:
1970 : 0 : flow_verbs_translate_item_mpls(dev_flow, items,
1971 : : item_flags);
1972 [ # # ]: 0 : subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
1973 : 0 : item_flags |= MLX5_FLOW_LAYER_MPLS;
1974 : 0 : break;
1975 : 0 : default:
1976 : 0 : return rte_flow_error_set(error, ENOTSUP,
1977 : : RTE_FLOW_ERROR_TYPE_ITEM,
1978 : : NULL, "item not supported");
1979 : : }
1980 : : }
1981 [ # # ]: 0 : if (item_flags & MLX5_FLOW_LAYER_GRE)
1982 : 0 : flow_verbs_translate_item_gre(dev_flow, gre_spec,
1983 : : tunnel_item, item_flags);
1984 : 0 : dev_flow->handle->layers = item_flags;
1985 : : /* Other members of attr will be ignored. */
1986 : 0 : dev_flow->verbs.attr.priority =
1987 : 0 : mlx5_flow_adjust_priority(dev, priority, subpriority);
1988 : 0 : dev_flow->verbs.attr.port = (uint8_t)priv->dev_port;
1989 : 0 : return 0;
1990 : : }
1991 : :
1992 : : /**
1993 : : * Remove the flow from the NIC but keeps it in memory.
1994 : : *
1995 : : * @param[in] dev
1996 : : * Pointer to the Ethernet device structure.
1997 : : * @param[in, out] flow
1998 : : * Pointer to flow structure.
1999 : : */
2000 : : static void
2001 : 0 : flow_verbs_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
2002 : : {
2003 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2004 : : struct mlx5_flow_handle *handle;
2005 : : uint32_t handle_idx;
2006 : :
2007 [ # # ]: 0 : if (!flow)
2008 : : return;
2009 [ # # # # : 0 : SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
# # ]
2010 : : handle_idx, handle, next) {
2011 [ # # ]: 0 : if (handle->drv_flow) {
2012 : 0 : claim_zero(mlx5_glue->destroy_flow(handle->drv_flow));
2013 : 0 : handle->drv_flow = NULL;
2014 : : }
2015 : : /* hrxq is union, don't touch it only the flag is set. */
2016 [ # # ]: 0 : if (handle->rix_hrxq &&
2017 [ # # ]: 0 : handle->fate_action == MLX5_FLOW_FATE_QUEUE) {
2018 : 0 : mlx5_hrxq_release(dev, handle->rix_hrxq);
2019 : 0 : handle->rix_hrxq = 0;
2020 : : }
2021 [ # # # # ]: 0 : if (handle->vf_vlan.tag && handle->vf_vlan.created)
2022 : 0 : mlx5_vlan_vmwa_release(dev, &handle->vf_vlan);
2023 : : }
2024 : : }
2025 : :
2026 : : /**
2027 : : * Remove the flow from the NIC and the memory.
2028 : : *
2029 : : * @param[in] dev
2030 : : * Pointer to the Ethernet device structure.
2031 : : * @param[in, out] flow
2032 : : * Pointer to flow structure.
2033 : : */
2034 : : static void
2035 : 0 : flow_verbs_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
2036 : : {
2037 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2038 : : struct mlx5_flow_handle *handle;
2039 : :
2040 [ # # ]: 0 : if (!flow)
2041 : : return;
2042 : 0 : flow_verbs_remove(dev, flow);
2043 [ # # ]: 0 : while (flow->dev_handles) {
2044 : : uint32_t tmp_idx = flow->dev_handles;
2045 : :
2046 : 0 : handle = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
2047 : : tmp_idx);
2048 [ # # ]: 0 : if (!handle)
2049 : : return;
2050 : 0 : flow->dev_handles = handle->next.next;
2051 : 0 : mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
2052 : : tmp_idx);
2053 : : }
2054 [ # # ]: 0 : if (flow->counter) {
2055 : 0 : flow_verbs_counter_release(dev, flow->counter);
2056 : 0 : flow->counter = 0;
2057 : : }
2058 : : }
2059 : :
2060 : : /**
2061 : : * Apply the flow to the NIC.
2062 : : *
2063 : : * @param[in] dev
2064 : : * Pointer to the Ethernet device structure.
2065 : : * @param[in, out] flow
2066 : : * Pointer to flow structure.
2067 : : * @param[out] error
2068 : : * Pointer to error structure.
2069 : : *
2070 : : * @return
2071 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
2072 : : */
2073 : : static int
2074 : 0 : flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
2075 : : struct rte_flow_error *error)
2076 : : {
2077 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2078 : : struct mlx5_flow_handle *handle;
2079 : : struct mlx5_flow *dev_flow;
2080 : : struct mlx5_hrxq *hrxq;
2081 : : uint32_t dev_handles;
2082 : : int err;
2083 : : int idx;
2084 : 0 : struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
2085 : :
2086 : : MLX5_ASSERT(wks);
2087 [ # # ]: 0 : for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
2088 : : dev_flow = &wks->flows[idx];
2089 : 0 : handle = dev_flow->handle;
2090 [ # # ]: 0 : if (handle->fate_action == MLX5_FLOW_FATE_DROP) {
2091 : : MLX5_ASSERT(priv->drop_queue.hrxq);
2092 : 0 : hrxq = priv->drop_queue.hrxq;
2093 : : } else {
2094 : 0 : struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
2095 : :
2096 : : MLX5_ASSERT(rss_desc->queue_num);
2097 : 0 : rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
2098 : 0 : rss_desc->hash_fields = dev_flow->hash_fields;
2099 : 0 : rss_desc->tunnel = !!(handle->layers &
2100 : : MLX5_FLOW_LAYER_TUNNEL);
2101 : 0 : rss_desc->shared_rss = 0;
2102 : 0 : hrxq = mlx5_hrxq_get(dev, rss_desc);
2103 [ # # ]: 0 : if (!hrxq) {
2104 : 0 : rte_flow_error_set
2105 : : (error, rte_errno,
2106 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2107 : : "cannot get hash queue");
2108 : 0 : goto error;
2109 : : }
2110 : 0 : handle->rix_hrxq = hrxq->idx;
2111 : : }
2112 : : MLX5_ASSERT(hrxq);
2113 : 0 : handle->drv_flow = mlx5_glue->create_flow
2114 : 0 : (hrxq->qp, &dev_flow->verbs.attr);
2115 [ # # ]: 0 : if (!handle->drv_flow) {
2116 : 0 : rte_flow_error_set(error, errno,
2117 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2118 : : NULL,
2119 : : "hardware refuses to create flow");
2120 : 0 : goto error;
2121 : : }
2122 [ # # ]: 0 : if (priv->vmwa_context &&
2123 [ # # # # ]: 0 : handle->vf_vlan.tag && !handle->vf_vlan.created) {
2124 : : /*
2125 : : * The rule contains the VLAN pattern.
2126 : : * For VF we are going to create VLAN
2127 : : * interface to make hypervisor set correct
2128 : : * e-Switch vport context.
2129 : : */
2130 : 0 : mlx5_vlan_vmwa_acquire(dev, &handle->vf_vlan);
2131 : : }
2132 : : }
2133 : : return 0;
2134 : 0 : error:
2135 : 0 : err = rte_errno; /* Save rte_errno before cleanup. */
2136 [ # # # # : 0 : SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
# # ]
2137 : : dev_handles, handle, next) {
2138 : : /* hrxq is union, don't touch it only the flag is set. */
2139 [ # # ]: 0 : if (handle->rix_hrxq &&
2140 [ # # ]: 0 : handle->fate_action == MLX5_FLOW_FATE_QUEUE) {
2141 : 0 : mlx5_hrxq_release(dev, handle->rix_hrxq);
2142 : 0 : handle->rix_hrxq = 0;
2143 : : }
2144 [ # # # # ]: 0 : if (handle->vf_vlan.tag && handle->vf_vlan.created)
2145 : 0 : mlx5_vlan_vmwa_release(dev, &handle->vf_vlan);
2146 : : }
2147 : 0 : rte_errno = err; /* Restore rte_errno. */
2148 : 0 : return -rte_errno;
2149 : : }
2150 : :
2151 : : /**
2152 : : * Query a flow.
2153 : : *
2154 : : * @see rte_flow_query()
2155 : : * @see rte_flow_ops
2156 : : */
2157 : : static int
2158 : 0 : flow_verbs_query(struct rte_eth_dev *dev,
2159 : : struct rte_flow *flow,
2160 : : const struct rte_flow_action *actions,
2161 : : void *data,
2162 : : struct rte_flow_error *error)
2163 : : {
2164 : : int ret = -EINVAL;
2165 : :
2166 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
2167 [ # # # ]: 0 : switch (actions->type) {
2168 : : case RTE_FLOW_ACTION_TYPE_VOID:
2169 : : break;
2170 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
2171 : 0 : ret = flow_verbs_counter_query(dev, flow, data, error);
2172 : 0 : break;
2173 : 0 : default:
2174 : 0 : return rte_flow_error_set(error, ENOTSUP,
2175 : : RTE_FLOW_ERROR_TYPE_ACTION,
2176 : : actions,
2177 : : "action not supported");
2178 : : }
2179 : : }
2180 : : return ret;
2181 : : }
2182 : :
2183 : : static int
2184 : 0 : flow_verbs_sync_domain(struct rte_eth_dev *dev, uint32_t domains,
2185 : : uint32_t flags)
2186 : : {
2187 : : RTE_SET_USED(dev);
2188 : : RTE_SET_USED(domains);
2189 : : RTE_SET_USED(flags);
2190 : :
2191 : 0 : return 0;
2192 : : }
2193 : :
2194 : : const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops = {
2195 : : .list_create = mlx5_flow_legacy_list_create,
2196 : : .list_destroy = mlx5_flow_legacy_list_destroy,
2197 : : .validate = flow_verbs_validate,
2198 : : .prepare = flow_verbs_prepare,
2199 : : .translate = flow_verbs_translate,
2200 : : .apply = flow_verbs_apply,
2201 : : .remove = flow_verbs_remove,
2202 : : .destroy = flow_verbs_destroy,
2203 : : .query = flow_verbs_query,
2204 : : .sync_domain = flow_verbs_sync_domain,
2205 : : .discover_priorities = flow_verbs_discover_priorities,
2206 : : .get_aged_flows = mlx5_flow_null_get_aged_flows,
2207 : : .counter_alloc = mlx5_flow_null_counter_allocate,
2208 : : .counter_free = mlx5_flow_null_counter_free,
2209 : : .counter_query = mlx5_flow_null_counter_query,
2210 : : };
|