Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0cfdd8f9 authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller
Browse files

smc: connection and link group creation



* create smc_connection for SMC-sockets
* determine suitable link group for a connection
* create a new link group if necessary

Signed-off-by: default avatarUrsula Braun <ubraun@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a046d57d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
obj-$(CONFIG_SMC)	+= smc.o
smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o
smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o smc_core.o
+93 −9
Original line number Diff line number Diff line
@@ -31,9 +31,19 @@

#include "smc.h"
#include "smc_clc.h"
#include "smc_core.h"
#include "smc_ib.h"
#include "smc_pnet.h"

static DEFINE_MUTEX(smc_create_lgr_pending);	/* serialize link group
						 * creation
						 */

struct smc_lgr_list smc_lgr_list = {		/* established link groups */
	.lock = __SPIN_LOCK_UNLOCKED(smc_lgr_list.lock),
	.list = LIST_HEAD_INIT(smc_lgr_list.list),
};

static void smc_tcp_listen_work(struct work_struct *);

static void smc_set_keepalive(struct sock *sk, int val)
@@ -235,11 +245,31 @@ int smc_netinfo_by_tcpsk(struct socket *clcsock,
	return rc;
}

static void smc_conn_save_peer_info(struct smc_sock *smc,
				    struct smc_clc_msg_accept_confirm *clc)
{
	smc->conn.peer_conn_idx = clc->conn_idx;
}

static void smc_link_save_peer_info(struct smc_link *link,
				    struct smc_clc_msg_accept_confirm *clc)
{
	link->peer_qpn = ntoh24(clc->qpn);
	memcpy(link->peer_gid, clc->lcl.gid, SMC_GID_SIZE);
	memcpy(link->peer_mac, clc->lcl.mac, sizeof(link->peer_mac));
	link->peer_psn = ntoh24(clc->psn);
	link->peer_mtu = clc->qp_mtu;
}

/* setup for RDMA connection of client */
static int smc_connect_rdma(struct smc_sock *smc)
{
	struct sockaddr_in *inaddr = (struct sockaddr_in *)smc->addr;
	struct smc_clc_msg_accept_confirm aclc;
	int local_contact = SMC_FIRST_CONTACT;
	struct smc_ib_device *smcibdev;
	struct smc_link *link;
	u8 srv_first_contact;
	int reason_code = 0;
	int rc = 0;
	u8 ibport;
@@ -278,26 +308,43 @@ static int smc_connect_rdma(struct smc_sock *smc)
	if (reason_code > 0)
		goto decline_rdma;

	/* tbd in follow-on patch: more steps to setup RDMA communcication,
	 * create connection, link group, link
	 */

	srv_first_contact = aclc.hdr.flag;
	mutex_lock(&smc_create_lgr_pending);
	local_contact = smc_conn_create(smc, inaddr->sin_addr.s_addr, smcibdev,
					ibport, &aclc.lcl, srv_first_contact);
	if (local_contact < 0) {
		rc = local_contact;
		if (rc == -ENOMEM)
			reason_code = SMC_CLC_DECL_MEM;/* insufficient memory*/
		else if (rc == -ENOLINK)
			reason_code = SMC_CLC_DECL_SYNCERR; /* synchr. error */
		goto decline_rdma_unlock;
	}
	link = &smc->conn.lgr->lnk[SMC_SINGLE_LINK];

	smc_conn_save_peer_info(smc, &aclc);
	if (local_contact == SMC_FIRST_CONTACT)
		smc_link_save_peer_info(link, &aclc);
	/* tbd in follow-on patch: more steps to setup RDMA communcication,
	 * create rmbs, map rmbs, rtoken_handling, modify_qp
	 */

	rc = smc_clc_send_confirm(smc);
	if (rc)
		goto out_err;
		goto out_err_unlock;

	/* tbd in follow-on patch: llc_confirm */

	mutex_unlock(&smc_create_lgr_pending);
out_connected:
	smc_copy_sock_settings_to_clc(smc);
	smc->sk.sk_state = SMC_ACTIVE;

	return rc;
	return rc ? rc : local_contact;

decline_rdma_unlock:
	mutex_unlock(&smc_create_lgr_pending);
	smc_conn_free(&smc->conn);
decline_rdma:
	/* RDMA setup failed, switch back to TCP */
	smc->use_fallback = true;
@@ -308,6 +355,9 @@ static int smc_connect_rdma(struct smc_sock *smc)
	}
	goto out_connected;

