udp_tunnel_core.c (5123B)
1// SPDX-License-Identifier: GPL-2.0-only 2#include <linux/module.h> 3#include <linux/errno.h> 4#include <linux/socket.h> 5#include <linux/kernel.h> 6#include <net/dst_metadata.h> 7#include <net/udp.h> 8#include <net/udp_tunnel.h> 9 10int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, 11 struct socket **sockp) 12{ 13 int err; 14 struct socket *sock = NULL; 15 struct sockaddr_in udp_addr; 16 17 err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock); 18 if (err < 0) 19 goto error; 20 21 if (cfg->bind_ifindex) { 22 err = sock_bindtoindex(sock->sk, cfg->bind_ifindex, true); 23 if (err < 0) 24 goto error; 25 } 26 27 udp_addr.sin_family = AF_INET; 28 udp_addr.sin_addr = cfg->local_ip; 29 udp_addr.sin_port = cfg->local_udp_port; 30 err = kernel_bind(sock, (struct sockaddr *)&udp_addr, 31 sizeof(udp_addr)); 32 if (err < 0) 33 goto error; 34 35 if (cfg->peer_udp_port) { 36 udp_addr.sin_family = AF_INET; 37 udp_addr.sin_addr = cfg->peer_ip; 38 udp_addr.sin_port = cfg->peer_udp_port; 39 err = kernel_connect(sock, (struct sockaddr *)&udp_addr, 40 sizeof(udp_addr), 0); 41 if (err < 0) 42 goto error; 43 } 44 45 sock->sk->sk_no_check_tx = !cfg->use_udp_checksums; 46 47 *sockp = sock; 48 return 0; 49 50error: 51 if (sock) { 52 kernel_sock_shutdown(sock, SHUT_RDWR); 53 sock_release(sock); 54 } 55 *sockp = NULL; 56 return err; 57} 58EXPORT_SYMBOL(udp_sock_create4); 59 60void setup_udp_tunnel_sock(struct net *net, struct socket *sock, 61 struct udp_tunnel_sock_cfg *cfg) 62{ 63 struct sock *sk = sock->sk; 64 65 /* Disable multicast loopback */ 66 inet_sk(sk)->mc_loop = 0; 67 68 /* Enable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */ 69 inet_inc_convert_csum(sk); 70 71 rcu_assign_sk_user_data(sk, cfg->sk_user_data); 72 73 udp_sk(sk)->encap_type = cfg->encap_type; 74 udp_sk(sk)->encap_rcv = cfg->encap_rcv; 75 udp_sk(sk)->encap_err_lookup = cfg->encap_err_lookup; 76 udp_sk(sk)->encap_destroy = cfg->encap_destroy; 77 udp_sk(sk)->gro_receive = cfg->gro_receive; 78 udp_sk(sk)->gro_complete = cfg->gro_complete; 79 80 udp_tunnel_encap_enable(sock); 81} 82EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); 83 84void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock, 85 unsigned short type) 86{ 87 struct sock *sk = sock->sk; 88 struct udp_tunnel_info ti; 89 90 ti.type = type; 91 ti.sa_family = sk->sk_family; 92 ti.port = inet_sk(sk)->inet_sport; 93 94 udp_tunnel_nic_add_port(dev, &ti); 95} 96EXPORT_SYMBOL_GPL(udp_tunnel_push_rx_port); 97 98void udp_tunnel_drop_rx_port(struct net_device *dev, struct socket *sock, 99 unsigned short type) 100{ 101 struct sock *sk = sock->sk; 102 struct udp_tunnel_info ti; 103 104 ti.type = type; 105 ti.sa_family = sk->sk_family; 106 ti.port = inet_sk(sk)->inet_sport; 107 108 udp_tunnel_nic_del_port(dev, &ti); 109} 110EXPORT_SYMBOL_GPL(udp_tunnel_drop_rx_port); 111 112/* Notify netdevs that UDP port started listening */ 113void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type) 114{ 115 struct sock *sk = sock->sk; 116 struct net *net = sock_net(sk); 117 struct udp_tunnel_info ti; 118 struct net_device *dev; 119 120 ti.type = type; 121 ti.sa_family = sk->sk_family; 122 ti.port = inet_sk(sk)->inet_sport; 123 124 rcu_read_lock(); 125 for_each_netdev_rcu(net, dev) { 126 udp_tunnel_nic_add_port(dev, &ti); 127 } 128 rcu_read_unlock(); 129} 130EXPORT_SYMBOL_GPL(udp_tunnel_notify_add_rx_port); 131 132/* Notify netdevs that UDP port is no more listening */ 133void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type) 134{ 135 struct sock *sk = sock->sk; 136 struct net *net = sock_net(sk); 137 struct udp_tunnel_info ti; 138 struct net_device *dev; 139 140 ti.type = type; 141 ti.sa_family = sk->sk_family; 142 ti.port = inet_sk(sk)->inet_sport; 143 144 rcu_read_lock(); 145 for_each_netdev_rcu(net, dev) { 146 udp_tunnel_nic_del_port(dev, &ti); 147 } 148 rcu_read_unlock(); 149} 150EXPORT_SYMBOL_GPL(udp_tunnel_notify_del_rx_port); 151 152void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, 153 __be32 src, __be32 dst, __u8 tos, __u8 ttl, 154 __be16 df, __be16 src_port, __be16 dst_port, 155 bool xnet, bool nocheck) 156{ 157 struct udphdr *uh; 158 159 __skb_push(skb, sizeof(*uh)); 160 skb_reset_transport_header(skb); 161 uh = udp_hdr(skb); 162 163 uh->dest = dst_port; 164 uh->source = src_port; 165 uh->len = htons(skb->len); 166 167 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 168 169 udp_set_csum(nocheck, skb, src, dst, skb->len); 170 171 iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet); 172} 173EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb); 174 175void udp_tunnel_sock_release(struct socket *sock) 176{ 177 rcu_assign_sk_user_data(sock->sk, NULL); 178 kernel_sock_shutdown(sock, SHUT_RDWR); 179 sock_release(sock); 180} 181EXPORT_SYMBOL_GPL(udp_tunnel_sock_release); 182 183struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, 184 __be16 flags, __be64 tunnel_id, int md_size) 185{ 186 struct metadata_dst *tun_dst; 187 struct ip_tunnel_info *info; 188 189 if (family == AF_INET) 190 tun_dst = ip_tun_rx_dst(skb, flags, tunnel_id, md_size); 191 else 192 tun_dst = ipv6_tun_rx_dst(skb, flags, tunnel_id, md_size); 193 if (!tun_dst) 194 return NULL; 195 196 info = &tun_dst->u.tun_info; 197 info->key.tp_src = udp_hdr(skb)->source; 198 info->key.tp_dst = udp_hdr(skb)->dest; 199 if (udp_hdr(skb)->check) 200 info->key.tun_flags |= TUNNEL_CSUM; 201 return tun_dst; 202} 203EXPORT_SYMBOL_GPL(udp_tun_rx_dst); 204 205MODULE_LICENSE("GPL");