Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf,fou: Add bpf_skb_{set,get}_fou_encap kfuncs

Add two new kfuncs that allow a BPF tc-hook, installed on an ipip
device in collect-metadata mode, to control FOU encap parameters on a
per-packet level. The set of kfuncs is registered with the fou module.

The bpf_skb_set_fou_encap kfunc is supposed to be used in tandem and after
a successful call to the bpf_skb_set_tunnel_key bpf-helper. UDP source and
destination ports can be controlled by passing a struct bpf_fou_encap. A
source port of zero will auto-assign a source port. enum bpf_fou_encap_type
is used to specify if the egress path should FOU or GUE encap the packet.

On the ingress path bpf_skb_get_fou_encap can be used to read UDP source
and destination ports from the receiver's point of view and allows for
packet multiplexing across different destination ports within a single
BPF program and ipip device.

Signed-off-by: Christian Ehrig <cehrig@cloudflare.com>
Link: https://lore.kernel.org/r/e17c94a646b63e78ce0dbf3f04b2c33dc948a32d.1680874078.git.cehrig@cloudflare.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Christian Ehrig and committed by
Alexei Starovoitov
c50e9609 ac931d4c

+127 -1
+2
include/net/fou.h
··· 17 17 int __gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, 18 18 u8 *protocol, __be16 *sport, int type); 19 19 20 + int register_fou_bpf(void); 21 + 20 22 #endif
+1 -1
net/ipv4/Makefile
··· 26 26 obj-$(CONFIG_IP_MROUTE_COMMON) += ipmr_base.o 27 27 obj-$(CONFIG_NET_IPIP) += ipip.o 28 28 gre-y := gre_demux.o 29 - fou-y := fou_core.o fou_nl.o 29 + fou-y := fou_core.o fou_nl.o fou_bpf.o 30 30 obj-$(CONFIG_NET_FOU) += fou.o 31 31 obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 32 32 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
+119
net/ipv4/fou_bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Unstable Fou Helpers for TC-BPF hook 3 + * 4 + * These are called from SCHED_CLS BPF programs. Note that it is 5 + * allowed to break compatibility for these functions since the interface they 6 + * are exposed through to BPF programs is explicitly unstable. 7 + */ 8 + 9 + #include <linux/bpf.h> 10 + #include <linux/btf_ids.h> 11 + 12 + #include <net/dst_metadata.h> 13 + #include <net/fou.h> 14 + 15 + struct bpf_fou_encap { 16 + __be16 sport; 17 + __be16 dport; 18 + }; 19 + 20 + enum bpf_fou_encap_type { 21 + FOU_BPF_ENCAP_FOU, 22 + FOU_BPF_ENCAP_GUE, 23 + }; 24 + 25 + __diag_push(); 26 + __diag_ignore_all("-Wmissing-prototypes", 27 + "Global functions as their definitions will be in BTF"); 28 + 29 + /* bpf_skb_set_fou_encap - Set FOU encap parameters 30 + * 31 + * This function allows for using GUE or FOU encapsulation together with an 32 + * ipip device in collect-metadata mode. 33 + * 34 + * It is meant to be used in BPF tc-hooks and after a call to the 35 + * bpf_skb_set_tunnel_key helper, responsible for setting IP addresses. 36 + * 37 + * Parameters: 38 + * @skb_ctx Pointer to ctx (__sk_buff) in TC program. Cannot be NULL 39 + * @encap Pointer to a `struct bpf_fou_encap` storing UDP src and 40 + * dst ports. If sport is set to 0 the kernel will auto-assign a 41 + * port. This is similar to using `encap-sport auto`. 42 + * Cannot be NULL 43 + * @type Encapsulation type for the packet. Their definitions are 44 + * specified in `enum bpf_fou_encap_type` 45 + */ 46 + __bpf_kfunc int bpf_skb_set_fou_encap(struct __sk_buff *skb_ctx, 47 + struct bpf_fou_encap *encap, int type) 48 + { 49 + struct sk_buff *skb = (struct sk_buff *)skb_ctx; 50 + struct ip_tunnel_info *info = skb_tunnel_info(skb); 51 + 52 + if (unlikely(!encap)) 53 + return -EINVAL; 54 + 55 + if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) 56 + return -EINVAL; 57 + 58 + switch (type) { 59 + case FOU_BPF_ENCAP_FOU: 60 + info->encap.type = TUNNEL_ENCAP_FOU; 61 + break; 62 + case FOU_BPF_ENCAP_GUE: 63 + info->encap.type = TUNNEL_ENCAP_GUE; 64 + break; 65 + default: 66 + info->encap.type = TUNNEL_ENCAP_NONE; 67 + } 68 + 69 + if (info->key.tun_flags & TUNNEL_CSUM) 70 + info->encap.flags |= TUNNEL_ENCAP_FLAG_CSUM; 71 + 72 + info->encap.sport = encap->sport; 73 + info->encap.dport = encap->dport; 74 + 75 + return 0; 76 + } 77 + 78 + /* bpf_skb_get_fou_encap - Get FOU encap parameters 79 + * 80 + * This function allows for reading encap metadata from a packet received 81 + * on an ipip device in collect-metadata mode. 82 + * 83 + * Parameters: 84 + * @skb_ctx Pointer to ctx (__sk_buff) in TC program. Cannot be NULL 85 + * @encap Pointer to a struct bpf_fou_encap storing UDP source and 86 + * destination port. Cannot be NULL 87 + */ 88 + __bpf_kfunc int bpf_skb_get_fou_encap(struct __sk_buff *skb_ctx, 89 + struct bpf_fou_encap *encap) 90 + { 91 + struct sk_buff *skb = (struct sk_buff *)skb_ctx; 92 + struct ip_tunnel_info *info = skb_tunnel_info(skb); 93 + 94 + if (unlikely(!info)) 95 + return -EINVAL; 96 + 97 + encap->sport = info->encap.sport; 98 + encap->dport = info->encap.dport; 99 + 100 + return 0; 101 + } 102 + 103 + __diag_pop() 104 + 105 + BTF_SET8_START(fou_kfunc_set) 106 + BTF_ID_FLAGS(func, bpf_skb_set_fou_encap) 107 + BTF_ID_FLAGS(func, bpf_skb_get_fou_encap) 108 + BTF_SET8_END(fou_kfunc_set) 109 + 110 + static const struct btf_kfunc_id_set fou_bpf_kfunc_set = { 111 + .owner = THIS_MODULE, 112 + .set = &fou_kfunc_set, 113 + }; 114 + 115 + int register_fou_bpf(void) 116 + { 117 + return register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, 118 + &fou_bpf_kfunc_set); 119 + }
+5
net/ipv4/fou_core.c
··· 1236 1236 if (ret < 0) 1237 1237 goto unregister; 1238 1238 1239 + ret = register_fou_bpf(); 1240 + if (ret < 0) 1241 + goto kfunc_failed; 1242 + 1239 1243 ret = ip_tunnel_encap_add_fou_ops(); 1240 1244 if (ret == 0) 1241 1245 return 0; 1242 1246 1247 + kfunc_failed: 1243 1248 genl_unregister_family(&fou_nl_family); 1244 1249 unregister: 1245 1250 unregister_pernet_device(&fou_net_ops);