net/smc: introduce CLC first contact extension
SMC Version 2 defines a first contact extension for CLC accept and CLC confirm. This patch covers sending and receiving of the CLC first contact extension. Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Signed-off-by: Karsten Graul <kgraul@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a7c9c5f4af
commit
b81a5eb789
6 changed files with 91 additions and 5 deletions
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
#include <linux/if_vlan.h>
|
#include <linux/if_vlan.h>
|
||||||
#include <linux/rcupdate_wait.h>
|
#include <linux/rcupdate_wait.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
@ -448,6 +449,16 @@ static void smcr_conn_save_peer_info(struct smc_sock *smc,
|
||||||
smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1);
|
smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool smc_isascii(char *hostname)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < SMC_MAX_HOSTNAME_LEN; i++)
|
||||||
|
if (!isascii(hostname[i]))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void smcd_conn_save_peer_info(struct smc_sock *smc,
|
static void smcd_conn_save_peer_info(struct smc_sock *smc,
|
||||||
struct smc_clc_msg_accept_confirm *clc)
|
struct smc_clc_msg_accept_confirm *clc)
|
||||||
{
|
{
|
||||||
|
@ -459,6 +470,22 @@ static void smcd_conn_save_peer_info(struct smc_sock *smc,
|
||||||
smc->conn.peer_rmbe_size = bufsize - sizeof(struct smcd_cdc_msg);
|
smc->conn.peer_rmbe_size = bufsize - sizeof(struct smcd_cdc_msg);
|
||||||
atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size);
|
atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size);
|
||||||
smc->conn.tx_off = bufsize * smc->conn.peer_rmbe_idx;
|
smc->conn.tx_off = bufsize * smc->conn.peer_rmbe_idx;
|
||||||
|
if (clc->hdr.version > SMC_V1 &&
|
||||||
|
(clc->hdr.typev2 & SMC_FIRST_CONTACT_MASK)) {
|
||||||
|
struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
|
||||||
|
(struct smc_clc_msg_accept_confirm_v2 *)clc;
|
||||||
|
struct smc_clc_first_contact_ext *fce =
|
||||||
|
(struct smc_clc_first_contact_ext *)
|
||||||
|
(((u8 *)clc_v2) + sizeof(*clc_v2));
|
||||||
|
|
||||||
|
memcpy(smc->conn.lgr->negotiated_eid, clc_v2->eid,
|
||||||
|
SMC_MAX_EID_LEN);
|
||||||
|
smc->conn.lgr->peer_os = fce->os_type;
|
||||||
|
smc->conn.lgr->peer_smc_release = fce->release;
|
||||||
|
if (smc_isascii(fce->hostname))
|
||||||
|
memcpy(smc->conn.lgr->peer_hostname, fce->hostname,
|
||||||
|
SMC_MAX_HOSTNAME_LEN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smc_conn_save_peer_info(struct smc_sock *smc,
|
static void smc_conn_save_peer_info(struct smc_sock *smc,
|
||||||
|
@ -662,6 +689,7 @@ static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc,
|
||||||
|
|
||||||
#define SMC_CLC_MAX_ACCEPT_LEN \
|
#define SMC_CLC_MAX_ACCEPT_LEN \
|
||||||
(sizeof(struct smc_clc_msg_accept_confirm_v2) + \
|
(sizeof(struct smc_clc_msg_accept_confirm_v2) + \
|
||||||
|
sizeof(struct smc_clc_first_contact_ext) + \
|
||||||
sizeof(struct smc_clc_msg_trail))
|
sizeof(struct smc_clc_msg_trail))
|
||||||
|
|
||||||
/* CLC handshake during connect */
|
/* CLC handshake during connect */
|
||||||
|
@ -2422,6 +2450,7 @@ static int __init smc_init(void)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
smc_ism_init();
|
smc_ism_init();
|
||||||
|
smc_clc_init();
|
||||||
|
|
||||||
rc = smc_pnet_init();
|
rc = smc_pnet_init();
|
||||||
if (rc)
|
if (rc)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
* devices
|
* devices
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define SMC_MAX_HOSTNAME_LEN 32
|
||||||
#define SMC_MAX_EID_LEN 32
|
#define SMC_MAX_EID_LEN 32
|
||||||
|
|
||||||
extern struct proto smc_proto;
|
extern struct proto smc_proto;
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <linux/inetdevice.h>
|
#include <linux/inetdevice.h>
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
|
#include <linux/utsname.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
|
||||||
#include <net/addrconf.h>
|
#include <net/addrconf.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
@ -35,6 +37,8 @@ static const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
|
||||||
/* eye catcher "SMCD" EBCDIC for CLC messages */
|
/* eye catcher "SMCD" EBCDIC for CLC messages */
|
||||||
static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
|
static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
|
||||||
|
|
||||||
|
static u8 smc_hostname[SMC_MAX_HOSTNAME_LEN];
|
||||||
|
|
||||||
/* check arriving CLC proposal */
|
/* check arriving CLC proposal */
|
||||||
static bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc)
|
static bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc)
|
||||||
{
|
{
|
||||||
|
@ -92,12 +96,23 @@ smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (hdr->typev1 == SMC_TYPE_D &&
|
if (hdr->typev1 == SMC_TYPE_D &&
|
||||||
ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2)
|
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)))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void smc_clc_fill_fce(struct smc_clc_first_contact_ext *fce, int *len)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/* check if received message has a correct header length and contains valid
|
/* check if received message has a correct header length and contains valid
|
||||||
* heading and trailing eyecatchers
|
* heading and trailing eyecatchers
|
||||||
*/
|
*/
|
||||||
|
@ -623,10 +638,11 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
|
||||||
{
|
{
|
||||||
struct smc_connection *conn = &smc->conn;
|
struct smc_connection *conn = &smc->conn;
|
||||||
struct smc_clc_msg_accept_confirm *clc;
|
struct smc_clc_msg_accept_confirm *clc;
|
||||||
|
struct smc_clc_first_contact_ext fce;
|
||||||
struct smc_clc_msg_trail trl;
|
struct smc_clc_msg_trail trl;
|
||||||
struct kvec vec[2];
|
struct kvec vec[3];
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
int i;
|
int i, len;
|
||||||
|
|
||||||
/* send SMC Confirm CLC msg */
|
/* send SMC Confirm CLC msg */
|
||||||
clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
|
clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
|
||||||
|
@ -652,8 +668,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
|
||||||
smc_ism_get_system_eid(conn->lgr->smcd, &eid);
|
smc_ism_get_system_eid(conn->lgr->smcd, &eid);
|
||||||
if (eid)
|
if (eid)
|
||||||
memcpy(clc_v2->eid, eid, SMC_MAX_EID_LEN);
|
memcpy(clc_v2->eid, eid, SMC_MAX_EID_LEN);
|
||||||
clc_v2->hdr.length =
|
len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
|
||||||
htons(SMCD_CLC_ACCEPT_CONFIRM_LEN_V2);
|
if (first_contact)
|
||||||
|
smc_clc_fill_fce(&fce, &len);
|
||||||
|
clc_v2->hdr.length = htons(len);
|
||||||
}
|
}
|
||||||
memcpy(trl.eyecatcher, SMCD_EYECATCHER,
|
memcpy(trl.eyecatcher, SMCD_EYECATCHER,
|
||||||
sizeof(SMCD_EYECATCHER));
|
sizeof(SMCD_EYECATCHER));
|
||||||
|
@ -701,6 +719,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
|
||||||
SMCD_CLC_ACCEPT_CONFIRM_LEN :
|
SMCD_CLC_ACCEPT_CONFIRM_LEN :
|
||||||
SMCR_CLC_ACCEPT_CONFIRM_LEN) -
|
SMCR_CLC_ACCEPT_CONFIRM_LEN) -
|
||||||
sizeof(trl);
|
sizeof(trl);
|
||||||
|
if (version > SMC_V1 && first_contact) {
|
||||||
|
vec[i].iov_base = &fce;
|
||||||
|
vec[i++].iov_len = sizeof(fce);
|
||||||
|
}
|
||||||
vec[i].iov_base = &trl;
|
vec[i].iov_base = &trl;
|
||||||
vec[i++].iov_len = sizeof(trl);
|
vec[i++].iov_len = sizeof(trl);
|
||||||
return kernel_sendmsg(smc->clcsock, &msg, vec, 1,
|
return kernel_sendmsg(smc->clcsock, &msg, vec, 1,
|
||||||
|
@ -748,3 +770,13 @@ int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
|
||||||
|
|
||||||
return len > 0 ? 0 : len;
|
return len > 0 ? 0 : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __init smc_clc_init(void)
|
||||||
|
{
|
||||||
|
struct new_utsname *u;
|
||||||
|
|
||||||
|
memset(smc_hostname, _S, sizeof(smc_hostname)); /* ASCII blanks */
|
||||||
|
u = utsname();
|
||||||
|
memcpy(smc_hostname, u->nodename,
|
||||||
|
min_t(size_t, strlen(u->nodename), sizeof(smc_hostname)));
|
||||||
|
}
|
||||||
|
|
|
@ -199,6 +199,23 @@ struct smcd_clc_msg_accept_confirm_common { /* SMCD accept/confirm */
|
||||||
__be32 linkid; /* Link identifier */
|
__be32 linkid; /* Link identifier */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define SMC_CLC_OS_ZOS 1
|
||||||
|
#define SMC_CLC_OS_LINUX 2
|
||||||
|
#define SMC_CLC_OS_AIX 3
|
||||||
|
|
||||||
|
struct smc_clc_first_contact_ext {
|
||||||
|
u8 reserved1;
|
||||||
|
#if defined(__BIG_ENDIAN_BITFIELD)
|
||||||
|
u8 os_type : 4,
|
||||||
|
release : 4;
|
||||||
|
#elif defined(__LITTLE_ENDIAN_BITFIELD)
|
||||||
|
u8 release : 4,
|
||||||
|
os_type : 4;
|
||||||
|
#endif
|
||||||
|
u8 reserved2[2];
|
||||||
|
u8 hostname[SMC_MAX_HOSTNAME_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */
|
struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */
|
||||||
struct smc_clc_msg_hdr hdr;
|
struct smc_clc_msg_hdr hdr;
|
||||||
union {
|
union {
|
||||||
|
@ -304,5 +321,6 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
|
||||||
u8 version);
|
u8 version);
|
||||||
int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact,
|
int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact,
|
||||||
u8 version);
|
u8 version);
|
||||||
|
void smc_clc_init(void) __init;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -418,6 +418,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
|
||||||
lgr->smcd = ini->ism_dev[ini->ism_selected];
|
lgr->smcd = ini->ism_dev[ini->ism_selected];
|
||||||
lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
|
lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
|
||||||
lgr_lock = &lgr->smcd->lgr_lock;
|
lgr_lock = &lgr->smcd->lgr_lock;
|
||||||
|
lgr->smc_version = ini->smcd_version;
|
||||||
lgr->peer_shutdown = 0;
|
lgr->peer_shutdown = 0;
|
||||||
atomic_inc(&ini->ism_dev[ini->ism_selected]->lgr_cnt);
|
atomic_inc(&ini->ism_dev[ini->ism_selected]->lgr_cnt);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -231,6 +231,11 @@ struct smc_link_group {
|
||||||
u8 freeing : 1; /* lgr is being freed */
|
u8 freeing : 1; /* lgr is being freed */
|
||||||
|
|
||||||
bool is_smcd; /* SMC-R or SMC-D */
|
bool is_smcd; /* SMC-R or SMC-D */
|
||||||
|
u8 smc_version;
|
||||||
|
u8 negotiated_eid[SMC_MAX_EID_LEN];
|
||||||
|
u8 peer_os; /* peer operating system */
|
||||||
|
u8 peer_smc_release;
|
||||||
|
u8 peer_hostname[SMC_MAX_HOSTNAME_LEN];
|
||||||
union {
|
union {
|
||||||
struct { /* SMC-R */
|
struct { /* SMC-R */
|
||||||
enum smc_lgr_role role;
|
enum smc_lgr_role role;
|
||||||
|
|
Loading…
Reference in a new issue