@@ -264,6 +264,18 @@ enum {
MAX_BTF_TRACING_TYPE,
};
+#if IS_ENABLED(CONFIG_SMC)
+enum {
+#define BTF_SMC_TYPE(name, type) name,
+BTF_SMC_TYPE(BTF_SMC_TYPE_SOCK, smc_sock)
+BTF_SMC_TYPE(BTF_SMC_TYPE_CONNECTION, smc_connection)
+BTF_SMC_TYPE(BTF_SMC_TYPE_HOST_CURSOR, smc_host_cursor)
+#undef BTF_SMC_TYPE
+MAX_BTF_SMC_TYPE,
+};
+extern u32 btf_smc_ids[];
+#endif
+
extern u32 btf_tracing_ids[];
extern u32 bpf_cgroup_btf_id[];
extern u32 bpf_local_storage_map_btf_id[];
@@ -16,6 +16,7 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/wait.h>
+#include <linux/bpf.h>
#include "linux/ism.h"
#ifdef ATOMIC64_INIT
@@ -315,4 +316,41 @@ struct smc_sock { /* smc sock container */
*/
};
+#define SMC_SOCK_CLOSED_TIMING (0)
+
+#ifdef CONFIG_BPF_SYSCALL
+
+/* BPF struct ops for smc protocol negotiator */
+struct smc_sock_negotiator_ops {
+ /* ret for negotiate */
+ int (*negotiate)(struct smc_sock *sk);
+
+ /* info gathering timing */
+ void (*collect_info)(struct sock *sk, int timing);
+};
+
+/* Query if current sock should go with SMC protocol
+ * SK_PASS for yes, otherwise for no.
+ */
+int smc_sock_should_select_smc(const struct smc_sock *smc);
+
+/* At some specific points in time,
+ * let negotiator can perform info gathering
+ * on target sock.
+ */
+void smc_sock_perform_collecting_info(const struct sock *sk, int timing);
+
+#else
+
+static inline int smc_sock_should_select_smc(const struct smc_sock *smc)
+{
+ return SK_PASS;
+}
+
+static inline void smc_sock_perform_collecting_info(const struct sock *sk, int timing)
+{
+}
+
+#endif /* CONFIG_BPF_SYSCALL */
+
#endif /* _SMC_H */
@@ -9,4 +9,8 @@
#include <net/tcp.h>
BPF_STRUCT_OPS_TYPE(tcp_congestion_ops)
#endif
+#if IS_ENABLED(CONFIG_SMC)
+#include <net/smc.h>
+BPF_STRUCT_OPS_TYPE(smc_sock_negotiator_ops)
+#endif
#endif
@@ -52,6 +52,11 @@ obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
obj-$(CONFIG_IUCV) += iucv/
obj-$(CONFIG_SMC) += smc/
+ifneq ($(CONFIG_SMC),)
+ifeq ($(CONFIG_BPF_SYSCALL),y)
+obj-y += smc/bpf_smc_struct_ops.o
+endif
+endif
obj-$(CONFIG_RFKILL) += rfkill/
obj-$(CONFIG_NET_9P) += 9p/
obj-$(CONFIG_CAIF) += caif/
new file mode 100644
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/bpf_verifier.h>
+#include <linux/btf_ids.h>
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <net/sock.h>
+#include <net/smc.h>
+
+extern struct bpf_struct_ops smc_sock_negotiator_ops;
+
+DEFINE_RWLOCK(smc_sock_negotiator_ops_rwlock);
+struct smc_sock_negotiator_ops *negotiator;
+
+/* convert sk to smc_sock */
+static inline struct smc_sock *smc_sk(const struct sock *sk)
+{
+ return (struct smc_sock *)sk;
+}
+
+/* register ops */
+static inline void smc_reg_passive_sk_ops(struct smc_sock_negotiator_ops *ops)
+{
+ write_lock_bh(&smc_sock_negotiator_ops_rwlock);
+ negotiator = ops;
+ write_unlock_bh(&smc_sock_negotiator_ops_rwlock);
+}
+
+/* unregister ops */
+static inline void smc_unreg_passive_sk_ops(struct smc_sock_negotiator_ops *ops)
+{
+ write_lock_bh(&smc_sock_negotiator_ops_rwlock);
+ if (negotiator == ops)
+ negotiator = NULL;
+ write_unlock_bh(&smc_sock_negotiator_ops_rwlock);
+}
+
+int smc_sock_should_select_smc(const struct smc_sock *smc)
+{
+ int ret = SK_PASS;
+
+ read_lock_bh(&smc_sock_negotiator_ops_rwlock);
+ if (negotiator && negotiator->negotiate)
+ ret = negotiator->negotiate((struct smc_sock *)smc);
+ read_unlock_bh(&smc_sock_negotiator_ops_rwlock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(smc_sock_should_select_smc);
+
+void smc_sock_perform_collecting_info(const struct sock *sk, int timing)
+{
+ read_lock_bh(&smc_sock_negotiator_ops_rwlock);
+ if (negotiator && negotiator->collect_info)
+ negotiator->collect_info((struct sock *)sk, timing);
+ read_unlock_bh(&smc_sock_negotiator_ops_rwlock);
+}
+EXPORT_SYMBOL_GPL(smc_sock_perform_collecting_info);
+
+/* define global smc ID for smc_struct_ops */
+BTF_ID_LIST_GLOBAL(btf_smc_ids, MAX_BTF_SMC_TYPE)
+#define BTF_SMC_TYPE(name, type) BTF_ID(struct, type)
+BTF_SMC_TYPE(BTF_SMC_TYPE_SOCK, smc_sock)
+BTF_SMC_TYPE(BTF_SMC_TYPE_CONNECTION, smc_connection)
+BTF_SMC_TYPE(BTF_SMC_TYPE_HOST_CURSOR, smc_host_cursor)
+#undef BTF_SMC_TYPE
+
+static int bpf_smc_passive_sk_init(struct btf *btf)
+{
+ return 0;
+}
+
+/* register ops by BPF */
+static int bpf_smc_passive_sk_ops_reg(void *kdata)
+{
+ struct smc_sock_negotiator_ops *ops = kdata;
+
+ /* at least one ops need implement */
+ if (!ops->negotiate || !ops->collect_info) {
+ pr_err("At least one ops need implement.\n");
+ return -EINVAL;
+ }
+
+ smc_reg_passive_sk_ops(ops);
+ /* always success now */
+ return 0;
+}
+
+/* unregister ops by BPF */
+static void bpf_smc_passive_sk_ops_unreg(void *kdata)
+{
+ smc_unreg_passive_sk_ops(kdata);
+}
+
+static int bpf_smc_passive_sk_ops_check_member(const struct btf_type *t,
+ const struct btf_member *member,
+ const struct bpf_prog *prog)
+{
+ return 0;
+}
+
+static int bpf_smc_passive_sk_ops_init_member(const struct btf_type *t,
+ const struct btf_member *member,
+ void *kdata, const void *udata)
+{
+ return 0;
+}
+
+static const struct bpf_func_proto *
+smc_passive_sk_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
+{
+ return bpf_base_func_proto(func_id);
+}
+
+static bool smc_passive_sk_ops_prog_is_valid_access(int off, int size, enum bpf_access_type type,
+ const struct bpf_prog *prog,
+ struct bpf_insn_access_aux *info)
+{
+ return bpf_tracing_btf_ctx_access(off, size, type, prog, info);
+}
+
+static int smc_passive_sk_ops_prog_struct_access(struct bpf_verifier_log *log,
+ const struct bpf_reg_state *reg,
+ int off, int size, enum bpf_access_type atype,
+ u32 *next_btf_id, enum bpf_type_flag *flag)
+{
+ /* only allow read now*/
+ if (atype == BPF_READ)
+ return btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
+
+ return -EACCES;
+}
+
+static const struct bpf_verifier_ops bpf_smc_passive_sk_verifier_ops = {
+ .get_func_proto = smc_passive_sk_prog_func_proto,
+ .is_valid_access = smc_passive_sk_ops_prog_is_valid_access,
+ .btf_struct_access = smc_passive_sk_ops_prog_struct_access
+};
+
+struct bpf_struct_ops bpf_smc_sock_negotiator_ops = {
+ .verifier_ops = &bpf_smc_passive_sk_verifier_ops,
+ .init = bpf_smc_passive_sk_init,
+ .check_member = bpf_smc_passive_sk_ops_check_member,
+ .init_member = bpf_smc_passive_sk_ops_init_member,
+ .reg = bpf_smc_passive_sk_ops_reg,
+ .unreg = bpf_smc_passive_sk_ops_unreg,
+ .name = "smc_sock_negotiator_ops",
+};