Commit 61f46fe8 authored by Petr Machata's avatar Petr Machata Committed by David S. Miller

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: default avatarPetr Machata <petrm@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ccdfd4f7
...@@ -375,32 +375,38 @@ static void vxlan_fdb_switchdev_notifier_info(const struct vxlan_dev *vxlan, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment