1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */
4 #include <linux/netdevice.h>
5 #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_priv *priv,
78 enum mlx5_traffic_types ttc_type,
79 u32 tir_num, u16 d_port)
81 enum fs_udp_type type = tt2fs_udp(ttc_type);
82 struct mlx5_flow_destination dest = {};
83 struct mlx5_flow_table *ft = NULL;
84 MLX5_DECLARE_FLOW_ACT(flow_act);
85 struct mlx5_flow_handle *rule;
86 struct mlx5_flow_spec *spec;
87 struct mlx5e_fs_udp *fs_udp;
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 fs_udp = priv->fs.udp;
98 ft = fs_udp->tables[type].t;
100 fs_udp_set_dport_flow(spec, type, d_port);
101 dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
102 dest.tir_num = tir_num;
104 rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
109 netdev_err(priv->netdev, "%s: add %s rule failed, err %d\n",
110 __func__, fs_udp_type2str(type), err);
115 static int fs_udp_add_default_rule(struct mlx5e_priv *priv, enum fs_udp_type type)
117 struct mlx5e_flow_table *fs_udp_t;
118 struct mlx5_flow_destination dest;
119 MLX5_DECLARE_FLOW_ACT(flow_act);
120 struct mlx5_flow_handle *rule;
121 struct mlx5e_fs_udp *fs_udp;
124 fs_udp = priv->fs.udp;
125 fs_udp_t = &fs_udp->tables[type];
127 dest = mlx5_ttc_get_default_dest(priv->fs.ttc, fs_udp2tt(type));
128 rule = mlx5_add_flow_rules(fs_udp_t->t, NULL, &flow_act, &dest, 1);
131 netdev_err(priv->netdev,
132 "%s: add default rule failed, fs type=%d, err %d\n",
133 __func__, type, err);
137 fs_udp->default_rules[type] = rule;
141 #define MLX5E_FS_UDP_NUM_GROUPS (2)
142 #define MLX5E_FS_UDP_GROUP1_SIZE (BIT(16))
143 #define MLX5E_FS_UDP_GROUP2_SIZE (BIT(0))
144 #define MLX5E_FS_UDP_TABLE_SIZE (MLX5E_FS_UDP_GROUP1_SIZE +\
145 MLX5E_FS_UDP_GROUP2_SIZE)
146 static int fs_udp_create_groups(struct mlx5e_flow_table *ft, enum fs_udp_type type)
148 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
149 void *outer_headers_c;
155 ft->g = kcalloc(MLX5E_FS_UDP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
156 in = kvzalloc(inlen, GFP_KERNEL);
163 mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
164 outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
165 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
166 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_version);
171 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport);
177 /* Match on udp protocol, Ipv4/6 and dport */
178 MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
179 MLX5_SET_CFG(in, start_flow_index, ix);
180 ix += MLX5E_FS_UDP_GROUP1_SIZE;
181 MLX5_SET_CFG(in, end_flow_index, ix - 1);
182 ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
183 if (IS_ERR(ft->g[ft->num_groups]))
187 /* Default Flow Group */
188 memset(in, 0, inlen);
189 MLX5_SET_CFG(in, start_flow_index, ix);
190 ix += MLX5E_FS_UDP_GROUP2_SIZE;
191 MLX5_SET_CFG(in, end_flow_index, ix - 1);
192 ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
193 if (IS_ERR(ft->g[ft->num_groups]))
201 err = PTR_ERR(ft->g[ft->num_groups]);
202 ft->g[ft->num_groups] = NULL;
209 static int fs_udp_create_table(struct mlx5e_priv *priv, enum fs_udp_type type)
211 struct mlx5e_flow_table *ft = &priv->fs.udp->tables[type];
212 struct mlx5_flow_table_attr ft_attr = {};
217 ft_attr.max_fte = MLX5E_FS_UDP_TABLE_SIZE;
218 ft_attr.level = MLX5E_FS_TT_UDP_FT_LEVEL;
219 ft_attr.prio = MLX5E_NIC_PRIO;
221 ft->t = mlx5_create_flow_table(priv->fs.ns, &ft_attr);
223 err = PTR_ERR(ft->t);
228 netdev_dbg(priv->netdev, "Created fs %s table id %u level %u\n",
229 fs_udp_type2str(type), ft->t->id, ft->t->level);
231 err = fs_udp_create_groups(ft, type);
235 err = fs_udp_add_default_rule(priv, type);
242 mlx5e_destroy_flow_table(ft);
246 static void fs_udp_destroy_table(struct mlx5e_fs_udp *fs_udp, int i)
248 if (IS_ERR_OR_NULL(fs_udp->tables[i].t))
251 mlx5_del_flow_rules(fs_udp->default_rules[i]);
252 mlx5e_destroy_flow_table(&fs_udp->tables[i]);
253 fs_udp->tables[i].t = NULL;
256 static int fs_udp_disable(struct mlx5e_priv *priv)
260 for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
261 /* Modify ttc rules destination to point back to the indir TIRs */
262 err = mlx5_ttc_fwd_default_dest(priv->fs.ttc, fs_udp2tt(i));
264 netdev_err(priv->netdev,
265 "%s: modify ttc[%d] default destination failed, err(%d)\n",
266 __func__, fs_udp2tt(i), err);
274 static int fs_udp_enable(struct mlx5e_priv *priv)
276 struct mlx5_flow_destination dest = {};
279 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
280 for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
281 dest.ft = priv->fs.udp->tables[i].t;
283 /* Modify ttc rules destination to point on the accel_fs FTs */
284 err = mlx5_ttc_fwd_dest(priv->fs.ttc, fs_udp2tt(i), &dest);
286 netdev_err(priv->netdev,
287 "%s: modify ttc[%d] destination to accel failed, err(%d)\n",
288 __func__, fs_udp2tt(i), err);
295 void mlx5e_fs_tt_redirect_udp_destroy(struct mlx5e_priv *priv)
297 struct mlx5e_fs_udp *fs_udp = priv->fs.udp;
303 if (--fs_udp->ref_cnt)
306 fs_udp_disable(priv);
308 for (i = 0; i < FS_UDP_NUM_TYPES; i++)
309 fs_udp_destroy_table(fs_udp, i);
315 int mlx5e_fs_tt_redirect_udp_create(struct mlx5e_priv *priv)
320 priv->fs.udp->ref_cnt++;
324 priv->fs.udp = kzalloc(sizeof(*priv->fs.udp), GFP_KERNEL);
328 for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
329 err = fs_udp_create_table(priv, i);
331 goto err_destroy_tables;
334 err = fs_udp_enable(priv);
336 goto err_destroy_tables;
338 priv->fs.udp->ref_cnt = 1;
344 fs_udp_destroy_table(priv->fs.udp, i);
351 static void fs_any_set_ethertype_flow(struct mlx5_flow_spec *spec, u16 ether_type)
353 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
354 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype);
355 MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ether_type);
358 struct mlx5_flow_handle *
359 mlx5e_fs_tt_redirect_any_add_rule(struct mlx5e_priv *priv,
360 u32 tir_num, u16 ether_type)
362 struct mlx5_flow_destination dest = {};
363 struct mlx5_flow_table *ft = NULL;
364 MLX5_DECLARE_FLOW_ACT(flow_act);
365 struct mlx5_flow_handle *rule;
366 struct mlx5_flow_spec *spec;
367 struct mlx5e_fs_any *fs_any;
370 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
372 return ERR_PTR(-ENOMEM);
374 fs_any = priv->fs.any;
375 ft = fs_any->table.t;
377 fs_any_set_ethertype_flow(spec, ether_type);
378 dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
379 dest.tir_num = tir_num;
381 rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
386 netdev_err(priv->netdev, "%s: add ANY rule failed, err %d\n",
392 static int fs_any_add_default_rule(struct mlx5e_priv *priv)
394 struct mlx5e_flow_table *fs_any_t;
395 struct mlx5_flow_destination dest;
396 MLX5_DECLARE_FLOW_ACT(flow_act);
397 struct mlx5_flow_handle *rule;
398 struct mlx5e_fs_any *fs_any;
401 fs_any = priv->fs.any;
402 fs_any_t = &fs_any->table;
404 dest = mlx5_ttc_get_default_dest(priv->fs.ttc, MLX5_TT_ANY);
405 rule = mlx5_add_flow_rules(fs_any_t->t, NULL, &flow_act, &dest, 1);
408 netdev_err(priv->netdev,
409 "%s: add default rule failed, fs type=ANY, err %d\n",
414 fs_any->default_rule = rule;
418 #define MLX5E_FS_ANY_NUM_GROUPS (2)
419 #define MLX5E_FS_ANY_GROUP1_SIZE (BIT(16))
420 #define MLX5E_FS_ANY_GROUP2_SIZE (BIT(0))
421 #define MLX5E_FS_ANY_TABLE_SIZE (MLX5E_FS_ANY_GROUP1_SIZE +\
422 MLX5E_FS_ANY_GROUP2_SIZE)
424 static int fs_any_create_groups(struct mlx5e_flow_table *ft)
426 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
427 void *outer_headers_c;
433 ft->g = kcalloc(MLX5E_FS_UDP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
434 in = kvzalloc(inlen, GFP_KERNEL);
441 /* Match on ethertype */
442 mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
443 outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
444 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ethertype);
445 MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
446 MLX5_SET_CFG(in, start_flow_index, ix);
447 ix += MLX5E_FS_ANY_GROUP1_SIZE;
448 MLX5_SET_CFG(in, end_flow_index, ix - 1);
449 ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
450 if (IS_ERR(ft->g[ft->num_groups]))
454 /* Default Flow Group */
455 memset(in, 0, inlen);
456 MLX5_SET_CFG(in, start_flow_index, ix);
457 ix += MLX5E_FS_ANY_GROUP2_SIZE;
458 MLX5_SET_CFG(in, end_flow_index, ix - 1);
459 ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
460 if (IS_ERR(ft->g[ft->num_groups]))
468 err = PTR_ERR(ft->g[ft->num_groups]);
469 ft->g[ft->num_groups] = NULL;
475 static int fs_any_create_table(struct mlx5e_priv *priv)
477 struct mlx5e_flow_table *ft = &priv->fs.any->table;
478 struct mlx5_flow_table_attr ft_attr = {};
483 ft_attr.max_fte = MLX5E_FS_UDP_TABLE_SIZE;
484 ft_attr.level = MLX5E_FS_TT_ANY_FT_LEVEL;
485 ft_attr.prio = MLX5E_NIC_PRIO;
487 ft->t = mlx5_create_flow_table(priv->fs.ns, &ft_attr);
489 err = PTR_ERR(ft->t);
494 netdev_dbg(priv->netdev, "Created fs ANY table id %u level %u\n",
495 ft->t->id, ft->t->level);
497 err = fs_any_create_groups(ft);
501 err = fs_any_add_default_rule(priv);
508 mlx5e_destroy_flow_table(ft);
512 static int fs_any_disable(struct mlx5e_priv *priv)
516 /* Modify ttc rules destination to point back to the indir TIRs */
517 err = mlx5_ttc_fwd_default_dest(priv->fs.ttc, MLX5_TT_ANY);
519 netdev_err(priv->netdev,
520 "%s: modify ttc[%d] default destination failed, err(%d)\n",
521 __func__, MLX5_TT_ANY, err);
527 static int fs_any_enable(struct mlx5e_priv *priv)
529 struct mlx5_flow_destination dest = {};
532 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
533 dest.ft = priv->fs.any->table.t;
535 /* Modify ttc rules destination to point on the accel_fs FTs */
536 err = mlx5_ttc_fwd_dest(priv->fs.ttc, MLX5_TT_ANY, &dest);
538 netdev_err(priv->netdev,
539 "%s: modify ttc[%d] destination to accel failed, err(%d)\n",
540 __func__, MLX5_TT_ANY, err);
546 static void fs_any_destroy_table(struct mlx5e_fs_any *fs_any)
548 if (IS_ERR_OR_NULL(fs_any->table.t))
551 mlx5_del_flow_rules(fs_any->default_rule);
552 mlx5e_destroy_flow_table(&fs_any->table);
553 fs_any->table.t = NULL;
556 void mlx5e_fs_tt_redirect_any_destroy(struct mlx5e_priv *priv)
558 struct mlx5e_fs_any *fs_any = priv->fs.any;
563 if (--fs_any->ref_cnt)
566 fs_any_disable(priv);
568 fs_any_destroy_table(fs_any);
574 int mlx5e_fs_tt_redirect_any_create(struct mlx5e_priv *priv)
579 priv->fs.any->ref_cnt++;
583 priv->fs.any = kzalloc(sizeof(*priv->fs.any), GFP_KERNEL);
587 err = fs_any_create_table(priv);
591 err = fs_any_enable(priv);
593 goto err_destroy_table;
595 priv->fs.any->ref_cnt = 1;
600 fs_any_destroy_table(priv->fs.any);