summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJoseph Gasparakis <joseph.gasparakis@intel.com>2013-09-04 02:13:38 -0700
committerDavid S. Miller <davem@davemloft.net>2013-09-05 12:44:30 -0400
commit53cf527513eed6e7170e9dceacd198f9267171b0 (patch)
treea3492c0373949048084213dc4bd02efd130aa5cf /drivers
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/vxlan.c68
1 files changed, 67 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,
return 1;
}
+/* Notify netdevs that UDP port started listening */
+static void vxlan_notify_add_rx_port(struct sock *sk)
+{
+ struct net_device *dev;
+ struct net *net = sock_net(sk);
+ sa_family_t sa_family = sk->sk_family;
+ u16 port = htons(inet_sk(sk)->inet_sport);
+
+ rcu_read_lock();
+ for_each_netdev_rcu(net, dev) {
+ if (dev->netdev_ops->ndo_add_vxlan_port)
+ dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
+ port);
+ }
+ rcu_read_unlock();
+}
+
+/* Notify netdevs that UDP port is no more listening */
+static void vxlan_notify_del_rx_port(struct sock *sk)
+{
+ struct net_device *dev;
+ struct net *net = sock_net(sk);
+ sa_family_t sa_family = sk->sk_family;
+ u16 port = htons(inet_sk(sk)->inet_sport);
+
+ rcu_read_lock();
+ for_each_netdev_rcu(net, dev) {
+ if (dev->netdev_ops->ndo_del_vxlan_port)
+ dev->netdev_ops->ndo_del_vxlan_port(dev, sa_family,
+ port);
+ }
+ rcu_read_unlock();
+}
+
/* Add new entry to forwarding table -- assumes lock held */
static int vxlan_fdb_create(struct vxlan_dev *vxlan,
const u8 *mac, union vxlan_addr *ip,
@@ -909,7 +943,9 @@ static void vxlan_sock_hold(struct vxlan_sock *vs)
void vxlan_sock_release(struct vxlan_sock *vs)
{
- struct vxlan_net *vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id);
+ struct sock *sk = vs->sock->sk;
+ struct net *net = sock_net(sk);
+ struct vxlan_net *vn = net_generic(net, vxlan_net_id);
if (!atomic_dec_and_test(&vs->refcnt))
return;
@@ -918,6 +954,7 @@ void vxlan_sock_release(struct vxlan_sock *vs)
hlist_del_rcu(&vs->hlist);
smp_wmb();
vs->sock->sk->sk_user_data = NULL;
+ vxlan_notify_del_rx_port(sk);
spin_unlock(&vn->sock_lock);
queue_work(vxlan_wq, &vs->del_work);
@@ -1983,6 +2020,34 @@ static struct device_type vxlan_type = {
.name = "vxlan",
};
+/* Calls the ndo_add_vxlan_port of the caller in order to
+ * supply the listening VXLAN udp ports.
+ */
+void vxlan_get_rx_port(struct net_device *dev)
+{
+ struct vxlan_sock *vs;
+ struct net *net = dev_net(dev);
+ struct vxlan_net *vn = net_generic(net, vxlan_net_id);
+ sa_family_t sa_family;
+ u16 port;
+ int i;
+
+ if (!dev || !dev->netdev_ops || !dev->netdev_ops->ndo_add_vxlan_port)
+ return;
+
+ spin_lock(&vn->sock_lock);
+ for (i = 0; i < PORT_HASH_SIZE; ++i) {
+ hlist_for_each_entry_rcu(vs, vs_head(net, i), hlist) {
+ port = htons(inet_sk(vs->sock->sk)->inet_sport);
+ sa_family = vs->sock->sk->sk_family;
+ dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
+ port);
+ }
+ }
+ spin_unlock(&vn->sock_lock);
+}
+EXPORT_SYMBOL_GPL(vxlan_get_rx_port);
+
/* Initialize the device structure. */
static void vxlan_setup(struct net_device *dev)
{
@@ -2244,6 +2309,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
spin_lock(&vn->sock_lock);
hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
+ vxlan_notify_add_rx_port(sk);
spin_unlock(&vn->sock_lock);
/* Mark socket as an encapsulation socket. */