162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Unstable XFRM 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/xfrm.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* bpf_xfrm_info - XFRM metadata information 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Members: 1862306a36Sopenharmony_ci * @if_id - XFRM if_id: 1962306a36Sopenharmony_ci * Transmit: if_id to be used in policy and state lookups 2062306a36Sopenharmony_ci * Receive: if_id of the state matched for the incoming packet 2162306a36Sopenharmony_ci * @link - Underlying device ifindex: 2262306a36Sopenharmony_ci * Transmit: used as the underlying device in VRF routing 2362306a36Sopenharmony_ci * Receive: the device on which the packet had been received 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_cistruct bpf_xfrm_info { 2662306a36Sopenharmony_ci u32 if_id; 2762306a36Sopenharmony_ci int link; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci__diag_push(); 3162306a36Sopenharmony_ci__diag_ignore_all("-Wmissing-prototypes", 3262306a36Sopenharmony_ci "Global functions as their definitions will be in xfrm_interface BTF"); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* bpf_skb_get_xfrm_info - Get XFRM metadata 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Parameters: 3762306a36Sopenharmony_ci * @skb_ctx - Pointer to ctx (__sk_buff) in TC program 3862306a36Sopenharmony_ci * Cannot be NULL 3962306a36Sopenharmony_ci * @to - Pointer to memory to which the metadata will be copied 4062306a36Sopenharmony_ci * Cannot be NULL 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci__bpf_kfunc int bpf_skb_get_xfrm_info(struct __sk_buff *skb_ctx, struct bpf_xfrm_info *to) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *)skb_ctx; 4562306a36Sopenharmony_ci struct xfrm_md_info *info; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci info = skb_xfrm_md_info(skb); 4862306a36Sopenharmony_ci if (!info) 4962306a36Sopenharmony_ci return -EINVAL; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci to->if_id = info->if_id; 5262306a36Sopenharmony_ci to->link = info->link; 5362306a36Sopenharmony_ci return 0; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* bpf_skb_get_xfrm_info - Set XFRM metadata 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Parameters: 5962306a36Sopenharmony_ci * @skb_ctx - Pointer to ctx (__sk_buff) in TC program 6062306a36Sopenharmony_ci * Cannot be NULL 6162306a36Sopenharmony_ci * @from - Pointer to memory from which the metadata will be copied 6262306a36Sopenharmony_ci * Cannot be NULL 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci__bpf_kfunc int bpf_skb_set_xfrm_info(struct __sk_buff *skb_ctx, const struct bpf_xfrm_info *from) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *)skb_ctx; 6762306a36Sopenharmony_ci struct metadata_dst *md_dst; 6862306a36Sopenharmony_ci struct xfrm_md_info *info; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (unlikely(skb_metadata_dst(skb))) 7162306a36Sopenharmony_ci return -EINVAL; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (!xfrm_bpf_md_dst) { 7462306a36Sopenharmony_ci struct metadata_dst __percpu *tmp; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci tmp = metadata_dst_alloc_percpu(0, METADATA_XFRM, GFP_ATOMIC); 7762306a36Sopenharmony_ci if (!tmp) 7862306a36Sopenharmony_ci return -ENOMEM; 7962306a36Sopenharmony_ci if (cmpxchg(&xfrm_bpf_md_dst, NULL, tmp)) 8062306a36Sopenharmony_ci metadata_dst_free_percpu(tmp); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci md_dst = this_cpu_ptr(xfrm_bpf_md_dst); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci info = &md_dst->u.xfrm_info; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci info->if_id = from->if_id; 8762306a36Sopenharmony_ci info->link = from->link; 8862306a36Sopenharmony_ci skb_dst_force(skb); 8962306a36Sopenharmony_ci info->dst_orig = skb_dst(skb); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci dst_hold((struct dst_entry *)md_dst); 9262306a36Sopenharmony_ci skb_dst_set(skb, (struct dst_entry *)md_dst); 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci__diag_pop() 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ciBTF_SET8_START(xfrm_ifc_kfunc_set) 9962306a36Sopenharmony_ciBTF_ID_FLAGS(func, bpf_skb_get_xfrm_info) 10062306a36Sopenharmony_ciBTF_ID_FLAGS(func, bpf_skb_set_xfrm_info) 10162306a36Sopenharmony_ciBTF_SET8_END(xfrm_ifc_kfunc_set) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic const struct btf_kfunc_id_set xfrm_interface_kfunc_set = { 10462306a36Sopenharmony_ci .owner = THIS_MODULE, 10562306a36Sopenharmony_ci .set = &xfrm_ifc_kfunc_set, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciint __init register_xfrm_interface_bpf(void) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci return register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, 11162306a36Sopenharmony_ci &xfrm_interface_kfunc_set); 11262306a36Sopenharmony_ci} 113