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