Commit 5b0a1414 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'smc-features'



Guangguan Wang says:

====================
net/smc: several features's implementation for smc v2.1

This patch set implement several new features in SMC v2.1(https://
www.ibm.com/support/pages/node/7009315), including vendor unique
experimental options, max connections per lgr negotiation, max links
per lgr negotiation.

v1 - v2:
 - rename field fce_v20 to fce_v2_base in struct
   smc_clc_first_contact_ext_v2x
 - use smc_get_clc_first_contact_ext in smc_connect
   _rdma_v2_prepare
 - adding comment about field vendor_oui in struct
   smc_clc_msg_smcd
 - remove comment about SMC_CONN_PER_LGR_MAX in smc_
   clc_srv_v2x_features_validate
 - rename smc_clc_clnt_v2x_features_validate

RFC v2 - v1:
 - more description in commit message
 - modify SMC_CONN_PER_LGR_xxx and SMC_LINKS_ADD_LNK_xxx
   macro defination and usage
 - rename field release_ver to release_nr
 - remove redundant release version check in client
 - explicitly set the rc value in smc_llc_cli/srv_add_link

RFC v1 - RFC v2:
 - Remove ini pointer NULL check and fix code style in
   smc_clc_send_confirm_accept.
 - Optimize the max_conns check in smc_clc_xxx_v2x_features_validate.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cb49ec03 bbed596c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -107,6 +107,8 @@ enum {
enum {
	SMC_NLA_LGR_R_V2_UNSPEC,
	SMC_NLA_LGR_R_V2_DIRECT,	/* u8 */
	SMC_NLA_LGR_R_V2_MAX_CONNS,	/* u8 */
	SMC_NLA_LGR_R_V2_MAX_LINKS,	/* u8 */
	__SMC_NLA_LGR_R_V2_MAX,
	SMC_NLA_LGR_R_V2_MAX = __SMC_NLA_LGR_R_V2_MAX - 1
};
+64 −22
Original line number Diff line number Diff line
@@ -641,6 +641,7 @@ static int smcr_clnt_conf_first_link(struct smc_sock *smc)
	smc_llc_link_active(link);
	smcr_lgr_set_type(link->lgr, SMC_LGR_SINGLE);

	if (link->lgr->max_links > 1) {
		/* optional 2nd link, receive ADD LINK request from server */
		qentry = smc_llc_wait(link->lgr, NULL, SMC_LLC_WAIT_TIME,
				      SMC_LLC_ADD_LINK);
@@ -655,6 +656,7 @@ static int smcr_clnt_conf_first_link(struct smc_sock *smc)
		}
		smc_llc_flow_qentry_clr(&link->lgr->llc_flow_lcl);
		smc_llc_cli_add_link(link, qentry);
	}
	return 0;
}

@@ -1144,7 +1146,7 @@ static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc,

#define SMC_CLC_MAX_ACCEPT_LEN \
	(sizeof(struct smc_clc_msg_accept_confirm_v2) + \
	 sizeof(struct smc_clc_first_contact_ext) + \
	 sizeof(struct smc_clc_first_contact_ext_v2x) + \
	 sizeof(struct smc_clc_msg_trail))

/* CLC handshake during connect */
@@ -1198,8 +1200,8 @@ static int smc_connect_rdma_v2_prepare(struct smc_sock *smc,
	struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
		(struct smc_clc_msg_accept_confirm_v2 *)aclc;
	struct smc_clc_first_contact_ext *fce =
		(struct smc_clc_first_contact_ext *)
			(((u8 *)clc_v2) + sizeof(*clc_v2));
		smc_get_clc_first_contact_ext(clc_v2, false);
	int rc;

	if (!ini->first_contact_peer || aclc->hdr.version == SMC_V1)
		return 0;
@@ -1218,6 +1220,12 @@ static int smc_connect_rdma_v2_prepare(struct smc_sock *smc,
			return SMC_CLC_DECL_NOINDIRECT;
		}
	}

	ini->release_nr = fce->release;
	rc = smc_clc_clnt_v2x_features_validate(fce, ini);
	if (rc)
		return rc;

	return 0;
}

