svn commit: r274308 - head/usr.sbin/ctld

Edward Tomasz Napierala trasz at FreeBSD.org
Sun Nov 9 13:01:11 UTC 2014


Author: trasz
Date: Sun Nov  9 13:01:09 2014
New Revision: 274308
URL: https://svnweb.freebsd.org/changeset/base/274308

Log:
  Add support for sending redirections to iSCSI target.
  
  MFC after:	1 month
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/usr.sbin/ctld/ctl.conf.5
  head/usr.sbin/ctld/ctld.c
  head/usr.sbin/ctld/ctld.h
  head/usr.sbin/ctld/login.c
  head/usr.sbin/ctld/parse.y
  head/usr.sbin/ctld/token.l

Modified: head/usr.sbin/ctld/ctl.conf.5
==============================================================================
--- head/usr.sbin/ctld/ctl.conf.5	Sun Nov  9 11:13:15 2014	(r274307)
+++ head/usr.sbin/ctld/ctl.conf.5	Sun Nov  9 13:01:09 2014	(r274308)
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 8, 2014
+.Dd November 9, 2014
 .Dt CTL.CONF 5
 .Os
 .Sh NAME
@@ -218,6 +218,17 @@ An IPv4 or IPv6 address and port to list
 .\".It Ic listen-iser Ar address
 .\"An IPv4 or IPv6 address and port to listen on for incoming connections
 .\"using iSER (iSCSI over RDMA) protocol.
+.It Ic redirect Aq Ar address
+IPv4 or IPv6 address to redirect initiators to.
+When configured, all initiators attempting to connect to portal
+belonging to this
+.Sy portal-group
+will get redirected using "Target moved temporarily" login response.
+Redirection happens before authentication and any
+.Sy initiator-name
+or
+.Sy initiator-portal
+checks are skipped.
 .El
 .Ss target Context
 .Bl -tag -width indent
@@ -296,6 +307,11 @@ The default portal group is
 .Qq Ar default ,
 which makes the target available
 on TCP port 3260 on all configured IPv4 and IPv6 addresses.
+.It Ic redirect Aq Ar address
+IPv4 or IPv6 address to redirect initiators to.
+When configured, all initiators attempting to connect to this target
+will get redirected using "Target moved temporarily" login response.
+Redirection happens after successful authentication.
 .It Ic lun Ar number
 Create a
 .Sy lun

Modified: head/usr.sbin/ctld/ctld.c
==============================================================================
--- head/usr.sbin/ctld/ctld.c	Sun Nov  9 11:13:15 2014	(r274307)
+++ head/usr.sbin/ctld/ctld.c	Sun Nov  9 13:01:09 2014	(r274308)
@@ -622,6 +622,7 @@ portal_group_delete(struct portal_group 
 	TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp)
 		portal_delete(portal);
 	free(pg->pg_name);
+	free(pg->pg_redirection);
 	free(pg);
 }
 
@@ -1000,6 +1001,22 @@ portal_group_set_filter(struct portal_gr
 	return (0);
 }
 
+int
+portal_group_set_redirection(struct portal_group *pg, const char *addr)
+{
+
+	if (pg->pg_redirection != NULL) {
+		log_warnx("cannot set redirection to \"%s\" for "
+		    "portal-group \"%s\"; already defined",
+		    addr, pg->pg_name);
+		return (1);
+	}
+
+	pg->pg_redirection = checked_strdup(addr);
+
+	return (0);
+}
+
 static bool
 valid_hex(const char ch)
 {
@@ -1144,6 +1161,7 @@ target_delete(struct target *targ)
 	TAILQ_FOREACH_SAFE(lun, &targ->t_luns, l_next, tmp)
 		lun_delete(lun);
 	free(targ->t_name);
+	free(targ->t_redirection);
 	free(targ);
 }
 
@@ -1160,6 +1178,22 @@ target_find(struct conf *conf, const cha
 	return (NULL);
 }
 
+int
+target_set_redirection(struct target *target, const char *addr)
+{
+
+	if (target->t_redirection != NULL) {
+		log_warnx("cannot set redirection to \"%s\" for "
+		    "target \"%s\"; already defined",
+		    addr, target->t_name);
+		return (1);
+	}
+
+	target->t_redirection = checked_strdup(addr);
+
+	return (0);
+}
+
 struct lun *
 lun_new(struct target *targ, int lun_id)
 {
@@ -1486,10 +1520,15 @@ conf_verify(struct conf *conf)
 				return (error);
 			found = true;
 		}
-		if (!found) {
+		if (!found && targ->t_redirection == NULL) {
 			log_warnx("no LUNs defined for target \"%s\"",
 			    targ->t_name);
 		}
+		if (found && targ->t_redirection != NULL) {
+			log_debugx("target \"%s\" contains luns, "
+			    " but configured for redirection",
+			    targ->t_name);
+		}
 	}
 	TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
 		assert(pg->pg_name != NULL);
