UDP tunnel sockets are always opened unbound to a specific device. This
patch allow the socket to be bound on a custom device, which
incidentally makes UDP tunnels VRF-aware if binding to an l3mdev.

Signed-off-by: Alexis Bauvin <abau...@scaleway.com>
Reviewed-by: Amine Kherbouche <akherbou...@scaleway.com>
Tested-by: Amine Kherbouche <akherbou...@scaleway.com>
---
 include/net/udp_tunnel.h  |  1 +
 net/ipv4/udp_tunnel.c     | 17 +++++++++++++++++
 net/ipv6/ip6_udp_tunnel.c | 16 ++++++++++++++++
 3 files changed, 34 insertions(+)

diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h
index fe680ab6b15a..9f7970d010f9 100644
--- a/include/net/udp_tunnel.h
+++ b/include/net/udp_tunnel.h
@@ -30,6 +30,7 @@ struct udp_port_cfg {
 
        __be16                  local_udp_port;
        __be16                  peer_udp_port;
+       int                     bind_ifindex;
        unsigned int            use_udp_checksums:1,
                                use_udp6_tx_checksums:1,
                                use_udp6_rx_checksums:1,
diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c
index 6539ff15e9a3..b7a8d355ff57 100644
--- a/net/ipv4/udp_tunnel.c
+++ b/net/ipv4/udp_tunnel.c
@@ -20,6 +20,23 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg 
*cfg,
        if (err < 0)
                goto error;
 
+       if (cfg->bind_ifindex) {
+               struct net_device *dev;
+
+               dev = dev_get_by_index(net, cfg->bind_ifindex);
+               if (!dev) {
+                       err = -ENODEV;
+                       goto error;
+               }
+
+               err = kernel_setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
+                                       dev->name, strlen(dev->name) + 1);
+               dev_put(dev);
+
+               if (err < 0)
+                       goto error;
+       }
+
        udp_addr.sin_family = AF_INET;
        udp_addr.sin_addr = cfg->local_ip;
        udp_addr.sin_port = cfg->local_udp_port;
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c
index b283f293ee4a..3965d5396b0a 100644
--- a/net/ipv6/ip6_udp_tunnel.c
+++ b/net/ipv6/ip6_udp_tunnel.c
@@ -31,6 +31,22 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg 
*cfg,
                if (err < 0)
                        goto error;
        }
+       if (cfg->bind_ifindex) {
+               struct net_device *dev;
+
+               dev = dev_get_by_index(net, cfg->bind_ifindex);
+               if (!dev) {
+                       err = -ENODEV;
+                       goto error;
+               }
+
+               err = kernel_setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
+                                       dev->name, strlen(dev->name) + 1);
+               dev_put(dev);
+
+               if (err < 0)
+                       goto error;
+       }
 
        udp6_addr.sin6_family = AF_INET6;
        memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6,
-- 

Reply via email to