vxlan: Add hardware FDB learning
In order to allow devices to signal learning events to VXLAN, introduce two new switchdev messages: SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE and SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE. Listen to these notifications in the vxlan driver. The FDB entries learned this way have an NTF_EXT_LEARNED flag, and only entries marked as such can be unlearned by the _DEL_ event. They are also immediately marked as offloaded. This is the same behavior that the bridge driver observes. Signed-off-by: Petr Machata <petrm@mellanox.com> Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0ec566aacc
commit
5728ae0d17
|
@ -3923,18 +3923,89 @@ out:
|
|||
spin_unlock_bh(&vxlan->hash_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
vxlan_fdb_external_learn_add(struct net_device *dev,
|
||||
struct switchdev_notifier_vxlan_fdb_info *fdb_info)
|
||||
{
|
||||
struct vxlan_dev *vxlan = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&vxlan->hash_lock);
|
||||
err = vxlan_fdb_update(vxlan, fdb_info->eth_addr, &fdb_info->remote_ip,
|
||||
NUD_REACHABLE,
|
||||
NLM_F_CREATE | NLM_F_REPLACE,
|
||||
fdb_info->remote_port,
|
||||
fdb_info->vni,
|
||||
fdb_info->remote_vni,
|
||||
fdb_info->remote_ifindex,
|
||||
NTF_USE | NTF_SELF | NTF_EXT_LEARNED,
|
||||
false);
|
||||
spin_unlock_bh(&vxlan->hash_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
vxlan_fdb_external_learn_del(struct net_device *dev,
|
||||
struct switchdev_notifier_vxlan_fdb_info *fdb_info)
|
||||
{
|
||||
struct vxlan_dev *vxlan = netdev_priv(dev);
|
||||
struct vxlan_fdb *f;
|
||||
int err = 0;
|
||||
|
||||
spin_lock_bh(&vxlan->hash_lock);
|
||||
|
||||
f = vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni);
|
||||
if (!f)
|
||||
err = -ENOENT;
|
||||
else if (f->flags & NTF_EXT_LEARNED)
|
||||
err = __vxlan_fdb_delete(vxlan, fdb_info->eth_addr,
|
||||
fdb_info->remote_ip,
|
||||
fdb_info->remote_port,
|
||||
fdb_info->vni,
|
||||
fdb_info->remote_vni,
|
||||
fdb_info->remote_ifindex,
|
||||
false);
|
||||
|
||||
spin_unlock_bh(&vxlan->hash_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vxlan_switchdev_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
|
||||
struct switchdev_notifier_vxlan_fdb_info *fdb_info;
|
||||
int err = 0;
|
||||
|
||||
switch (event) {
|
||||
case SWITCHDEV_VXLAN_FDB_OFFLOADED:
|
||||
vxlan_fdb_offloaded_set(dev, ptr);
|
||||
break;
|
||||
case SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE:
|
||||
fdb_info = ptr;
|
||||
err = vxlan_fdb_external_learn_add(dev, fdb_info);
|
||||
if (err) {
|
||||
err = notifier_from_errno(err);
|
||||
break;
|
||||
}
|
||||
fdb_info->offloaded = true;
|
||||
vxlan_fdb_offloaded_set(dev, fdb_info);
|
||||
break;
|
||||
case SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE:
|
||||
fdb_info = ptr;
|
||||
err = vxlan_fdb_external_learn_del(dev, fdb_info);
|
||||
if (err) {
|
||||
err = notifier_from_errno(err);
|
||||
break;
|
||||
}
|
||||
fdb_info->offloaded = false;
|
||||
vxlan_fdb_offloaded_set(dev, fdb_info);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct notifier_block vxlan_switchdev_notifier_block __read_mostly = {
|
||||
|
|
|
@ -146,6 +146,8 @@ enum switchdev_notifier_type {
|
|||
SWITCHDEV_FDB_DEL_TO_DEVICE,
|
||||
SWITCHDEV_FDB_OFFLOADED,
|
||||
|
||||
SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE,
|
||||
SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE,
|
||||
SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE,
|
||||
SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE,
|
||||
SWITCHDEV_VXLAN_FDB_OFFLOADED,
|
||||
|
|
Loading…
Reference in New Issue