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 __diag_push(); 31 __diag_ignore_all("-Wmissing-prototypes", 32 "Global functions as their definitions will be in xfrm_interface BTF"); 33 34 /* bpf_skb_get_xfrm_info - Get XFRM metadata 35 * 36 * Parameters: 37 * @skb_ctx - Pointer to ctx (__sk_buff) in TC program 38 * Cannot be NULL 39 * @to - Pointer to memory to which the metadata will be copied 40 * Cannot be NULL 41 */ 42 __used noinline 43 int bpf_skb_get_xfrm_info(struct __sk_buff *skb_ctx, struct bpf_xfrm_info *to) 44 { 45 struct sk_buff *skb = (struct sk_buff *)skb_ctx; 46 struct xfrm_md_info *info; 47 48 info = skb_xfrm_md_info(skb); 49 if (!info) 50 return -EINVAL; 51 52 to->if_id = info->if_id; 53 to->link = info->link; 54 return 0; 55 } 56 57 /* bpf_skb_get_xfrm_info - Set XFRM metadata 58 * 59 * Parameters: 60 * @skb_ctx - Pointer to ctx (__sk_buff) in TC program 61 * Cannot be NULL 62 * @from - Pointer to memory from which the metadata will be copied 63 * Cannot be NULL 64 */ 65 __used noinline 66 int bpf_skb_set_xfrm_info(struct __sk_buff *skb_ctx, 67 const struct bpf_xfrm_info *from) 68 { 69 struct sk_buff *skb = (struct sk_buff *)skb_ctx; 70 struct metadata_dst *md_dst; 71 struct xfrm_md_info *info; 72 73 if (unlikely(skb_metadata_dst(skb))) 74 return -EINVAL; 75 76 if (!xfrm_bpf_md_dst) { 77 struct metadata_dst __percpu *tmp; 78 79 tmp = metadata_dst_alloc_percpu(0, METADATA_XFRM, GFP_ATOMIC); 80 if (!tmp) 81 return -ENOMEM; 82 if (cmpxchg(&xfrm_bpf_md_dst, NULL, tmp)) 83 metadata_dst_free_percpu(tmp); 84 } 85 md_dst = this_cpu_ptr(xfrm_bpf_md_dst); 86 87 info = &md_dst->u.xfrm_info; 88 89 info->if_id = from->if_id; 90 info->link = from->link; 91 skb_dst_force(skb); 92 info->dst_orig = skb_dst(skb); 93 94 dst_hold((struct dst_entry *)md_dst); 95 skb_dst_set(skb, (struct dst_entry *)md_dst); 96 return 0; 97 } 98 99 __diag_pop() 100 101 BTF_SET8_START(xfrm_ifc_kfunc_set) 102 BTF_ID_FLAGS(func, bpf_skb_get_xfrm_info) 103 BTF_ID_FLAGS(func, bpf_skb_set_xfrm_info) 104 BTF_SET8_END(xfrm_ifc_kfunc_set) 105 106 static const struct btf_kfunc_id_set xfrm_interface_kfunc_set = { 107 .owner = THIS_MODULE, 108 .set = &xfrm_ifc_kfunc_set, 109 }; 110 111 int __init register_xfrm_interface_bpf(void) 112 { 113 return register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, 114 &xfrm_interface_kfunc_set); 115 } 116