diff options
author | Hans Wippel <hwippel@linux.ibm.com> | 2018-06-28 13:05:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-06-30 07:42:26 -0400 |
commit | 413498440e30bfe381ac99dfc31628a3d8d4382a (patch) | |
tree | 57f5c081e80000c02c1a0387f067b02a15cdfc2d /net/smc | |
parent | be244f28d22f77d939ba2b973c102ad2b49d3496 (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.c | 216 | ||||
-rw-r--r-- | net/smc/smc_core.c | 2 | ||||
-rw-r--r-- | net/smc/smc_core.h | 1 |
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 | ||
375 | static void smc_conn_save_peer_info(struct smc_sock *smc, | 377 | static 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 | ||
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 | |||
387 | static void smc_link_save_peer_info(struct smc_link *link, | 411 | static 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 */ | ||
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 | |||
453 | /* CLC handshake during connect */ | 512 | /* CLC handshake during connect */ |
454 | static int smc_connect_clc(struct smc_sock *smc, int smc_type, | 513 | static 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 */ | ||
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 | |||
541 | /* perform steps before actually connecting */ | 636 | /* perform steps before actually connecting */ |
542 | static int __smc_connect(struct smc_sock *smc) | 637 | static 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 */ | ||
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 | |||
912 | /* listen worker: register buffers */ | 1081 | /* listen worker: register buffers */ |
913 | static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact) | 1082 | static 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 | */ |
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) |
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); | |||
257 | void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn); | 257 | void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn); |
258 | void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn); | 258 | void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn); |
259 | void smc_rmb_sync_sg_for_device(struct smc_connection *conn); | 259 | void smc_rmb_sync_sg_for_device(struct smc_connection *conn); |
260 | int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id); | ||
260 | 261 | ||
261 | void smc_conn_free(struct smc_connection *conn); | 262 | void smc_conn_free(struct smc_connection *conn); |
262 | int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact, | 263 | int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact, |