Skip to content

Commit e7b7a64

Browse files
Ursula Braundavem330
authored andcommitted
smc: support variable CLC proposal messages
According to RFC7609 [1] the CLC proposal message contains an area of unknown length for future growth. Additionally it may contain up to 8 IPv6 prefixes. The current version of the SMC-code does not understand CLC proposal messages using these variable length fields and, thus, is incompatible with SMC implementations in other operating systems. This patch makes sure, SMC understands incoming CLC proposals * with arbitrary length values for future growth * with up to 8 IPv6 prefixes [1] SMC-R Informational RFC: http://www.rfc-editor.org/info/rfc7609 Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com> Reviewed-by: Hans Wippel <hwippel@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 6b5771a commit e7b7a64

File tree

3 files changed

+107
-24
lines changed

3 files changed

+107
-24
lines changed

net/smc/af_smc.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -751,14 +751,16 @@ static void smc_listen_work(struct work_struct *work)
751751
{
752752
struct smc_sock *new_smc = container_of(work, struct smc_sock,
753753
smc_listen_work);
754+
struct smc_clc_msg_proposal_prefix *pclc_prfx;
754755
struct socket *newclcsock = new_smc->clcsock;
755756
struct smc_sock *lsmc = new_smc->listen_smc;
756757
struct smc_clc_msg_accept_confirm cclc;
757758
int local_contact = SMC_REUSE_CONTACT;
758759
struct sock *newsmcsk = &new_smc->sk;
759-
struct smc_clc_msg_proposal pclc;
760+
struct smc_clc_msg_proposal *pclc;
760761
struct smc_ib_device *smcibdev;
761762
struct sockaddr_in peeraddr;
763+
u8 buf[SMC_CLC_MAX_LEN];
762764
struct smc_link *link;
763765
int reason_code = 0;
764766
int rc = 0, len;
@@ -775,7 +777,7 @@ static void smc_listen_work(struct work_struct *work)
775777
/* do inband token exchange -
776778
*wait for and receive SMC Proposal CLC message
777779
*/
778-
reason_code = smc_clc_wait_msg(new_smc, &pclc, sizeof(pclc),
780+
reason_code = smc_clc_wait_msg(new_smc, &buf, sizeof(buf),
779781
SMC_CLC_PROPOSAL);
780782
if (reason_code < 0)
781783
goto out_err;
@@ -804,8 +806,11 @@ static void smc_listen_work(struct work_struct *work)
804806
reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */
805807
goto decline_rdma;
806808
}
807-
if ((pclc.outgoing_subnet != subnet) ||
808-
(pclc.prefix_len != prefix_len)) {
809+
810+
pclc = (struct smc_clc_msg_proposal *)&buf;
811+
pclc_prfx = smc_clc_proposal_get_prefix(pclc);
812+
if (pclc_prfx->outgoing_subnet != subnet ||
813+
pclc_prfx->prefix_len != prefix_len) {
809814
reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */
810815
goto decline_rdma;
811816
}
@@ -816,7 +821,7 @@ static void smc_listen_work(struct work_struct *work)
816821
/* allocate connection / link group */
817822
mutex_lock(&smc_create_lgr_pending);
818823
local_contact = smc_conn_create(new_smc, peeraddr.sin_addr.s_addr,
819-
smcibdev, ibport, &pclc.lcl, 0);
824+
smcibdev, ibport, &pclc->lcl, 0);
820825
if (local_contact < 0) {
821826
rc = local_contact;
822827
if (rc == -ENOMEM)

net/smc/smc_clc.c

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,54 @@
2222
#include "smc_clc.h"
2323
#include "smc_ib.h"
2424

25+
/* check if received message has a correct header length and contains valid
26+
* heading and trailing eyecatchers
27+
*/
28+
static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm)
29+
{
30+
struct smc_clc_msg_proposal_prefix *pclc_prfx;
31+
struct smc_clc_msg_accept_confirm *clc;
32+
struct smc_clc_msg_proposal *pclc;
33+
struct smc_clc_msg_decline *dclc;
34+
struct smc_clc_msg_trail *trl;
35+
36+
if (memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)))
37+
return false;
38+
switch (clcm->type) {
39+
case SMC_CLC_PROPOSAL:
40+
pclc = (struct smc_clc_msg_proposal *)clcm;
41+
pclc_prfx = smc_clc_proposal_get_prefix(pclc);
42+
if (ntohs(pclc->hdr.length) !=
43+
sizeof(*pclc) + ntohs(pclc->iparea_offset) +
44+
sizeof(*pclc_prfx) +
45+
pclc_prfx->ipv6_prefixes_cnt *
46+
sizeof(struct smc_clc_ipv6_prefix) +
47+
sizeof(*trl))
48+
return false;
49+
trl = (struct smc_clc_msg_trail *)
50+
((u8 *)pclc + ntohs(pclc->hdr.length) - sizeof(*trl));
51+
break;
52+
case SMC_CLC_ACCEPT:
53+
case SMC_CLC_CONFIRM:
54+
clc = (struct smc_clc_msg_accept_confirm *)clcm;
55+
if (ntohs(clc->hdr.length) != sizeof(*clc))
56+
return false;
57+
trl = &clc->trl;
58+
break;
59+
case SMC_CLC_DECLINE:
60+
dclc = (struct smc_clc_msg_decline *)clcm;
61+
if (ntohs(dclc->hdr.length) != sizeof(*dclc))
62+
return false;
63+
trl = &dclc->trl;
64+
break;
65+
default:
66+
return false;
67+
}
68+
if (memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)))
69+
return false;
70+
return true;
71+
}
72+
2573
/* Wait for data on the tcp-socket, analyze received data
2674
* Returns:
2775
* 0 if success and it was not a decline that we received.
@@ -72,9 +120,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
72120
}
73121
datlen = ntohs(clcm->length);
74122
if ((len < sizeof(struct smc_clc_msg_hdr)) ||
75-
(datlen < sizeof(struct smc_clc_msg_decline)) ||
76-
(datlen > sizeof(struct smc_clc_msg_accept_confirm)) ||
77-
memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) ||
123+
(datlen > buflen) ||
78124
((clcm->type != SMC_CLC_DECLINE) &&
79125
(clcm->type != expected_type))) {
80126
smc->sk.sk_err = EPROTO;
@@ -89,7 +135,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
89135
krflags = MSG_WAITALL;
90136
smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME;
91137
len = kernel_recvmsg(smc->clcsock, &msg, &vec, 1, datlen, krflags);
92-
if (len < datlen) {
138+
if (len < datlen || !smc_clc_msg_hdr_valid(clcm)) {
93139
smc->sk.sk_err = EPROTO;
94140
reason_code = -EPROTO;
95141
goto out;
@@ -141,33 +187,43 @@ int smc_clc_send_proposal(struct smc_sock *smc,
141187
struct smc_ib_device *smcibdev,
142188
u8 ibport)
143189
{
190+
struct smc_clc_msg_proposal_prefix pclc_prfx;
144191
struct smc_clc_msg_proposal pclc;
192+
struct smc_clc_msg_trail trl;
145193
int reason_code = 0;
194+
struct kvec vec[3];
146195
struct msghdr msg;
147-
struct kvec vec;
148-
int len, rc;
196+
int len, plen, rc;
149197

150198
/* send SMC Proposal CLC message */
199+
plen = sizeof(pclc) + sizeof(pclc_prfx) + sizeof(trl);
151200
memset(&pclc, 0, sizeof(pclc));
152201
memcpy(pclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
153202
pclc.hdr.type = SMC_CLC_PROPOSAL;
154-
pclc.hdr.length = htons(sizeof(pclc));
203+
pclc.hdr.length = htons(plen);
155204
pclc.hdr.version = SMC_CLC_V1; /* SMC version */
156205
memcpy(pclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
157206
memcpy(&pclc.lcl.gid, &smcibdev->gid[ibport - 1], SMC_GID_SIZE);
158207
memcpy(&pclc.lcl.mac, &smcibdev->mac[ibport - 1], ETH_ALEN);
208+
pclc.iparea_offset = htons(0);
159209

210+
memset(&pclc_prfx, 0, sizeof(pclc_prfx));
160211
/* determine subnet and mask from internal TCP socket */
161-
rc = smc_netinfo_by_tcpsk(smc->clcsock, &pclc.outgoing_subnet,
162-
&pclc.prefix_len);
212+
rc = smc_netinfo_by_tcpsk(smc->clcsock, &pclc_prfx.outgoing_subnet,
213+
&pclc_prfx.prefix_len);
163214
if (rc)
164215
return SMC_CLC_DECL_CNFERR; /* configuration error */
165-
memcpy(pclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
216+
pclc_prfx.ipv6_prefixes_cnt = 0;
217+
memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
166218
memset(&msg, 0, sizeof(msg));
167-
vec.iov_base = &pclc;
168-
vec.iov_len = sizeof(pclc);
219+
vec[0].iov_base = &pclc;
220+
vec[0].iov_len = sizeof(pclc);
221+
vec[1].iov_base = &pclc_prfx;
222+
vec[1].iov_len = sizeof(pclc_prfx);
223+
vec[2].iov_base = &trl;
224+
vec[2].iov_len = sizeof(trl);
169225
/* due to the few bytes needed for clc-handshake this cannot block */
170-
len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, sizeof(pclc));
226+
len = kernel_sendmsg(smc->clcsock, &msg, vec, 3, plen);
171227
if (len < sizeof(pclc)) {
172228
if (len >= 0) {
173229
reason_code = -ENETUNREACH;

net/smc/smc_clc.h

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct smc_clc_msg_hdr { /* header1 of clc messages */
4444
#if defined(__BIG_ENDIAN_BITFIELD)
4545
u8 version : 4,
4646
flag : 1,
47-
rsvd : 3;
47+
rsvd : 3;
4848
#elif defined(__LITTLE_ENDIAN_BITFIELD)
4949
u8 rsvd : 3,
5050
flag : 1,
@@ -62,17 +62,31 @@ struct smc_clc_msg_local { /* header2 of clc messages */
6262
u8 mac[6]; /* mac of ib_device port */
6363
};
6464

65-
struct smc_clc_msg_proposal { /* clc proposal message */
66-
struct smc_clc_msg_hdr hdr;
67-
struct smc_clc_msg_local lcl;
68-
__be16 iparea_offset; /* offset to IP address information area */
65+
struct smc_clc_ipv6_prefix {
66+
u8 prefix[4];
67+
u8 prefix_len;
68+
} __packed;
69+
70+
struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/
6971
__be32 outgoing_subnet; /* subnet mask */
7072
u8 prefix_len; /* number of significant bits in mask */
7173
u8 reserved[2];
7274
u8 ipv6_prefixes_cnt; /* number of IPv6 prefixes in prefix array */
73-
struct smc_clc_msg_trail trl; /* eye catcher "SMCR" EBCDIC */
7475
} __aligned(4);
7576

77+
struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */
78+
struct smc_clc_msg_hdr hdr;
79+
struct smc_clc_msg_local lcl;
80+
__be16 iparea_offset; /* offset to IP address information area */
81+
} __aligned(4);
82+
83+
#define SMC_CLC_PROPOSAL_MAX_OFFSET 0x28
84+
#define SMC_CLC_PROPOSAL_MAX_PREFIX (8 * sizeof(struct smc_clc_ipv6_prefix))
85+
#define SMC_CLC_MAX_LEN (sizeof(struct smc_clc_msg_proposal) + \
86+
SMC_CLC_PROPOSAL_MAX_OFFSET + \
87+
SMC_CLC_PROPOSAL_MAX_PREFIX + \
88+
sizeof(struct smc_clc_msg_trail))
89+
7690
struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */
7791
struct smc_clc_msg_hdr hdr;
7892
struct smc_clc_msg_local lcl;
@@ -102,6 +116,14 @@ struct smc_clc_msg_decline { /* clc decline message */
102116
struct smc_clc_msg_trail trl; /* eye catcher "SMCR" EBCDIC */
103117
} __aligned(4);
104118

119+
/* determine start of the prefix area within the proposal message */
120+
static inline struct smc_clc_msg_proposal_prefix *
121+
smc_clc_proposal_get_prefix(struct smc_clc_msg_proposal *pclc)
122+
{
123+
return (struct smc_clc_msg_proposal_prefix *)
124+
((u8 *)pclc + sizeof(*pclc) + ntohs(pclc->iparea_offset));
125+
}
126+
105127
struct smc_sock;
106128
struct smc_ib_device;
107129

0 commit comments

Comments
 (0)