1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
// SPDX-License-Identifier: GPL-2.0-only
/*
* Shared Memory Communications over RDMA (SMC-R) and RoCE
*
* Definitions for the IPPROTO_SMC (socket related)
*
* Copyright IBM Corp. 2016, 2018
* Copyright (c) 2024, Alibaba Inc.
*
* Author: D. Wythe <alibuda@linux.alibaba.com>
*/
#include <net/protocol.h>
#include <net/sock.h>
#include "smc_inet.h"
#include "smc.h"
static int smc_inet_init_sock(struct sock *sk);
static struct proto smc_inet_prot = {
.name = "INET_SMC",
.owner = THIS_MODULE,
.init = smc_inet_init_sock,
.hash = smc_hash_sk,
.unhash = smc_unhash_sk,
.release_cb = smc_release_cb,
.obj_size = sizeof(struct smc_sock),
.h.smc_hash = &smc_v4_hashinfo,
.slab_flags = SLAB_TYPESAFE_BY_RCU,
};
static const struct proto_ops smc_inet_stream_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
.release = smc_release,
.bind = smc_bind,
.connect = smc_connect,
.socketpair = sock_no_socketpair,
.accept = smc_accept,
.getname = smc_getname,
.poll = smc_poll,
.ioctl = smc_ioctl,
.listen = smc_listen,
.shutdown = smc_shutdown,
.setsockopt = smc_setsockopt,
.getsockopt = smc_getsockopt,
.sendmsg = smc_sendmsg,
.recvmsg = smc_recvmsg,
.mmap = sock_no_mmap,
.splice_read = smc_splice_read,
};
static struct inet_protosw smc_inet_protosw = {
.type = SOCK_STREAM,
.protocol = IPPROTO_SMC,
.prot = &smc_inet_prot,
.ops = &smc_inet_stream_ops,
.flags = INET_PROTOSW_ICSK,
};
#if IS_ENABLED(CONFIG_IPV6)
struct smc6_sock {
struct smc_sock smc;
struct ipv6_pinfo inet6;
};
static struct proto smc_inet6_prot = {
.name = "INET6_SMC",
.owner = THIS_MODULE,
.init = smc_inet_init_sock,
.hash = smc_hash_sk,
.unhash = smc_unhash_sk,
.release_cb = smc_release_cb,
.obj_size = sizeof(struct smc6_sock),
.h.smc_hash = &smc_v6_hashinfo,
.slab_flags = SLAB_TYPESAFE_BY_RCU,
.ipv6_pinfo_offset = offsetof(struct smc6_sock, inet6),
};
static const struct proto_ops smc_inet6_stream_ops = {
.family = PF_INET6,
.owner = THIS_MODULE,
.release = smc_release,
.bind = smc_bind,
.connect = smc_connect,
.socketpair = sock_no_socketpair,
.accept = smc_accept,
.getname = smc_getname,
.poll = smc_poll,
.ioctl = smc_ioctl,
.listen = smc_listen,
.shutdown = smc_shutdown,
.setsockopt = smc_setsockopt,
.getsockopt = smc_getsockopt,
.sendmsg = smc_sendmsg,
.recvmsg = smc_recvmsg,
.mmap = sock_no_mmap,
.splice_read = smc_splice_read,
};
static struct inet_protosw smc_inet6_protosw = {
.type = SOCK_STREAM,
.protocol = IPPROTO_SMC,
.prot = &smc_inet6_prot,
.ops = &smc_inet6_stream_ops,
.flags = INET_PROTOSW_ICSK,
};
#endif /* CONFIG_IPV6 */
static unsigned int smc_sync_mss(struct sock *sk, u32 pmtu)
{
/* No need pass it through to clcsock, mss can always be set by
* sock_create_kern or smc_setsockopt.
*/
return 0;
}
static int smc_inet_init_sock(struct sock *sk)
{
struct net *net = sock_net(sk);
/* init common smc sock */
smc_sk_init(net, sk, IPPROTO_SMC);
inet_csk(sk)->icsk_sync_mss = smc_sync_mss;
/* create clcsock */
return smc_create_clcsk(net, sk, sk->sk_family);
}
int __init smc_inet_init(void)
{
int rc;
rc = proto_register(&smc_inet_prot, 1);
if (rc) {
pr_err("%s: proto_register smc_inet_prot fails with %d\n",
__func__, rc);
return rc;
}
/* no return value */
inet_register_protosw(&smc_inet_protosw);
#if IS_ENABLED(CONFIG_IPV6)
rc = proto_register(&smc_inet6_prot, 1);
if (rc) {
pr_err("%s: proto_register smc_inet6_prot fails with %d\n",
__func__, rc);
goto out_inet6_prot;
}
rc = inet6_register_protosw(&smc_inet6_protosw);
if (rc) {
pr_err("%s: inet6_register_protosw smc_inet6_protosw fails with %d\n",
__func__, rc);
goto out_inet6_protosw;
}
return rc;
out_inet6_protosw:
proto_unregister(&smc_inet6_prot);
out_inet6_prot:
inet_unregister_protosw(&smc_inet_protosw);
proto_unregister(&smc_inet_prot);
#endif /* CONFIG_IPV6 */
return rc;
}
void smc_inet_exit(void)
{
#if IS_ENABLED(CONFIG_IPV6)
inet6_unregister_protosw(&smc_inet6_protosw);
proto_unregister(&smc_inet6_prot);
#endif /* CONFIG_IPV6 */
inet_unregister_protosw(&smc_inet_protosw);
proto_unregister(&smc_inet_prot);
}
|