| // SPDX-License-Identifier: GPL-2.0-only | 
 | /* Unstable Fou Helpers for TC-BPF hook | 
 |  * | 
 |  * These are called from SCHED_CLS BPF programs. Note that it is | 
 |  * allowed to break compatibility for these functions since the interface they | 
 |  * are exposed through to BPF programs is explicitly unstable. | 
 |  */ | 
 |  | 
 | #include <linux/bpf.h> | 
 | #include <linux/btf_ids.h> | 
 |  | 
 | #include <net/dst_metadata.h> | 
 | #include <net/fou.h> | 
 |  | 
 | struct bpf_fou_encap { | 
 | 	__be16 sport; | 
 | 	__be16 dport; | 
 | }; | 
 |  | 
 | enum bpf_fou_encap_type { | 
 | 	FOU_BPF_ENCAP_FOU, | 
 | 	FOU_BPF_ENCAP_GUE, | 
 | }; | 
 |  | 
 | __bpf_kfunc_start_defs(); | 
 |  | 
 | /* bpf_skb_set_fou_encap - Set FOU encap parameters | 
 |  * | 
 |  * This function allows for using GUE or FOU encapsulation together with an | 
 |  * ipip device in collect-metadata mode. | 
 |  * | 
 |  * It is meant to be used in BPF tc-hooks and after a call to the | 
 |  * bpf_skb_set_tunnel_key helper, responsible for setting IP addresses. | 
 |  * | 
 |  * Parameters: | 
 |  * @skb_ctx	Pointer to ctx (__sk_buff) in TC program. Cannot be NULL | 
 |  * @encap	Pointer to a `struct bpf_fou_encap` storing UDP src and | 
 |  * 		dst ports. If sport is set to 0 the kernel will auto-assign a | 
 |  * 		port. This is similar to using `encap-sport auto`. | 
 |  * 		Cannot be NULL | 
 |  * @type	Encapsulation type for the packet. Their definitions are | 
 |  * 		specified in `enum bpf_fou_encap_type` | 
 |  */ | 
 | __bpf_kfunc int bpf_skb_set_fou_encap(struct __sk_buff *skb_ctx, | 
 | 				      struct bpf_fou_encap *encap, int type) | 
 | { | 
 | 	struct sk_buff *skb = (struct sk_buff *)skb_ctx; | 
 | 	struct ip_tunnel_info *info = skb_tunnel_info(skb); | 
 |  | 
 | 	if (unlikely(!encap)) | 
 | 		return -EINVAL; | 
 |  | 
 | 	if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) | 
 | 		return -EINVAL; | 
 |  | 
 | 	switch (type) { | 
 | 	case FOU_BPF_ENCAP_FOU: | 
 | 		info->encap.type = TUNNEL_ENCAP_FOU; | 
 | 		break; | 
 | 	case FOU_BPF_ENCAP_GUE: | 
 | 		info->encap.type = TUNNEL_ENCAP_GUE; | 
 | 		break; | 
 | 	default: | 
 | 		info->encap.type = TUNNEL_ENCAP_NONE; | 
 | 	} | 
 |  | 
 | 	if (info->key.tun_flags & TUNNEL_CSUM) | 
 | 		info->encap.flags |= TUNNEL_ENCAP_FLAG_CSUM; | 
 |  | 
 | 	info->encap.sport = encap->sport; | 
 | 	info->encap.dport = encap->dport; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* bpf_skb_get_fou_encap - Get FOU encap parameters | 
 |  * | 
 |  * This function allows for reading encap metadata from a packet received | 
 |  * on an ipip device in collect-metadata mode. | 
 |  * | 
 |  * Parameters: | 
 |  * @skb_ctx	Pointer to ctx (__sk_buff) in TC program. Cannot be NULL | 
 |  * @encap	Pointer to a struct bpf_fou_encap storing UDP source and | 
 |  * 		destination port. Cannot be NULL | 
 |  */ | 
 | __bpf_kfunc int bpf_skb_get_fou_encap(struct __sk_buff *skb_ctx, | 
 | 				      struct bpf_fou_encap *encap) | 
 | { | 
 | 	struct sk_buff *skb = (struct sk_buff *)skb_ctx; | 
 | 	struct ip_tunnel_info *info = skb_tunnel_info(skb); | 
 |  | 
 | 	if (unlikely(!info)) | 
 | 		return -EINVAL; | 
 |  | 
 | 	encap->sport = info->encap.sport; | 
 | 	encap->dport = info->encap.dport; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | __bpf_kfunc_end_defs(); | 
 |  | 
 | BTF_SET8_START(fou_kfunc_set) | 
 | BTF_ID_FLAGS(func, bpf_skb_set_fou_encap) | 
 | BTF_ID_FLAGS(func, bpf_skb_get_fou_encap) | 
 | BTF_SET8_END(fou_kfunc_set) | 
 |  | 
 | static const struct btf_kfunc_id_set fou_bpf_kfunc_set = { | 
 | 	.owner = THIS_MODULE, | 
 | 	.set   = &fou_kfunc_set, | 
 | }; | 
 |  | 
 | int register_fou_bpf(void) | 
 | { | 
 | 	return register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, | 
 | 					 &fou_bpf_kfunc_set); | 
 | } |