Skip to content

Commit ff9b752

Browse files
w1ldptrSaeed Mahameed
authored and
Saeed Mahameed
committed
net/mlx5: Bridge, support LAG
Allow adding bond net devices to mlx5 bridge with following changes: - Modify bridge representor code to obtain uplink represetor that belongs to eswitch that is registered for notification. Require representor to be in shared FDB mode. If representor is the lag master, then consider its port as local, otherwise treat it as peer. - Use devcom to match on paired eswitch metadata in peer FDB entries. This is necessary for shared FDB LAG to function since packets are always received on active eswitch instance as opposed to parent eswitch of port. - Support for deleting peer flows when receiving SWITCHDEV_FDB_DEL_TO_BRIDGE notification was implemented in one of previous patches in series. Now also implement support for handling SWITCHDEV_FDB_ADD_TO_BRIDGE which can be generated on peer by bridge update workqueue task in LAG configuration. Refresh the flow 'lastuse' timestamp to current jiffies when receiving such notification on eswitch that manages the local FDB entry. This allows peer entries to prevent ageing of the FDB. Signed-off-by: Vlad Buslov <vladbu@nvidia.com> Reviewed-by: Roi Dayan <roid@nvidia.com> Reviewed-by: Mark Bloch <mbloch@nvidia.com> Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
1 parent c358ea1 commit ff9b752

File tree

3 files changed

+159
-48
lines changed

3 files changed

+159
-48
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c

Lines changed: 87 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,46 +41,88 @@ static bool mlx5_esw_bridge_dev_same_hw(struct net_device *dev, struct mlx5_eswi
4141
return system_guid == esw_system_guid;
4242
}
4343

44-
static int mlx5_esw_bridge_vport_num_vhca_id_get(struct net_device *dev, struct mlx5_eswitch *esw,
45-
u16 *vport_num, u16 *esw_owner_vhca_id)
44+
static struct net_device *
45+
mlx5_esw_bridge_lag_rep_get(struct net_device *dev, struct mlx5_eswitch *esw)
46+
{
47+
struct net_device *lower;
48+
struct list_head *iter;
49+
50+
netdev_for_each_lower_dev(dev, lower, iter) {
51+
struct mlx5_core_dev *mdev;
52+
struct mlx5e_priv *priv;
53+
54+
if (!mlx5e_eswitch_rep(lower))
55+
continue;
56+
57+
priv = netdev_priv(lower);
58+
mdev = priv->mdev;
59+
if (mlx5_lag_is_shared_fdb(mdev) && mlx5_esw_bridge_dev_same_esw(lower, esw))
60+
return lower;
61+
}
62+
63+
return NULL;
64+
}
65+
66+
static struct net_device *
67+
mlx5_esw_bridge_rep_vport_num_vhca_id_get(struct net_device *dev, struct mlx5_eswitch *esw,
68+
u16 *vport_num, u16 *esw_owner_vhca_id)
4669
{
4770
struct mlx5e_rep_priv *rpriv;
4871
struct mlx5e_priv *priv;
4972

50-
if (!mlx5e_eswitch_rep(dev) || !mlx5_esw_bridge_dev_same_hw(dev, esw))
51-
return -ENODEV;
73+
if (netif_is_lag_master(dev))
74+
dev = mlx5_esw_bridge_lag_rep_get(dev, esw);
75+
76+
if (!dev || !mlx5e_eswitch_rep(dev) || !mlx5_esw_bridge_dev_same_hw(dev, esw))
77+
return NULL;
5278

5379
priv = netdev_priv(dev);
5480
rpriv = priv->ppriv;
5581
*vport_num = rpriv->rep->vport;
5682
*esw_owner_vhca_id = MLX5_CAP_GEN(priv->mdev, vhca_id);
57-
return 0;
83+
return dev;
5884
}
5985

60-
static int
86+
static struct net_device *
6187
mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(struct net_device *dev, struct mlx5_eswitch *esw,
6288
u16 *vport_num, u16 *esw_owner_vhca_id)
6389
{
6490
struct net_device *lower_dev;
6591
struct list_head *iter;
6692

67-
if (mlx5e_eswitch_rep(dev))
68-
return mlx5_esw_bridge_vport_num_vhca_id_get(dev, esw, vport_num,
69-
esw_owner_vhca_id);
93+
if (netif_is_lag_master(dev) || mlx5e_eswitch_rep(dev))
94+
return mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, esw, vport_num,
95+
esw_owner_vhca_id);
7096

7197
netdev_for_each_lower_dev(dev, lower_dev, iter) {
72-
int err;
98+
struct net_device *rep;
7399

74100
if (netif_is_bridge_master(lower_dev))
75101
continue;
76102

77-
err = mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(lower_dev, esw, vport_num,
103+
rep = mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(lower_dev, esw, vport_num,
78104
esw_owner_vhca_id);
79-
if (!err)
80-
return 0;
105+
if (rep)
106+
return rep;
81107
}
82108

83-
return -ENODEV;
109+
return NULL;
110+
}
111+
112+
static bool mlx5_esw_bridge_is_local(struct net_device *dev, struct net_device *rep,
113+
struct mlx5_eswitch *esw)
114+
{
115+
struct mlx5_core_dev *mdev;
116+
struct mlx5e_priv *priv;
117+
118+
if (!mlx5_esw_bridge_dev_same_esw(rep, esw))
119+
return false;
120+
121+
priv = netdev_priv(rep);
122+
mdev = priv->mdev;
123+
if (netif_is_lag_master(dev))
124+
return mlx5_lag_is_shared_fdb(mdev) && mlx5_lag_is_master(mdev);
125+
return true;
84126
}
85127

86128
static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr)
@@ -90,8 +132,8 @@ static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr
90132
netdev_nb);
91133
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
92134
struct netdev_notifier_changeupper_info *info = ptr;
135+
struct net_device *upper = info->upper_dev, *rep;
93136
struct mlx5_eswitch *esw = br_offloads->esw;
94-
struct net_device *upper = info->upper_dev;
95137
u16 vport_num, esw_owner_vhca_id;
96138
struct netlink_ext_ack *extack;
97139
int ifindex = upper->ifindex;
@@ -100,20 +142,19 @@ static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr
100142
if (!netif_is_bridge_master(upper))
101143
return 0;
102144

103-
err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
104-
&esw_owner_vhca_id);
105-
if (err)
145+
rep = mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, esw, &vport_num, &esw_owner_vhca_id);
146+
if (!rep)
106147
return 0;
107148

108149
extack = netdev_notifier_info_to_extack(&info->info);
109150

110-
if (mlx5_esw_bridge_dev_same_esw(dev, esw))
151+
if (mlx5_esw_bridge_is_local(dev, rep, esw))
111152
err = info->linking ?
112153
mlx5_esw_bridge_vport_link(ifindex, vport_num, esw_owner_vhca_id,
113154
br_offloads, extack) :
114155
mlx5_esw_bridge_vport_unlink(ifindex, vport_num, esw_owner_vhca_id,
115156
br_offloads, extack);
116-
else if (mlx5_esw_bridge_dev_same_hw(dev, esw))
157+
else if (mlx5_esw_bridge_dev_same_hw(rep, esw))
117158
err = info->linking ?
118159
mlx5_esw_bridge_vport_peer_link(ifindex, vport_num, esw_owner_vhca_id,
119160
br_offloads, extack) :
@@ -151,9 +192,8 @@ mlx5_esw_bridge_port_obj_add(struct net_device *dev,
151192
u16 vport_num, esw_owner_vhca_id;
152193
int err;
153194

154-
err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
155-
&esw_owner_vhca_id);
156-
if (err)
195+
if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
196+
&esw_owner_vhca_id))
157197
return 0;
158198

