vxlan: Allow vetoing of FDB notifications
Change vxlan_fdb_switchdev_call_notifiers() to return the result from calling switchdev notifiers. Propagate the error number up the stack. In vxlan_fdb_update_existing() and vxlan_fdb_update_create() add rollbacks to clean up the work that was done before the veto. Signed-off-by: Petr Machata <petrm@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ccdfd4f71d
commit
61f46fe8c6
1 changed files with 46 additions and 18 deletions
|
@ -375,32 +375,38 @@ static void vxlan_fdb_switchdev_notifier_info(const struct vxlan_dev *vxlan,
|
||||||
fdb_info->added_by_user = fdb->flags & NTF_VXLAN_ADDED_BY_USER;
|
fdb_info->added_by_user = fdb->flags & NTF_VXLAN_ADDED_BY_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan,
|
static int vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan,
|
||||||
struct vxlan_fdb *fdb,
|
struct vxlan_fdb *fdb,
|
||||||
struct vxlan_rdst *rd,
|
struct vxlan_rdst *rd,
|
||||||
bool adding)
|
bool adding)
|
||||||
{
|
{
|
||||||
struct switchdev_notifier_vxlan_fdb_info info;
|
struct switchdev_notifier_vxlan_fdb_info info;
|
||||||
enum switchdev_notifier_type notifier_type;
|
enum switchdev_notifier_type notifier_type;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (WARN_ON(!rd))
|
if (WARN_ON(!rd))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
notifier_type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE
|
notifier_type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE
|
||||||
: SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE;
|
: SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE;
|
||||||
vxlan_fdb_switchdev_notifier_info(vxlan, fdb, rd, &info);
|
vxlan_fdb_switchdev_notifier_info(vxlan, fdb, rd, &info);
|
||||||
call_switchdev_notifiers(notifier_type, vxlan->dev,
|
ret = call_switchdev_notifiers(notifier_type, vxlan->dev,
|
||||||
&info.info);
|
&info.info);
|
||||||
|
return notifier_to_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
|
static int vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
|
||||||
struct vxlan_rdst *rd, int type, bool swdev_notify)
|
struct vxlan_rdst *rd, int type, bool swdev_notify)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
if (swdev_notify) {
|
if (swdev_notify) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RTM_NEWNEIGH:
|
case RTM_NEWNEIGH:
|
||||||
vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd,
|
err = vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd,
|
||||||
true);
|
true);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
break;
|
break;
|
||||||
case RTM_DELNEIGH:
|
case RTM_DELNEIGH:
|
||||||
vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd,
|
vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd,
|
||||||
|
@ -410,6 +416,7 @@ static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
|
||||||
}
|
}
|
||||||
|
|
||||||
__vxlan_fdb_notify(vxlan, fdb, rd, type);
|
__vxlan_fdb_notify(vxlan, fdb, rd, type);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa)
|
static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa)
|
||||||
|
@ -868,7 +875,8 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
|
||||||
struct vxlan_rdst *rd = NULL;
|
struct vxlan_rdst *rd = NULL;
|
||||||
struct vxlan_rdst oldrd;
|
struct vxlan_rdst oldrd;
|
||||||
int notify = 0;
|
int notify = 0;
|
||||||
int rc;
|
int rc = 0;
|
||||||
|
int err;
|
||||||
|
|
||||||
/* Do not allow an externally learned entry to take over an entry added
|
/* Do not allow an externally learned entry to take over an entry added
|
||||||
* by the user.
|
* by the user.
|
||||||
|
@ -915,10 +923,20 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
|
||||||
if (rd == NULL)
|
if (rd == NULL)
|
||||||
rd = first_remote_rtnl(f);
|
rd = first_remote_rtnl(f);
|
||||||
|
|
||||||
vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify);
|
err = vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH,
|
||||||
|
swdev_notify);
|
||||||
|
if (err)
|
||||||
|
goto err_notify;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_notify:
|
||||||
|
if ((flags & NLM_F_REPLACE) && rc)
|
||||||
|
*rd = oldrd;
|
||||||
|
else if ((flags & NLM_F_APPEND) && rc)
|
||||||
|
list_del_rcu(&rd->list);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
|
static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
|
||||||
|
@ -943,9 +961,16 @@ static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
|
rc = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
|
||||||
swdev_notify);
|
swdev_notify);
|
||||||
|
if (rc)
|
||||||
|
goto err_notify;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_notify:
|
||||||
|
vxlan_fdb_destroy(vxlan, f, false, false);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add new entry to forwarding table -- assumes lock held */
|
/* Add new entry to forwarding table -- assumes lock held */
|
||||||
|
@ -3515,9 +3540,12 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev,
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
/* notify default fdb entry */
|
/* notify default fdb entry */
|
||||||
if (f)
|
if (f) {
|
||||||
vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
|
err = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f),
|
||||||
true);
|
RTM_NEWNEIGH, true);
|
||||||
|
if (err)
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
list_add(&vxlan->next, &vn->vxlan_list);
|
list_add(&vxlan->next, &vn->vxlan_list);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue