Skip to content

Commit

Permalink
net/mlx5: Bridge, allow merged eswitch connectivity
Browse files Browse the repository at this point in the history
Allow connectivity between representors of different eswitch instances that
are attached to same bridge when merged_eswitch capability is enabled. Add
ports of peer eswitch to bridge instance and mark them with
MLX5_ESW_BRIDGE_PORT_FLAG_PEER. Mark FDBs offloaded on peer ports with
MLX5_ESW_BRIDGE_FLAG_PEER flag. Such FDBs can only be aged out on their
local eswitch instance, which then sends SWITCHDEV_FDB_DEL_TO_BRIDGE event.
Listen to the event on mlx5 bridge implementation and delete peer FDBs in
event handler.

Signed-off-by: Vlad Buslov <[email protected]>
Reviewed-by: Roi Dayan <[email protected]>
Reviewed-by: Mark Bloch <[email protected]>
Signed-off-by: Saeed Mahameed <[email protected]>
  • Loading branch information
w1ldptr authored and Saeed Mahameed committed Aug 16, 2021
1 parent bf3d56d commit c358ea1
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 28 deletions.
60 changes: 45 additions & 15 deletions drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ struct mlx5_bridge_switchdev_fdb_work {
struct work_struct work;
struct switchdev_notifier_fdb_info fdb_info;
struct net_device *dev;
struct mlx5_esw_bridge_offloads *br_offloads;
bool add;
};

Expand All @@ -25,13 +26,28 @@ static bool mlx5_esw_bridge_dev_same_esw(struct net_device *dev, struct mlx5_esw
return esw == priv->mdev->priv.eswitch;
}

static bool mlx5_esw_bridge_dev_same_hw(struct net_device *dev, struct mlx5_eswitch *esw)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5_core_dev *mdev, *esw_mdev;
u64 system_guid, esw_system_guid;

mdev = priv->mdev;
esw_mdev = esw->dev;

system_guid = mlx5_query_nic_system_image_guid(mdev);
esw_system_guid = mlx5_query_nic_system_image_guid(esw_mdev);

return system_guid == esw_system_guid;
}

static int mlx5_esw_bridge_vport_num_vhca_id_get(struct net_device *dev, struct mlx5_eswitch *esw,
u16 *vport_num, u16 *esw_owner_vhca_id)
{
struct mlx5e_rep_priv *rpriv;
struct mlx5e_priv *priv;

if (!mlx5e_eswitch_rep(dev) || !mlx5_esw_bridge_dev_same_esw(dev, esw))
if (!mlx5e_eswitch_rep(dev) || !mlx5_esw_bridge_dev_same_hw(dev, esw))
return -ENODEV;

priv = netdev_priv(dev);
Expand All @@ -48,7 +64,7 @@ mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(struct net_device *dev, struct m
struct net_device *lower_dev;
struct list_head *iter;

if (mlx5e_eswitch_rep(dev) && mlx5_esw_bridge_dev_same_esw(dev, esw))
if (mlx5e_eswitch_rep(dev))
return mlx5_esw_bridge_vport_num_vhca_id_get(dev, esw, vport_num,
esw_owner_vhca_id);

Expand All @@ -74,6 +90,7 @@ static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr
netdev_nb);
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct netdev_notifier_changeupper_info *info = ptr;
struct mlx5_eswitch *esw = br_offloads->esw;
struct net_device *upper = info->upper_dev;
u16 vport_num, esw_owner_vhca_id;
struct netlink_ext_ack *extack;
Expand All @@ -90,11 +107,20 @@ static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr

extack = netdev_notifier_info_to_extack(&info->info);

return info->linking ?
mlx5_esw_bridge_vport_link(ifindex, vport_num, esw_owner_vhca_id, br_offloads,
extack) :
mlx5_esw_bridge_vport_unlink(ifindex, vport_num, esw_owner_vhca_id, br_offloads,
extack);
if (mlx5_esw_bridge_dev_same_esw(dev, esw))
err = info->linking ?
mlx5_esw_bridge_vport_link(ifindex, vport_num, esw_owner_vhca_id,
br_offloads, extack) :
mlx5_esw_bridge_vport_unlink(ifindex, vport_num, esw_owner_vhca_id,
br_offloads, extack);
else if (mlx5_esw_bridge_dev_same_hw(dev, esw))
err = info->linking ?
mlx5_esw_bridge_vport_peer_link(ifindex, vport_num, esw_owner_vhca_id,
br_offloads, extack) :
mlx5_esw_bridge_vport_peer_unlink(ifindex, vport_num, esw_owner_vhca_id,
br_offloads, extack);

return err;
}

