1 #include <linux/version.h>
3 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,20,0)
5 #include <linux/module.h>
6 #include <linux/errno.h>
7 #include <linux/socket.h>
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <net/ip_tunnels.h>
13 #include <net/udp_tunnel.h>
14 #include <net/net_namespace.h>
16 int udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
17 struct socket **sockp)
20 struct socket *sock = NULL;
22 #if IS_ENABLED(CONFIG_IPV6)
23 if (cfg->family == AF_INET6) {
24 struct sockaddr_in6 udp6_addr;
26 err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock);
30 sk_change_net(sock->sk, net);
32 udp6_addr.sin6_family = AF_INET6;
33 memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6,
34 sizeof(udp6_addr.sin6_addr));
35 udp6_addr.sin6_port = cfg->local_udp_port;
36 err = kernel_bind(sock, (struct sockaddr *)&udp6_addr,
41 if (cfg->peer_udp_port) {
42 udp6_addr.sin6_family = AF_INET6;
43 memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6,
44 sizeof(udp6_addr.sin6_addr));
45 udp6_addr.sin6_port = cfg->peer_udp_port;
46 err = kernel_connect(sock,
47 (struct sockaddr *)&udp6_addr,
48 sizeof(udp6_addr), 0);
54 if (cfg->family == AF_INET) {
55 struct sockaddr_in udp_addr;
57 err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock);
61 sk_change_net(sock->sk, net);
63 udp_addr.sin_family = AF_INET;
64 udp_addr.sin_addr = cfg->local_ip;
65 udp_addr.sin_port = cfg->local_udp_port;
66 err = kernel_bind(sock, (struct sockaddr *)&udp_addr,
71 if (cfg->peer_udp_port) {
72 udp_addr.sin_family = AF_INET;
73 udp_addr.sin_addr = cfg->peer_ip;
74 udp_addr.sin_port = cfg->peer_udp_port;
75 err = kernel_connect(sock,
76 (struct sockaddr *)&udp_addr,
92 kernel_sock_shutdown(sock, SHUT_RDWR);
93 sk_release_kernel(sock->sk);
98 EXPORT_SYMBOL_GPL(udp_sock_create);
100 void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
101 struct udp_tunnel_sock_cfg *cfg)
103 struct sock *sk = sock->sk;
105 /* Disable multicast loopback */
106 inet_sk(sk)->mc_loop = 0;
108 rcu_assign_sk_user_data(sk, cfg->sk_user_data);
110 udp_sk(sk)->encap_type = cfg->encap_type;
111 udp_sk(sk)->encap_rcv = cfg->encap_rcv;
112 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
113 udp_sk(sk)->encap_destroy = cfg->encap_destroy;
116 udp_tunnel_encap_enable(sock);
118 EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock);
120 void ovs_udp_gso(struct sk_buff *skb)
122 int udp_offset = skb_transport_offset(skb);
126 uh->len = htons(skb->len - udp_offset);
128 EXPORT_SYMBOL_GPL(ovs_udp_gso);
130 void ovs_udp_csum_gso(struct sk_buff *skb)
132 struct iphdr *iph = ip_hdr(skb);
133 int udp_offset = skb_transport_offset(skb);
137 /* csum segment if tunnel sets skb with csum. The cleanest way
138 * to do this just to set it up from scratch. */
139 skb->ip_summed = CHECKSUM_NONE;
140 udp_set_csum(true, skb, iph->saddr, iph->daddr,
141 skb->len - udp_offset);
143 EXPORT_SYMBOL_GPL(ovs_udp_csum_gso);
145 int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb,
146 __be32 src, __be32 dst, __u8 tos, __u8 ttl,
147 __be16 df, __be16 src_port, __be16 dst_port,
148 bool xnet, bool nocheck)
152 __skb_push(skb, sizeof(*uh));
153 skb_reset_transport_header(skb);
157 uh->source = src_port;
158 uh->len = htons(skb->len);
160 udp_set_csum(nocheck, skb, src, dst, skb->len);
162 return iptunnel_xmit(skb->sk, rt, skb, src, dst, IPPROTO_UDP,
165 EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb);
167 void udp_tunnel_sock_release(struct socket *sock)
169 rcu_assign_sk_user_data(sock->sk, NULL);
170 kernel_sock_shutdown(sock, SHUT_RDWR);
171 sk_release_kernel(sock->sk);
173 EXPORT_SYMBOL_GPL(udp_tunnel_sock_release);
175 #endif /* Linux version < 3.20 */