Skip to content

Commit 5c21c4c

Browse files
Ursula Braundavem330
authored andcommitted
net/smc: determine accepted ISM devices
SMCD Version 2 allows to propose up to 8 additional ISM devices offered to the peer as candidates for SMCD communication. This patch covers the server side, i.e. selection of an ISM device matching one of the proposed ISM devices, that will be used for CLC accept Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Signed-off-by: Karsten Graul <kgraul@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 8c3dca3 commit 5c21c4c

File tree

4 files changed

+208
-34
lines changed

4 files changed

+208
-34
lines changed

net/smc/af_smc.c

Lines changed: 179 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,13 +1236,56 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
12361236
smc_listen_out_connected(new_smc);
12371237
}
12381238

1239+
/* listen worker: version checking */
1240+
static int smc_listen_v2_check(struct smc_sock *new_smc,
1241+
struct smc_clc_msg_proposal *pclc,
1242+
struct smc_init_info *ini)
1243+
{
1244+
struct smc_clc_smcd_v2_extension *pclc_smcd_v2_ext;
1245+
struct smc_clc_v2_extension *pclc_v2_ext;
1246+
1247+
ini->smc_type_v1 = pclc->hdr.typev1;
1248+
ini->smc_type_v2 = pclc->hdr.typev2;
1249+
ini->smcd_version = ini->smc_type_v1 != SMC_TYPE_N ? SMC_V1 : 0;
1250+
if (pclc->hdr.version > SMC_V1)
1251+
ini->smcd_version |=
1252+
ini->smc_type_v2 != SMC_TYPE_N ? SMC_V2 : 0;
1253+
if (!smc_ism_v2_capable) {
1254+
ini->smcd_version &= ~SMC_V2;
1255+
goto out;
1256+
}
1257+
pclc_v2_ext = smc_get_clc_v2_ext(pclc);
1258+
if (!pclc_v2_ext) {
1259+
ini->smcd_version &= ~SMC_V2;
1260+
goto out;
1261+
}
1262+
pclc_smcd_v2_ext = smc_get_clc_smcd_v2_ext(pclc_v2_ext);
1263+
if (!pclc_smcd_v2_ext)
1264+
ini->smcd_version &= ~SMC_V2;
1265+
1266+
out:
1267+
if (!ini->smcd_version) {
1268+
if (pclc->hdr.typev1 == SMC_TYPE_B ||
1269+
pclc->hdr.typev2 == SMC_TYPE_B)
1270+
return SMC_CLC_DECL_NOSMCDEV;
1271+
if (pclc->hdr.typev1 == SMC_TYPE_D ||
1272+
pclc->hdr.typev2 == SMC_TYPE_D)
1273+
return SMC_CLC_DECL_NOSMCDDEV;
1274+
return SMC_CLC_DECL_NOSMCRDEV;
1275+
}
1276+
1277+
return 0;
1278+
}
1279+
12391280
/* listen worker: check prefixes */
12401281
static int smc_listen_prfx_check(struct smc_sock *new_smc,
12411282
struct smc_clc_msg_proposal *pclc)
12421283
{
12431284
struct smc_clc_msg_proposal_prefix *pclc_prfx;
12441285
struct socket *newclcsock = new_smc->clcsock;
12451286

1287+
if (pclc->hdr.typev1 == SMC_TYPE_N)
1288+
return 0;
12461289
pclc_prfx = smc_clc_proposal_get_prefix(pclc);
12471290
if (smc_clc_prfx_match(newclcsock, pclc_prfx))
12481291
return SMC_CLC_DECL_DIFFPREFIX;
@@ -1292,20 +1335,119 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
12921335
return 0;
12931336
}
12941337