static int mlx5_esw_bridge_switchdev_port_event(struct notifier_block *nb,
Expand Down Expand Up @@ -253,16 +279,14 @@ static void mlx5_esw_bridge_switchdev_fdb_event_work(struct work_struct *work)
container_of(work, struct mlx5_bridge_switchdev_fdb_work, work);
struct switchdev_notifier_fdb_info *fdb_info =
&fdb_work->fdb_info;
struct mlx5_esw_bridge_offloads *br_offloads;
struct mlx5_esw_bridge_offloads *br_offloads =
fdb_work->br_offloads;
struct net_device *dev = fdb_work->dev;
u16 vport_num, esw_owner_vhca_id;
struct mlx5e_priv *priv;
int err;

rtnl_lock();

priv = netdev_priv(dev);
br_offloads = priv->mdev->priv.eswitch->br_offloads;
err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
&esw_owner_vhca_id);
if (err)
Expand All @@ -282,7 +306,8 @@ static void mlx5_esw_bridge_switchdev_fdb_event_work(struct work_struct *work)

static struct mlx5_bridge_switchdev_fdb_work *
mlx5_esw_bridge_init_switchdev_fdb_work(struct net_device *dev, bool add,
struct switchdev_notifier_fdb_info *fdb_info)
struct switchdev_notifier_fdb_info *fdb_info,
struct mlx5_esw_bridge_offloads *br_offloads)
{
struct mlx5_bridge_switchdev_fdb_work *work;
u8 *addr;
Expand All @@ -304,6 +329,7 @@ mlx5_esw_bridge_init_switchdev_fdb_work(struct net_device *dev, bool add,

dev_hold(dev);
work->dev = dev;
work->br_offloads = br_offloads;
work->add = add;
return work;
}
Expand Down Expand Up @@ -334,10 +360,13 @@ static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb,

if (!mlx5e_eswitch_rep(dev))
return NOTIFY_DONE;
if (!mlx5_esw_bridge_dev_same_esw(dev, br_offloads->esw))
return NOTIFY_DONE;

switch (event) {
case SWITCHDEV_FDB_DEL_TO_BRIDGE:
/* only handle the event when source is on another eswitch */
if (mlx5_esw_bridge_dev_same_esw(dev, br_offloads->esw))
break;
fallthrough;
case SWITCHDEV_FDB_ADD_TO_DEVICE:
case SWITCHDEV_FDB_DEL_TO_DEVICE:
fdb_info = container_of(info,
Expand All @@ -346,7 +375,8 @@ static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb,

work = mlx5_esw_bridge_init_switchdev_fdb_work(dev,
event == SWITCHDEV_FDB_ADD_TO_DEVICE,
fdb_info);
fdb_info,
br_offloads);
if (IS_ERR(work)) {
WARN_ONCE(1, "Failed to init switchdev work, err=%ld",
PTR_ERR(work));
Expand Down
61 changes: 50 additions & 11 deletions drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ mlx5_esw_bridge_fdb_offload_notify(struct net_device *dev, const unsigned char *
static void
mlx5_esw_bridge_fdb_del_notify(struct mlx5_esw_bridge_fdb_entry *entry)
{
if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER))
if (!(entry->flags & (MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER | MLX5_ESW_BRIDGE_FLAG_PEER)))
mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
entry->key.vid,
SWITCHDEV_FDB_DEL_TO_BRIDGE);
Expand Down Expand Up @@ -513,7 +513,7 @@ mlx5_esw_bridge_ingress_filter_flow_create(u16 vport_num, const unsigned char *a
}

static struct mlx5_flow_handle *
mlx5_esw_bridge_egress_flow_create(u16 vport_num, const unsigned char *addr,
mlx5_esw_bridge_egress_flow_create(u16 vport_num, u16 esw_owner_vhca_id, const unsigned char *addr,
struct mlx5_esw_bridge_vlan *vlan,
struct mlx5_esw_bridge *bridge)
{
Expand Down Expand Up @@ -558,6 +558,10 @@ mlx5_esw_bridge_egress_flow_create(u16 vport_num, const unsigned char *addr,
vlan->vid);
}

if (MLX5_CAP_ESW(bridge->br_offloads->esw->dev, merged_eswitch)) {
dest.vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID;
dest.vport.vhca_id = esw_owner_vhca_id;
}
handle = mlx5_add_flow_rules(bridge->egress_ft, rule_spec, &flow_act, &dest, 1);

kvfree(rule_spec);
Expand Down Expand Up @@ -917,7 +921,7 @@ mlx5_esw_bridge_port_vlan_lookup(u16 vid, u16 vport_num, u16 esw_owner_vhca_id,

static struct mlx5_esw_bridge_fdb_entry *
mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
const unsigned char *addr, u16 vid, bool added_by_user,
const unsigned char *addr, u16 vid, bool added_by_user, bool peer,
struct mlx5_eswitch *esw, struct mlx5_esw_bridge *bridge)
{
struct mlx5_esw_bridge_vlan *vlan = NULL;
Expand Down Expand Up @@ -945,6 +949,8 @@ mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, u16 esw_ow
entry->lastuse = jiffies;
if (added_by_user)
entry->flags |= MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER;
if (peer)
entry->flags |= MLX5_ESW_BRIDGE_FLAG_PEER;

counter = mlx5_fc_create(esw->dev, true);
if (IS_ERR(counter)) {
Expand Down Expand Up @@ -974,7 +980,8 @@ mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, u16 esw_ow
entry->filter_handle = handle;
}

handle = mlx5_esw_bridge_egress_flow_create(vport_num, addr, vlan, bridge);
handle = mlx5_esw_bridge_egress_flow_create(vport_num, esw_owner_vhca_id, addr, vlan,
bridge);
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
esw_warn(esw->dev, "Failed to create egress flow(vport=%u,err=%d)\n",
Expand Down Expand Up @@ -1050,7 +1057,7 @@ int mlx5_esw_bridge_vlan_filtering_set(u16 vport_num, u16 esw_owner_vhca_id, boo
return 0;
}

static int mlx5_esw_bridge_vport_init(u16 vport_num, u16 esw_owner_vhca_id,
static int mlx5_esw_bridge_vport_init(u16 vport_num, u16 esw_owner_vhca_id, u16 flags,
struct mlx5_esw_bridge_offloads *br_offloads,
struct mlx5_esw_bridge *bridge)
{
Expand All @@ -1065,6 +1072,7 @@ static int mlx5_esw_bridge_vport_init(u16 vport_num, u16 esw_owner_vhca_id,
port->vport_num = vport_num;
port->esw_owner_vhca_id = esw_owner_vhca_id;
port->bridge = bridge;
port->flags |= flags;
xa_init(&port->vlans);
err = mlx5_esw_bridge_port_insert(port, br_offloads);
if (err) {
Expand Down Expand Up @@ -1101,9 +1109,10 @@ static int mlx5_esw_bridge_vport_cleanup(struct mlx5_esw_bridge_offloads *br_off
return 0;
}

int mlx5_esw_bridge_vport_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack)
static int mlx5_esw_bridge_vport_link_with_flags(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
u16 flags,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack)
{
struct mlx5_esw_bridge *bridge;
int err;
Expand All @@ -1114,7 +1123,7 @@ int mlx5_esw_bridge_vport_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id
return PTR_ERR(bridge);
}

err = mlx5_esw_bridge_vport_init(vport_num, esw_owner_vhca_id, br_offloads, bridge);
err = mlx5_esw_bridge_vport_init(vport_num, esw_owner_vhca_id, flags, br_offloads, bridge);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Error initializing port");
goto err_vport;
Expand All @@ -1126,6 +1135,14 @@ int mlx5_esw_bridge_vport_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id
return err;
}

int mlx5_esw_bridge_vport_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack)
{
return mlx5_esw_bridge_vport_link_with_flags(ifindex, vport_num, esw_owner_vhca_id, 0,
br_offloads, extack);
}

int mlx5_esw_bridge_vport_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack)
Expand All @@ -1149,6 +1166,26 @@ int mlx5_esw_bridge_vport_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_
return err;
}

int mlx5_esw_bridge_vport_peer_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack)
{
if (!MLX5_CAP_ESW(br_offloads->esw->dev, merged_eswitch))
return 0;

return mlx5_esw_bridge_vport_link_with_flags(ifindex, vport_num, esw_owner_vhca_id,
MLX5_ESW_BRIDGE_PORT_FLAG_PEER,
br_offloads, extack);
}

int mlx5_esw_bridge_vport_peer_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack)
{
return mlx5_esw_bridge_vport_unlink(ifindex, vport_num, esw_owner_vhca_id, br_offloads,
extack);
}

int mlx5_esw_bridge_port_vlan_add(u16 vport_num, u16 esw_owner_vhca_id, u16 vid, u16 flags,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack)
Expand Down Expand Up @@ -1206,14 +1243,15 @@ void mlx5_esw_bridge_fdb_create(struct net_device *dev, u16 vport_num, u16 esw_o
bridge = port->bridge;
entry = mlx5_esw_bridge_fdb_entry_init(dev, vport_num, esw_owner_vhca_id, fdb_info->addr,
fdb_info->vid, fdb_info->added_by_user,
port->flags & MLX5_ESW_BRIDGE_PORT_FLAG_PEER,
br_offloads->esw, bridge);
if (IS_ERR(entry))
return;

if (entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER)
mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid,
SWITCHDEV_FDB_OFFLOADED);
else
else if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_PEER))
/* Take over dynamic entries to prevent kernel bridge from aging them out. */
mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid,
SWITCHDEV_FDB_ADD_TO_BRIDGE);
Expand Down Expand Up @@ -1263,7 +1301,8 @@ void mlx5_esw_bridge_update(struct mlx5_esw_bridge_offloads *br_offloads)