@@ -1236,6 +1244,8 @@ static int smc_connect_rdma(struct smc_sock *smc,
	memcpy(ini->peer_systemid, aclc->r0.lcl.id_for_peer, SMC_SYSTEMID_LEN);
	memcpy(ini->peer_gid, aclc->r0.lcl.gid, SMC_GID_SIZE);
	memcpy(ini->peer_mac, aclc->r0.lcl.mac, ETH_ALEN);
	ini->max_conns = SMC_CONN_PER_LGR_MAX;
	ini->max_links = SMC_LINKS_ADD_LNK_MAX;

	reason_code = smc_connect_rdma_v2_prepare(smc, aclc, ini);
	if (reason_code)
@@ -1386,6 +1396,16 @@ static int smc_connect_ism(struct smc_sock *smc,
		struct smc_clc_msg_accept_confirm_v2 *aclc_v2 =
			(struct smc_clc_msg_accept_confirm_v2 *)aclc;

		if (ini->first_contact_peer) {
			struct smc_clc_first_contact_ext *fce =
				smc_get_clc_first_contact_ext(aclc_v2, true);

			ini->release_nr = fce->release;
			rc = smc_clc_clnt_v2x_features_validate(fce, ini);
			if (rc)
				return rc;
		}

		rc = smc_v2_determine_accepted_chid(aclc_v2, ini);
		if (rc)
			return rc;
@@ -1420,7 +1440,7 @@ static int smc_connect_ism(struct smc_sock *smc,
	}

	rc = smc_clc_send_confirm(smc, ini->first_contact_local,
				  aclc->hdr.version, eid, NULL);
				  aclc->hdr.version, eid, ini);
	if (rc)
		goto connect_abort;
	mutex_unlock(&smc_server_lgr_pending);
@@ -1870,10 +1890,12 @@ static int smcr_serv_conf_first_link(struct smc_sock *smc)
	smc_llc_link_active(link);
	smcr_lgr_set_type(link->lgr, SMC_LGR_SINGLE);

	if (link->lgr->max_links > 1) {
		down_write(&link->lgr->llc_conf_mutex);
		/* initial contact - try to establish second link */
		smc_llc_srv_add_link(link, NULL);
		up_write(&link->lgr->llc_conf_mutex);
	}
	return 0;
}

@@ -1996,6 +2018,10 @@ static int smc_listen_v2_check(struct smc_sock *new_smc,
		}
	}

	ini->release_nr = pclc_v2_ext->hdr.flag.release;
	if (pclc_v2_ext->hdr.flag.release > SMC_RELEASE)
		ini->release_nr = SMC_RELEASE;

out:
	if (!ini->smcd_version && !ini->smcr_version)
		return rc;
@@ -2430,6 +2456,10 @@ static void smc_listen_work(struct work_struct *work)
	if (rc)
		goto out_decl;

	rc = smc_clc_srv_v2x_features_validate(pclc, ini);
	if (rc)
		goto out_decl;

	mutex_lock(&smc_server_lgr_pending);
	smc_close_init(new_smc);
	smc_rx_init(new_smc);
@@ -2443,7 +2473,7 @@ static void smc_listen_work(struct work_struct *work)
	/* send SMC Accept CLC message */
	accept_version = ini->is_smcd ? ini->smcd_version : ini->smcr_version;
	rc = smc_clc_send_accept(new_smc, ini->first_contact_local,
				 accept_version, ini->negotiated_eid);
				 accept_version, ini->negotiated_eid, ini);
	if (rc)
		goto out_unlock;

@@ -2462,6 +2492,18 @@ static void smc_listen_work(struct work_struct *work)
		goto out_decl;
	}

	rc = smc_clc_v2x_features_confirm_check(cclc, ini);
	if (rc) {
		if (!ini->is_smcd)
			goto out_unlock;
		goto out_decl;
	}

	/* fce smc release version is needed in smc_listen_rdma_finish,
	 * so save fce info here.
	 */
	smc_conn_save_peer_info_fce(new_smc, cclc);

	/* finish worker */
	if (!ini->is_smcd) {
		rc = smc_listen_rdma_finish(new_smc, cclc,
+4 −1
Original line number Diff line number Diff line
@@ -21,7 +21,10 @@

#define SMC_V1		1		/* SMC version V1 */
#define SMC_V2		2		/* SMC version V2 */
#define SMC_RELEASE	0

#define SMC_RELEASE_0 0
#define SMC_RELEASE_1 1
#define SMC_RELEASE	SMC_RELEASE_1 /* the latest release version */

#define SMCPROTO_SMC		0	/* SMC protocol, IPv4 */
#define SMCPROTO_SMC6		1	/* SMC protocol, IPv6 */
+122 −25
Original line number Diff line number Diff line
@@ -391,9 +391,7 @@ smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2)
			return false;
	} else {
		if (hdr->typev1 == SMC_TYPE_D &&
		    ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 &&
		    (ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 +
				sizeof(struct smc_clc_first_contact_ext)))
		    ntohs(hdr->length) < SMCD_CLC_ACCEPT_CONFIRM_LEN_V2)
			return false;
		if (hdr->typev1 == SMC_TYPE_R &&
		    ntohs(hdr->length) < SMCR_CLC_ACCEPT_CONFIRM_LEN_V2)
