diff options
author | Andy Zhou <azhou@nicira.com> | 2014-09-16 20:31:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-19 15:57:15 -0400 |
commit | 6a93cc9052748c6355ec9d5b6c38b77f85f1cb0d (patch) | |
tree | 4855feb2fa46451d755bf841a3e463ba2a8053a0 | |
parent | fd384412e199b62c3ddaabd18dce86d0e164c5b9 (diff) |
udp-tunnel: Add a few more UDP tunnel APIs
Added a few more UDP tunnel APIs that can be shared by UDP based
tunnel protocol implementation. The main ones are highlighted below.
setup_udp_tunnel_sock() configures UDP listener socket for
receiving UDP encapsulated packets.
udp_tunnel_xmit_skb() and upd_tunnel6_xmit_skb() transmit skb
using UDP encapsulation.
udp_tunnel_sock_release() closes the UDP tunnel listener socket.
Signed-off-by: Andy Zhou <azhou@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/udp_tunnel.h | 57 | ||||
-rw-r--r-- | net/ipv4/udp_tunnel.c | 53 | ||||
-rw-r--r-- | net/ipv6/ip6_udp_tunnel.c | 42 |
3 files changed, 151 insertions, 1 deletions
diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index 0b9e017c9038..a47790bcaa38 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h | |||
@@ -1,6 +1,14 @@ | |||
1 | #ifndef __NET_UDP_TUNNEL_H | 1 | #ifndef __NET_UDP_TUNNEL_H |
2 | #define __NET_UDP_TUNNEL_H | 2 | #define __NET_UDP_TUNNEL_H |
3 | 3 | ||
4 | #include <net/ip_tunnels.h> | ||
5 | #include <net/udp.h> | ||
6 | |||
7 | #if IS_ENABLED(CONFIG_IPV6) | ||
8 | #include <net/ipv6.h> | ||
9 | #include <net/addrconf.h> | ||
10 | #endif | ||
11 | |||
4 | struct udp_port_cfg { | 12 | struct udp_port_cfg { |
5 | u8 family; | 13 | u8 family; |
6 | 14 | ||
@@ -53,4 +61,53 @@ static inline int udp_sock_create(struct net *net, | |||
53 | return -EPFNOSUPPORT; | 61 | return -EPFNOSUPPORT; |
54 | } | 62 | } |
55 | 63 | ||
64 | typedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb); | ||
65 | typedef void (*udp_tunnel_encap_destroy_t)(struct sock *sk); | ||
66 | |||
67 | struct udp_tunnel_sock_cfg { | ||
68 | void *sk_user_data; /* user data used by encap_rcv call back */ | ||
69 | /* Used for setting up udp_sock fields, see udp.h for details */ | ||
70 | __u8 encap_type; | ||
71 | udp_tunnel_encap_rcv_t encap_rcv; | ||
72 | udp_tunnel_encap_destroy_t encap_destroy; | ||
73 | }; | ||
74 | |||
75 | /* Setup the given (UDP) sock to receive UDP encapsulated packets */ | ||
76 | void setup_udp_tunnel_sock(struct net *net, struct socket *sock, | ||
77 | struct udp_tunnel_sock_cfg *sock_cfg); | ||
78 | |||
79 | /* Transmit the skb using UDP encapsulation. */ | ||
80 | int udp_tunnel_xmit_skb(struct socket *sock, struct rtable *rt, | ||
81 | struct sk_buff *skb, __be32 src, __be32 dst, | ||
82 | __u8 tos, __u8 ttl, __be16 df, __be16 src_port, | ||
83 | __be16 dst_port, bool xnet); | ||
84 | |||
85 | #if IS_ENABLED(CONFIG_IPV6) | ||
86 | int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst, | ||
87 | struct sk_buff *skb, struct net_device *dev, | ||
88 | struct in6_addr *saddr, struct in6_addr *daddr, | ||
89 | __u8 prio, __u8 ttl, __be16 src_port, | ||
90 | __be16 dst_port); | ||
91 | #endif | ||
92 | |||
93 | void udp_tunnel_sock_release(struct socket *sock); | ||
94 | |||
95 | static inline struct sk_buff *udp_tunnel_handle_offloads(struct sk_buff *skb, | ||
96 | bool udp_csum) | ||
97 | { | ||
98 | int type = udp_csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | ||
99 | |||
100 | return iptunnel_handle_offloads(skb, udp_csum, type); | ||
101 | } | ||
102 | |||
103 | static inline void udp_tunnel_encap_enable(struct socket *sock) | ||
104 | { | ||
105 | #if IS_ENABLED(CONFIG_IPV6) | ||
106 | if (sock->sk->sk_family == PF_INET6) | ||
107 | ipv6_stub->udpv6_encap_enable(); | ||
108 | else | ||
109 | #endif | ||
110 | udp_encap_enable(); | ||
111 | } | ||
112 | |||
56 | #endif | 113 | #endif |
diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c index 7fccf6c3417a..1671263e5fa0 100644 --- a/net/ipv4/udp_tunnel.c +++ b/net/ipv4/udp_tunnel.c | |||
@@ -11,7 +11,7 @@ | |||
11 | int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, | 11 | int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, |
12 | struct socket **sockp) | 12 | struct socket **sockp) |
13 | { | 13 | { |
14 | int err = -EINVAL; | 14 | int err; |
15 | struct socket *sock = NULL; | 15 | struct socket *sock = NULL; |
16 | struct sockaddr_in udp_addr; | 16 | struct sockaddr_in udp_addr; |
17 | 17 | ||
@@ -54,4 +54,55 @@ error: | |||
54 | } | 54 | } |
55 | EXPORT_SYMBOL(udp_sock_create4); | 55 | EXPORT_SYMBOL(udp_sock_create4); |
56 | 56 | ||
57 | void setup_udp_tunnel_sock(struct net *net, struct socket *sock, | ||
58 | struct udp_tunnel_sock_cfg *cfg) | ||
59 | { | ||
60 | struct sock *sk = sock->sk; | ||
61 | |||
62 | /* Disable multicast loopback */ | ||
63 | inet_sk(sk)->mc_loop = 0; | ||
64 | |||
65 | /* Enable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */ | ||
66 | udp_set_convert_csum(sk, true); | ||
67 | |||
68 | rcu_assign_sk_user_data(sk, cfg->sk_user_data); | ||
69 | |||
70 | udp_sk(sk)->encap_type = cfg->encap_type; | ||
71 | udp_sk(sk)->encap_rcv = cfg->encap_rcv; | ||
72 | udp_sk(sk)->encap_destroy = cfg->encap_destroy; | ||
73 | |||
74 | udp_tunnel_encap_enable(sock); | ||
75 | } | ||
76 | EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); | ||
77 | |||
78 | int udp_tunnel_xmit_skb(struct socket *sock, struct rtable *rt, | ||
79 | struct sk_buff *skb, __be32 src, __be32 dst, | ||
80 | __u8 tos, __u8 ttl, __be16 df, __be16 src_port, | ||
81 | __be16 dst_port, bool xnet) | ||
82 | { | ||
83 | struct udphdr *uh; | ||
84 | |||
85 | __skb_push(skb, sizeof(*uh)); | ||
86 | skb_reset_transport_header(skb); | ||
87 | uh = udp_hdr(skb); | ||
88 | |||
89 | uh->dest = dst_port; | ||
90 | uh->source = src_port; | ||
91 | uh->len = htons(skb->len); | ||
92 | |||
93 | udp_set_csum(sock->sk->sk_no_check_tx, skb, src, dst, skb->len); | ||
94 | |||
95 | return iptunnel_xmit(sock->sk, rt, skb, src, dst, IPPROTO_UDP, | ||
96 | tos, ttl, df, xnet); | ||
97 | } | ||
98 | EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb); | ||
99 | |||
100 | void udp_tunnel_sock_release(struct socket *sock) | ||
101 | { | ||
102 | rcu_assign_sk_user_data(sock->sk, NULL); | ||
103 | kernel_sock_shutdown(sock, SHUT_RDWR); | ||
104 | sk_release_kernel(sock->sk); | ||
105 | } | ||
106 | EXPORT_SYMBOL_GPL(udp_tunnel_sock_release); | ||
107 | |||
57 | MODULE_LICENSE("GPL"); | 108 | MODULE_LICENSE("GPL"); |
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index bcfbb4b496fc..cbc990712cc1 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c | |||
@@ -61,3 +61,45 @@ error: | |||
61 | return err; | 61 | return err; |
62 | } | 62 | } |
63 | EXPORT_SYMBOL_GPL(udp_sock_create6); | 63 | EXPORT_SYMBOL_GPL(udp_sock_create6); |
64 | |||
65 | int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst, | ||
66 | struct sk_buff *skb, struct net_device *dev, | ||
67 | struct in6_addr *saddr, struct in6_addr *daddr, | ||
68 | __u8 prio, __u8 ttl, __be16 src_port, __be16 dst_port) | ||
69 | { | ||
70 | struct udphdr *uh; | ||
71 | struct ipv6hdr *ip6h; | ||
72 | struct sock *sk = sock->sk; | ||
73 | |||
74 | __skb_push(skb, sizeof(*uh)); | ||
75 | skb_reset_transport_header(skb); | ||
76 | uh = udp_hdr(skb); | ||
77 | |||
78 | uh->dest = dst_port; | ||
79 | uh->source = src_port; | ||
80 | |||
81 | uh->len = htons(skb->len); | ||
82 | uh->check = 0; | ||
83 | |||
84 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | ||
85 | IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | ||
86 | | IPSKB_REROUTED); | ||
87 | skb_dst_set(skb, dst); | ||
88 | |||
89 | udp6_set_csum(udp_get_no_check6_tx(sk), skb, &inet6_sk(sk)->saddr, | ||
90 | &sk->sk_v6_daddr, skb->len); | ||
91 | |||
92 | __skb_push(skb, sizeof(*ip6h)); | ||
93 | skb_reset_network_header(skb); | ||
94 | ip6h = ipv6_hdr(skb); | ||
95 | ip6_flow_hdr(ip6h, prio, htonl(0)); | ||
96 | ip6h->payload_len = htons(skb->len); | ||
97 | ip6h->nexthdr = IPPROTO_UDP; | ||
98 | ip6h->hop_limit = ttl; | ||
99 | ip6h->daddr = *daddr; | ||
100 | ip6h->saddr = *saddr; | ||
101 | |||
102 | ip6tunnel_xmit(skb, dev); | ||
103 | return 0; | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); | ||