out_err_unlock:
	mutex_unlock(&smc_create_lgr_pending);
	smc_conn_free(&smc->conn);
out_err:
	return rc;
}
@@ -476,10 +526,12 @@ static void smc_listen_work(struct work_struct *work)
	struct socket *newclcsock = new_smc->clcsock;
	struct smc_sock *lsmc = new_smc->listen_smc;
	struct smc_clc_msg_accept_confirm cclc;
	int local_contact = SMC_REUSE_CONTACT;
	struct sock *newsmcsk = &new_smc->sk;
	struct smc_clc_msg_proposal pclc;
	struct smc_ib_device *smcibdev;
	struct sockaddr_in peeraddr;
	struct smc_link *link;
	int reason_code = 0;
	int rc = 0, len;
	__be32 subnet;
@@ -527,15 +579,30 @@ static void smc_listen_work(struct work_struct *work)
	/* get address of the peer connected to the internal TCP socket */
	kernel_getpeername(newclcsock, (struct sockaddr *)&peeraddr, &len);

	/* tbd in follow-on patch: more steps to setup RDMA communcication,
	 * create connection, link_group, link
	/* allocate connection / link group */
	mutex_lock(&smc_create_lgr_pending);
	local_contact = smc_conn_create(new_smc, peeraddr.sin_addr.s_addr,
					smcibdev, ibport, &pclc.lcl, 0);
	if (local_contact == SMC_REUSE_CONTACT)
		/* lock no longer needed, free it due to following
		 * smc_clc_wait_msg() call
		 */
		mutex_unlock(&smc_create_lgr_pending);
	if (local_contact < 0) {
		rc = local_contact;
		if (rc == -ENOMEM)
			reason_code = SMC_CLC_DECL_MEM;/* insufficient memory*/
		else if (rc == -ENOLINK)
			reason_code = SMC_CLC_DECL_SYNCERR; /* synchr. error */
		goto decline_rdma;
	}
	link = &new_smc->conn.lgr->lnk[SMC_SINGLE_LINK];

	/* tbd in follow-on patch: more steps to setup RDMA communcication,
	 * create rmbs, map rmbs
	 */

	rc = smc_clc_send_accept(new_smc);
	rc = smc_clc_send_accept(new_smc, local_contact);
	if (rc)
		goto out_err;