159199
port_obj_info->handled = true;
@@ -178,11 +218,9 @@ mlx5_esw_bridge_port_obj_del(struct net_device *dev,
178218
const struct switchdev_obj *obj = port_obj_info->obj;
179219
const struct switchdev_obj_port_vlan *vlan;
180220
u16 vport_num, esw_owner_vhca_id;
181-
int err;
182221

183-
err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
184-
&esw_owner_vhca_id);
185-
if (err)
222+
if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
223+
&esw_owner_vhca_id))
186224
return 0;
187225

188226
port_obj_info->handled = true;
@@ -208,9 +246,8 @@ mlx5_esw_bridge_port_obj_attr_set(struct net_device *dev,
208246
u16 vport_num, esw_owner_vhca_id;
209247
int err;
210248

211-
err = mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
212-
&esw_owner_vhca_id);
213-
if (err)
249+
if (!mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
250+
&esw_owner_vhca_id))
214251
return 0;
215252

216253
port_attr_info->handled = true;
@@ -283,13 +320,11 @@ static void mlx5_esw_bridge_switchdev_fdb_event_work(struct work_struct *work)
283320
fdb_work->br_offloads;
284321
struct net_device *dev = fdb_work->dev;
285322
u16 vport_num, esw_owner_vhca_id;
286-
int err;
287323

288324
rtnl_lock();
289325

290-
err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
291-
&esw_owner_vhca_id);
292-
if (err)
326+
if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
327+
&esw_owner_vhca_id))
293328
goto out;
294329

295330
if (fdb_work->add)
@@ -343,8 +378,10 @@ static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb,
343378
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
344379
struct switchdev_notifier_fdb_info *fdb_info;
345380
struct mlx5_bridge_switchdev_fdb_work *work;
381+
struct mlx5_eswitch *esw = br_offloads->esw;
346382
struct switchdev_notifier_info *info = ptr;
347-
struct net_device *upper;
383+
u16 vport_num, esw_owner_vhca_id;
384+
struct net_device *upper, *rep;
348385

349386
if (event == SWITCHDEV_PORT_ATTR_SET) {
350387
int err = mlx5_esw_bridge_port_obj_attr_set(dev, ptr, br_offloads);
@@ -358,13 +395,25 @@ static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb,
358395
if (!netif_is_bridge_master(upper))
359396
return NOTIFY_DONE;
360397

361-
if (!mlx5e_eswitch_rep(dev))
398+
rep = mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, esw, &vport_num, &esw_owner_vhca_id);
399+
if (!rep)
362400
return NOTIFY_DONE;
363401

364402
switch (event) {
403+
case SWITCHDEV_FDB_ADD_TO_BRIDGE:
404+
/* only handle the event on native eswtich of representor */
405+
if (!mlx5_esw_bridge_is_local(dev, rep, esw))
406+
break;
407+
408+
fdb_info = container_of(info,
409+
struct switchdev_notifier_fdb_info,
410+
info);
411+
mlx5_esw_bridge_fdb_update_used(dev, vport_num, esw_owner_vhca_id, br_offloads,
412+
fdb_info);
413+
break;
365414
case SWITCHDEV_FDB_DEL_TO_BRIDGE:
366-
/* only handle the event when source is on another eswitch */
367-
if (mlx5_esw_bridge_dev_same_esw(dev, br_offloads->esw))
415+
/* only handle the event on peers */
416+
if (mlx5_esw_bridge_is_local(dev, rep, esw))
368417
break;
369418
fallthrough;
370419
case SWITCHDEV_FDB_ADD_TO_DEVICE:

drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/notifier.h>
66
#include <net/netevent.h>
77
#include <net/switchdev.h>
8+
#include "lib/devcom.h"
89
#include "bridge.h"
910
#include "eswitch.h"
1011
#include "bridge_priv.h"
@@ -408,9 +409,10 @@ mlx5_esw_bridge_egress_table_cleanup(struct mlx5_esw_bridge *bridge)
408409
}
409410

