Skip to content

Commit 96e3268

Browse files
Eli CohenSaeed Mahameed
authored andcommitted
net/mlx5e: Eswitch, Use per vport tables for mirroring
When using port mirroring, we forward the traffic to another table and use that table to forward to the mirrored vport. Since the hardware loses the values of reg c, and in particular reg c0, we fail the match on the input vport which previously existed in reg c0. To overcome this situation, we use a set of per vport tables, positioned at the lowest priority, and forward traffic to those tables. Since these tables are per vport, we can avoid matching on reg c0. Fixes: c01cfd0 ("net/mlx5: E-Switch, Add match on vport metadata for rule in fast path") Signed-off-by: Eli Cohen <[email protected]> Reviewed-by: Mark Bloch <[email protected]> Reviewed-by: Paul Blakey <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 1708dd5 commit 96e3268

File tree

5 files changed

+221
-18
lines changed

5 files changed

+221
-18
lines changed

drivers/net/ethernet/mellanox/mlx5/core/eswitch.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949

5050
/* The index of the last real chain (FT) + 1 as chain zero is valid as well */
5151
#define FDB_NUM_CHAINS (FDB_FT_CHAIN + 1)
52+
#define ESW_OFFLOADS_NUM_GROUPS 4
5253

5354
#define FDB_TC_MAX_PRIO 16
5455
#define FDB_TC_LEVELS_PER_PRIO 2
@@ -183,6 +184,12 @@ struct mlx5_eswitch_fdb {
183184
int vlan_push_pop_refcount;
184185

185186
struct mlx5_esw_chains_priv *esw_chains_priv;
187+
struct {
188+
DECLARE_HASHTABLE(table, 8);
189+
/* Protects vports.table */
190+
struct mutex lock;
191+
} vports;
192+
186193
} offloads;
187194
};
188195
u32 flags;
@@ -623,6 +630,9 @@ void
623630
esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw,
624631
struct mlx5_vport *vport);
625632

633+
int mlx5_esw_vport_tbl_get(struct mlx5_eswitch *esw);
634+
void mlx5_esw_vport_tbl_put(struct mlx5_eswitch *esw);
635+
626636
#else /* CONFIG_MLX5_ESWITCH */
627637
/* eswitch API stubs */
628638
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }

drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c

Lines changed: 196 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,179 @@
5050
#define MLX5_ESW_MISS_FLOWS (2)
5151
#define UPLINK_REP_INDEX 0
5252

53+
/* Per vport tables */
54+
55+
#define MLX5_ESW_VPORT_TABLE_SIZE 128
56+
57+
/* This struct is used as a key to the hash table and we need it to be packed
58+
* so hash result is consistent
59+
*/
60+
struct mlx5_vport_key {
61+
u32 chain;
62+
u16 prio;
63+
u16 vport;
64+
u16 vhca_id;
65+
} __packed;
66+
67+
struct mlx5_vport_table {
68+
struct hlist_node hlist;
69+
struct mlx5_flow_table *fdb;
70+
u32 num_rules;
71+
struct mlx5_vport_key key;
72+
};
73+
74+
static struct mlx5_flow_table *
75+
esw_vport_tbl_create(struct mlx5_eswitch *esw, struct mlx5_flow_namespace *ns)
76+
{
77+
struct mlx5_flow_table_attr ft_attr = {};
78+
struct mlx5_flow_table *fdb;
79+
80+
ft_attr.autogroup.max_num_groups = ESW_OFFLOADS_NUM_GROUPS;
81+
ft_attr.max_fte = MLX5_ESW_VPORT_TABLE_SIZE;
82+
ft_attr.prio = FDB_PER_VPORT;
83+
fdb = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
84+
if (IS_ERR(fdb)) {
85+
esw_warn(esw->dev, "Failed to create per vport FDB Table err %ld\n",
86+
PTR_ERR(fdb));
87+
}
88+
89+
return fdb;
90+
}
91+
92+
static u32 flow_attr_to_vport_key(struct mlx5_eswitch *esw,
93+
struct mlx5_esw_flow_attr *attr,
94+
struct mlx5_vport_key *key)
95+
{
96+
key->vport = attr->in_rep->vport;
97+
key->chain = attr->chain;
98+
key->prio = attr->prio;
99+
key->vhca_id = MLX5_CAP_GEN(esw->dev, vhca_id);
100+
return jhash(key, sizeof(*key), 0);
101+
}
102+
103+
/* caller must hold vports.lock */
104+
static struct mlx5_vport_table *
105+
esw_vport_tbl_lookup(struct mlx5_eswitch *esw, struct mlx5_vport_key *skey, u32 key)
106+
{
107+
struct mlx5_vport_table *e;
108+
109+
hash_for_each_possible(esw->fdb_table.offloads.vports.table, e, hlist, key)
110+
if (!memcmp(&e->key, skey, sizeof(*skey)))
111+
return e;
112+
113+
return NULL;
114+
}
115+
116+
static void
117+
esw_vport_tbl_put(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *attr)
118+
{
119+
struct mlx5_vport_table *e;
120+
struct mlx5_vport_key key;
121+
u32 hkey;
122+
123+
mutex_lock(&esw->fdb_table.offloads.vports.lock);
124+
hkey = flow_attr_to_vport_key(esw, attr, &key);
125+
e = esw_vport_tbl_lookup(esw, &key, hkey);
126+
if (!e || --e->num_rules)
127+
goto out;
128+
129+
hash_del(&e->hlist);
130+
mlx5_destroy_flow_table(e->fdb);
131+
kfree(e);
132+
out:
133+
mutex_unlock(&esw->fdb_table.offloads.vports.lock);
134+
}
135+
136+
static struct mlx5_flow_table *
137+
esw_vport_tbl_get(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *attr)
138+
{
139+
struct mlx5_core_dev *dev = esw->dev;
140+
struct mlx5_flow_namespace *ns;
141+
struct mlx5_flow_table *fdb;
142+
struct mlx5_vport_table *e;
143+
struct mlx5_vport_key skey;
144+
u32 hkey;
145+
146+
mutex_lock(&esw->fdb_table.offloads.vports.lock);
147+
hkey = flow_attr_to_vport_key(esw, attr, &skey);
148+
e = esw_vport_tbl_lookup(esw, &skey, hkey);
149+
if (e) {
150+
e->num_rules++;
151+
goto out;
152+
}
153+
154+
e = kzalloc(sizeof(*e), GFP_KERNEL);
155+
if (!e) {
156+
fdb = ERR_PTR(-ENOMEM);
157+
goto err_alloc;
158+
}
159+
160+
ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
161+
if (!ns) {
162+
esw_warn(dev, "Failed to get FDB namespace\n");
163+
fdb = ERR_PTR(-ENOENT);
164+
goto err_ns;
165+
}
166+
167+
fdb = esw_vport_tbl_create(esw, ns);
168+
if (IS_ERR(fdb))
169+
goto err_ns;
170+
171+
e->fdb = fdb;
172+
e->num_rules = 1;
173+
e->key = skey;
174+
hash_add(esw->fdb_table.offloads.vports.table, &e->hlist, hkey);
175+
out:
176+
mutex_unlock(&esw->fdb_table.offloads.vports.lock);
177+
return e->fdb;
178+
179+
err_ns:
180+
kfree(e);
181+
err_alloc:
182+
mutex_unlock(&esw->fdb_table.offloads.vports.lock);
183+
return fdb;
184+
}
185+
186+
int mlx5_esw_vport_tbl_get(struct mlx5_eswitch *esw)
187+
{
188+
struct mlx5_esw_flow_attr attr = {};
189+
struct mlx5_eswitch_rep rep = {};
190+
struct mlx5_flow_table *fdb;
191+
struct mlx5_vport *vport;
192+
int i;
193+
194+
attr.prio = 1;
195+
attr.in_rep = &rep;
196+
mlx5_esw_for_all_vports(esw, i, vport) {
197+
attr.in_rep->vport = vport->vport;
198+
fdb = esw_vport_tbl_get(esw, &attr);
199+
if (!fdb)
200+
goto out;
201+
}
202+
return 0;
203+
204+
out:
205+
mlx5_esw_vport_tbl_put(esw);
206+
return PTR_ERR(fdb);
207+
}
208+
209+
void mlx5_esw_vport_tbl_put(struct mlx5_eswitch *esw)
210+
{
211+
struct mlx5_esw_flow_attr attr = {};
212+
struct mlx5_eswitch_rep rep = {};
213+
struct mlx5_vport *vport;
214+
int i;
215+
216+
attr.prio = 1;
217+
attr.in_rep = &rep;
218+
mlx5_esw_for_all_vports(esw, i, vport) {
219+
attr.in_rep->vport = vport->vport;
220+
esw_vport_tbl_put(esw, &attr);
221+
}
222+
}
223+
224+
/* End: Per vport tables */
225+
53226
static struct mlx5_eswitch_rep *mlx5_eswitch_get_rep(struct mlx5_eswitch *esw,
54227
u16 vport_num)
55228
{
@@ -191,8 +364,6 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
191364
i++;
192365
}
193366

194-
mlx5_eswitch_set_rule_source_port(esw, spec, attr);
195-
196367
if (attr->outer_match_level != MLX5_MATCH_NONE)
197368
spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
198369
if (attr->inner_match_level != MLX5_MATCH_NONE)
@@ -201,8 +372,13 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
201372
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
202373
flow_act.modify_hdr = attr->modify_hdr;
203374

204-
fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio,
205-
!!split);
375+
if (split) {
376+
fdb = esw_vport_tbl_get(esw, attr);
377+
} else {
378+
fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio,
379+
0);
380+
mlx5_eswitch_set_rule_source_port(esw, spec, attr);
381+
}
206382
if (IS_ERR(fdb)) {
207383
rule = ERR_CAST(fdb);
208384
goto err_esw_get;
@@ -221,7 +397,10 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
221397
return rule;
222398

223399
err_add_rule:
224-
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, !!split);
400+
if (split)
401+
esw_vport_tbl_put(esw, attr);
402+
else
403+
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 0);
225404
err_esw_get:
226405
if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH) && attr->dest_chain)
227406
mlx5_esw_chains_put_table(esw, attr->dest_chain, 1, 0);
@@ -247,7 +426,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
247426
goto err_get_fast;
248427
}
249428

250-
fwd_fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio, 1);
429+
fwd_fdb = esw_vport_tbl_get(esw, attr);
251430
if (IS_ERR(fwd_fdb)) {
252431
rule = ERR_CAST(fwd_fdb);
253432
goto err_get_fwd;
@@ -285,7 +464,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
285464

286465
return rule;
287466
add_err:
288-
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 1);
467+
esw_vport_tbl_put(esw, attr);
289468
err_get_fwd:
290469
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 0);
291470
err_get_fast:
@@ -312,11 +491,14 @@ __mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
312491
atomic64_dec(&esw->offloads.num_flows);
313492

314493
if (fwd_rule) {
315-
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 1);
494+
esw_vport_tbl_put(esw, attr);
316495
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 0);
317496
} else {
318-
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio,
319-
!!split);
497+
if (split)
498+
esw_vport_tbl_put(esw, attr);
499+
else
500+
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio,
501+
0);
320502
if (attr->dest_chain)
321503
mlx5_esw_chains_put_table(esw, attr->dest_chain, 1, 0);
322504
}
@@ -1923,6 +2105,9 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
19232105
if (err)
19242106
goto create_fg_err;
19252107

2108+
mutex_init(&esw->fdb_table.offloads.vports.lock);
2109+
hash_init(esw->fdb_table.offloads.vports.table);
2110+
19262111
return 0;
19272112

19282113
create_fg_err:
@@ -1939,6 +2124,7 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
19392124

19402125
static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
19412126
{
2127+
mutex_destroy(&esw->fdb_table.offloads.vports.lock);
19422128
esw_destroy_vport_rx_group(esw);
19432129
esw_destroy_offloads_table(esw);
19442130
esw_destroy_offloads_fdb_tables(esw);

drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
#define fdb_ignore_flow_level_supported(esw) \
2222
(MLX5_CAP_ESW_FLOWTABLE_FDB((esw)->dev, ignore_flow_level))
2323

24-
#define ESW_OFFLOADS_NUM_GROUPS 4
25-
2624
/* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS),
2725
* and a virtual memory region of 16M (ESW_SIZE), this region is duplicated
2826
* for each flow table pool. We can allocate up to 16M of each pool,
@@ -704,12 +702,9 @@ mlx5_esw_chains_open(struct mlx5_eswitch *esw)
704702

705703
/* Open level 1 for split rules now if prios isn't supported */
706704
if (!mlx5_esw_chains_prios_supported(esw)) {
707-
ft = mlx5_esw_chains_get_table(esw, 0, 1, 1);
708-
709-
if (IS_ERR(ft)) {
710-
err = PTR_ERR(ft);
705+
err = mlx5_esw_vport_tbl_get(esw);
706+
if (err)
711707
goto level_1_err;
712-
}
713708
}
714709

715710
return 0;
@@ -725,7 +720,7 @@ static void
725720
mlx5_esw_chains_close(struct mlx5_eswitch *esw)
726721
{
727722
if (!mlx5_esw_chains_prios_supported(esw))
728-
mlx5_esw_chains_put_table(esw, 0, 1, 1);
723+
mlx5_esw_vport_tbl_put(esw);
729724
mlx5_esw_chains_put_table(esw, 0, 1, 0);
730725
mlx5_esw_chains_put_table(esw, mlx5_esw_chains_get_ft_chain(esw), 1, 0);
731726
}

drivers/net/ethernet/mellanox/mlx5/core/fs_core.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2700,6 +2700,17 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
27002700
goto out_err;
27012701
}
27022702

2703+
/* We put this priority last, knowing that nothing will get here
2704+
* unless explicitly forwarded to. This is possible because the
2705+
* slow path tables have catch all rules and nothing gets passed
2706+
* those tables.
2707+
*/
2708+
maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_PER_VPORT, 1);
2709+
if (IS_ERR(maj_prio)) {
2710+
err = PTR_ERR(maj_prio);
2711+
goto out_err;
2712+
}
2713+
27032714
set_prio_attrs(steering->fdb_root_ns);
27042715
return 0;
27052716

include/linux/mlx5/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ enum {
8484
FDB_TC_OFFLOAD,
8585
FDB_FT_OFFLOAD,
8686
FDB_SLOW_PATH,
87+
FDB_PER_VPORT,
8788
};
8889

8990
struct mlx5_pkt_reformat;

0 commit comments

Comments
 (0)