blob: b613b866a2ef55bbf996f4b9a88d4f742a6cbc57 [file] [log] [blame]
Ursula Brauna046d572017-01-09 16:55:16 +01001/*
2 * Shared Memory Communications over RDMA (SMC-R) and RoCE
3 *
4 * CLC (connection layer control) handshake over initial TCP socket to
5 * prepare for RDMA traffic
6 *
7 * Copyright IBM Corp. 2016
8 *
9 * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com>
10 */
11
12#include <linux/in.h>
13#include <net/sock.h>
14#include <net/tcp.h>
15
16#include "smc.h"
17#include "smc_clc.h"
18#include "smc_ib.h"
19
20/* Wait for data on the tcp-socket, analyze received data
21 * Returns:
22 * 0 if success and it was not a decline that we received.
23 * SMC_CLC_DECL_REPLY if decline received for fallback w/o another decl send.
24 * clcsock error, -EINTR, -ECONNRESET, -EPROTO otherwise.
25 */
26int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
27 u8 expected_type)
28{
29 struct sock *clc_sk = smc->clcsock->sk;
30 struct smc_clc_msg_hdr *clcm = buf;
31 struct msghdr msg = {NULL, 0};
32 int reason_code = 0;
33 struct kvec vec;
34 int len, datlen;
35 int krflags;
36
37 /* peek the first few bytes to determine length of data to receive
38 * so we don't consume any subsequent CLC message or payload data
39 * in the TCP byte stream
40 */
41 vec.iov_base = buf;
42 vec.iov_len = buflen;
43 krflags = MSG_PEEK | MSG_WAITALL;
44 smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME;
45 len = kernel_recvmsg(smc->clcsock, &msg, &vec, 1,
46 sizeof(struct smc_clc_msg_hdr), krflags);
47 if (signal_pending(current)) {
48 reason_code = -EINTR;
49 clc_sk->sk_err = EINTR;
50 smc->sk.sk_err = EINTR;
51 goto out;
52 }
53 if (clc_sk->sk_err) {
54 reason_code = -clc_sk->sk_err;
55 smc->sk.sk_err = clc_sk->sk_err;
56 goto out;
57 }
58 if (!len) { /* peer has performed orderly shutdown */
59 smc->sk.sk_err = ECONNRESET;
60 reason_code = -ECONNRESET;
61 goto out;
62 }
63 if (len < 0) {
64 smc->sk.sk_err = -len;
65 reason_code = len;
66 goto out;
67 }
68 datlen = ntohs(clcm->length);
69 if ((len < sizeof(struct smc_clc_msg_hdr)) ||
70 (datlen < sizeof(struct smc_clc_msg_decline)) ||
71 (datlen > sizeof(struct smc_clc_msg_accept_confirm)) ||
72 memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) ||
73 ((clcm->type != SMC_CLC_DECLINE) &&
74 (clcm->type != expected_type))) {
75 smc->sk.sk_err = EPROTO;
76 reason_code = -EPROTO;
77 goto out;
78 }
79
80 /* receive the complete CLC message */
81 vec.iov_base = buf;
82 vec.iov_len = buflen;
83 memset(&msg, 0, sizeof(struct msghdr));
84 krflags = MSG_WAITALL;
85 smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME;
86 len = kernel_recvmsg(smc->clcsock, &msg, &vec, 1, datlen, krflags);
87 if (len < datlen) {
88 smc->sk.sk_err = EPROTO;
89 reason_code = -EPROTO;
90 goto out;
91 }
92 if (clcm->type == SMC_CLC_DECLINE)
93 reason_code = SMC_CLC_DECL_REPLY;
94out:
95 return reason_code;
96}
97
98/* send CLC DECLINE message across internal TCP socket */
99int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info,
100 u8 out_of_sync)
101{
102 struct smc_clc_msg_decline dclc;
103 struct msghdr msg;
104 struct kvec vec;
105 int len;
106
107 memset(&dclc, 0, sizeof(dclc));
108 memcpy(dclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
109 dclc.hdr.type = SMC_CLC_DECLINE;
110 dclc.hdr.length = htons(sizeof(struct smc_clc_msg_decline));
111 dclc.hdr.version = SMC_CLC_V1;
112 dclc.hdr.flag = out_of_sync ? 1 : 0;
113 memcpy(dclc.id_for_peer, local_systemid, sizeof(local_systemid));
114 dclc.peer_diagnosis = htonl(peer_diag_info);
115 memcpy(dclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
116
117 memset(&msg, 0, sizeof(msg));
118 vec.iov_base = &dclc;
119 vec.iov_len = sizeof(struct smc_clc_msg_decline);
120 len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1,
121 sizeof(struct smc_clc_msg_decline));
122 if (len < sizeof(struct smc_clc_msg_decline))
123 smc->sk.sk_err = EPROTO;
124 if (len < 0)
125 smc->sk.sk_err = -len;
126 return len;
127}
128
129/* send CLC PROPOSAL message across internal TCP socket */
130int smc_clc_send_proposal(struct smc_sock *smc,
131 struct smc_ib_device *smcibdev,
132 u8 ibport)
133{
134 struct smc_clc_msg_proposal pclc;
135 int reason_code = 0;
136 struct msghdr msg;
137 struct kvec vec;
138 int len, rc;
139
140 /* send SMC Proposal CLC message */
141 memset(&pclc, 0, sizeof(pclc));
142 memcpy(pclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
143 pclc.hdr.type = SMC_CLC_PROPOSAL;
144 pclc.hdr.length = htons(sizeof(pclc));
145 pclc.hdr.version = SMC_CLC_V1; /* SMC version */
146 memcpy(pclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
147 memcpy(&pclc.lcl.gid, &smcibdev->gid[ibport - 1], SMC_GID_SIZE);
148 memcpy(&pclc.lcl.mac, &smcibdev->mac[ibport - 1],
149 sizeof(smcibdev->mac[ibport - 1]));
150
151 /* determine subnet and mask from internal TCP socket */
152 rc = smc_netinfo_by_tcpsk(smc->clcsock, &pclc.outgoing_subnet,
153 &pclc.prefix_len);
154 if (rc)
155 return SMC_CLC_DECL_CNFERR; /* configuration error */
156 memcpy(pclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
157 memset(&msg, 0, sizeof(msg));
158 vec.iov_base = &pclc;
159 vec.iov_len = sizeof(pclc);
160 /* due to the few bytes needed for clc-handshake this cannot block */
161 len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, sizeof(pclc));
162 if (len < sizeof(pclc)) {
163 if (len >= 0) {
164 reason_code = -ENETUNREACH;
165 smc->sk.sk_err = -reason_code;
166 } else {
167 smc->sk.sk_err = smc->clcsock->sk->sk_err;
168 reason_code = -smc->sk.sk_err;
169 }
170 }
171
172 return reason_code;
173}
174
175/* send CLC CONFIRM message across internal TCP socket */
176int smc_clc_send_confirm(struct smc_sock *smc)
177{
178 struct smc_clc_msg_accept_confirm cclc;
179 int reason_code = 0;
180 struct msghdr msg;
181 struct kvec vec;
182 int len;
183
184 /* send SMC Confirm CLC msg */
185 memset(&cclc, 0, sizeof(cclc));
186 memcpy(cclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
187 cclc.hdr.type = SMC_CLC_CONFIRM;
188 cclc.hdr.length = htons(sizeof(cclc));
189 cclc.hdr.version = SMC_CLC_V1; /* SMC version */
190 memcpy(cclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
191
192 /* tbd in follow-on patch: fill in link-related values */
193
194 /* tbd in follow-on patch: fill in rmb-related values */
195
196 cclc.conn_idx = 1; /* for now: 1 RMB = 1 RMBE */
197
198 memcpy(cclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
199
200 memset(&msg, 0, sizeof(msg));
201 vec.iov_base = &cclc;
202 vec.iov_len = sizeof(cclc);
203 len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, sizeof(cclc));
204 if (len < sizeof(cclc)) {
205 if (len >= 0) {
206 reason_code = -ENETUNREACH;
207 smc->sk.sk_err = -reason_code;
208 } else {
209 smc->sk.sk_err = smc->clcsock->sk->sk_err;
210 reason_code = -smc->sk.sk_err;
211 }
212 }
213 return reason_code;
214}
215
216/* send CLC ACCEPT message across internal TCP socket */
217int smc_clc_send_accept(struct smc_sock *new_smc)
218{
219 struct smc_clc_msg_accept_confirm aclc;
220 struct msghdr msg;
221 struct kvec vec;
222 int rc = 0;
223 int len;
224
225 memset(&aclc, 0, sizeof(aclc));
226 memcpy(aclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
227 aclc.hdr.type = SMC_CLC_ACCEPT;
228 aclc.hdr.length = htons(sizeof(aclc));
229 aclc.hdr.version = SMC_CLC_V1; /* SMC version */
230 memcpy(aclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
231
232 /* tbd in follow-on patch: fill in link-related values */
233
234 /* tbd in follow-on patch: fill in rmb-related values */
235
236 aclc.conn_idx = 1; /* as long as 1 RMB = 1 RMBE */
237 memcpy(aclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
238
239 memset(&msg, 0, sizeof(msg));
240 vec.iov_base = &aclc;
241 vec.iov_len = sizeof(aclc);
242 len = kernel_sendmsg(new_smc->clcsock, &msg, &vec, 1, sizeof(aclc));
243 if (len < sizeof(aclc)) {
244 if (len >= 0)
245 new_smc->sk.sk_err = EPROTO;
246 else
247 new_smc->sk.sk_err = new_smc->clcsock->sk->sk_err;
248 rc = sock_error(&new_smc->sk);
249 }
250
251 return rc;
252}