Skip to content

Commit 4134984

Browse files
Hans Wippeldavem330
authored andcommitted
net/smc: add SMC-D support in af_smc
This patch ties together the previous SMC-D patches. It adds support for SMC-D to the listen and connect functions and, thus, enables SMC-D support in the SMC code. If a connection supports both SMC-R and SMC-D, SMC-D is preferred. Signed-off-by: Hans Wippel <[email protected]> Signed-off-by: Ursula Braun <[email protected]> Suggested-by: Thomas Richter <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent be244f2 commit 4134984

File tree

3 files changed

+200
-19
lines changed

3 files changed

+200
-19
lines changed

net/smc/af_smc.c

Lines changed: 198 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/workqueue.h>
2424
#include <linux/in.h>
2525
#include <linux/sched/signal.h>
26+
#include <linux/if_vlan.h>
2627

2728
#include <net/sock.h>
2829
#include <net/tcp.h>
@@ -35,6 +36,7 @@
3536
#include "smc_cdc.h"
3637
#include "smc_core.h"
3738
#include "smc_ib.h"
39+
#include "smc_ism.h"
3840
#include "smc_pnet.h"
3941
#include "smc_tx.h"
4042
#include "smc_rx.h"
@@ -372,8 +374,8 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc)
372374
return 0;
373375
}
374376

375-
static void smc_conn_save_peer_info(struct smc_sock *smc,
376-
struct smc_clc_msg_accept_confirm *clc)
377+
static void smcr_conn_save_peer_info(struct smc_sock *smc,
378+
struct smc_clc_msg_accept_confirm *clc)
377379
{
378380
int bufsize = smc_uncompress_bufsize(clc->rmbe_size);
379381

@@ -384,6 +386,28 @@ static void smc_conn_save_peer_info(struct smc_sock *smc,
384386
smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1);
385387
}
386388

