Skip to content

Commit 8da202b

Browse files
Huy NguyenSaeed Mahameed
authored andcommitted
net/mlx5: E-Switch, Add support for VEPA in legacy mode.
In Virtual Ethernet Port Aggregator (VEPA) mode, the packet skips the system internal virtual switch and forwards to external network switch. In Mellanox HCA case, the virtual switch is the HCA's Eswitch. To support this, an new FDB flow table are created with level 0 and linked to the existing FDB flow table in legacy mode. By default, VEPA is turned off and this FDB flow table is empty. When VEPA is turned on, two rules are created. One rule to forward on uplink vport traffic to the legacy FDB. The other rule forward all other traffic to uplink vport. Other design alternatives were not chosen as explained below: 1. Create a forward rule in ACL flow table (most efficient design). This approach is the not chosen because firmware does not support forward rule to uplink vport (0xffff) for ACL flow table. 2. Add additional source port criteria in all the FDB rules to make the FDB rules to be received rules only. This approach is not chosen because it is not efficient as there can many rules in the FDB and VEPA mode cannot be controlled per vport. 3. Add a highest prioirty flow group in the existing legacy FDB Flow Table instead of a new flow table. This approoach does not work because the new flow group has the same match criteria as the promiscuous flow group and mlx5_add_flow_rules does not allow specifying flow group. Signed-off-by: Huy Nguyen <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 2e5b053 commit 8da202b

File tree

2 files changed

+207
-21
lines changed

2 files changed

+207
-21
lines changed

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

Lines changed: 202 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ enum {
6464
PROMISC_CHANGE = BIT(3),
6565
};
6666

67+
static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw);
68+
static void esw_cleanup_vepa_rules(struct mlx5_eswitch *esw);
69+
6770
/* Vport context events */
6871
#define SRIOV_VPORT_EVENTS (UC_ADDR_CHANGE | \
6972
MC_ADDR_CHANGE | \
@@ -268,6 +271,37 @@ esw_fdb_set_vport_promisc_rule(struct mlx5_eswitch *esw, u16 vport)
268271
return __esw_fdb_set_vport_rule(esw, vport, true, mac_c, mac_v);
269272
}
270273

274+
enum {
275+
LEGACY_VEPA_PRIO = 0,
276+
LEGACY_FDB_PRIO,
277+
};
278+
279+
static int esw_create_legacy_vepa_table(struct mlx5_eswitch *esw)
280+
{
281+
struct mlx5_core_dev *dev = esw->dev;
282+
struct mlx5_flow_namespace *root_ns;
283+
struct mlx5_flow_table *fdb;
284+
int err;
285+
286+
root_ns = mlx5_get_fdb_sub_ns(dev, 0);
287+
if (!root_ns) {
288+
esw_warn(dev, "Failed to get FDB flow namespace\n");
289+
return -EOPNOTSUPP;
290+
}
291+
292+
/* num FTE 2, num FG 2 */
293+
fdb = mlx5_create_auto_grouped_flow_table(root_ns, LEGACY_VEPA_PRIO,
294+
2, 2, 0, 0);
295+
if (IS_ERR(fdb)) {
296+
err = PTR_ERR(fdb);
297+
esw_warn(dev, "Failed to create VEPA FDB err %d\n", err);
298+
return err;
299+
}
300+
esw->fdb_table.legacy.vepa_fdb = fdb;
301+
302+
return 0;
303+
}
304+
271305
static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
272306
{
273307
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
@@ -296,8 +330,8 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
296330
return -ENOMEM;
297331

298332
table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
299-
300333
ft_attr.max_fte = table_size;
334+
ft_attr.prio = LEGACY_FDB_PRIO;
301335
fdb = mlx5_create_flow_table(root_ns, &ft_attr);
302336
if (IS_ERR(fdb)) {
303337
err = PTR_ERR(fdb);
@@ -356,41 +390,65 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
356390
esw->fdb_table.legacy.promisc_grp = g;
357391

358392
out:
359-
if (err) {
360-
if (!IS_ERR_OR_NULL(esw->fdb_table.legacy.allmulti_grp)) {
361-
mlx5_destroy_flow_group(esw->fdb_table.legacy.allmulti_grp);
362-
esw->fdb_table.legacy.allmulti_grp = NULL;
363-
}
364-
if (!IS_ERR_OR_NULL(esw->fdb_table.legacy.addr_grp)) {
365-
mlx5_destroy_flow_group(esw->fdb_table.legacy.addr_grp);
366-
esw->fdb_table.legacy.addr_grp = NULL;
367-
}
368-
if (!IS_ERR_OR_NULL(esw->fdb_table.legacy.fdb)) {
369-
mlx5_destroy_flow_table(esw->fdb_table.legacy.fdb);
370-
esw->fdb_table.legacy.fdb = NULL;
371-
}
372-
}
393+
if (err)
394+
esw_destroy_legacy_fdb_table(esw);
373395

374396
kvfree(flow_group_in);
375397
return err;
376398
}
377399

400+
static void esw_destroy_legacy_vepa_table(struct mlx5_eswitch *esw)
401+
{
402+
esw_debug(esw->dev, "Destroy VEPA Table\n");
403+
if (!esw->fdb_table.legacy.vepa_fdb)
404+
return;
405+
406+
mlx5_destroy_flow_table(esw->fdb_table.legacy.vepa_fdb);
407+
esw->fdb_table.legacy.vepa_fdb = NULL;
408+
}
409+
378410
static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw)
379411
{
412+
esw_debug(esw->dev, "Destroy FDB Table\n");
380413
if (!esw->fdb_table.legacy.fdb)
381414
return;
382415

383-
esw_debug(esw->dev, "Destroy FDB Table\n");
384-
mlx5_destroy_flow_group(esw->fdb_table.legacy.promisc_grp);
385-
mlx5_destroy_flow_group(esw->fdb_table.legacy.allmulti_grp);
386-
mlx5_destroy_flow_group(esw->fdb_table.legacy.addr_grp);
416+
if (esw->fdb_table.legacy.promisc_grp)
417+
mlx5_destroy_flow_group(esw->fdb_table.legacy.promisc_grp);
418+
if (esw->fdb_table.legacy.allmulti_grp)
419+
mlx5_destroy_flow_group(esw->fdb_table.legacy.allmulti_grp);
420+
if (esw->fdb_table.legacy.addr_grp)
421+
mlx5_destroy_flow_group(esw->fdb_table.legacy.addr_grp);
387422
mlx5_destroy_flow_table(esw->fdb_table.legacy.fdb);
423+
388424
esw->fdb_table.legacy.fdb = NULL;
389425
esw->fdb_table.legacy.addr_grp = NULL;
390426
esw->fdb_table.legacy.allmulti_grp = NULL;
391427
esw->fdb_table.legacy.promisc_grp = NULL;
392428
}
393429

