Skip to content

Commit 066d49c

Browse files
Cosmin Ratiukuba-moo
Cosmin Ratiu
authored andcommitted
net/mlx5e: CT: Offload connections with hardware steering rules
This is modeled similar to how software steering works: - a reference-counted matcher is maintained for each combination of nat/no_nat x ipv4/ipv6 x tcp/udp/gre. - adding a rule involves finding+referencing or creating a corresponding matcher, then actually adding a rule. - updating rules is implemented using the bwc_rule update API, which can change a rule's actions without touching the match value. By using a T-Rex traffic generator to initiate multi-million UDP flows per second, a kernel running with these patches on the RX side was able to offload ~600K flows per second, which is about ~7x larger than what software steering could do on the same hardware (256-thread AMD EPYC, 512 GB RAM, ConnectX-7 b2b). Signed-off-by: Cosmin Ratiu <[email protected]> Reviewed-by: Jianbo Liu <[email protected]> Signed-off-by: Tariq Toukan <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 554f977 commit 066d49c

File tree

1 file changed

+247
-2
lines changed

1 file changed

+247
-2
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_hmfs.c

+247-2
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,276 @@
33

44
#include "en_tc.h"
55
#include "en/tc_ct.h"
6+
#include "en/tc_priv.h"
67
#include "en/tc/ct_fs.h"
8+
#include "fs_core.h"
9+
#include "steering/hws/fs_hws_pools.h"
10+
#include "steering/hws/mlx5hws.h"
11+
#include "steering/hws/table.h"
12+
13+
struct mlx5_ct_fs_hmfs_matcher {
14+
struct mlx5hws_bwc_matcher *hws_bwc_matcher;
15+
refcount_t ref;
16+
};
17+
18+
/* We need {ipv4, ipv6} x {tcp, udp, gre} matchers. */
19+
#define NUM_MATCHERS (2 * 3)
20+
21+
struct mlx5_ct_fs_hmfs {
22+
struct mlx5hws_table *ct_tbl;
23+
struct mlx5hws_table *ct_nat_tbl;
24+
struct mlx5_flow_table *ct_nat;
25+
struct mlx5hws_action *fwd_action;
26+
struct mlx5hws_action *last_action;
27+
struct mlx5hws_context *ctx;
28+
struct mutex lock; /* Guards matchers */
29+
struct mlx5_ct_fs_hmfs_matcher matchers[NUM_MATCHERS];
30+
struct mlx5_ct_fs_hmfs_matcher matchers_nat[NUM_MATCHERS];
31+
};
32+
33+
struct mlx5_ct_fs_hmfs_rule {
34+
struct mlx5_ct_fs_rule fs_rule;
35+
struct mlx5hws_bwc_rule *hws_bwc_rule;
36+
struct mlx5_ct_fs_hmfs_matcher *hmfs_matcher;
37+
struct mlx5_fc *counter;
38+
};
39+
40+
static u32 get_matcher_idx(bool ipv4, bool tcp, bool gre)
41+
{
42+
return ipv4 * 3 + tcp * 2 + gre;
43+
}
744

