summaryrefslogtreecommitdiff
path: root/datapath
diff options
context:
space:
mode:
authorPravin B Shelar <pshelar@ovn.org>2016-07-07 21:51:17 -0700
committerPravin B Shelar <pshelar@ovn.org>2016-07-08 19:27:49 -0700
commitb7ebebcdd7d6513fee9b3f181c47bb5b11a08297 (patch)
tree4c5fd0d3f23255ffb21c31c02033cabf672ffb4f /datapath
parent1c95839fee02afa9396a799fff7e42634b1e598a (diff)
downloadopenvswitch-b7ebebcdd7d6513fee9b3f181c47bb5b11a08297.tar.gz
datapath: compat: Update udp_sock_create
Update udp-socket-create to create ipv6 socket currectly. Partially backports commit fd384412e199b ("udp_tunnel: Seperate ipv6 functions into its own file.") Signed-off-by: Pravin B Shelar <pshelar@ovn.org> Acked-by: Jesse Gross <jesse@kernel.org>
Diffstat (limited to 'datapath')
-rw-r--r--datapath/linux/Modules.mk1
-rw-r--r--datapath/linux/compat/include/linux/udp.h33
-rw-r--r--datapath/linux/compat/include/net/udp.h1
-rw-r--r--datapath/linux/compat/include/net/udp_tunnel.h30
-rw-r--r--datapath/linux/compat/udp.c12
-rw-r--r--datapath/linux/compat/udp_tunnel.c123
-rw-r--r--datapath/linux/compat/vxlan.c7
7 files changed, 153 insertions, 54 deletions
diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
index ae7c75324..ef080837b 100644
--- a/datapath/linux/Modules.mk
+++ b/datapath/linux/Modules.mk
@@ -67,6 +67,7 @@ openvswitch_headers += \
linux/compat/include/linux/stddef.h \
linux/compat/include/linux/types.h \
linux/compat/include/linux/u64_stats_sync.h \
+ linux/compat/include/linux/udp.h \
linux/compat/include/linux/workqueue.h \
linux/compat/include/net/checksum.h \
linux/compat/include/net/dst.h \
diff --git a/datapath/linux/compat/include/linux/udp.h b/datapath/linux/compat/include/linux/udp.h
new file mode 100644
index 000000000..22e57d4c0
--- /dev/null
+++ b/datapath/linux/compat/include/linux/udp.h
@@ -0,0 +1,33 @@
+#ifndef __LINUX_UDP_WRAPPER_H
+#define __LINUX_UDP_WRAPPER_H 1
+
+#include_next <linux/udp.h>
+#include <linux/ipv6.h>
+
+#ifndef HAVE_NO_CHECK6_TX
+static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
+{
+#ifdef HAVE_SK_NO_CHECK_TX
+ sk->sk_no_check_tx = val;
+#endif
+}
+
+static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
+{
+#ifdef HAVE_SK_NO_CHECK_TX
+ sk->sk_no_check_rx = val;
+#else
+ /* since netwroking stack is not checking for zero UDP checksum
+ * check it in OVS module. */
+ #define OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
+#endif
+}
+#endif
+
+#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
+#define udp6_csum_zero_error rpl_udp6_csum_zero_error
+
+void rpl_udp6_csum_zero_error(struct sk_buff *skb);
+#endif
+
+#endif
diff --git a/datapath/linux/compat/include/net/udp.h b/datapath/linux/compat/include/net/udp.h
index 41254aad7..fa49fa573 100644
--- a/datapath/linux/compat/include/net/udp.h
+++ b/datapath/linux/compat/include/net/udp.h
@@ -59,5 +59,4 @@ static inline __sum16 udp_v4_check(int len, __be32 saddr,
void rpl_udp_set_csum(bool nocheck, struct sk_buff *skb,
__be32 saddr, __be32 daddr, int len);
#endif
-
#endif
diff --git a/datapath/linux/compat/include/net/udp_tunnel.h b/datapath/linux/compat/include/net/udp_tunnel.h
index 605fe63e3..d953e091b 100644
--- a/datapath/linux/compat/include/net/udp_tunnel.h
+++ b/datapath/linux/compat/include/net/udp_tunnel.h
@@ -41,9 +41,35 @@ struct udp_port_cfg {
ipv6_v6only:1;
};
+#define udp_sock_create4 rpl_udp_sock_create4
+int rpl_udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
+ struct socket **sockp);
+
+#define udp_sock_create6 rpl_udp_sock_create6
+#if IS_ENABLED(CONFIG_IPV6)
+int rpl_udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
+ struct socket **sockp);
+#else
+static inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
+ struct socket **sockp)
+{
+ return -EPFNOSUPPORT;
+}
+#endif
+
#define udp_sock_create rpl_udp_sock_create
-int rpl_udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
- struct socket **sockp);
+static inline int udp_sock_create(struct net *net,
+ struct udp_port_cfg *cfg,
+ struct socket **sockp)
+{
+ if (cfg->family == AF_INET)
+ return udp_sock_create4(net, cfg, sockp);
+
+ if (cfg->family == AF_INET6)
+ return udp_sock_create6(net, cfg, sockp);
+
+ return -EPFNOSUPPORT;
+}
typedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb);
typedef void (*udp_tunnel_encap_destroy_t)(struct sock *sk);
diff --git a/datapath/linux/compat/udp.c b/datapath/linux/compat/udp.c
index 487d317bb..f0362b64d 100644
--- a/datapath/linux/compat/udp.c
+++ b/datapath/linux/compat/udp.c
@@ -42,3 +42,15 @@ void rpl_udp_set_csum(bool nocheck, struct sk_buff *skb,
EXPORT_SYMBOL_GPL(rpl_udp_set_csum);
#endif /* Linux version < 3.16 */
+
+#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
+void rpl_udp6_csum_zero_error(struct sk_buff *skb)
+{
+ /* RFC 2460 section 8.1 says that we SHOULD log
+ * this error. Well, it is reasonable.
+ */
+ net_dbg_ratelimited("IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
+ &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source),
+ &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest));
+}
+#endif
diff --git a/datapath/linux/compat/udp_tunnel.c b/datapath/linux/compat/udp_tunnel.c
index b4d345b56..daa3fa15f 100644
--- a/datapath/linux/compat/udp_tunnel.c
+++ b/datapath/linux/compat/udp_tunnel.c
@@ -16,74 +16,95 @@
#include <net/ip6_tunnel.h>
-int rpl_udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
- struct socket **sockp)
+int rpl_udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
+ struct socket **sockp)
{
int err;
struct socket *sock = NULL;
+ struct sockaddr_in udp_addr;
-#if IS_ENABLED(CONFIG_IPV6)
- if (cfg->family == AF_INET6) {
- struct sockaddr_in6 udp6_addr;
+ err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock);
+ if (err < 0)
+ goto error;
- err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock);
- 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;
+ err = kernel_bind(sock, (struct sockaddr *)&udp_addr,
+ sizeof(udp_addr));
+ if (err < 0)
+ goto error;
- 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 (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
+ }
+#ifdef HAVE_SK_NO_CHECK_TX
+ sock->sk->sk_no_check_tx = !cfg->use_udp_checksums;
#endif
- if (cfg->family == AF_INET) {
- struct sockaddr_in udp_addr;
+ *sockp = sock;
+ return 0;
- err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock);
- if (err < 0)
- goto error;
+error:
+ if (sock) {
+ kernel_sock_shutdown(sock, SHUT_RDWR);
+ sock_release(sock);
+ }
+ *sockp = NULL;
+ return err;
+}
+EXPORT_SYMBOL(rpl_udp_sock_create4);
- 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));
+int rpl_udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
+ struct socket **sockp)
+{
+ struct sockaddr_in6 udp6_addr;
+ int err;
+ struct socket *sock = NULL;
+
+ err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock);
+ if (err < 0)
+ goto error;
+
+ if (cfg->ipv6_v6only) {
+ int val = 1;
+
+ err = kernel_setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *) &val, sizeof(val));
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;
+ 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;
+ udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums);
+ udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums);
*sockp = sock;
-
return 0;
error:
@@ -94,7 +115,7 @@ error:
*sockp = NULL;
return err;
}
-EXPORT_SYMBOL_GPL(rpl_udp_sock_create);
+EXPORT_SYMBOL_GPL(rpl_udp_sock_create6);
void rpl_setup_udp_tunnel_sock(struct net *net, struct socket *sock,
struct udp_tunnel_sock_cfg *cfg)
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
index d45125d4c..37769903c 100644
--- a/datapath/linux/compat/vxlan.c
+++ b/datapath/linux/compat/vxlan.c
@@ -850,6 +850,13 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
oip6 = ipv6_hdr(skb);
saddr.sin6.sin6_addr = oip6->saddr;
saddr.sa.sa_family = AF_INET6;
+#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
+ if (!udp_hdr(skb)->check &&
+ !(vs->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) {
+ udp6_csum_zero_error(skb);
+ goto drop;
+ }
+#endif
#endif
}