if (time_after(lastuse, entry->lastuse)) {
mlx5_esw_bridge_fdb_entry_refresh(lastuse, entry);
} else if (time_is_before_jiffies(entry->lastuse + bridge->ageing_time)) {
} else if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_PEER) &&
time_is_before_jiffies(entry->lastuse + bridge->ageing_time)) {
mlx5_esw_bridge_fdb_del_notify(entry);
mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
}
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ int mlx5_esw_bridge_vport_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id
int mlx5_esw_bridge_vport_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack);
int mlx5_esw_bridge_vport_peer_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack);
int mlx5_esw_bridge_vport_peer_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct netlink_ext_ack *extack);
void mlx5_esw_bridge_fdb_create(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_offloads *br_offloads,
struct switchdev_notifier_fdb_info *fdb_info);
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ struct mlx5_esw_bridge_fdb_key {

enum {
MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER = BIT(0),
MLX5_ESW_BRIDGE_FLAG_PEER = BIT(1),
};

enum {
MLX5_ESW_BRIDGE_PORT_FLAG_PEER = BIT(0),
};

struct mlx5_esw_bridge_fdb_entry {
Expand Down Expand Up @@ -49,6 +54,7 @@ struct mlx5_esw_bridge_vlan {
struct mlx5_esw_bridge_port {
u16 vport_num;
u16 esw_owner_vhca_id;
u16 flags;
struct mlx5_esw_bridge *bridge;
struct xarray vlans;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,17 @@ DECLARE_EVENT_CLASS(mlx5_esw_bridge_port_template,
TP_STRUCT__entry(
__field(u16, vport_num)
__field(u16, esw_owner_vhca_id)
__field(u16, flags)
),
TP_fast_assign(
__entry->vport_num = port->vport_num;
__entry->esw_owner_vhca_id = port->esw_owner_vhca_id;
__entry->flags = port->flags;
),
TP_printk("vport_num=%hu esw_owner_vhca_id=%hu",
TP_printk("vport_num=%hu esw_owner_vhca_id=%hu flags=%hx",
__entry->vport_num,
__entry->esw_owner_vhca_id)
__entry->esw_owner_vhca_id,
__entry->flags)
);

DEFINE_EVENT(mlx5_esw_bridge_port_template,
Expand Down

0 comments on commit c358ea1

Please sign in to comment.