1295-
static void smc_find_ism_device_serv(struct smc_sock *new_smc,
1296-
struct smc_clc_msg_proposal *pclc,
1297-
struct smc_init_info *ini)
1338+
static bool smc_is_already_selected(struct smcd_dev *smcd,
1339+
struct smc_init_info *ini,
1340+
int matches)
1341+
{
1342+
int i;
1343+
1344+
for (i = 0; i < matches; i++)
1345+
if (smcd == ini->ism_dev[i])
1346+
return true;
1347+
1348+
return false;
1349+
}
1350+
1351+
/* check for ISM devices matching proposed ISM devices */
1352+
static void smc_check_ism_v2_match(struct smc_init_info *ini,
1353+
u16 proposed_chid, u64 proposed_gid,
1354+
unsigned int *matches)
1355+
{
1356+
struct smcd_dev *smcd;
1357+
1358+
list_for_each_entry(smcd, &smcd_dev_list.list, list) {
1359+
if (smcd->going_away)
1360+
continue;
1361+
if (smc_is_already_selected(smcd, ini, *matches))
1362+
continue;
1363+
if (smc_ism_get_chid(smcd) == proposed_chid &&
1364+
!smc_ism_cantalk(proposed_gid, ISM_RESERVED_VLANID, smcd)) {
1365+
ini->ism_peer_gid[*matches] = proposed_gid;
1366+
ini->ism_dev[*matches] = smcd;
1367+
(*matches)++;
1368+
break;
1369+
}
1370+
}
1371+
}
1372+
1373+
static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
1374+
struct smc_clc_msg_proposal *pclc,
1375+
struct smc_init_info *ini)
1376+
{
1377+
struct smc_clc_smcd_v2_extension *smcd_v2_ext;
1378+
struct smc_clc_v2_extension *smc_v2_ext;
1379+
struct smc_clc_msg_smcd *pclc_smcd;
1380+
unsigned int matches = 0;
1381+
u8 *eid = NULL;
1382+
int i;
1383+
1384+
if (!(ini->smcd_version & SMC_V2) || !smcd_indicated(ini->smc_type_v2))
1385+
return;
1386+
1387+
pclc_smcd = smc_get_clc_msg_smcd(pclc);
1388+
smc_v2_ext = smc_get_clc_v2_ext(pclc);
1389+
smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext);
1390+
if (!smcd_v2_ext ||
1391+
!smc_v2_ext->hdr.flag.seid) /* no system EID support for SMCD */
1392+
goto not_found;
1393+
1394+
mutex_lock(&smcd_dev_list.mutex);
1395+
if (pclc_smcd->ism.chid)
1396+
/* check for ISM device matching proposed native ISM device */
1397+
smc_check_ism_v2_match(ini, ntohs(pclc_smcd->ism.chid),
1398+
ntohll(pclc_smcd->ism.gid), &matches);
1399+
for (i = 1; i <= smc_v2_ext->hdr.ism_gid_cnt; i++) {
1400+
/* check for ISM devices matching proposed non-native ISM
1401+
* devices
1402+
*/
1403+
smc_check_ism_v2_match(ini,
1404+
ntohs(smcd_v2_ext->gidchid[i - 1].chid),
1405+
ntohll(smcd_v2_ext->gidchid[i - 1].gid),
1406+
&matches);
1407+
}
1408+
mutex_unlock(&smcd_dev_list.mutex);
1409+
1410+
if (ini->ism_dev[0]) {
1411+
smc_ism_get_system_eid(ini->ism_dev[0], &eid);
1412+
if (memcmp(eid, smcd_v2_ext->system_eid, SMC_MAX_EID_LEN))
1413+
goto not_found;
1414+
} else {
1415+
goto not_found;
1416+
}
1417+
1418+
/* separate - outside the smcd_dev_list.lock */
1419+
for (i = 0; i < matches; i++) {
1420+
ini->smcd_version = SMC_V2;
1421+
ini->is_smcd = true;
1422+
ini->ism_selected = i;
1423+
if (smc_listen_ism_init(new_smc, ini))
1424+
/* try next active ISM device */
1425+
continue;
1426+
return; /* matching and usable V2 ISM device found */
1427+
}
1428+
1429+
not_found:
1430+
ini->smcd_version &= ~SMC_V2;
1431+
ini->ism_dev[0] = NULL;
1432+
ini->is_smcd = false;
1433+
}
1434+
1435+
static void smc_find_ism_v1_device_serv(struct smc_sock *new_smc,
1436+
struct smc_clc_msg_proposal *pclc,
1437+
struct smc_init_info *ini)
12981438
{
12991439
struct smc_clc_msg_smcd *pclc_smcd = smc_get_clc_msg_smcd(pclc);
13001440

1301-
if (!smcd_indicated(pclc->hdr.typev1))
1441+
/* check if ISM V1 is available */
1442+
if (!(ini->smcd_version & SMC_V1) || !smcd_indicated(ini->smc_type_v1))
13021443
goto not_found;
13031444
ini->is_smcd = true; /* prepare ISM check */
13041445
ini->ism_peer_gid[0] = ntohll(pclc_smcd->ism.gid);
13051446
if (smc_find_ism_device(new_smc, ini))
13061447
goto not_found;
1448+
ini->ism_selected = 0;
13071449
if (!smc_listen_ism_init(new_smc, ini))
1308-
return; /* ISM device found */
1450+
return; /* V1 ISM device found */
13091451

13101452
not_found:
13111453
ini->ism_dev[0] = NULL;
@@ -1326,21 +1468,21 @@ static int smc_listen_rdma_reg(struct smc_sock *new_smc, bool local_first)
13261468
return 0;
13271469
}
13281470

