162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Unstable Fou Helpers for TC-BPF hook
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * These are called from SCHED_CLS BPF programs. Note that it is
562306a36Sopenharmony_ci * allowed to break compatibility for these functions since the interface they
662306a36Sopenharmony_ci * are exposed through to BPF programs is explicitly unstable.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bpf.h>
1062306a36Sopenharmony_ci#include <linux/btf_ids.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <net/dst_metadata.h>
1362306a36Sopenharmony_ci#include <net/fou.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct bpf_fou_encap {
1662306a36Sopenharmony_ci	__be16 sport;
1762306a36Sopenharmony_ci	__be16 dport;
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cienum bpf_fou_encap_type {
2162306a36Sopenharmony_ci	FOU_BPF_ENCAP_FOU,
2262306a36Sopenharmony_ci	FOU_BPF_ENCAP_GUE,
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci__diag_push();
2662306a36Sopenharmony_ci__diag_ignore_all("-Wmissing-prototypes",
2762306a36Sopenharmony_ci		  "Global functions as their definitions will be in BTF");
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* bpf_skb_set_fou_encap - Set FOU encap parameters
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * This function allows for using GUE or FOU encapsulation together with an
3262306a36Sopenharmony_ci * ipip device in collect-metadata mode.
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * It is meant to be used in BPF tc-hooks and after a call to the
3562306a36Sopenharmony_ci * bpf_skb_set_tunnel_key helper, responsible for setting IP addresses.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * Parameters:
3862306a36Sopenharmony_ci * @skb_ctx	Pointer to ctx (__sk_buff) in TC program. Cannot be NULL
3962306a36Sopenharmony_ci * @encap	Pointer to a `struct bpf_fou_encap` storing UDP src and
4062306a36Sopenharmony_ci * 		dst ports. If sport is set to 0 the kernel will auto-assign a
4162306a36Sopenharmony_ci * 		port. This is similar to using `encap-sport auto`.
4262306a36Sopenharmony_ci * 		Cannot be NULL
4362306a36Sopenharmony_ci * @type	Encapsulation type for the packet. Their definitions are
4462306a36Sopenharmony_ci * 		specified in `enum bpf_fou_encap_type`
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ci__bpf_kfunc int bpf_skb_set_fou_encap(struct __sk_buff *skb_ctx,
4762306a36Sopenharmony_ci				      struct bpf_fou_encap *encap, int type)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct sk_buff *skb = (struct sk_buff *)skb_ctx;
5062306a36Sopenharmony_ci	struct ip_tunnel_info *info = skb_tunnel_info(skb);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (unlikely(!encap))
5362306a36Sopenharmony_ci		return -EINVAL;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX)))
5662306a36Sopenharmony_ci		return -EINVAL;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	switch (type) {
5962306a36Sopenharmony_ci	case FOU_BPF_ENCAP_FOU:
6062306a36Sopenharmony_ci		info->encap.type = TUNNEL_ENCAP_FOU;
6162306a36Sopenharmony_ci		break;
6262306a36Sopenharmony_ci	case FOU_BPF_ENCAP_GUE:
6362306a36Sopenharmony_ci		info->encap.type = TUNNEL_ENCAP_GUE;
6462306a36Sopenharmony_ci		break;
6562306a36Sopenharmony_ci	default:
6662306a36Sopenharmony_ci		info->encap.type = TUNNEL_ENCAP_NONE;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (info->key.tun_flags & TUNNEL_CSUM)
7062306a36Sopenharmony_ci		info->encap.flags |= TUNNEL_ENCAP_FLAG_CSUM;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	info->encap.sport = encap->sport;
7362306a36Sopenharmony_ci	info->encap.dport = encap->dport;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return 0;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/* bpf_skb_get_fou_encap - Get FOU encap parameters
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * This function allows for reading encap metadata from a packet received
8162306a36Sopenharmony_ci * on an ipip device in collect-metadata mode.
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * Parameters:
8462306a36Sopenharmony_ci * @skb_ctx	Pointer to ctx (__sk_buff) in TC program. Cannot be NULL
8562306a36Sopenharmony_ci * @encap	Pointer to a struct bpf_fou_encap storing UDP source and
8662306a36Sopenharmony_ci * 		destination port. Cannot be NULL
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_ci__bpf_kfunc int bpf_skb_get_fou_encap(struct __sk_buff *skb_ctx,
8962306a36Sopenharmony_ci				      struct bpf_fou_encap *encap)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct sk_buff *skb = (struct sk_buff *)skb_ctx;
9262306a36Sopenharmony_ci	struct ip_tunnel_info *info = skb_tunnel_info(skb);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (unlikely(!info))
9562306a36Sopenharmony_ci		return -EINVAL;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	encap->sport = info->encap.sport;
9862306a36Sopenharmony_ci	encap->dport = info->encap.dport;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci__diag_pop()
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ciBTF_SET8_START(fou_kfunc_set)
10662306a36Sopenharmony_ciBTF_ID_FLAGS(func, bpf_skb_set_fou_encap)
10762306a36Sopenharmony_ciBTF_ID_FLAGS(func, bpf_skb_get_fou_encap)
10862306a36Sopenharmony_ciBTF_SET8_END(fou_kfunc_set)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const struct btf_kfunc_id_set fou_bpf_kfunc_set = {
11162306a36Sopenharmony_ci	.owner = THIS_MODULE,
11262306a36Sopenharmony_ci	.set   = &fou_kfunc_set,
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciint register_fou_bpf(void)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	return register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS,
11862306a36Sopenharmony_ci					 &fou_bpf_kfunc_set);
11962306a36Sopenharmony_ci}
120