1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Unstable XFRM 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/xfrm.h> |
14 | |
15 | /* bpf_xfrm_info - XFRM metadata information |
16 | * |
17 | * Members: |
18 | * @if_id - XFRM if_id: |
19 | * Transmit: if_id to be used in policy and state lookups |
20 | * Receive: if_id of the state matched for the incoming packet |
21 | * @link - Underlying device ifindex: |
22 | * Transmit: used as the underlying device in VRF routing |
23 | * Receive: the device on which the packet had been received |
24 | */ |
25 | struct bpf_xfrm_info { |
26 | u32 if_id; |
27 | int link; |
28 | }; |
29 | |
30 | __bpf_kfunc_start_defs(); |
31 | |
32 | /* bpf_skb_get_xfrm_info - Get XFRM metadata |
33 | * |
34 | * Parameters: |
35 | * @skb_ctx - Pointer to ctx (__sk_buff) in TC program |
36 | * Cannot be NULL |
37 | * @to - Pointer to memory to which the metadata will be copied |
38 | * Cannot be NULL |
39 | */ |
40 | __bpf_kfunc int bpf_skb_get_xfrm_info(struct __sk_buff *skb_ctx, struct bpf_xfrm_info *to) |
41 | { |
42 | struct sk_buff *skb = (struct sk_buff *)skb_ctx; |
43 | struct xfrm_md_info *info; |
44 | |
45 | info = skb_xfrm_md_info(skb); |
46 | if (!info) |
47 | return -EINVAL; |
48 | |
49 | to->if_id = info->if_id; |
50 | to->link = info->link; |
51 | return 0; |
52 | } |
53 | |
54 | /* bpf_skb_get_xfrm_info - Set XFRM metadata |
55 | * |
56 | * Parameters: |
57 | * @skb_ctx - Pointer to ctx (__sk_buff) in TC program |
58 | * Cannot be NULL |
59 | * @from - Pointer to memory from which the metadata will be copied |
60 | * Cannot be NULL |
61 | */ |
62 | __bpf_kfunc int bpf_skb_set_xfrm_info(struct __sk_buff *skb_ctx, const struct bpf_xfrm_info *from) |
63 | { |
64 | struct sk_buff *skb = (struct sk_buff *)skb_ctx; |
65 | struct metadata_dst *md_dst; |
66 | struct xfrm_md_info *info; |
67 | |
68 | if (unlikely(skb_metadata_dst(skb))) |
69 | return -EINVAL; |
70 | |
71 | if (!xfrm_bpf_md_dst) { |
72 | struct metadata_dst __percpu *tmp; |
73 | |
74 | tmp = metadata_dst_alloc_percpu(optslen: 0, type: METADATA_XFRM, GFP_ATOMIC); |
75 | if (!tmp) |
76 | return -ENOMEM; |
77 | if (cmpxchg(&xfrm_bpf_md_dst, NULL, tmp)) |
78 | metadata_dst_free_percpu(md_dst: tmp); |
79 | } |
80 | md_dst = this_cpu_ptr(xfrm_bpf_md_dst); |
81 | |
82 | info = &md_dst->u.xfrm_info; |
83 | |
84 | info->if_id = from->if_id; |
85 | info->link = from->link; |
86 | skb_dst_force(skb); |
87 | info->dst_orig = skb_dst(skb); |
88 | |
89 | dst_hold(dst: (struct dst_entry *)md_dst); |
90 | skb_dst_set(skb, dst: (struct dst_entry *)md_dst); |
91 | return 0; |
92 | } |
93 | |
94 | __bpf_kfunc_end_defs(); |
95 | |
96 | BTF_KFUNCS_START(xfrm_ifc_kfunc_set) |
97 | BTF_ID_FLAGS(func, bpf_skb_get_xfrm_info) |
98 | BTF_ID_FLAGS(func, bpf_skb_set_xfrm_info) |
99 | BTF_KFUNCS_END(xfrm_ifc_kfunc_set) |
100 | |
101 | static const struct btf_kfunc_id_set xfrm_interface_kfunc_set = { |
102 | .owner = THIS_MODULE, |
103 | .set = &xfrm_ifc_kfunc_set, |
104 | }; |
105 | |
106 | int __init register_xfrm_interface_bpf(void) |
107 | { |
108 | return register_btf_kfunc_id_set(prog_type: BPF_PROG_TYPE_SCHED_CLS, |
109 | s: &xfrm_interface_kfunc_set); |
110 | } |
111 | |