Commit 42042dbb authored by Karsten Graul's avatar Karsten Graul Committed by David S. Miller
Browse files

net/smc: prepare for SMC-Rv2 connection



Prepare the connection establishment with SMC-Rv2. Detect eligible
RoCE cards and indicate all supported SMC modes for the connection.

Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ed990df2
Loading
Loading
Loading
Loading
+62 −35
Original line number Diff line number Diff line
@@ -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,16 +967,23 @@ static int smc_connect_ism(struct smc_sock *smc,
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 &&
	    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) &&
	       !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)))))
		     !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;

+11 −0
Original line number Diff line number Diff line
@@ -114,6 +114,17 @@ static int smc_clc_ueid_add(char *ueid)
	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];
+12 −0
Original line number Diff line number Diff line
@@ -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);
+28 −0
Original line number Diff line number Diff line
@@ -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];