1329-
static int smc_find_rdma_device_serv(struct smc_sock *new_smc,
1330-
struct smc_clc_msg_proposal *pclc,
1331-
struct smc_init_info *ini)
1471+
static int smc_find_rdma_v1_device_serv(struct smc_sock *new_smc,
1472+
struct smc_clc_msg_proposal *pclc,
1473+
struct smc_init_info *ini)
13321474
{
13331475
int rc;
13341476

1335-
if (!smcr_indicated(pclc->hdr.typev1))
1477+
if (!smcr_indicated(ini->smc_type_v1))
13361478
return SMC_CLC_DECL_NOSMCDEV;
13371479

13381480
/* prepare RDMA check */
13391481
ini->ib_lcl = &pclc->lcl;
13401482
rc = smc_find_rdma_device(new_smc, ini);
13411483
if (rc) {
13421484
/* no RDMA device found */
1343-
if (pclc->hdr.typev1 == SMC_TYPE_B)
1485+
if (ini->smc_type_v1 == SMC_TYPE_B)
13441486
/* neither ISM nor RDMA device found */
13451487
rc = SMC_CLC_DECL_NOSMCDEV;
13461488
return rc;
@@ -1356,15 +1498,35 @@ static int smc_listen_find_device(struct smc_sock *new_smc,
13561498
struct smc_clc_msg_proposal *pclc,
13571499
struct smc_init_info *ini)
13581500
{
1359-
/* check if ISM is available */
1360-
smc_find_ism_device_serv(new_smc, pclc, ini);
1361-
if (ini->is_smcd)
1501+
int rc;
1502+
1503+
/* check for ISM device matching V2 proposed device */
1504+
smc_find_ism_v2_device_serv(new_smc, pclc, ini);
1505+
if (ini->ism_dev[0])
13621506
return 0;
1507+
1508+
if (!(ini->smcd_version & SMC_V1))
1509+
return SMC_CLC_DECL_NOSMCDEV;
1510+
1511+
/* check for matching IP prefix and subnet length */
1512+
rc = smc_listen_prfx_check(new_smc, pclc);
1513+
if (rc)
1514+
return rc;
1515+
1516+
/* get vlan id from IP device */
1517+
if (smc_vlan_by_tcpsk(new_smc->clcsock, ini))
1518+
return SMC_CLC_DECL_GETVLANERR;
1519+
1520+
/* check for ISM device matching V1 proposed device */
1521+
smc_find_ism_v1_device_serv(new_smc, pclc, ini);
1522+
if (ini->ism_dev[0])
1523+
return 0;
1524+
13631525
if (pclc->hdr.typev1 == SMC_TYPE_D)
13641526
return SMC_CLC_DECL_NOSMCDDEV; /* skip RDMA and decline */
13651527

13661528
/* check if RDMA is available */
1367-
return smc_find_rdma_device_serv(new_smc, pclc, ini);
1529+
return smc_find_rdma_v1_device_serv(new_smc, pclc, ini);
13681530
}
13691531

13701532
/* listen worker: finish RDMA setup */
@@ -1440,22 +1602,16 @@ static void smc_listen_work(struct work_struct *work)
14401602
goto out_decl;
14411603
}
14421604

1443-
/* check for matching IP prefix and subnet length */
1444-
rc = smc_listen_prfx_check(new_smc, pclc);
1445-
if (rc)
1446-
goto out_decl;
1447-
14481605
ini = kzalloc(sizeof(*ini), GFP_KERNEL);
14491606
if (!ini) {
14501607
rc = SMC_CLC_DECL_MEM;
14511608
goto out_decl;
14521609
}
14531610

1454-
/* get vlan id from IP device */
1455-
if (smc_vlan_by_tcpsk(new_smc->clcsock, ini)) {
1456-
rc = SMC_CLC_DECL_GETVLANERR;
1611+
/* initial version checking */
1612+
rc = smc_listen_v2_check(new_smc, pclc, ini);
1613+
if (rc)
14571614
goto out_decl;
1458-
}
14591615

14601616
mutex_lock(&smc_server_lgr_pending);
14611617
smc_close_init(new_smc);

net/smc/smc_clc.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,22 @@ smc_get_clc_v2_ext(struct smc_clc_msg_proposal *prop)
260260
ntohs(prop_smcd->v2_ext_offset));
261261
}
262262

