aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoseph Gasparakis <joseph.gasparakis@intel.com>2013-09-04 05:13:38 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-05 12:44:30 -0400
commit53cf527513eed6e7170e9dceacd198f9267171b0 (patch)
treea3492c0373949048084213dc4bd02efd130aa5cf
parenteef23b53985f8e08256f24d76e576d69fb0d44d3 (diff)
vxlan: Notify drivers for listening UDP port changes
This patch adds two more ndo ops: ndo_add_rx_vxlan_port() and ndo_del_rx_vxlan_port(). Drivers can get notifications through the above functions about changes of the UDP listening port of VXLAN. Also, when physical ports come up, now they can call vxlan_get_rx_port() in order to obtain the port number(s) of the existing VXLAN interface in case they already up before them. This information about the listening UDP port would be used for VXLAN related offloads. A big thank you to John Fastabend (john.r.fastabend@intel.com) for his input and his suggestions on this patch set. CC: John Fastabend <john.r.fastabend@intel.com> CC: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: Joseph Gasparakis <joseph.gasparakis@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/vxlan.c68
-rw-r--r--include/linux/netdevice.h19
-rw-r--r--include/net/vxlan.h1
3 files changed, 87 insertions, 1 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index bd35d2dfc50a..bf64b4191dcc 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -558,6 +558,40 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
558 return 1; 558 return 1;
559} 559}
560 560
561/* Notify netdevs that UDP port started listening */
562static void vxlan_notify_add_rx_port(struct sock *sk)
563{
564 struct net_device *dev;
565 struct net *net = sock_net(sk);
566 sa_family_t sa_family = sk->sk_family;
567 u16 port = htons(inet_sk(sk)->inet_sport);
568
569 rcu_read_lock();
570 for_each_netdev_rcu(net, dev) {
571 if (dev->netdev_ops->ndo_add_vxlan_port)
572 dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
573 port);
574 }
575 rcu_read_unlock();
576}
577
578/* Notify netdevs that UDP port is no more listening */
579static void vxlan_notify_del_rx_port(struct sock *sk)
580{
581 struct net_device *dev;
582 struct net *net = sock_net(sk);
583 sa_family_t sa_family = sk->sk_family;
584 u16 port = htons(inet_sk(sk)->inet_sport);
585
586 rcu_read_lock();
587 for_each_netdev_rcu(net, dev) {
588 if (dev->netdev_ops->ndo_del_vxlan_port)
589 dev->netdev_ops->ndo_del_vxlan_port(dev, sa_family,
590 port);
591 }
592 rcu_read_unlock();
593}
594
561/* Add new entry to forwarding table -- assumes lock held */ 595/* Add new entry to forwarding table -- assumes lock held */
562static int vxlan_fdb_create(struct vxlan_dev *vxlan, 596static int vxlan_fdb_create(struct vxlan_dev *vxlan,
563 const u8 *mac, union vxlan_addr *ip, 597 const u8 *mac, union vxlan_addr *ip,
@@ -909,7 +943,9 @@ static void vxlan_sock_hold(struct vxlan_sock *vs)
909 943
910void vxlan_sock_release(struct vxlan_sock *vs) 944void vxlan_sock_release(struct vxlan_sock *vs)
911{ 945{
912 struct vxlan_net *vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id); 946 struct sock *sk = vs->sock->sk;
947 struct net *net = sock_net(sk);
948 struct vxlan_net *vn = net_generic(net, vxlan_net_id);
913 949
914 if (!atomic_dec_and_test(&vs->refcnt)) 950 if (!atomic_dec_and_test(&vs->refcnt))
915 return; 951 return;
@@ -918,6 +954,7 @@ void vxlan_sock_release(struct vxlan_sock *vs)
918 hlist_del_rcu(&vs->hlist); 954 hlist_del_rcu(&vs->hlist);
919 smp_wmb(); 955 smp_wmb();
920 vs->sock->sk->sk_user_data = NULL; 956 vs->sock->sk->sk_user_data = NULL;
957 vxlan_notify_del_rx_port(sk);
921 spin_unlock(&vn->sock_lock); 958 spin_unlock(&vn->sock_lock);
922 959
923 queue_work(vxlan_wq, &vs->del_work); 960 queue_work(vxlan_wq, &vs->del_work);
@@ -1983,6 +2020,34 @@ static struct device_type vxlan_type = {
1983 .name = "vxlan", 2020 .name = "vxlan",
1984}; 2021};
1985 2022
2023/* Calls the ndo_add_vxlan_port of the caller in order to
2024 * supply the listening VXLAN udp ports.
2025 */
2026void vxlan_get_rx_port(struct net_device *dev)
2027{
2028 struct vxlan_sock *vs;
2029 struct net *net = dev_net(dev);
2030 struct vxlan_net *vn = net_generic(net, vxlan_net_id);
2031 sa_family_t sa_family;
2032 u16 port;
2033 int i;
2034
2035 if (!dev || !dev->netdev_ops || !dev->netdev_ops->ndo_add_vxlan_port)
2036 return;
2037
2038 spin_lock(&vn->sock_lock);
2039 for (i = 0; i < PORT_HASH_SIZE; ++i) {
2040 hlist_for_each_entry_rcu(vs, vs_head(net, i), hlist) {
2041 port = htons(inet_sk(vs->sock->sk)->inet_sport);
2042 sa_family = vs->sock->sk->sk_family;
2043 dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
2044 port);
2045 }
2046 }
2047 spin_unlock(&vn->sock_lock);
2048}
2049EXPORT_SYMBOL_GPL(vxlan_get_rx_port);
2050
1986/* Initialize the device structure. */ 2051/* Initialize the device structure. */
1987static void vxlan_setup(struct net_device *dev) 2052static void vxlan_setup(struct net_device *dev)
1988{ 2053{
@@ -2244,6 +2309,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
2244 2309
2245 spin_lock(&vn->sock_lock); 2310 spin_lock(&vn->sock_lock);
2246 hlist_add_head_rcu(&vs->hlist, vs_head(net, port)); 2311 hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
2312 vxlan_notify_add_rx_port(sk);
2247 spin_unlock(&vn->sock_lock); 2313 spin_unlock(&vn->sock_lock);
2248 2314
2249 /* Mark socket as an encapsulation socket. */ 2315 /* Mark socket as an encapsulation socket. */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3ad49b833eab..8ed4ae943053 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -948,6 +948,19 @@ struct netdev_phys_port_id {
948 * Called to get ID of physical port of this device. If driver does 948 * Called to get ID of physical port of this device. If driver does
949 * not implement this, it is assumed that the hw is not able to have 949 * not implement this, it is assumed that the hw is not able to have
950 * multiple net devices on single physical port. 950 * multiple net devices on single physical port.
951 *
952 * void (*ndo_add_vxlan_port)(struct net_device *dev,
953 * sa_family_t sa_family, __u16 port);
954 * Called by vxlan to notiy a driver about the UDP port and socket
955 * address family that vxlan is listnening to. It is called only when
956 * a new port starts listening. The operation is protected by the
957 * vxlan_net->sock_lock.
958 *
959 * void (*ndo_del_vxlan_port)(struct net_device *dev,
960 * sa_family_t sa_family, __u16 port);
961 * Called by vxlan to notify the driver about a UDP port and socket
962 * address family that vxlan is not listening to anymore. The operation
963 * is protected by the vxlan_net->sock_lock.
951 */ 964 */
952struct net_device_ops { 965struct net_device_ops {
953 int (*ndo_init)(struct net_device *dev); 966 int (*ndo_init)(struct net_device *dev);
@@ -1078,6 +1091,12 @@ struct net_device_ops {
1078 bool new_carrier); 1091 bool new_carrier);
1079 int (*ndo_get_phys_port_id)(struct net_device *dev, 1092 int (*ndo_get_phys_port_id)(struct net_device *dev,
1080 struct netdev_phys_port_id *ppid); 1093 struct netdev_phys_port_id *ppid);
1094 void (*ndo_add_vxlan_port)(struct net_device *dev,
1095 sa_family_t sa_family,
1096 __u16 port);
1097 void (*ndo_del_vxlan_port)(struct net_device *dev,
1098 sa_family_t sa_family,
1099 __u16 port);
1081}; 1100};
1082 1101
1083/* 1102/*
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index e09c40b68027..2d64d3cd4999 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -36,4 +36,5 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
36 36
37__be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb); 37__be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb);
38 38
39void vxlan_get_rx_port(struct net_device *netdev);
39#endif 40#endif