Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2024 NVIDIA Corporation & Affiliates
3 : : */
4 : :
5 : : #include <rte_flow.h>
6 : :
7 : : #include <mlx5_malloc.h>
8 : : #include "mlx5.h"
9 : : #include "mlx5_defs.h"
10 : : #include "mlx5_flow.h"
11 : : #include "mlx5_rx.h"
12 : : #include "rte_common.h"
13 : :
14 : : #ifdef HAVE_MLX5_HWS_SUPPORT
15 : :
16 : : struct mlx5_nta_rss_ctx {
17 : : struct rte_eth_dev *dev;
18 : : struct rte_flow_attr *attr;
19 : : struct rte_flow_item *pattern;
20 : : struct rte_flow_action *actions;
21 : : const struct rte_flow_action_rss *rss_conf;
22 : : struct rte_flow_error *error;
23 : : struct mlx5_nta_rss_flow_head *head;
24 : : uint64_t pattern_flags;
25 : : enum mlx5_flow_type flow_type;
26 : : bool external;
27 : : };
28 : :
29 : : #define MLX5_RSS_PTYPE_ITEM_INDEX 0
30 : : #ifdef MLX5_RSS_PTYPE_DEBUG
31 : : #define MLX5_RSS_PTYPE_ACTION_INDEX 1
32 : : #else
33 : : #define MLX5_RSS_PTYPE_ACTION_INDEX 0
34 : : #endif
35 : :
36 : : #define MLX5_RSS_PTYPE_ITEMS_NUM (MLX5_RSS_PTYPE_ITEM_INDEX + 2)
37 : : #define MLX5_RSS_PTYPE_ACTIONS_NUM (MLX5_RSS_PTYPE_ACTION_INDEX + 2)
38 : :
39 : : static int
40 : 0 : mlx5_nta_ptype_rss_flow_create(struct mlx5_nta_rss_ctx *ctx,
41 : : uint32_t ptype, uint64_t rss_type)
42 : : {
43 : : int ret;
44 : : struct rte_flow_hw *flow;
45 : 0 : struct rte_flow_item_ptype *ptype_spec = (void *)(uintptr_t)
46 : 0 : ctx->pattern[MLX5_RSS_PTYPE_ITEM_INDEX].spec;
47 : 0 : struct rte_flow_action_rss *rss_conf = (void *)(uintptr_t)
48 : 0 : ctx->actions[MLX5_RSS_PTYPE_ACTION_INDEX].conf;
49 : 0 : bool dbg_log = rte_log_can_log(mlx5_logtype, RTE_LOG_DEBUG);
50 : : uint32_t mark_id = 0;
51 : : #ifdef MLX5_RSS_PTYPE_DEBUG
52 : : struct rte_flow_action_mark *mark = (void *)(uintptr_t)
53 : : ctx->actions[MLX5_RSS_PTYPE_ACTION_INDEX - 1].conf;
54 : :
55 : : /*
56 : : * Inner L3 and L4 ptype values are too large for 24bit mark
57 : : */
58 : : mark->id =
59 : : ((ptype & (RTE_PTYPE_INNER_L3_MASK | RTE_PTYPE_INNER_L4_MASK)) == ptype) ?
60 : : ptype >> 20 : ptype;
61 : : mark_id = mark->id;
62 : : dbg_log = true;
63 : : #endif
64 : 0 : ptype_spec->packet_type = ptype;
65 : 0 : rss_conf->types = rss_type;
66 : 0 : ret = flow_hw_create_flow(ctx->dev, MLX5_FLOW_TYPE_GEN, ctx->attr,
67 : 0 : ctx->pattern, ctx->actions,
68 : : MLX5_FLOW_ITEM_PTYPE, MLX5_FLOW_ACTION_RSS,
69 : 0 : ctx->external, &flow, ctx->error);
70 [ # # ]: 0 : if (flow) {
71 : 0 : SLIST_INSERT_HEAD(ctx->head, flow, nt2hws->next);
72 [ # # ]: 0 : if (dbg_log) {
73 : 0 : DRV_LOG(NOTICE,
74 : : "PTYPE RSS: group %u ptype spec %#x rss types %#lx mark %#x\n",
75 : : ctx->attr->group, ptype_spec->packet_type,
76 : : (unsigned long)rss_conf->types, mark_id);
77 : : }
78 : : }
79 : 0 : return ret;
80 : : }
81 : :
82 : : /*
83 : : * Call conditions:
84 : : * * Flow pattern did not include outer L3 and L4 items.
85 : : * * RSS configuration had L3 hash types.
86 : : */
87 : : static struct rte_flow_hw *
88 : 0 : mlx5_hw_rss_expand_l3(struct mlx5_nta_rss_ctx *rss_ctx)
89 : : {
90 : : int ret;
91 : : int ptype_ip4, ptype_ip6;
92 [ # # ]: 0 : uint64_t rss_types = rte_eth_rss_hf_refine(rss_ctx->rss_conf->types);
93 : :
94 [ # # ]: 0 : if (rss_ctx->rss_conf->level < 2) {
95 : : ptype_ip4 = RTE_PTYPE_L3_IPV4;
96 : : ptype_ip6 = RTE_PTYPE_L3_IPV6;
97 : : } else {
98 : : ptype_ip4 = RTE_PTYPE_INNER_L3_IPV4;
99 : : ptype_ip6 = RTE_PTYPE_INNER_L3_IPV6;
100 : : }
101 [ # # ]: 0 : if (rss_types & MLX5_IPV4_LAYER_TYPES) {
102 : 0 : ret = mlx5_nta_ptype_rss_flow_create
103 : : (rss_ctx, ptype_ip4, (rss_types & ~MLX5_IPV6_LAYER_TYPES));
104 [ # # ]: 0 : if (ret)
105 : 0 : goto error;
106 : : }
107 [ # # ]: 0 : if (rss_types & MLX5_IPV6_LAYER_TYPES) {
108 : 0 : ret = mlx5_nta_ptype_rss_flow_create
109 : : (rss_ctx, ptype_ip6, rss_types & ~MLX5_IPV4_LAYER_TYPES);
110 [ # # ]: 0 : if (ret)
111 : 0 : goto error;
112 : : }
113 : 0 : return SLIST_FIRST(rss_ctx->head);
114 : :
115 : 0 : error:
116 : 0 : flow_hw_list_destroy(rss_ctx->dev, rss_ctx->flow_type,
117 : 0 : (uintptr_t)SLIST_FIRST(rss_ctx->head));
118 : 0 : return NULL;
119 : : }
120 : :
121 : : static void
122 : 0 : mlx5_nta_rss_expand_l3_l4(struct mlx5_nta_rss_ctx *rss_ctx,
123 : : uint64_t rss_types, uint64_t rss_l3_types)
124 : : {
125 : : int ret;
126 : : int ptype_l3, ptype_l4_esp, ptype_l4_udp, ptype_l4_tcp;
127 : 0 : uint64_t rss = rss_types &
128 [ # # ]: 0 : ~(rss_l3_types == MLX5_IPV4_LAYER_TYPES ?
129 : : MLX5_IPV6_LAYER_TYPES : MLX5_IPV4_LAYER_TYPES);
130 : :
131 : :
132 [ # # ]: 0 : if (rss_ctx->rss_conf->level < 2) {
133 : : ptype_l3 = rss_l3_types == MLX5_IPV4_LAYER_TYPES ?
134 [ # # ]: 0 : RTE_PTYPE_L3_IPV4 : RTE_PTYPE_L3_IPV6;
135 : : ptype_l4_esp = RTE_PTYPE_L4_ESP;
136 : : ptype_l4_udp = RTE_PTYPE_L4_UDP;
137 : : ptype_l4_tcp = RTE_PTYPE_L4_TCP;
138 : : } else {
139 : : ptype_l3 = rss_l3_types == MLX5_IPV4_LAYER_TYPES ?
140 [ # # ]: 0 : RTE_PTYPE_INNER_L3_IPV4 : RTE_PTYPE_INNER_L3_IPV6;
141 : : ptype_l4_esp = RTE_PTYPE_INNER_L4_ESP;
142 : : ptype_l4_udp = RTE_PTYPE_INNER_L4_UDP;
143 : : ptype_l4_tcp = RTE_PTYPE_INNER_L4_TCP;
144 : : }
145 [ # # ]: 0 : if (rss_types & RTE_ETH_RSS_ESP) {
146 : 0 : ret = mlx5_nta_ptype_rss_flow_create
147 : 0 : (rss_ctx, ptype_l3 | ptype_l4_esp,
148 : : rss & ~(RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP));
149 [ # # ]: 0 : if (ret)
150 : 0 : goto error;
151 : : }
152 [ # # ]: 0 : if (rss_types & RTE_ETH_RSS_UDP) {
153 : 0 : ret = mlx5_nta_ptype_rss_flow_create(rss_ctx,
154 : 0 : ptype_l3 | ptype_l4_udp,
155 : : rss & ~(RTE_ETH_RSS_ESP | RTE_ETH_RSS_TCP));
156 [ # # ]: 0 : if (ret)
157 : 0 : goto error;
158 : : }
159 [ # # ]: 0 : if (rss_types & RTE_ETH_RSS_TCP) {
160 : 0 : ret = mlx5_nta_ptype_rss_flow_create(rss_ctx,
161 : 0 : ptype_l3 | ptype_l4_tcp,
162 : : rss & ~(RTE_ETH_RSS_ESP | RTE_ETH_RSS_UDP));
163 [ # # ]: 0 : if (ret)
164 : 0 : goto error;
165 : : }
166 : : return;
167 : 0 : error:
168 : 0 : flow_hw_list_destroy(rss_ctx->dev, rss_ctx->flow_type,
169 : 0 : (uintptr_t)SLIST_FIRST(rss_ctx->head));
170 : : }
171 : :
172 : : /*
173 : : * Call conditions:
174 : : * * Flow pattern did not include L4 item.
175 : : * * RSS configuration had L4 hash types.
176 : : */
177 : : static struct rte_flow_hw *
178 : 0 : mlx5_hw_rss_expand_l4(struct mlx5_nta_rss_ctx *rss_ctx)
179 : : {
180 [ # # ]: 0 : uint64_t rss_types = rte_eth_rss_hf_refine(rss_ctx->rss_conf->types);
181 : 0 : uint64_t l3_item = rss_ctx->pattern_flags &
182 : 0 : (rss_ctx->rss_conf->level < 2 ?
183 [ # # ]: 0 : MLX5_FLOW_LAYER_OUTER_L3 : MLX5_FLOW_LAYER_INNER_L3);
184 : :
185 [ # # ]: 0 : if (l3_item) {
186 : : /*
187 : : * Outer L3 header was present in the original pattern.
188 : : * Expand L4 level only.
189 : : */
190 [ # # ]: 0 : if (l3_item & MLX5_FLOW_LAYER_L3_IPV4)
191 : 0 : mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types, MLX5_IPV4_LAYER_TYPES);
192 : : else
193 : 0 : mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types, MLX5_IPV6_LAYER_TYPES);
194 : : } else {
195 [ # # ]: 0 : if (rss_types & (MLX5_IPV4_LAYER_TYPES | MLX5_IPV6_LAYER_TYPES)) {
196 : 0 : mlx5_hw_rss_expand_l3(rss_ctx);
197 : : /*
198 : : * No outer L3 item in application flow pattern.
199 : : * RSS hash types are L3 and L4.
200 : : * ** Expand L3 according to RSS configuration and L4.
201 : : */
202 [ # # ]: 0 : if (rss_types & MLX5_IPV4_LAYER_TYPES)
203 : 0 : mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types,
204 : : MLX5_IPV4_LAYER_TYPES);
205 [ # # ]: 0 : if (rss_types & MLX5_IPV6_LAYER_TYPES)
206 : 0 : mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types,
207 : : MLX5_IPV6_LAYER_TYPES);
208 : : } else {
209 : : /*
210 : : * No outer L3 item in application flow pattern,
211 : : * RSS hash type is L4 only.
212 : : */
213 : 0 : mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types,
214 : : MLX5_IPV4_LAYER_TYPES);
215 : 0 : mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types,
216 : : MLX5_IPV6_LAYER_TYPES);
217 : : }
218 : : }
219 : 0 : return SLIST_EMPTY(rss_ctx->head) ? NULL : SLIST_FIRST(rss_ctx->head);
220 : : }
221 : :
222 : : static struct mlx5_indexed_pool *
223 : 0 : mlx5_nta_ptype_ipool_create(struct rte_eth_dev *dev)
224 : : {
225 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
226 : 0 : struct mlx5_indexed_pool_config ipool_cfg = {
227 : : .size = 1,
228 : : .trunk_size = 32,
229 : : .grow_trunk = 5,
230 : : .grow_shift = 1,
231 : : .need_lock = 1,
232 : 0 : .release_mem_en = !!priv->sh->config.reclaim_mode,
233 : : .malloc = mlx5_malloc,
234 : : .max_idx = MLX5_FLOW_TABLE_PTYPE_RSS_NUM,
235 : : .free = mlx5_free,
236 : : .type = "mlx5_nta_ptype_rss"
237 : : };
238 : 0 : return mlx5_ipool_create(&ipool_cfg);
239 : : }
240 : :
241 : : static void
242 : : mlx5_hw_release_rss_ptype_group(struct rte_eth_dev *dev, uint32_t group)
243 : : {
244 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
245 : :
246 : 0 : if (!priv->ptype_rss_groups)
247 : : return;
248 : 0 : mlx5_ipool_free(priv->ptype_rss_groups, group);
249 : : }
250 : :
251 : : static uint32_t
252 : 0 : mlx5_hw_get_rss_ptype_group(struct rte_eth_dev *dev)
253 : : {
254 : : void *obj;
255 : 0 : uint32_t idx = 0;
256 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
257 : :
258 [ # # ]: 0 : if (!priv->ptype_rss_groups) {
259 : 0 : priv->ptype_rss_groups = mlx5_nta_ptype_ipool_create(dev);
260 [ # # ]: 0 : if (!priv->ptype_rss_groups) {
261 : 0 : DRV_LOG(DEBUG, "PTYPE RSS: failed to allocate groups pool");
262 : 0 : return 0;
263 : : }
264 : : }
265 : 0 : obj = mlx5_ipool_malloc(priv->ptype_rss_groups, &idx);
266 [ # # ]: 0 : if (!obj) {
267 : 0 : DRV_LOG(DEBUG, "PTYPE RSS: failed to fetch ptype group from the pool");
268 : 0 : return 0;
269 : : }
270 : 0 : return idx + MLX5_FLOW_TABLE_PTYPE_RSS_BASE;
271 : : }
272 : :
273 : : static struct rte_flow_hw *
274 : 0 : mlx5_hw_rss_ptype_create_miss_flow(struct rte_eth_dev *dev,
275 : : const struct rte_flow_action_rss *rss_conf,
276 : : uint32_t ptype_group, bool external,
277 : : struct rte_flow_error *error)
278 : : {
279 : 0 : struct rte_flow_hw *flow = NULL;
280 : 0 : const struct rte_flow_attr miss_attr = {
281 : : .ingress = 1,
282 : : .group = ptype_group,
283 : : .priority = 3
284 : : };
285 : 0 : const struct rte_flow_item miss_pattern[2] = {
286 : : [0] = { .type = RTE_FLOW_ITEM_TYPE_ETH },
287 : : [1] = { .type = RTE_FLOW_ITEM_TYPE_END }
288 : : };
289 : 0 : struct rte_flow_action miss_actions[] = {
290 : : #ifdef MLX5_RSS_PTYPE_DEBUG
291 : : [MLX5_RSS_PTYPE_ACTION_INDEX - 1] = {
292 : : .type = RTE_FLOW_ACTION_TYPE_MARK,
293 : : .conf = &(const struct rte_flow_action_mark){.id = 0xfac}
294 : : },
295 : : #endif
296 : : [MLX5_RSS_PTYPE_ACTION_INDEX] = {
297 : : .type = RTE_FLOW_ACTION_TYPE_RSS,
298 : : .conf = rss_conf
299 : : },
300 : : [MLX5_RSS_PTYPE_ACTION_INDEX + 1] = { .type = RTE_FLOW_ACTION_TYPE_END }
301 : : };
302 : :
303 : 0 : flow_hw_create_flow(dev, MLX5_FLOW_TYPE_GEN, &miss_attr,
304 : : miss_pattern, miss_actions, 0, MLX5_FLOW_ACTION_RSS,
305 : : external, &flow, error);
306 : 0 : return flow;
307 : : }
308 : :
309 : : static struct rte_flow_hw *
310 : 0 : mlx5_hw_rss_ptype_create_base_flow(struct rte_eth_dev *dev,
311 : : const struct rte_flow_attr *attr,
312 : : const struct rte_flow_item pattern[],
313 : : const struct rte_flow_action orig_actions[],
314 : : uint32_t ptype_group, uint64_t item_flags,
315 : : uint64_t action_flags, bool external,
316 : : enum mlx5_flow_type flow_type,
317 : : struct rte_flow_error *error)
318 : : {
319 : : int i = 0;
320 : 0 : struct rte_flow_hw *flow = NULL;
321 : : struct rte_flow_action actions[MLX5_HW_MAX_ACTS];
322 : : enum mlx5_indirect_type indirect_type;
323 : :
324 : : do {
325 [ # # # ]: 0 : switch (orig_actions[i].type) {
326 : 0 : case RTE_FLOW_ACTION_TYPE_INDIRECT:
327 : 0 : indirect_type = (typeof(indirect_type))
328 : 0 : MLX5_INDIRECT_ACTION_TYPE_GET
329 : : (orig_actions[i].conf);
330 [ # # ]: 0 : if (indirect_type != MLX5_INDIRECT_ACTION_TYPE_RSS) {
331 : 0 : actions[i] = orig_actions[i];
332 : 0 : break;
333 : : }
334 : : /* Fall through */
335 : : case RTE_FLOW_ACTION_TYPE_RSS:
336 : 0 : actions[i].type = RTE_FLOW_ACTION_TYPE_JUMP;
337 : 0 : actions[i].conf = &(const struct rte_flow_action_jump) {
338 : : .group = ptype_group
339 : : };
340 : 0 : break;
341 : 0 : default:
342 : 0 : actions[i] = orig_actions[i];
343 : : }
344 : :
345 [ # # ]: 0 : } while (actions[i++].type != RTE_FLOW_ACTION_TYPE_END);
346 : 0 : action_flags &= ~MLX5_FLOW_ACTION_RSS;
347 : 0 : action_flags |= MLX5_FLOW_ACTION_JUMP;
348 : 0 : flow_hw_create_flow(dev, flow_type, attr, pattern, actions,
349 : : item_flags, action_flags, external, &flow, error);
350 : 0 : return flow;
351 : : }
352 : :
353 : : const struct rte_flow_action_rss *
354 : 0 : flow_nta_locate_rss(struct rte_eth_dev *dev,
355 : : const struct rte_flow_action actions[],
356 : : struct rte_flow_error *error)
357 : : {
358 : : const struct rte_flow_action *a;
359 : : const struct rte_flow_action_rss *rss_conf = NULL;
360 : :
361 [ # # ]: 0 : for (a = actions; a->type != RTE_FLOW_ACTION_TYPE_END; a++) {
362 [ # # ]: 0 : if (a->type == RTE_FLOW_ACTION_TYPE_RSS) {
363 : 0 : rss_conf = a->conf;
364 : 0 : break;
365 : : }
366 [ # # ]: 0 : if (a->type == RTE_FLOW_ACTION_TYPE_INDIRECT &&
367 [ # # ]: 0 : MLX5_INDIRECT_ACTION_TYPE_GET(a->conf) ==
368 : : MLX5_INDIRECT_ACTION_TYPE_RSS) {
369 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
370 : : struct mlx5_shared_action_rss *shared_rss;
371 : : uint32_t handle = (uint32_t)(uintptr_t)a->conf;
372 : :
373 : 0 : shared_rss = mlx5_ipool_get
374 : 0 : (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
375 : : MLX5_INDIRECT_ACTION_IDX_GET(handle));
376 [ # # ]: 0 : if (!shared_rss) {
377 : 0 : rte_flow_error_set(error, EINVAL,
378 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF,
379 : 0 : a->conf, "invalid shared RSS handle");
380 : 0 : return NULL;
381 : : }
382 : 0 : rss_conf = &shared_rss->origin;
383 : 0 : break;
384 : : }
385 : : }
386 [ # # ]: 0 : if (a->type == RTE_FLOW_ACTION_TYPE_END) {
387 : 0 : rte_flow_error_set(error, 0, RTE_FLOW_ERROR_TYPE_NONE, NULL, NULL);
388 : 0 : return NULL;
389 : : }
390 : : return rss_conf;
391 : : }
392 : :
393 : : static __rte_always_inline void
394 : : mlx5_nta_rss_init_ptype_ctx(struct mlx5_nta_rss_ctx *rss_ctx,
395 : : struct rte_eth_dev *dev,
396 : : struct rte_flow_attr *ptype_attr,
397 : : struct rte_flow_item *ptype_pattern,
398 : : struct rte_flow_action *ptype_actions,
399 : : const struct rte_flow_action_rss *rss_conf,
400 : : struct mlx5_nta_rss_flow_head *head,
401 : : struct rte_flow_error *error,
402 : : uint64_t item_flags,
403 : : enum mlx5_flow_type flow_type, bool external)
404 : : {
405 : 0 : rss_ctx->dev = dev;
406 : 0 : rss_ctx->attr = ptype_attr;
407 : 0 : rss_ctx->pattern = ptype_pattern;
408 : 0 : rss_ctx->actions = ptype_actions;
409 : 0 : rss_ctx->rss_conf = rss_conf;
410 : 0 : rss_ctx->error = error;
411 : 0 : rss_ctx->head = head;
412 : 0 : rss_ctx->pattern_flags = item_flags;
413 : 0 : rss_ctx->flow_type = flow_type;
414 : 0 : rss_ctx->external = external;
415 : : }
416 : :
417 : : static struct rte_flow_hw *
418 : 0 : flow_nta_create_single(struct rte_eth_dev *dev,
419 : : const struct rte_flow_attr *attr,
420 : : const struct rte_flow_item items[],
421 : : const struct rte_flow_action actions[],
422 : : struct rte_flow_action_rss *rss_conf,
423 : : int64_t item_flags, uint64_t action_flags,
424 : : bool external, bool copy_actions,
425 : : enum mlx5_flow_type flow_type,
426 : : struct rte_flow_error *error)
427 : : {
428 : 0 : struct rte_flow_hw *flow = NULL;
429 : : struct rte_flow_action copy[MLX5_HW_MAX_ACTS];
430 : : const struct rte_flow_action *_actions;
431 : :
432 [ # # ]: 0 : if (copy_actions) {
433 : : int i;
434 : :
435 : : _actions = copy;
436 : 0 : for (i = 0; ; i++) {
437 : 0 : copy[i] = actions[i];
438 [ # # # # ]: 0 : switch (actions[i].type) {
439 : 0 : case RTE_FLOW_ACTION_TYPE_RSS:
440 : 0 : copy[i].conf = rss_conf;
441 : 0 : break;
442 : 0 : case RTE_FLOW_ACTION_TYPE_INDIRECT:
443 [ # # ]: 0 : if (MLX5_INDIRECT_ACTION_TYPE_GET(actions[i].conf) ==
444 : : MLX5_INDIRECT_ACTION_TYPE_RSS) {
445 : 0 : copy[i].type = RTE_FLOW_ACTION_TYPE_RSS;
446 : 0 : copy[i].conf = rss_conf;
447 : : }
448 : : break;
449 : 0 : case RTE_FLOW_ACTION_TYPE_END:
450 : 0 : goto end;
451 : : default:
452 : : break;
453 : : }
454 : : }
455 : : } else {
456 : : _actions = actions;
457 : : }
458 : 0 : end:
459 : 0 : flow_hw_create_flow(dev, flow_type, attr, items,
460 : : _actions, item_flags, action_flags,
461 : : external, &flow, error);
462 : 0 : return flow;
463 : : }
464 : :
465 : : /*
466 : : * MLX5 HW hashes IPv4 and IPv6 L3 headers and UDP, TCP, ESP L4 headers.
467 : : * RSS expansion is required when RSS action was configured to hash
468 : : * network protocol that was not mentioned in flow pattern.
469 : : *
470 : : */
471 : : #define MLX5_PTYPE_RSS_OUTER_MASK (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6 | \
472 : : RTE_PTYPE_L4_UDP | RTE_PTYPE_L4_TCP | \
473 : : RTE_PTYPE_L4_ESP)
474 : : #define MLX5_PTYPE_RSS_INNER_MASK (RTE_PTYPE_INNER_L3_IPV4 | RTE_PTYPE_INNER_L3_IPV6 | \
475 : : RTE_PTYPE_INNER_L4_TCP | RTE_PTYPE_INNER_L4_UDP)
476 : :
477 : : struct rte_flow_hw *
478 : 0 : flow_nta_handle_rss(struct rte_eth_dev *dev,
479 : : const struct rte_flow_attr *attr,
480 : : const struct rte_flow_item items[],
481 : : const struct rte_flow_action actions[],
482 : : const struct rte_flow_action_rss *rss_conf,
483 : : uint64_t item_flags, uint64_t action_flags,
484 : : bool external, enum mlx5_flow_type flow_type,
485 : : struct rte_flow_error *error)
486 : : {
487 : : struct rte_flow_hw *rss_base = NULL, *rss_next = NULL, *rss_miss = NULL;
488 : 0 : struct rte_flow_action_rss ptype_rss_conf = *rss_conf;
489 : : struct mlx5_nta_rss_ctx rss_ctx;
490 [ # # ]: 0 : uint64_t rss_types = rte_eth_rss_hf_refine(rss_conf->types);
491 : : bool expand = true;
492 : : bool copy_actions = false;
493 : 0 : bool inner_rss = rss_conf->level > 1;
494 : : bool outer_rss = !inner_rss;
495 [ # # # # : 0 : bool l3_item = (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L3)) ||
# # ]
496 [ # # ]: 0 : (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L3));
497 [ # # # # : 0 : bool l4_item = (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L4)) ||
# # ]
498 [ # # ]: 0 : (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L4));
499 : 0 : bool l3_hash = rss_types & (MLX5_IPV4_LAYER_TYPES | MLX5_IPV6_LAYER_TYPES);
500 : 0 : bool l4_hash = rss_types & (RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_ESP);
501 : 0 : struct mlx5_nta_rss_flow_head expansion_head = SLIST_HEAD_INITIALIZER(0);
502 : 0 : struct rte_flow_attr ptype_attr = {
503 : : .ingress = 1
504 : : };
505 : 0 : struct rte_flow_item_ptype ptype_spec = { .packet_type = 0 };
506 : 0 : const struct rte_flow_item_ptype ptype_mask = {
507 : : .packet_type = outer_rss ?
508 [ # # ]: 0 : MLX5_PTYPE_RSS_OUTER_MASK : MLX5_PTYPE_RSS_INNER_MASK
509 : : };
510 : 0 : struct rte_flow_item ptype_pattern[MLX5_RSS_PTYPE_ITEMS_NUM] = {
511 : : [MLX5_RSS_PTYPE_ITEM_INDEX] = {
512 : : .type = RTE_FLOW_ITEM_TYPE_PTYPE,
513 : : .spec = &ptype_spec,
514 : : .mask = &ptype_mask
515 : : },
516 : : [MLX5_RSS_PTYPE_ITEM_INDEX + 1] = { .type = RTE_FLOW_ITEM_TYPE_END }
517 : : };
518 : 0 : struct rte_flow_action ptype_actions[MLX5_RSS_PTYPE_ACTIONS_NUM] = {
519 : : #ifdef MLX5_RSS_PTYPE_DEBUG
520 : : [MLX5_RSS_PTYPE_ACTION_INDEX - 1] = {
521 : : .type = RTE_FLOW_ACTION_TYPE_MARK,
522 : : .conf = &(const struct rte_flow_action_mark) {.id = 101}
523 : : },
524 : : #endif
525 : : [MLX5_RSS_PTYPE_ACTION_INDEX] = {
526 : : .type = RTE_FLOW_ACTION_TYPE_RSS,
527 : : .conf = &ptype_rss_conf
528 : : },
529 : : [MLX5_RSS_PTYPE_ACTION_INDEX + 1] = { .type = RTE_FLOW_ACTION_TYPE_END }
530 : : };
531 : :
532 : 0 : ptype_rss_conf.types = rss_types;
533 [ # # ]: 0 : if (l4_item) {
534 : : /*
535 : : * Original flow pattern extended up to L4 level.
536 : : * L4 is the maximal expansion level.
537 : : * Original pattern does not need expansion.
538 : : */
539 : : expand = false;
540 [ # # ]: 0 : } else if (!l4_hash) {
541 [ # # ]: 0 : if (!l3_hash) {
542 : : /*
543 : : * RSS action was not configured to hash L3 or L4.
544 : : * No expansion needed.
545 : : */
546 : : expand = false;
547 [ # # ]: 0 : } else if (l3_item) {
548 : : /*
549 : : * Original flow pattern extended up to L3 level.
550 : : * RSS action was not set for L4 hash.
551 : : */
552 : 0 : bool ip4_item =
553 [ # # # # : 0 : (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)) ||
# # ]
554 [ # # ]: 0 : (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4));
555 : 0 : bool ip6_item =
556 [ # # # # : 0 : (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)) ||
# # ]
557 [ # # ]: 0 : (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6));
558 : 0 : bool ip4_hash = rss_types & MLX5_IPV4_LAYER_TYPES;
559 : 0 : bool ip6_hash = rss_types & MLX5_IPV6_LAYER_TYPES;
560 : :
561 : : expand = false;
562 [ # # ]: 0 : if (ip4_item && ip4_hash) {
563 : 0 : ptype_rss_conf.types &= ~MLX5_IPV6_LAYER_TYPES;
564 : : copy_actions = true;
565 [ # # ]: 0 : } else if (ip6_item && ip6_hash) {
566 : : /*
567 : : * MLX5 HW will not activate TIR IPv6 hash
568 : : * if that TIR has also IPv4 hash
569 : : */
570 : 0 : ptype_rss_conf.types &= ~MLX5_IPV4_LAYER_TYPES;
571 : : copy_actions = true;
572 : : }
573 : : }
574 : : }
575 [ # # ]: 0 : if (!expand)
576 : 0 : return flow_nta_create_single(dev, attr, items, actions,
577 : : &ptype_rss_conf, item_flags,
578 : : action_flags, external,
579 : : copy_actions, flow_type, error);
580 : : /* Create RSS expansions in dedicated PTYPE flow group */
581 : 0 : ptype_attr.group = mlx5_hw_get_rss_ptype_group(dev);
582 [ # # ]: 0 : if (!ptype_attr.group) {
583 : 0 : rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
584 : : NULL, "cannot get RSS PTYPE group");
585 : 0 : return NULL;
586 : : }
587 : 0 : mlx5_nta_rss_init_ptype_ctx(&rss_ctx, dev, &ptype_attr, ptype_pattern,
588 : : ptype_actions, &ptype_rss_conf, &expansion_head,
589 : : error, item_flags, flow_type, external);
590 : 0 : rss_miss = mlx5_hw_rss_ptype_create_miss_flow(dev, &ptype_rss_conf, ptype_attr.group,
591 : : external, error);
592 [ # # ]: 0 : if (!rss_miss)
593 : 0 : goto error;
594 [ # # ]: 0 : if (l4_hash) {
595 : 0 : rss_next = mlx5_hw_rss_expand_l4(&rss_ctx);
596 [ # # ]: 0 : if (!rss_next)
597 : 0 : goto error;
598 [ # # ]: 0 : } else if (l3_hash) {
599 : 0 : rss_next = mlx5_hw_rss_expand_l3(&rss_ctx);
600 [ # # ]: 0 : if (!rss_next)
601 : 0 : goto error;
602 : : }
603 : 0 : rss_base = mlx5_hw_rss_ptype_create_base_flow(dev, attr, items, actions,
604 : : ptype_attr.group, item_flags,
605 : : action_flags, external,
606 : : flow_type, error);
607 [ # # ]: 0 : if (!rss_base)
608 : 0 : goto error;
609 : 0 : SLIST_INSERT_HEAD(&expansion_head, rss_miss, nt2hws->next);
610 : 0 : SLIST_INSERT_HEAD(&expansion_head, rss_base, nt2hws->next);
611 : : /**
612 : : * PMD must return to application a reference to the base flow.
613 : : * This way RSS expansion could work with counter, meter and other
614 : : * flow actions.
615 : : */
616 : : MLX5_ASSERT(rss_base == SLIST_FIRST(&expansion_head));
617 : : rss_next = SLIST_NEXT(rss_base, nt2hws->next);
618 [ # # ]: 0 : while (rss_next) {
619 : 0 : rss_next->nt2hws->chaned_flow = 1;
620 : 0 : rss_next = SLIST_NEXT(rss_next, nt2hws->next);
621 : : }
622 : : return SLIST_FIRST(&expansion_head);
623 : :
624 : 0 : error:
625 [ # # ]: 0 : if (rss_miss)
626 : 0 : flow_hw_list_destroy(dev, flow_type, (uintptr_t)rss_miss);
627 [ # # ]: 0 : if (rss_next)
628 : 0 : flow_hw_list_destroy(dev, flow_type, (uintptr_t)rss_next);
629 [ # # ]: 0 : mlx5_hw_release_rss_ptype_group(dev, ptype_attr.group);
630 : : return NULL;
631 : : }
632 : :
633 : : #endif
|