diff options
Diffstat (limited to 'drivers/net/vxlan.c')
| -rw-r--r-- | drivers/net/vxlan.c | 63 |
1 files changed, 47 insertions, 16 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 0ba1e7edbb1b..f4c6db419ddb 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
| @@ -136,7 +136,8 @@ struct vxlan_dev { | |||
| 136 | u32 flags; /* VXLAN_F_* below */ | 136 | u32 flags; /* VXLAN_F_* below */ |
| 137 | 137 | ||
| 138 | struct work_struct sock_work; | 138 | struct work_struct sock_work; |
| 139 | struct work_struct igmp_work; | 139 | struct work_struct igmp_join; |
| 140 | struct work_struct igmp_leave; | ||
| 140 | 141 | ||
| 141 | unsigned long age_interval; | 142 | unsigned long age_interval; |
| 142 | struct timer_list age_timer; | 143 | struct timer_list age_timer; |
| @@ -736,7 +737,6 @@ static bool vxlan_snoop(struct net_device *dev, | |||
| 736 | return false; | 737 | return false; |
| 737 | } | 738 | } |
| 738 | 739 | ||
| 739 | |||
| 740 | /* See if multicast group is already in use by other ID */ | 740 | /* See if multicast group is already in use by other ID */ |
| 741 | static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip) | 741 | static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip) |
| 742 | { | 742 | { |
| @@ -770,12 +770,13 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs) | |||
| 770 | queue_work(vxlan_wq, &vs->del_work); | 770 | queue_work(vxlan_wq, &vs->del_work); |
| 771 | } | 771 | } |
| 772 | 772 | ||
| 773 | /* Callback to update multicast group membership. | 773 | /* Callback to update multicast group membership when first VNI on |
| 774 | * Scheduled when vxlan goes up/down. | 774 | * multicast asddress is brought up |
| 775 | * Done as workqueue because ip_mc_join_group acquires RTNL. | ||
| 775 | */ | 776 | */ |
| 776 | static void vxlan_igmp_work(struct work_struct *work) | 777 | static void vxlan_igmp_join(struct work_struct *work) |
| 777 | { | 778 | { |
| 778 | struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_work); | 779 | struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join); |
| 779 | struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id); | 780 | struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id); |
| 780 | struct vxlan_sock *vs = vxlan->vn_sock; | 781 | struct vxlan_sock *vs = vxlan->vn_sock; |
| 781 | struct sock *sk = vs->sock->sk; | 782 | struct sock *sk = vs->sock->sk; |
| @@ -785,10 +786,27 @@ static void vxlan_igmp_work(struct work_struct *work) | |||
| 785 | }; | 786 | }; |
| 786 | 787 | ||
| 787 | lock_sock(sk); | 788 | lock_sock(sk); |
| 788 | if (vxlan_group_used(vn, vxlan->default_dst.remote_ip)) | 789 | ip_mc_join_group(sk, &mreq); |
| 789 | ip_mc_join_group(sk, &mreq); | 790 | release_sock(sk); |
| 790 | else | 791 | |
| 791 | ip_mc_leave_group(sk, &mreq); | 792 | vxlan_sock_release(vn, vs); |
| 793 | dev_put(vxlan->dev); | ||
| 794 | } | ||
| 795 | |||
| 796 | /* Inverse of vxlan_igmp_join when last VNI is brought down */ | ||
| 797 | static void vxlan_igmp_leave(struct work_struct *work) | ||
| 798 | { | ||
| 799 | struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave); | ||
| 800 | struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id); | ||
| 801 | struct vxlan_sock *vs = vxlan->vn_sock; | ||
| 802 | struct sock *sk = vs->sock->sk; | ||
| 803 | struct ip_mreqn mreq = { | ||
| 804 | .imr_multiaddr.s_addr = vxlan->default_dst.remote_ip, | ||
| 805 | .imr_ifindex = vxlan->default_dst.remote_ifindex, | ||
| 806 | }; | ||
| 807 | |||
| 808 | lock_sock(sk); | ||
| 809 | ip_mc_leave_group(sk, &mreq); | ||
| 792 | release_sock(sk); | 810 | release_sock(sk); |
| 793 | 811 | ||
| 794 | vxlan_sock_release(vn, vs); | 812 | vxlan_sock_release(vn, vs); |
| @@ -1359,6 +1377,7 @@ static void vxlan_uninit(struct net_device *dev) | |||
| 1359 | /* Start ageing timer and join group when device is brought up */ | 1377 | /* Start ageing timer and join group when device is brought up */ |
| 1360 | static int vxlan_open(struct net_device *dev) | 1378 | static int vxlan_open(struct net_device *dev) |
| 1361 | { | 1379 | { |
| 1380 | struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); | ||
| 1362 | struct vxlan_dev *vxlan = netdev_priv(dev); | 1381 | struct vxlan_dev *vxlan = netdev_priv(dev); |
| 1363 | struct vxlan_sock *vs = vxlan->vn_sock; | 1382 | struct vxlan_sock *vs = vxlan->vn_sock; |
| 1364 | 1383 | ||
| @@ -1366,10 +1385,11 @@ static int vxlan_open(struct net_device *dev) | |||
| 1366 | if (!vs) | 1385 | if (!vs) |
| 1367 | return -ENOTCONN; | 1386 | return -ENOTCONN; |
| 1368 | 1387 | ||
| 1369 | if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) { | 1388 | if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) && |
| 1389 | ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) { | ||
| 1370 | vxlan_sock_hold(vs); | 1390 | vxlan_sock_hold(vs); |
| 1371 | dev_hold(dev); | 1391 | dev_hold(dev); |
| 1372 | queue_work(vxlan_wq, &vxlan->igmp_work); | 1392 | queue_work(vxlan_wq, &vxlan->igmp_join); |
| 1373 | } | 1393 | } |
| 1374 | 1394 | ||
| 1375 | if (vxlan->age_interval) | 1395 | if (vxlan->age_interval) |
| @@ -1400,13 +1420,15 @@ static void vxlan_flush(struct vxlan_dev *vxlan) | |||
| 1400 | /* Cleanup timer and forwarding table on shutdown */ | 1420 | /* Cleanup timer and forwarding table on shutdown */ |
| 1401 | static int vxlan_stop(struct net_device *dev) | 1421 | static int vxlan_stop(struct net_device *dev) |
| 1402 | { | 1422 | { |
| 1423 | struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); | ||
| 1403 | struct vxlan_dev *vxlan = netdev_priv(dev); | 1424 | struct vxlan_dev *vxlan = netdev_priv(dev); |
| 1404 | struct vxlan_sock *vs = vxlan->vn_sock; | 1425 | struct vxlan_sock *vs = vxlan->vn_sock; |
| 1405 | 1426 | ||
| 1406 | if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) { | 1427 | if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) && |
| 1428 | ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) { | ||
| 1407 | vxlan_sock_hold(vs); | 1429 | vxlan_sock_hold(vs); |
| 1408 | dev_hold(dev); | 1430 | dev_hold(dev); |
| 1409 | queue_work(vxlan_wq, &vxlan->igmp_work); | 1431 | queue_work(vxlan_wq, &vxlan->igmp_leave); |
| 1410 | } | 1432 | } |
| 1411 | 1433 | ||
| 1412 | del_timer_sync(&vxlan->age_timer); | 1434 | del_timer_sync(&vxlan->age_timer); |
| @@ -1471,7 +1493,8 @@ static void vxlan_setup(struct net_device *dev) | |||
| 1471 | 1493 | ||
| 1472 | INIT_LIST_HEAD(&vxlan->next); | 1494 | INIT_LIST_HEAD(&vxlan->next); |
| 1473 | spin_lock_init(&vxlan->hash_lock); | 1495 | spin_lock_init(&vxlan->hash_lock); |
| 1474 | INIT_WORK(&vxlan->igmp_work, vxlan_igmp_work); | 1496 | INIT_WORK(&vxlan->igmp_join, vxlan_igmp_join); |
| 1497 | INIT_WORK(&vxlan->igmp_leave, vxlan_igmp_leave); | ||
| 1475 | INIT_WORK(&vxlan->sock_work, vxlan_sock_work); | 1498 | INIT_WORK(&vxlan->sock_work, vxlan_sock_work); |
| 1476 | 1499 | ||
| 1477 | init_timer_deferrable(&vxlan->age_timer); | 1500 | init_timer_deferrable(&vxlan->age_timer); |
| @@ -1767,9 +1790,15 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, | |||
| 1767 | 1790 | ||
| 1768 | static void vxlan_dellink(struct net_device *dev, struct list_head *head) | 1791 | static void vxlan_dellink(struct net_device *dev, struct list_head *head) |
| 1769 | { | 1792 | { |
| 1793 | struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); | ||
| 1770 | struct vxlan_dev *vxlan = netdev_priv(dev); | 1794 | struct vxlan_dev *vxlan = netdev_priv(dev); |
| 1771 | 1795 | ||
| 1796 | flush_workqueue(vxlan_wq); | ||
| 1797 | |||
| 1798 | spin_lock(&vn->sock_lock); | ||
| 1772 | hlist_del_rcu(&vxlan->hlist); | 1799 | hlist_del_rcu(&vxlan->hlist); |
| 1800 | spin_unlock(&vn->sock_lock); | ||
| 1801 | |||
| 1773 | list_del(&vxlan->next); | 1802 | list_del(&vxlan->next); |
| 1774 | unregister_netdevice_queue(dev, head); | 1803 | unregister_netdevice_queue(dev, head); |
| 1775 | } | 1804 | } |
| @@ -1872,10 +1901,12 @@ static __net_exit void vxlan_exit_net(struct net *net) | |||
| 1872 | { | 1901 | { |
| 1873 | struct vxlan_net *vn = net_generic(net, vxlan_net_id); | 1902 | struct vxlan_net *vn = net_generic(net, vxlan_net_id); |
| 1874 | struct vxlan_dev *vxlan; | 1903 | struct vxlan_dev *vxlan; |
| 1904 | LIST_HEAD(list); | ||
| 1875 | 1905 | ||
| 1876 | rtnl_lock(); | 1906 | rtnl_lock(); |
| 1877 | list_for_each_entry(vxlan, &vn->vxlan_list, next) | 1907 | list_for_each_entry(vxlan, &vn->vxlan_list, next) |
| 1878 | dev_close(vxlan->dev); | 1908 | unregister_netdevice_queue(vxlan->dev, &list); |
| 1909 | unregister_netdevice_many(&list); | ||
| 1879 | rtnl_unlock(); | 1910 | rtnl_unlock(); |
| 1880 | } | 1911 | } |
| 1881 | 1912 | ||