430+
static int esw_create_legacy_table(struct mlx5_eswitch *esw)
431+
{
432+
int err;
433+
434+
err = esw_create_legacy_vepa_table(esw);
435+
if (err)
436+
return err;
437+
438+
err = esw_create_legacy_fdb_table(esw);
439+
if (err)
440+
esw_destroy_legacy_vepa_table(esw);
441+
442+
return err;
443+
}
444+
445+
static void esw_destroy_legacy_table(struct mlx5_eswitch *esw)
446+
{
447+
esw_cleanup_vepa_rules(esw);
448+
esw_destroy_legacy_fdb_table(esw);
449+
esw_destroy_legacy_vepa_table(esw);
450+
}
451+
394452
/* E-Switch vport UC/MC lists management */
395453
typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,
396454
struct vport_addr *vaddr);
@@ -1677,7 +1735,9 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
16771735
mlx5_lag_update(esw->dev);
16781736

16791737
if (mode == SRIOV_LEGACY) {
1680-
err = esw_create_legacy_fdb_table(esw);
1738+
err = esw_create_legacy_table(esw);
1739+
if (err)
1740+
goto abort;
16811741
} else {
16821742
mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
16831743
mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
@@ -1758,7 +1818,7 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
17581818
esw_destroy_tsar(esw);
17591819

17601820
if (esw->mode == SRIOV_LEGACY)
1761-
esw_destroy_legacy_fdb_table(esw);
1821+
esw_destroy_legacy_table(esw);
17621822
else if (esw->mode == SRIOV_OFFLOADS)
17631823
esw_offloads_cleanup(esw);
17641824

@@ -2041,6 +2101,127 @@ int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
20412101
return err;
20422102
}
20432103

