Commit e5c4744c authored by Karsten Graul's avatar Karsten Graul Committed by David S. Miller

net/smc: add SMC-Rv2 connection establishment

Send a CLC proposal message, and the remote side process this type of
message and determine the target GID. Check for a valid route to this
GID, and complete the connection establishment.
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 42042dbb
...@@ -439,6 +439,47 @@ static int smcr_clnt_conf_first_link(struct smc_sock *smc) ...@@ -439,6 +439,47 @@ static int smcr_clnt_conf_first_link(struct smc_sock *smc)
return 0; return 0;
} }
static bool smc_isascii(char *hostname)
{
int i;
for (i = 0; i < SMC_MAX_HOSTNAME_LEN; i++)
if (!isascii(hostname[i]))
return false;
return true;
}
static void smc_conn_save_peer_info_fce(struct smc_sock *smc,
struct smc_clc_msg_accept_confirm *clc)
{
struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
(struct smc_clc_msg_accept_confirm_v2 *)clc;
struct smc_clc_first_contact_ext *fce;
int clc_v2_len;
if (clc->hdr.version == SMC_V1 ||
!(clc->hdr.typev2 & SMC_FIRST_CONTACT_MASK))
return;
if (smc->conn.lgr->is_smcd) {
memcpy(smc->conn.lgr->negotiated_eid, clc_v2->d1.eid,
SMC_MAX_EID_LEN);
clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm_v2,
d1);
} else {
memcpy(smc->conn.lgr->negotiated_eid, clc_v2->r1.eid,
SMC_MAX_EID_LEN);
clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm_v2,
r1);
}
fce = (struct smc_clc_first_contact_ext *)(((u8 *)clc_v2) + clc_v2_len);
smc->conn.lgr->peer_os = fce->os_type;
smc->conn.lgr->peer_smc_release = fce->release;
if (smc_isascii(fce->hostname))
memcpy(smc->conn.lgr->peer_hostname, fce->hostname,
SMC_MAX_HOSTNAME_LEN);
}
static void smcr_conn_save_peer_info(struct smc_sock *smc, static void smcr_conn_save_peer_info(struct smc_sock *smc,
struct smc_clc_msg_accept_confirm *clc) struct smc_clc_msg_accept_confirm *clc)
{ {
...@@ -451,16 +492,6 @@ static void smcr_conn_save_peer_info(struct smc_sock *smc, ...@@ -451,16 +492,6 @@ static void smcr_conn_save_peer_info(struct smc_sock *smc,
smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1); smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1);
} }
static bool smc_isascii(char *hostname)
{
int i;
for (i = 0; i < SMC_MAX_HOSTNAME_LEN; i++)
if (!isascii(hostname[i]))
return false;
return true;
}
static void smcd_conn_save_peer_info(struct smc_sock *smc, static void smcd_conn_save_peer_info(struct smc_sock *smc,
struct smc_clc_msg_accept_confirm *clc) struct smc_clc_msg_accept_confirm *clc)
{ {
...@@ -472,22 +503,6 @@ static void smcd_conn_save_peer_info(struct smc_sock *smc, ...@@ -472,22 +503,6 @@ static void smcd_conn_save_peer_info(struct smc_sock *smc,
smc->conn.peer_rmbe_size = bufsize - sizeof(struct smcd_cdc_msg); smc->conn.peer_rmbe_size = bufsize - sizeof(struct smcd_cdc_msg);
atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size); atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size);
smc->conn.tx_off = bufsize * smc->conn.peer_rmbe_idx; smc->conn.tx_off = bufsize * smc->conn.peer_rmbe_idx;
if (clc->hdr.version > SMC_V1 &&
(clc->hdr.typev2 & SMC_FIRST_CONTACT_MASK)) {
struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
(struct smc_clc_msg_accept_confirm_v2 *)clc;
struct smc_clc_first_contact_ext *fce =
(struct smc_clc_first_contact_ext *)
(((u8 *)clc_v2) + sizeof(*clc_v2));
memcpy(smc->conn.lgr->negotiated_eid, clc_v2->eid,
SMC_MAX_EID_LEN);
smc->conn.lgr->peer_os = fce->os_type;
smc->conn.lgr->peer_smc_release = fce->release;
if (smc_isascii(fce->hostname))
memcpy(smc->conn.lgr->peer_hostname, fce->hostname,
SMC_MAX_HOSTNAME_LEN);
}
} }
static void smc_conn_save_peer_info(struct smc_sock *smc, static void smc_conn_save_peer_info(struct smc_sock *smc,
...@@ -497,14 +512,16 @@ static void smc_conn_save_peer_info(struct smc_sock *smc, ...@@ -497,14 +512,16 @@ static void smc_conn_save_peer_info(struct smc_sock *smc,
smcd_conn_save_peer_info(smc, clc); smcd_conn_save_peer_info(smc, clc);
else else
smcr_conn_save_peer_info(smc, clc); smcr_conn_save_peer_info(smc, clc);
smc_conn_save_peer_info_fce(smc, clc);
} }
static void smc_link_save_peer_info(struct smc_link *link, static void smc_link_save_peer_info(struct smc_link *link,
struct smc_clc_msg_accept_confirm *clc) struct smc_clc_msg_accept_confirm *clc,
struct smc_init_info *ini)
{ {
link->peer_qpn = ntoh24(clc->r0.qpn); link->peer_qpn = ntoh24(clc->r0.qpn);
memcpy(link->peer_gid, clc->r0.lcl.gid, SMC_GID_SIZE); memcpy(link->peer_gid, ini->peer_gid, SMC_GID_SIZE);
memcpy(link->peer_mac, clc->r0.lcl.mac, sizeof(link->peer_mac)); memcpy(link->peer_mac, ini->peer_mac, sizeof(link->peer_mac));
link->peer_psn = ntoh24(clc->r0.psn); link->peer_psn = ntoh24(clc->r0.psn);
link->peer_mtu = clc->r0.qp_mtu; link->peer_mtu = clc->r0.qp_mtu;
} }
...@@ -769,6 +786,64 @@ static int smc_connect_clc(struct smc_sock *smc, ...@@ -769,6 +786,64 @@ static int smc_connect_clc(struct smc_sock *smc,
SMC_CLC_ACCEPT, CLC_WAIT_TIME); SMC_CLC_ACCEPT, CLC_WAIT_TIME);
} }
static void smc_fill_gid_list(struct smc_link_group *lgr,
struct smc_gidlist *gidlist,
struct smc_ib_device *known_dev, u8 *known_gid)
{
struct smc_init_info *alt_ini = NULL;
memset(gidlist, 0, sizeof(*gidlist));
memcpy(gidlist->list[gidlist->len++], known_gid, SMC_GID_SIZE);
alt_ini = kzalloc(sizeof(*alt_ini), GFP_KERNEL);
if (!alt_ini)
goto out;
alt_ini->vlan_id = lgr->vlan_id;
alt_ini->check_smcrv2 = true;
alt_ini->smcrv2.saddr = lgr->saddr;
smc_pnet_find_alt_roce(lgr, alt_ini, known_dev);
if (!alt_ini->smcrv2.ib_dev_v2)
goto out;
memcpy(gidlist->list[gidlist->len++], alt_ini->smcrv2.ib_gid_v2,
SMC_GID_SIZE);
out:
kfree(alt_ini);
}
static int smc_connect_rdma_v2_prepare(struct smc_sock *smc,
struct smc_clc_msg_accept_confirm *aclc,
struct smc_init_info *ini)
{
struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
(struct smc_clc_msg_accept_confirm_v2 *)aclc;
struct smc_clc_first_contact_ext *fce =
(struct smc_clc_first_contact_ext *)
(((u8 *)clc_v2) + sizeof(*clc_v2));
if (!ini->first_contact_peer || aclc->hdr.version == SMC_V1)
return 0;
if (fce->v2_direct) {
memcpy(ini->smcrv2.nexthop_mac, &aclc->r0.lcl.mac, ETH_ALEN);
ini->smcrv2.uses_gateway = false;
} else {
if (smc_ib_find_route(smc->clcsock->sk->sk_rcv_saddr,
smc_ib_gid_to_ipv4(aclc->r0.lcl.gid),
ini->smcrv2.nexthop_mac,
&ini->smcrv2.uses_gateway))
return SMC_CLC_DECL_NOROUTE;
if (!ini->smcrv2.uses_gateway) {
/* mismatch: peer claims indirect, but its direct */
return SMC_CLC_DECL_NOINDIRECT;
}
}
return 0;
}
/* setup for RDMA connection of client */ /* setup for RDMA connection of client */
static int smc_connect_rdma(struct smc_sock *smc, static int smc_connect_rdma(struct smc_sock *smc,
struct smc_clc_msg_accept_confirm *aclc, struct smc_clc_msg_accept_confirm *aclc,
...@@ -776,11 +851,18 @@ static int smc_connect_rdma(struct smc_sock *smc, ...@@ -776,11 +851,18 @@ static int smc_connect_rdma(struct smc_sock *smc,
{ {
int i, reason_code = 0; int i, reason_code = 0;
struct smc_link *link; struct smc_link *link;
u8 *eid = NULL;
ini->is_smcd = false; ini->is_smcd = false;
ini->ib_lcl = &aclc->r0.lcl;
ini->ib_clcqpn = ntoh24(aclc->r0.qpn); ini->ib_clcqpn = ntoh24(aclc->r0.qpn);
ini->first_contact_peer = aclc->hdr.typev2 & SMC_FIRST_CONTACT_MASK; ini->first_contact_peer = aclc->hdr.typev2 & SMC_FIRST_CONTACT_MASK;
memcpy(ini->peer_systemid, aclc->r0.lcl.id_for_peer, SMC_SYSTEMID_LEN);
memcpy(ini->peer_gid, aclc->r0.lcl.gid, SMC_GID_SIZE);
memcpy(ini->peer_mac, aclc->r0.lcl.mac, ETH_ALEN);
reason_code = smc_connect_rdma_v2_prepare(smc, aclc, ini);
if (reason_code)
return reason_code;
mutex_lock(&smc_client_lgr_pending); mutex_lock(&smc_client_lgr_pending);
reason_code = smc_conn_create(smc, ini); reason_code = smc_conn_create(smc, ini);
...@@ -802,8 +884,9 @@ static int smc_connect_rdma(struct smc_sock *smc, ...@@ -802,8 +884,9 @@ static int smc_connect_rdma(struct smc_sock *smc,
if (l->peer_qpn == ntoh24(aclc->r0.qpn) && if (l->peer_qpn == ntoh24(aclc->r0.qpn) &&
!memcmp(l->peer_gid, &aclc->r0.lcl.gid, !memcmp(l->peer_gid, &aclc->r0.lcl.gid,
SMC_GID_SIZE) && SMC_GID_SIZE) &&
!memcmp(l->peer_mac, &aclc->r0.lcl.mac, (aclc->hdr.version > SMC_V1 ||
sizeof(l->peer_mac))) { !memcmp(l->peer_mac, &aclc->r0.lcl.mac,
sizeof(l->peer_mac)))) {
link = l; link = l;
break; break;
} }
...@@ -822,7 +905,7 @@ static int smc_connect_rdma(struct smc_sock *smc, ...@@ -822,7 +905,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
} }
if (ini->first_contact_local) if (ini->first_contact_local)
smc_link_save_peer_info(link, aclc); smc_link_save_peer_info(link, aclc, ini);
if (smc_rmb_rtoken_handling(&smc->conn, link, aclc)) { if (smc_rmb_rtoken_handling(&smc->conn, link, aclc)) {
reason_code = SMC_CLC_DECL_ERR_RTOK; reason_code = SMC_CLC_DECL_ERR_RTOK;
...@@ -845,8 +928,18 @@ static int smc_connect_rdma(struct smc_sock *smc, ...@@ -845,8 +928,18 @@ static int smc_connect_rdma(struct smc_sock *smc,
} }
smc_rmb_sync_sg_for_device(&smc->conn); smc_rmb_sync_sg_for_device(&smc->conn);
if (aclc->hdr.version > SMC_V1) {
struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
(struct smc_clc_msg_accept_confirm_v2 *)aclc;
eid = clc_v2->r1.eid;
if (ini->first_contact_local)
smc_fill_gid_list(link->lgr, &ini->smcrv2.gidlist,
link->smcibdev, link->gid);
}
reason_code = smc_clc_send_confirm(smc, ini->first_contact_local, reason_code = smc_clc_send_confirm(smc, ini->first_contact_local,
SMC_V1, NULL); aclc->hdr.version, eid, ini);
if (reason_code) if (reason_code)
goto connect_abort; goto connect_abort;
...@@ -886,7 +979,7 @@ smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm_v2 *aclc, ...@@ -886,7 +979,7 @@ smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm_v2 *aclc,
int i; int i;
for (i = 0; i < ini->ism_offered_cnt + 1; i++) { for (i = 0; i < ini->ism_offered_cnt + 1; i++) {
if (ini->ism_chid[i] == ntohs(aclc->chid)) { if (ini->ism_chid[i] == ntohs(aclc->d1.chid)) {
ini->ism_selected = i; ini->ism_selected = i;
return 0; return 0;
} }
...@@ -940,11 +1033,11 @@ static int smc_connect_ism(struct smc_sock *smc, ...@@ -940,11 +1033,11 @@ static int smc_connect_ism(struct smc_sock *smc,
struct smc_clc_msg_accept_confirm_v2 *clc_v2 = struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
(struct smc_clc_msg_accept_confirm_v2 *)aclc; (struct smc_clc_msg_accept_confirm_v2 *)aclc;
eid = clc_v2->eid; eid = clc_v2->d1.eid;
} }
rc = smc_clc_send_confirm(smc, ini->first_contact_local, rc = smc_clc_send_confirm(smc, ini->first_contact_local,
aclc->hdr.version, eid); aclc->hdr.version, eid, NULL);
if (rc) if (rc)
goto connect_abort; goto connect_abort;
mutex_unlock(&smc_server_lgr_pending); mutex_unlock(&smc_server_lgr_pending);
...@@ -1735,7 +1828,7 @@ static int smc_listen_rdma_finish(struct smc_sock *new_smc, ...@@ -1735,7 +1828,7 @@ static int smc_listen_rdma_finish(struct smc_sock *new_smc,
int reason_code = 0; int reason_code = 0;
if (local_first) if (local_first)
smc_link_save_peer_info(link, cclc); smc_link_save_peer_info(link, cclc, NULL);
if (smc_rmb_rtoken_handling(&new_smc->conn, link, cclc)) if (smc_rmb_rtoken_handling(&new_smc->conn, link, cclc))
return SMC_CLC_DECL_ERR_RTOK; return SMC_CLC_DECL_ERR_RTOK;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define SMCR_CLC_ACCEPT_CONFIRM_LEN 68 #define SMCR_CLC_ACCEPT_CONFIRM_LEN 68
#define SMCD_CLC_ACCEPT_CONFIRM_LEN 48 #define SMCD_CLC_ACCEPT_CONFIRM_LEN 48
#define SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 78 #define SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 78
#define SMCR_CLC_ACCEPT_CONFIRM_LEN_V2 108
#define SMC_CLC_RECV_BUF_LEN 100 #define SMC_CLC_RECV_BUF_LEN 100
/* eye catcher "SMCR" EBCDIC for CLC messages */ /* eye catcher "SMCR" EBCDIC for CLC messages */
...@@ -309,7 +310,8 @@ bool smc_clc_match_eid(u8 *negotiated_eid, ...@@ -309,7 +310,8 @@ bool smc_clc_match_eid(u8 *negotiated_eid,
negotiated_eid[0] = 0; negotiated_eid[0] = 0;
read_lock(&smc_clc_eid_table.lock); read_lock(&smc_clc_eid_table.lock);
if (smc_clc_eid_table.seid_enabled && if (peer_eid && local_eid &&
smc_clc_eid_table.seid_enabled &&
smc_v2_ext->hdr.flag.seid && smc_v2_ext->hdr.flag.seid &&
!memcmp(peer_eid, local_eid, SMC_MAX_EID_LEN)) { !memcmp(peer_eid, local_eid, SMC_MAX_EID_LEN)) {
memcpy(negotiated_eid, peer_eid, SMC_MAX_EID_LEN); memcpy(negotiated_eid, peer_eid, SMC_MAX_EID_LEN);
...@@ -391,6 +393,9 @@ smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2) ...@@ -391,6 +393,9 @@ smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2)
(ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 + (ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 +
sizeof(struct smc_clc_first_contact_ext))) sizeof(struct smc_clc_first_contact_ext)))
return false; return false;
if (hdr->typev1 == SMC_TYPE_R &&
ntohs(hdr->length) < SMCR_CLC_ACCEPT_CONFIRM_LEN_V2)
return false;
} }
return true; return true;
} }
...@@ -844,8 +849,8 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -844,8 +849,8 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
} else { } else {
struct smc_clc_eid_entry *ueident; struct smc_clc_eid_entry *ueident;
u16 v2_ext_offset; u16 v2_ext_offset;
u8 *eid = NULL;
v2_ext->hdr.flag.release = SMC_RELEASE;
v2_ext_offset = sizeof(*pclc_smcd) - v2_ext_offset = sizeof(*pclc_smcd) -
offsetofend(struct smc_clc_msg_smcd, v2_ext_offset); offsetofend(struct smc_clc_msg_smcd, v2_ext_offset);
if (ini->smc_type_v1 != SMC_TYPE_N) if (ini->smc_type_v1 != SMC_TYPE_N)
...@@ -853,6 +858,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -853,6 +858,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
pclc_prfx->ipv6_prefixes_cnt * pclc_prfx->ipv6_prefixes_cnt *
sizeof(ipv6_prfx[0]); sizeof(ipv6_prfx[0]);
pclc_smcd->v2_ext_offset = htons(v2_ext_offset); pclc_smcd->v2_ext_offset = htons(v2_ext_offset);
plen += sizeof(*v2_ext);
read_lock(&smc_clc_eid_table.lock); read_lock(&smc_clc_eid_table.lock);
v2_ext->hdr.eid_cnt = smc_clc_eid_table.ueid_cnt; v2_ext->hdr.eid_cnt = smc_clc_eid_table.ueid_cnt;
...@@ -862,10 +868,13 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -862,10 +868,13 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
memcpy(v2_ext->user_eids[i++], ueident->eid, memcpy(v2_ext->user_eids[i++], ueident->eid,
sizeof(ueident->eid)); sizeof(ueident->eid));
} }
v2_ext->hdr.flag.seid = smc_clc_eid_table.seid_enabled;
read_unlock(&smc_clc_eid_table.lock); read_unlock(&smc_clc_eid_table.lock);
}
if (smcd_indicated(ini->smc_type_v2)) {
u8 *eid = NULL;
v2_ext->hdr.flag.seid = smc_clc_eid_table.seid_enabled;
v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt; v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt;
v2_ext->hdr.flag.release = SMC_RELEASE;
v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) - v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) -
offsetofend(struct smc_clnt_opts_area_hdr, offsetofend(struct smc_clnt_opts_area_hdr,
smcd_v2_ext_offset) + smcd_v2_ext_offset) +
...@@ -873,7 +882,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -873,7 +882,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
smc_ism_get_system_eid(&eid); smc_ism_get_system_eid(&eid);
if (eid && v2_ext->hdr.flag.seid) if (eid && v2_ext->hdr.flag.seid)
memcpy(smcd_v2_ext->system_eid, eid, SMC_MAX_EID_LEN); memcpy(smcd_v2_ext->system_eid, eid, SMC_MAX_EID_LEN);
plen += sizeof(*v2_ext) + sizeof(*smcd_v2_ext); plen += sizeof(*smcd_v2_ext);
if (ini->ism_offered_cnt) { if (ini->ism_offered_cnt) {
for (i = 1; i <= ini->ism_offered_cnt; i++) { for (i = 1; i <= ini->ism_offered_cnt; i++) {
gidchids[i - 1].gid = gidchids[i - 1].gid =
...@@ -885,6 +894,9 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -885,6 +894,9 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
sizeof(struct smc_clc_smcd_gid_chid); sizeof(struct smc_clc_smcd_gid_chid);
} }
} }
if (smcr_indicated(ini->smc_type_v2))
memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE);
pclc_base->hdr.length = htons(plen); pclc_base->hdr.length = htons(plen);
memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
...@@ -908,12 +920,14 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -908,12 +920,14 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
vec[i].iov_base = v2_ext; vec[i].iov_base = v2_ext;
vec[i++].iov_len = sizeof(*v2_ext) + vec[i++].iov_len = sizeof(*v2_ext) +
(v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN); (v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN);
vec[i].iov_base = smcd_v2_ext; if (smcd_indicated(ini->smc_type_v2)) {
vec[i++].iov_len = sizeof(*smcd_v2_ext); vec[i].iov_base = smcd_v2_ext;
if (ini->ism_offered_cnt) { vec[i++].iov_len = sizeof(*smcd_v2_ext);
vec[i].iov_base = gidchids; if (ini->ism_offered_cnt) {
vec[i++].iov_len = ini->ism_offered_cnt * vec[i].iov_base = gidchids;
vec[i++].iov_len = ini->ism_offered_cnt *
sizeof(struct smc_clc_smcd_gid_chid); sizeof(struct smc_clc_smcd_gid_chid);
}
} }
} }
vec[i].iov_base = trl; vec[i].iov_base = trl;
...@@ -936,13 +950,14 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -936,13 +950,14 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
static int smc_clc_send_confirm_accept(struct smc_sock *smc, static int smc_clc_send_confirm_accept(struct smc_sock *smc,
struct smc_clc_msg_accept_confirm_v2 *clc_v2, struct smc_clc_msg_accept_confirm_v2 *clc_v2,
int first_contact, u8 version, int first_contact, u8 version,
u8 *eid) u8 *eid, struct smc_init_info *ini)
{ {
struct smc_connection *conn = &smc->conn; struct smc_connection *conn = &smc->conn;
struct smc_clc_msg_accept_confirm *clc; struct smc_clc_msg_accept_confirm *clc;
struct smc_clc_first_contact_ext fce; struct smc_clc_first_contact_ext fce;
struct smc_clc_fce_gid_ext gle;
struct smc_clc_msg_trail trl; struct smc_clc_msg_trail trl;
struct kvec vec[3]; struct kvec vec[5];
struct msghdr msg; struct msghdr msg;
int i, len; int i, len;
...@@ -964,9 +979,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, ...@@ -964,9 +979,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
if (version == SMC_V1) { if (version == SMC_V1) {
clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN); clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
} else { } else {
clc_v2->chid = htons(smc_ism_get_chid(conn->lgr->smcd)); clc_v2->d1.chid =
if (eid[0]) htons(smc_ism_get_chid(conn->lgr->smcd));
memcpy(clc_v2->eid, eid, SMC_MAX_EID_LEN); if (eid && eid[0])
memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2; len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
if (first_contact) if (first_contact)
smc_clc_fill_fce(&fce, &len); smc_clc_fill_fce(&fce, &len);
...@@ -1005,6 +1021,26 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, ...@@ -1005,6 +1021,26 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
clc->r0.rmb_dma_addr = cpu_to_be64((u64)sg_dma_address clc->r0.rmb_dma_addr = cpu_to_be64((u64)sg_dma_address
(conn->rmb_desc->sgt[link->link_idx].sgl)); (conn->rmb_desc->sgt[link->link_idx].sgl));
hton24(clc->r0.psn, link->psn_initial); hton24(clc->r0.psn, link->psn_initial);
if (version == SMC_V1) {
clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
} else {
if (eid && eid[0])
memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN);
len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2;
if (first_contact) {
smc_clc_fill_fce(&fce, &len);
fce.v2_direct = !link->lgr->uses_gateway;
memset(&gle, 0, sizeof(gle));
if (ini && clc->hdr.type == SMC_CLC_CONFIRM) {
gle.gid_cnt = ini->smcrv2.gidlist.len;
len += sizeof(gle);
len += gle.gid_cnt * sizeof(gle.gid[0]);
} else {
len += sizeof(gle.reserved);
}
}
clc_v2->hdr.length = htons(len);
}
memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
} }
...@@ -1012,7 +1048,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, ...@@ -1012,7 +1048,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
i = 0; i = 0;
vec[i].iov_base = clc_v2; vec[i].iov_base = clc_v2;
if (version > SMC_V1) if (version > SMC_V1)
vec[i++].iov_len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 - sizeof(trl); vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ?
SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 :
SMCR_CLC_ACCEPT_CONFIRM_LEN_V2) -
sizeof(trl);
else else
vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ? vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ?
SMCD_CLC_ACCEPT_CONFIRM_LEN : SMCD_CLC_ACCEPT_CONFIRM_LEN :
...@@ -1021,6 +1060,18 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, ...@@ -1021,6 +1060,18 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
if (version > SMC_V1 && first_contact) { if (version > SMC_V1 && first_contact) {
vec[i].iov_base = &fce; vec[i].iov_base = &fce;
vec[i++].iov_len = sizeof(fce); vec[i++].iov_len = sizeof(fce);
if (!conn->lgr->is_smcd) {
if (clc->hdr.type == SMC_CLC_CONFIRM) {
vec[i].iov_base = &gle;
vec[i++].iov_len = sizeof(gle);
vec[i].iov_base = &ini->smcrv2.gidlist.list;
vec[i++].iov_len = gle.gid_cnt *
sizeof(gle.gid[0]);
} else {
vec[i].iov_base = &gle.reserved;
vec[i++].iov_len = sizeof(gle.reserved);
}
}
} }
vec[i].iov_base = &trl; vec[i].iov_base = &trl;
vec[i++].iov_len = sizeof(trl); vec[i++].iov_len = sizeof(trl);
...@@ -1030,7 +1081,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, ...@@ -1030,7 +1081,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
/* send CLC CONFIRM message across internal TCP socket */ /* send CLC CONFIRM message across internal TCP socket */
int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact, int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
u8 version, u8 *eid) u8 version, u8 *eid, struct smc_init_info *ini)
{ {
struct smc_clc_msg_accept_confirm_v2 cclc_v2; struct smc_clc_msg_accept_confirm_v2 cclc_v2;
int reason_code = 0; int reason_code = 0;
...@@ -1040,7 +1091,7 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact, ...@@ -1040,7 +1091,7 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
memset(&cclc_v2, 0, sizeof(cclc_v2)); memset(&cclc_v2, 0, sizeof(cclc_v2));
cclc_v2.hdr.type = SMC_CLC_CONFIRM; cclc_v2.hdr.type = SMC_CLC_CONFIRM;
len = smc_clc_send_confirm_accept(smc, &cclc_v2, clnt_first_contact, len = smc_clc_send_confirm_accept(smc, &cclc_v2, clnt_first_contact,
version, eid); version, eid, ini);
if (len < ntohs(cclc_v2.hdr.length)) { if (len < ntohs(cclc_v2.hdr.length)) {
if (len >= 0) { if (len >= 0) {
reason_code = -ENETUNREACH; reason_code = -ENETUNREACH;
...@@ -1063,7 +1114,7 @@ int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact, ...@@ -1063,7 +1114,7 @@ int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
memset(&aclc_v2, 0, sizeof(aclc_v2)); memset(&aclc_v2, 0, sizeof(aclc_v2));
aclc_v2.hdr.type = SMC_CLC_ACCEPT; aclc_v2.hdr.type = SMC_CLC_ACCEPT;
len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact, len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact,
version, negotiated_eid); version, negotiated_eid, NULL);
if (len < ntohs(aclc_v2.hdr.length)) if (len < ntohs(aclc_v2.hdr.length))
len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err; len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err;
......
...@@ -54,6 +54,8 @@ ...@@ -54,6 +54,8 @@
#define SMC_CLC_DECL_NOSRVLINK 0x030b0000 /* SMC-R link from srv not found */ #define SMC_CLC_DECL_NOSRVLINK 0x030b0000 /* SMC-R link from srv not found */
#define SMC_CLC_DECL_VERSMISMAT 0x030c0000 /* SMC version mismatch */ #define SMC_CLC_DECL_VERSMISMAT 0x030c0000 /* SMC version mismatch */
#define SMC_CLC_DECL_MAX_DMB 0x030d0000 /* SMC-D DMB limit exceeded */ #define SMC_CLC_DECL_MAX_DMB 0x030d0000 /* SMC-D DMB limit exceeded */
#define SMC_CLC_DECL_NOROUTE 0x030e0000 /* SMC-Rv2 conn. no route to peer */
#define SMC_CLC_DECL_NOINDIRECT 0x030f0000 /* SMC-Rv2 conn. indirect mismatch*/
#define SMC_CLC_DECL_SYNCERR 0x04000000 /* synchronization error */ #define SMC_CLC_DECL_SYNCERR 0x04000000 /* synchronization error */
#define SMC_CLC_DECL_PEERDECL 0x05000000 /* peer declined during handshake */ #define SMC_CLC_DECL_PEERDECL 0x05000000 /* peer declined during handshake */
#define SMC_CLC_DECL_INTERR 0x09990000 /* internal error */ #define SMC_CLC_DECL_INTERR 0x09990000 /* internal error */
...@@ -213,11 +215,14 @@ struct smcd_clc_msg_accept_confirm_common { /* SMCD accept/confirm */ ...@@ -213,11 +215,14 @@ struct smcd_clc_msg_accept_confirm_common { /* SMCD accept/confirm */
#define SMC_CLC_OS_AIX 3 #define SMC_CLC_OS_AIX 3
struct smc_clc_first_contact_ext { struct smc_clc_first_contact_ext {
u8 reserved1;
#if defined(__BIG_ENDIAN_BITFIELD) #if defined(__BIG_ENDIAN_BITFIELD)
u8 v2_direct : 1,
reserved : 7;
u8 os_type : 4, u8 os_type : 4,
release : 4; release : 4;
#elif defined(__LITTLE_ENDIAN_BITFIELD) #elif defined(__LITTLE_ENDIAN_BITFIELD)
u8 reserved : 7,
v2_direct : 1;
u8 release : 4, u8 release : 4,
os_type : 4; os_type : 4;
#endif #endif
...@@ -225,6 +230,13 @@ struct smc_clc_first_contact_ext { ...@@ -225,6 +230,13 @@ struct smc_clc_first_contact_ext {
u8 hostname[SMC_MAX_HOSTNAME_LEN]; u8 hostname[SMC_MAX_HOSTNAME_LEN];
}; };
struct smc_clc_fce_gid_ext {
u8 reserved[16];
u8 gid_cnt;
u8 reserved2[3];
u8 gid[][SMC_GID_SIZE];
};
struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */ struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */
struct smc_clc_msg_hdr hdr; struct smc_clc_msg_hdr hdr;
union { union {
...@@ -239,13 +251,17 @@ struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */ ...@@ -239,13 +251,17 @@ struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */
struct smc_clc_msg_accept_confirm_v2 { /* clc accept / confirm message */ struct smc_clc_msg_accept_confirm_v2 { /* clc accept / confirm message */
struct smc_clc_msg_hdr hdr; struct smc_clc_msg_hdr hdr;
union { union {
struct smcr_clc_msg_accept_confirm r0; /* SMC-R */ struct { /* SMC-R */
struct smcr_clc_msg_accept_confirm r0;
u8 eid[SMC_MAX_EID_LEN];
u8 reserved6[8];
} r1;
struct { /* SMC-D */ struct { /* SMC-D */
struct smcd_clc_msg_accept_confirm_common d0; struct smcd_clc_msg_accept_confirm_common d0;
__be16 chid; __be16 chid;
u8 eid[SMC_MAX_EID_LEN]; u8 eid[SMC_MAX_EID_LEN];
u8 reserved5[8]; u8 reserved5[8];
}; } d1;
}; };
}; };
...@@ -345,7 +361,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen, ...@@ -345,7 +361,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info, u8 version); int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info, u8 version);
int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini); int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini);
int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact, int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
u8 version, u8 *eid); u8 version, u8 *eid, struct smc_init_info *ini);
int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact, int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact,
u8 version, u8 *negotiated_eid); u8 version, u8 *negotiated_eid);
void smc_clc_init(void) __init; void smc_clc_init(void) __init;
......
...@@ -288,6 +288,9 @@ struct smc_link_group { ...@@ -288,6 +288,9 @@ struct smc_link_group {
/* link keep alive time */ /* link keep alive time */
u32 llc_termination_rsn; u32 llc_termination_rsn;
/* rsn code for termination */ /* rsn code for termination */
u8 nexthop_mac[ETH_ALEN];
u8 uses_gateway;
__be32 saddr;
}; };
struct { /* SMC-D */ struct { /* SMC-D */
u64 peer_gid; u64 peer_gid;
...@@ -340,6 +343,9 @@ struct smc_init_info { ...@@ -340,6 +343,9 @@ struct smc_init_info {
struct smc_clc_msg_local *ib_lcl; struct smc_clc_msg_local *ib_lcl;
u8 smcr_version; u8 smcr_version;
u8 check_smcrv2; u8 check_smcrv2;
u8 peer_gid[SMC_GID_SIZE];
u8 peer_mac[ETH_ALEN];
u8 peer_systemid[SMC_SYSTEMID_LEN];
struct smc_ib_device *ib_dev; struct smc_ib_device *ib_dev;
u8 ib_gid[SMC_GID_SIZE]; u8 ib_gid[SMC_GID_SIZE];
u8 ib_port; u8 ib_port;
......
...@@ -183,6 +183,33 @@ bool smc_ib_port_active(struct smc_ib_device *smcibdev, u8 ibport) ...@@ -183,6 +183,33 @@ bool smc_ib_port_active(struct smc_ib_device *smcibdev, u8 ibport)
return smcibdev->pattr[ibport - 1].state == IB_PORT_ACTIVE; return smcibdev->pattr[ibport - 1].state == IB_PORT_ACTIVE;
} }
int smc_ib_find_route(__be32 saddr, __be32 daddr,
u8 nexthop_mac[], u8 *uses_gateway)
{
struct neighbour *neigh = NULL;
struct rtable *rt = NULL;
struct flowi4 fl4 = {
.saddr = saddr,
.daddr = daddr
};
if (daddr == cpu_to_be32(INADDR_NONE))
goto out;
rt = ip_route_output_flow(&init_net, &fl4, NULL);
if (IS_ERR(rt))
goto out;
if (rt->rt_uses_gateway && rt->rt_gw_family != AF_INET)
goto out;
neigh = rt->dst.ops->neigh_lookup(&rt->dst, NULL, &fl4.daddr);
if (neigh) {
memcpy(nexthop_mac, neigh->ha, ETH_ALEN);
*uses_gateway = rt->rt_uses_gateway;
return 0;
}
out:
return -ENOENT;
}
/* determine the gid for an ib-device port and vlan id */ /* determine the gid for an ib-device port and vlan id */
int smc_ib_determine_gid(struct smc_ib_device *smcibdev, u8 ibport, int smc_ib_determine_gid(struct smc_ib_device *smcibdev, u8 ibport,
unsigned short vlan_id, u8 gid[], u8 *sgid_index) unsigned short vlan_id, u8 gid[], u8 *sgid_index)
......
...@@ -59,6 +59,17 @@ struct smc_ib_device { /* ib-device infos for smc */ ...@@ -59,6 +59,17 @@ struct smc_ib_device { /* ib-device infos for smc */
int ndev_ifidx[SMC_MAX_PORTS]; /* ndev if indexes */ int ndev_ifidx[SMC_MAX_PORTS]; /* ndev if indexes */
}; };
static inline __be32 smc_ib_gid_to_ipv4(u8 gid[SMC_GID_SIZE])
{
struct in6_addr *addr6 = (struct in6_addr *)gid;
if (ipv6_addr_v4mapped(addr6) ||
!(addr6->s6_addr32[0] | addr6->s6_addr32[1] | addr6->s6_addr32[2]))
return addr6->s6_addr32[3];
return cpu_to_be32(INADDR_NONE);
}
struct smc_init_info_smcrv2;
struct smc_buf_desc; struct smc_buf_desc;
struct smc_link; struct smc_link;
...@@ -91,6 +102,8 @@ void smc_ib_sync_sg_for_device(struct smc_link *lnk, ...@@ -91,6 +102,8 @@ void smc_ib_sync_sg_for_device(struct smc_link *lnk,
enum dma_data_direction data_direction); enum dma_data_direction data_direction);
int smc_ib_determine_gid(struct smc_ib_device *smcibdev, u8 ibport, int smc_ib_determine_gid(struct smc_ib_device *smcibdev, u8 ibport,
unsigned short vlan_id, u8 gid[], u8 *sgid_index); unsigned short vlan_id, u8 gid[], u8 *sgid_index);
int smc_ib_find_route(__be32 saddr, __be32 daddr,
u8 nexthop_mac[], u8 *uses_gateway);
bool smc_ib_is_valid_local_systemid(void); bool smc_ib_is_valid_local_systemid(void);
int smcr_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb); int smcr_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment