| From foo@baz Fri Jul 27 08:31:26 CEST 2018 |
| From: Roopa Prabhu <roopa@cumulusnetworks.com> |
| Date: Fri, 20 Jul 2018 13:21:04 -0700 |
| Subject: vxlan: fix default fdb entry netlink notify ordering during netdev create |
| |
| From: Roopa Prabhu <roopa@cumulusnetworks.com> |
| |
| [ Upstream commit e99465b952861533d9ba748fdbecc96d9a36da3e ] |
| |
| Problem: |
| In vxlan_newlink, a default fdb entry is added before register_netdev. |
| The default fdb creation function also notifies user-space of the |
| fdb entry on the vxlan device which user-space does not know about yet. |
| (RTM_NEWNEIGH goes before RTM_NEWLINK for the same ifindex). |
| |
| This patch fixes the user-space netlink notification ordering issue |
| with the following changes: |
| - decouple fdb notify from fdb create. |
| - Move fdb notify after register_netdev. |
| - Call rtnl_configure_link in vxlan newlink handler to notify |
| userspace about the newlink before fdb notify and |
| hence avoiding the user-space race. |
| |
| Fixes: afbd8bae9c79 ("vxlan: add implicit fdb entry for default destination") |
| Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/vxlan.c | 29 +++++++++++++++++++++-------- |
| 1 file changed, 21 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/net/vxlan.c |
| +++ b/drivers/net/vxlan.c |
| @@ -3190,6 +3190,7 @@ static int __vxlan_dev_create(struct net |
| { |
| struct vxlan_net *vn = net_generic(net, vxlan_net_id); |
| struct vxlan_dev *vxlan = netdev_priv(dev); |
| + struct vxlan_fdb *f = NULL; |
| int err; |
| |
| err = vxlan_dev_configure(net, dev, conf, false, extack); |
| @@ -3200,27 +3201,38 @@ static int __vxlan_dev_create(struct net |
| |
| /* create an fdb entry for a valid default destination */ |
| if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) { |
| - err = vxlan_fdb_update(vxlan, all_zeros_mac, |
| + err = vxlan_fdb_create(vxlan, all_zeros_mac, |
| &vxlan->default_dst.remote_ip, |
| NUD_REACHABLE | NUD_PERMANENT, |
| - NLM_F_EXCL | NLM_F_CREATE, |
| vxlan->cfg.dst_port, |
| vxlan->default_dst.remote_vni, |
| vxlan->default_dst.remote_vni, |
| vxlan->default_dst.remote_ifindex, |
| - NTF_SELF); |
| + NTF_SELF, &f); |
| if (err) |
| return err; |
| } |
| |
| err = register_netdevice(dev); |
| + if (err) |
| + goto errout; |
| + |
| + err = rtnl_configure_link(dev, NULL); |
| if (err) { |
| - vxlan_fdb_delete_default(vxlan, vxlan->default_dst.remote_vni); |
| - return err; |
| + unregister_netdevice(dev); |
| + goto errout; |
| } |
| |
| + /* notify default fdb entry */ |
| + if (f) |
| + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH); |
| + |
| list_add(&vxlan->next, &vn->vxlan_list); |
| return 0; |
| +errout: |
| + if (f) |
| + vxlan_fdb_destroy(vxlan, f, false); |
| + return err; |
| } |
| |
| static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], |
| @@ -3449,6 +3461,7 @@ static int vxlan_changelink(struct net_d |
| struct vxlan_rdst *dst = &vxlan->default_dst; |
| struct vxlan_rdst old_dst; |
| struct vxlan_config conf; |
| + struct vxlan_fdb *f = NULL; |
| int err; |
| |
| err = vxlan_nl2conf(tb, data, |
| @@ -3474,19 +3487,19 @@ static int vxlan_changelink(struct net_d |
| old_dst.remote_ifindex, 0); |
| |
| if (!vxlan_addr_any(&dst->remote_ip)) { |
| - err = vxlan_fdb_update(vxlan, all_zeros_mac, |
| + err = vxlan_fdb_create(vxlan, all_zeros_mac, |
| &dst->remote_ip, |
| NUD_REACHABLE | NUD_PERMANENT, |
| - NLM_F_CREATE | NLM_F_APPEND, |
| vxlan->cfg.dst_port, |
| dst->remote_vni, |
| dst->remote_vni, |
| dst->remote_ifindex, |
| - NTF_SELF); |
| + NTF_SELF, &f); |
| if (err) { |
| spin_unlock_bh(&vxlan->hash_lock); |
| return err; |
| } |
| + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH); |
| } |
| spin_unlock_bh(&vxlan->hash_lock); |
| } |