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