845
static int mlx5_ct_fs_hmfs_init(struct mlx5_ct_fs *fs, struct mlx5_flow_table *ct,
946
struct mlx5_flow_table *ct_nat, struct mlx5_flow_table *post_ct)
1047
{
48+
u32 flags = MLX5HWS_ACTION_FLAG_HWS_FDB | MLX5HWS_ACTION_FLAG_SHARED;
49+
struct mlx5hws_table *ct_tbl, *ct_nat_tbl, *post_ct_tbl;
50+
struct mlx5_ct_fs_hmfs *fs_hmfs = mlx5_ct_fs_priv(fs);
51+
52+
ct_tbl = ct->fs_hws_table.hws_table;
53+
ct_nat_tbl = ct_nat->fs_hws_table.hws_table;
54+
post_ct_tbl = post_ct->fs_hws_table.hws_table;
55+
fs_hmfs->ct_nat = ct_nat;
56+
57+
if (!ct_tbl || !ct_nat_tbl || !post_ct_tbl) {
58+
netdev_warn(fs->netdev, "ct_fs_hmfs: failed to init, missing backing hws tables");
59+
return -EOPNOTSUPP;
60+
}
61+
62+
netdev_dbg(fs->netdev, "using hmfs steering");
63+
64+
fs_hmfs->ct_tbl = ct_tbl;
65+
fs_hmfs->ct_nat_tbl = ct_nat_tbl;
66+
fs_hmfs->ctx = ct_tbl->ctx;
67+
mutex_init(&fs_hmfs->lock);
68+
69+
fs_hmfs->fwd_action = mlx5hws_action_create_dest_table(ct_tbl->ctx, post_ct_tbl, flags);
70+
if (!fs_hmfs->fwd_action) {
71+
netdev_warn(fs->netdev, "ct_fs_hmfs: failed to create fwd action\n");
72+
return -EINVAL;
73+
}
74+
fs_hmfs->last_action = mlx5hws_action_create_last(ct_tbl->ctx, flags);
75+
if (!fs_hmfs->last_action) {
76+
netdev_warn(fs->netdev, "ct_fs_hmfs: failed to create last action\n");
77+
mlx5hws_action_destroy(fs_hmfs->fwd_action);
78+
return -EINVAL;
79+
}
80+
1181
return 0;
1282
}
1383

1484
static void mlx5_ct_fs_hmfs_destroy(struct mlx5_ct_fs *fs)
1585
{
86+
struct mlx5_ct_fs_hmfs *fs_hmfs = mlx5_ct_fs_priv(fs);
87+
88+
mlx5hws_action_destroy(fs_hmfs->last_action);
89+
mlx5hws_action_destroy(fs_hmfs->fwd_action);
90+
}
91+
92+
static struct mlx5hws_bwc_matcher *
93+
mlx5_ct_fs_hmfs_matcher_create(struct mlx5_ct_fs *fs, struct mlx5hws_table *tbl,
94+
struct mlx5_flow_spec *spec, bool ipv4, bool tcp, bool gre)
95+
{
96+
u8 match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2 | MLX5_MATCH_OUTER_HEADERS;
97+
struct mlx5hws_match_parameters mask = {
98+
.match_buf = spec->match_criteria,
99+
.match_sz = sizeof(spec->match_criteria),
100+
};
101+
u32 priority = get_matcher_idx(ipv4, tcp, gre); /* Static priority based on params. */
102+
struct mlx5hws_bwc_matcher *hws_bwc_matcher;
103+
104+
hws_bwc_matcher = mlx5hws_bwc_matcher_create(tbl, priority, match_criteria_enable, &mask);
105+
if (!hws_bwc_matcher)
106+
return ERR_PTR(-EINVAL);
107+
108+
return hws_bwc_matcher;
109+
}
110+
111+
static struct mlx5_ct_fs_hmfs_matcher *
112+
mlx5_ct_fs_hmfs_matcher_get(struct mlx5_ct_fs *fs, struct mlx5_flow_spec *spec,
113+
bool nat, bool ipv4, bool tcp, bool gre)
114+
{
115+
struct mlx5_ct_fs_hmfs *fs_hmfs = mlx5_ct_fs_priv(fs);
116+
u32 matcher_idx = get_matcher_idx(ipv4, tcp, gre);
117+
struct mlx5_ct_fs_hmfs_matcher *hmfs_matcher;
118+
struct mlx5hws_bwc_matcher *hws_bwc_matcher;
119+
struct mlx5hws_table *tbl;
120+
121+
hmfs_matcher = nat ?
122+
(fs_hmfs->matchers_nat + matcher_idx) :
123+
(fs_hmfs->matchers + matcher_idx);
124+
125+
if (refcount_inc_not_zero(&hmfs_matcher->ref))
126+
return hmfs_matcher;
127+
128+
mutex_lock(&fs_hmfs->lock);
129+
130+
/* Retry with lock, as the matcher might be already created by another cpu. */
131+
if (refcount_inc_not_zero(&hmfs_matcher->ref))
132+
goto out_unlock;
133+
134+
tbl = nat ? fs_hmfs->ct_nat_tbl : fs_hmfs->ct_tbl;
135+
136+
hws_bwc_matcher = mlx5_ct_fs_hmfs_matcher_create(fs, tbl, spec, ipv4, tcp, gre);
137+
if (IS_ERR(hws_bwc_matcher)) {
138+
netdev_warn(fs->netdev,
139+
"ct_fs_hmfs: failed to create bwc matcher (nat %d, ipv4 %d, tcp %d, gre %d), err: %ld\n",
140+
nat, ipv4, tcp, gre, PTR_ERR(hws_bwc_matcher));
141+
142+
hmfs_matcher = ERR_CAST(hws_bwc_matcher);
143+
goto out_unlock;
144+
}
145+
146+
hmfs_matcher->hws_bwc_matcher = hws_bwc_matcher;
147+
refcount_set(&hmfs_matcher->ref, 1);
148+
149+
out_unlock:
150+
mutex_unlock(&fs_hmfs->lock);
151+
return hmfs_matcher;
152+
}
153+
154+
static void
155+
mlx5_ct_fs_hmfs_matcher_put(struct mlx5_ct_fs *fs, struct mlx5_ct_fs_hmfs_matcher *hmfs_matcher)
156+
{
157+
struct mlx5_ct_fs_hmfs *fs_hmfs = mlx5_ct_fs_priv(fs);
158+
159+
if (!refcount_dec_and_mutex_lock(&hmfs_matcher->ref, &fs_hmfs->lock))
160+
return;
161+
162+
mlx5hws_bwc_matcher_destroy(hmfs_matcher->hws_bwc_matcher);
163+
mutex_unlock(&fs_hmfs->lock);
164+
}
165+
166+
#define NUM_CT_HMFS_RULES 4
167+
168+
static void mlx5_ct_fs_hmfs_fill_rule_actions(struct mlx5_ct_fs_hmfs *fs_hmfs,
169+
struct mlx5_flow_attr *attr,
170+
struct mlx5hws_rule_action *rule_actions)
171+
{
172+
struct mlx5_fs_hws_action *mh_action = &attr->modify_hdr->fs_hws_action;
173+
174+
memset(rule_actions, 0, NUM_CT_HMFS_RULES * sizeof(*rule_actions));
175+
rule_actions[0].action = mlx5_fc_get_hws_action(fs_hmfs->ctx, attr->counter);
176+
/* Modify header is special, it may require extra arguments outside the action itself. */
177+
if (mh_action->mh_data) {
178+
rule_actions[1].modify_header.offset = mh_action->mh_data->offset;
179+
rule_actions[1].modify_header.data = mh_action->mh_data->data;
180+
}
181+
rule_actions[1].action = mh_action->hws_action;
182+
rule_actions[2].action = fs_hmfs->fwd_action;
183+
rule_actions[3].action = fs_hmfs->last_action;
16184
}
17185

