1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. */
4 #include <linux/netdevice.h>
9 MLX5_LAG_FT_LEVEL_INNER_TTC,
10 MLX5_LAG_FT_LEVEL_DEFINER,
13 static struct mlx5_flow_group *
14 mlx5_create_hash_flow_group(struct mlx5_flow_table *ft,
15 struct mlx5_flow_definer *definer,
18 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
19 struct mlx5_flow_group *fg;
22 in = kvzalloc(inlen, GFP_KERNEL);
24 return ERR_PTR(-ENOMEM);
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);
33 fg = mlx5_create_flow_group(ft, in);
38 static int mlx5_lag_create_port_sel_table(struct mlx5_lag *ldev,
39 struct mlx5_lag_definer *lag_definer,
42 struct mlx5_core_dev *dev = ldev->pf[MLX5_LAG_P1].dev;
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;
51 ft_attr.max_fte = ldev->ports * ldev->buckets;
52 ft_attr.level = MLX5_LAG_FT_LEVEL_DEFINER;
54 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_PORT_SEL);
56 mlx5_core_warn(dev, "Failed to get port selection namespace\n");
60 lag_definer->ft = mlx5_create_flow_table(ns, &ft_attr);
61 if (IS_ERR(lag_definer->ft)) {
62 mlx5_core_warn(dev, "Failed to create port selection table\n");
63 return PTR_ERR(lag_definer->ft);
66 lag_definer->fg = mlx5_create_hash_flow_group(lag_definer->ft,
69 if (IS_ERR(lag_definer->fg)) {
70 err = PTR_ERR(lag_definer->fg);
74 dest.type = MLX5_FLOW_DESTINATION_TYPE_UPLINK;
75 dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
76 flow_act.flags |= FLOW_ACT_NO_APPEND;
77 for (i = 0; i < ldev->ports; i++) {
78 for (j = 0; j < ldev->buckets; j++) {
81 idx = i * ldev->buckets + j;
82 affinity = ports[idx];
84 dest.vport.vhca_id = MLX5_CAP_GEN(ldev->pf[affinity - 1].dev,
86 lag_definer->rules[idx] = mlx5_add_flow_rules(lag_definer->ft,
89 if (IS_ERR(lag_definer->rules[idx])) {
90 err = PTR_ERR(lag_definer->rules[idx]);
93 mlx5_del_flow_rules(lag_definer->rules[idx]);
102 mlx5_destroy_flow_group(lag_definer->fg);
104 mlx5_destroy_flow_table(lag_definer->ft);
108 static int mlx5_lag_set_definer_inner(u32 *match_definer_mask,
109 enum mlx5_traffic_types tt)
115 case MLX5_TT_IPV4_UDP:
116 case MLX5_TT_IPV4_TCP:
118 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
120 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
122 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
124 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
129 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
131 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
133 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
135 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
137 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
139 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
141 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
144 case MLX5_TT_IPV6_TCP:
145 case MLX5_TT_IPV6_UDP:
147 MLX5_SET_TO_ONES(match_definer_format_31, match_definer_mask,
149 MLX5_SET_TO_ONES(match_definer_format_31, match_definer_mask,
151 ipv6 = MLX5_ADDR_OF(match_definer_format_31, match_definer_mask,
153 memset(ipv6, 0xff, 16);
154 ipv6 = MLX5_ADDR_OF(match_definer_format_31, match_definer_mask,
156 memset(ipv6, 0xff, 16);
160 ipv6 = MLX5_ADDR_OF(match_definer_format_32, match_definer_mask,
162 memset(ipv6, 0xff, 16);
163 ipv6 = MLX5_ADDR_OF(match_definer_format_32, match_definer_mask,
165 memset(ipv6, 0xff, 16);
166 MLX5_SET_TO_ONES(match_definer_format_32, match_definer_mask,
168 MLX5_SET_TO_ONES(match_definer_format_32, match_definer_mask,
170 MLX5_SET_TO_ONES(match_definer_format_32, match_definer_mask,
172 MLX5_SET_TO_ONES(match_definer_format_32, match_definer_mask,
177 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
179 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
181 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
183 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
185 MLX5_SET_TO_ONES(match_definer_format_23, match_definer_mask,
193 static int mlx5_lag_set_definer(u32 *match_definer_mask,
194 enum mlx5_traffic_types tt, bool tunnel,
195 enum netdev_lag_hash hash)
201 return mlx5_lag_set_definer_inner(match_definer_mask, tt);
204 case MLX5_TT_IPV4_UDP:
205 case MLX5_TT_IPV4_TCP:
207 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
209 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
211 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
213 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
218 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
220 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
222 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
224 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
226 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
228 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
230 MLX5_SET_TO_ONES(match_definer_format_22, match_definer_mask,
233 case MLX5_TT_IPV6_TCP:
234 case MLX5_TT_IPV6_UDP:
236 MLX5_SET_TO_ONES(match_definer_format_29, match_definer_mask,
238 MLX5_SET_TO_ONES(match_definer_format_29, match_definer_mask,
240 ipv6 = MLX5_ADDR_OF(match_definer_format_29, match_definer_mask,
242 memset(ipv6, 0xff, 16);
243 ipv6 = MLX5_ADDR_OF(match_definer_format_29, match_definer_mask,
245 memset(ipv6, 0xff, 16);
249 ipv6 = MLX5_ADDR_OF(match_definer_format_30, match_definer_mask,
251 memset(ipv6, 0xff, 16);
252 ipv6 = MLX5_ADDR_OF(match_definer_format_30, match_definer_mask,
254 memset(ipv6, 0xff, 16);
255 MLX5_SET_TO_ONES(match_definer_format_30, match_definer_mask,
257 MLX5_SET_TO_ONES(match_definer_format_30, match_definer_mask,
259 MLX5_SET_TO_ONES(match_definer_format_30, match_definer_mask,
261 MLX5_SET_TO_ONES(match_definer_format_30, match_definer_mask,
266 MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
268 MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
271 if (hash == NETDEV_LAG_HASH_VLAN_SRCMAC) {
272 MLX5_SET_TO_ONES(match_definer_format_0,
274 outer_first_vlan_vid);
278 MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
280 MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
282 MLX5_SET_TO_ONES(match_definer_format_0, match_definer_mask,
290 static struct mlx5_lag_definer *
291 mlx5_lag_create_definer(struct mlx5_lag *ldev, enum netdev_lag_hash hash,
292 enum mlx5_traffic_types tt, bool tunnel, u8 *ports)
294 struct mlx5_core_dev *dev = ldev->pf[MLX5_LAG_P1].dev;
295 struct mlx5_lag_definer *lag_definer;
296 u32 *match_definer_mask;
299 lag_definer = kzalloc(sizeof(*lag_definer), GFP_KERNEL);
301 return ERR_PTR(-ENOMEM);
303 match_definer_mask = kvzalloc(MLX5_FLD_SZ_BYTES(match_definer,
306 if (!match_definer_mask) {
308 goto free_lag_definer;
311 format_id = mlx5_lag_set_definer(match_definer_mask, tt, tunnel, hash);
312 lag_definer->definer =
313 mlx5_create_match_definer(dev, MLX5_FLOW_NAMESPACE_PORT_SEL,
314 format_id, match_definer_mask);
315 if (IS_ERR(lag_definer->definer)) {
316 err = PTR_ERR(lag_definer->definer);
320 err = mlx5_lag_create_port_sel_table(ldev, lag_definer, ports);
322 goto destroy_match_definer;
324 kvfree(match_definer_mask);
328 destroy_match_definer:
329 mlx5_destroy_match_definer(dev, lag_definer->definer);
331 kvfree(match_definer_mask);
337 static void mlx5_lag_destroy_definer(struct mlx5_lag *ldev,
338 struct mlx5_lag_definer *lag_definer)
340 struct mlx5_core_dev *dev = ldev->pf[MLX5_LAG_P1].dev;
345 for (i = 0; i < ldev->ports; i++) {
346 for (j = 0; j < ldev->buckets; j++) {
347 idx = i * ldev->buckets + j;
348 mlx5_del_flow_rules(lag_definer->rules[idx]);
351 mlx5_destroy_flow_group(lag_definer->fg);
352 mlx5_destroy_flow_table(lag_definer->ft);
353 mlx5_destroy_match_definer(dev, lag_definer->definer);
357 static void mlx5_lag_destroy_definers(struct mlx5_lag *ldev)
359 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
362 for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
363 if (port_sel->outer.definers[tt])
364 mlx5_lag_destroy_definer(ldev,
365 port_sel->outer.definers[tt]);
366 if (port_sel->inner.definers[tt])
367 mlx5_lag_destroy_definer(ldev,
368 port_sel->inner.definers[tt]);
372 static int mlx5_lag_create_definers(struct mlx5_lag *ldev,
373 enum netdev_lag_hash hash_type,
376 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
377 struct mlx5_lag_definer *lag_definer;
380 for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
381 lag_definer = mlx5_lag_create_definer(ldev, hash_type, tt,
383 if (IS_ERR(lag_definer)) {
384 err = PTR_ERR(lag_definer);
385 goto destroy_definers;
387 port_sel->outer.definers[tt] = lag_definer;
389 if (!port_sel->tunnel)
393 mlx5_lag_create_definer(ldev, hash_type, tt,
395 if (IS_ERR(lag_definer)) {
396 err = PTR_ERR(lag_definer);
397 goto destroy_definers;
399 port_sel->inner.definers[tt] = lag_definer;
405 mlx5_lag_destroy_definers(ldev);
409 static void set_tt_map(struct mlx5_lag_port_sel *port_sel,
410 enum netdev_lag_hash hash)
412 port_sel->tunnel = false;
415 case NETDEV_LAG_HASH_E34:
416 port_sel->tunnel = true;
418 case NETDEV_LAG_HASH_L34:
419 set_bit(MLX5_TT_IPV4_TCP, port_sel->tt_map);
420 set_bit(MLX5_TT_IPV4_UDP, port_sel->tt_map);
421 set_bit(MLX5_TT_IPV6_TCP, port_sel->tt_map);
422 set_bit(MLX5_TT_IPV6_UDP, port_sel->tt_map);
423 set_bit(MLX5_TT_IPV4, port_sel->tt_map);
424 set_bit(MLX5_TT_IPV6, port_sel->tt_map);
425 set_bit(MLX5_TT_ANY, port_sel->tt_map);
427 case NETDEV_LAG_HASH_E23:
428 port_sel->tunnel = true;
430 case NETDEV_LAG_HASH_L23:
431 set_bit(MLX5_TT_IPV4, port_sel->tt_map);
432 set_bit(MLX5_TT_IPV6, port_sel->tt_map);
433 set_bit(MLX5_TT_ANY, port_sel->tt_map);
436 set_bit(MLX5_TT_ANY, port_sel->tt_map);
441 #define SET_IGNORE_DESTS_BITS(tt_map, dests) \
445 for_each_clear_bit(idx, tt_map, MLX5_NUM_TT) \
446 set_bit(idx, dests); \
449 static void mlx5_lag_set_inner_ttc_params(struct mlx5_lag *ldev,
450 struct ttc_params *ttc_params)
452 struct mlx5_core_dev *dev = ldev->pf[MLX5_LAG_P1].dev;
453 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
454 struct mlx5_flow_table_attr *ft_attr;
457 ttc_params->ns = mlx5_get_flow_namespace(dev,
458 MLX5_FLOW_NAMESPACE_PORT_SEL);
459 ft_attr = &ttc_params->ft_attr;
460 ft_attr->level = MLX5_LAG_FT_LEVEL_INNER_TTC;
462 for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
463 ttc_params->dests[tt].type =
464 MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
465 ttc_params->dests[tt].ft = port_sel->inner.definers[tt]->ft;
467 SET_IGNORE_DESTS_BITS(port_sel->tt_map, ttc_params->ignore_dests);
470 static void mlx5_lag_set_outer_ttc_params(struct mlx5_lag *ldev,
471 struct ttc_params *ttc_params)
473 struct mlx5_core_dev *dev = ldev->pf[MLX5_LAG_P1].dev;
474 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
475 struct mlx5_flow_table_attr *ft_attr;
478 ttc_params->ns = mlx5_get_flow_namespace(dev,
479 MLX5_FLOW_NAMESPACE_PORT_SEL);
480 ft_attr = &ttc_params->ft_attr;
481 ft_attr->level = MLX5_LAG_FT_LEVEL_TTC;
483 for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
484 ttc_params->dests[tt].type =
485 MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
486 ttc_params->dests[tt].ft = port_sel->outer.definers[tt]->ft;
488 SET_IGNORE_DESTS_BITS(port_sel->tt_map, ttc_params->ignore_dests);
490 ttc_params->inner_ttc = port_sel->tunnel;
491 if (!port_sel->tunnel)
494 for (tt = 0; tt < MLX5_NUM_TUNNEL_TT; tt++) {
495 ttc_params->tunnel_dests[tt].type =
496 MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
497 ttc_params->tunnel_dests[tt].ft =
498 mlx5_get_ttc_flow_table(port_sel->inner.ttc);
502 static int mlx5_lag_create_ttc_table(struct mlx5_lag *ldev)
504 struct mlx5_core_dev *dev = ldev->pf[MLX5_LAG_P1].dev;
505 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
506 struct ttc_params ttc_params = {};
508 mlx5_lag_set_outer_ttc_params(ldev, &ttc_params);
509 port_sel->outer.ttc = mlx5_create_ttc_table(dev, &ttc_params);
510 if (IS_ERR(port_sel->outer.ttc))
511 return PTR_ERR(port_sel->outer.ttc);
516 static int mlx5_lag_create_inner_ttc_table(struct mlx5_lag *ldev)
518 struct mlx5_core_dev *dev = ldev->pf[MLX5_LAG_P1].dev;
519 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
520 struct ttc_params ttc_params = {};
522 mlx5_lag_set_inner_ttc_params(ldev, &ttc_params);
523 port_sel->inner.ttc = mlx5_create_inner_ttc_table(dev, &ttc_params);
524 if (IS_ERR(port_sel->inner.ttc))
525 return PTR_ERR(port_sel->inner.ttc);
530 int mlx5_lag_port_sel_create(struct mlx5_lag *ldev,
531 enum netdev_lag_hash hash_type, u8 *ports)
533 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
536 set_tt_map(port_sel, hash_type);
537 err = mlx5_lag_create_definers(ldev, hash_type, ports);
541 if (port_sel->tunnel) {
542 err = mlx5_lag_create_inner_ttc_table(ldev);
544 goto destroy_definers;
547 err = mlx5_lag_create_ttc_table(ldev);
554 if (port_sel->tunnel)
555 mlx5_destroy_ttc_table(port_sel->inner.ttc);
557 mlx5_lag_destroy_definers(ldev);
561 static int __mlx5_lag_modify_definers_destinations(struct mlx5_lag *ldev,
562 struct mlx5_lag_definer *def,
565 struct mlx5_flow_destination dest = {};
571 dest.type = MLX5_FLOW_DESTINATION_TYPE_UPLINK;
572 dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
574 for (i = 0; i < ldev->ports; i++) {
575 for (j = 0; j < ldev->buckets; j++) {
576 idx = i * ldev->buckets + j;
577 if (ldev->v2p_map[i] == ports[i])
580 dest.vport.vhca_id = MLX5_CAP_GEN(ldev->pf[ports[idx] - 1].dev,
582 err = mlx5_modify_rule_destination(def->rules[idx], &dest, NULL);
592 mlx5_lag_modify_definers_destinations(struct mlx5_lag *ldev,
593 struct mlx5_lag_definer **definers,
596 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
600 for_each_set_bit(tt, port_sel->tt_map, MLX5_NUM_TT) {
601 err = __mlx5_lag_modify_definers_destinations(ldev, definers[tt], ports);
609 int mlx5_lag_port_sel_modify(struct mlx5_lag *ldev, u8 *ports)
611 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
614 err = mlx5_lag_modify_definers_destinations(ldev,
615 port_sel->outer.definers,
620 if (!port_sel->tunnel)
623 return mlx5_lag_modify_definers_destinations(ldev,
624 port_sel->inner.definers,
628 void mlx5_lag_port_sel_destroy(struct mlx5_lag *ldev)
630 struct mlx5_lag_port_sel *port_sel = &ldev->port_sel;
632 mlx5_destroy_ttc_table(port_sel->outer.ttc);
633 if (port_sel->tunnel)
634 mlx5_destroy_ttc_table(port_sel->inner.ttc);
635 mlx5_lag_destroy_definers(ldev);
636 memset(port_sel, 0, sizeof(*port_sel));