263+
static inline struct smc_clc_smcd_v2_extension *
264+
smc_get_clc_smcd_v2_ext(struct smc_clc_v2_extension *prop_v2ext)
265+
{
266+
if (!prop_v2ext)
267+
return NULL;
268+
if (!ntohs(prop_v2ext->hdr.smcd_v2_ext_offset))
269+
return NULL;
270+
271+
return (struct smc_clc_smcd_v2_extension *)
272+
((u8 *)prop_v2ext +
273+
offsetof(struct smc_clc_v2_extension, hdr) +
274+
offsetof(struct smc_clnt_opts_area_hdr, smcd_v2_ext_offset) +
275+
sizeof(prop_v2ext->hdr.smcd_v2_ext_offset) +
276+
ntohs(prop_v2ext->hdr.smcd_v2_ext_offset));
277+
}
278+
263279
struct smcd_dev;
264280
struct smc_init_info;
265281

net/smc/smc_core.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,8 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
375375
int i;
376376

377377
if (ini->is_smcd && ini->vlan_id) {
378-
if (smc_ism_get_vlan(ini->ism_dev[0], ini->vlan_id)) {
378+
if (smc_ism_get_vlan(ini->ism_dev[ini->ism_selected],
379+
ini->vlan_id)) {
379380
rc = SMC_CLC_DECL_ISMVLANERR;
380381
goto out;
381382
}
@@ -412,13 +413,13 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
412413
lgr->conns_all = RB_ROOT;
413414
if (ini->is_smcd) {
414415
/* SMC-D specific settings */
415-
get_device(&ini->ism_dev[0]->dev);
416-
lgr->peer_gid = ini->ism_peer_gid[0];
417-
lgr->smcd = ini->ism_dev[0];
418-
lgr_list = &ini->ism_dev[0]->lgr_list;
416+
get_device(&ini->ism_dev[ini->ism_selected]->dev);
417+
lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected];
418+
lgr->smcd = ini->ism_dev[ini->ism_selected];
419+
lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
419420
lgr_lock = &lgr->smcd->lgr_lock;
420421
lgr->peer_shutdown = 0;
421-
atomic_inc(&ini->ism_dev[0]->lgr_cnt);
422+
atomic_inc(&ini->ism_dev[ini->ism_selected]->lgr_cnt);
422423
} else {
423424
/* SMC-R specific settings */
424425
lgr->role = smc->listen_smc ? SMC_SERV : SMC_CLNT;
@@ -449,7 +450,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
449450
kfree(lgr);
450451
ism_put_vlan:
451452
if (ini->is_smcd && ini->vlan_id)
452-
smc_ism_put_vlan(ini->ism_dev[0], ini->vlan_id);
453+
smc_ism_put_vlan(ini->ism_dev[ini->ism_selected], ini->vlan_id);
453454
out:
454455
if (rc < 0) {
455456
if (rc == -ENOMEM)
@@ -1288,9 +1289,9 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
12881289
spinlock_t *lgr_lock;
12891290
int rc = 0;
12901291

1291-
lgr_list = ini->is_smcd ? &ini->ism_dev[0]->lgr_list :
1292+
lgr_list = ini->is_smcd ? &ini->ism_dev[ini->ism_selected]->lgr_list :
12921293
&smc_lgr_list.list;
1293-
lgr_lock = ini->is_smcd ? &ini->ism_dev[0]->lgr_lock :
1294+
lgr_lock = ini->is_smcd ? &ini->ism_dev[ini->ism_selected]->lgr_lock :
12941295
&smc_lgr_list.lock;
12951296
ini->first_contact_local = 1;
12961297
role = smc->listen_smc ? SMC_SERV : SMC_CLNT;
@@ -1303,8 +1304,8 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
13031304
list_for_each_entry(lgr, lgr_list, list) {
13041305
write_lock_bh(&lgr->conns_lock);
13051306
if ((ini->is_smcd ?
1306-
smcd_lgr_match(lgr, ini->ism_dev[0],
1307-
ini->ism_peer_gid[0]) :
1307+
smcd_lgr_match(lgr, ini->ism_dev[ini->ism_selected],
1308+
ini->ism_peer_gid[ini->ism_selected]) :
13081309
smcr_lgr_match(lgr, ini->ib_lcl, role, ini->ib_clcqpn)) &&
13091310
!lgr->sync_err &&
13101311
lgr->vlan_id == ini->vlan_id &&

net/smc/smc_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ struct smc_init_info {
307307
struct smcd_dev *ism_dev[SMC_MAX_ISM_DEVS + 1];
308308
u16 ism_chid[SMC_MAX_ISM_DEVS + 1];
309309
u8 ism_offered_cnt; /* # of ISM devices offered */
310+
u8 ism_selected; /* index of selected ISM dev*/
310311
u8 smcd_version;
311312
};
312313

0 commit comments

Comments
 (0)