@@ -546,6 +613,9 @@ static void smc_listen_work(struct work_struct *work)
		goto out_err;
	if (reason_code > 0)
		goto decline_rdma;
	smc_conn_save_peer_info(new_smc, &cclc);
	if (local_contact == SMC_FIRST_CONTACT)
		smc_link_save_peer_info(link, &cclc);

	/* tbd in follow-on patch: more steps to setup RDMA communcication,
	 * rtoken_handling, modify_qp
@@ -555,6 +625,8 @@ static void smc_listen_work(struct work_struct *work)
	sk_refcnt_debug_inc(newsmcsk);
	newsmcsk->sk_state = SMC_ACTIVE;
enqueue:
	if (local_contact == SMC_FIRST_CONTACT)
		mutex_unlock(&smc_create_lgr_pending);
	lock_sock(&lsmc->sk);
	if (lsmc->sk.sk_state == SMC_LISTEN) {
		smc_accept_enqueue(&lsmc->sk, newsmcsk);
@@ -570,6 +642,7 @@ static void smc_listen_work(struct work_struct *work)

decline_rdma:
	/* RDMA setup failed, switch back to TCP */
	smc_conn_free(&new_smc->conn);
	new_smc->use_fallback = true;
	if (reason_code && (reason_code != SMC_CLC_DECL_REPLY)) {
		rc = smc_clc_send_decline(new_smc, reason_code, 0);
@@ -1024,6 +1097,17 @@ static int __init smc_init(void)

static void __exit smc_exit(void)
{
	struct smc_link_group *lgr, *lg;
	LIST_HEAD(lgr_freeing_list);

	spin_lock_bh(&smc_lgr_list.lock);
	if (!list_empty(&smc_lgr_list.list))
		list_splice_init(&smc_lgr_list.list, &lgr_freeing_list);
	spin_unlock_bh(&smc_lgr_list.lock);
	list_for_each_entry_safe(lgr, lg, &lgr_freeing_list, list) {
		list_del_init(&lgr->list);
		smc_lgr_free(lgr); /* free link group */
	}
	smc_ib_unregister_client();
	sock_unregister(PF_SMC);
	proto_unregister(&smc_proto);
+36 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
#include <linux/types.h>
#include <net/sock.h>

#include "smc_ib.h"

#define SMCPROTO_SMC		0	/* SMC protocol */

#define SMC_MAX_PORTS		2	/* Max # of ports */
@@ -25,9 +27,19 @@ enum smc_state { /* possible states of an SMC socket */
	SMC_LISTEN	= 10,
};

struct smc_link_group;

struct smc_connection {
	struct rb_node		alert_node;
	struct smc_link_group	*lgr;		/* link group of connection */
	u32			alert_token_local; /* unique conn. id */
	u8			peer_conn_idx;	/* from tcp handshake */
};

struct smc_sock {				/* smc sock container */
	struct sock		sk;
	struct socket		*clcsock;	/* internal tcp socket */
	struct smc_connection	conn;		/* smc connection */
	struct sockaddr		*addr;		/* inet connect address */
	struct smc_sock		*listen_smc;	/* listen parent */
	struct work_struct	tcp_listen_work;/* handle tcp socket accepts */
@@ -46,6 +58,24 @@ static inline struct smc_sock *smc_sk(const struct sock *sk)

extern u8	local_systemid[SMC_SYSTEMID_LEN]; /* unique system identifier */

/* convert an u32 value into network byte order, store it into a 3 byte field */
static inline void hton24(u8 *net, u32 host)
{
	__be32 t;

	t = cpu_to_be32(host);
	memcpy(net, ((u8 *)&t) + 1, 3);
}

/* convert a received 3 byte field into host byte order*/
static inline u32 ntoh24(u8 *net)
{
	__be32 t = 0;

	memcpy(((u8 *)&t) + 1, net, 3);
	return be32_to_cpu(t);
}

#ifdef CONFIG_XFRM
static inline bool using_ipsec(struct smc_sock *smc)
{
@@ -59,7 +89,13 @@ static inline bool using_ipsec(struct smc_sock *smc)
}
#endif

struct smc_clc_msg_local;

int smc_netinfo_by_tcpsk(struct socket *clcsock, __be32 *subnet,
			 u8 *prefix_len);
void smc_conn_free(struct smc_connection *conn);
int smc_conn_create(struct smc_sock *smc, __be32 peer_in_addr,
		    struct smc_ib_device *smcibdev, u8 ibport,
		    struct smc_clc_msg_local *lcl, int srv_first_contact);

#endif	/* __SMC_H */
+32 −6
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <net/tcp.h>

#include "smc.h"
#include "smc_core.h"
#include "smc_clc.h"
#include "smc_ib.h"

@@ -89,8 +90,13 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
		reason_code = -EPROTO;
		goto out;
	}
	if (clcm->type == SMC_CLC_DECLINE)
	if (clcm->type == SMC_CLC_DECLINE) {
		reason_code = SMC_CLC_DECL_REPLY;
		if (ntohl(((struct smc_clc_msg_decline *)buf)->peer_diagnosis)
			== SMC_CLC_DECL_SYNCERR)
			smc->conn.lgr->sync_err = true;
	}

out:
	return reason_code;
}
@@ -175,12 +181,15 @@ int smc_clc_send_proposal(struct smc_sock *smc,
/* send CLC CONFIRM message across internal TCP socket */
int smc_clc_send_confirm(struct smc_sock *smc)
{
	struct smc_connection *conn = &smc->conn;
	struct smc_clc_msg_accept_confirm cclc;
	struct smc_link *link;
	int reason_code = 0;
	struct msghdr msg;
	struct kvec vec;
	int len;

	link = &conn->lgr->lnk[SMC_SINGLE_LINK];
	/* send SMC Confirm CLC msg */
	memset(&cclc, 0, sizeof(cclc));
	memcpy(cclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
@@ -188,12 +197,18 @@ int smc_clc_send_confirm(struct smc_sock *smc)
	cclc.hdr.length = htons(sizeof(cclc));
	cclc.hdr.version = SMC_CLC_V1;		/* SMC version */
	memcpy(cclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));

	/* tbd in follow-on patch: fill in link-related values */
	memcpy(&cclc.lcl.gid, &link->smcibdev->gid[link->ibport - 1],
	       SMC_GID_SIZE);
	memcpy(&cclc.lcl.mac, &link->smcibdev->mac[link->ibport - 1],
	       sizeof(link->smcibdev->mac));

	/* tbd in follow-on patch: fill in rmb-related values */

	hton24(cclc.qpn, link->roce_qp->qp_num);
	cclc.conn_idx = 1; /* for now: 1 RMB = 1 RMBE */
	cclc.rmbe_alert_token = htonl(conn->alert_token_local);
	cclc.qp_mtu = min(link->path_mtu, link->peer_mtu);
	hton24(cclc.psn, link->psn_initial);

	memcpy(cclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));

@@ -214,26 +229,37 @@ int smc_clc_send_confirm(struct smc_sock *smc)
}

/* send CLC ACCEPT message across internal TCP socket */
int smc_clc_send_accept(struct smc_sock *new_smc)
int smc_clc_send_accept(struct smc_sock *new_smc, int srv_first_contact)
{
	struct smc_connection *conn = &new_smc->conn;
	struct smc_clc_msg_accept_confirm aclc;
	struct smc_link *link;
	struct msghdr msg;
	struct kvec vec;
	int rc = 0;
	int len;

	link = &conn->lgr->lnk[SMC_SINGLE_LINK];
	memset(&aclc, 0, sizeof(aclc));
	memcpy(aclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
	aclc.hdr.type = SMC_CLC_ACCEPT;
	aclc.hdr.length = htons(sizeof(aclc));
	aclc.hdr.version = SMC_CLC_V1;		/* SMC version */
	if (srv_first_contact)
		aclc.hdr.flag = 1;
	memcpy(aclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));

	/* tbd in follow-on patch: fill in link-related values */
	memcpy(&aclc.lcl.gid, &link->smcibdev->gid[link->ibport - 1],
	       SMC_GID_SIZE);
	memcpy(&aclc.lcl.mac, link->smcibdev->mac[link->ibport - 1],
	       sizeof(link->smcibdev->mac[link->ibport - 1]));

	/* tbd in follow-on patch: fill in rmb-related values */

	hton24(aclc.qpn, link->roce_qp->qp_num);
	aclc.conn_idx = 1;			/* as long as 1 RMB = 1 RMBE */
	aclc.rmbe_alert_token = htonl(conn->alert_token_local);
	aclc.qp_mtu = link->path_mtu;
	hton24(aclc.psn, link->psn_initial);
	memcpy(aclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));

	memset(&msg, 0, sizeof(msg));
+1 −1
Original line number Diff line number Diff line
@@ -109,6 +109,6 @@ int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info,
int smc_clc_send_proposal(struct smc_sock *smc, struct smc_ib_device *smcibdev,
			  u8 ibport);
int smc_clc_send_confirm(struct smc_sock *smc);
int smc_clc_send_accept(struct smc_sock *smc);
int smc_clc_send_accept(struct smc_sock *smc, int srv_first_contact);

#endif
Loading