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
15struct bpf_fou_encap {
16	__be16 sport;
17	__be16 dport;
18};
19
20enum bpf_fou_encap_type {
21	FOU_BPF_ENCAP_FOU,
22	FOU_BPF_ENCAP_GUE,
23};
24
25__bpf_kfunc_start_defs();
26
27/* bpf_skb_set_fou_encap - Set FOU encap parameters
28 *
29 * This function allows for using GUE or FOU encapsulation together with an
30 * ipip device in collect-metadata mode.
31 *
32 * It is meant to be used in BPF tc-hooks and after a call to the
33 * bpf_skb_set_tunnel_key helper, responsible for setting IP addresses.
34 *
35 * Parameters:
36 * @skb_ctx	Pointer to ctx (__sk_buff) in TC program. Cannot be NULL
37 * @encap	Pointer to a `struct bpf_fou_encap` storing UDP src and
38 * 		dst ports. If sport is set to 0 the kernel will auto-assign a
39 * 		port. This is similar to using `encap-sport auto`.
40 * 		Cannot be NULL
41 * @type	Encapsulation type for the packet. Their definitions are
42 * 		specified in `enum bpf_fou_encap_type`
43 */
44__bpf_kfunc int bpf_skb_set_fou_encap(struct __sk_buff *skb_ctx,
45				      struct bpf_fou_encap *encap, int type)
46{
47	struct sk_buff *skb = (struct sk_buff *)skb_ctx;
48	struct ip_tunnel_info *info = skb_tunnel_info(skb);
49
50	if (unlikely(!encap))
51		return -EINVAL;
52
53	if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX)))
54		return -EINVAL;
55
56	switch (type) {
57	case FOU_BPF_ENCAP_FOU:
58		info->encap.type = TUNNEL_ENCAP_FOU;
59		break;
60	case FOU_BPF_ENCAP_GUE:
61		info->encap.type = TUNNEL_ENCAP_GUE;
62		break;
63	default:
64		info->encap.type = TUNNEL_ENCAP_NONE;
65	}
66
67	if (info->key.tun_flags & TUNNEL_CSUM)
68		info->encap.flags |= TUNNEL_ENCAP_FLAG_CSUM;
69
70	info->encap.sport = encap->sport;
71	info->encap.dport = encap->dport;
72
73	return 0;
74}
75
76/* bpf_skb_get_fou_encap - Get FOU encap parameters
77 *
78 * This function allows for reading encap metadata from a packet received
79 * on an ipip device in collect-metadata mode.
80 *
81 * Parameters:
82 * @skb_ctx	Pointer to ctx (__sk_buff) in TC program. Cannot be NULL
83 * @encap	Pointer to a struct bpf_fou_encap storing UDP source and
84 * 		destination port. Cannot be NULL
85 */
86__bpf_kfunc int bpf_skb_get_fou_encap(struct __sk_buff *skb_ctx,
87				      struct bpf_fou_encap *encap)
88{
89	struct sk_buff *skb = (struct sk_buff *)skb_ctx;
90	struct ip_tunnel_info *info = skb_tunnel_info(skb);
91
92	if (unlikely(!info))
93		return -EINVAL;
94
95	encap->sport = info->encap.sport;
96	encap->dport = info->encap.dport;
97
98	return 0;
99}
100
101__bpf_kfunc_end_defs();
102
103BTF_KFUNCS_START(fou_kfunc_set)
104BTF_ID_FLAGS(func, bpf_skb_set_fou_encap)
105BTF_ID_FLAGS(func, bpf_skb_get_fou_encap)
106BTF_KFUNCS_END(fou_kfunc_set)
107
108static const struct btf_kfunc_id_set fou_bpf_kfunc_set = {
109	.owner = THIS_MODULE,
110	.set   = &fou_kfunc_set,
111};
112
113int register_fou_bpf(void)
114{
115	return register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS,
116					 &fou_bpf_kfunc_set);
117}
118