Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 23 Sep 2015 15:49:27 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r288146 - head/sys/cam/ctl
Message-ID:  <201509231549.t8NFnR0d003682@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Wed Sep 23 15:49:27 2015
New Revision: 288146
URL: https://svnweb.freebsd.org/changeset/base/288146

Log:
  Make HA peers announce their parameters on connect.
  
  HA protocol requires strict version, parameters and configuration match.
  Differences there may cause full set of problems up to kernel panic.
  To avoid that, validate peer parameters on connect, and abort connection
  immediately if some mismatch detected.

Modified:
  head/sys/cam/ctl/ctl.c
  head/sys/cam/ctl/ctl_ha.c
  head/sys/cam/ctl/ctl_ha.h
  head/sys/cam/ctl/ctl_io.h

Modified: head/sys/cam/ctl/ctl.c
==============================================================================
--- head/sys/cam/ctl/ctl.c	Wed Sep 23 12:45:08 2015	(r288145)
+++ head/sys/cam/ctl/ctl.c	Wed Sep 23 15:49:27 2015	(r288146)
@@ -715,8 +715,20 @@ ctl_isc_ha_link_up(struct ctl_softc *sof
 {
 	struct ctl_port *port;
 	struct ctl_lun *lun;
+	union ctl_ha_msg msg;
 	int i;
 
+	/* Announce this node parameters to peer for validation. */
+	msg.login.msg_type = CTL_MSG_LOGIN;
+	msg.login.version = CTL_HA_VERSION;
+	msg.login.ha_mode = softc->ha_mode;
+	msg.login.ha_id = softc->ha_id;
+	msg.login.max_luns = CTL_MAX_LUNS;
+	msg.login.max_ports = CTL_MAX_PORTS;
+	msg.login.max_init_per_port = CTL_MAX_INIT_PER_PORT;
+	ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg.login, sizeof(msg.login),
+	    M_WAITOK);
+
 	STAILQ_FOREACH(port, &softc->port_list, links) {
 		ctl_isc_announce_port(port);
 		for (i = 0; i < CTL_MAX_INIT_PER_PORT; i++) {
@@ -999,6 +1011,36 @@ ctl_isc_iid_sync(struct ctl_softc *softc
 		port->wwpn_iid[iid].name = NULL;
 }
 
+static void
+ctl_isc_login(struct ctl_softc *softc, union ctl_ha_msg *msg, int len)
+{
+
+	if (msg->login.version != CTL_HA_VERSION) {
+		printf("CTL HA peers have different versions %d != %d\n",
+		    msg->login.version, CTL_HA_VERSION);
+		ctl_ha_msg_abort(CTL_HA_CHAN_CTL);
+		return;
+	}
+	if (msg->login.ha_mode != softc->ha_mode) {
+		printf("CTL HA peers have different ha_mode %d != %d\n",
+		    msg->login.ha_mode, softc->ha_mode);
+		ctl_ha_msg_abort(CTL_HA_CHAN_CTL);
+		return;
+	}
+	if (msg->login.ha_id == softc->ha_id) {
+		printf("CTL HA peers have same ha_id %d\n", msg->login.ha_id);
+		ctl_ha_msg_abort(CTL_HA_CHAN_CTL);
+		return;
+	}
+	if (msg->login.max_luns != CTL_MAX_LUNS ||
+	    msg->login.max_ports != CTL_MAX_PORTS ||
+	    msg->login.max_init_per_port != CTL_MAX_INIT_PER_PORT) {
+		printf("CTL HA peers have different limits\n");
+		ctl_ha_msg_abort(CTL_HA_CHAN_CTL);
+		return;
+	}
+}
+
 /*
  * ISC (Inter Shelf Communication) event handler.  Events from the HA
  * subsystem come in here.
@@ -1275,9 +1317,13 @@ ctl_isc_event_handler(ctl_ha_channel cha
 		case CTL_MSG_IID_SYNC:
 			ctl_isc_iid_sync(softc, msg, param);
 			break;
+		case CTL_MSG_LOGIN:
+			ctl_isc_login(softc, msg, param);
+			break;
 		default:
 			printf("Received HA message of unknown type %d\n",
 			    msg->hdr.msg_type);
+			ctl_ha_msg_abort(CTL_HA_CHAN_CTL);
 			break;
 		}
 		if (msg != &msgbuf)

Modified: head/sys/cam/ctl/ctl_ha.c
==============================================================================
--- head/sys/cam/ctl/ctl_ha.c	Wed Sep 23 12:45:08 2015	(r288145)
+++ head/sys/cam/ctl/ctl_ha.c	Wed Sep 23 15:49:27 2015	(r288146)
@@ -283,8 +283,9 @@ ctl_ha_rx_thread(void *arg)
 		else
 			next = sizeof(wire_hdr);
 		SOCKBUF_LOCK(&so->so_rcv);
-		while (sbavail(&so->so_rcv) < next) {
-			if (softc->ha_connected == 0 || so->so_error ||
+		while (sbavail(&so->so_rcv) < next || softc->ha_disconnect) {
+			if (softc->ha_connected == 0 || softc->ha_disconnect ||
+			    so->so_error ||
 			    (so->so_rcv.sb_state & SBS_CANTRCVMORE)) {
 				goto errout;
 			}
@@ -541,6 +542,18 @@ ctl_ha_listen(struct ha_softc *softc)
 			printf("%s: REUSEADDR setting failed %d\n",
 			    __func__, error);
 		}
+		bzero(&opt, sizeof(struct sockopt));
+		opt.sopt_dir = SOPT_SET;
+		opt.sopt_level = SOL_SOCKET;
+		opt.sopt_name = SO_REUSEPORT;
+		opt.sopt_val = &val;
+		opt.sopt_valsize = sizeof(val);
+		val = 1;
+		error = sosetopt(softc->ha_lso, &opt);
+		if (error) {
+			printf("%s: REUSEPORT setting failed %d\n",
+			    __func__, error);
+		}
 		SOCKBUF_LOCK(&softc->ha_lso->so_rcv);
 		soupcall_set(softc->ha_lso, SO_RCV, ctl_ha_lupcall, softc);
 		SOCKBUF_UNLOCK(&softc->ha_lso->so_rcv);
@@ -572,7 +585,8 @@ ctl_ha_conn_thread(void *arg)
 	while (1) {
 		if (softc->ha_disconnect || softc->ha_shutdown) {
 			ctl_ha_close(softc);
-			ctl_ha_lclose(softc);
+			if (softc->ha_disconnect == 2 || softc->ha_shutdown)
+				ctl_ha_lclose(softc);
 			softc->ha_disconnect = 0;
 			if (softc->ha_shutdown)
 				break;
@@ -666,7 +680,7 @@ ctl_ha_peer_sysctl(SYSCTL_HANDLER_ARGS)
 		sa->sin_addr.s_addr =
 		    htonl((b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
 	}
-	softc->ha_disconnect = 1;
+	softc->ha_disconnect = 2;
 	softc->ha_wakeup = 1;
 	mtx_unlock(&softc->ha_lock);
 	wakeup(&softc->ha_wakeup);
@@ -811,6 +825,19 @@ ctl_ha_msg_send(ctl_ha_channel channel, 
 	return (ctl_ha_msg_send2(channel, addr, len, NULL, 0, wait));
 }
 
+ctl_ha_status
+ctl_ha_msg_abort(ctl_ha_channel channel)
+{
+	struct ha_softc *softc = &ha_softc;
+
+	mtx_lock(&softc->ha_lock);
+	softc->ha_disconnect = 1;
+	softc->ha_wakeup = 1;
+	mtx_unlock(&softc->ha_lock);
+	wakeup(&softc->ha_wakeup);
+	return (CTL_HA_STATUS_SUCCESS);
+}
+
 /*
  * Allocate a data transfer request structure.
  */

Modified: head/sys/cam/ctl/ctl_ha.h
==============================================================================
--- head/sys/cam/ctl/ctl_ha.h	Wed Sep 23 12:45:08 2015	(r288145)
+++ head/sys/cam/ctl/ctl_ha.h	Wed Sep 23 15:49:27 2015	(r288146)
@@ -125,6 +125,7 @@ ctl_ha_status ctl_ha_msg_send(ctl_ha_cha
     size_t len, int wait);
 ctl_ha_status ctl_ha_msg_send2(ctl_ha_channel channel, const void *addr,
     size_t len, const void *addr2, size_t len2, int wait);
+ctl_ha_status ctl_ha_msg_abort(ctl_ha_channel channel);
 ctl_ha_status ctl_ha_msg_deregister(ctl_ha_channel channel);
 
 struct ctl_ha_dt_req * ctl_dt_req_alloc(void);

Modified: head/sys/cam/ctl/ctl_io.h
==============================================================================
--- head/sys/cam/ctl/ctl_io.h	Wed Sep 23 12:45:08 2015	(r288145)
+++ head/sys/cam/ctl/ctl_io.h	Wed Sep 23 15:49:27 2015	(r288146)
@@ -197,6 +197,7 @@ typedef enum {
 	CTL_MSG_PORT_SYNC,		/* Information about port. */
 	CTL_MSG_LUN_SYNC,		/* Information about LUN. */
 	CTL_MSG_IID_SYNC,		/* Information about initiator. */
+	CTL_MSG_LOGIN,			/* Information about HA peer. */
 	CTL_MSG_FAILOVER		/* Fake, never sent though the wire */
 } ctl_msg_type;
 
@@ -358,6 +359,25 @@ struct ctl_taskio {
 	uint8_t			task_resp[3];/* Response information */
 };
 
+
+/*
+ * HA link messages.
+ */
+#define	CTL_HA_VERSION		1
+
+/*
+ * Used for CTL_MSG_LOGIN.
+ */
+struct ctl_ha_msg_login {
+	ctl_msg_type		msg_type;
+	int			version;
+	int			ha_mode;
+	int			ha_id;
+	int			max_luns;
+	int			max_ports;
+	int			max_init_per_port;
+};
+
 typedef enum {
 	CTL_PR_REG_KEY,
 	CTL_PR_UNREG_KEY,
@@ -523,16 +543,14 @@ union ctl_ha_msg {
 	struct ctl_ha_msg_port	port;
 	struct ctl_ha_msg_lun	lun;
 	struct ctl_ha_msg_iid	iid;
+	struct ctl_ha_msg_login	login;
 };
 
-
 struct ctl_prio {
 	struct ctl_io_hdr  io_hdr;
 	struct ctl_ha_msg_pr pr_msg;
 };
 
-
-
 union ctl_io {
 	struct ctl_io_hdr io_hdr;	/* common to all I/O types */
 	struct ctl_scsiio scsiio;	/* Normal SCSI commands */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509231549.t8NFnR0d003682>