123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <linux/module.h> 223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <linux/errno.h> 323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <linux/socket.h> 423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <linux/skbuff.h> 523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <linux/ip.h> 623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <linux/udp.h> 723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <linux/types.h> 823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <linux/kernel.h> 923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <net/genetlink.h> 1037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert#include <net/gue.h> 1123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <net/ip.h> 12afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert#include <net/protocol.h> 1323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <net/udp.h> 1423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <net/udp_tunnel.h> 1523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <net/xfrm.h> 1623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <uapi/linux/fou.h> 1723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert#include <uapi/linux/genetlink.h> 1823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 1923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic DEFINE_SPINLOCK(fou_lock); 2023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic LIST_HEAD(fou_list); 2123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 2223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstruct fou { 2323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct socket *sock; 2423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert u8 protocol; 2523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert u16 port; 26afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert struct udp_offload udp_offloads; 2723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct list_head list; 2823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert}; 2923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 3023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstruct fou_cfg { 3137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert u16 type; 3223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert u8 protocol; 3323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct udp_port_cfg udp_config; 3423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert}; 3523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 3623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic inline struct fou *fou_from_sock(struct sock *sk) 3723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 3823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return sk->sk_user_data; 3923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 4023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 4123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int fou_udp_encap_recv_deliver(struct sk_buff *skb, 4223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert u8 protocol, size_t len) 4323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 4423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct iphdr *iph = ip_hdr(skb); 4523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 4623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert /* Remove 'len' bytes from the packet (UDP header and 4723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert * FOU header if present), modify the protocol to the one 4823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert * we found, and then call rcv_encap. 4923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert */ 5023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert iph->tot_len = htons(ntohs(iph->tot_len) - len); 5123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert __skb_pull(skb, len); 5223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert skb_postpull_rcsum(skb, udp_hdr(skb), len); 5323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert skb_reset_transport_header(skb); 5423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 5523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return -protocol; 5623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 5723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 5823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int fou_udp_recv(struct sock *sk, struct sk_buff *skb) 5923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 6023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct fou *fou = fou_from_sock(sk); 6123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 6223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (!fou) 6323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return 1; 6423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 6523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return fou_udp_encap_recv_deliver(skb, fou->protocol, 6623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert sizeof(struct udphdr)); 6723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 6823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 6937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertstatic int gue_udp_recv(struct sock *sk, struct sk_buff *skb) 7037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert{ 7137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert struct fou *fou = fou_from_sock(sk); 7237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert size_t len; 7337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert struct guehdr *guehdr; 7437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert struct udphdr *uh; 7537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 7637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (!fou) 7737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert return 1; 7837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 7937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert len = sizeof(struct udphdr) + sizeof(struct guehdr); 8037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (!pskb_may_pull(skb, len)) 8137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto drop; 8237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 8337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert uh = udp_hdr(skb); 8437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert guehdr = (struct guehdr *)&uh[1]; 8537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 8637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert len += guehdr->hlen << 2; 8737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (!pskb_may_pull(skb, len)) 8837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto drop; 8937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 90d8f00d27105a1553a13d4a96c3eb4544f70ca908Li RongQing uh = udp_hdr(skb); 91d8f00d27105a1553a13d4a96c3eb4544f70ca908Li RongQing guehdr = (struct guehdr *)&uh[1]; 92d8f00d27105a1553a13d4a96c3eb4544f70ca908Li RongQing 9337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (guehdr->version != 0) 9437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto drop; 9537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 9637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (guehdr->flags) { 9737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert /* No support yet */ 9837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto drop; 9937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert } 10037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 10137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert return fou_udp_encap_recv_deliver(skb, guehdr->next_hdr, len); 10237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertdrop: 10337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert kfree_skb(skb); 10437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert return 0; 10537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert} 10637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 107afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbertstatic struct sk_buff **fou_gro_receive(struct sk_buff **head, 108efc98d08e1ec4fd131f794370b274dceaf32c958Tom Herbert struct sk_buff *skb) 109afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert{ 110afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert const struct net_offload *ops; 111afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert struct sk_buff **pp = NULL; 112afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert u8 proto = NAPI_GRO_CB(skb)->proto; 113efc98d08e1ec4fd131f794370b274dceaf32c958Tom Herbert const struct net_offload **offloads; 114afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 115afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert rcu_read_lock(); 116efc98d08e1ec4fd131f794370b274dceaf32c958Tom Herbert offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; 117afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert ops = rcu_dereference(offloads[proto]); 118afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert if (!ops || !ops->callbacks.gro_receive) 119afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert goto out_unlock; 120afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 121afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert pp = ops->callbacks.gro_receive(head, skb); 122afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 123afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbertout_unlock: 124afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert rcu_read_unlock(); 125afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 126afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert return pp; 127afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert} 128afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 129efc98d08e1ec4fd131f794370b274dceaf32c958Tom Herbertstatic int fou_gro_complete(struct sk_buff *skb, int nhoff) 130afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert{ 131afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert const struct net_offload *ops; 132afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert u8 proto = NAPI_GRO_CB(skb)->proto; 133afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert int err = -ENOSYS; 134efc98d08e1ec4fd131f794370b274dceaf32c958Tom Herbert const struct net_offload **offloads; 135afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 136cfdf1e1ba5bf55e095cf4bcaa9585c4759f239e8Jesse Gross udp_tunnel_gro_complete(skb, nhoff); 137cfdf1e1ba5bf55e095cf4bcaa9585c4759f239e8Jesse Gross 138afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert rcu_read_lock(); 139efc98d08e1ec4fd131f794370b274dceaf32c958Tom Herbert offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; 140afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert ops = rcu_dereference(offloads[proto]); 141afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert if (WARN_ON(!ops || !ops->callbacks.gro_complete)) 142afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert goto out_unlock; 143afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 144afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert err = ops->callbacks.gro_complete(skb, nhoff); 145afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 146afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbertout_unlock: 147afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert rcu_read_unlock(); 148afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 149afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert return err; 150afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert} 151afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 15237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertstatic struct sk_buff **gue_gro_receive(struct sk_buff **head, 15337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert struct sk_buff *skb) 15437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert{ 15537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert const struct net_offload **offloads; 15637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert const struct net_offload *ops; 15737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert struct sk_buff **pp = NULL; 15837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert struct sk_buff *p; 15937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert u8 proto; 16037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert struct guehdr *guehdr; 16137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert unsigned int hlen, guehlen; 16237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert unsigned int off; 16337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert int flush = 1; 16437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 16537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert off = skb_gro_offset(skb); 16637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert hlen = off + sizeof(*guehdr); 16737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert guehdr = skb_gro_header_fast(skb, off); 16837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (skb_gro_header_hard(skb, hlen)) { 16937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert guehdr = skb_gro_header_slow(skb, hlen, off); 17037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (unlikely(!guehdr)) 17137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto out; 17237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert } 17337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 17437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert proto = guehdr->next_hdr; 17537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 17637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert rcu_read_lock(); 17737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; 17837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert ops = rcu_dereference(offloads[proto]); 17937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (WARN_ON(!ops || !ops->callbacks.gro_receive)) 18037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto out_unlock; 18137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 18237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert guehlen = sizeof(*guehdr) + (guehdr->hlen << 2); 18337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 18437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert hlen = off + guehlen; 18537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (skb_gro_header_hard(skb, hlen)) { 18637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert guehdr = skb_gro_header_slow(skb, hlen, off); 18737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (unlikely(!guehdr)) 18837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto out_unlock; 18937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert } 19037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 19137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert flush = 0; 19237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 19337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert for (p = *head; p; p = p->next) { 19437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert const struct guehdr *guehdr2; 19537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 19637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (!NAPI_GRO_CB(p)->same_flow) 19737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert continue; 19837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 19937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert guehdr2 = (struct guehdr *)(p->data + off); 20037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 20137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert /* Compare base GUE header to be equal (covers 20237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert * hlen, version, next_hdr, and flags. 20337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert */ 20437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (guehdr->word != guehdr2->word) { 20537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert NAPI_GRO_CB(p)->same_flow = 0; 20637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert continue; 20737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert } 20837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 20937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert /* Compare optional fields are the same. */ 21037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (guehdr->hlen && memcmp(&guehdr[1], &guehdr2[1], 21137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert guehdr->hlen << 2)) { 21237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert NAPI_GRO_CB(p)->same_flow = 0; 21337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert continue; 21437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert } 21537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert } 21637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 21737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert skb_gro_pull(skb, guehlen); 21837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 21937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/ 22037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert skb_gro_postpull_rcsum(skb, guehdr, guehlen); 22137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 22237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert pp = ops->callbacks.gro_receive(head, skb); 22337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 22437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertout_unlock: 22537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert rcu_read_unlock(); 22637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertout: 22737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert NAPI_GRO_CB(skb)->flush |= flush; 22837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 22937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert return pp; 23037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert} 23137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 23237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertstatic int gue_gro_complete(struct sk_buff *skb, int nhoff) 23337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert{ 23437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert const struct net_offload **offloads; 23537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert struct guehdr *guehdr = (struct guehdr *)(skb->data + nhoff); 23637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert const struct net_offload *ops; 23737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert unsigned int guehlen; 23837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert u8 proto; 23937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert int err = -ENOENT; 24037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 24137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert proto = guehdr->next_hdr; 24237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 24337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert guehlen = sizeof(*guehdr) + (guehdr->hlen << 2); 24437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 24537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert rcu_read_lock(); 24637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; 24737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert ops = rcu_dereference(offloads[proto]); 24837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (WARN_ON(!ops || !ops->callbacks.gro_complete)) 24937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto out_unlock; 25037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 25137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert err = ops->callbacks.gro_complete(skb, nhoff + guehlen); 25237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 25337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertout_unlock: 25437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert rcu_read_unlock(); 25537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert return err; 25637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert} 25737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 25823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int fou_add_to_port_list(struct fou *fou) 25923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 26023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct fou *fout; 26123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 26223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert spin_lock(&fou_lock); 26323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert list_for_each_entry(fout, &fou_list, list) { 26423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (fou->port == fout->port) { 26523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert spin_unlock(&fou_lock); 26623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return -EALREADY; 26723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert } 26823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert } 26923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 27023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert list_add(&fou->list, &fou_list); 27123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert spin_unlock(&fou_lock); 27223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 27323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return 0; 27423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 27523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 27623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic void fou_release(struct fou *fou) 27723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 27823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct socket *sock = fou->sock; 27923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct sock *sk = sock->sk; 28023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 28123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert udp_del_offload(&fou->udp_offloads); 28223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 28323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert list_del(&fou->list); 28423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 28523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert /* Remove hooks into tunnel socket */ 28623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert sk->sk_user_data = NULL; 28723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 28823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert sock_release(sock); 28923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 29023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert kfree(fou); 29123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 29223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 29337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertstatic int fou_encap_init(struct sock *sk, struct fou *fou, struct fou_cfg *cfg) 29437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert{ 29537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert udp_sk(sk)->encap_rcv = fou_udp_recv; 29637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->protocol = cfg->protocol; 29737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->udp_offloads.callbacks.gro_receive = fou_gro_receive; 29837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->udp_offloads.callbacks.gro_complete = fou_gro_complete; 29937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->udp_offloads.port = cfg->udp_config.local_udp_port; 30037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->udp_offloads.ipproto = cfg->protocol; 30137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 30237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert return 0; 30337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert} 30437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 30537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbertstatic int gue_encap_init(struct sock *sk, struct fou *fou, struct fou_cfg *cfg) 30637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert{ 30737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert udp_sk(sk)->encap_rcv = gue_udp_recv; 30837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->udp_offloads.callbacks.gro_receive = gue_gro_receive; 30937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->udp_offloads.callbacks.gro_complete = gue_gro_complete; 31037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->udp_offloads.port = cfg->udp_config.local_udp_port; 31137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 31237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert return 0; 31337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert} 31437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 31523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int fou_create(struct net *net, struct fou_cfg *cfg, 31623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct socket **sockp) 31723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 31823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct fou *fou = NULL; 31923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert int err; 32023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct socket *sock = NULL; 32123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct sock *sk; 32223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 32323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert /* Open UDP socket */ 32423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert err = udp_sock_create(net, &cfg->udp_config, &sock); 32523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (err < 0) 32623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert goto error; 32723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 32823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert /* Allocate FOU port structure */ 32923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert fou = kzalloc(sizeof(*fou), GFP_KERNEL); 33023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (!fou) { 33123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert err = -ENOMEM; 33223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert goto error; 33323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert } 33423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 33523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert sk = sock->sk; 33623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 33737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert fou->port = cfg->udp_config.local_udp_port; 33837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 33937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert /* Initial for fou type */ 34037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert switch (cfg->type) { 34137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert case FOU_ENCAP_DIRECT: 34237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert err = fou_encap_init(sk, fou, cfg); 34337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (err) 34437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto error; 34537dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert break; 34637dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert case FOU_ENCAP_GUE: 34737dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert err = gue_encap_init(sk, fou, cfg); 34837dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (err) 34937dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto error; 35037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert break; 35137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert default: 35237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert err = -EINVAL; 35337dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert goto error; 35437dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert } 35523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 35623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert udp_sk(sk)->encap_type = 1; 35723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert udp_encap_enable(); 35823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 35923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert sk->sk_user_data = fou; 36023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert fou->sock = sock; 36123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 36223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert udp_set_convert_csum(sk, true); 36323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 36423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert sk->sk_allocation = GFP_ATOMIC; 36523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 366afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert if (cfg->udp_config.family == AF_INET) { 367afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert err = udp_add_offload(&fou->udp_offloads); 368afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert if (err) 369afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert goto error; 370afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert } 371afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert 37223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert err = fou_add_to_port_list(fou); 37323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (err) 37423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert goto error; 37523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 37623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (sockp) 37723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert *sockp = sock; 37823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 37923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return 0; 38023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 38123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herberterror: 38223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert kfree(fou); 38323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (sock) 38423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert sock_release(sock); 38523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 38623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return err; 38723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 38823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 38923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int fou_destroy(struct net *net, struct fou_cfg *cfg) 39023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 39123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct fou *fou; 39223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert u16 port = cfg->udp_config.local_udp_port; 39323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert int err = -EINVAL; 39423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 39523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert spin_lock(&fou_lock); 39623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert list_for_each_entry(fou, &fou_list, list) { 39723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (fou->port == port) { 398afe93325bc02a5b2dea0cd7d78225de692265e6eTom Herbert udp_del_offload(&fou->udp_offloads); 39923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert fou_release(fou); 40023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert err = 0; 40123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert break; 40223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert } 40323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert } 40423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert spin_unlock(&fou_lock); 40523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 40623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return err; 40723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 40823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 40923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic struct genl_family fou_nl_family = { 41023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .id = GENL_ID_GENERATE, 41123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .hdrsize = 0, 41223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .name = FOU_GENL_NAME, 41323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .version = FOU_GENL_VERSION, 41423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .maxattr = FOU_ATTR_MAX, 41523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .netnsok = true, 41623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert}; 41723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 41823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic struct nla_policy fou_nl_policy[FOU_ATTR_MAX + 1] = { 41923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert [FOU_ATTR_PORT] = { .type = NLA_U16, }, 42023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert [FOU_ATTR_AF] = { .type = NLA_U8, }, 42123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert [FOU_ATTR_IPPROTO] = { .type = NLA_U8, }, 42237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert [FOU_ATTR_TYPE] = { .type = NLA_U8, }, 42323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert}; 42423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 42523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int parse_nl_config(struct genl_info *info, 42623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct fou_cfg *cfg) 42723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 42823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert memset(cfg, 0, sizeof(*cfg)); 42923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 43023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert cfg->udp_config.family = AF_INET; 43123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 43223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (info->attrs[FOU_ATTR_AF]) { 43323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert u8 family = nla_get_u8(info->attrs[FOU_ATTR_AF]); 43423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 43523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (family != AF_INET && family != AF_INET6) 43623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return -EINVAL; 43723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 43823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert cfg->udp_config.family = family; 43923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert } 44023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 44123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (info->attrs[FOU_ATTR_PORT]) { 44223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert u16 port = nla_get_u16(info->attrs[FOU_ATTR_PORT]); 44323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 44423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert cfg->udp_config.local_udp_port = port; 44523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert } 44623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 44723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (info->attrs[FOU_ATTR_IPPROTO]) 44823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert cfg->protocol = nla_get_u8(info->attrs[FOU_ATTR_IPPROTO]); 44923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 45037dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert if (info->attrs[FOU_ATTR_TYPE]) 45137dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert cfg->type = nla_get_u8(info->attrs[FOU_ATTR_TYPE]); 45237dd0247797b168ad1cc7f5dbec825a1ee66535bTom Herbert 45323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return 0; 45423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 45523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 45623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int fou_nl_cmd_add_port(struct sk_buff *skb, struct genl_info *info) 45723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 45823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct fou_cfg cfg; 45923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert int err; 46023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 46123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert err = parse_nl_config(info, &cfg); 46223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert if (err) 46323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return err; 46423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 46523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return fou_create(&init_net, &cfg, NULL); 46623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 46723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 46823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int fou_nl_cmd_rm_port(struct sk_buff *skb, struct genl_info *info) 46923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 47023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct fou_cfg cfg; 47123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 47223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert parse_nl_config(info, &cfg); 47323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 47423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return fou_destroy(&init_net, &cfg); 47523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 47623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 47723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic const struct genl_ops fou_nl_ops[] = { 47823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert { 47923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .cmd = FOU_CMD_ADD, 48023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .doit = fou_nl_cmd_add_port, 48123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .policy = fou_nl_policy, 48223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .flags = GENL_ADMIN_PERM, 48323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert }, 48423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert { 48523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .cmd = FOU_CMD_DEL, 48623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .doit = fou_nl_cmd_rm_port, 48723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .policy = fou_nl_policy, 48823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert .flags = GENL_ADMIN_PERM, 48923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert }, 49023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert}; 49123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 49223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic int __init fou_init(void) 49323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 49423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert int ret; 49523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 49623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert ret = genl_register_family_with_ops(&fou_nl_family, 49723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert fou_nl_ops); 49823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 49923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert return ret; 50023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 50123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 50223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertstatic void __exit fou_fini(void) 50323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert{ 50423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert struct fou *fou, *next; 50523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 50623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert genl_unregister_family(&fou_nl_family); 50723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 50823461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert /* Close all the FOU sockets */ 50923461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 51023461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert spin_lock(&fou_lock); 51123461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert list_for_each_entry_safe(fou, next, &fou_list, list) 51223461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert fou_release(fou); 51323461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert spin_unlock(&fou_lock); 51423461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert} 51523461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbert 51623461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertmodule_init(fou_init); 51723461551c00628c3f3fe9cf837bf53cf8f212b63Tom Herbertmodule_exit(fou_fini); 51823461551c00628c3f3fe9cf837bf53cf8f212b63Tom HerbertMODULE_AUTHOR("Tom Herbert <therbert@google.com>"); 51923461551c00628c3f3fe9cf837bf53cf8f212b63Tom HerbertMODULE_LICENSE("GPL"); 520