From eb6eebd28b30d2b39419764a1e843ed30405c3b9 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 6 Feb 2015 15:16:20 -0800 Subject: [PATCH] datapath: Account for "udp: Add udp_sock_create for UDP tunnels to open listener socket" Upstream commit: udp: Add udp_sock_create for UDP tunnels to open listener socket Added udp_tunnel.c which can contain some common functions for UDP tunnels. The first function in this is udp_sock_create which is used to open the listener port for a UDP tunnel. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller Upstream: 8024e028 ("udp: Add udp_sock_create for UDP tunnels to open listener socket") Signed-off-by: Jesse Gross Acked-by: Thomas Graf --- datapath/linux/.gitignore | 1 + datapath/linux/Modules.mk | 2 + .../linux/compat/include/net/udp_tunnel.h | 40 ++++++++ datapath/linux/compat/udp_tunnel.c | 98 +++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 datapath/linux/compat/include/net/udp_tunnel.h create mode 100644 datapath/linux/compat/udp_tunnel.c diff --git a/datapath/linux/.gitignore b/datapath/linux/.gitignore index be233fcc3ee..fb19d78bed1 100644 --- a/datapath/linux/.gitignore +++ b/datapath/linux/.gitignore @@ -38,6 +38,7 @@ /time.c /tmp /tunnel.c +/udp_tunnel.c /utils.c /vlan.c /vport-generic.c diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk index a4633318ad5..945f8591108 100644 --- a/datapath/linux/Modules.mk +++ b/datapath/linux/Modules.mk @@ -11,6 +11,7 @@ openvswitch_sources += \ linux/compat/net_namespace.c \ linux/compat/reciprocal_div.c \ linux/compat/skbuff-openvswitch.c \ + linux/compat/udp_tunnel.c \ linux/compat/vxlan.c \ linux/compat/utils.c openvswitch_headers += \ @@ -71,6 +72,7 @@ openvswitch_headers += \ linux/compat/include/net/net_namespace.h \ linux/compat/include/net/netlink.h \ linux/compat/include/net/udp.h \ + linux/compat/include/net/udp_tunnel.h \ linux/compat/include/net/sock.h \ linux/compat/include/net/vxlan.h \ linux/compat/include/net/sctp/checksum.h diff --git a/datapath/linux/compat/include/net/udp_tunnel.h b/datapath/linux/compat/include/net/udp_tunnel.h new file mode 100644 index 00000000000..f25023f847a --- /dev/null +++ b/datapath/linux/compat/include/net/udp_tunnel.h @@ -0,0 +1,40 @@ +#ifndef __NET_UDP_TUNNEL_WRAPPER_H +#define __NET_UDP_TUNNEL_WRAPPER_H + +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +#include_next +#else + +struct udp_port_cfg { + u8 family; + + /* Used only for kernel-created sockets */ + union { + struct in_addr local_ip; +#if IS_ENABLED(CONFIG_IPV6) + struct in6_addr local_ip6; +#endif + }; + + union { + struct in_addr peer_ip; +#if IS_ENABLED(CONFIG_IPV6) + struct in6_addr peer_ip6; +#endif + }; + + __be16 local_udp_port; + __be16 peer_udp_port; + unsigned int use_udp_checksums:1, + use_udp6_tx_checksums:1, + use_udp6_rx_checksums:1; +}; + +int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, + struct socket **sockp); + +#endif /* Linux version < 3.17 */ +#endif diff --git a/datapath/linux/compat/udp_tunnel.c b/datapath/linux/compat/udp_tunnel.c new file mode 100644 index 00000000000..e5fd224075a --- /dev/null +++ b/datapath/linux/compat/udp_tunnel.c @@ -0,0 +1,98 @@ +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, + struct socket **sockp) +{ + int err = -EINVAL; + struct socket *sock = NULL; + +#if IS_ENABLED(CONFIG_IPV6) + if (cfg->family == AF_INET6) { + struct sockaddr_in6 udp6_addr; + + err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); + if (err < 0) + goto error; + + sk_change_net(sock->sk, net); + + udp6_addr.sin6_family = AF_INET6; + memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6, + sizeof(udp6_addr.sin6_addr)); + udp6_addr.sin6_port = cfg->local_udp_port; + err = kernel_bind(sock, (struct sockaddr *)&udp6_addr, + sizeof(udp6_addr)); + if (err < 0) + goto error; + + if (cfg->peer_udp_port) { + udp6_addr.sin6_family = AF_INET6; + memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6, + sizeof(udp6_addr.sin6_addr)); + udp6_addr.sin6_port = cfg->peer_udp_port; + err = kernel_connect(sock, + (struct sockaddr *)&udp6_addr, + sizeof(udp6_addr), 0); + } + if (err < 0) + goto error; + } else +#endif + if (cfg->family == AF_INET) { + struct sockaddr_in udp_addr; + + err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); + if (err < 0) + goto error; + + sk_change_net(sock->sk, net); + + udp_addr.sin_family = AF_INET; + udp_addr.sin_addr = cfg->local_ip; + udp_addr.sin_port = cfg->local_udp_port; + err = kernel_bind(sock, (struct sockaddr *)&udp_addr, + sizeof(udp_addr)); + if (err < 0) + goto error; + + if (cfg->peer_udp_port) { + udp_addr.sin_family = AF_INET; + udp_addr.sin_addr = cfg->peer_ip; + udp_addr.sin_port = cfg->peer_udp_port; + err = kernel_connect(sock, + (struct sockaddr *)&udp_addr, + sizeof(udp_addr), 0); + if (err < 0) + goto error; + } + } else { + return -EPFNOSUPPORT; + } + + + *sockp = sock; + + return 0; + +error: + if (sock) { + kernel_sock_shutdown(sock, SHUT_RDWR); + sk_release_kernel(sock->sk); + } + *sockp = NULL; + return err; +} + +#endif /* Linux version < 3.17 */