Skip to content

Commit 1c80bd6

Browse files
ayalevinSaeed Mahameed
authored andcommitted
net/mlx5e: Introduce Flow Steering UDP API
Add a new FS API which captures the UDP traffic from the traffic classifier into a dedicated FS table. This API handles both UDP over IPv4 and IPv6 in the same manner. The tables (one for UDPv4 and another for UDPv6) consist of a group matching the UDP destination port and a must-be-last group which contains a default rule redirecting the unmatched packets back to the RSS logic. Signed-off-by: Aya Levin <[email protected]> Reviewed-by: Tariq Toukan <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent c809cf6 commit 1c80bd6

File tree

5 files changed

+368
-2
lines changed

5 files changed

+368
-2
lines changed

drivers/net/ethernet/mellanox/mlx5/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
2727
en_selftest.o en/port.o en/monitor_stats.o en/health.o \
2828
en/reporter_tx.o en/reporter_rx.o en/params.o en/xsk/pool.o \
2929
en/xsk/setup.o en/xsk/rx.o en/xsk/tx.o en/devlink.o en/ptp.o \
30-
en/qos.o en/trap.o
30+
en/qos.o en/trap.o en/fs_tt_redirect.o
3131

3232
#
3333
# Netdev extra

drivers/net/ethernet/mellanox/mlx5/core/en/fs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ enum {
137137
MLX5E_L2_FT_LEVEL,
138138
MLX5E_TTC_FT_LEVEL,
139139
MLX5E_INNER_TTC_FT_LEVEL,
140+
MLX5E_FS_TT_UDP_FT_LEVEL = MLX5E_INNER_TTC_FT_LEVEL + 1,
140141
#ifdef CONFIG_MLX5_EN_TLS
141142
MLX5E_ACCEL_FS_TCP_FT_LEVEL = MLX5E_INNER_TTC_FT_LEVEL + 1,
142143
#endif
@@ -241,6 +242,8 @@ static inline int mlx5e_arfs_disable(struct mlx5e_priv *priv) { return -EOPNOTSU
241242
struct mlx5e_accel_fs_tcp;
242243
#endif
243244

245+
struct mlx5e_fs_udp;
246+
244247
struct mlx5e_flow_steering {
245248
struct mlx5_flow_namespace *ns;
246249
struct mlx5_flow_namespace *egress_ns;
@@ -259,6 +262,7 @@ struct mlx5e_flow_steering {
259262
#ifdef CONFIG_MLX5_EN_TLS
260263
struct mlx5e_accel_fs_tcp *accel_tcp;
261264
#endif
265+
struct mlx5e_fs_udp *udp;
262266
};
263267

264268
struct ttc_params {
Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2+
/* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */
3+
4+
#include <linux/netdevice.h>
5+
#include "en/fs_tt_redirect.h"
6+
#include "fs_core.h"
7+
8+
enum fs_udp_type {
9+
FS_IPV4_UDP,
10+
FS_IPV6_UDP,
11+
FS_UDP_NUM_TYPES,
12+
};
13+
14+
struct mlx5e_fs_udp {
15+
struct mlx5e_flow_table tables[FS_UDP_NUM_TYPES];
16+
struct mlx5_flow_handle *default_rules[FS_UDP_NUM_TYPES];
17+
int ref_cnt;
18+
};
19+
20+
static char *fs_udp_type2str(enum fs_udp_type i)
21+
{
22+
switch (i) {
23+
case FS_IPV4_UDP:
24+
return "UDP v4";
25+
default: /* FS_IPV6_UDP */
26+
return "UDP v6";
27+
}
28+
}
29+
30+
static enum mlx5e_traffic_types fs_udp2tt(enum fs_udp_type i)
31+
{
32+
switch (i) {
33+
case FS_IPV4_UDP:
34+
return MLX5E_TT_IPV4_UDP;
35+
default: /* FS_IPV6_UDP */
36+
return MLX5E_TT_IPV6_UDP;
37+
}
38+
}
39+
40+
static enum fs_udp_type tt2fs_udp(enum mlx5e_traffic_types i)
41+
{
42+
switch (i) {
43+
case MLX5E_TT_IPV4_UDP:
44+
return FS_IPV4_UDP;
45+
case MLX5E_TT_IPV6_UDP:
46+
return FS_IPV6_UDP;
47+
default:
48+
return FS_UDP_NUM_TYPES;
49+
}
50+
}
51+
52+
void mlx5e_fs_tt_redirect_del_rule(struct mlx5_flow_handle *rule)
53+
{
54+
mlx5_del_flow_rules(rule);
55+
}
56+
57+
static void fs_udp_set_dport_flow(struct mlx5_flow_spec *spec, enum fs_udp_type type,
58+
u16 udp_dport)
59+
{
60+
spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
61+
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
62+
MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_UDP);
63+
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version);
64+
MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version,
65+
type == FS_IPV4_UDP ? 4 : 6);
66+
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.udp_dport);
67+
MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_dport, udp_dport);
68+
}
69+
70+
struct mlx5_flow_handle *
71+
mlx5e_fs_tt_redirect_udp_add_rule(struct mlx5e_priv *priv,
72+
enum mlx5e_traffic_types ttc_type,
73+
u32 tir_num, u16 d_port)
74+
{
75+
enum fs_udp_type type = tt2fs_udp(ttc_type);
76+
struct mlx5_flow_destination dest = {};
77+
struct mlx5_flow_table *ft = NULL;
78+
MLX5_DECLARE_FLOW_ACT(flow_act);
79+
struct mlx5_flow_handle *rule;
80+
struct mlx5_flow_spec *spec;
81+
struct mlx5e_fs_udp *fs_udp;
82+
int err;
83+
84+
if (type == FS_UDP_NUM_TYPES)
85+
return ERR_PTR(-EINVAL);
86+
87+
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
88+
if (!spec)
89+
return ERR_PTR(-ENOMEM);
90+
91+
fs_udp = priv->fs.udp;
92+
ft = fs_udp->tables[type].t;
93+
94+
fs_udp_set_dport_flow(spec, type, d_port);
95+
dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
96+
dest.tir_num = tir_num;
97+
98+
rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
99+
kvfree(spec);
100+
101+
if (IS_ERR(rule)) {
102+
err = PTR_ERR(rule);
103+
netdev_err(priv->netdev, "%s: add %s rule failed, err %d\n",
104+
__func__, fs_udp_type2str(type), err);
105+
}
106+
return rule;
107+
}
108+
109+
static int fs_udp_add_default_rule(struct mlx5e_priv *priv, enum fs_udp_type type)
110+
{
111+
struct mlx5e_flow_table *fs_udp_t;
112+
struct mlx5_flow_destination dest;
113+
MLX5_DECLARE_FLOW_ACT(flow_act);
114+
struct mlx5_flow_handle *rule;
115+
struct mlx5e_fs_udp *fs_udp;
116+
int err;
117+
118+
fs_udp = priv->fs.udp;
119+
fs_udp_t = &fs_udp->tables[type];
120+
121+
dest = mlx5e_ttc_get_default_dest(priv, fs_udp2tt(type));
122+
rule = mlx5_add_flow_rules(fs_udp_t->t, NULL, &flow_act, &dest, 1);
123+
if (IS_ERR(rule)) {
124+
err = PTR_ERR(rule);
125+
netdev_err(priv->netdev,
126+
"%s: add default rule failed, fs type=%d, err %d\n",
127+
__func__, type, err);
128+
return err;
129+
}
130+
131+
fs_udp->default_rules[type] = rule;
132+
return 0;
133+
}
134+
135+
#define MLX5E_FS_UDP_NUM_GROUPS (2)
136+
#define MLX5E_FS_UDP_GROUP1_SIZE (BIT(16))
137+
#define MLX5E_FS_UDP_GROUP2_SIZE (BIT(0))
138+
#define MLX5E_FS_UDP_TABLE_SIZE (MLX5E_FS_UDP_GROUP1_SIZE +\
139+
MLX5E_FS_UDP_GROUP2_SIZE)
140+
static int fs_udp_create_groups(struct mlx5e_flow_table *ft, enum fs_udp_type type)
141+
{
142+
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
143+
void *outer_headers_c;
144+
int ix = 0;
145+
u32 *in;
146+
int err;
147+
u8 *mc;
148+
149+
ft->g = kcalloc(MLX5E_FS_UDP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
150+
in = kvzalloc(inlen, GFP_KERNEL);
151+
if (!in || !ft->g) {
152+
kfree(ft->g);
153+
kvfree(in);
154+
return -ENOMEM;
155+
}
156+
157+
mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
158+
outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
159+
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
160+
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_version);
161+
162+
switch (type) {
163+
case FS_IPV4_UDP:
164+
case FS_IPV6_UDP:
165+
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport);
166+
break;
167+
default:
168+
err = -EINVAL;
169+
goto out;
170+
}
171+
/* Match on udp protocol, Ipv4/6 and dport */
172+
MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
173+
MLX5_SET_CFG(in, start_flow_index, ix);
174+
ix += MLX5E_FS_UDP_GROUP1_SIZE;
175+
MLX5_SET_CFG(in, end_flow_index, ix - 1);
176+
ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
177+
if (IS_ERR(ft->g[ft->num_groups]))
178+
goto err;
179+
ft->num_groups++;
180+
181+
/* Default Flow Group */
182+
memset(in, 0, inlen);
183+
MLX5_SET_CFG(in, start_flow_index, ix);
184+
ix += MLX5E_FS_UDP_GROUP2_SIZE;
185+
MLX5_SET_CFG(in, end_flow_index, ix - 1);
186+
ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
187+
if (IS_ERR(ft->g[ft->num_groups]))
188+
goto err;
189+
ft->num_groups++;
190+
191+
kvfree(in);
192+
return 0;
193+
194+
err:
195+
err = PTR_ERR(ft->g[ft->num_groups]);
196+
ft->g[ft->num_groups] = NULL;
197+
out:
198+
kvfree(in);
199+
200+
return err;
201+
}
202+
203+
static int fs_udp_create_table(struct mlx5e_priv *priv, enum fs_udp_type type)
204+
{
205+
struct mlx5e_flow_table *ft = &priv->fs.udp->tables[type];
206+
struct mlx5_flow_table_attr ft_attr = {};
207+
int err;
208+
209+
ft->num_groups = 0;
210+
211+
ft_attr.max_fte = MLX5E_FS_UDP_TABLE_SIZE;
212+
ft_attr.level = MLX5E_FS_TT_UDP_FT_LEVEL;
213+
ft_attr.prio = MLX5E_NIC_PRIO;
214+
215+
ft->t = mlx5_create_flow_table(priv->fs.ns, &ft_attr);
216+
if (IS_ERR(ft->t)) {
217+
err = PTR_ERR(ft->t);
218+
ft->t = NULL;
219+
return err;
220+
}
221+
222+
netdev_dbg(priv->netdev, "Created fs %s table id %u level %u\n",
223+
fs_udp_type2str(type), ft->t->id, ft->t->level);
224+
225+
err = fs_udp_create_groups(ft, type);
226+
if (err)
227+
goto err;
228+
229+
err = fs_udp_add_default_rule(priv, type);
230+
if (err)
231+
goto err;
232+
233+
return 0;
234+
235+
err:
236+
mlx5e_destroy_flow_table(ft);
237+
return err;
238+
}
239+
240+
static void fs_udp_destroy_table(struct mlx5e_fs_udp *fs_udp, int i)
241+
{
242+
if (IS_ERR_OR_NULL(fs_udp->tables[i].t))
243+
return;
244+
245+
mlx5_del_flow_rules(fs_udp->default_rules[i]);
246+
mlx5e_destroy_flow_table(&fs_udp->tables[i]);
247+
fs_udp->tables[i].t = NULL;
248+
}
249+
250+
static int fs_udp_disable(struct mlx5e_priv *priv)
251+
{
252+
int err, i;
253+
254+
for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
255+
/* Modify ttc rules destination to point back to the indir TIRs */
256+
err = mlx5e_ttc_fwd_default_dest(priv, fs_udp2tt(i));
257+
if (err) {
258+
netdev_err(priv->netdev,
259+
"%s: modify ttc[%d] default destination failed, err(%d)\n",
260+
__func__, fs_udp2tt(i), err);
261+
return err;
262+
}
263+
}
264+
265+
return 0;
266+
}
267+
268+
static int fs_udp_enable(struct mlx5e_priv *priv)
269+
{
270+
struct mlx5_flow_destination dest = {};
271+
int err, i;
272+
273+
dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
274+
for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
275+
dest.ft = priv->fs.udp->tables[i].t;
276+
277+
/* Modify ttc rules destination to point on the accel_fs FTs */
278+
err = mlx5e_ttc_fwd_dest(priv, fs_udp2tt(i), &dest);
279+
if (err) {
280+
netdev_err(priv->netdev,
281+
"%s: modify ttc[%d] destination to accel failed, err(%d)\n",
282+
__func__, fs_udp2tt(i), err);
283+
return err;
284+
}
285+
}
286+
return 0;
287+
}
288+
289+
void mlx5e_fs_tt_redirect_udp_destroy(struct mlx5e_priv *priv)
290+
{
291+
struct mlx5e_fs_udp *fs_udp = priv->fs.udp;
292+
int i;
293+
294+
if (!fs_udp)
295+
return;
296+
297+
if (--fs_udp->ref_cnt)
298+
return;
299+
300+
fs_udp_disable(priv);
301+
302+
for (i = 0; i < FS_UDP_NUM_TYPES; i++)
303+
fs_udp_destroy_table(fs_udp, i);
304+
305+
kfree(fs_udp);
306+
priv->fs.udp = NULL;
307+
}
308+
309+
int mlx5e_fs_tt_redirect_udp_create(struct mlx5e_priv *priv)
310+
{
311+
int i, err;
312+
313+
if (priv->fs.udp) {
314+
priv->fs.udp->ref_cnt++;
315+
return 0;
316+
}
317+
318+
priv->fs.udp = kzalloc(sizeof(*priv->fs.udp), GFP_KERNEL);
319+
if (!priv->fs.udp)
320+
return -ENOMEM;
321+
322+
for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
323+
err = fs_udp_create_table(priv, i);
324+
if (err)
325+
goto err_destroy_tables;
326+
}
327+
328+
err = fs_udp_enable(priv);
329+
if (err)
330+
goto err_destroy_tables;
331+
332+
priv->fs.udp->ref_cnt = 1;
333+
334+
return 0;
335+
336+
err_destroy_tables:
337+
while (--i >= 0)
338+
fs_udp_destroy_table(priv->fs.udp, i);
339+
340+
kfree(priv->fs.udp);
341+
priv->fs.udp = NULL;
342+
return err;
343+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+
/* Copyright (c) 2021 Mellanox Technologies. */
3+
4+
#ifndef __MLX5E_FS_TT_REDIRECT_H__
5+
#define __MLX5E_FS_TT_REDIRECT_H__
6+
7+
#include "en.h"
8+
#include "en/fs.h"
9+
10+
void mlx5e_fs_tt_redirect_del_rule(struct mlx5_flow_handle *rule);
11+
12+
/* UDP traffic type redirect */
13+
struct mlx5_flow_handle *
14+
mlx5e_fs_tt_redirect_udp_add_rule(struct mlx5e_priv *priv,
15+
enum mlx5e_traffic_types ttc_type,
16+
u32 tir_num, u16 d_port);
17+
void mlx5e_fs_tt_redirect_udp_destroy(struct mlx5e_priv *priv);
18+
int mlx5e_fs_tt_redirect_udp_create(struct mlx5e_priv *priv);
19+
#endif

0 commit comments

Comments
 (0)