|  | 
|  | 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 <[email protected]> | 
|  | 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 | +	return smc_hs_ctrl_reg(kdata); | 
|  | 75 | +} | 
|  | 76 | + | 
|  | 77 | +static void smc_bpf_hs_ctrl_unreg(void *kdata, struct bpf_link *link) | 
|  | 78 | +{ | 
|  | 79 | +	smc_hs_ctrl_unreg(kdata); | 
|  | 80 | +} | 
|  | 81 | + | 
|  | 82 | +static int smc_bpf_hs_ctrl_init_member(const struct btf_type *t, | 
|  | 83 | +				       const struct btf_member *member, | 
|  | 84 | +				       void *kdata, const void *udata) | 
|  | 85 | +{ | 
|  | 86 | +	const struct smc_hs_ctrl *u_ctrl; | 
|  | 87 | +	struct smc_hs_ctrl *k_ctrl; | 
|  | 88 | +	u32 moff; | 
|  | 89 | + | 
|  | 90 | +	u_ctrl = (const struct smc_hs_ctrl *)udata; | 
|  | 91 | +	k_ctrl = (struct smc_hs_ctrl *)kdata; | 
|  | 92 | + | 
|  | 93 | +	moff = __btf_member_bit_offset(t, member) / 8; | 
|  | 94 | +	switch (moff) { | 
|  | 95 | +	case offsetof(struct smc_hs_ctrl, name): | 
|  | 96 | +		if (bpf_obj_name_cpy(k_ctrl->name, u_ctrl->name, | 
|  | 97 | +				     sizeof(u_ctrl->name)) <= 0) | 
|  | 98 | +			return -EINVAL; | 
|  | 99 | +		return 1; | 
|  | 100 | +	case offsetof(struct smc_hs_ctrl, flags): | 
|  | 101 | +		if (u_ctrl->flags & ~SMC_HS_CTRL_ALL_FLAGS) | 
|  | 102 | +			return -EINVAL; | 
|  | 103 | +		k_ctrl->flags = u_ctrl->flags; | 
|  | 104 | +		return 1; | 
|  | 105 | +	default: | 
|  | 106 | +		break; | 
|  | 107 | +	} | 
|  | 108 | + | 
|  | 109 | +	return 0; | 
|  | 110 | +} | 
|  | 111 | + | 
|  | 112 | +static const struct bpf_func_proto * | 
|  | 113 | +bpf_smc_hs_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) | 
|  | 114 | +{ | 
|  | 115 | +	return bpf_base_func_proto(func_id, prog); | 
|  | 116 | +} | 
|  | 117 | + | 
|  | 118 | +static const struct bpf_verifier_ops smc_bpf_verifier_ops = { | 
|  | 119 | +	.get_func_proto		= bpf_smc_hs_func_proto, | 
|  | 120 | +	.is_valid_access	= bpf_tracing_btf_ctx_access, | 
|  | 121 | +}; | 
|  | 122 | + | 
|  | 123 | +static struct bpf_struct_ops bpf_smc_hs_ctrl_ops = { | 
|  | 124 | +	.name		= "smc_hs_ctrl", | 
|  | 125 | +	.init		= smc_bpf_hs_ctrl_init, | 
|  | 126 | +	.reg		= smc_bpf_hs_ctrl_reg, | 
|  | 127 | +	.unreg		= smc_bpf_hs_ctrl_unreg, | 
|  | 128 | +	.cfi_stubs	= &__smc_bpf_hs_ctrl, | 
|  | 129 | +	.verifier_ops	= &smc_bpf_verifier_ops, | 
|  | 130 | +	.init_member	= smc_bpf_hs_ctrl_init_member, | 
|  | 131 | +	.owner		= THIS_MODULE, | 
|  | 132 | +}; | 
|  | 133 | + | 
|  | 134 | +int bpf_smc_hs_ctrl_init(void) | 
|  | 135 | +{ | 
|  | 136 | +	return register_bpf_struct_ops(&bpf_smc_hs_ctrl_ops, smc_hs_ctrl); | 
|  | 137 | +} | 
0 commit comments