@@ -420,13 +418,29 @@ smc_clc_msg_decl_valid(struct smc_clc_msg_decline *dclc)
	return true;
}

static void smc_clc_fill_fce(struct smc_clc_first_contact_ext *fce, int *len)
static int smc_clc_fill_fce(struct smc_clc_first_contact_ext_v2x *fce,
			    struct smc_init_info *ini)
{
	int ret = sizeof(*fce);

	memset(fce, 0, sizeof(*fce));
	fce->os_type = SMC_CLC_OS_LINUX;
	fce->release = SMC_RELEASE;
	memcpy(fce->hostname, smc_hostname, sizeof(smc_hostname));
	(*len) += sizeof(*fce);
	fce->fce_v2_base.os_type = SMC_CLC_OS_LINUX;
	fce->fce_v2_base.release = ini->release_nr;
	memcpy(fce->fce_v2_base.hostname, smc_hostname, sizeof(smc_hostname));
	if (ini->is_smcd && ini->release_nr < SMC_RELEASE_1) {
		ret = sizeof(struct smc_clc_first_contact_ext);
		goto out;
	}

	if (ini->release_nr >= SMC_RELEASE_1) {
		if (!ini->is_smcd) {
			fce->max_conns = ini->max_conns;
			fce->max_links = ini->max_links;
		}
	}

out:
	return ret;
}

/* check if received message has a correct header length and contains valid
@@ -927,8 +941,11 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
				sizeof(struct smc_clc_smcd_gid_chid);
		}
	}
	if (smcr_indicated(ini->smc_type_v2))
	if (smcr_indicated(ini->smc_type_v2)) {
		memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE);
		v2_ext->max_conns = SMC_CONN_PER_LGR_PREFER;
		v2_ext->max_links = SMC_LINKS_PER_LGR_MAX_PREFER;
	}

	pclc_base->hdr.length = htons(plen);
	memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
@@ -986,13 +1003,13 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
				       u8 *eid, struct smc_init_info *ini)
{
	struct smc_connection *conn = &smc->conn;
	struct smc_clc_first_contact_ext_v2x fce;
	struct smc_clc_msg_accept_confirm *clc;
	struct smc_clc_first_contact_ext fce;
	struct smc_clc_fce_gid_ext gle;
	struct smc_clc_msg_trail trl;
	int i, len, fce_len;
	struct kvec vec[5];
	struct msghdr msg;
	int i, len;

	/* send SMC Confirm CLC msg */
	clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
@@ -1018,8 +1035,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
			if (eid && eid[0])
				memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
			len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
			if (first_contact)
				smc_clc_fill_fce(&fce, &len);
			if (first_contact) {
				fce_len = smc_clc_fill_fce(&fce, ini);
				len += fce_len;
			}
			clc_v2->hdr.length = htons(len);
		}
		memcpy(trl.eyecatcher, SMCD_EYECATCHER,
@@ -1063,15 +1082,14 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
				memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN);
			len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2;
			if (first_contact) {
				smc_clc_fill_fce(&fce, &len);
				fce.v2_direct = !link->lgr->uses_gateway;
				fce_len = smc_clc_fill_fce(&fce, ini);
				len += fce_len;
				fce.fce_v2_base.v2_direct = !link->lgr->uses_gateway;
				if (clc->hdr.type == SMC_CLC_CONFIRM) {
					memset(&gle, 0, sizeof(gle));
				if (ini && clc->hdr.type == SMC_CLC_CONFIRM) {
					gle.gid_cnt = ini->smcrv2.gidlist.len;
					len += sizeof(gle);
					len += gle.gid_cnt * sizeof(gle.gid[0]);
				} else {
					len += sizeof(gle.reserved);
				}
			}
			clc_v2->hdr.length = htons(len);
@@ -1094,7 +1112,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
				   sizeof(trl);
	if (version > SMC_V1 && first_contact) {
		vec[i].iov_base = &fce;
		vec[i++].iov_len = sizeof(fce);
		vec[i++].iov_len = fce_len;
		if (!conn->lgr->is_smcd) {
			if (clc->hdr.type == SMC_CLC_CONFIRM) {
				vec[i].iov_base = &gle;
@@ -1102,9 +1120,6 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
				vec[i].iov_base = &ini->smcrv2.gidlist.list;
				vec[i++].iov_len = gle.gid_cnt *
						   sizeof(gle.gid[0]);
			} else {
				vec[i].iov_base = &gle.reserved;
				vec[i++].iov_len = sizeof(gle.reserved);
			}
		}
	}
@@ -1141,7 +1156,7 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,

/* send CLC ACCEPT message across internal TCP socket */
int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
			u8 version, u8 *negotiated_eid)
			u8 version, u8 *negotiated_eid, struct smc_init_info *ini)
{
	struct smc_clc_msg_accept_confirm_v2 aclc_v2;
	int len;
@@ -1149,13 +1164,95 @@ int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
	memset(&aclc_v2, 0, sizeof(aclc_v2));
	aclc_v2.hdr.type = SMC_CLC_ACCEPT;
	len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact,
					  version, negotiated_eid, NULL);
					  version, negotiated_eid, ini);
	if (len < ntohs(aclc_v2.hdr.length))
		len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err;

	return len > 0 ? 0 : len;
}

