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; }
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to