diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-08-19 14:22:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-20 03:15:43 -0400 |
commit | 9c2e24e16fbccf6cc1102442acc4a629f79615a7 (patch) | |
tree | 7965520c9933a05a47901d31ddc99db42a7bbd65 /drivers/net/vxlan.c | |
parent | 7559fb2fc547b3507ba462c6558e291fb21b9cee (diff) |
vxlan: Restructure vxlan socket apis.
Restructure vxlan-socket management APIs so that it can be
shared between vxlan and ovs modules.
This patch does not change any functionality.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
v6-v7:
- get rid of zero refcnt vs from hashtable.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxlan.c')
-rw-r--r-- | drivers/net/vxlan.c | 92 |
1 files changed, 51 insertions, 41 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 570ad7aa7204..b784ee668a4e 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -188,7 +188,7 @@ static inline struct vxlan_rdst *first_remote_rtnl(struct vxlan_fdb *fdb) | |||
188 | } | 188 | } |
189 | 189 | ||
190 | /* Find VXLAN socket based on network namespace and UDP port */ | 190 | /* Find VXLAN socket based on network namespace and UDP port */ |
191 | static struct vxlan_sock *vxlan_find_port(struct net *net, __be16 port) | 191 | static struct vxlan_sock *vxlan_find_sock(struct net *net, __be16 port) |
192 | { | 192 | { |
193 | struct vxlan_sock *vs; | 193 | struct vxlan_sock *vs; |
194 | 194 | ||
@@ -205,7 +205,7 @@ static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, __be16 port) | |||
205 | struct vxlan_sock *vs; | 205 | struct vxlan_sock *vs; |
206 | struct vxlan_dev *vxlan; | 206 | struct vxlan_dev *vxlan; |
207 | 207 | ||
208 | vs = vxlan_find_port(net, port); | 208 | vs = vxlan_find_sock(net, port); |
209 | if (!vs) | 209 | if (!vs) |
210 | return NULL; | 210 | return NULL; |
211 | 211 | ||
@@ -1365,25 +1365,31 @@ static void vxlan_cleanup(unsigned long arg) | |||
1365 | mod_timer(&vxlan->age_timer, next_timer); | 1365 | mod_timer(&vxlan->age_timer, next_timer); |
1366 | } | 1366 | } |
1367 | 1367 | ||
1368 | static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan) | ||
1369 | { | ||
1370 | __u32 vni = vxlan->default_dst.remote_vni; | ||
1371 | |||
1372 | vxlan->vn_sock = vs; | ||
1373 | hlist_add_head_rcu(&vxlan->hlist, vni_head(vs, vni)); | ||
1374 | } | ||
1375 | |||
1368 | /* Setup stats when device is created */ | 1376 | /* Setup stats when device is created */ |
1369 | static int vxlan_init(struct net_device *dev) | 1377 | static int vxlan_init(struct net_device *dev) |
1370 | { | 1378 | { |
1371 | struct vxlan_dev *vxlan = netdev_priv(dev); | 1379 | struct vxlan_dev *vxlan = netdev_priv(dev); |
1372 | struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); | 1380 | struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); |
1373 | struct vxlan_sock *vs; | 1381 | struct vxlan_sock *vs; |
1374 | __u32 vni = vxlan->default_dst.remote_vni; | ||
1375 | 1382 | ||
1376 | dev->tstats = alloc_percpu(struct pcpu_tstats); | 1383 | dev->tstats = alloc_percpu(struct pcpu_tstats); |
1377 | if (!dev->tstats) | 1384 | if (!dev->tstats) |
1378 | return -ENOMEM; | 1385 | return -ENOMEM; |
1379 | 1386 | ||
1380 | spin_lock(&vn->sock_lock); | 1387 | spin_lock(&vn->sock_lock); |
1381 | vs = vxlan_find_port(dev_net(dev), vxlan->dst_port); | 1388 | vs = vxlan_find_sock(dev_net(dev), vxlan->dst_port); |
1382 | if (vs) { | 1389 | if (vs) { |
1383 | /* If we have a socket with same port already, reuse it */ | 1390 | /* If we have a socket with same port already, reuse it */ |
1384 | atomic_inc(&vs->refcnt); | 1391 | atomic_inc(&vs->refcnt); |
1385 | vxlan->vn_sock = vs; | 1392 | vxlan_vs_add_dev(vs, vxlan); |
1386 | hlist_add_head_rcu(&vxlan->hlist, vni_head(vs, vni)); | ||
1387 | } else { | 1393 | } else { |
1388 | /* otherwise make new socket outside of RTNL */ | 1394 | /* otherwise make new socket outside of RTNL */ |
1389 | dev_hold(dev); | 1395 | dev_hold(dev); |
@@ -1633,6 +1639,7 @@ static void vxlan_del_work(struct work_struct *work) | |||
1633 | 1639 | ||
1634 | static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port) | 1640 | static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port) |
1635 | { | 1641 | { |
1642 | struct vxlan_net *vn = net_generic(net, vxlan_net_id); | ||
1636 | struct vxlan_sock *vs; | 1643 | struct vxlan_sock *vs; |
1637 | struct sock *sk; | 1644 | struct sock *sk; |
1638 | struct sockaddr_in vxlan_addr = { | 1645 | struct sockaddr_in vxlan_addr = { |
@@ -1644,8 +1651,10 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port) | |||
1644 | unsigned int h; | 1651 | unsigned int h; |
1645 | 1652 | ||
1646 | vs = kmalloc(sizeof(*vs), GFP_KERNEL); | 1653 | vs = kmalloc(sizeof(*vs), GFP_KERNEL); |
1647 | if (!vs) | 1654 | if (!vs) { |
1655 | pr_debug("memory alocation failure\n"); | ||
1648 | return ERR_PTR(-ENOMEM); | 1656 | return ERR_PTR(-ENOMEM); |
1657 | } | ||
1649 | 1658 | ||
1650 | for (h = 0; h < VNI_HASH_SIZE; ++h) | 1659 | for (h = 0; h < VNI_HASH_SIZE; ++h) |
1651 | INIT_HLIST_HEAD(&vs->vni_list[h]); | 1660 | INIT_HLIST_HEAD(&vs->vni_list[h]); |
@@ -1673,57 +1682,57 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port) | |||
1673 | kfree(vs); | 1682 | kfree(vs); |
1674 | return ERR_PTR(rc); | 1683 | return ERR_PTR(rc); |
1675 | } | 1684 | } |
1685 | atomic_set(&vs->refcnt, 1); | ||
1676 | 1686 | ||
1677 | /* Disable multicast loopback */ | 1687 | /* Disable multicast loopback */ |
1678 | inet_sk(sk)->mc_loop = 0; | 1688 | inet_sk(sk)->mc_loop = 0; |
1689 | spin_lock(&vn->sock_lock); | ||
1690 | hlist_add_head_rcu(&vs->hlist, vs_head(net, port)); | ||
1691 | spin_unlock(&vn->sock_lock); | ||
1679 | 1692 | ||
1680 | /* Mark socket as an encapsulation socket. */ | 1693 | /* Mark socket as an encapsulation socket. */ |
1681 | udp_sk(sk)->encap_type = 1; | 1694 | udp_sk(sk)->encap_type = 1; |
1682 | udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv; | 1695 | udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv; |
1683 | udp_encap_enable(); | 1696 | udp_encap_enable(); |
1684 | atomic_set(&vs->refcnt, 1); | 1697 | return vs; |
1698 | } | ||
1699 | |||
1700 | static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port) | ||
1701 | { | ||
1702 | struct vxlan_net *vn = net_generic(net, vxlan_net_id); | ||
1703 | struct vxlan_sock *vs; | ||
1704 | |||
1705 | vs = vxlan_socket_create(net, port); | ||
1706 | if (!IS_ERR(vs)) | ||
1707 | return vs; | ||
1685 | 1708 | ||
1709 | spin_lock(&vn->sock_lock); | ||
1710 | vs = vxlan_find_sock(net, port); | ||
1711 | if (vs) | ||
1712 | atomic_inc(&vs->refcnt); | ||
1713 | else | ||
1714 | vs = ERR_PTR(-EINVAL); | ||
1715 | |||
1716 | spin_unlock(&vn->sock_lock); | ||
1686 | return vs; | 1717 | return vs; |
1687 | } | 1718 | } |
1688 | 1719 | ||
1689 | /* Scheduled at device creation to bind to a socket */ | 1720 | /* Scheduled at device creation to bind to a socket */ |
1690 | static void vxlan_sock_work(struct work_struct *work) | 1721 | static void vxlan_sock_work(struct work_struct *work) |
1691 | { | 1722 | { |
1692 | struct vxlan_dev *vxlan | 1723 | struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, sock_work); |
1693 | = container_of(work, struct vxlan_dev, sock_work); | 1724 | struct net *net = dev_net(vxlan->dev); |
1694 | struct net_device *dev = vxlan->dev; | ||
1695 | struct net *net = dev_net(dev); | ||
1696 | __u32 vni = vxlan->default_dst.remote_vni; | ||
1697 | __be16 port = vxlan->dst_port; | ||
1698 | struct vxlan_net *vn = net_generic(net, vxlan_net_id); | 1725 | struct vxlan_net *vn = net_generic(net, vxlan_net_id); |
1699 | struct vxlan_sock *nvs, *ovs; | 1726 | __be16 port = vxlan->dst_port; |
1700 | 1727 | struct vxlan_sock *nvs; | |
1701 | nvs = vxlan_socket_create(net, port); | ||
1702 | if (IS_ERR(nvs)) { | ||
1703 | netdev_err(vxlan->dev, "Can not create UDP socket, %ld\n", | ||
1704 | PTR_ERR(nvs)); | ||
1705 | goto out; | ||
1706 | } | ||
1707 | 1728 | ||
1729 | nvs = vxlan_sock_add(net, port); | ||
1708 | spin_lock(&vn->sock_lock); | 1730 | spin_lock(&vn->sock_lock); |
1709 | /* Look again to see if can reuse socket */ | 1731 | if (!IS_ERR(nvs)) |
1710 | ovs = vxlan_find_port(net, port); | 1732 | vxlan_vs_add_dev(nvs, vxlan); |
1711 | if (ovs) { | 1733 | spin_unlock(&vn->sock_lock); |
1712 | atomic_inc(&ovs->refcnt); | 1734 | |
1713 | vxlan->vn_sock = ovs; | 1735 | dev_put(vxlan->dev); |
1714 | hlist_add_head_rcu(&vxlan->hlist, vni_head(ovs, vni)); | ||
1715 | spin_unlock(&vn->sock_lock); | ||
1716 | |||
1717 | sk_release_kernel(nvs->sock->sk); | ||
1718 | kfree(nvs); | ||
1719 | } else { | ||
1720 | vxlan->vn_sock = nvs; | ||
1721 | hlist_add_head_rcu(&nvs->hlist, vs_head(net, port)); | ||
1722 | hlist_add_head_rcu(&vxlan->hlist, vni_head(nvs, vni)); | ||
1723 | spin_unlock(&vn->sock_lock); | ||
1724 | } | ||
1725 | out: | ||
1726 | dev_put(dev); | ||
1727 | } | 1736 | } |
1728 | 1737 | ||
1729 | static int vxlan_newlink(struct net *net, struct net_device *dev, | 1738 | static int vxlan_newlink(struct net *net, struct net_device *dev, |
@@ -1838,7 +1847,8 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head) | |||
1838 | struct vxlan_dev *vxlan = netdev_priv(dev); | 1847 | struct vxlan_dev *vxlan = netdev_priv(dev); |
1839 | 1848 | ||
1840 | spin_lock(&vn->sock_lock); | 1849 | spin_lock(&vn->sock_lock); |
1841 | hlist_del_rcu(&vxlan->hlist); | 1850 | if (!hlist_unhashed(&vxlan->hlist)) |
1851 | hlist_del_rcu(&vxlan->hlist); | ||
1842 | spin_unlock(&vn->sock_lock); | 1852 | spin_unlock(&vn->sock_lock); |
1843 | 1853 | ||
1844 | list_del(&vxlan->next); | 1854 | list_del(&vxlan->next); |