|
@@ -33,6 +33,7 @@
|
|
|
#include <net/ip_tunnels.h>
|
|
|
#include <net/icmp.h>
|
|
|
#include <net/udp.h>
|
|
|
+#include <net/udp_tunnel.h>
|
|
|
#include <net/rtnetlink.h>
|
|
|
#include <net/route.h>
|
|
|
#include <net/dsfield.h>
|
|
@@ -2339,102 +2340,37 @@ static void vxlan_del_work(struct work_struct *work)
|
|
|
kfree_rcu(vs, rcu);
|
|
|
}
|
|
|
|
|
|
-#if IS_ENABLED(CONFIG_IPV6)
|
|
|
-/* Create UDP socket for encapsulation receive. AF_INET6 socket
|
|
|
- * could be used for both IPv4 and IPv6 communications, but
|
|
|
- * users may set bindv6only=1.
|
|
|
- */
|
|
|
-static struct socket *create_v6_sock(struct net *net, __be16 port, u32 flags)
|
|
|
+static struct socket *vxlan_create_sock(struct net *net, bool ipv6,
|
|
|
+ __be16 port, u32 flags)
|
|
|
{
|
|
|
- struct sock *sk;
|
|
|
struct socket *sock;
|
|
|
- struct sockaddr_in6 vxlan_addr = {
|
|
|
- .sin6_family = AF_INET6,
|
|
|
- .sin6_port = port,
|
|
|
- };
|
|
|
- int rc, val = 1;
|
|
|
-
|
|
|
- rc = sock_create_kern(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
|
|
|
- if (rc < 0) {
|
|
|
- pr_debug("UDPv6 socket create failed\n");
|
|
|
- return ERR_PTR(rc);
|
|
|
- }
|
|
|
-
|
|
|
- /* Put in proper namespace */
|
|
|
- sk = sock->sk;
|
|
|
- sk_change_net(sk, net);
|
|
|
-
|
|
|
- kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
|
|
|
- (char *)&val, sizeof(val));
|
|
|
- rc = kernel_bind(sock, (struct sockaddr *)&vxlan_addr,
|
|
|
- sizeof(struct sockaddr_in6));
|
|
|
- if (rc < 0) {
|
|
|
- pr_debug("bind for UDPv6 socket %pI6:%u (%d)\n",
|
|
|
- &vxlan_addr.sin6_addr, ntohs(vxlan_addr.sin6_port), rc);
|
|
|
- sk_release_kernel(sk);
|
|
|
- return ERR_PTR(rc);
|
|
|
- }
|
|
|
- /* At this point, IPv6 module should have been loaded in
|
|
|
- * sock_create_kern().
|
|
|
- */
|
|
|
- BUG_ON(!ipv6_stub);
|
|
|
-
|
|
|
- /* Disable multicast loopback */
|
|
|
- inet_sk(sk)->mc_loop = 0;
|
|
|
-
|
|
|
- if (flags & VXLAN_F_UDP_ZERO_CSUM6_TX)
|
|
|
- udp_set_no_check6_tx(sk, true);
|
|
|
-
|
|
|
- if (flags & VXLAN_F_UDP_ZERO_CSUM6_RX)
|
|
|
- udp_set_no_check6_rx(sk, true);
|
|
|
-
|
|
|
- return sock;
|
|
|
-}
|
|
|
-
|
|
|
-#else
|
|
|
+ struct udp_port_cfg udp_conf;
|
|
|
+ int err;
|
|
|
|
|
|
-static struct socket *create_v6_sock(struct net *net, __be16 port, u32 flags)
|
|
|
-{
|
|
|
- return ERR_PTR(-EPFNOSUPPORT);
|
|
|
-}
|
|
|
-#endif
|
|
|
+ memset(&udp_conf, 0, sizeof(udp_conf));
|
|
|
|
|
|
-static struct socket *create_v4_sock(struct net *net, __be16 port, u32 flags)
|
|
|
-{
|
|
|
- struct sock *sk;
|
|
|
- struct socket *sock;
|
|
|
- struct sockaddr_in vxlan_addr = {
|
|
|
- .sin_family = AF_INET,
|
|
|
- .sin_addr.s_addr = htonl(INADDR_ANY),
|
|
|
- .sin_port = port,
|
|
|
- };
|
|
|
- int rc;
|
|
|
-
|
|
|
- /* Create UDP socket for encapsulation receive. */
|
|
|
- rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
|
|
|
- if (rc < 0) {
|
|
|
- pr_debug("UDP socket create failed\n");
|
|
|
- return ERR_PTR(rc);
|
|
|
+ if (ipv6) {
|
|
|
+ udp_conf.family = AF_INET6;
|
|
|
+ udp_conf.use_udp6_tx_checksums =
|
|
|
+ !!(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
|
|
|
+ udp_conf.use_udp6_rx_checksums =
|
|
|
+ !!(flags & VXLAN_F_UDP_ZERO_CSUM6_RX);
|
|
|
+ } else {
|
|
|
+ udp_conf.family = AF_INET;
|
|
|
+ udp_conf.local_ip.s_addr = INADDR_ANY;
|
|
|
+ udp_conf.use_udp_checksums =
|
|
|
+ !!(flags & VXLAN_F_UDP_CSUM);
|
|
|
}
|
|
|
|
|
|
- /* Put in proper namespace */
|
|
|
- sk = sock->sk;
|
|
|
- sk_change_net(sk, net);
|
|
|
+ udp_conf.local_udp_port = port;
|
|
|
|
|
|
- rc = kernel_bind(sock, (struct sockaddr *) &vxlan_addr,
|
|
|
- sizeof(vxlan_addr));
|
|
|
- if (rc < 0) {
|
|
|
- pr_debug("bind for UDP socket %pI4:%u (%d)\n",
|
|
|
- &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
|
|
|
- sk_release_kernel(sk);
|
|
|
- return ERR_PTR(rc);
|
|
|
- }
|
|
|
+ /* Open UDP socket */
|
|
|
+ err = udp_sock_create(net, &udp_conf, &sock);
|
|
|
+ if (err < 0)
|
|
|
+ return ERR_PTR(err);
|
|
|
|
|
|
/* Disable multicast loopback */
|
|
|
- inet_sk(sk)->mc_loop = 0;
|
|
|
-
|
|
|
- if (!(flags & VXLAN_F_UDP_CSUM))
|
|
|
- sock->sk->sk_no_check_tx = 1;
|
|
|
+ inet_sk(sock->sk)->mc_loop = 0;
|
|
|
|
|
|
return sock;
|
|
|
}
|
|
@@ -2460,10 +2396,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
|
|
|
|
|
|
INIT_WORK(&vs->del_work, vxlan_del_work);
|
|
|
|
|
|
- if (ipv6)
|
|
|
- sock = create_v6_sock(net, port, flags);
|
|
|
- else
|
|
|
- sock = create_v4_sock(net, port, flags);
|
|
|
+ sock = vxlan_create_sock(net, ipv6, port, flags);
|
|
|
if (IS_ERR(sock)) {
|
|
|
kfree(vs);
|
|
|
return ERR_CAST(sock);
|