int smc_clc_srv_v2x_features_validate(struct smc_clc_msg_proposal *pclc,
				      struct smc_init_info *ini)
{
	struct smc_clc_v2_extension *pclc_v2_ext;

	ini->max_conns = SMC_CONN_PER_LGR_MAX;
	ini->max_links = SMC_LINKS_ADD_LNK_MAX;

	if ((!(ini->smcd_version & SMC_V2) && !(ini->smcr_version & SMC_V2)) ||
	    ini->release_nr < SMC_RELEASE_1)
		return 0;

	pclc_v2_ext = smc_get_clc_v2_ext(pclc);
	if (!pclc_v2_ext)
		return SMC_CLC_DECL_NOV2EXT;

	if (ini->smcr_version & SMC_V2) {
		ini->max_conns = min_t(u8, pclc_v2_ext->max_conns, SMC_CONN_PER_LGR_PREFER);
		if (ini->max_conns < SMC_CONN_PER_LGR_MIN)
			return SMC_CLC_DECL_MAXCONNERR;

		ini->max_links = min_t(u8, pclc_v2_ext->max_links, SMC_LINKS_PER_LGR_MAX_PREFER);
		if (ini->max_links < SMC_LINKS_ADD_LNK_MIN)
			return SMC_CLC_DECL_MAXLINKERR;
	}

	return 0;
}

int smc_clc_clnt_v2x_features_validate(struct smc_clc_first_contact_ext *fce,
				       struct smc_init_info *ini)
{
	struct smc_clc_first_contact_ext_v2x *fce_v2x =
		(struct smc_clc_first_contact_ext_v2x *)fce;

	if (ini->release_nr < SMC_RELEASE_1)
		return 0;

	if (!ini->is_smcd) {
		if (fce_v2x->max_conns < SMC_CONN_PER_LGR_MIN)
			return SMC_CLC_DECL_MAXCONNERR;
		ini->max_conns = fce_v2x->max_conns;

		if (fce_v2x->max_links > SMC_LINKS_ADD_LNK_MAX ||
		    fce_v2x->max_links < SMC_LINKS_ADD_LNK_MIN)
			return SMC_CLC_DECL_MAXLINKERR;
		ini->max_links = fce_v2x->max_links;
	}

	return 0;
}

int smc_clc_v2x_features_confirm_check(struct smc_clc_msg_accept_confirm *cclc,
				       struct smc_init_info *ini)
{
	struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
		(struct smc_clc_msg_accept_confirm_v2 *)cclc;
	struct smc_clc_first_contact_ext *fce =
		smc_get_clc_first_contact_ext(clc_v2, ini->is_smcd);
	struct smc_clc_first_contact_ext_v2x *fce_v2x =
		(struct smc_clc_first_contact_ext_v2x *)fce;

	if (cclc->hdr.version == SMC_V1 ||
	    !(cclc->hdr.typev2 & SMC_FIRST_CONTACT_MASK))
		return 0;

	if (ini->release_nr != fce->release)
		return SMC_CLC_DECL_RELEASEERR;

	if (fce->release < SMC_RELEASE_1)
		return 0;

	if (!ini->is_smcd) {
		if (fce_v2x->max_conns != ini->max_conns)
			return SMC_CLC_DECL_MAXCONNERR;
		if (fce_v2x->max_links != ini->max_links)
			return SMC_CLC_DECL_MAXLINKERR;
	}

	return 0;
}

