Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 16 Nov 2010 23:39:26 +0200
From:      Mikolaj Golub <to.my.trociny@gmail.com>
To:        freebsd-fs@freebsd.org
Subject:   HAST: more than one remote nodes, is it possible?
Message-ID:  <86eial2bjl.fsf@kopusha.home.net>

next in thread | raw e-mail | index | archive | help
--=-=-=

Hi,

So is it possible to have several remote (secondary) nodes with HAST? Although
current version of hastd supports only one remote node, it looks like it is
possible building HAST devices in stack :-)

I tried this under VirtulBox and it worked for me.

Having 2 pairs of hosts I built lower HAST devise on both pairs and then upper
resource using lower as a provider for upper. Any host can be used as primary
for upper in this configuration. To make things more interesting I installed
jail (VIMAGE) on upper device so vm can be moved between 4 hosts.

Below is hast.conf:

----------------------------------------------------------------------

# Stacked HAST -- data are written to 4 nodes (lolek, bolek, chuk and
# gek) and are accessible on one of the nodes as /dev/hast/upper
#
# /dev/hast/upper
#        |
#        P------------upper-------------S
#        |         172.20.68.30         |
# /dev/hast/lower                /dev/hast/lower
#        |                              |
#        P-----lower----S               P----lower-----S
#        | 172.20.68.31 |               | 172.20.68.32 |
#     /dev/ad4       /dev/ad4        /dev/ad4       /dev/ad4
# 
#      lolek          bolek            chuk           gek

exec /etc/vip.sh

resource lower {

	local /dev/ad4

	on lolek {
		remote bolek
	}

	on bolek {
		remote lolek
	}

	on chuk {
		remote gek
	}

	on gek {
		remote chuk
	}
}

resource upper {

	local /dev/hast/lower
	# XXX: HAST should be patched to know friends 
	friends lolek bolek chuk gek

	on lolek {
		remote 172.20.68.32
	}

	on bolek {
		remote 172.20.68.32
	}

	on chuk {
		remote 172.20.68.31
	}

	on gek {
		remote 172.20.68.31
	}
}

----------------------------------------------------------------------

As it is noted in the comments above hastd should be patched: current version
of hastd allows only connections from addresses specified as remote. The patch
is attached.

/etc/vip.sh is used to switch IP addresses between hosts.

Details can be found here:

http://code.google.com/p/hastmon/wiki/StackedHAST

-- 
Mikolaj Golub


--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment; filename=hastd.friends.patch

Index: sbin/hastd/parse.y
===================================================================
--- sbin/hastd/parse.y	(revision 214604)
+++ sbin/hastd/parse.y	(working copy)
@@ -209,8 +209,13 @@ void
 yy_config_free(struct hastd_config *config)
 {
 	struct hast_resource *res;
+	struct hast_address *addr;
 
 	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
+		while ((addr = TAILQ_FIRST(&res->hr_friends)) != NULL) {
+			TAILQ_REMOVE(&res->hr_friends, addr, ha_next);
+			free(addr);
+		}
 		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
 		free(res);
 	}
@@ -218,7 +223,8 @@ yy_config_free(struct hastd_config *config)
 }
 %}
 
-%token CONTROL LISTEN PORT REPLICATION TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON
+%token CONTROL LISTEN PORT REPLICATION TIMEOUT EXEC EXTENTSIZE
+%token RESOURCE NAME LOCAL REMOTE FRIENDS ON
 %token FULLSYNC MEMSYNC ASYNC
 %token NUM STR OB CB
 
@@ -418,6 +424,8 @@ node_entry:
 	control_statement
 	|
 	listen_statement
+	|
+	friends_statement
 	;
 
 resource_statement:	RESOURCE resource_start OB resource_entries CB
@@ -513,6 +521,7 @@ resource_start:	STR
 		curres->hr_localpath[0] = '\0';
 		curres->hr_localfd = -1;
 		curres->hr_remoteaddr[0] = '\0';
+		TAILQ_INIT(&curres->hr_friends);
 		curres->hr_ggateunit = -1;
 	}
 	;
@@ -533,6 +542,8 @@ resource_entry:
 	|
 	local_statement
 	|
+	friends_statement
+	|
 	resource_node_statement
 	;
 
@@ -598,6 +609,40 @@ local_statement:	LOCAL STR
 	}
 	;
 
+friends_statement:	FRIENDS friend_addresses
+	;
+
+friend_addresses:
+	|
+	friend_addresses friend_address
+	;
+
+friend_address:		STR
+	{
+		struct hast_address *addr;
+
+		assert(depth == 1 || depth == 2);
+		
+		if (depth == 1 || mynode) {
+			assert(curres != NULL);
+			addr = calloc(1, sizeof(*addr));
+			if (addr == NULL) {
+				errx(EX_TEMPFAIL,
+				    "cannot allocate memory for resource");
+			}
+			if (strlcpy(addr->ha_addr, $1,
+				sizeof(addr->ha_addr)) >=
+			    sizeof(addr->ha_addr)) {
+				pjdlog_error("address argument too long");
+				free($1);
+				return (1);
+			}
+			free($1);
+			TAILQ_INSERT_TAIL(&curres->hr_friends, addr, ha_next);
+		}
+	}
+	;
+
 resource_node_statement:ON resource_node_start OB resource_node_entries CB
 	{
 		mynode = false;
Index: sbin/hastd/hastd.c
===================================================================
--- sbin/hastd/hastd.c	(revision 214604)
+++ sbin/hastd/hastd.c	(working copy)
@@ -156,6 +156,29 @@ child_exit(void)
 	}
 }
 