389+
static void smcd_conn_save_peer_info(struct smc_sock *smc,
390+
struct smc_clc_msg_accept_confirm *clc)
391+
{
392+
int bufsize = smc_uncompress_bufsize(clc->dmbe_size);
393+
394+
smc->conn.peer_rmbe_idx = clc->dmbe_idx;
395+
smc->conn.peer_token = clc->token;
396+
/* msg header takes up space in the buffer */
397+
smc->conn.peer_rmbe_size = bufsize - sizeof(struct smcd_cdc_msg);
398+
atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size);
399+
smc->conn.tx_off = bufsize * smc->conn.peer_rmbe_idx;
400+
}
401+
402+
static void smc_conn_save_peer_info(struct smc_sock *smc,
403+
struct smc_clc_msg_accept_confirm *clc)
404+
{
405+
if (smc->conn.lgr->is_smcd)
406+
smcd_conn_save_peer_info(smc, clc);
407+
else
408+
smcr_conn_save_peer_info(smc, clc);
409+
}
410+
387411
static void smc_link_save_peer_info(struct smc_link *link,
388412
struct smc_clc_msg_accept_confirm *clc)
389413
{
@@ -450,15 +474,51 @@ static int smc_check_rdma(struct smc_sock *smc, struct smc_ib_device **ibdev,
450474
return reason_code;
451475
}
452476

477+
/* check if there is an ISM device available for this connection. */
478+
/* called for connect and listen */
479+
static int smc_check_ism(struct smc_sock *smc, struct smcd_dev **ismdev)
480+
{
481+
/* Find ISM device with same PNETID as connecting interface */
482+
smc_pnet_find_ism_resource(smc->clcsock->sk, ismdev);
483+
if (!(*ismdev))
484+
return SMC_CLC_DECL_CNFERR; /* configuration error */
485+
return 0;
486+
}
487+
488+
/* Check for VLAN ID and register it on ISM device just for CLC handshake */
489+
static int smc_connect_ism_vlan_setup(struct smc_sock *smc,
490+
struct smcd_dev *ismdev,
491+
unsigned short vlan_id)
492+
{
493+
if (vlan_id && smc_ism_get_vlan(ismdev, vlan_id))
494+
return SMC_CLC_DECL_CNFERR;
495+
return 0;
496+
}
497+
498+
/* cleanup temporary VLAN ID registration used for CLC handshake. If ISM is
499+
* used, the VLAN ID will be registered again during the connection setup.
500+
*/
501+
static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc, bool is_smcd,
502+
struct smcd_dev *ismdev,
503+
unsigned short vlan_id)
504+
{
505+
if (!is_smcd)
506+
return 0;
507+
if (vlan_id && smc_ism_put_vlan(ismdev, vlan_id))
508+
return SMC_CLC_DECL_CNFERR;
509+
return 0;
510+
}
511+
453512
/* CLC handshake during connect */
454513
static int smc_connect_clc(struct smc_sock *smc, int smc_type,
455514
struct smc_clc_msg_accept_confirm *aclc,
456-
struct smc_ib_device *ibdev, u8 ibport)
515+
struct smc_ib_device *ibdev, u8 ibport,
516+
struct smcd_dev *ismdev)
457517
{
458518
int rc = 0;
459519

460520
/* do inband token exchange */
461-
rc = smc_clc_send_proposal(smc, smc_type, ibdev, ibport, NULL);
521+
rc = smc_clc_send_proposal(smc, smc_type, ibdev, ibport, ismdev);
462522
if (rc)
463523
return rc;
464524
/* receive SMC Accept CLC message */
@@ -538,11 +598,50 @@ static int smc_connect_rdma(struct smc_sock *smc,
538598
return 0;
539599
}
540600

601+
/* setup for ISM connection of client */
602+
static int smc_connect_ism(struct smc_sock *smc,
603+
struct smc_clc_msg_accept_confirm *aclc,
604+
struct smcd_dev *ismdev)
605+
{
606+
int local_contact = SMC_FIRST_CONTACT;
607+
int rc = 0;
608+
609+
mutex_lock(&smc_create_lgr_pending);
610+
local_contact = smc_conn_create(smc, true, aclc->hdr.flag, NULL, 0,
611+
NULL, ismdev, aclc->gid);
612+
if (local_contact < 0)
613+
return smc_connect_abort(smc, SMC_CLC_DECL_MEM, 0);
614+
615+
/* Create send and receive buffers */
616+
if (smc_buf_create(smc, true))
617+
return smc_connect_abort(smc, SMC_CLC_DECL_MEM, local_contact);
618+
619+
smc_conn_save_peer_info(smc, aclc);
620+
smc_close_init(smc);
621+
smc_rx_init(smc);
622+
smc_tx_init(smc);
623+
624+
rc = smc_clc_send_confirm(smc);
625+
if (rc)
626+
return smc_connect_abort(smc, rc, local_contact);
627+
mutex_unlock(&smc_create_lgr_pending);
628+
629+
smc_copy_sock_settings_to_clc(smc);
630+
if (smc->sk.sk_state == SMC_INIT)
631+
smc->sk.sk_state = SMC_ACTIVE;
632+
633+
return 0;
634+
}
635+
541636
/* perform steps before actually connecting */
542637
static int __smc_connect(struct smc_sock *smc)
543638
{
639+
bool ism_supported = false, rdma_supported = false;
544640
struct smc_clc_msg_accept_confirm aclc;
545641
struct smc_ib_device *ibdev;
642+
struct smcd_dev *ismdev;
643+
unsigned short vlan;
644+
int smc_type;
546645
int rc = 0;
547646
u8 ibport;
548647

@@ -559,20 +658,52 @@ static int __smc_connect(struct smc_sock *smc)
559658
if (using_ipsec(smc))
560659
return smc_connect_decline_fallback(smc, SMC_CLC_DECL_IPSEC);
561660

562-
/* check if a RDMA device is available; if not, fall back */
563-
if (smc_check_rdma(smc, &ibdev, &ibport))
661+
/* check for VLAN ID */
662+
if (smc_vlan_by_tcpsk(smc->clcsock, &vlan))
663+
return smc_connect_decline_fallback(smc, SMC_CLC_DECL_CNFERR);
664+
665+
/* check if there is an ism device available */
666+
if (!smc_check_ism(smc, &ismdev) &&
667+
!smc_connect_ism_vlan_setup(smc, ismdev, vlan)) {
668+
/* ISM is supported for this connection */
669+
ism_supported = true;
670+
smc_type = SMC_TYPE_D;
671+
}
672+
673+
/* check if there is a rdma device available */
674+
if (!smc_check_rdma(smc, &ibdev, &ibport)) {
675+
/* RDMA is supported for this connection */
676+
rdma_supported = true;
677+
if (ism_supported)
678+
smc_type = SMC_TYPE_B; /* both */
679+
else
680+
smc_type = SMC_TYPE_R; /* only RDMA */
681+
}
682+
683+
/* if neither ISM nor RDMA are supported, fallback */
684+
if (!rdma_supported && !ism_supported)
564685
return smc_connect_decline_fallback(smc, SMC_CLC_DECL_CNFERR);
565686

566687
/* perform CLC handshake */
567-
rc = smc_connect_clc(smc, SMC_TYPE_R, &aclc, ibdev, ibport);
568-
if (rc)
688+
rc = smc_connect_clc(smc, smc_type, &aclc, ibdev, ibport, ismdev);
689+
if (rc) {
690+
smc_connect_ism_vlan_cleanup(smc, ism_supported, ismdev, vlan);
569691
return smc_connect_decline_fallback(smc, rc);
692+
}
570693

571-
/* connect using rdma */
572-
rc = smc_connect_rdma(smc, &aclc, ibdev, ibport);
573-
if (rc)
694+
/* depending on previous steps, connect using rdma or ism */
695+
if (rdma_supported && aclc.hdr.path == SMC_TYPE_R)
696+
rc = smc_connect_rdma(smc, &aclc, ibdev, ibport);
697+
else if (ism_supported && aclc.hdr.path == SMC_TYPE_D)
698+
rc = smc_connect_ism(smc, &aclc, ismdev);
699+
else
700+
rc = SMC_CLC_DECL_CNFERR;
701+
if (rc) {
702+
smc_connect_ism_vlan_cleanup(smc, ism_supported, ismdev, vlan);
574703
return smc_connect_decline_fallback(smc, rc);
704+
}
575705

706+
smc_connect_ism_vlan_cleanup(smc, ism_supported, ismdev, vlan);
576707
return 0;
577708
}
578709

@@ -909,6 +1040,44 @@ static int smc_listen_rdma_init(struct smc_sock *new_smc,
9091040
return 0;
9101041
}
9111042

1043+
/* listen worker: initialize connection and buffers for SMC-D */
1044+
static int smc_listen_ism_init(struct smc_sock *new_smc,
1045+
struct smc_clc_msg_proposal *pclc,
1046+
struct smcd_dev *ismdev,
1047+
int *local_contact)
1048+
{
1049+
struct smc_clc_msg_smcd *pclc_smcd;
1050+
1051+
pclc_smcd = smc_get_clc_msg_smcd(pclc);
1052+
*local_contact = smc_conn_create(new_smc, true, 0, NULL, 0, NULL,
1053+
ismdev, pclc_smcd->gid);
1054+
if (*local_contact < 0) {
1055+
if (*local_contact == -ENOMEM)
1056+
return SMC_CLC_DECL_MEM;/* insufficient memory*/
1057+
return SMC_CLC_DECL_INTERR; /* other error */
1058+
}
1059+
1060+
/* Check if peer can be reached via ISM device */
1061+
if (smc_ism_cantalk(new_smc->conn.lgr->peer_gid,
1062+
new_smc->conn.lgr->vlan_id,
1063+
new_smc->conn.lgr->smcd)) {
1064+
if (*local_contact == SMC_FIRST_CONTACT)
1065+
smc_lgr_forget(new_smc->conn.lgr);
1066+
smc_conn_free(&new_smc->conn);
1067+
return SMC_CLC_DECL_CNFERR;
1068+
}
1069+
1070+
/* Create send and receive buffers */
1071+
if (smc_buf_create(new_smc, true)) {
1072+
if (*local_contact == SMC_FIRST_CONTACT)
1073+
smc_lgr_forget(new_smc->conn.lgr);
1074+
smc_conn_free(&new_smc->conn);
1075+
return SMC_CLC_DECL_MEM;
1076+
}
1077+
1078+
return 0;
1079+
}
1080+
9121081
/* listen worker: register buffers */
9131082
static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact)
9141083
{
@@ -967,6 +1136,8 @@ static void smc_listen_work(struct work_struct *work)
9671136
struct smc_clc_msg_accept_confirm cclc;
9681137
struct smc_clc_msg_proposal *pclc;
9691138
struct smc_ib_device *ibdev;
1139+
bool ism_supported = false;
1140+
struct smcd_dev *ismdev;
9701141
u8 buf[SMC_CLC_MAX_LEN];
9711142
int local_contact = 0;
9721143
int reason_code = 0;
@@ -1007,13 +1178,21 @@ static void smc_listen_work(struct work_struct *work)
10071178
smc_rx_init(new_smc);
10081179
smc_tx_init(new_smc);
10091180

1181+
/* check if ISM is available */
1182+
if ((pclc->hdr.path == SMC_TYPE_D || pclc->hdr.path == SMC_TYPE_B) &&
1183+
!smc_check_ism(new_smc, &ismdev) &&
1184+
!smc_listen_ism_init(new_smc, pclc, ismdev, &local_contact)) {
1185+
ism_supported = true;
1186+
}
1187+
10101188
/* check if RDMA is available */
1011-
if ((pclc->hdr.path != SMC_TYPE_R && pclc->hdr.path != SMC_TYPE_B) ||
1012-
smc_check_rdma(new_smc, &ibdev, &ibport) ||
1013-
smc_listen_rdma_check(new_smc, pclc) ||
1014-
smc_listen_rdma_init(new_smc, pclc, ibdev, ibport,
1015-
&local_contact) ||
1016-
smc_listen_rdma_reg(new_smc, local_contact)) {
1189+
if (!ism_supported &&
1190+
((pclc->hdr.path != SMC_TYPE_R && pclc->hdr.path != SMC_TYPE_B) ||
1191+
smc_check_rdma(new_smc, &ibdev, &ibport) ||
1192+
smc_listen_rdma_check(new_smc, pclc) ||
1193+
smc_listen_rdma_init(new_smc, pclc, ibdev, ibport,
1194+
&local_contact) ||
1195+
smc_listen_rdma_reg(new_smc, local_contact))) {
10171196
/* SMC not supported, decline */
10181197
mutex_unlock(&smc_create_lgr_pending);
10191198
smc_listen_decline(new_smc, SMC_CLC_DECL_CNFERR, local_contact);
@@ -1038,7 +1217,8 @@ static void smc_listen_work(struct work_struct *work)
10381217
}
10391218

10401219
/* finish worker */
1041-
smc_listen_rdma_finish(new_smc, &cclc, local_contact);
1220+
if (!ism_supported)
1221+
smc_listen_rdma_finish(new_smc, &cclc, local_contact);
10421222
smc_conn_save_peer_info(new_smc, &cclc);
10431223
mutex_unlock(&smc_create_lgr_pending);
10441224
smc_listen_out_connected(new_smc);

net/smc/smc_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid)
478478
/* Determine vlan of internal TCP socket.
479479
* @vlan_id: address to store the determined vlan id into
480480
*/
481-
static int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id)
481+
int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id)
482482
{
483483
struct dst_entry *dst = sk_dst_get(clcsock->sk);
484484
struct net_device *ndev;

net/smc/smc_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ void smc_sndbuf_sync_sg_for_cpu(struct smc_connection *conn);
257257
void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn);
258258
void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn);
259259
void smc_rmb_sync_sg_for_device(struct smc_connection *conn);
260+
int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id);
260261

261262
void smc_conn_free(struct smc_connection *conn);
262263
int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,

0 commit comments

Comments
 (0)