2104+
static void esw_cleanup_vepa_rules(struct mlx5_eswitch *esw)
2105+
{
2106+
if (esw->fdb_table.legacy.vepa_uplink_rule)
2107+
mlx5_del_flow_rules(esw->fdb_table.legacy.vepa_uplink_rule);
2108+
2109+
if (esw->fdb_table.legacy.vepa_star_rule)
2110+
mlx5_del_flow_rules(esw->fdb_table.legacy.vepa_star_rule);
2111+
2112+
esw->fdb_table.legacy.vepa_uplink_rule = NULL;
2113+
esw->fdb_table.legacy.vepa_star_rule = NULL;
2114+
}
2115+
2116+
static int _mlx5_eswitch_set_vepa_locked(struct mlx5_eswitch *esw,
2117+
u8 setting)
2118+
{
2119+
struct mlx5_flow_destination dest = {};
2120+
struct mlx5_flow_act flow_act = {};
2121+
struct mlx5_flow_handle *flow_rule;
2122+
struct mlx5_flow_spec *spec;
2123+
int err = 0;
2124+
void *misc;
2125+
2126+
if (!setting) {
2127+
esw_cleanup_vepa_rules(esw);
2128+
return 0;
2129+
}
2130+
2131+
if (esw->fdb_table.legacy.vepa_uplink_rule)
2132+
return 0;
2133+
2134+
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
2135+
if (!spec)
2136+
return -ENOMEM;
2137+
2138+
/* Uplink rule forward uplink traffic to FDB */
2139+
misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
2140+
MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_UPLINK);
2141+
2142+
misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
2143+
MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
2144+
2145+
spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
2146+
dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
2147+
dest.ft = esw->fdb_table.legacy.fdb;
2148+
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2149+
flow_rule = mlx5_add_flow_rules(esw->fdb_table.legacy.vepa_fdb, spec,
2150+
&flow_act, &dest, 1);
2151+
if (IS_ERR(flow_rule)) {
2152+
err = PTR_ERR(flow_rule);
2153+
goto out;
2154+
} else {
2155+
esw->fdb_table.legacy.vepa_uplink_rule = flow_rule;
2156+
}
2157+
2158+
/* Star rule to forward all traffic to uplink vport */
2159+
memset(spec, 0, sizeof(*spec));
2160+
dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
2161+
dest.vport.num = MLX5_VPORT_UPLINK;
2162+
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2163+
flow_rule = mlx5_add_flow_rules(esw->fdb_table.legacy.vepa_fdb, spec,
2164+
&flow_act, &dest, 1);
2165+
if (IS_ERR(flow_rule)) {
2166+
err = PTR_ERR(flow_rule);
2167+
goto out;
2168+
} else {
2169+
esw->fdb_table.legacy.vepa_star_rule = flow_rule;
2170+
}
2171+
2172+
out:
2173+
kvfree(spec);
2174+
if (err)
2175+
esw_cleanup_vepa_rules(esw);
2176+
return err;
2177+
}
2178+
2179+
int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting)
2180+
{
2181+
int err = 0;
2182+
2183+
if (!esw)
2184+
return -EOPNOTSUPP;
2185+
2186+
if (!ESW_ALLOWED(esw))
2187+
return -EPERM;
2188+
2189+
mutex_lock(&esw->state_lock);
2190+
if (esw->mode != SRIOV_LEGACY) {
2191+
err = -EOPNOTSUPP;
2192+
goto out;
2193+
}
2194+
2195+
err = _mlx5_eswitch_set_vepa_locked(esw, setting);
2196+
2197+
out:
2198+
mutex_unlock(&esw->state_lock);
2199+
return err;
2200+
}
2201+
2202+
int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting)
2203+
{
2204+
int err = 0;
2205+
2206+
if (!esw)
2207+
return -EOPNOTSUPP;
2208+
2209+
if (!ESW_ALLOWED(esw))
2210+
return -EPERM;
2211+
2212+
mutex_lock(&esw->state_lock);
2213+
if (esw->mode != SRIOV_LEGACY) {
2214+
err = -EOPNOTSUPP;
2215+
goto out;
2216+
}
2217+
2218+
*setting = esw->fdb_table.legacy.vepa_uplink_rule ? 1 : 0;
2219+
2220+
out:
2221+
mutex_unlock(&esw->state_lock);
2222+
return err;
2223+
}
2224+
20442225
int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
20452226
int vport, bool setting)
20462227
{

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ struct mlx5_eswitch_fdb {
137137
struct mlx5_flow_group *addr_grp;
138138
struct mlx5_flow_group *allmulti_grp;
139139
struct mlx5_flow_group *promisc_grp;
140+
struct mlx5_flow_table *vepa_fdb;
141+
struct mlx5_flow_handle *vepa_uplink_rule;
142+
struct mlx5_flow_handle *vepa_star_rule;
140143
} legacy;
141144

142145
struct offloads_fdb {
@@ -242,6 +245,8 @@ int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
242245
int vport_num, bool setting);
243246
int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, int vport,
244247
u32 max_rate, u32 min_rate);
248+
int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting);
249+
int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting);
245250
int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
246251
int vport, struct ifla_vf_info *ivi);
247252
int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,

0 commit comments

Comments
 (0)