410411
static struct mlx5_flow_handle *
411-
mlx5_esw_bridge_ingress_flow_create(u16 vport_num, const unsigned char *addr,
412-
struct mlx5_esw_bridge_vlan *vlan, u32 counter_id,
413-
struct mlx5_esw_bridge *bridge)
412+
mlx5_esw_bridge_ingress_flow_with_esw_create(u16 vport_num, const unsigned char *addr,
413+
struct mlx5_esw_bridge_vlan *vlan, u32 counter_id,
414+
struct mlx5_esw_bridge *bridge,
415+
struct mlx5_eswitch *esw)
414416
{
415417
struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads;
416418
struct mlx5_flow_act flow_act = {
@@ -438,7 +440,7 @@ mlx5_esw_bridge_ingress_flow_create(u16 vport_num, const unsigned char *addr,
438440
MLX5_SET(fte_match_param, rule_spec->match_criteria,
439441
misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask());
440442
MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_0,
441-
mlx5_eswitch_get_vport_metadata_for_match(br_offloads->esw, vport_num));
443+
mlx5_eswitch_get_vport_metadata_for_match(esw, vport_num));
442444

443445
if (vlan && vlan->pkt_reformat_push) {
444446
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
@@ -466,6 +468,35 @@ mlx5_esw_bridge_ingress_flow_create(u16 vport_num, const unsigned char *addr,
466468
return handle;
467469
}
468470

471+
static struct mlx5_flow_handle *
472+
mlx5_esw_bridge_ingress_flow_create(u16 vport_num, const unsigned char *addr,
473+
struct mlx5_esw_bridge_vlan *vlan, u32 counter_id,
474+
struct mlx5_esw_bridge *bridge)
475+
{
476+
return mlx5_esw_bridge_ingress_flow_with_esw_create(vport_num, addr, vlan, counter_id,
477+
bridge, bridge->br_offloads->esw);
478+
}
479+
480+
static struct mlx5_flow_handle *
481+
mlx5_esw_bridge_ingress_flow_peer_create(u16 vport_num, const unsigned char *addr,
482+
struct mlx5_esw_bridge_vlan *vlan, u32 counter_id,
483+
struct mlx5_esw_bridge *bridge)
484+
{
485+
struct mlx5_devcom *devcom = bridge->br_offloads->esw->dev->priv.devcom;
486+
static struct mlx5_flow_handle *handle;
487+
struct mlx5_eswitch *peer_esw;
488+
489+
peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
490+
if (!peer_esw)
491+
return ERR_PTR(-ENODEV);
492+
493+
handle = mlx5_esw_bridge_ingress_flow_with_esw_create(vport_num, addr, vlan, counter_id,
494+
bridge, peer_esw);
495+
496+
mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
497+
return handle;
498+
}
499+
469500
static struct mlx5_flow_handle *
470501
mlx5_esw_bridge_ingress_filter_flow_create(u16 vport_num, const unsigned char *addr,
471502
struct mlx5_esw_bridge *bridge)
@@ -679,12 +710,10 @@ static void mlx5_esw_bridge_port_erase(struct mlx5_esw_bridge_port *port,
679710
xa_erase(&br_offloads->ports, mlx5_esw_bridge_port_key(port));
680711
}
681712

682-
static void mlx5_esw_bridge_fdb_entry_refresh(unsigned long lastuse,
683-
struct mlx5_esw_bridge_fdb_entry *entry)
713+
static void mlx5_esw_bridge_fdb_entry_refresh(struct mlx5_esw_bridge_fdb_entry *entry)
684714
{
685715
trace_mlx5_esw_bridge_fdb_entry_refresh(entry);
686716

687-
entry->lastuse = lastuse;
688717
mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
689718
entry->key.vid,
690719
SWITCHDEV_FDB_ADD_TO_BRIDGE);
@@ -959,8 +988,11 @@ mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, u16 esw_ow
959988
}
960989
entry->ingress_counter = counter;
961990

962-
handle = mlx5_esw_bridge_ingress_flow_create(vport_num, addr, vlan, mlx5_fc_id(counter),
963-
bridge);
991+
handle = peer ?
992+
mlx5_esw_bridge_ingress_flow_peer_create(vport_num, addr, vlan,
993+
mlx5_fc_id(counter), bridge) :
994+
mlx5_esw_bridge_ingress_flow_create(vport_num, addr, vlan,
995+
mlx5_fc_id(counter), bridge);
964996
if (IS_ERR(handle)) {
965997
err = PTR_ERR(handle);
966998
esw_warn(esw->dev, "Failed to create ingress flow(vport=%u,err=%d)\n",
@@ -1228,6 +1260,33 @@ void mlx5_esw_bridge_port_vlan_del(u16 vport_num, u16 esw_owner_vhca_id, u16 vid
12281260
mlx5_esw_bridge_vlan_cleanup(port, vlan, port->bridge);
12291261
}
12301262

1263+
void mlx5_esw_bridge_fdb_update_used(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
1264+
struct mlx5_esw_bridge_offloads *br_offloads,
1265+
struct switchdev_notifier_fdb_info *fdb_info)
1266+
{
1267+
struct mlx5_esw_bridge_fdb_entry *entry;
1268+
struct mlx5_esw_bridge_fdb_key key;
1269+
struct mlx5_esw_bridge_port *port;
1270+
struct mlx5_esw_bridge *bridge;
1271+
1272+
port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads);
1273+
if (!port || port->flags & MLX5_ESW_BRIDGE_PORT_FLAG_PEER)
1274+
return;
1275+
1276+
bridge = port->bridge;
1277+
ether_addr_copy(key.addr, fdb_info->addr);
1278+
key.vid = fdb_info->vid;
1279+
entry = rhashtable_lookup_fast(&bridge->fdb_ht, &key, fdb_ht_params);
1280+
if (!entry) {
1281+
esw_debug(br_offloads->esw->dev,
1282+
"FDB entry with specified key not found (MAC=%pM,vid=%u,vport=%u)\n",
1283+
key.addr, key.vid, vport_num);
1284+
return;
1285+
}
1286+
1287+
entry->lastuse = jiffies;
1288+
}
1289+
12311290
void mlx5_esw_bridge_fdb_create(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
12321291
struct mlx5_esw_bridge_offloads *br_offloads,
12331292
struct switchdev_notifier_fdb_info *fdb_info)
@@ -1300,7 +1359,7 @@ void mlx5_esw_bridge_update(struct mlx5_esw_bridge_offloads *br_offloads)
13001359
continue;
13011360

13021361
if (time_after(lastuse, entry->lastuse)) {
1303-
mlx5_esw_bridge_fdb_entry_refresh(lastuse, entry);
1362+
mlx5_esw_bridge_fdb_entry_refresh(entry);
13041363
} else if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_PEER) &&
13051364
time_is_before_jiffies(entry->lastuse + bridge->ageing_time)) {
13061365
mlx5_esw_bridge_fdb_del_notify(entry);

drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ int mlx5_esw_bridge_vport_peer_link(int ifindex, u16 vport_num, u16 esw_owner_vh
4646
int mlx5_esw_bridge_vport_peer_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
4747
struct mlx5_esw_bridge_offloads *br_offloads,
4848
struct netlink_ext_ack *extack);
49+
void mlx5_esw_bridge_fdb_update_used(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
50+
struct mlx5_esw_bridge_offloads *br_offloads,
51+
struct switchdev_notifier_fdb_info *fdb_info);
4952
void mlx5_esw_bridge_fdb_create(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
5053
struct mlx5_esw_bridge_offloads *br_offloads,
5154
struct switchdev_notifier_fdb_info *fdb_info);

0 commit comments

Comments
 (0)