+static int
+friendscmp(const struct hast_resource *res0, const struct hast_resource *res1)
+{
+	struct hast_address *friend0, *friend1;
+	int nfriends0, nfriends1;
+
+	nfriends0 = nfriends1 = 0;
+	
+	TAILQ_FOREACH(friend0, &res0->hr_friends, ha_next) {
+		TAILQ_FOREACH(friend1, &res1->hr_friends, ha_next) {
+			if (strcmp(friend0->ha_addr, friend1->ha_addr) == 0)
+				break;
+		}
+		if (friend1 == NULL)
+			return (1);
+		nfriends0++;
+	}
+	TAILQ_FOREACH(friend1, &res1->hr_friends, ha_next) {
+		nfriends1++;
+	}
+	return (nfriends0 - nfriends1);
+}
+
 static bool
 resource_needs_restart(const struct hast_resource *res0,
     const struct hast_resource *res1)
@@ -177,6 +200,8 @@ resource_needs_restart(const struct hast_resource
 			return (true);
 		if (strcmp(res0->hr_exec, res1->hr_exec) != 0)
 			return (true);
+		if (friendscmp(res0, res1) != 0)
+			return (true);
 	}
 	return (false);
 }
@@ -201,6 +226,7 @@ resource_needs_reload(const struct hast_resource *
 		return (true);
 	if (strcmp(res0->hr_exec, res1->hr_exec) != 0)
 		return (true);
+
 	return (false);
 }
 
@@ -384,6 +410,7 @@ listen_accept(void)
 	struct hast_resource *res;
 	struct proto_conn *conn;
 	struct nv *nvin, *nvout, *nverr;
+	struct hast_address *friend;
 	const char *resname;
 	const unsigned char *token;
 	char laddr[256], raddr[256];
@@ -416,6 +443,12 @@ listen_accept(void)
 	TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
 		if (proto_address_match(conn, res->hr_remoteaddr))
 			break;
+		TAILQ_FOREACH(friend, &res->hr_friends, ha_next) {
+			if (proto_address_match(conn, friend->ha_addr))
+				break;
+		}
+		if (friend != NULL)
+			break;
 	}
 	if (res == NULL) {
 		pjdlog_error("Client %s isn't known.", raddr);
@@ -469,9 +502,15 @@ listen_accept(void)
 
 	/* Does the remote host have access to this resource? */
 	if (!proto_address_match(conn, res->hr_remoteaddr)) {
-		pjdlog_error("Client %s has no access to the resource.", raddr);
-		nv_add_stringf(nverr, "errmsg", "No access to the resource.");
-		goto fail;
+		TAILQ_FOREACH(friend, &res->hr_friends, ha_next) {
+			if (proto_address_match(conn, friend->ha_addr))
+				break;
+		}
+		if (friend == NULL) {
+			pjdlog_error("Client %s has no access to the resource.", raddr);
+			nv_add_stringf(nverr, "errmsg", "No access to the resource.");
+			goto fail;
+		}
 	}
 	/* Is the resource marked as secondary? */
 	if (res->hr_role != HAST_ROLE_SECONDARY) {
Index: sbin/hastd/hast.h
===================================================================
--- sbin/hastd/hast.h	(revision 214604)
+++ sbin/hastd/hast.h	(working copy)
@@ -150,6 +150,8 @@ struct hast_resource {
 
 	/* Address of the remote component. */
 	char	hr_remoteaddr[HAST_ADDRSIZE];
+	/* Hosts that can connect to us. */
+	TAILQ_HEAD(, hast_address) hr_friends;
 	/* Connection for incoming data. */
 	struct proto_conn *hr_remotein;
 	/* Connection for outgoing data. */
@@ -193,6 +195,11 @@ struct hast_resource {
 	TAILQ_ENTRY(hast_resource) hr_next;
 };
 
+struct hast_address {
+	char	ha_addr[HAST_ADDRSIZE];
+	TAILQ_ENTRY(hast_address) ha_next;
+};
+
 struct hastd_config *yy_config_parse(const char *config, bool exitonerror);
 void yy_config_free(struct hastd_config *config);
 
Index: sbin/hastd/hast.conf.5
===================================================================
--- sbin/hastd/hast.conf.5	(revision 214604)
+++ sbin/hastd/hast.conf.5	(working copy)
@@ -81,6 +81,7 @@ resource <name> {
 	local <path>
 	timeout <seconds>
 	exec <path>
+	friends <addr ...>
 
 	on <node> {
 		# Resource-node section
@@ -89,6 +90,7 @@ resource <name> {
 		local <path>
 		# Required
 		remote <addr>
+		friends <addr ...>
 	}
 	on <node> {
 		# Resource-node section
@@ -97,6 +99,7 @@ resource <name> {
 		local <path>
 		# Required
 		remote <addr>
+		friends <addr ...>
 	}
 }
 .Ed
@@ -155,6 +158,13 @@ tcp4://0.0.0.0:8457
 .Pp
 The default value is
 .Pa tcp4://0.0.0.0:8457 .
+.It Ic friends Aq addr ...
+.Pp
+List of addresses (separated by space) of hosts that can connect to
+the node.
+Format is the same as for the
+.Ic listen
+statement.
 .It Ic replication Aq mode
 .Pp
 Replication mode should be one of the following:
Index: sbin/hastd/token.l
===================================================================
--- sbin/hastd/token.l	(revision 214604)
+++ sbin/hastd/token.l	(working copy)
@@ -53,6 +53,7 @@ exec			{ DP; return EXEC; }
 resource		{ DP; return RESOURCE; }
 name			{ DP; return NAME; }
 local			{ DP; return LOCAL; }
+friends			{ DP; return FRIENDS; }
 remote			{ DP; return REMOTE; }
 on			{ DP; return ON; }
 fullsync		{ DP; return FULLSYNC; }

--=-=-=--



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