18186
static struct mlx5_ct_fs_rule *
19187
mlx5_ct_fs_hmfs_ct_rule_add(struct mlx5_ct_fs *fs, struct mlx5_flow_spec *spec,
20188
struct mlx5_flow_attr *attr, struct flow_rule *flow_rule)
21189
{
22-
return ERR_PTR(-EOPNOTSUPP);
190+
struct mlx5hws_rule_action rule_actions[NUM_CT_HMFS_RULES];
191+
struct mlx5_ct_fs_hmfs *fs_hmfs = mlx5_ct_fs_priv(fs);
192+
struct mlx5hws_match_parameters match_params = {
193+
.match_buf = spec->match_value,
194+
.match_sz = ARRAY_SIZE(spec->match_value),
195+
};
196+
struct mlx5_ct_fs_hmfs_matcher *hmfs_matcher;
197+
struct mlx5_ct_fs_hmfs_rule *hmfs_rule;
198+
bool nat, tcp, ipv4, gre;
199+
int err;
200+
201+
if (!mlx5e_tc_ct_is_valid_flow_rule(fs->netdev, flow_rule))
202+
return ERR_PTR(-EOPNOTSUPP);
203+
204+
hmfs_rule = kzalloc(sizeof(*hmfs_rule), GFP_KERNEL);
205+
if (!hmfs_rule)
206+
return ERR_PTR(-ENOMEM);
207+
208+
nat = (attr->ft == fs_hmfs->ct_nat);
209+
ipv4 = mlx5e_tc_get_ip_version(spec, true) == 4;
210+
tcp = MLX5_GET(fte_match_param, spec->match_value,
211+
outer_headers.ip_protocol) == IPPROTO_TCP;
212+
gre = MLX5_GET(fte_match_param, spec->match_value,
213+
outer_headers.ip_protocol) == IPPROTO_GRE;
214+
215+
hmfs_matcher = mlx5_ct_fs_hmfs_matcher_get(fs, spec, nat, ipv4, tcp, gre);
216+
if (IS_ERR(hmfs_matcher)) {
217+
err = PTR_ERR(hmfs_matcher);
218+
goto err_free_rule;
219+
}
220+
hmfs_rule->hmfs_matcher = hmfs_matcher;
221+
222+
mlx5_ct_fs_hmfs_fill_rule_actions(fs_hmfs, attr, rule_actions);
223+
hmfs_rule->counter = attr->counter;
224+
225+
hmfs_rule->hws_bwc_rule =
226+
mlx5hws_bwc_rule_create(hmfs_matcher->hws_bwc_matcher, &match_params,
227+
spec->flow_context.flow_source, rule_actions);
228+
if (!hmfs_rule->hws_bwc_rule) {
229+
err = -EINVAL;
230+
goto err_put_matcher;
231+
}
232+
233+
return &hmfs_rule->fs_rule;
234+
235+
err_put_matcher:
236+
mlx5_fc_put_hws_action(hmfs_rule->counter);
237+
mlx5_ct_fs_hmfs_matcher_put(fs, hmfs_matcher);
238+
err_free_rule:
239+
kfree(hmfs_rule);
240+
return ERR_PTR(err);
23241
}
24242

