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