1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Shared Memory Communications over RDMA (SMC-R) and RoCE 4 * 5 * Generic hook for SMC handshake flow. 6 * 7 * Copyright IBM Corp. 2016 8 * Copyright (c) 2025, Alibaba Inc. 9 * 10 * Author: D. Wythe <alibuda@linux.alibaba.com> 11 */ 12 13 #include <linux/bpf_verifier.h> 14 #include <linux/bpf.h> 15 #include <linux/btf.h> 16 #include <linux/rculist.h> 17 18 #include "smc_hs_bpf.h" 19 20 static DEFINE_SPINLOCK(smc_hs_ctrl_list_lock); 21 static LIST_HEAD(smc_hs_ctrl_list); 22 23 static int smc_hs_ctrl_reg(struct smc_hs_ctrl *ctrl) 24 { 25 int ret = 0; 26 27 spin_lock(&smc_hs_ctrl_list_lock); 28 /* already exist or duplicate name */ 29 if (smc_hs_ctrl_find_by_name(ctrl->name)) 30 ret = -EEXIST; 31 else 32 list_add_tail_rcu(&ctrl->list, &smc_hs_ctrl_list); 33 spin_unlock(&smc_hs_ctrl_list_lock); 34 return ret; 35 } 36 37 static void smc_hs_ctrl_unreg(struct smc_hs_ctrl *ctrl) 38 { 39 spin_lock(&smc_hs_ctrl_list_lock); 40 list_del_rcu(&ctrl->list); 41 spin_unlock(&smc_hs_ctrl_list_lock); 42 43 /* Ensure that all readers to complete */ 44 synchronize_rcu(); 45 } 46 47 struct smc_hs_ctrl *smc_hs_ctrl_find_by_name(const char *name) 48 { 49 struct smc_hs_ctrl *ctrl; 50 51 list_for_each_entry_rcu(ctrl, &smc_hs_ctrl_list, list) { 52 if (strcmp(ctrl->name, name) == 0) 53 return ctrl; 54 } 55 return NULL; 56 } 57 58 static int __smc_bpf_stub_set_tcp_option(struct tcp_sock *tp) { return 1; } 59 static int __smc_bpf_stub_set_tcp_option_cond(const struct tcp_sock *tp, 60 struct inet_request_sock *ireq) 61 { 62 return 1; 63 } 64 65 static struct smc_hs_ctrl __smc_bpf_hs_ctrl = { 66 .syn_option = __smc_bpf_stub_set_tcp_option, 67 .synack_option = __smc_bpf_stub_set_tcp_option_cond, 68 }; 69 70 static int smc_bpf_hs_ctrl_init(struct btf *btf) { return 0; } 71 72 static int smc_bpf_hs_ctrl_reg(void *kdata, struct bpf_link *link) 73 { 74 if (link) 75 return -EOPNOTSUPP; 76 77 return smc_hs_ctrl_reg(kdata); 78 } 79 80 static void smc_bpf_hs_ctrl_unreg(void *kdata, struct bpf_link *link) 81 { 82 smc_hs_ctrl_unreg(kdata); 83 } 84 85 static int smc_bpf_hs_ctrl_init_member(const struct btf_type *t, 86 const struct btf_member *member, 87 void *kdata, const void *udata) 88 { 89 const struct smc_hs_ctrl *u_ctrl; 90 struct smc_hs_ctrl *k_ctrl; 91 u32 moff; 92 93 u_ctrl = (const struct smc_hs_ctrl *)udata; 94 k_ctrl = (struct smc_hs_ctrl *)kdata; 95 96 moff = __btf_member_bit_offset(t, member) / 8; 97 switch (moff) { 98 case offsetof(struct smc_hs_ctrl, name): 99 if (bpf_obj_name_cpy(k_ctrl->name, u_ctrl->name, 100 sizeof(u_ctrl->name)) <= 0) 101 return -EINVAL; 102 return 1; 103 case offsetof(struct smc_hs_ctrl, flags): 104 if (u_ctrl->flags & ~SMC_HS_CTRL_ALL_FLAGS) 105 return -EINVAL; 106 k_ctrl->flags = u_ctrl->flags; 107 return 1; 108 default: 109 break; 110 } 111 112 return 0; 113 } 114 115 static const struct bpf_func_proto * 116 bpf_smc_hs_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 117 { 118 return bpf_base_func_proto(func_id, prog); 119 } 120 121 static const struct bpf_verifier_ops smc_bpf_verifier_ops = { 122 .get_func_proto = bpf_smc_hs_func_proto, 123 .is_valid_access = bpf_tracing_btf_ctx_access, 124 }; 125 126 static struct bpf_struct_ops bpf_smc_hs_ctrl_ops = { 127 .name = "smc_hs_ctrl", 128 .init = smc_bpf_hs_ctrl_init, 129 .reg = smc_bpf_hs_ctrl_reg, 130 .unreg = smc_bpf_hs_ctrl_unreg, 131 .cfi_stubs = &__smc_bpf_hs_ctrl, 132 .verifier_ops = &smc_bpf_verifier_ops, 133 .init_member = smc_bpf_hs_ctrl_init_member, 134 .owner = THIS_MODULE, 135 }; 136 137 int bpf_smc_hs_ctrl_init(void) 138 { 139 return register_bpf_struct_ops(&bpf_smc_hs_ctrl_ops, smc_hs_ctrl); 140 } 141