25243
static void mlx5_ct_fs_hmfs_ct_rule_del(struct mlx5_ct_fs *fs, struct mlx5_ct_fs_rule *fs_rule)
26244
{
245+
struct mlx5_ct_fs_hmfs_rule *hmfs_rule = container_of(fs_rule,
246+
struct mlx5_ct_fs_hmfs_rule,
247+
fs_rule);
248+
mlx5hws_bwc_rule_destroy(hmfs_rule->hws_bwc_rule);
249+
mlx5_fc_put_hws_action(hmfs_rule->counter);
250+
mlx5_ct_fs_hmfs_matcher_put(fs, hmfs_rule->hmfs_matcher);
251+
kfree(hmfs_rule);
27252
}
28253

29254
static int mlx5_ct_fs_hmfs_ct_rule_update(struct mlx5_ct_fs *fs, struct mlx5_ct_fs_rule *fs_rule,
30255
struct mlx5_flow_spec *spec, struct mlx5_flow_attr *attr)
31256
{
32-
return -EOPNOTSUPP;
257+
struct mlx5_ct_fs_hmfs_rule *hmfs_rule = container_of(fs_rule,
258+
struct mlx5_ct_fs_hmfs_rule,
259+
fs_rule);
260+
struct mlx5hws_rule_action rule_actions[NUM_CT_HMFS_RULES];
261+
struct mlx5_ct_fs_hmfs *fs_hmfs = mlx5_ct_fs_priv(fs);
262+
int err;
263+
264+
mlx5_ct_fs_hmfs_fill_rule_actions(fs_hmfs, attr, rule_actions);
265+
266+
err = mlx5hws_bwc_rule_action_update(hmfs_rule->hws_bwc_rule, rule_actions);
267+
if (err) {
268+
mlx5_fc_put_hws_action(attr->counter);
269+
return err;
270+
}
271+
272+
mlx5_fc_put_hws_action(hmfs_rule->counter);
273+
hmfs_rule->counter = attr->counter;
274+
275+
return 0;
33276
}
34277

35278
static struct mlx5_ct_fs_ops hmfs_ops = {
@@ -39,6 +282,8 @@ static struct mlx5_ct_fs_ops hmfs_ops = {
39282

40283
.init = mlx5_ct_fs_hmfs_init,
41284
.destroy = mlx5_ct_fs_hmfs_destroy,
285+
286+
.priv_size = sizeof(struct mlx5_ct_fs_hmfs),
42287
};
43288

44289
struct mlx5_ct_fs_ops *mlx5_ct_fs_hmfs_ops_get(void)

0 commit comments

Comments
 (0)