1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */
4 #include "en/fs_tt_redirect.h"
15 struct mlx5e_flow_table tables
[FS_UDP_NUM_TYPES
];
16 struct mlx5_flow_handle
*default_rules
[FS_UDP_NUM_TYPES
];
21 struct mlx5e_flow_table table
;
22 struct mlx5_flow_handle
*default_rule
;
26 static char *fs_udp_type2str(enum fs_udp_type i
)
31 default: /* FS_IPV6_UDP */
36 static enum mlx5_traffic_types
fs_udp2tt(enum fs_udp_type i
)
40 return MLX5_TT_IPV4_UDP
;
41 default: /* FS_IPV6_UDP */
42 return MLX5_TT_IPV6_UDP
;
46 static enum fs_udp_type
tt2fs_udp(enum mlx5_traffic_types i
)
49 case MLX5_TT_IPV4_UDP
:
51 case MLX5_TT_IPV6_UDP
:
54 return FS_UDP_NUM_TYPES
;
58 void mlx5e_fs_tt_redirect_del_rule(struct mlx5_flow_handle
*rule
)
60 mlx5_del_flow_rules(rule
);
63 static void fs_udp_set_dport_flow(struct mlx5_flow_spec
*spec
, enum fs_udp_type type
,
66 spec
->match_criteria_enable
= MLX5_MATCH_OUTER_HEADERS
;
67 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.ip_protocol
);
68 MLX5_SET(fte_match_param
, spec
->match_value
, outer_headers
.ip_protocol
, IPPROTO_UDP
);
69 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.ip_version
);
70 MLX5_SET(fte_match_param
, spec
->match_value
, outer_headers
.ip_version
,
71 type
== FS_IPV4_UDP
? 4 : 6);
72 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.udp_dport
);
73 MLX5_SET(fte_match_param
, spec
->match_value
, outer_headers
.udp_dport
, udp_dport
);
76 struct mlx5_flow_handle
*
77 mlx5e_fs_tt_redirect_udp_add_rule(struct mlx5e_flow_steering
*fs
,
78 enum mlx5_traffic_types ttc_type
,
79 u32 tir_num
, u16 d_port
)
81 struct mlx5e_fs_udp
*fs_udp
= mlx5e_fs_get_udp(fs
);
82 enum fs_udp_type type
= tt2fs_udp(ttc_type
);
83 struct mlx5_flow_destination dest
= {};
84 struct mlx5_flow_table
*ft
= NULL
;
85 MLX5_DECLARE_FLOW_ACT(flow_act
);
86 struct mlx5_flow_handle
*rule
;
87 struct mlx5_flow_spec
*spec
;
90 if (type
== FS_UDP_NUM_TYPES
)
91 return ERR_PTR(-EINVAL
);
93 spec
= kvzalloc(sizeof(*spec
), GFP_KERNEL
);
95 return ERR_PTR(-ENOMEM
);
97 ft
= fs_udp
->tables
[type
].t
;
99 fs_udp_set_dport_flow(spec
, type
, d_port
);
100 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_TIR
;
101 dest
.tir_num
= tir_num
;
103 rule
= mlx5_add_flow_rules(ft
, spec
, &flow_act
, &dest
, 1);
108 fs_err(fs
, "%s: add %s rule failed, err %d\n",
109 __func__
, fs_udp_type2str(type
), err
);
114 static int fs_udp_add_default_rule(struct mlx5e_flow_steering
*fs
, enum fs_udp_type type
)
116 struct mlx5_ttc_table
*ttc
= mlx5e_fs_get_ttc(fs
, false);
117 struct mlx5e_fs_udp
*fs_udp
= mlx5e_fs_get_udp(fs
);
118 struct mlx5e_flow_table
*fs_udp_t
;
119 struct mlx5_flow_destination dest
;
120 MLX5_DECLARE_FLOW_ACT(flow_act
);
121 struct mlx5_flow_handle
*rule
;
124 fs_udp_t
= &fs_udp
->tables
[type
];
126 dest
= mlx5_ttc_get_default_dest(ttc
, fs_udp2tt(type
));
127 rule
= mlx5_add_flow_rules(fs_udp_t
->t
, NULL
, &flow_act
, &dest
, 1);
130 fs_err(fs
, "%s: add default rule failed, fs type=%d, err %d\n",
131 __func__
, type
, err
);
135 fs_udp
->default_rules
[type
] = rule
;
139 #define MLX5E_FS_UDP_NUM_GROUPS (2)
140 #define MLX5E_FS_UDP_GROUP1_SIZE (BIT(16))
141 #define MLX5E_FS_UDP_GROUP2_SIZE (BIT(0))
142 #define MLX5E_FS_UDP_TABLE_SIZE (MLX5E_FS_UDP_GROUP1_SIZE +\
143 MLX5E_FS_UDP_GROUP2_SIZE)
144 static int fs_udp_create_groups(struct mlx5e_flow_table
*ft
, enum fs_udp_type type
)
146 int inlen
= MLX5_ST_SZ_BYTES(create_flow_group_in
);
147 void *outer_headers_c
;
153 ft
->g
= kcalloc(MLX5E_FS_UDP_NUM_GROUPS
, sizeof(*ft
->g
), GFP_KERNEL
);
154 in
= kvzalloc(inlen
, GFP_KERNEL
);
161 mc
= MLX5_ADDR_OF(create_flow_group_in
, in
, match_criteria
);
162 outer_headers_c
= MLX5_ADDR_OF(fte_match_param
, mc
, outer_headers
);
163 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4
, outer_headers_c
, ip_protocol
);
164 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4
, outer_headers_c
, ip_version
);
169 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4
, outer_headers_c
, udp_dport
);
175 /* Match on udp protocol, Ipv4/6 and dport */
176 MLX5_SET_CFG(in
, match_criteria_enable
, MLX5_MATCH_OUTER_HEADERS
);
177 MLX5_SET_CFG(in
, start_flow_index
, ix
);
178 ix
+= MLX5E_FS_UDP_GROUP1_SIZE
;
179 MLX5_SET_CFG(in
, end_flow_index
, ix
- 1);
180 ft
->g
[ft
->num_groups
] = mlx5_create_flow_group(ft
->t
, in
);
181 if (IS_ERR(ft
->g
[ft
->num_groups
]))
185 /* Default Flow Group */
186 memset(in
, 0, inlen
);
187 MLX5_SET_CFG(in
, start_flow_index
, ix
);
188 ix
+= MLX5E_FS_UDP_GROUP2_SIZE
;
189 MLX5_SET_CFG(in
, end_flow_index
, ix
- 1);
190 ft
->g
[ft
->num_groups
] = mlx5_create_flow_group(ft
->t
, in
);
191 if (IS_ERR(ft
->g
[ft
->num_groups
]))
199 err
= PTR_ERR(ft
->g
[ft
->num_groups
]);
200 ft
->g
[ft
->num_groups
] = NULL
;
207 static int fs_udp_create_table(struct mlx5e_flow_steering
*fs
, enum fs_udp_type type
)
209 struct mlx5_flow_namespace
*ns
= mlx5e_fs_get_ns(fs
, false);
210 struct mlx5e_fs_udp
*fs_udp
= mlx5e_fs_get_udp(fs
);
211 struct mlx5_flow_table_attr ft_attr
= {};
212 struct mlx5e_flow_table
*ft
;
215 ft
= &fs_udp
->tables
[type
];
218 ft_attr
.max_fte
= MLX5E_FS_UDP_TABLE_SIZE
;
219 ft_attr
.level
= MLX5E_FS_TT_UDP_FT_LEVEL
;
220 ft_attr
.prio
= MLX5E_NIC_PRIO
;
222 ft
->t
= mlx5_create_flow_table(ns
, &ft_attr
);
224 err
= PTR_ERR(ft
->t
);
229 mlx5_core_dbg(mlx5e_fs_get_mdev(fs
), "Created fs %s table id %u level %u\n",
230 fs_udp_type2str(type
), ft
->t
->id
, ft
->t
->level
);
232 err
= fs_udp_create_groups(ft
, type
);
236 err
= fs_udp_add_default_rule(fs
, type
);
243 mlx5e_destroy_flow_table(ft
);
247 static void fs_udp_destroy_table(struct mlx5e_fs_udp
*fs_udp
, int i
)
249 if (IS_ERR_OR_NULL(fs_udp
->tables
[i
].t
))
252 mlx5_del_flow_rules(fs_udp
->default_rules
[i
]);
253 mlx5e_destroy_flow_table(&fs_udp
->tables
[i
]);
254 fs_udp
->tables
[i
].t
= NULL
;
257 static int fs_udp_disable(struct mlx5e_flow_steering
*fs
)
259 struct mlx5_ttc_table
*ttc
= mlx5e_fs_get_ttc(fs
, false);
262 for (i
= 0; i
< FS_UDP_NUM_TYPES
; i
++) {
263 /* Modify ttc rules destination to point back to the indir TIRs */
264 err
= mlx5_ttc_fwd_default_dest(ttc
, fs_udp2tt(i
));
266 fs_err(fs
, "%s: modify ttc[%d] default destination failed, err(%d)\n",
267 __func__
, fs_udp2tt(i
), err
);
275 static int fs_udp_enable(struct mlx5e_flow_steering
*fs
)
277 struct mlx5_ttc_table
*ttc
= mlx5e_fs_get_ttc(fs
, false);
278 struct mlx5e_fs_udp
*udp
= mlx5e_fs_get_udp(fs
);
279 struct mlx5_flow_destination dest
= {};
282 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE
;
283 for (i
= 0; i
< FS_UDP_NUM_TYPES
; i
++) {
284 dest
.ft
= udp
->tables
[i
].t
;
286 /* Modify ttc rules destination to point on the accel_fs FTs */
287 err
= mlx5_ttc_fwd_dest(ttc
, fs_udp2tt(i
), &dest
);
289 fs_err(fs
, "%s: modify ttc[%d] destination to accel failed, err(%d)\n",
290 __func__
, fs_udp2tt(i
), err
);
297 void mlx5e_fs_tt_redirect_udp_destroy(struct mlx5e_flow_steering
*fs
)
299 struct mlx5e_fs_udp
*fs_udp
= mlx5e_fs_get_udp(fs
);
305 if (--fs_udp
->ref_cnt
)
310 for (i
= 0; i
< FS_UDP_NUM_TYPES
; i
++)
311 fs_udp_destroy_table(fs_udp
, i
);
314 mlx5e_fs_set_udp(fs
, NULL
);
317 int mlx5e_fs_tt_redirect_udp_create(struct mlx5e_flow_steering
*fs
)
319 struct mlx5e_fs_udp
*udp
= mlx5e_fs_get_udp(fs
);
327 udp
= kzalloc(sizeof(*udp
), GFP_KERNEL
);
330 mlx5e_fs_set_udp(fs
, udp
);
332 for (i
= 0; i
< FS_UDP_NUM_TYPES
; i
++) {
333 err
= fs_udp_create_table(fs
, i
);
335 goto err_destroy_tables
;
338 err
= fs_udp_enable(fs
);
340 goto err_destroy_tables
;
348 fs_udp_destroy_table(udp
, i
);
351 mlx5e_fs_set_udp(fs
, NULL
);
355 static void fs_any_set_ethertype_flow(struct mlx5_flow_spec
*spec
, u16 ether_type
)
357 spec
->match_criteria_enable
= MLX5_MATCH_OUTER_HEADERS
;
358 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.ethertype
);
359 MLX5_SET(fte_match_param
, spec
->match_value
, outer_headers
.ethertype
, ether_type
);
362 struct mlx5_flow_handle
*
363 mlx5e_fs_tt_redirect_any_add_rule(struct mlx5e_flow_steering
*fs
,
364 u32 tir_num
, u16 ether_type
)
366 struct mlx5e_fs_any
*fs_any
= mlx5e_fs_get_any(fs
);
367 struct mlx5_flow_destination dest
= {};
368 struct mlx5_flow_table
*ft
= NULL
;
369 MLX5_DECLARE_FLOW_ACT(flow_act
);
370 struct mlx5_flow_handle
*rule
;
371 struct mlx5_flow_spec
*spec
;
374 spec
= kvzalloc(sizeof(*spec
), GFP_KERNEL
);
376 return ERR_PTR(-ENOMEM
);
378 ft
= fs_any
->table
.t
;
380 fs_any_set_ethertype_flow(spec
, ether_type
);
381 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_TIR
;
382 dest
.tir_num
= tir_num
;
384 rule
= mlx5_add_flow_rules(ft
, spec
, &flow_act
, &dest
, 1);
389 fs_err(fs
, "%s: add ANY rule failed, err %d\n",
395 static int fs_any_add_default_rule(struct mlx5e_flow_steering
*fs
)
397 struct mlx5_ttc_table
*ttc
= mlx5e_fs_get_ttc(fs
, false);
398 struct mlx5e_fs_any
*fs_any
= mlx5e_fs_get_any(fs
);
399 struct mlx5e_flow_table
*fs_any_t
;
400 struct mlx5_flow_destination dest
;
401 MLX5_DECLARE_FLOW_ACT(flow_act
);
402 struct mlx5_flow_handle
*rule
;
405 fs_any_t
= &fs_any
->table
;
406 dest
= mlx5_ttc_get_default_dest(ttc
, MLX5_TT_ANY
);
407 rule
= mlx5_add_flow_rules(fs_any_t
->t
, NULL
, &flow_act
, &dest
, 1);
410 fs_err(fs
, "%s: add default rule failed, fs type=ANY, err %d\n",
415 fs_any
->default_rule
= rule
;
419 #define MLX5E_FS_ANY_NUM_GROUPS (2)
420 #define MLX5E_FS_ANY_GROUP1_SIZE (BIT(16))
421 #define MLX5E_FS_ANY_GROUP2_SIZE (BIT(0))
422 #define MLX5E_FS_ANY_TABLE_SIZE (MLX5E_FS_ANY_GROUP1_SIZE +\
423 MLX5E_FS_ANY_GROUP2_SIZE)
425 static int fs_any_create_groups(struct mlx5e_flow_table
*ft
)
427 int inlen
= MLX5_ST_SZ_BYTES(create_flow_group_in
);
428 void *outer_headers_c
;
434 ft
->g
= kcalloc(MLX5E_FS_UDP_NUM_GROUPS
, sizeof(*ft
->g
), GFP_KERNEL
);
435 in
= kvzalloc(inlen
, GFP_KERNEL
);
442 /* Match on ethertype */
443 mc
= MLX5_ADDR_OF(create_flow_group_in
, in
, match_criteria
);
444 outer_headers_c
= MLX5_ADDR_OF(fte_match_param
, mc
, outer_headers
);
445 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4
, outer_headers_c
, ethertype
);
446 MLX5_SET_CFG(in
, match_criteria_enable
, MLX5_MATCH_OUTER_HEADERS
);
447 MLX5_SET_CFG(in
, start_flow_index
, ix
);
448 ix
+= MLX5E_FS_ANY_GROUP1_SIZE
;
449 MLX5_SET_CFG(in
, end_flow_index
, ix
- 1);
450 ft
->g
[ft
->num_groups
] = mlx5_create_flow_group(ft
->t
, in
);
451 if (IS_ERR(ft
->g
[ft
->num_groups
]))
455 /* Default Flow Group */
456 memset(in
, 0, inlen
);
457 MLX5_SET_CFG(in
, start_flow_index
, ix
);
458 ix
+= MLX5E_FS_ANY_GROUP2_SIZE
;
459 MLX5_SET_CFG(in
, end_flow_index
, ix
- 1);
460 ft
->g
[ft
->num_groups
] = mlx5_create_flow_group(ft
->t
, in
);
461 if (IS_ERR(ft
->g
[ft
->num_groups
]))
469 err
= PTR_ERR(ft
->g
[ft
->num_groups
]);
470 ft
->g
[ft
->num_groups
] = NULL
;
476 static int fs_any_create_table(struct mlx5e_flow_steering
*fs
)
478 struct mlx5_flow_namespace
*ns
= mlx5e_fs_get_ns(fs
, false);
479 struct mlx5e_fs_any
*fs_any
= mlx5e_fs_get_any(fs
);
480 struct mlx5e_flow_table
*ft
= &fs_any
->table
;
481 struct mlx5_flow_table_attr ft_attr
= {};
486 ft_attr
.max_fte
= MLX5E_FS_UDP_TABLE_SIZE
;
487 ft_attr
.level
= MLX5E_FS_TT_ANY_FT_LEVEL
;
488 ft_attr
.prio
= MLX5E_NIC_PRIO
;
490 ft
->t
= mlx5_create_flow_table(ns
, &ft_attr
);
492 err
= PTR_ERR(ft
->t
);
497 mlx5_core_dbg(mlx5e_fs_get_mdev(fs
), "Created fs ANY table id %u level %u\n",
498 ft
->t
->id
, ft
->t
->level
);
500 err
= fs_any_create_groups(ft
);
504 err
= fs_any_add_default_rule(fs
);
511 mlx5e_destroy_flow_table(ft
);
515 static int fs_any_disable(struct mlx5e_flow_steering
*fs
)
517 struct mlx5_ttc_table
*ttc
= mlx5e_fs_get_ttc(fs
, false);
520 /* Modify ttc rules destination to point back to the indir TIRs */
521 err
= mlx5_ttc_fwd_default_dest(ttc
, MLX5_TT_ANY
);
524 "%s: modify ttc[%d] default destination failed, err(%d)\n",
525 __func__
, MLX5_TT_ANY
, err
);
531 static int fs_any_enable(struct mlx5e_flow_steering
*fs
)
533 struct mlx5_ttc_table
*ttc
= mlx5e_fs_get_ttc(fs
, false);
534 struct mlx5e_fs_any
*any
= mlx5e_fs_get_any(fs
);
535 struct mlx5_flow_destination dest
= {};
538 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE
;
539 dest
.ft
= any
->table
.t
;
541 /* Modify ttc rules destination to point on the accel_fs FTs */
542 err
= mlx5_ttc_fwd_dest(ttc
, MLX5_TT_ANY
, &dest
);
545 "%s: modify ttc[%d] destination to accel failed, err(%d)\n",
546 __func__
, MLX5_TT_ANY
, err
);
552 static void fs_any_destroy_table(struct mlx5e_fs_any
*fs_any
)
554 if (IS_ERR_OR_NULL(fs_any
->table
.t
))
557 mlx5_del_flow_rules(fs_any
->default_rule
);
558 mlx5e_destroy_flow_table(&fs_any
->table
);
559 fs_any
->table
.t
= NULL
;
562 void mlx5e_fs_tt_redirect_any_destroy(struct mlx5e_flow_steering
*fs
)
564 struct mlx5e_fs_any
*fs_any
= mlx5e_fs_get_any(fs
);
569 if (--fs_any
->ref_cnt
)
574 fs_any_destroy_table(fs_any
);
577 mlx5e_fs_set_any(fs
, NULL
);
580 int mlx5e_fs_tt_redirect_any_create(struct mlx5e_flow_steering
*fs
)
582 struct mlx5e_fs_any
*fs_any
= mlx5e_fs_get_any(fs
);
590 fs_any
= kzalloc(sizeof(*fs_any
), GFP_KERNEL
);
593 mlx5e_fs_set_any(fs
, fs_any
);
595 err
= fs_any_create_table(fs
);
599 err
= fs_any_enable(fs
);
601 goto err_destroy_table
;
608 fs_any_destroy_table(fs_any
);
610 mlx5e_fs_set_any(fs
, NULL
);