Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ursula Braun and committed by
David S. Miller
e7b7a64a 6b5771aa

+107 -24
+10 -5
net/smc/af_smc.c
··· 751 751 { 752 752 struct smc_sock *new_smc = container_of(work, struct smc_sock, 753 753 smc_listen_work); 754 + struct smc_clc_msg_proposal_prefix *pclc_prfx; 754 755 struct socket *newclcsock = new_smc->clcsock; 755 756 struct smc_sock *lsmc = new_smc->listen_smc; 756 757 struct smc_clc_msg_accept_confirm cclc; 757 758 int local_contact = SMC_REUSE_CONTACT; 758 759 struct sock *newsmcsk = &new_smc->sk; 759 - struct smc_clc_msg_proposal pclc; 760 + struct smc_clc_msg_proposal *pclc; 760 761 struct smc_ib_device *smcibdev; 761 762 struct sockaddr_in peeraddr; 763 + u8 buf[SMC_CLC_MAX_LEN]; 762 764 struct smc_link *link; 763 765 int reason_code = 0; 764 766 int rc = 0, len; ··· 777 775 /* do inband token exchange - 778 776 *wait for and receive SMC Proposal CLC message 779 777 */ 780 - reason_code = smc_clc_wait_msg(new_smc, &pclc, sizeof(pclc), 778 + reason_code = smc_clc_wait_msg(new_smc, &buf, sizeof(buf), 781 779 SMC_CLC_PROPOSAL); 782 780 if (reason_code < 0) 783 781 goto out_err; ··· 806 804 reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */ 807 805 goto decline_rdma; 808 806 } 809 - if ((pclc.outgoing_subnet != subnet) || 810 - (pclc.prefix_len != prefix_len)) { 807 + 808 + pclc = (struct smc_clc_msg_proposal *)&buf; 809 + pclc_prfx = smc_clc_proposal_get_prefix(pclc); 810 + if (pclc_prfx->outgoing_subnet != subnet || 811 + pclc_prfx->prefix_len != prefix_len) { 811 812 reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */ 812 813 goto decline_rdma; 813 814 } ··· 821 816 /* allocate connection / link group */ 822 817 mutex_lock(&smc_create_lgr_pending); 823 818 local_contact = smc_conn_create(new_smc, peeraddr.sin_addr.s_addr, 824 - smcibdev, ibport, &pclc.lcl, 0); 819 + smcibdev, ibport, &pclc->lcl, 0); 825 820 if (local_contact < 0) { 826 821 rc = local_contact; 827 822 if (rc == -ENOMEM)
+69 -13
net/smc/smc_clc.c
··· 22 22 #include "smc_clc.h" 23 23 #include "smc_ib.h" 24 24 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 + 25 73 /* Wait for data on the tcp-socket, analyze received data 26 74 * Returns: 27 75 * 0 if success and it was not a decline that we received. ··· 120 72 } 121 73 datlen = ntohs(clcm->length); 122 74 if ((len < sizeof(struct smc_clc_msg_hdr)) || 123 - (datlen < sizeof(struct smc_clc_msg_decline)) || 124 - (datlen > sizeof(struct smc_clc_msg_accept_confirm)) || 125 - memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) || 75 + (datlen > buflen) || 126 76 ((clcm->type != SMC_CLC_DECLINE) && 127 77 (clcm->type != expected_type))) { 128 78 smc->sk.sk_err = EPROTO; ··· 135 89 krflags = MSG_WAITALL; 136 90 smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME; 137 91 len = kernel_recvmsg(smc->clcsock, &msg, &vec, 1, datlen, krflags); 138 - if (len < datlen) { 92 + if (len < datlen || !smc_clc_msg_hdr_valid(clcm)) { 139 93 smc->sk.sk_err = EPROTO; 140 94 reason_code = -EPROTO; 141 95 goto out; ··· 187 141 struct smc_ib_device *smcibdev, 188 142 u8 ibport) 189 143 { 144 + struct smc_clc_msg_proposal_prefix pclc_prfx; 190 145 struct smc_clc_msg_proposal pclc; 146 + struct smc_clc_msg_trail trl; 191 147 int reason_code = 0; 148 + struct kvec vec[3]; 192 149 struct msghdr msg; 193 - struct kvec vec; 194 - int len, rc; 150 + int len, plen, rc; 195 151 196 152 /* send SMC Proposal CLC message */ 153 + plen = sizeof(pclc) + sizeof(pclc_prfx) + sizeof(trl); 197 154 memset(&pclc, 0, sizeof(pclc)); 198 155 memcpy(pclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); 199 156 pclc.hdr.type = SMC_CLC_PROPOSAL; 200 - pclc.hdr.length = htons(sizeof(pclc)); 157 + pclc.hdr.length = htons(plen); 201 158 pclc.hdr.version = SMC_CLC_V1; /* SMC version */ 202 159 memcpy(pclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid)); 203 160 memcpy(&pclc.lcl.gid, &smcibdev->gid[ibport - 1], SMC_GID_SIZE); 204 161 memcpy(&pclc.lcl.mac, &smcibdev->mac[ibport - 1], ETH_ALEN); 162 + pclc.iparea_offset = htons(0); 205 163 164 + memset(&pclc_prfx, 0, sizeof(pclc_prfx)); 206 165 /* determine subnet and mask from internal TCP socket */ 207 - rc = smc_netinfo_by_tcpsk(smc->clcsock, &pclc.outgoing_subnet, 208 - &pclc.prefix_len); 166 + rc = smc_netinfo_by_tcpsk(smc->clcsock, &pclc_prfx.outgoing_subnet, 167 + &pclc_prfx.prefix_len); 209 168 if (rc) 210 169 return SMC_CLC_DECL_CNFERR; /* configuration error */ 211 - memcpy(pclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); 170 + pclc_prfx.ipv6_prefixes_cnt = 0; 171 + memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); 212 172 memset(&msg, 0, sizeof(msg)); 213 - vec.iov_base = &pclc; 214 - vec.iov_len = sizeof(pclc); 173 + vec[0].iov_base = &pclc; 174 + vec[0].iov_len = sizeof(pclc); 175 + vec[1].iov_base = &pclc_prfx; 176 + vec[1].iov_len = sizeof(pclc_prfx); 177 + vec[2].iov_base = &trl; 178 + vec[2].iov_len = sizeof(trl); 215 179 /* due to the few bytes needed for clc-handshake this cannot block */ 216 - len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, sizeof(pclc)); 180 + len = kernel_sendmsg(smc->clcsock, &msg, vec, 3, plen); 217 181 if (len < sizeof(pclc)) { 218 182 if (len >= 0) { 219 183 reason_code = -ENETUNREACH;
+28 -6
net/smc/smc_clc.h
··· 44 44 #if defined(__BIG_ENDIAN_BITFIELD) 45 45 u8 version : 4, 46 46 flag : 1, 47 - rsvd : 3; 47 + rsvd : 3; 48 48 #elif defined(__LITTLE_ENDIAN_BITFIELD) 49 49 u8 rsvd : 3, 50 50 flag : 1, ··· 62 62 u8 mac[6]; /* mac of ib_device port */ 63 63 }; 64 64 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*/ 69 71 __be32 outgoing_subnet; /* subnet mask */ 70 72 u8 prefix_len; /* number of significant bits in mask */ 71 73 u8 reserved[2]; 72 74 u8 ipv6_prefixes_cnt; /* number of IPv6 prefixes in prefix array */ 73 - struct smc_clc_msg_trail trl; /* eye catcher "SMCR" EBCDIC */ 74 75 } __aligned(4); 76 + 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)) 75 89 76 90 struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */ 77 91 struct smc_clc_msg_hdr hdr; ··· 115 101 u8 reserved2[4]; 116 102 struct smc_clc_msg_trail trl; /* eye catcher "SMCR" EBCDIC */ 117 103 } __aligned(4); 104 + 105 + /* determine start of the prefix area within the proposal message */ 106 + static inline struct smc_clc_msg_proposal_prefix * 107 + smc_clc_proposal_get_prefix(struct smc_clc_msg_proposal *pclc) 108 + { 109 + return (struct smc_clc_msg_proposal_prefix *) 110 + ((u8 *)pclc + sizeof(*pclc) + ntohs(pclc->iparea_offset)); 111 + } 118 112 119 113 struct smc_sock; 120 114 struct smc_ib_device;