void smc_clc_get_hostname(u8 **host)
{
	*host = &smc_hostname[0];
+49 −4
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@
#define SMC_CLC_DECL_NOSEID	0x03030006  /* peer sent no SEID	      */
#define SMC_CLC_DECL_NOSMCD2DEV	0x03030007  /* no SMC-Dv2 device found	      */
#define SMC_CLC_DECL_NOUEID	0x03030008  /* peer sent no UEID	      */
#define SMC_CLC_DECL_RELEASEERR	0x03030009  /* release version negotiate failed */
#define SMC_CLC_DECL_MAXCONNERR	0x0303000a  /* max connections negotiate failed */
#define SMC_CLC_DECL_MAXLINKERR	0x0303000b  /* max links negotiate failed */
#define SMC_CLC_DECL_MODEUNSUPP	0x03040000  /* smc modes do not match (R or D)*/
#define SMC_CLC_DECL_RMBE_EC	0x03050000  /* peer has eyecatcher in RMBE    */
#define SMC_CLC_DECL_OPTUNSUPP	0x03060000  /* fastopen sockopt not supported */
@@ -133,7 +136,9 @@ struct smc_clc_smcd_gid_chid {
struct smc_clc_v2_extension {
	struct smc_clnt_opts_area_hdr hdr;
	u8 roce[16];		/* RoCEv2 GID */
	u8 reserved[16];
	u8 max_conns;
	u8 max_links;
	u8 reserved[14];
	u8 user_eids[][SMC_MAX_EID_LEN];
};

@@ -147,7 +152,9 @@ struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/
struct smc_clc_msg_smcd {	/* SMC-D GID information */
	struct smc_clc_smcd_gid_chid ism; /* ISM native GID+CHID of requestor */
	__be16 v2_ext_offset;	/* SMC Version 2 Extension Offset */
	u8 reserved[28];
	u8 vendor_oui[3];	/* vendor organizationally unique identifier */
	u8 vendor_exp_options[5];
	u8 reserved[20];
};

struct smc_clc_smcd_v2_extension {
@@ -231,8 +238,19 @@ struct smc_clc_first_contact_ext {
	u8 hostname[SMC_MAX_HOSTNAME_LEN];
};

struct smc_clc_first_contact_ext_v2x {
	struct smc_clc_first_contact_ext fce_v2_base;
	u8 max_conns; /* for SMC-R only */
	u8 max_links; /* for SMC-R only */
	u8 reserved3[2];
	__be32 vendor_exp_options;
	u8 reserved4[8];
} __packed;		/* format defined in
			 * IBM Shared Memory Communications Version 2 (Third Edition)
			 * (https://www.ibm.com/support/pages/node/7009315)
			 */

struct smc_clc_fce_gid_ext {
	u8 reserved[16];
	u8 gid_cnt;
	u8 reserved2[3];
	u8 gid[][SMC_GID_SIZE];
@@ -370,6 +388,27 @@ smc_get_clc_smcd_v2_ext(struct smc_clc_v2_extension *prop_v2ext)
		 ntohs(prop_v2ext->hdr.smcd_v2_ext_offset));
}

static inline struct smc_clc_first_contact_ext *
smc_get_clc_first_contact_ext(struct smc_clc_msg_accept_confirm_v2 *clc_v2,
			      bool is_smcd)
{
	int clc_v2_len;

	if (clc_v2->hdr.version == SMC_V1 ||
	    !(clc_v2->hdr.typev2 & SMC_FIRST_CONTACT_MASK))
		return NULL;

	if (is_smcd)
		clc_v2_len =
			offsetofend(struct smc_clc_msg_accept_confirm_v2, d1);
	else
		clc_v2_len =
			offsetofend(struct smc_clc_msg_accept_confirm_v2, r1);

	return (struct smc_clc_first_contact_ext *)(((u8 *)clc_v2) +
						    clc_v2_len);
}

struct smcd_dev;
struct smc_init_info;

@@ -382,7 +421,13 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini);
int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
			 u8 version, u8 *eid, struct smc_init_info *ini);
int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact,
			u8 version, u8 *negotiated_eid);
			u8 version, u8 *negotiated_eid, struct smc_init_info *ini);
int smc_clc_srv_v2x_features_validate(struct smc_clc_msg_proposal *pclc,
				      struct smc_init_info *ini);
int smc_clc_clnt_v2x_features_validate(struct smc_clc_first_contact_ext *fce,
				       struct smc_init_info *ini);
int smc_clc_v2x_features_confirm_check(struct smc_clc_msg_accept_confirm *cclc,
				       struct smc_init_info *ini);
void smc_clc_init(void) __init;
void smc_clc_exit(void);
void smc_clc_get_hostname(u8 **host);
Loading