File Index
Files and directories
Sign in
FILE

port_sel.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. */
  3
  4#include <linux/netdevice.h>
  5#include "lag.h"
  6
  7enum {
  8	MLX5_LAG_FT_LEVEL_TTC,
  9	MLX5_LAG_FT_LEVEL_INNER_TTC,
 10	MLX5_LAG_FT_LEVEL_DEFINER,
 11};
 12
 13static struct mlx5_flow_group *
 14mlx5_create_hash_flow_group(struct mlx5_flow_table *ft,
 15			    struct mlx5_flow_definer *definer,
 16			    u8 rules)
 17{
 18	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
 19	struct mlx5_flow_group *fg;
 20	u32 *in;
 21
 22	in = kvzalloc(inlen, GFP_KERNEL);
 23	if (!in)
 24		return ERR_PTR(-ENOMEM);
 25
 26	MLX5_SET(create_flow_group_in, in, match_definer_id,
 27		 mlx5_get_match_definer_id(definer));
 28	MLX5_SET(create_flow_group_in, in, start_flow_index, 0);
 29	MLX5_SET(create_flow_group_in, in, end_flow_index, rules - 1);
 30	MLX5_SET(create_flow_group_in, in, group_type,
 31		 MLX5_CREATE_FLOW_GROUP_IN_GROUP_TYPE_HASH_SPLIT);
 32
 33	fg = mlx5_create_flow_group(ft, in);
 34	kvfree(in);
 35	return fg;
 36}
 37
 38static int mlx5_lag_create_port_sel_table(struct mlx5_lag *ldev,
 39					  struct mlx5_lag_definer *lag_definer,
 40					  u8 *ports)
 41{
 42	int first_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
 43	struct mlx5_flow_table_attr ft_attr = {};
 44	struct mlx5_flow_destination dest = {};
 45	MLX5_DECLARE_FLOW_ACT(flow_act);
 46	struct mlx5_flow_namespace *ns;
 47	struct mlx5_core_dev *dev;
 48	int err, i, j, k, idx;
 49
 50	if (first_idx < 0)
 51		return -EINVAL;
 52
 53	dev = ldev->pf[first_idx].dev;
 54	ft_attr.max_fte = ldev->ports * ldev->buckets;
 55	ft_attr.level = MLX5_LAG_FT_LEVEL_DEFINER;
 56
 57	ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_PORT_SEL);
 58	if (!ns) {
 59		mlx5_core_warn(dev, "Failed to get port selection namespace\n");
 60		return -EOPNOTSUPP;
 61	}
 62
 63	lag_definer->ft = mlx5_create_flow_table(ns, &ft_attr);
 64	if (IS_ERR(lag_definer->ft)) {
 65		mlx5_core_warn(dev, "Failed to create port selection table\n");
 66		return PTR_ERR(lag_definer->ft);
 67	}
 68
 69	lag_definer->fg = mlx5_create_hash_flow_group(lag_definer->ft,
 70						      lag_definer->definer,
 71						      ft_attr.max_fte);
 72	if (IS_ERR(lag_definer->fg)) {
 73		err = PTR_ERR(lag_definer->fg);
 74		goto destroy_ft;
 75	}
 76
 77	dest.type = MLX5_FLOW_DESTINATION_TYPE_UPLINK;
 78	dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
 79	flow_act.flags |= FLOW_ACT_NO_APPEND;
 80	mlx5_ldev_for_each(i, 0, ldev) {
 81		for (j = 0; j < ldev->buckets; j++) {
 82			u8 affinity;
 83
 84			idx = i * ldev->buckets + j;
 85			affinity = ports[idx];
 86
 87			dest.vport.vhca_id = MLX5_CAP_GEN(ldev->pf[affinity - 1].dev,
 88							  vhca_id);
 89			lag_definer->rules[idx] = mlx5_add_flow_rules(lag_definer->ft,
 90								      NULL, &flow_act,
 91								      &dest, 1);
 92			if (IS_ERR(lag_definer->rules[idx])) {
 93				err = PTR_ERR(lag_definer->rules[idx]);
 94				mlx5_ldev_for_each_reverse(k, i, 0, ldev) {
 95					while (j--) {
 96						idx = k * ldev->buckets + j;
 97						mlx5_del_flow_rules(lag_definer->rules[idx]);
 98					}
 99					j = ldev->buckets;
100				}
101				goto destroy_fg;
102			}
103		}
104	}
105
106	return 0;
107
108destroy_fg:
109	mlx5_destroy_flow_group(lag_definer->fg);
110destroy_ft:
111	mlx5_destroy_flow_table(lag_definer->ft);
112	return err;
113}
114
115static int mlx5_lag_set_definer_inner(u32 *match_definer_mask,
116				      enum mlx5_traffic_types tt)
117{
118	int format_id;
119	u8 *ipv6;
120
121	switch (tt) {
122	case MLX5_TT_IPV4_UDP:
123	case MLX5_TT_IPV4_TCP:
124		format_id = 23;
125		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
126				 inner_l4_sport);
127		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
128				 inner_l4_dport);
129		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
130				 inner_ip_src_addr);
131		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
132				 inner_ip_dest_addr);
133		break;
134	case MLX5_TT_IPV4:
135		format_id = 23;
136		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
137				 inner_l3_type);
138		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
139				 inner_dmac_47_16);
140		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
141				 inner_dmac_15_0);
142		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
143				 inner_smac_47_16);
144		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
145				 inner_smac_15_0);
146		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
147				 inner_ip_src_addr);
148		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
149				 inner_ip_dest_addr);
150		break;
151	case MLX5_TT_IPV6_TCP:
152	case MLX5_TT_IPV6_UDP:
153		format_id = 31;
154		MLX5_SET_TO_ONES(match_definer_format_31, match_definer_mask,
155				 inner_l4_sport);
156		MLX5_SET_TO_ONES(match_definer_format_31, match_definer_mask,
157				 inner_l4_dport);
158		ipv6 = MLX5_ADDR_OF(match_definer_format_31, match_definer_mask,
159				    inner_ip_dest_addr);
160		memset(ipv6, 0xff, 16);
161		ipv6 = MLX5_ADDR_OF(match_definer_format_31, match_definer_mask,
162				    inner_ip_src_addr);
163		memset(ipv6, 0xff, 16);
164		break;
165	case MLX5_TT_IPV6:
166		format_id = 32;
167		ipv6 = MLX5_ADDR_OF(match_definer_format_32, match_definer_mask,
168				    inner_ip_dest_addr);
169		memset(ipv6, 0xff, 16);
170		ipv6 = MLX5_ADDR_OF(match_definer_format_32, match_definer_mask,
171				    inner_ip_src_addr);
172		memset(ipv6, 0xff, 16);
173		MLX5_SET_TO_ONES(match_definer_format_32, match_definer_mask,
174				 inner_dmac_47_16);
175		MLX5_SET_TO_ONES(match_definer_format_32, match_definer_mask,
176				 inner_dmac_15_0);
177		MLX5_SET_TO_ONES(match_definer_format_32, match_definer_mask,
178				 inner_smac_47_16);
179		MLX5_SET_TO_ONES(match_definer_format_32, match_definer_mask,
180				 inner_smac_15_0);
181		break;
182	default:
183		format_id = 23;
184		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
185				 inner_l3_type);
186		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
187				 inner_dmac_47_16);
188		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
189				 inner_dmac_15_0);
190		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
191				 inner_smac_47_16);
192		MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
193				 inner_smac_15_0);
194		break;
195	}
196
197	return format_id;
198}
199
200static int mlx5_lag_set_definer(u32 *match_definer_mask,
201				enum mlx5_traffic_types tt, bool tunnel,
202				enum netdev_lag_hash hash)
203{
204	int format_id;
205	u8 *ipv6;
206
207	if (tunnel)
208		return mlx5_lag_set_definer_inner(match_definer_mask, tt);
209
210	switch (tt) {
211	case MLX5_TT_IPV4_UDP:
212	case MLX5_TT_IPV4_TCP:
213		format_id = 22;
214		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
215				 outer_l4_sport);
216		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
217				 outer_l4_dport);
218		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
219				 outer_ip_src_addr);
220		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
221				 outer_ip_dest_addr);
222		break;
223	case MLX5_TT_IPV4:
224		format_id = 22;
225		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
226				 outer_l3_type);
227		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
228				 outer_dmac_47_16);
229		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
230				 outer_dmac_15_0);
231		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
232				 outer_smac_47_16);
233		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
234				 outer_smac_15_0);
235		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
236				 outer_ip_src_addr);
237		MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
238				 outer_ip_dest_addr);
239		break;
240	case MLX5_TT_IPV6_TCP:
241	case MLX5_TT_IPV6_UDP:
242		format_id = 29;
243		MLX5_SET_TO_ONES(match_definer_format_29, match_definer_mask,
244				 outer_l4_sport);
245		MLX5_SET_TO_ONES(match_definer_format_29, match_definer_mask,
246				 outer_l4_dport);
247		ipv6 = MLX5_ADDR_OF(match_definer_format_29, match_definer_mask,
248				    outer_ip_dest_addr);
249		memset(ipv6, 0xff, 16);
250		ipv6 = MLX5_ADDR_OF(match_definer_format_29, match_definer_mask,
251				    outer_ip_src_addr);
252		memset(ipv6, 0xff, 16);
253		break;
254	case MLX5_TT_IPV6:
255		format_id = 30;
256		ipv6 = MLX5_ADDR_OF(match_definer_format_30, match_definer_mask,
257				    outer_ip_dest_addr);
258		memset(ipv6, 0xff, 16);
259		ipv6 = MLX5_ADDR_OF(match_definer_format_30, match_definer_mask,
260				    outer_ip_src_addr);
261		memset(ipv6, 0xff, 16);
262		MLX5_SET_TO_ONES(match_definer_format_30, match_definer_mask,
263				 outer_dmac_47_16);
264		MLX5_SET_TO_ONES(match_definer_format_30, match_definer_mask,
265				 outer_dmac_15_0);
266		MLX5_SET_TO_ONES(match_definer_format_30, match_definer_mask,
267				 outer_smac_47_16);
268		MLX5_SET_TO_ONES(match_definer_format_30, match_definer_mask,
269				 outer_smac_15_0);
270		break;
271	default:
272		format_id = 0;
273		MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
274				 outer_smac_47_16);
275		MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
276				 outer_smac_15_0);
277
278		if (hash == NETDEV_LAG_HASH_VLAN_SRCMAC) {
279			MLX5_SET_TO_ONES(match_definer_format_0,
280					 match_definer_mask,
281					 outer_first_vlan_vid);
282			break;
283		}
284
285		MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
286				 outer_ethertype);
287		MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
288				 outer_dmac_47_16);
289		MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
290				 outer_dmac_15_0);
291		break;
292	}
293
294	return format_id;
295}
296
297static struct mlx5_lag_definer *
298mlx5_lag_create_definer(struct mlx5_lag *ldev, enum netdev_lag_hash hash,
299			enum mlx5_traffic_types tt, bool tunnel, u8 *ports)
300{
301	int first_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
302	struct mlx5_lag_definer *lag_definer;
303	struct mlx5_core_dev *dev;
304	u32 *match_definer_mask;
305	int format_id, err;
306
307	if (first_idx < 0)
308		return ERR_PTR(-EINVAL);
309
310	dev = ldev->pf[first_idx].dev;
311	lag_definer = kzalloc(sizeof(*lag_definer), GFP_KERNEL);
312	if (!lag_definer)
313		return ERR_PTR(-ENOMEM);
314
315	match_definer_mask = kvzalloc(MLX5_FLD_SZ_BYTES(match_definer,
316							match_mask),
317				      GFP_KERNEL);
318	if (!match_definer_mask) {
319		err = -ENOMEM;
320		goto free_lag_definer;
321	}
322
323	format_id = mlx5_lag_set_definer(match_definer_mask, tt, tunnel, hash);
324	lag_definer->definer =
325		mlx5_create_match_definer(dev, MLX5_FLOW_NAMESPACE_PORT_SEL,
326					  format_id, match_definer_mask);
327	if (IS_ERR(lag_definer->definer)) {
328		err = PTR_ERR(lag_definer->definer);
329		goto free_mask;
330	}
331
332	err = mlx5_lag_create_port_sel_table(ldev, lag_definer, ports);
333	if (err)
334		goto destroy_match_definer;
335
336	kvfree(match_definer_mask);
337
338	return lag_definer;
339
340destroy_match_definer:
341	mlx5_destroy_match_definer(dev, lag_definer->definer);
342free_mask:
343	kvfree(match_definer_mask);
344free_lag_definer:
345	kfree(lag_definer);
346	return ERR_PTR(err);
347}
348
349static void mlx5_lag_destroy_definer(struct mlx5_lag *ldev,
350				     struct mlx5_lag_definer *lag_definer)
351{
352	int first_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
353	struct mlx5_core_dev *dev;
354	int idx, i, j;
355
356	if (first_idx < 0)
357		return;
358
359	dev = ldev->pf[first_idx].dev;
360	mlx5_ldev_for_each(i, first_idx, ldev) {
361		for (j = 0; j < ldev->buckets; j++) {
362			idx = i * ldev->buckets + j;
363			mlx5_del_flow_rules(lag_definer->rules[idx]);
364		}
365	}
366	mlx5_destroy_flow_group(lag_definer->fg);
367	mlx5_destroy_flow_table(lag_definer->ft);
368	mlx5_destroy_match_definer(dev, lag_definer->definer);
369	kfree(lag_definer);
370}
371
372static void mlx5_lag_destroy_definers(struct mlx5_lag *ldev)
373{
374	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
375	int tt;
376
377	for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
378		if (port_sel->outer.definers[tt])
379			mlx5_lag_destroy_definer(ldev,
380						 port_sel->outer.definers[tt]);
381		if (port_sel->inner.definers[tt])
382			mlx5_lag_destroy_definer(ldev,
383						 port_sel->inner.definers[tt]);
384	}
385}
386
387static int mlx5_lag_create_definers(struct mlx5_lag *ldev,
388				    enum netdev_lag_hash hash_type,
389				    u8 *ports)
390{
391	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
392	struct mlx5_lag_definer *lag_definer;
393	int tt, err;
394
395	for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
396		lag_definer = mlx5_lag_create_definer(ldev, hash_type, tt,
397						      false, ports);
398		if (IS_ERR(lag_definer)) {
399			err = PTR_ERR(lag_definer);
400			goto destroy_definers;
401		}
402		port_sel->outer.definers[tt] = lag_definer;
403
404		if (!port_sel->tunnel)
405			continue;
406
407		lag_definer =
408			mlx5_lag_create_definer(ldev, hash_type, tt,
409						true, ports);
410		if (IS_ERR(lag_definer)) {
411			err = PTR_ERR(lag_definer);
412			goto destroy_definers;
413		}
414		port_sel->inner.definers[tt] = lag_definer;
415	}
416
417	return 0;
418
419destroy_definers:
420	mlx5_lag_destroy_definers(ldev);
421	return err;
422}
423
424static void set_tt_map(struct mlx5_lag_port_sel *port_sel,
425		       enum netdev_lag_hash hash)
426{
427	port_sel->tunnel = false;
428
429	switch (hash) {
430	case NETDEV_LAG_HASH_E34:
431		port_sel->tunnel = true;
432		fallthrough;
433	case NETDEV_LAG_HASH_L34:
434		set_bit(MLX5_TT_IPV4_TCP, port_sel->tt_map);
435		set_bit(MLX5_TT_IPV4_UDP, port_sel->tt_map);
436		set_bit(MLX5_TT_IPV6_TCP, port_sel->tt_map);
437		set_bit(MLX5_TT_IPV6_UDP, port_sel->tt_map);
438		set_bit(MLX5_TT_IPV4, port_sel->tt_map);
439		set_bit(MLX5_TT_IPV6, port_sel->tt_map);
440		set_bit(MLX5_TT_ANY, port_sel->tt_map);
441		break;
442	case NETDEV_LAG_HASH_E23:
443		port_sel->tunnel = true;
444		fallthrough;
445	case NETDEV_LAG_HASH_L23:
446		set_bit(MLX5_TT_IPV4, port_sel->tt_map);
447		set_bit(MLX5_TT_IPV6, port_sel->tt_map);
448		set_bit(MLX5_TT_ANY, port_sel->tt_map);
449		break;
450	default:
451		set_bit(MLX5_TT_ANY, port_sel->tt_map);
452		break;
453	}
454}
455
456#define SET_IGNORE_DESTS_BITS(tt_map, dests)				\
457	do {								\
458		int idx;						\
459									\
460		for_each_clear_bit(idx, tt_map, MLX5_NUM_TT)		\
461			set_bit(idx, dests);				\
462	} while (0)
463
464static void mlx5_lag_set_inner_ttc_params(struct mlx5_lag *ldev,
465					  struct ttc_params *ttc_params)
466{
467	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
468	struct mlx5_flow_table_attr *ft_attr;
469	int tt;
470
471	ttc_params->ns_type = MLX5_FLOW_NAMESPACE_PORT_SEL;
472	ft_attr = &ttc_params->ft_attr;
473	ft_attr->level = MLX5_LAG_FT_LEVEL_INNER_TTC;
474
475	for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
476		ttc_params->dests[tt].type =
477			MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
478		ttc_params->dests[tt].ft = port_sel->inner.definers[tt]->ft;
479	}
480	SET_IGNORE_DESTS_BITS(port_sel->tt_map, ttc_params->ignore_dests);
481}
482
483static void mlx5_lag_set_outer_ttc_params(struct mlx5_lag *ldev,
484					  struct ttc_params *ttc_params)
485{
486	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
487	struct mlx5_flow_table_attr *ft_attr;
488	int tt;
489
490	ttc_params->ns_type = MLX5_FLOW_NAMESPACE_PORT_SEL;
491	ft_attr = &ttc_params->ft_attr;
492	ft_attr->level = MLX5_LAG_FT_LEVEL_TTC;
493
494	for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
495		ttc_params->dests[tt].type =
496			MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
497		ttc_params->dests[tt].ft = port_sel->outer.definers[tt]->ft;
498	}
499	SET_IGNORE_DESTS_BITS(port_sel->tt_map, ttc_params->ignore_dests);
500
501	ttc_params->inner_ttc = port_sel->tunnel;
502	if (!port_sel->tunnel)
503		return;
504
505	for (tt = 0; tt < MLX5_NUM_TUNNEL_TT; tt++) {
506		ttc_params->tunnel_dests[tt].type =
507			MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
508		ttc_params->tunnel_dests[tt].ft =
509			mlx5_get_ttc_flow_table(port_sel->inner.ttc);
510	}
511}
512
513static int mlx5_lag_create_ttc_table(struct mlx5_lag *ldev)
514{
515	int first_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
516	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
517	struct ttc_params ttc_params = {};
518	struct mlx5_core_dev *dev;
519
520	if (first_idx < 0)
521		return -EINVAL;
522
523	dev = ldev->pf[first_idx].dev;
524	mlx5_lag_set_outer_ttc_params(ldev, &ttc_params);
525	port_sel->outer.ttc = mlx5_create_ttc_table(dev, &ttc_params);
526	return PTR_ERR_OR_ZERO(port_sel->outer.ttc);
527}
528
529static int mlx5_lag_create_inner_ttc_table(struct mlx5_lag *ldev)
530{
531	int first_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
532	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
533	struct ttc_params ttc_params = {};
534	struct mlx5_core_dev *dev;
535
536	if (first_idx < 0)
537		return -EINVAL;
538
539	dev = ldev->pf[first_idx].dev;
540	mlx5_lag_set_inner_ttc_params(ldev, &ttc_params);
541	port_sel->inner.ttc = mlx5_create_inner_ttc_table(dev, &ttc_params);
542	return PTR_ERR_OR_ZERO(port_sel->inner.ttc);
543}
544
545int mlx5_lag_port_sel_create(struct mlx5_lag *ldev,
546			     enum netdev_lag_hash hash_type, u8 *ports)
547{
548	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
549	int err;
550
551	set_tt_map(port_sel, hash_type);
552	err = mlx5_lag_create_definers(ldev, hash_type, ports);
553	if (err)
554		goto clear_port_sel;
555
556	if (port_sel->tunnel) {
557		err = mlx5_lag_create_inner_ttc_table(ldev);
558		if (err)
559			goto destroy_definers;
560	}
561
562	err = mlx5_lag_create_ttc_table(ldev);
563	if (err)
564		goto destroy_inner;
565
566	return 0;
567
568destroy_inner:
569	if (port_sel->tunnel)
570		mlx5_destroy_ttc_table(port_sel->inner.ttc);
571destroy_definers:
572	mlx5_lag_destroy_definers(ldev);
573clear_port_sel:
574	memset(port_sel, 0, sizeof(*port_sel));
575	return err;
576}
577
578static int __mlx5_lag_modify_definers_destinations(struct mlx5_lag *ldev,
579						   struct mlx5_lag_definer *def,
580						   u8 *ports)
581{
582	struct mlx5_flow_destination dest = {};
583	int idx;
584	int err;
585	int i;
586	int j;
587
588	dest.type = MLX5_FLOW_DESTINATION_TYPE_UPLINK;
589	dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
590
591	mlx5_ldev_for_each(i, 0, ldev) {
592		for (j = 0; j < ldev->buckets; j++) {
593			idx = i * ldev->buckets + j;
594			if (ldev->v2p_map[idx] == ports[idx])
595				continue;
596
597			dest.vport.vhca_id = MLX5_CAP_GEN(ldev->pf[ports[idx] - 1].dev,
598							  vhca_id);
599			err = mlx5_modify_rule_destination(def->rules[idx], &dest, NULL);
600			if (err)
601				return err;
602		}
603	}
604
605	return 0;
606}
607
608static int
609mlx5_lag_modify_definers_destinations(struct mlx5_lag *ldev,
610				      struct mlx5_lag_definer **definers,
611				      u8 *ports)
612{
613	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
614	int err;
615	int tt;
616
617	for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
618		err = __mlx5_lag_modify_definers_destinations(ldev, definers[tt], ports);
619		if (err)
620			return err;
621	}
622
623	return 0;
624}
625
626int mlx5_lag_port_sel_modify(struct mlx5_lag *ldev, u8 *ports)
627{
628	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
629	int err;
630
631	err = mlx5_lag_modify_definers_destinations(ldev,
632						    port_sel->outer.definers,
633						    ports);
634	if (err)
635		return err;
636
637	if (!port_sel->tunnel)
638		return 0;
639
640	return mlx5_lag_modify_definers_destinations(ldev,
641						     port_sel->inner.definers,
642						     ports);
643}
644
645void mlx5_lag_port_sel_destroy(struct mlx5_lag *ldev)
646{
647	struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
648
649	mlx5_destroy_ttc_table(port_sel->outer.ttc);
650	if (port_sel->tunnel)
651		mlx5_destroy_ttc_table(port_sel->inner.ttc);
652	mlx5_lag_destroy_definers(ldev);
653	memset(port_sel, 0, sizeof(*port_sel));
654}
~/ Read-only file preview.