@@ -1506,13 +1545,22 @@ conf_verify(struct conf *conf)
 			if (targ->t_portal_group == pg)
 				break;
 		}
-		if (targ == NULL) {
+		if (pg->pg_redirection != NULL) {
+			if (targ != NULL) {
+				log_debugx("portal-group \"%s\" assigned "
+				    "to target \"%s\", but configured "
+				    "for redirection",
+				    pg->pg_name, targ->t_name);
+			}
+			pg->pg_unassigned = false;
+		} else if (targ != NULL) {
+			pg->pg_unassigned = false;
+		} else {
 			if (strcmp(pg->pg_name, "default") != 0)
 				log_warnx("portal-group \"%s\" not assigned "
 				    "to any target", pg->pg_name);
 			pg->pg_unassigned = true;
-		} else
-			pg->pg_unassigned = false;
+		}
 	}
 	TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) {
 		if (ag->ag_name == NULL)

Modified: head/usr.sbin/ctld/ctld.h
==============================================================================
--- head/usr.sbin/ctld/ctld.h	Sun Nov  9 11:13:15 2014	(r274307)
+++ head/usr.sbin/ctld/ctld.h	Sun Nov  9 13:01:09 2014	(r274308)
@@ -117,6 +117,7 @@ struct portal_group {
 	int				pg_discovery_filter;
 	bool				pg_unassigned;
 	TAILQ_HEAD(, portal)		pg_portals;
+	char				*pg_redirection;
 
 	uint16_t			pg_tag;
 };
@@ -151,6 +152,7 @@ struct target {
 	struct portal_group		*t_portal_group;
 	char				*t_name;
 	char				*t_alias;
+	char				*t_redirection;
 };
 
 struct isns {
@@ -301,6 +303,8 @@ int			portal_group_add_listen(struct por
 			    const char *listen, bool iser);
 int			portal_group_set_filter(struct portal_group *pg,
 			    const char *filter);
+int			portal_group_set_redirection(struct portal_group *pg,
+			    const char *addr);
 
 int			isns_new(struct conf *conf, const char *addr);
 void			isns_delete(struct isns *is);
@@ -312,6 +316,8 @@ struct target		*target_new(struct conf *
 void			target_delete(struct target *target);
 struct target		*target_find(struct conf *conf,
 			    const char *name);
+int			target_set_redirection(struct target *target,
+			    const char *addr);
 
 struct lun		*lun_new(struct target *target, int lun_id);
 void			lun_delete(struct lun *lun);

Modified: head/usr.sbin/ctld/login.c
==============================================================================
--- head/usr.sbin/ctld/login.c	Sun Nov  9 11:13:15 2014	(r274307)
+++ head/usr.sbin/ctld/login.c	Sun Nov  9 13:01:09 2014	(r274308)
@@ -613,6 +613,66 @@ login_negotiate_key(struct pdu *request,
 }
 
 static void
+login_redirect(struct pdu *request, const char *target_address)
+{
+	struct pdu *response;
+	struct iscsi_bhs_login_response *bhslr2;
+	struct keys *response_keys;
+
+	response = login_new_response(request);
+	bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
+	bhslr2->bhslr_status_class = 0x01;
+	bhslr2->bhslr_status_detail = 0x01;
+	login_set_csg(response, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
+	login_set_nsg(response, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
+
+	response_keys = keys_new();
+	keys_add(response_keys, "TargetAddress", target_address);
+
+	keys_save(response_keys, response);
+	pdu_send(response);
+	pdu_delete(response);
+	keys_delete(response_keys);
+}
+
+static bool
+login_portal_redirect(struct connection *conn, struct pdu *request)
+{
+	const struct portal_group *pg;
+
+	pg = conn->conn_portal->p_portal_group;
+	if (pg->pg_redirection == NULL)
+		return (false);
+
+	log_debugx("portal-group \"%s\" configured to redirect to %s",
+	    pg->pg_name, pg->pg_redirection);
+	login_redirect(request, pg->pg_redirection);
+
+	return (true);
+}
+
+static bool
+login_target_redirect(struct connection *conn, struct pdu *request)
+{
+	const char *target_address;
+
+	assert(conn->conn_portal->p_portal_group->pg_redirection == NULL);
+
+	if (conn->conn_target == NULL)
+		return (false);
+
+	target_address = conn->conn_target->t_redirection;
+	if (target_address == NULL)
+		return (false);
+
+	log_debugx("target \"%s\" configured to redirect to %s",
+	  conn->conn_target->t_name, target_address);
+	login_redirect(request, target_address);
+
+	return (true);
+}
+
+static void
 login_negotiate(struct connection *conn, struct pdu *request)
 {
 	struct pdu *response;
@@ -680,6 +740,7 @@ login(struct connection *conn)
 	struct portal_group *pg;
 	const char *initiator_name, *initiator_alias, *session_type,
 	    *target_name, *auth_method;
+	bool redirected;
 
 	/*
 	 * Handle the initial Login Request - figure out required authentication
@@ -722,6 +783,12 @@ login(struct connection *conn)
 	 */
 	setproctitle("%s (%s)", conn->conn_initiator_addr, conn->conn_initiator_name);
 
+	redirected = login_portal_redirect(conn, request);
+	if (redirected) {
+		log_debugx("initiator redirected; exiting");
+		exit(0);
+	}
+
 	initiator_alias = keys_find(request_keys, "InitiatorAlias");
 	if (initiator_alias != NULL)
 		conn->conn_initiator_alias = checked_strdup(initiator_alias);
@@ -809,6 +876,12 @@ login(struct connection *conn)
 
 		keys_delete(request_keys);
 
+		redirected = login_target_redirect(conn, request);
+		if (redirected) {
+			log_debugx("initiator redirected; exiting");
+			exit(0);
+		}
+
 		log_debugx("initiator skipped the authentication, "
 		    "and we don't need it; proceeding with negotiation");
 		login_negotiate(conn, request);
@@ -820,6 +893,12 @@ login(struct connection *conn)
 		 * Initiator might want to to authenticate,
 		 * but we don't need it.
 		 */
+		redirected = login_target_redirect(conn, request);
+		if (redirected) {
+			log_debugx("initiator redirected; exiting");
+			exit(0);
+		}
+
 		log_debugx("authentication not required; "
 		    "transitioning to operational parameter negotiation");
 
@@ -908,5 +987,17 @@ login(struct connection *conn)
 
 	login_chap(conn, ag);
 
+	/*
+	 * RFC 3720, 10.13.5.  Status-Class and Status-Detail, says
+	 * the redirection SHOULD be accepted by the initiator before
+	 * authentication, but MUST be be accepted afterwards; that's
+	 * why we're doing it here and not earlier.
+	 */
+	redirected = login_target_redirect(conn, request);
+	if (redirected) {
+		log_debugx("initiator redirected; exiting");
+		exit(0);
+	}
+
 	login_negotiate(conn, NULL);
 }

Modified: head/usr.sbin/ctld/parse.y
==============================================================================
--- head/usr.sbin/ctld/parse.y	Sun Nov  9 11:13:15 2014	(r274307)
+++ head/usr.sbin/ctld/parse.y	Sun Nov  9 13:01:09 2014	(r274308)
@@ -61,7 +61,8 @@ extern void	yyrestart(FILE *);
 %token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER
 %token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
 %token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION
-%token PATH PIDFILE PORTAL_GROUP SEMICOLON SERIAL SIZE STR TARGET TIMEOUT 
+%token PATH PIDFILE PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR
+%token TARGET TIMEOUT 
 
 %union
 {
@@ -338,6 +339,8 @@ portal_group_entry:
 	portal_group_listen
 	|
 	portal_group_listen_iser
+	|
+	portal_group_redirect
 	;
 
 portal_group_discovery_auth_group:	DISCOVERY_AUTH_GROUP STR
@@ -393,6 +396,17 @@ portal_group_listen_iser:	LISTEN_ISER ST
 	}
 	;
 
+portal_group_redirect:	REDIRECT STR
+	{
+		int error;
+
+		error = portal_group_set_redirection(portal_group, $2);
+		free($2);
+		if (error != 0)
+			return (1);
+	}
+	;
+
 target:	TARGET target_name
     OPENING_BRACKET target_entries CLOSING_BRACKET
 	{
@@ -433,6 +447,8 @@ target_entry:
 	|
 	target_portal_group
 	|
+	target_redirect
+	|
 	target_lun
 	;
 
@@ -635,6 +651,17 @@ target_portal_group:	PORTAL_GROUP STR
 	}
 	;
 
+target_redirect:	REDIRECT STR
+	{
+		int error;
+
+		error = target_set_redirection(target, $2);
+		free($2);
+		if (error != 0)
+			return (1);
+	}
+	;
+
 target_lun:	LUN lun_number
     OPENING_BRACKET lun_entries CLOSING_BRACKET
 	{

Modified: head/usr.sbin/ctld/token.l
==============================================================================
--- head/usr.sbin/ctld/token.l	Sun Nov  9 11:13:15 2014	(r274307)
+++ head/usr.sbin/ctld/token.l	Sun Nov  9 13:01:09 2014	(r274308)
@@ -72,6 +72,7 @@ isns-server		{ return ISNS_SERVER; }
 isns-period		{ return ISNS_PERIOD; }
 isns-timeout		{ return ISNS_TIMEOUT; }
 portal-group		{ return PORTAL_GROUP; }
+redirect		{ return REDIRECT; }
 serial			{ return SERIAL; }
 size			{ return SIZE; }
 target			{ return TARGET; }


More information about the svn-src-all mailing list