2 * Shared Memory Communications over RDMA (SMC-R) and RoCE
4 * CLC (connection layer control) handshake over initial TCP socket to
5 * prepare for RDMA traffic
7 * Copyright IBM Corp. 2016
9 * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com>
20 /* Wait for data on the tcp-socket, analyze received data
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.
26 int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
29 struct sock *clc_sk = smc->clcsock->sk;
30 struct smc_clc_msg_hdr *clcm = buf;
31 struct msghdr msg = {NULL, 0};
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
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)) {
49 clc_sk->sk_err = EINTR;
50 smc->sk.sk_err = EINTR;
54 reason_code = -clc_sk->sk_err;
55 smc->sk.sk_err = clc_sk->sk_err;
58 if (!len) { /* peer has performed orderly shutdown */
59 smc->sk.sk_err = ECONNRESET;
60 reason_code = -ECONNRESET;
64 smc->sk.sk_err = -len;
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;
80 /* receive the complete CLC message */
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);
88 smc->sk.sk_err = EPROTO;
89 reason_code = -EPROTO;
92 if (clcm->type == SMC_CLC_DECLINE)
93 reason_code = SMC_CLC_DECL_REPLY;
98 /* send CLC DECLINE message across internal TCP socket */
99 int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info,
102 struct smc_clc_msg_decline dclc;
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));
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;
125 smc->sk.sk_err = -len;
129 /* send CLC PROPOSAL message across internal TCP socket */
130 int smc_clc_send_proposal(struct smc_sock *smc,
131 struct smc_ib_device *smcibdev,
134 struct smc_clc_msg_proposal pclc;
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]));
151 /* determine subnet and mask from internal TCP socket */
152 rc = smc_netinfo_by_tcpsk(smc->clcsock, &pclc.outgoing_subnet,
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)) {
164 reason_code = -ENETUNREACH;
165 smc->sk.sk_err = -reason_code;
167 smc->sk.sk_err = smc->clcsock->sk->sk_err;
168 reason_code = -smc->sk.sk_err;
175 /* send CLC CONFIRM message across internal TCP socket */
176 int smc_clc_send_confirm(struct smc_sock *smc)
178 struct smc_clc_msg_accept_confirm cclc;
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));
192 /* tbd in follow-on patch: fill in link-related values */
194 /* tbd in follow-on patch: fill in rmb-related values */
196 cclc.conn_idx = 1; /* for now: 1 RMB = 1 RMBE */
198 memcpy(cclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
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)) {
206 reason_code = -ENETUNREACH;
207 smc->sk.sk_err = -reason_code;
209 smc->sk.sk_err = smc->clcsock->sk->sk_err;
210 reason_code = -smc->sk.sk_err;
216 /* send CLC ACCEPT message across internal TCP socket */
217 int smc_clc_send_accept(struct smc_sock *new_smc)
219 struct smc_clc_msg_accept_confirm aclc;
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));
232 /* tbd in follow-on patch: fill in link-related values */
234 /* tbd in follow-on patch: fill in rmb-related values */
236 aclc.conn_idx = 1; /* as long as 1 RMB = 1 RMBE */
237 memcpy(aclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
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)) {
245 new_smc->sk.sk_err = EPROTO;
247 new_smc->sk.sk_err = new_smc->clcsock->sk->sk_err;
248 rc = sock_error(&new_smc->sk);