net/smc: prepare for SMC-Rv2 connection
authorKarsten Graul <kgraul@linux.ibm.com>
Sat, 16 Oct 2021 09:37:44 +0000 (11:37 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 16 Oct 2021 13:58:12 +0000 (14:58 +0100)
Prepare the connection establishment with SMC-Rv2. Detect eligible
RoCE cards and indicate all supported SMC modes for the connection.

Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/smc/af_smc.c
net/smc/smc_clc.c
net/smc/smc_clc.h
net/smc/smc_core.h

index f69ef3f..f21e745 100644 (file)
@@ -608,7 +608,9 @@ static int smc_find_rdma_device(struct smc_sock *smc, struct smc_init_info *ini)
         * used for the internal TCP socket
         */
        smc_pnet_find_roce_resource(smc->clcsock->sk, ini);
-       if (!ini->ib_dev)
+       if (!ini->check_smcrv2 && !ini->ib_dev)
+               return SMC_CLC_DECL_NOSMCRDEV;
+       if (ini->check_smcrv2 && !ini->smcrv2.ib_dev_v2)
                return SMC_CLC_DECL_NOSMCRDEV;
        return 0;
 }
@@ -692,27 +694,42 @@ static int smc_find_proposal_devices(struct smc_sock *smc,
        int rc = 0;
 
        /* check if there is an ism device available */
-       if (ini->smcd_version & SMC_V1) {
-               if (smc_find_ism_device(smc, ini) ||
-                   smc_connect_ism_vlan_setup(smc, ini)) {
-                       if (ini->smc_type_v1 == SMC_TYPE_B)
-                               ini->smc_type_v1 = SMC_TYPE_R;
-                       else
-                               ini->smc_type_v1 = SMC_TYPE_N;
-               } /* else ISM V1 is supported for this connection */
-               if (smc_find_rdma_device(smc, ini)) {
-                       if (ini->smc_type_v1 == SMC_TYPE_B)
-                               ini->smc_type_v1 = SMC_TYPE_D;
-                       else
-                               ini->smc_type_v1 = SMC_TYPE_N;
-               } /* else RDMA is supported for this connection */
-       }
-       if (smc_ism_is_v2_capable() && smc_find_ism_v2_device_clnt(smc, ini))
-               ini->smc_type_v2 = SMC_TYPE_N;
+       if (!(ini->smcd_version & SMC_V1) ||
+           smc_find_ism_device(smc, ini) ||
+           smc_connect_ism_vlan_setup(smc, ini))
+               ini->smcd_version &= ~SMC_V1;
+       /* else ISM V1 is supported for this connection */
+
+       /* check if there is an rdma device available */
+       if (!(ini->smcr_version & SMC_V1) ||
+           smc_find_rdma_device(smc, ini))
+               ini->smcr_version &= ~SMC_V1;
+       /* else RDMA is supported for this connection */
+
+       ini->smc_type_v1 = smc_indicated_type(ini->smcd_version & SMC_V1,
+                                             ini->smcr_version & SMC_V1);
+
+       /* check if there is an ism v2 device available */
+       if (!(ini->smcd_version & SMC_V2) ||
+           !smc_ism_is_v2_capable() ||
+           smc_find_ism_v2_device_clnt(smc, ini))
+               ini->smcd_version &= ~SMC_V2;
+
+       /* check if there is an rdma v2 device available */
+       ini->check_smcrv2 = true;
+       ini->smcrv2.saddr = smc->clcsock->sk->sk_rcv_saddr;
+       if (!(ini->smcr_version & SMC_V2) ||
+           smc->clcsock->sk->sk_family != AF_INET ||
+           !smc_clc_ueid_count() ||
+           smc_find_rdma_device(smc, ini))
+               ini->smcr_version &= ~SMC_V2;
+       ini->check_smcrv2 = false;
+
+       ini->smc_type_v2 = smc_indicated_type(ini->smcd_version & SMC_V2,
+                                             ini->smcr_version & SMC_V2);
 
        /* if neither ISM nor RDMA are supported, fallback */
-       if (!smcr_indicated(ini->smc_type_v1) &&
-           ini->smc_type_v1 == SMC_TYPE_N && ini->smc_type_v2 == SMC_TYPE_N)
+       if (ini->smc_type_v1 == SMC_TYPE_N && ini->smc_type_v2 == SMC_TYPE_N)
                rc = SMC_CLC_DECL_NOSMCDEV;
 
        return rc;
@@ -950,17 +967,24 @@ connect_abort:
 static int smc_connect_check_aclc(struct smc_init_info *ini,
                                  struct smc_clc_msg_accept_confirm *aclc)
 {
-       if ((aclc->hdr.typev1 == SMC_TYPE_R &&
-            !smcr_indicated(ini->smc_type_v1)) ||
-           (aclc->hdr.typev1 == SMC_TYPE_D &&
-            ((!smcd_indicated(ini->smc_type_v1) &&
-              !smcd_indicated(ini->smc_type_v2)) ||
-             (aclc->hdr.version == SMC_V1 &&
-              !smcd_indicated(ini->smc_type_v1)) ||
-             (aclc->hdr.version == SMC_V2 &&
-              !smcd_indicated(ini->smc_type_v2)))))
+       if (aclc->hdr.typev1 != SMC_TYPE_R &&
+           aclc->hdr.typev1 != SMC_TYPE_D)
                return SMC_CLC_DECL_MODEUNSUPP;
 
+       if (aclc->hdr.version >= SMC_V2) {
+               if ((aclc->hdr.typev1 == SMC_TYPE_R &&
+                    !smcr_indicated(ini->smc_type_v2)) ||
+                   (aclc->hdr.typev1 == SMC_TYPE_D &&
+                    !smcd_indicated(ini->smc_type_v2)))
+                       return SMC_CLC_DECL_MODEUNSUPP;
+       } else {
+               if ((aclc->hdr.typev1 == SMC_TYPE_R &&
+                    !smcr_indicated(ini->smc_type_v1)) ||
+                   (aclc->hdr.typev1 == SMC_TYPE_D &&
+                    !smcd_indicated(ini->smc_type_v1)))
+                       return SMC_CLC_DECL_MODEUNSUPP;
+       }
+
        return 0;
 }
 
@@ -991,14 +1015,15 @@ static int __smc_connect(struct smc_sock *smc)
                return smc_connect_decline_fallback(smc, SMC_CLC_DECL_MEM,
                                                    version);
 
-       ini->smcd_version = SMC_V1;
-       ini->smcd_version |= smc_ism_is_v2_capable() ? SMC_V2 : 0;
+       ini->smcd_version = SMC_V1 | SMC_V2;
+       ini->smcr_version = SMC_V1 | SMC_V2;
        ini->smc_type_v1 = SMC_TYPE_B;
-       ini->smc_type_v2 = smc_ism_is_v2_capable() ? SMC_TYPE_D : SMC_TYPE_N;
+       ini->smc_type_v2 = SMC_TYPE_B;
 
        /* get vlan id from IP device */
        if (smc_vlan_by_tcpsk(smc->clcsock, ini)) {
                ini->smcd_version &= ~SMC_V1;
+               ini->smcr_version = 0;
                ini->smc_type_v1 = SMC_TYPE_N;
                if (!ini->smcd_version) {
                        rc = SMC_CLC_DECL_GETVLANERR;
@@ -1026,15 +1051,17 @@ static int __smc_connect(struct smc_sock *smc)
        /* check if smc modes and versions of CLC proposal and accept match */
        rc = smc_connect_check_aclc(ini, aclc);
        version = aclc->hdr.version == SMC_V1 ? SMC_V1 : SMC_V2;
-       ini->smcd_version = version;
        if (rc)
                goto vlan_cleanup;
 
        /* depending on previous steps, connect using rdma or ism */
-       if (aclc->hdr.typev1 == SMC_TYPE_R)
+       if (aclc->hdr.typev1 == SMC_TYPE_R) {
+               ini->smcr_version = version;
                rc = smc_connect_rdma(smc, aclc, ini);
-       else if (aclc->hdr.typev1 == SMC_TYPE_D)
+       } else if (aclc->hdr.typev1 == SMC_TYPE_D) {
+               ini->smcd_version = version;
                rc = smc_connect_ism(smc, aclc, ini);
+       }
        if (rc)
                goto vlan_cleanup;
 
index 1cc8a76..8d44f06 100644 (file)
@@ -114,6 +114,17 @@ err_out:
        return rc;
 }
 
+int smc_clc_ueid_count(void)
+{
+       int count;
+
+       read_lock(&smc_clc_eid_table.lock);
+       count = smc_clc_eid_table.ueid_cnt;
+       read_unlock(&smc_clc_eid_table.lock);
+
+       return count;
+}
+
 int smc_nl_add_ueid(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *nla_ueid = info->attrs[SMC_NLA_EID_TABLE_ENTRY];
index 974d01d..37ce97f 100644 (file)
@@ -282,6 +282,17 @@ static inline bool smcd_indicated(int smc_type)
        return smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B;
 }
 
+static inline u8 smc_indicated_type(int is_smcd, int is_smcr)
+{
+       if (is_smcd && is_smcr)
+               return SMC_TYPE_B;
+       if (is_smcd)
+               return SMC_TYPE_D;
+       if (is_smcr)
+               return SMC_TYPE_R;
+       return SMC_TYPE_N;
+}
+
 /* get SMC-D info from proposal message */
 static inline struct smc_clc_msg_smcd *
 smc_get_clc_msg_smcd(struct smc_clc_msg_proposal *prop)
@@ -343,6 +354,7 @@ void smc_clc_get_hostname(u8 **host);
 bool smc_clc_match_eid(u8 *negotiated_eid,
                       struct smc_clc_v2_extension *smc_v2_ext,
                       u8 *peer_eid, u8 *local_eid);
+int smc_clc_ueid_count(void);
 int smc_nl_dump_ueid(struct sk_buff *skb, struct netlink_callback *cb);
 int smc_nl_add_ueid(struct sk_buff *skb, struct genl_info *info);
 int smc_nl_remove_ueid(struct sk_buff *skb, struct genl_info *info);
index 83d30b0..4a1778a 100644 (file)
@@ -302,6 +302,31 @@ struct smc_link_group {
 
 struct smc_clc_msg_local;
 
+#define GID_LIST_SIZE  2
+
+struct smc_gidlist {
+       u8                      len;
+       u8                      list[GID_LIST_SIZE][SMC_GID_SIZE];
+};
+
+struct smc_init_info_smcrv2 {
+       /* Input fields */
+       __be32                  saddr;
+       struct sock             *clc_sk;
+       __be32                  daddr;
+
+       /* Output fields when saddr is set */
+       struct smc_ib_device    *ib_dev_v2;
+       u8                      ib_port_v2;
+       u8                      ib_gid_v2[SMC_GID_SIZE];
+
+       /* Additional output fields when clc_sk and daddr is set as well */
+       u8                      uses_gateway;
+       u8                      nexthop_mac[ETH_ALEN];
+
+       struct smc_gidlist      gidlist;
+};
+
 struct smc_init_info {
        u8                      is_smcd;
        u8                      smc_type_v1;
@@ -313,10 +338,13 @@ struct smc_init_info {
        u8                      negotiated_eid[SMC_MAX_EID_LEN];
        /* SMC-R */
        struct smc_clc_msg_local *ib_lcl;
+       u8                      smcr_version;
+       u8                      check_smcrv2;
        struct smc_ib_device    *ib_dev;
        u8                      ib_gid[SMC_GID_SIZE];
        u8                      ib_port;
        u32                     ib_clcqpn;
+       struct smc_init_info_smcrv2 smcrv2;
        /* SMC-D */
        u64                     ism_peer_gid[SMC_MAX_ISM_DEVS + 1];
        struct smcd_dev         *ism_dev[SMC_MAX_ISM_DEVS + 1];