aboutsummaryrefslogtreecommitdiffstats
path: root/net/smc
diff options
context:
space:
mode:
authorHans Wippel <hwippel@linux.ibm.com>2018-06-28 13:05:11 -0400
committerDavid S. Miller <davem@davemloft.net>2018-06-30 07:42:26 -0400
commit413498440e30bfe381ac99dfc31628a3d8d4382a (patch)
tree57f5c081e80000c02c1a0387f067b02a15cdfc2d /net/smc
parentbe244f28d22f77d939ba2b973c102ad2b49d3496 (diff)
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 <hwippel@linux.ibm.com> Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Suggested-by: Thomas Richter <tmricht@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/smc')
-rw-r--r--net/smc/af_smc.c216
-rw-r--r--net/smc/smc_core.c2
-rw-r--r--net/smc/smc_core.h1
3 files changed, 200 insertions, 19 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 20afa94be8bb..cbbb947dbfcf 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -23,6 +23,7 @@
23#include <linux/workqueue.h> 23#include <linux/workqueue.h>
24#include <linux/in.h> 24#include <linux/in.h>
25#include <linux/sched/signal.h> 25#include <linux/sched/signal.h>
26#include <linux/if_vlan.h>
26 27
27#include <net/sock.h> 28#include <net/sock.h>
28#include <net/tcp.h> 29#include <net/tcp.h>
@@ -35,6 +36,7 @@
35#include "smc_cdc.h" 36#include "smc_cdc.h"
36#include "smc_core.h" 37#include "smc_core.h"
37#include "smc_ib.h" 38#include "smc_ib.h"
39#include "smc_ism.h"
38#include "smc_pnet.h" 40#include "smc_pnet.h"
39#include "smc_tx.h" 41#include "smc_tx.h"
40#include "smc_rx.h" 42#include "smc_rx.h"
@@ -372,8 +374,8 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc)
372 return 0; 374 return 0;
373} 375}
374 376
375static void smc_conn_save_peer_info(struct smc_sock *smc, 377static void smcr_conn_save_peer_info(struct smc_sock *smc,
376 struct smc_clc_msg_accept_confirm *clc) 378 struct smc_clc_msg_accept_confirm *clc)
377{ 379{
378 int bufsize = smc_uncompress_bufsize(clc->rmbe_size); 380 int bufsize = smc_uncompress_bufsize(clc->rmbe_size);
379 381
@@ -384,6 +386,28 @@ static void smc_conn_save_peer_info(struct smc_sock *smc,
384 smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1); 386 smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1);
385} 387}
386 388
389static 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
402static 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
387static void smc_link_save_peer_info(struct smc_link *link, 411static void smc_link_save_peer_info(struct smc_link *link,
388 struct smc_clc_msg_accept_confirm *clc) 412 struct smc_clc_msg_accept_confirm *clc)
389{ 413{
@@ -450,15 +474,51 @@ static int smc_check_rdma(struct smc_sock *smc, struct smc_ib_device **ibdev,
450 return reason_code; 474 return reason_code;
451} 475}
452 476
477/* check if there is an ISM device available for this connection. */
478/* called for connect and listen */
479static 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 */
489static 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 */
501static 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
453/* CLC handshake during connect */ 512/* CLC handshake during connect */
454static int smc_connect_clc(struct smc_sock *smc, int smc_type, 513static int smc_connect_clc(struct smc_sock *smc, int smc_type,
455 struct smc_clc_msg_accept_confirm *aclc, 514 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)
457{ 517{
458 int rc = 0; 518 int rc = 0;
459 519
460 /* do inband token exchange */ 520 /* 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);
462 if (rc) 522 if (rc)
463 return rc; 523 return rc;
464 /* receive SMC Accept CLC message */ 524 /* receive SMC Accept CLC message */
@@ -538,11 +598,50 @@ static int smc_connect_rdma(struct smc_sock *smc,
538 return 0; 598 return 0;
539} 599}
540 600
601/* setup for ISM connection of client */
602static 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
541/* perform steps before actually connecting */ 636/* perform steps before actually connecting */
542static int __smc_connect(struct smc_sock *smc) 637static int __smc_connect(struct smc_sock *smc)
543{ 638{
639 bool ism_supported = false, rdma_supported = false;
544 struct smc_clc_msg_accept_confirm aclc; 640 struct smc_clc_msg_accept_confirm aclc;
545 struct smc_ib_device *ibdev; 641 struct smc_ib_device *ibdev;
642 struct smcd_dev *ismdev;
643 unsigned short vlan;
644 int smc_type;
546 int rc = 0; 645 int rc = 0;
547 u8 ibport; 646 u8 ibport;
548 647
@@ -559,20 +658,52 @@ static int __smc_connect(struct smc_sock *smc)
559 if (using_ipsec(smc)) 658 if (using_ipsec(smc))
560 return smc_connect_decline_fallback(smc, SMC_CLC_DECL_IPSEC); 659 return smc_connect_decline_fallback(smc, SMC_CLC_DECL_IPSEC);
561 660
562 /* check if a RDMA device is available; if not, fall back */ 661 /* check for VLAN ID */
563 if (smc_check_rdma(smc, &ibdev, &ibport)) 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)
564 return smc_connect_decline_fallback(smc, SMC_CLC_DECL_CNFERR); 685 return smc_connect_decline_fallback(smc, SMC_CLC_DECL_CNFERR);
565 686
566 /* perform CLC handshake */ 687 /* perform CLC handshake */
567 rc = smc_connect_clc(smc, SMC_TYPE_R, &aclc, ibdev, ibport); 688 rc = smc_connect_clc(smc, smc_type, &aclc, ibdev, ibport, ismdev);
568 if (rc) 689 if (rc) {
690 smc_connect_ism_vlan_cleanup(smc, ism_supported, ismdev, vlan);
569 return smc_connect_decline_fallback(smc, rc); 691 return smc_connect_decline_fallback(smc, rc);
692 }
570 693
571 /* connect using rdma */ 694 /* depending on previous steps, connect using rdma or ism */
572 rc = smc_connect_rdma(smc, &aclc, ibdev, ibport); 695 if (rdma_supported && aclc.hdr.path == SMC_TYPE_R)
573 if (rc) 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);
574 return smc_connect_decline_fallback(smc, rc); 703 return smc_connect_decline_fallback(smc, rc);
704 }
575 705
706 smc_connect_ism_vlan_cleanup(smc, ism_supported, ismdev, vlan);
576 return 0; 707 return 0;
577} 708}
578 709
@@ -909,6 +1040,44 @@ static int smc_listen_rdma_init(struct smc_sock *new_smc,
909 return 0; 1040 return 0;
910} 1041}
911 1042
1043/* listen worker: initialize connection and buffers for SMC-D */
1044static 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
912/* listen worker: register buffers */ 1081/* listen worker: register buffers */
913static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact) 1082static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact)
914{ 1083{
@@ -967,6 +1136,8 @@ static void smc_listen_work(struct work_struct *work)
967 struct smc_clc_msg_accept_confirm cclc; 1136 struct smc_clc_msg_accept_confirm cclc;
968 struct smc_clc_msg_proposal *pclc; 1137 struct smc_clc_msg_proposal *pclc;
969 struct smc_ib_device *ibdev; 1138 struct smc_ib_device *ibdev;
1139 bool ism_supported = false;
1140 struct smcd_dev *ismdev;
970 u8 buf[SMC_CLC_MAX_LEN]; 1141 u8 buf[SMC_CLC_MAX_LEN];
971 int local_contact = 0; 1142 int local_contact = 0;
972 int reason_code = 0; 1143 int reason_code = 0;
@@ -1007,13 +1178,21 @@ static void smc_listen_work(struct work_struct *work)
1007 smc_rx_init(new_smc); 1178 smc_rx_init(new_smc);
1008 smc_tx_init(new_smc); 1179 smc_tx_init(new_smc);
1009 1180
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
1010 /* check if RDMA is available */ 1188 /* check if RDMA is available */
1011 if ((pclc->hdr.path != SMC_TYPE_R && pclc->hdr.path != SMC_TYPE_B) || 1189 if (!ism_supported &&
1012 smc_check_rdma(new_smc, &ibdev, &ibport) || 1190 ((pclc->hdr.path != SMC_TYPE_R && pclc->hdr.path != SMC_TYPE_B) ||
1013 smc_listen_rdma_check(new_smc, pclc) || 1191 smc_check_rdma(new_smc, &ibdev, &ibport) ||
1014 smc_listen_rdma_init(new_smc, pclc, ibdev, ibport, 1192 smc_listen_rdma_check(new_smc, pclc) ||
1015 &local_contact) || 1193 smc_listen_rdma_init(new_smc, pclc, ibdev, ibport,
1016 smc_listen_rdma_reg(new_smc, local_contact)) { 1194 &local_contact) ||
1195 smc_listen_rdma_reg(new_smc, local_contact))) {
1017 /* SMC not supported, decline */ 1196 /* SMC not supported, decline */
1018 mutex_unlock(&smc_create_lgr_pending); 1197 mutex_unlock(&smc_create_lgr_pending);
1019 smc_listen_decline(new_smc, SMC_CLC_DECL_CNFERR, local_contact); 1198 smc_listen_decline(new_smc, SMC_CLC_DECL_CNFERR, local_contact);
@@ -1038,7 +1217,8 @@ static void smc_listen_work(struct work_struct *work)
1038 } 1217 }
1039 1218
1040 /* finish worker */ 1219 /* 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);
1042 smc_conn_save_peer_info(new_smc, &cclc); 1222 smc_conn_save_peer_info(new_smc, &cclc);
1043 mutex_unlock(&smc_create_lgr_pending); 1223 mutex_unlock(&smc_create_lgr_pending);
1044 smc_listen_out_connected(new_smc); 1224 smc_listen_out_connected(new_smc);
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index 434c028162a4..66741e61a3b0 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -478,7 +478,7 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid)
478/* Determine vlan of internal TCP socket. 478/* Determine vlan of internal TCP socket.
479 * @vlan_id: address to store the determined vlan id into 479 * @vlan_id: address to store the determined vlan id into
480 */ 480 */
481static int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id) 481int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id)
482{ 482{
483 struct dst_entry *dst = sk_dst_get(clcsock->sk); 483 struct dst_entry *dst = sk_dst_get(clcsock->sk);
484 struct net_device *ndev; 484 struct net_device *ndev;
diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h
index cd9268a9570e..8b47e0168fc3 100644
--- a/net/smc/smc_core.h
+++ b/net/smc/smc_core.h
@@ -257,6 +257,7 @@ void smc_sndbuf_sync_sg_for_cpu(struct smc_connection *conn);
257void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn); 257void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn);
258void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn); 258void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn);
259void smc_rmb_sync_sg_for_device(struct smc_connection *conn); 259void smc_rmb_sync_sg_for_device(struct smc_connection *conn);
260int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id);
260 261
261void smc_conn_free(struct smc_connection *conn); 262void smc_conn_free(struct smc_connection *conn);
262int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact, 263int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,