2013-09-14 15:29:06 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2012 The FreeBSD Foundation
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This software was developed by Edward Tomasz Napierala under sponsorship
|
|
|
|
* from the FreeBSD Foundation.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-08-21 15:32:38 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <netinet/in.h>
|
2014-07-28 12:47:09 +00:00
|
|
|
#include <arpa/inet.h>
|
2013-09-14 15:29:06 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "ctld.h"
|
2014-10-25 12:50:26 +00:00
|
|
|
#include "isns.h"
|
2013-09-14 15:29:06 +00:00
|
|
|
|
2014-04-16 10:06:37 +00:00
|
|
|
bool proxy_mode = false;
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
static volatile bool sighup_received = false;
|
|
|
|
static volatile bool sigterm_received = false;
|
|
|
|
static volatile bool sigalrm_received = false;
|
|
|
|
|
|
|
|
static int nchildren = 0;
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
fprintf(stderr, "usage: ctld [-d][-f config-file]\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
checked_strdup(const char *s)
|
|
|
|
{
|
|
|
|
char *c;
|
|
|
|
|
|
|
|
c = strdup(s);
|
|
|
|
if (c == NULL)
|
|
|
|
log_err(1, "strdup");
|
|
|
|
return (c);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct conf *
|
|
|
|
conf_new(void)
|
|
|
|
{
|
|
|
|
struct conf *conf;
|
|
|
|
|
|
|
|
conf = calloc(1, sizeof(*conf));
|
|
|
|
if (conf == NULL)
|
|
|
|
log_err(1, "calloc");
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
TAILQ_INIT(&conf->conf_luns);
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_INIT(&conf->conf_targets);
|
|
|
|
TAILQ_INIT(&conf->conf_auth_groups);
|
|
|
|
TAILQ_INIT(&conf->conf_portal_groups);
|
2014-10-25 12:50:26 +00:00
|
|
|
TAILQ_INIT(&conf->conf_isns);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
conf->conf_isns_period = 900;
|
|
|
|
conf->conf_isns_timeout = 5;
|
2013-09-14 15:29:06 +00:00
|
|
|
conf->conf_debug = 0;
|
|
|
|
conf->conf_timeout = 60;
|
|
|
|
conf->conf_maxproc = 30;
|
|
|
|
|
|
|
|
return (conf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
conf_delete(struct conf *conf)
|
|
|
|
{
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
struct lun *lun, *ltmp;
|
2013-09-14 15:29:06 +00:00
|
|
|
struct target *targ, *tmp;
|
|
|
|
struct auth_group *ag, *cagtmp;
|
|
|
|
struct portal_group *pg, *cpgtmp;
|
2014-10-25 12:50:26 +00:00
|
|
|
struct isns *is, *istmp;
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
assert(conf->conf_pidfh == NULL);
|
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
TAILQ_FOREACH_SAFE(lun, &conf->conf_luns, l_next, ltmp)
|
|
|
|
lun_delete(lun);
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_FOREACH_SAFE(targ, &conf->conf_targets, t_next, tmp)
|
|
|
|
target_delete(targ);
|
|
|
|
TAILQ_FOREACH_SAFE(ag, &conf->conf_auth_groups, ag_next, cagtmp)
|
|
|
|
auth_group_delete(ag);
|
|
|
|
TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp)
|
|
|
|
portal_group_delete(pg);
|
2014-10-25 12:50:26 +00:00
|
|
|
TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp)
|
|
|
|
isns_delete(is);
|
2013-09-14 15:29:06 +00:00
|
|
|
free(conf->conf_pidfile_path);
|
|
|
|
free(conf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct auth *
|
|
|
|
auth_new(struct auth_group *ag)
|
|
|
|
{
|
|
|
|
struct auth *auth;
|
|
|
|
|
|
|
|
auth = calloc(1, sizeof(*auth));
|
|
|
|
if (auth == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
auth->a_auth_group = ag;
|
|
|
|
TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next);
|
|
|
|
return (auth);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
auth_delete(struct auth *auth)
|
|
|
|
{
|
|
|
|
TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next);
|
|
|
|
|
|
|
|
free(auth->a_user);
|
|
|
|
free(auth->a_secret);
|
|
|
|
free(auth->a_mutual_user);
|
|
|
|
free(auth->a_mutual_secret);
|
|
|
|
free(auth);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct auth *
|
2014-04-16 11:01:59 +00:00
|
|
|
auth_find(const struct auth_group *ag, const char *user)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
const struct auth *auth;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(auth, &ag->ag_auths, a_next) {
|
|
|
|
if (strcmp(auth->a_user, user) == 0)
|
|
|
|
return (auth);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2014-02-11 11:10:01 +00:00
|
|
|
static void
|
|
|
|
auth_check_secret_length(struct auth *auth)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = strlen(auth->a_secret);
|
|
|
|
if (len > 16) {
|
|
|
|
if (auth->a_auth_group->ag_name != NULL)
|
|
|
|
log_warnx("secret for user \"%s\", auth-group \"%s\", "
|
|
|
|
"is too long; it should be at most 16 characters "
|
|
|
|
"long", auth->a_user, auth->a_auth_group->ag_name);
|
|
|
|
else
|
|
|
|
log_warnx("secret for user \"%s\", target \"%s\", "
|
|
|
|
"is too long; it should be at most 16 characters "
|
|
|
|
"long", auth->a_user,
|
2014-02-11 11:14:50 +00:00
|
|
|
auth->a_auth_group->ag_target->t_name);
|
2014-02-11 11:10:01 +00:00
|
|
|
}
|
|
|
|
if (len < 12) {
|
|
|
|
if (auth->a_auth_group->ag_name != NULL)
|
|
|
|
log_warnx("secret for user \"%s\", auth-group \"%s\", "
|
|
|
|
"is too short; it should be at least 12 characters "
|
|
|
|
"long", auth->a_user,
|
|
|
|
auth->a_auth_group->ag_name);
|
|
|
|
else
|
|
|
|
log_warnx("secret for user \"%s\", target \"%s\", "
|
|
|
|
"is too short; it should be at least 16 characters "
|
|
|
|
"long", auth->a_user,
|
2014-02-11 11:14:50 +00:00
|
|
|
auth->a_auth_group->ag_target->t_name);
|
2014-02-11 11:10:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (auth->a_mutual_secret != NULL) {
|
|
|
|
len = strlen(auth->a_secret);
|
|
|
|
if (len > 16) {
|
|
|
|
if (auth->a_auth_group->ag_name != NULL)
|
|
|
|
log_warnx("mutual secret for user \"%s\", "
|
|
|
|
"auth-group \"%s\", is too long; it should "
|
|
|
|
"be at most 16 characters long",
|
|
|
|
auth->a_user, auth->a_auth_group->ag_name);
|
|
|
|
else
|
|
|
|
log_warnx("mutual secret for user \"%s\", "
|
|
|
|
"target \"%s\", is too long; it should "
|
|
|
|
"be at most 16 characters long",
|
|
|
|
auth->a_user,
|
2014-02-11 11:14:50 +00:00
|
|
|
auth->a_auth_group->ag_target->t_name);
|
2014-02-11 11:10:01 +00:00
|
|
|
}
|
|
|
|
if (len < 12) {
|
|
|
|
if (auth->a_auth_group->ag_name != NULL)
|
|
|
|
log_warnx("mutual secret for user \"%s\", "
|
|
|
|
"auth-group \"%s\", is too short; it "
|
|
|
|
"should be at least 12 characters long",
|
|
|
|
auth->a_user, auth->a_auth_group->ag_name);
|
|
|
|
else
|
|
|
|
log_warnx("mutual secret for user \"%s\", "
|
|
|
|
"target \"%s\", is too short; it should be "
|
|
|
|
"at least 16 characters long",
|
|
|
|
auth->a_user,
|
2014-02-11 11:14:50 +00:00
|
|
|
auth->a_auth_group->ag_target->t_name);
|
2014-02-11 11:10:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct auth *
|
|
|
|
auth_new_chap(struct auth_group *ag, const char *user,
|
|
|
|
const char *secret)
|
|
|
|
{
|
|
|
|
struct auth *auth;
|
|
|
|
|
|
|
|
if (ag->ag_type == AG_TYPE_UNKNOWN)
|
|
|
|
ag->ag_type = AG_TYPE_CHAP;
|
|
|
|
if (ag->ag_type != AG_TYPE_CHAP) {
|
|
|
|
if (ag->ag_name != NULL)
|
|
|
|
log_warnx("cannot mix \"chap\" authentication with "
|
|
|
|
"other types for auth-group \"%s\"", ag->ag_name);
|
|
|
|
else
|
|
|
|
log_warnx("cannot mix \"chap\" authentication with "
|
|
|
|
"other types for target \"%s\"",
|
2014-02-11 11:14:50 +00:00
|
|
|
ag->ag_target->t_name);
|
2014-02-11 11:10:01 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
auth = auth_new(ag);
|
|
|
|
auth->a_user = checked_strdup(user);
|
|
|
|
auth->a_secret = checked_strdup(secret);
|
|
|
|
|
|
|
|
auth_check_secret_length(auth);
|
|
|
|
|
|
|
|
return (auth);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct auth *
|
|
|
|
auth_new_chap_mutual(struct auth_group *ag, const char *user,
|
|
|
|
const char *secret, const char *user2, const char *secret2)
|
|
|
|
{
|
|
|
|
struct auth *auth;
|
|
|
|
|
|
|
|
if (ag->ag_type == AG_TYPE_UNKNOWN)
|
|
|
|
ag->ag_type = AG_TYPE_CHAP_MUTUAL;
|
|
|
|
if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) {
|
|
|
|
if (ag->ag_name != NULL)
|
|
|
|
log_warnx("cannot mix \"chap-mutual\" authentication "
|
|
|
|
"with other types for auth-group \"%s\"",
|
2014-10-22 09:17:17 +00:00
|
|
|
ag->ag_name);
|
2014-02-11 11:10:01 +00:00
|
|
|
else
|
|
|
|
log_warnx("cannot mix \"chap-mutual\" authentication "
|
|
|
|
"with other types for target \"%s\"",
|
2014-02-11 11:14:50 +00:00
|
|
|
ag->ag_target->t_name);
|
2014-02-11 11:10:01 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
auth = auth_new(ag);
|
|
|
|
auth->a_user = checked_strdup(user);
|
|
|
|
auth->a_secret = checked_strdup(secret);
|
|
|
|
auth->a_mutual_user = checked_strdup(user2);
|
|
|
|
auth->a_mutual_secret = checked_strdup(secret2);
|
|
|
|
|
|
|
|
auth_check_secret_length(auth);
|
|
|
|
|
|
|
|
return (auth);
|
|
|
|
}
|
|
|
|
|
2014-02-11 11:08:04 +00:00
|
|
|
const struct auth_name *
|
|
|
|
auth_name_new(struct auth_group *ag, const char *name)
|
|
|
|
{
|
|
|
|
struct auth_name *an;
|
|
|
|
|
|
|
|
an = calloc(1, sizeof(*an));
|
|
|
|
if (an == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
an->an_auth_group = ag;
|
|
|
|
an->an_initator_name = checked_strdup(name);
|
|
|
|
TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next);
|
|
|
|
return (an);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
auth_name_delete(struct auth_name *an)
|
|
|
|
{
|
|
|
|
TAILQ_REMOVE(&an->an_auth_group->ag_names, an, an_next);
|
|
|
|
|
|
|
|
free(an->an_initator_name);
|
|
|
|
free(an);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
auth_name_defined(const struct auth_group *ag)
|
|
|
|
{
|
|
|
|
if (TAILQ_EMPTY(&ag->ag_names))
|
|
|
|
return (false);
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct auth_name *
|
|
|
|
auth_name_find(const struct auth_group *ag, const char *name)
|
|
|
|
{
|
|
|
|
const struct auth_name *auth_name;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) {
|
|
|
|
if (strcmp(auth_name->an_initator_name, name) == 0)
|
|
|
|
return (auth_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2014-10-24 11:40:09 +00:00
|
|
|
int
|
|
|
|
auth_name_check(const struct auth_group *ag, const char *initiator_name)
|
|
|
|
{
|
|
|
|
if (!auth_name_defined(ag))
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
if (auth_name_find(ag, initiator_name) == NULL)
|
|
|
|
return (1);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2014-02-11 11:08:04 +00:00
|
|
|
const struct auth_portal *
|
|
|
|
auth_portal_new(struct auth_group *ag, const char *portal)
|
|
|
|
{
|
|
|
|
struct auth_portal *ap;
|
2014-07-28 12:47:09 +00:00
|
|
|
char *net, *mask, *str, *tmp;
|
|
|
|
int len, dm, m;
|
2014-02-11 11:08:04 +00:00
|
|
|
|
|
|
|
ap = calloc(1, sizeof(*ap));
|
|
|
|
if (ap == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
ap->ap_auth_group = ag;
|
|
|
|
ap->ap_initator_portal = checked_strdup(portal);
|
2014-07-28 12:47:09 +00:00
|
|
|
mask = str = checked_strdup(portal);
|
|
|
|
net = strsep(&mask, "/");
|
|
|
|
if (net[0] == '[')
|
|
|
|
net++;
|
|
|
|
len = strlen(net);
|
|
|
|
if (len == 0)
|
|
|
|
goto error;
|
|
|
|
if (net[len - 1] == ']')
|
|
|
|
net[len - 1] = 0;
|
|
|
|
if (strchr(net, ':') != NULL) {
|
|
|
|
struct sockaddr_in6 *sin6 =
|
|
|
|
(struct sockaddr_in6 *)&ap->ap_sa;
|
|
|
|
|
|
|
|
sin6->sin6_len = sizeof(*sin6);
|
|
|
|
sin6->sin6_family = AF_INET6;
|
|
|
|
if (inet_pton(AF_INET6, net, &sin6->sin6_addr) <= 0)
|
|
|
|
goto error;
|
|
|
|
dm = 128;
|
|
|
|
} else {
|
|
|
|
struct sockaddr_in *sin =
|
|
|
|
(struct sockaddr_in *)&ap->ap_sa;
|
|
|
|
|
|
|
|
sin->sin_len = sizeof(*sin);
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
if (inet_pton(AF_INET, net, &sin->sin_addr) <= 0)
|
|
|
|
goto error;
|
|
|
|
dm = 32;
|
|
|
|
}
|
|
|
|
if (mask != NULL) {
|
|
|
|
m = strtol(mask, &tmp, 0);
|
|
|
|
if (m < 0 || m > dm || tmp[0] != 0)
|
|
|
|
goto error;
|
|
|
|
} else
|
|
|
|
m = dm;
|
|
|
|
ap->ap_mask = m;
|
|
|
|
free(str);
|
2014-02-11 11:08:04 +00:00
|
|
|
TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next);
|
|
|
|
return (ap);
|
2014-07-28 12:47:09 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
log_errx(1, "Incorrect initiator portal '%s'", portal);
|
|
|
|
return (NULL);
|
2014-02-11 11:08:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
auth_portal_delete(struct auth_portal *ap)
|
|
|
|
{
|
|
|
|
TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next);
|
|
|
|
|
|
|
|
free(ap->ap_initator_portal);
|
|
|
|
free(ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
auth_portal_defined(const struct auth_group *ag)
|
|
|
|
{
|
|
|
|
if (TAILQ_EMPTY(&ag->ag_portals))
|
|
|
|
return (false);
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct auth_portal *
|
2014-07-28 12:47:09 +00:00
|
|
|
auth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss)
|
2014-02-11 11:08:04 +00:00
|
|
|
{
|
2014-07-28 12:47:09 +00:00
|
|
|
const struct auth_portal *ap;
|
2014-07-28 14:32:20 +00:00
|
|
|
const uint8_t *a, *b;
|
2014-07-28 12:47:09 +00:00
|
|
|
int i;
|
2014-07-28 14:32:20 +00:00
|
|
|
uint8_t bmask;
|
2014-02-11 11:08:04 +00:00
|
|
|
|
2014-07-28 12:47:09 +00:00
|
|
|
TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) {
|
|
|
|
if (ap->ap_sa.ss_family != ss->ss_family)
|
|
|
|
continue;
|
|
|
|
if (ss->ss_family == AF_INET) {
|
2014-07-28 14:32:20 +00:00
|
|
|
a = (const uint8_t *)
|
|
|
|
&((const struct sockaddr_in *)ss)->sin_addr;
|
|
|
|
b = (const uint8_t *)
|
|
|
|
&((const struct sockaddr_in *)&ap->ap_sa)->sin_addr;
|
2014-07-28 12:47:09 +00:00
|
|
|
} else {
|
2014-07-28 14:32:20 +00:00
|
|
|
a = (const uint8_t *)
|
|
|
|
&((const struct sockaddr_in6 *)ss)->sin6_addr;
|
|
|
|
b = (const uint8_t *)
|
|
|
|
&((const struct sockaddr_in6 *)&ap->ap_sa)->sin6_addr;
|
2014-07-28 12:47:09 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < ap->ap_mask / 8; i++) {
|
|
|
|
if (a[i] != b[i])
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
if (ap->ap_mask % 8) {
|
|
|
|
bmask = 0xff << (8 - (ap->ap_mask % 8));
|
|
|
|
if ((a[i] & bmask) != (b[i] & bmask))
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
return (ap);
|
|
|
|
next:
|
|
|
|
;
|
2014-02-11 11:08:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2014-10-24 11:40:09 +00:00
|
|
|
int
|
|
|
|
auth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!auth_portal_defined(ag))
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
if (auth_portal_find(ag, sa) == NULL)
|
|
|
|
return (1);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
struct auth_group *
|
|
|
|
auth_group_new(struct conf *conf, const char *name)
|
|
|
|
{
|
|
|
|
struct auth_group *ag;
|
|
|
|
|
|
|
|
if (name != NULL) {
|
|
|
|
ag = auth_group_find(conf, name);
|
|
|
|
if (ag != NULL) {
|
|
|
|
log_warnx("duplicated auth-group \"%s\"", name);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ag = calloc(1, sizeof(*ag));
|
|
|
|
if (ag == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
if (name != NULL)
|
|
|
|
ag->ag_name = checked_strdup(name);
|
|
|
|
TAILQ_INIT(&ag->ag_auths);
|
2014-02-11 11:08:04 +00:00
|
|
|
TAILQ_INIT(&ag->ag_names);
|
|
|
|
TAILQ_INIT(&ag->ag_portals);
|
2013-09-14 15:29:06 +00:00
|
|
|
ag->ag_conf = conf;
|
|
|
|
TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next);
|
|
|
|
|
|
|
|
return (ag);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
auth_group_delete(struct auth_group *ag)
|
|
|
|
{
|
2014-02-11 11:08:04 +00:00
|
|
|
struct auth *auth, *auth_tmp;
|
|
|
|
struct auth_name *auth_name, *auth_name_tmp;
|
|
|
|
struct auth_portal *auth_portal, *auth_portal_tmp;
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next);
|
|
|
|
|
2014-02-11 11:08:04 +00:00
|
|
|
TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp)
|
2013-09-14 15:29:06 +00:00
|
|
|
auth_delete(auth);
|
2014-02-11 11:08:04 +00:00
|
|
|
TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp)
|
|
|
|
auth_name_delete(auth_name);
|
|
|
|
TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next,
|
|
|
|
auth_portal_tmp)
|
|
|
|
auth_portal_delete(auth_portal);
|
2013-09-14 15:29:06 +00:00
|
|
|
free(ag->ag_name);
|
|
|
|
free(ag);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct auth_group *
|
2014-04-16 11:01:59 +00:00
|
|
|
auth_group_find(const struct conf *conf, const char *name)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct auth_group *ag;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) {
|
|
|
|
if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0)
|
|
|
|
return (ag);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2014-02-11 11:26:05 +00:00
|
|
|
int
|
2014-10-29 09:36:02 +00:00
|
|
|
auth_group_set_type(struct auth_group *ag, const char *str)
|
2014-02-11 11:26:05 +00:00
|
|
|
{
|
2014-10-29 09:36:02 +00:00
|
|
|
int type;
|
2014-02-11 11:26:05 +00:00
|
|
|
|
|
|
|
if (strcmp(str, "none") == 0) {
|
|
|
|
type = AG_TYPE_NO_AUTHENTICATION;
|
2014-02-11 11:32:36 +00:00
|
|
|
} else if (strcmp(str, "deny") == 0) {
|
|
|
|
type = AG_TYPE_DENY;
|
2014-02-11 11:26:05 +00:00
|
|
|
} else if (strcmp(str, "chap") == 0) {
|
|
|
|
type = AG_TYPE_CHAP;
|
|
|
|
} else if (strcmp(str, "chap-mutual") == 0) {
|
|
|
|
type = AG_TYPE_CHAP_MUTUAL;
|
|
|
|
} else {
|
|
|
|
if (ag->ag_name != NULL)
|
|
|
|
log_warnx("invalid auth-type \"%s\" for auth-group "
|
|
|
|
"\"%s\"", str, ag->ag_name);
|
|
|
|
else
|
|
|
|
log_warnx("invalid auth-type \"%s\" for target "
|
|
|
|
"\"%s\"", str, ag->ag_target->t_name);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2014-10-29 09:36:02 +00:00
|
|
|
if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) {
|
|
|
|
if (ag->ag_name != NULL) {
|
2014-02-11 11:26:05 +00:00
|
|
|
log_warnx("cannot set auth-type to \"%s\" for "
|
|
|
|
"auth-group \"%s\"; already has a different "
|
|
|
|
"type", str, ag->ag_name);
|
2014-10-29 09:36:02 +00:00
|
|
|
} else {
|
2014-02-11 11:26:05 +00:00
|
|
|
log_warnx("cannot set auth-type to \"%s\" for target "
|
|
|
|
"\"%s\"; already has a different type",
|
|
|
|
str, ag->ag_target->t_name);
|
2014-10-29 09:36:02 +00:00
|
|
|
}
|
2014-02-11 11:26:05 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2014-10-29 09:36:02 +00:00
|
|
|
ag->ag_type = type;
|
|
|
|
|
|
|
|
return (0);
|
2014-02-11 11:26:05 +00:00
|
|
|
}
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
static struct portal *
|
|
|
|
portal_new(struct portal_group *pg)
|
|
|
|
{
|
|
|
|
struct portal *portal;
|
|
|
|
|
|
|
|
portal = calloc(1, sizeof(*portal));
|
|
|
|
if (portal == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
TAILQ_INIT(&portal->p_targets);
|
|
|
|
portal->p_portal_group = pg;
|
|
|
|
TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next);
|
|
|
|
return (portal);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
portal_delete(struct portal *portal)
|
|
|
|
{
|
2014-09-06 09:03:13 +00:00
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next);
|
2014-09-06 09:03:13 +00:00
|
|
|
if (portal->p_ai != NULL)
|
|
|
|
freeaddrinfo(portal->p_ai);
|
2013-09-14 15:29:06 +00:00
|
|
|
free(portal->p_listen);
|
|
|
|
free(portal);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct portal_group *
|
|
|
|
portal_group_new(struct conf *conf, const char *name)
|
|
|
|
{
|
|
|
|
struct portal_group *pg;
|
|
|
|
|
2013-09-18 21:15:21 +00:00
|
|
|
pg = portal_group_find(conf, name);
|
|
|
|
if (pg != NULL) {
|
|
|
|
log_warnx("duplicated portal-group \"%s\"", name);
|
|
|
|
return (NULL);
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pg = calloc(1, sizeof(*pg));
|
|
|
|
if (pg == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
pg->pg_name = checked_strdup(name);
|
|
|
|
TAILQ_INIT(&pg->pg_portals);
|
|
|
|
pg->pg_conf = conf;
|
|
|
|
conf->conf_last_portal_group_tag++;
|
|
|
|
pg->pg_tag = conf->conf_last_portal_group_tag;
|
|
|
|
TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next);
|
|
|
|
|
|
|
|
return (pg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
portal_group_delete(struct portal_group *pg)
|
|
|
|
{
|
|
|
|
struct portal *portal, *tmp;
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next);
|
|
|
|
|
|
|
|
TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp)
|
|
|
|
portal_delete(portal);
|
|
|
|
free(pg->pg_name);
|
2014-11-09 13:01:09 +00:00
|
|
|
free(pg->pg_redirection);
|
2013-09-14 15:29:06 +00:00
|
|
|
free(pg);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct portal_group *
|
2014-04-16 11:01:59 +00:00
|
|
|
portal_group_find(const struct conf *conf, const char *name)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct portal_group *pg;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
|
|
|
|
if (strcmp(pg->pg_name, name) == 0)
|
|
|
|
return (pg);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
static int
|
|
|
|
parse_addr_port(char *arg, const char *def_port, struct addrinfo **ai)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct addrinfo hints;
|
2014-12-03 09:32:51 +00:00
|
|
|
char *str, *addr, *ch;
|
2013-09-14 15:29:06 +00:00
|
|
|
const char *port;
|
|
|
|
int error, colons = 0;
|
|
|
|
|
2014-12-03 09:32:51 +00:00
|
|
|
str = arg = strdup(arg);
|
2013-09-14 15:29:06 +00:00
|
|
|
if (arg[0] == '[') {
|
|
|
|
/*
|
|
|
|
* IPv6 address in square brackets, perhaps with port.
|
|
|
|
*/
|
|
|
|
arg++;
|
|
|
|
addr = strsep(&arg, "]");
|
2014-10-25 12:50:26 +00:00
|
|
|
if (arg == NULL)
|
2013-09-14 15:29:06 +00:00
|
|
|
return (1);
|
|
|
|
if (arg[0] == '\0') {
|
2014-10-25 12:50:26 +00:00
|
|
|
port = def_port;
|
2013-09-14 15:29:06 +00:00
|
|
|
} else if (arg[0] == ':') {
|
|
|
|
port = arg + 1;
|
2014-12-03 09:32:51 +00:00
|
|
|
} else {
|
|
|
|
free(str);
|
2013-09-14 15:29:06 +00:00
|
|
|
return (1);
|
2014-12-03 09:32:51 +00:00
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Either IPv6 address without brackets - and without
|
|
|
|
* a port - or IPv4 address. Just count the colons.
|
|
|
|
*/
|
|
|
|
for (ch = arg; *ch != '\0'; ch++) {
|
|
|
|
if (*ch == ':')
|
|
|
|
colons++;
|
|
|
|
}
|
|
|
|
if (colons > 1) {
|
|
|
|
addr = arg;
|
2014-10-25 12:50:26 +00:00
|
|
|
port = def_port;
|
2013-09-14 15:29:06 +00:00
|
|
|
} else {
|
|
|
|
addr = strsep(&arg, ":");
|
|
|
|
if (arg == NULL)
|
2014-10-25 12:50:26 +00:00
|
|
|
port = def_port;
|
2013-09-14 15:29:06 +00:00
|
|
|
else
|
|
|
|
port = arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_family = PF_UNSPEC;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_flags = AI_PASSIVE;
|
2014-10-25 12:50:26 +00:00
|
|
|
error = getaddrinfo(addr, port, &hints, ai);
|
2014-12-03 09:32:51 +00:00
|
|
|
free(str);
|
|
|
|
return ((error != 0) ? 1 : 0);
|
2014-10-25 12:50:26 +00:00
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
int
|
|
|
|
portal_group_add_listen(struct portal_group *pg, const char *value, bool iser)
|
|
|
|
{
|
|
|
|
struct portal *portal;
|
|
|
|
|
|
|
|
portal = portal_new(pg);
|
|
|
|
portal->p_listen = checked_strdup(value);
|
|
|
|
portal->p_iser = iser;
|
|
|
|
|
|
|
|
if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) {
|
|
|
|
log_warnx("invalid listen address %s", portal->p_listen);
|
2014-09-06 09:03:13 +00:00
|
|
|
portal_delete(portal);
|
2013-09-14 15:29:06 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: getaddrinfo(3) may return multiple addresses; we should turn
|
|
|
|
* those into multiple portals.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
int
|
|
|
|
isns_new(struct conf *conf, const char *addr)
|
|
|
|
{
|
|
|
|
struct isns *isns;
|
|
|
|
|
|
|
|
isns = calloc(1, sizeof(*isns));
|
|
|
|
if (isns == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
isns->i_conf = conf;
|
|
|
|
TAILQ_INSERT_TAIL(&conf->conf_isns, isns, i_next);
|
|
|
|
isns->i_addr = checked_strdup(addr);
|
|
|
|
|
|
|
|
if (parse_addr_port(isns->i_addr, "3205", &isns->i_ai)) {
|
|
|
|
log_warnx("invalid iSNS address %s", isns->i_addr);
|
|
|
|
isns_delete(isns);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: getaddrinfo(3) may return multiple addresses; we should turn
|
|
|
|
* those into multiple servers.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isns_delete(struct isns *isns)
|
|
|
|
{
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&isns->i_conf->conf_isns, isns, i_next);
|
|
|
|
free(isns->i_addr);
|
|
|
|
if (isns->i_ai != NULL)
|
|
|
|
freeaddrinfo(isns->i_ai);
|
|
|
|
free(isns);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
isns_do_connect(struct isns *isns)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = socket(isns->i_ai->ai_family, isns->i_ai->ai_socktype,
|
|
|
|
isns->i_ai->ai_protocol);
|
|
|
|
if (s < 0) {
|
|
|
|
log_warn("socket(2) failed for %s", isns->i_addr);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
if (connect(s, isns->i_ai->ai_addr, isns->i_ai->ai_addrlen)) {
|
|
|
|
log_warn("connect(2) failed for %s", isns->i_addr);
|
|
|
|
close(s);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
return(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
isns_do_register(struct isns *isns, int s, const char *hostname)
|
|
|
|
{
|
|
|
|
struct conf *conf = isns->i_conf;
|
|
|
|
struct target *target;
|
|
|
|
struct portal *portal;
|
|
|
|
struct portal_group *pg;
|
|
|
|
struct isns_req *req;
|
|
|
|
int res = 0;
|
|
|
|
uint32_t error;
|
|
|
|
|
|
|
|
req = isns_req_create(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT);
|
|
|
|
isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name);
|
|
|
|
isns_req_add_delim(req);
|
|
|
|
isns_req_add_str(req, 1, hostname);
|
|
|
|
isns_req_add_32(req, 2, 2); /* 2 -- iSCSI */
|
|
|
|
isns_req_add_32(req, 6, conf->conf_isns_period);
|
|
|
|
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
|
|
|
|
if (pg->pg_unassigned)
|
|
|
|
continue;
|
|
|
|
TAILQ_FOREACH(portal, &pg->pg_portals, p_next) {
|
|
|
|
isns_req_add_addr(req, 16, portal->p_ai);
|
|
|
|
isns_req_add_port(req, 17, portal->p_ai);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TAILQ_FOREACH(target, &conf->conf_targets, t_next) {
|
|
|
|
isns_req_add_str(req, 32, target->t_name);
|
|
|
|
isns_req_add_32(req, 33, 1); /* 1 -- Target*/
|
|
|
|
if (target->t_alias != NULL)
|
|
|
|
isns_req_add_str(req, 34, target->t_alias);
|
|
|
|
pg = target->t_portal_group;
|
|
|
|
isns_req_add_32(req, 51, pg->pg_tag);
|
|
|
|
TAILQ_FOREACH(portal, &pg->pg_portals, p_next) {
|
|
|
|
isns_req_add_addr(req, 49, portal->p_ai);
|
|
|
|
isns_req_add_port(req, 50, portal->p_ai);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res = isns_req_send(s, req);
|
|
|
|
if (res < 0) {
|
|
|
|
log_warn("send(2) failed for %s", isns->i_addr);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
res = isns_req_receive(s, req);
|
|
|
|
if (res < 0) {
|
|
|
|
log_warn("receive(2) failed for %s", isns->i_addr);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
error = isns_req_get_status(req);
|
|
|
|
if (error != 0) {
|
|
|
|
log_warnx("iSNS register error %d for %s", error, isns->i_addr);
|
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
quit:
|
|
|
|
isns_req_free(req);
|
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
isns_do_check(struct isns *isns, int s, const char *hostname)
|
|
|
|
{
|
|
|
|
struct conf *conf = isns->i_conf;
|
|
|
|
struct isns_req *req;
|
|
|
|
int res = 0;
|
|
|
|
uint32_t error;
|
|
|
|
|
|
|
|
req = isns_req_create(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT);
|
|
|
|
isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name);
|
|
|
|
isns_req_add_str(req, 1, hostname);
|
|
|
|
isns_req_add_delim(req);
|
|
|
|
isns_req_add(req, 2, 0, NULL);
|
|
|
|
res = isns_req_send(s, req);
|
|
|
|
if (res < 0) {
|
|
|
|
log_warn("send(2) failed for %s", isns->i_addr);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
res = isns_req_receive(s, req);
|
|
|
|
if (res < 0) {
|
|
|
|
log_warn("receive(2) failed for %s", isns->i_addr);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
error = isns_req_get_status(req);
|
|
|
|
if (error != 0) {
|
|
|
|
log_warnx("iSNS check error %d for %s", error, isns->i_addr);
|
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
quit:
|
|
|
|
isns_req_free(req);
|
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
isns_do_deregister(struct isns *isns, int s, const char *hostname)
|
|
|
|
{
|
|
|
|
struct conf *conf = isns->i_conf;
|
|
|
|
struct isns_req *req;
|
|
|
|
int res = 0;
|
|
|
|
uint32_t error;
|
|
|
|
|
|
|
|
req = isns_req_create(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT);
|
|
|
|
isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name);
|
|
|
|
isns_req_add_delim(req);
|
|
|
|
isns_req_add_str(req, 1, hostname);
|
|
|
|
res = isns_req_send(s, req);
|
|
|
|
if (res < 0) {
|
|
|
|
log_warn("send(2) failed for %s", isns->i_addr);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
res = isns_req_receive(s, req);
|
|
|
|
if (res < 0) {
|
|
|
|
log_warn("receive(2) failed for %s", isns->i_addr);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
error = isns_req_get_status(req);
|
|
|
|
if (error != 0) {
|
|
|
|
log_warnx("iSNS deregister error %d for %s", error, isns->i_addr);
|
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
quit:
|
|
|
|
isns_req_free(req);
|
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isns_register(struct isns *isns, struct isns *oldisns)
|
|
|
|
{
|
|
|
|
struct conf *conf = isns->i_conf;
|
2014-11-07 19:32:10 +00:00
|
|
|
int s;
|
2014-10-25 12:50:26 +00:00
|
|
|
char hostname[256];
|
|
|
|
|
|
|
|
if (TAILQ_EMPTY(&conf->conf_targets) ||
|
|
|
|
TAILQ_EMPTY(&conf->conf_portal_groups))
|
|
|
|
return;
|
|
|
|
set_timeout(conf->conf_isns_timeout, false);
|
|
|
|
s = isns_do_connect(isns);
|
|
|
|
if (s < 0) {
|
|
|
|
set_timeout(0, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gethostname(hostname, sizeof(hostname));
|
|
|
|
|
|
|
|
if (oldisns == NULL || TAILQ_EMPTY(&oldisns->i_conf->conf_targets))
|
|
|
|
oldisns = isns;
|
2014-11-07 19:32:10 +00:00
|
|
|
isns_do_deregister(oldisns, s, hostname);
|
|
|
|
isns_do_register(isns, s, hostname);
|
2014-10-25 12:50:26 +00:00
|
|
|
close(s);
|
|
|
|
set_timeout(0, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isns_check(struct isns *isns)
|
|
|
|
{
|
|
|
|
struct conf *conf = isns->i_conf;
|
|
|
|
int s, res;
|
|
|
|
char hostname[256];
|
|
|
|
|
|
|
|
if (TAILQ_EMPTY(&conf->conf_targets) ||
|
|
|
|
TAILQ_EMPTY(&conf->conf_portal_groups))
|
|
|
|
return;
|
|
|
|
set_timeout(conf->conf_isns_timeout, false);
|
|
|
|
s = isns_do_connect(isns);
|
|
|
|
if (s < 0) {
|
|
|
|
set_timeout(0, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gethostname(hostname, sizeof(hostname));
|
|
|
|
|
|
|
|
res = isns_do_check(isns, s, hostname);
|
|
|
|
if (res < 0) {
|
2014-11-07 19:32:10 +00:00
|
|
|
isns_do_deregister(isns, s, hostname);
|
|
|
|
isns_do_register(isns, s, hostname);
|
2014-10-25 12:50:26 +00:00
|
|
|
}
|
|
|
|
close(s);
|
|
|
|
set_timeout(0, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isns_deregister(struct isns *isns)
|
|
|
|
{
|
|
|
|
struct conf *conf = isns->i_conf;
|
2014-11-07 19:32:10 +00:00
|
|
|
int s;
|
2014-10-25 12:50:26 +00:00
|
|
|
char hostname[256];
|
|
|
|
|
|
|
|
if (TAILQ_EMPTY(&conf->conf_targets) ||
|
|
|
|
TAILQ_EMPTY(&conf->conf_portal_groups))
|
|
|
|
return;
|
|
|
|
set_timeout(conf->conf_isns_timeout, false);
|
|
|
|
s = isns_do_connect(isns);
|
|
|
|
if (s < 0)
|
|
|
|
return;
|
|
|
|
gethostname(hostname, sizeof(hostname));
|
|
|
|
|
2014-11-07 19:32:10 +00:00
|
|
|
isns_do_deregister(isns, s, hostname);
|
2014-10-25 12:50:26 +00:00
|
|
|
close(s);
|
|
|
|
set_timeout(0, false);
|
|
|
|
}
|
|
|
|
|
2014-10-29 09:26:55 +00:00
|
|
|
int
|
2014-10-29 09:36:02 +00:00
|
|
|
portal_group_set_filter(struct portal_group *pg, const char *str)
|
2014-10-29 09:26:55 +00:00
|
|
|
{
|
2014-10-29 09:36:02 +00:00
|
|
|
int filter;
|
2014-10-29 09:26:55 +00:00
|
|
|
|
|
|
|
if (strcmp(str, "none") == 0) {
|
|
|
|
filter = PG_FILTER_NONE;
|
|
|
|
} else if (strcmp(str, "portal") == 0) {
|
|
|
|
filter = PG_FILTER_PORTAL;
|
|
|
|
} else if (strcmp(str, "portal-name") == 0) {
|
|
|
|
filter = PG_FILTER_PORTAL_NAME;
|
|
|
|
} else if (strcmp(str, "portal-name-auth") == 0) {
|
|
|
|
filter = PG_FILTER_PORTAL_NAME_AUTH;
|
|
|
|
} else {
|
|
|
|
log_warnx("invalid discovery-filter \"%s\" for portal-group "
|
|
|
|
"\"%s\"; valid values are \"none\", \"portal\", "
|
|
|
|
"\"portal-name\", and \"portal-name-auth\"",
|
|
|
|
str, pg->pg_name);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2014-10-29 09:36:02 +00:00
|
|
|
if (pg->pg_discovery_filter != PG_FILTER_UNKNOWN &&
|
|
|
|
pg->pg_discovery_filter != filter) {
|
2014-10-29 09:26:55 +00:00
|
|
|
log_warnx("cannot set discovery-filter to \"%s\" for "
|
|
|
|
"portal-group \"%s\"; already has a different "
|
|
|
|
"value", str, pg->pg_name);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2014-10-29 09:36:02 +00:00
|
|
|
pg->pg_discovery_filter = filter;
|
|
|
|
|
|
|
|
return (0);
|
2014-10-29 09:26:55 +00:00
|
|
|
}
|
|
|
|
|
2014-11-09 13:01:09 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
static bool
|
|
|
|
valid_hex(const char ch)
|
|
|
|
{
|
|
|
|
switch (ch) {
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
case 'a':
|
|
|
|
case 'A':
|
|
|
|
case 'b':
|
|
|
|
case 'B':
|
|
|
|
case 'c':
|
|
|
|
case 'C':
|
|
|
|
case 'd':
|
|
|
|
case 'D':
|
|
|
|
case 'e':
|
|
|
|
case 'E':
|
|
|
|
case 'f':
|
|
|
|
case 'F':
|
|
|
|
return (true);
|
|
|
|
default:
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
valid_iscsi_name(const char *name)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (strlen(name) >= MAX_NAME_LEN) {
|
|
|
|
log_warnx("overlong name for target \"%s\"; max length allowed "
|
|
|
|
"by iSCSI specification is %d characters",
|
|
|
|
name, MAX_NAME_LEN);
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In the cases below, we don't return an error, just in case the admin
|
|
|
|
* was right, and we're wrong.
|
|
|
|
*/
|
|
|
|
if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) {
|
|
|
|
for (i = strlen("iqn."); name[i] != '\0'; i++) {
|
|
|
|
/*
|
|
|
|
* XXX: We should verify UTF-8 normalisation, as defined
|
2014-10-22 09:17:17 +00:00
|
|
|
* by 3.2.6.2: iSCSI Name Encoding.
|
2013-09-14 15:29:06 +00:00
|
|
|
*/
|
|
|
|
if (isalnum(name[i]))
|
|
|
|
continue;
|
|
|
|
if (name[i] == '-' || name[i] == '.' || name[i] == ':')
|
|
|
|
continue;
|
|
|
|
log_warnx("invalid character \"%c\" in target name "
|
|
|
|
"\"%s\"; allowed characters are letters, digits, "
|
|
|
|
"'-', '.', and ':'", name[i], name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* XXX: Check more stuff: valid date and a valid reversed domain.
|
|
|
|
*/
|
|
|
|
} else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) {
|
|
|
|
if (strlen(name) != strlen("eui.") + 16)
|
|
|
|
log_warnx("invalid target name \"%s\"; the \"eui.\" "
|
|
|
|
"should be followed by exactly 16 hexadecimal "
|
|
|
|
"digits", name);
|
|
|
|
for (i = strlen("eui."); name[i] != '\0'; i++) {
|
|
|
|
if (!valid_hex(name[i])) {
|
|
|
|
log_warnx("invalid character \"%c\" in target "
|
|
|
|
"name \"%s\"; allowed characters are 1-9 "
|
|
|
|
"and A-F", name[i], name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) {
|
|
|
|
if (strlen(name) > strlen("naa.") + 32)
|
|
|
|
log_warnx("invalid target name \"%s\"; the \"naa.\" "
|
|
|
|
"should be followed by at most 32 hexadecimal "
|
|
|
|
"digits", name);
|
|
|
|
for (i = strlen("naa."); name[i] != '\0'; i++) {
|
|
|
|
if (!valid_hex(name[i])) {
|
|
|
|
log_warnx("invalid character \"%c\" in target "
|
|
|
|
"name \"%s\"; allowed characters are 1-9 "
|
|
|
|
"and A-F", name[i], name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log_warnx("invalid target name \"%s\"; should start with "
|
|
|
|
"either \".iqn\", \"eui.\", or \"naa.\"",
|
|
|
|
name);
|
|
|
|
}
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct target *
|
2014-02-11 11:14:50 +00:00
|
|
|
target_new(struct conf *conf, const char *name)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct target *targ;
|
|
|
|
int i, len;
|
|
|
|
|
2014-02-11 11:14:50 +00:00
|
|
|
targ = target_find(conf, name);
|
2013-09-14 15:29:06 +00:00
|
|
|
if (targ != NULL) {
|
2014-02-11 11:14:50 +00:00
|
|
|
log_warnx("duplicated target \"%s\"", name);
|
2013-09-14 15:29:06 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
2014-02-11 11:14:50 +00:00
|
|
|
if (valid_iscsi_name(name) == false) {
|
|
|
|
log_warnx("target name \"%s\" is invalid", name);
|
2013-09-14 15:29:06 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
targ = calloc(1, sizeof(*targ));
|
|
|
|
if (targ == NULL)
|
|
|
|
log_err(1, "calloc");
|
2014-02-11 11:14:50 +00:00
|
|
|
targ->t_name = checked_strdup(name);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* RFC 3722 requires us to normalize the name to lowercase.
|
|
|
|
*/
|
2014-02-11 11:14:50 +00:00
|
|
|
len = strlen(name);
|
2013-09-14 15:29:06 +00:00
|
|
|
for (i = 0; i < len; i++)
|
2014-02-11 11:14:50 +00:00
|
|
|
targ->t_name[i] = tolower(targ->t_name[i]);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
targ->t_conf = conf;
|
|
|
|
TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next);
|
|
|
|
|
|
|
|
return (targ);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
target_delete(struct target *targ)
|
|
|
|
{
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next);
|
|
|
|
|
2014-02-11 11:14:50 +00:00
|
|
|
free(targ->t_name);
|
2014-11-09 13:01:09 +00:00
|
|
|
free(targ->t_redirection);
|
2013-09-14 15:29:06 +00:00
|
|
|
free(targ);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct target *
|
2014-02-11 11:14:50 +00:00
|
|
|
target_find(struct conf *conf, const char *name)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct target *targ;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
|
2014-02-11 11:14:50 +00:00
|
|
|
if (strcasecmp(targ->t_name, name) == 0)
|
2013-09-14 15:29:06 +00:00
|
|
|
return (targ);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2014-11-09 13:01:09 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
void
|
|
|
|
target_set_ctl_port(struct target *target, uint32_t value)
|
|
|
|
{
|
|
|
|
|
|
|
|
target->t_ctl_port = value;
|
|
|
|
}
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
struct lun *
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
lun_new(struct conf *conf, const char *name)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct lun *lun;
|
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
lun = lun_find(conf, name);
|
2013-09-14 15:29:06 +00:00
|
|
|
if (lun != NULL) {
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
log_warnx("duplicated lun \"%s\"", name);
|
2013-09-14 15:29:06 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
lun = calloc(1, sizeof(*lun));
|
|
|
|
if (lun == NULL)
|
|
|
|
log_err(1, "calloc");
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
lun->l_conf = conf;
|
|
|
|
lun->l_name = checked_strdup(name);
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_INIT(&lun->l_options);
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
TAILQ_INSERT_TAIL(&conf->conf_luns, lun, l_next);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
return (lun);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_delete(struct lun *lun)
|
|
|
|
{
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
struct target *targ;
|
2013-09-14 15:29:06 +00:00
|
|
|
struct lun_option *lo, *tmp;
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
int i;
|
2013-09-14 15:29:06 +00:00
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
TAILQ_FOREACH(targ, &lun->l_conf->conf_targets, t_next) {
|
|
|
|
for (i = 0; i < MAX_LUNS; i++) {
|
|
|
|
if (targ->t_luns[i] == lun)
|
|
|
|
targ->t_luns[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TAILQ_REMOVE(&lun->l_conf->conf_luns, lun, l_next);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp)
|
|
|
|
lun_option_delete(lo);
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
free(lun->l_name);
|
2013-09-14 15:29:06 +00:00
|
|
|
free(lun->l_backend);
|
|
|
|
free(lun->l_device_id);
|
|
|
|
free(lun->l_path);
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
free(lun->l_scsiname);
|
2013-09-14 15:29:06 +00:00
|
|
|
free(lun->l_serial);
|
|
|
|
free(lun);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct lun *
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
lun_find(const struct conf *conf, const char *name)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct lun *lun;
|
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
TAILQ_FOREACH(lun, &conf->conf_luns, l_next) {
|
|
|
|
if (strcmp(lun->l_name, name) == 0)
|
2013-09-14 15:29:06 +00:00
|
|
|
return (lun);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_set_backend(struct lun *lun, const char *value)
|
|
|
|
{
|
|
|
|
free(lun->l_backend);
|
|
|
|
lun->l_backend = checked_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_set_blocksize(struct lun *lun, size_t value)
|
|
|
|
{
|
|
|
|
|
|
|
|
lun->l_blocksize = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_set_device_id(struct lun *lun, const char *value)
|
|
|
|
{
|
|
|
|
free(lun->l_device_id);
|
|
|
|
lun->l_device_id = checked_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_set_path(struct lun *lun, const char *value)
|
|
|
|
{
|
|
|
|
free(lun->l_path);
|
|
|
|
lun->l_path = checked_strdup(value);
|
|
|
|
}
|
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
void
|
|
|
|
lun_set_scsiname(struct lun *lun, const char *value)
|
|
|
|
{
|
|
|
|
free(lun->l_scsiname);
|
|
|
|
lun->l_scsiname = checked_strdup(value);
|
|
|
|
}
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
void
|
|
|
|
lun_set_serial(struct lun *lun, const char *value)
|
|
|
|
{
|
|
|
|
free(lun->l_serial);
|
|
|
|
lun->l_serial = checked_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_set_size(struct lun *lun, size_t value)
|
|
|
|
{
|
|
|
|
|
|
|
|
lun->l_size = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_set_ctl_lun(struct lun *lun, uint32_t value)
|
|
|
|
{
|
|
|
|
|
|
|
|
lun->l_ctl_lun = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct lun_option *
|
|
|
|
lun_option_new(struct lun *lun, const char *name, const char *value)
|
|
|
|
{
|
|
|
|
struct lun_option *lo;
|
|
|
|
|
|
|
|
lo = lun_option_find(lun, name);
|
|
|
|
if (lo != NULL) {
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
log_warnx("duplicated lun option \"%s\" for lun \"%s\"",
|
|
|
|
name, lun->l_name);
|
2013-09-14 15:29:06 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
lo = calloc(1, sizeof(*lo));
|
|
|
|
if (lo == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
lo->lo_name = checked_strdup(name);
|
|
|
|
lo->lo_value = checked_strdup(value);
|
|
|
|
lo->lo_lun = lun;
|
|
|
|
TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next);
|
|
|
|
|
|
|
|
return (lo);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_option_delete(struct lun_option *lo)
|
|
|
|
{
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next);
|
|
|
|
|
|
|
|
free(lo->lo_name);
|
|
|
|
free(lo->lo_value);
|
|
|
|
free(lo);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct lun_option *
|
2014-04-16 11:01:59 +00:00
|
|
|
lun_option_find(const struct lun *lun, const char *name)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct lun_option *lo;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
|
|
|
|
if (strcmp(lo->lo_name, name) == 0)
|
|
|
|
return (lo);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lun_option_set(struct lun_option *lo, const char *value)
|
|
|
|
{
|
|
|
|
|
|
|
|
free(lo->lo_value);
|
|
|
|
lo->lo_value = checked_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct connection *
|
2014-07-28 12:47:09 +00:00
|
|
|
connection_new(struct portal *portal, int fd, const char *host,
|
|
|
|
const struct sockaddr *client_sa)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct connection *conn;
|
|
|
|
|
|
|
|
conn = calloc(1, sizeof(*conn));
|
|
|
|
if (conn == NULL)
|
|
|
|
log_err(1, "calloc");
|
|
|
|
conn->conn_portal = portal;
|
|
|
|
conn->conn_socket = fd;
|
|
|
|
conn->conn_initiator_addr = checked_strdup(host);
|
2014-07-28 12:47:09 +00:00
|
|
|
memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Default values, from RFC 3720, section 12.
|
|
|
|
*/
|
|
|
|
conn->conn_max_data_segment_length = 8192;
|
|
|
|
conn->conn_max_burst_length = 262144;
|
|
|
|
conn->conn_immediate_data = true;
|
|
|
|
|
|
|
|
return (conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static void
|
|
|
|
conf_print(struct conf *conf)
|
|
|
|
{
|
|
|
|
struct auth_group *ag;
|
|
|
|
struct auth *auth;
|
2014-02-11 11:08:04 +00:00
|
|
|
struct auth_name *auth_name;
|
|
|
|
struct auth_portal *auth_portal;
|
2013-09-14 15:29:06 +00:00
|
|
|
struct portal_group *pg;
|
|
|
|
struct portal *portal;
|
|
|
|
struct target *targ;
|
|
|
|
struct lun *lun;
|
|
|
|
struct lun_option *lo;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) {
|
|
|
|
fprintf(stderr, "auth-group %s {\n", ag->ag_name);
|
|
|
|
TAILQ_FOREACH(auth, &ag->ag_auths, a_next)
|
|
|
|
fprintf(stderr, "\t chap-mutual %s %s %s %s\n",
|
|
|
|
auth->a_user, auth->a_secret,
|
|
|
|
auth->a_mutual_user, auth->a_mutual_secret);
|
2014-02-11 11:08:04 +00:00
|
|
|
TAILQ_FOREACH(auth_name, &ag->ag_names, an_next)
|
|
|
|
fprintf(stderr, "\t initiator-name %s\n",
|
|
|
|
auth_name->an_initator_name);
|
|
|
|
TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next)
|
|
|
|
fprintf(stderr, "\t initiator-portal %s\n",
|
|
|
|
auth_portal->an_initator_portal);
|
2013-09-14 15:29:06 +00:00
|
|
|
fprintf(stderr, "}\n");
|
|
|
|
}
|
|
|
|
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
|
|
|
|
fprintf(stderr, "portal-group %s {\n", pg->pg_name);
|
|
|
|
TAILQ_FOREACH(portal, &pg->pg_portals, p_next)
|
|
|
|
fprintf(stderr, "\t listen %s\n", portal->p_listen);
|
|
|
|
fprintf(stderr, "}\n");
|
|
|
|
}
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
TAILQ_FOREACH(lun, &conf->conf_luns, l_next) {
|
|
|
|
fprintf(stderr, "\tlun %s {\n", lun->l_name);
|
|
|
|
fprintf(stderr, "\t\tpath %s\n", lun->l_path);
|
|
|
|
TAILQ_FOREACH(lo, &lun->l_options, lo_next)
|
|
|
|
fprintf(stderr, "\t\toption %s %s\n",
|
|
|
|
lo->lo_name, lo->lo_value);
|
|
|
|
fprintf(stderr, "\t}\n");
|
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
|
2014-02-11 11:14:50 +00:00
|
|
|
fprintf(stderr, "target %s {\n", targ->t_name);
|
2013-09-14 15:29:06 +00:00
|
|
|
if (targ->t_alias != NULL)
|
|
|
|
fprintf(stderr, "\t alias %s\n", targ->t_alias);
|
|
|
|
fprintf(stderr, "}\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-02-11 10:53:08 +00:00
|
|
|
static int
|
|
|
|
conf_verify_lun(struct lun *lun)
|
|
|
|
{
|
|
|
|
const struct lun *lun2;
|
|
|
|
|
|
|
|
if (lun->l_backend == NULL)
|
|
|
|
lun_set_backend(lun, "block");
|
|
|
|
if (strcmp(lun->l_backend, "block") == 0) {
|
|
|
|
if (lun->l_path == NULL) {
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
log_warnx("missing path for lun \"%s\"",
|
|
|
|
lun->l_name);
|
2014-02-11 10:53:08 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
} else if (strcmp(lun->l_backend, "ramdisk") == 0) {
|
|
|
|
if (lun->l_size == 0) {
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
log_warnx("missing size for ramdisk-backed lun \"%s\"",
|
|
|
|
lun->l_name);
|
2014-02-11 10:53:08 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
if (lun->l_path != NULL) {
|
|
|
|
log_warnx("path must not be specified "
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
"for ramdisk-backed lun \"%s\"",
|
|
|
|
lun->l_name);
|
2014-02-11 10:53:08 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lun->l_blocksize == 0) {
|
|
|
|
lun_set_blocksize(lun, DEFAULT_BLOCKSIZE);
|
|
|
|
} else if (lun->l_blocksize < 0) {
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
log_warnx("invalid blocksize for lun \"%s\"; "
|
|
|
|
"must be larger than 0", lun->l_name);
|
2014-02-11 10:53:08 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) {
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
log_warnx("invalid size for lun \"%s\"; "
|
|
|
|
"must be multiple of blocksize", lun->l_name);
|
2014-02-11 10:53:08 +00:00
|
|
|
return (1);
|
|
|
|
}
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
TAILQ_FOREACH(lun2, &lun->l_conf->conf_luns, l_next) {
|
|
|
|
if (lun == lun2)
|
|
|
|
continue;
|
|
|
|
if (lun->l_path != NULL && lun2->l_path != NULL &&
|
|
|
|
strcmp(lun->l_path, lun2->l_path) == 0) {
|
|
|
|
log_debugx("WARNING: path \"%s\" duplicated "
|
|
|
|
"between lun \"%s\", and "
|
|
|
|
"lun \"%s\"", lun->l_path,
|
|
|
|
lun->l_name, lun2->l_name);
|
2014-02-11 10:55:32 +00:00
|
|
|
}
|
|
|
|
}
|
2014-02-11 10:53:08 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
int
|
|
|
|
conf_verify(struct conf *conf)
|
|
|
|
{
|
|
|
|
struct auth_group *ag;
|
|
|
|
struct portal_group *pg;
|
|
|
|
struct target *targ;
|
2014-02-11 10:53:08 +00:00
|
|
|
struct lun *lun;
|
2014-10-22 09:40:46 +00:00
|
|
|
bool found;
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
int error, i;
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
if (conf->conf_pidfile_path == NULL)
|
|
|
|
conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE);
|
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
TAILQ_FOREACH(lun, &conf->conf_luns, l_next) {
|
|
|
|
error = conf_verify_lun(lun);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
|
|
|
|
if (targ->t_auth_group == NULL) {
|
2014-02-11 11:29:05 +00:00
|
|
|
targ->t_auth_group = auth_group_find(conf,
|
|
|
|
"default");
|
|
|
|
assert(targ->t_auth_group != NULL);
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
if (targ->t_portal_group == NULL) {
|
|
|
|
targ->t_portal_group = portal_group_find(conf,
|
|
|
|
"default");
|
|
|
|
assert(targ->t_portal_group != NULL);
|
|
|
|
}
|
2014-10-22 09:40:46 +00:00
|
|
|
found = false;
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
for (i = 0; i < MAX_LUNS; i++) {
|
|
|
|
if (targ->t_luns[i] != NULL)
|
|
|
|
found = true;
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
2014-11-09 13:01:09 +00:00
|
|
|
if (!found && targ->t_redirection == NULL) {
|
2014-04-15 14:55:56 +00:00
|
|
|
log_warnx("no LUNs defined for target \"%s\"",
|
|
|
|
targ->t_name);
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
2014-11-09 13:01:09 +00:00
|
|
|
if (found && targ->t_redirection != NULL) {
|
|
|
|
log_debugx("target \"%s\" contains luns, "
|
|
|
|
" but configured for redirection",
|
|
|
|
targ->t_name);
|
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
|
|
|
|
assert(pg->pg_name != NULL);
|
|
|
|
if (pg->pg_discovery_auth_group == NULL) {
|
|
|
|
pg->pg_discovery_auth_group =
|
2014-02-11 11:31:08 +00:00
|
|
|
auth_group_find(conf, "default");
|
2013-09-14 15:29:06 +00:00
|
|
|
assert(pg->pg_discovery_auth_group != NULL);
|
|
|
|
}
|
|
|
|
|
2014-10-29 09:26:55 +00:00
|
|
|
if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN)
|
|
|
|
pg->pg_discovery_filter = PG_FILTER_NONE;
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
|
|
|
|
if (targ->t_portal_group == pg)
|
|
|
|
break;
|
|
|
|
}
|
2014-11-09 13:01:09 +00:00
|
|
|
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 {
|
2013-09-14 15:29:06 +00:00
|
|
|
if (strcmp(pg->pg_name, "default") != 0)
|
|
|
|
log_warnx("portal-group \"%s\" not assigned "
|
|
|
|
"to any target", pg->pg_name);
|
|
|
|
pg->pg_unassigned = true;
|
2014-11-09 13:01:09 +00:00
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) {
|
|
|
|
if (ag->ag_name == NULL)
|
|
|
|
assert(ag->ag_target != NULL);
|
|
|
|
else
|
|
|
|
assert(ag->ag_target == NULL);
|
|
|
|
|
2014-10-22 09:40:46 +00:00
|
|
|
found = false;
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
|
2014-10-22 09:40:46 +00:00
|
|
|
if (targ->t_auth_group == ag) {
|
|
|
|
found = true;
|
2013-09-14 15:29:06 +00:00
|
|
|
break;
|
2014-10-22 09:40:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
|
|
|
|
if (pg->pg_discovery_auth_group == ag) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
2014-10-22 09:40:46 +00:00
|
|
|
if (!found && ag->ag_name != NULL &&
|
2014-02-11 11:31:08 +00:00
|
|
|
strcmp(ag->ag_name, "default") != 0 &&
|
2013-09-14 15:29:06 +00:00
|
|
|
strcmp(ag->ag_name, "no-authentication") != 0 &&
|
|
|
|
strcmp(ag->ag_name, "no-access") != 0) {
|
|
|
|
log_warnx("auth-group \"%s\" not assigned "
|
|
|
|
"to any target", ag->ag_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
conf_apply(struct conf *oldconf, struct conf *newconf)
|
|
|
|
{
|
|
|
|
struct target *oldtarg, *newtarg, *tmptarg;
|
|
|
|
struct lun *oldlun, *newlun, *tmplun;
|
|
|
|
struct portal_group *oldpg, *newpg;
|
|
|
|
struct portal *oldp, *newp;
|
2014-10-25 12:50:26 +00:00
|
|
|
struct isns *oldns, *newns;
|
2013-09-14 15:29:06 +00:00
|
|
|
pid_t otherpid;
|
2014-11-22 15:09:18 +00:00
|
|
|
int changed, cumulated_error = 0, error, sockbuf;
|
2013-09-14 15:29:06 +00:00
|
|
|
int one = 1;
|
|
|
|
|
|
|
|
if (oldconf->conf_debug != newconf->conf_debug) {
|
|
|
|
log_debugx("changing debug level to %d", newconf->conf_debug);
|
|
|
|
log_init(newconf->conf_debug);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldconf->conf_pidfh != NULL) {
|
|
|
|
assert(oldconf->conf_pidfile_path != NULL);
|
|
|
|
if (newconf->conf_pidfile_path != NULL &&
|
|
|
|
strcmp(oldconf->conf_pidfile_path,
|
|
|
|
newconf->conf_pidfile_path) == 0) {
|
|
|
|
newconf->conf_pidfh = oldconf->conf_pidfh;
|
|
|
|
oldconf->conf_pidfh = NULL;
|
|
|
|
} else {
|
|
|
|
log_debugx("removing pidfile %s",
|
|
|
|
oldconf->conf_pidfile_path);
|
|
|
|
pidfile_remove(oldconf->conf_pidfh);
|
|
|
|
oldconf->conf_pidfh = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) {
|
|
|
|
log_debugx("opening pidfile %s", newconf->conf_pidfile_path);
|
|
|
|
newconf->conf_pidfh =
|
|
|
|
pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid);
|
|
|
|
if (newconf->conf_pidfh == NULL) {
|
|
|
|
if (errno == EEXIST)
|
|
|
|
log_errx(1, "daemon already running, pid: %jd.",
|
|
|
|
(intmax_t)otherpid);
|
|
|
|
log_err(1, "cannot open or create pidfile \"%s\"",
|
|
|
|
newconf->conf_pidfile_path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
/* Deregister on removed iSNS servers. */
|
|
|
|
TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) {
|
|
|
|
TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) {
|
|
|
|
if (strcmp(oldns->i_addr, newns->i_addr) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (newns == NULL)
|
|
|
|
isns_deregister(oldns);
|
|
|
|
}
|
|
|
|
|
2014-04-16 11:06:45 +00:00
|
|
|
/*
|
|
|
|
* XXX: If target or lun removal fails, we should somehow "move"
|
2014-10-22 09:17:17 +00:00
|
|
|
* the old lun or target into newconf, so that subsequent
|
|
|
|
* conf_apply() would try to remove them again. That would
|
|
|
|
* be somewhat hairy, though, and lun deletion failures don't
|
|
|
|
* really happen, so leave it as it is for now.
|
2014-04-16 11:06:45 +00:00
|
|
|
*/
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
/*
|
|
|
|
* First, remove any targets present in the old configuration
|
|
|
|
* and missing in the new one.
|
|
|
|
*/
|
2013-09-14 15:29:06 +00:00
|
|
|
TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) {
|
2014-02-11 11:14:50 +00:00
|
|
|
newtarg = target_find(newconf, oldtarg->t_name);
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
if (newtarg != NULL)
|
|
|
|
continue;
|
|
|
|
error = kernel_port_remove(oldtarg);
|
|
|
|
if (error != 0) {
|
|
|
|
log_warnx("failed to remove target %s",
|
|
|
|
oldtarg->t_name);
|
|
|
|
/*
|
|
|
|
* XXX: Uncomment after fixing the root cause.
|
|
|
|
*
|
|
|
|
* cumulated_error++;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Second, remove any LUNs present in the old configuration
|
|
|
|
* and missing in the new one.
|
|
|
|
*/
|
|
|
|
TAILQ_FOREACH_SAFE(oldlun, &oldconf->conf_luns, l_next, tmplun) {
|
|
|
|
newlun = lun_find(newconf, oldlun->l_name);
|
|
|
|
if (newlun == NULL) {
|
|
|
|
log_debugx("lun \"%s\", CTL lun %d "
|
|
|
|
"not found in new configuration; "
|
|
|
|
"removing", oldlun->l_name, oldlun->l_ctl_lun);
|
|
|
|
error = kernel_lun_remove(oldlun);
|
2014-11-21 18:00:00 +00:00
|
|
|
if (error != 0) {
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
log_warnx("failed to remove lun \"%s\", "
|
|
|
|
"CTL lun %d",
|
|
|
|
oldlun->l_name, oldlun->l_ctl_lun);
|
|
|
|
cumulated_error++;
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
* Also remove the LUNs changed by more than size.
|
2013-09-14 15:29:06 +00:00
|
|
|
*/
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
changed = 0;
|
|
|
|
assert(oldlun->l_backend != NULL);
|
|
|
|
assert(newlun->l_backend != NULL);
|
|
|
|
if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) {
|
|
|
|
log_debugx("backend for lun \"%s\", "
|
|
|
|
"CTL lun %d changed; removing",
|
|
|
|
oldlun->l_name, oldlun->l_ctl_lun);
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
if (oldlun->l_blocksize != newlun->l_blocksize) {
|
|
|
|
log_debugx("blocksize for lun \"%s\", "
|
|
|
|
"CTL lun %d changed; removing",
|
|
|
|
oldlun->l_name, oldlun->l_ctl_lun);
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
if (newlun->l_device_id != NULL &&
|
|
|
|
(oldlun->l_device_id == NULL ||
|
|
|
|
strcmp(oldlun->l_device_id, newlun->l_device_id) !=
|
|
|
|
0)) {
|
|
|
|
log_debugx("device-id for lun \"%s\", "
|
|
|
|
"CTL lun %d changed; removing",
|
|
|
|
oldlun->l_name, oldlun->l_ctl_lun);
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
if (newlun->l_path != NULL &&
|
|
|
|
(oldlun->l_path == NULL ||
|
|
|
|
strcmp(oldlun->l_path, newlun->l_path) != 0)) {
|
|
|
|
log_debugx("path for lun \"%s\", "
|
|
|
|
"CTL lun %d, changed; removing",
|
|
|
|
oldlun->l_name, oldlun->l_ctl_lun);
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
if (newlun->l_serial != NULL &&
|
|
|
|
(oldlun->l_serial == NULL ||
|
|
|
|
strcmp(oldlun->l_serial, newlun->l_serial) != 0)) {
|
|
|
|
log_debugx("serial for lun \"%s\", "
|
|
|
|
"CTL lun %d changed; removing",
|
|
|
|
oldlun->l_name, oldlun->l_ctl_lun);
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
if (changed) {
|
|
|
|
error = kernel_lun_remove(oldlun);
|
|
|
|
if (error != 0) {
|
|
|
|
log_warnx("failed to remove lun \"%s\", "
|
|
|
|
"CTL lun %d",
|
|
|
|
oldlun->l_name, oldlun->l_ctl_lun);
|
|
|
|
cumulated_error++;
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
lun_delete(oldlun);
|
|
|
|
continue;
|
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
lun_set_ctl_lun(newlun, oldlun->l_ctl_lun);
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_FOREACH_SAFE(newlun, &newconf->conf_luns, l_next, tmplun) {
|
|
|
|
oldlun = lun_find(oldconf, newlun->l_name);
|
|
|
|
if (oldlun != NULL) {
|
|
|
|
if (newlun->l_size != oldlun->l_size ||
|
|
|
|
newlun->l_size == 0) {
|
|
|
|
log_debugx("resizing lun \"%s\", CTL lun %d",
|
|
|
|
newlun->l_name, newlun->l_ctl_lun);
|
|
|
|
error = kernel_lun_resize(newlun);
|
2013-09-14 15:29:06 +00:00
|
|
|
if (error != 0) {
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
log_warnx("failed to "
|
|
|
|
"resize lun \"%s\", CTL lun %d",
|
|
|
|
newlun->l_name,
|
|
|
|
newlun->l_ctl_lun);
|
2013-09-14 15:29:06 +00:00
|
|
|
cumulated_error++;
|
|
|
|
}
|
|
|
|
}
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
log_debugx("adding lun \"%s\"", newlun->l_name);
|
|
|
|
error = kernel_lun_add(newlun);
|
|
|
|
if (error != 0) {
|
|
|
|
log_warnx("failed to add lun \"%s\"", newlun->l_name);
|
|
|
|
lun_delete(newlun);
|
|
|
|
cumulated_error++;
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now add new targets or modify existing ones.
|
|
|
|
*/
|
|
|
|
TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) {
|
2014-02-11 11:14:50 +00:00
|
|
|
oldtarg = target_find(oldconf, newtarg->t_name);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
if (oldtarg == NULL)
|
2014-11-21 12:35:18 +00:00
|
|
|
error = kernel_port_add(newtarg);
|
CTL LUN mapping rewrite.
Replace iSCSI-specific LUN mapping mechanism with new one, working for any
ports. By default all ports are created without LUN mapping, exposing all
CTL LUNs as before. But, if needed, LUN mapping can be manually set on
per-port basis via ctladm. For its iSCSI ports ctld does it via ioctl(2).
The next step will be to teach ctld to work with FibreChannel ports also.
Respecting additional flexibility of the new mechanism, ctl.conf now allows
alternative syntax for LUN definition. LUNs can now be defined in global
context, and then referenced from targets by unique name, as needed. It
allows same LUN to be exposed several times via multiple targets.
While there, increase limit for LUNs per target in ctld from 256 to 1024.
Some initiators do not support LUNs above 255, but that is not our problem.
Discussed with: trasz
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
2015-02-01 21:50:28 +00:00
|
|
|
else {
|
|
|
|
target_set_ctl_port(newtarg, oldtarg->t_ctl_port);
|
|
|
|
error = kernel_port_update(newtarg);
|
|
|
|
}
|
|
|
|
if (error != 0) {
|
|
|
|
log_warnx("failed to %s target %s",
|
|
|
|
(oldtarg == NULL) ? "add" : "update",
|
|
|
|
newtarg->t_name);
|
|
|
|
/*
|
|
|
|
* XXX: Uncomment after fixing the root cause.
|
|
|
|
*
|
|
|
|
* cumulated_error++;
|
|
|
|
*/
|
2014-11-21 12:35:18 +00:00
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Go through the new portals, opening the sockets as neccessary.
|
|
|
|
*/
|
|
|
|
TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) {
|
|
|
|
if (newpg->pg_unassigned) {
|
|
|
|
log_debugx("not listening on portal-group \"%s\", "
|
|
|
|
"not assigned to any target",
|
|
|
|
newpg->pg_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) {
|
|
|
|
/*
|
|
|
|
* Try to find already open portal and reuse
|
|
|
|
* the listening socket. We don't care about
|
|
|
|
* what portal or portal group that was, what
|
|
|
|
* matters is the listening address.
|
|
|
|
*/
|
|
|
|
TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups,
|
|
|
|
pg_next) {
|
|
|
|
TAILQ_FOREACH(oldp, &oldpg->pg_portals,
|
|
|
|
p_next) {
|
|
|
|
if (strcmp(newp->p_listen,
|
|
|
|
oldp->p_listen) == 0 &&
|
|
|
|
oldp->p_socket > 0) {
|
|
|
|
newp->p_socket =
|
|
|
|
oldp->p_socket;
|
|
|
|
oldp->p_socket = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (newp->p_socket > 0) {
|
|
|
|
/*
|
|
|
|
* We're done with this portal.
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ICL_KERNEL_PROXY
|
2014-04-16 10:06:37 +00:00
|
|
|
if (proxy_mode) {
|
2014-04-16 10:29:34 +00:00
|
|
|
newpg->pg_conf->conf_portal_id++;
|
|
|
|
newp->p_id = newpg->pg_conf->conf_portal_id;
|
|
|
|
log_debugx("listening on %s, portal-group "
|
|
|
|
"\"%s\", portal id %d, using ICL proxy",
|
|
|
|
newp->p_listen, newpg->pg_name, newp->p_id);
|
|
|
|
kernel_listen(newp->p_ai, newp->p_iser,
|
|
|
|
newp->p_id);
|
2014-04-16 10:06:37 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
assert(proxy_mode == false);
|
2013-09-14 15:29:06 +00:00
|
|
|
assert(newp->p_iser == false);
|
|
|
|
|
|
|
|
log_debugx("listening on %s, portal-group \"%s\"",
|
|
|
|
newp->p_listen, newpg->pg_name);
|
|
|
|
newp->p_socket = socket(newp->p_ai->ai_family,
|
|
|
|
newp->p_ai->ai_socktype,
|
|
|
|
newp->p_ai->ai_protocol);
|
|
|
|
if (newp->p_socket < 0) {
|
|
|
|
log_warn("socket(2) failed for %s",
|
|
|
|
newp->p_listen);
|
|
|
|
cumulated_error++;
|
|
|
|
continue;
|
|
|
|
}
|
2014-11-22 15:09:18 +00:00
|
|
|
sockbuf = SOCKBUF_SIZE;
|
|
|
|
if (setsockopt(newp->p_socket, SOL_SOCKET, SO_RCVBUF,
|
|
|
|
&sockbuf, sizeof(sockbuf)) == -1)
|
|
|
|
log_warn("setsockopt(SO_RCVBUF) failed "
|
|
|
|
"for %s", newp->p_listen);
|
|
|
|
sockbuf = SOCKBUF_SIZE;
|
|
|
|
if (setsockopt(newp->p_socket, SOL_SOCKET, SO_SNDBUF,
|
|
|
|
&sockbuf, sizeof(sockbuf)) == -1)
|
|
|
|
log_warn("setsockopt(SO_SNDBUF) failed "
|
|
|
|
"for %s", newp->p_listen);
|
2013-09-14 15:29:06 +00:00
|
|
|
error = setsockopt(newp->p_socket, SOL_SOCKET,
|
|
|
|
SO_REUSEADDR, &one, sizeof(one));
|
|
|
|
if (error != 0) {
|
|
|
|
log_warn("setsockopt(SO_REUSEADDR) failed "
|
|
|
|
"for %s", newp->p_listen);
|
|
|
|
close(newp->p_socket);
|
|
|
|
newp->p_socket = 0;
|
|
|
|
cumulated_error++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
error = bind(newp->p_socket, newp->p_ai->ai_addr,
|
|
|
|
newp->p_ai->ai_addrlen);
|
|
|
|
if (error != 0) {
|
|
|
|
log_warn("bind(2) failed for %s",
|
|
|
|
newp->p_listen);
|
|
|
|
close(newp->p_socket);
|
|
|
|
newp->p_socket = 0;
|
|
|
|
cumulated_error++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
error = listen(newp->p_socket, -1);
|
|
|
|
if (error != 0) {
|
|
|
|
log_warn("listen(2) failed for %s",
|
|
|
|
newp->p_listen);
|
|
|
|
close(newp->p_socket);
|
|
|
|
newp->p_socket = 0;
|
|
|
|
cumulated_error++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Go through the no longer used sockets, closing them.
|
|
|
|
*/
|
|
|
|
TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) {
|
|
|
|
TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) {
|
|
|
|
if (oldp->p_socket <= 0)
|
|
|
|
continue;
|
|
|
|
log_debugx("closing socket for %s, portal-group \"%s\"",
|
|
|
|
oldp->p_listen, oldpg->pg_name);
|
|
|
|
close(oldp->p_socket);
|
|
|
|
oldp->p_socket = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
/* (Re-)Register on remaining/new iSNS servers. */
|
|
|
|
TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) {
|
|
|
|
TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) {
|
|
|
|
if (strcmp(oldns->i_addr, newns->i_addr) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
isns_register(newns, oldns);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Schedule iSNS update */
|
|
|
|
if (!TAILQ_EMPTY(&newconf->conf_isns))
|
|
|
|
set_timeout((newconf->conf_isns_period + 2) / 3, false);
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
return (cumulated_error);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
timed_out(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (sigalrm_received);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-10-25 12:50:26 +00:00
|
|
|
sigalrm_handler_fatal(int dummy __unused)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* It would be easiest to just log an error and exit. We can't
|
|
|
|
* do this, though, because log_errx() is not signal safe, since
|
|
|
|
* it calls syslog(3). Instead, set a flag checked by pdu_send()
|
|
|
|
* and pdu_receive(), to call log_errx() there. Should they fail
|
|
|
|
* to notice, we'll exit here one second later.
|
|
|
|
*/
|
|
|
|
if (sigalrm_received) {
|
|
|
|
/*
|
|
|
|
* Oh well. Just give up and quit.
|
|
|
|
*/
|
|
|
|
_exit(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
sigalrm_received = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-10-25 12:50:26 +00:00
|
|
|
sigalrm_handler(int dummy __unused)
|
|
|
|
{
|
|
|
|
|
|
|
|
sigalrm_received = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
set_timeout(int timeout, int fatal)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct sigaction sa;
|
|
|
|
struct itimerval itv;
|
|
|
|
int error;
|
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
if (timeout <= 0) {
|
2013-09-14 15:29:06 +00:00
|
|
|
log_debugx("session timeout disabled");
|
2014-10-25 12:50:26 +00:00
|
|
|
bzero(&itv, sizeof(itv));
|
|
|
|
error = setitimer(ITIMER_REAL, &itv, NULL);
|
|
|
|
if (error != 0)
|
|
|
|
log_err(1, "setitimer");
|
|
|
|
sigalrm_received = false;
|
2013-09-14 15:29:06 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
sigalrm_received = false;
|
2013-09-14 15:29:06 +00:00
|
|
|
bzero(&sa, sizeof(sa));
|
2014-10-25 12:50:26 +00:00
|
|
|
if (fatal)
|
|
|
|
sa.sa_handler = sigalrm_handler_fatal;
|
|
|
|
else
|
|
|
|
sa.sa_handler = sigalrm_handler;
|
2013-09-14 15:29:06 +00:00
|
|
|
sigfillset(&sa.sa_mask);
|
|
|
|
error = sigaction(SIGALRM, &sa, NULL);
|
|
|
|
if (error != 0)
|
|
|
|
log_err(1, "sigaction");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First SIGALRM will arive after conf_timeout seconds.
|
|
|
|
* If we do nothing, another one will arrive a second later.
|
|
|
|
*/
|
2014-10-25 12:50:26 +00:00
|
|
|
log_debugx("setting session timeout to %d seconds", timeout);
|
2013-09-14 15:29:06 +00:00
|
|
|
bzero(&itv, sizeof(itv));
|
|
|
|
itv.it_interval.tv_sec = 1;
|
2014-10-25 12:50:26 +00:00
|
|
|
itv.it_value.tv_sec = timeout;
|
2013-09-14 15:29:06 +00:00
|
|
|
error = setitimer(ITIMER_REAL, &itv, NULL);
|
|
|
|
if (error != 0)
|
|
|
|
log_err(1, "setitimer");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
wait_for_children(bool block)
|
|
|
|
{
|
|
|
|
pid_t pid;
|
|
|
|
int status;
|
|
|
|
int num = 0;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
/*
|
|
|
|
* If "block" is true, wait for at least one process.
|
|
|
|
*/
|
|
|
|
if (block && num == 0)
|
|
|
|
pid = wait4(-1, &status, 0, NULL);
|
|
|
|
else
|
|
|
|
pid = wait4(-1, &status, WNOHANG, NULL);
|
|
|
|
if (pid <= 0)
|
|
|
|
break;
|
|
|
|
if (WIFSIGNALED(status)) {
|
|
|
|
log_warnx("child process %d terminated with signal %d",
|
|
|
|
pid, WTERMSIG(status));
|
|
|
|
} else if (WEXITSTATUS(status) != 0) {
|
|
|
|
log_warnx("child process %d terminated with exit status %d",
|
|
|
|
pid, WEXITSTATUS(status));
|
|
|
|
} else {
|
|
|
|
log_debugx("child process %d terminated gracefully", pid);
|
|
|
|
}
|
|
|
|
num++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (num);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-04-16 11:00:10 +00:00
|
|
|
handle_connection(struct portal *portal, int fd,
|
2014-07-28 12:47:09 +00:00
|
|
|
const struct sockaddr *client_sa, bool dont_fork)
|
2013-09-14 15:29:06 +00:00
|
|
|
{
|
|
|
|
struct connection *conn;
|
|
|
|
int error;
|
|
|
|
pid_t pid;
|
|
|
|
char host[NI_MAXHOST + 1];
|
|
|
|
struct conf *conf;
|
|
|
|
|
|
|
|
conf = portal->p_portal_group->pg_conf;
|
|
|
|
|
|
|
|
if (dont_fork) {
|
|
|
|
log_debugx("incoming connection; not forking due to -d flag");
|
|
|
|
} else {
|
|
|
|
nchildren -= wait_for_children(false);
|
|
|
|
assert(nchildren >= 0);
|
|
|
|
|
|
|
|
while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) {
|
|
|
|
log_debugx("maxproc limit of %d child processes hit; "
|
|
|
|
"waiting for child process to exit", conf->conf_maxproc);
|
|
|
|
nchildren -= wait_for_children(true);
|
|
|
|
assert(nchildren >= 0);
|
|
|
|
}
|
|
|
|
log_debugx("incoming connection; forking child process #%d",
|
|
|
|
nchildren);
|
|
|
|
nchildren++;
|
|
|
|
pid = fork();
|
|
|
|
if (pid < 0)
|
|
|
|
log_err(1, "fork");
|
|
|
|
if (pid > 0) {
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pidfile_close(conf->conf_pidfh);
|
|
|
|
|
2014-07-28 12:47:09 +00:00
|
|
|
error = getnameinfo(client_sa, client_sa->sa_len,
|
2014-04-16 11:00:10 +00:00
|
|
|
host, sizeof(host), NULL, 0, NI_NUMERICHOST);
|
|
|
|
if (error != 0)
|
|
|
|
log_errx(1, "getnameinfo: %s", gai_strerror(error));
|
|
|
|
|
|
|
|
log_debugx("accepted connection from %s; portal group \"%s\"",
|
|
|
|
host, portal->p_portal_group->pg_name);
|
|
|
|
log_set_peer_addr(host);
|
|
|
|
setproctitle("%s", host);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
2014-07-28 12:47:09 +00:00
|
|
|
conn = connection_new(portal, fd, host, client_sa);
|
2014-10-25 12:50:26 +00:00
|
|
|
set_timeout(conf->conf_timeout, true);
|
2013-09-14 15:29:06 +00:00
|
|
|
kernel_capsicate();
|
|
|
|
login(conn);
|
|
|
|
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
|
|
|
|
kernel_handoff(conn);
|
|
|
|
log_debugx("connection handed off to the kernel");
|
|
|
|
} else {
|
|
|
|
assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY);
|
|
|
|
discovery(conn);
|
|
|
|
}
|
|
|
|
log_debugx("nothing more to do; exiting");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
fd_add(int fd, fd_set *fdset, int nfds)
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip sockets which we failed to bind.
|
|
|
|
*/
|
|
|
|
if (fd <= 0)
|
|
|
|
return (nfds);
|
|
|
|
|
|
|
|
FD_SET(fd, fdset);
|
|
|
|
if (fd > nfds)
|
|
|
|
nfds = fd;
|
|
|
|
return (nfds);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
main_loop(struct conf *conf, bool dont_fork)
|
|
|
|
{
|
|
|
|
struct portal_group *pg;
|
|
|
|
struct portal *portal;
|
2014-04-16 10:49:48 +00:00
|
|
|
struct sockaddr_storage client_sa;
|
|
|
|
socklen_t client_salen;
|
2013-09-14 15:29:06 +00:00
|
|
|
#ifdef ICL_KERNEL_PROXY
|
|
|
|
int connection_id;
|
2014-04-16 10:29:34 +00:00
|
|
|
int portal_id;
|
2014-04-16 10:06:37 +00:00
|
|
|
#endif
|
2013-09-14 15:29:06 +00:00
|
|
|
fd_set fdset;
|
|
|
|
int error, nfds, client_fd;
|
|
|
|
|
|
|
|
pidfile_write(conf->conf_pidfh);
|
|
|
|
|
|
|
|
for (;;) {
|
2014-10-25 12:50:26 +00:00
|
|
|
if (sighup_received || sigterm_received || timed_out())
|
2013-09-14 15:29:06 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef ICL_KERNEL_PROXY
|
2014-04-16 10:06:37 +00:00
|
|
|
if (proxy_mode) {
|
2014-04-16 11:00:10 +00:00
|
|
|
client_salen = sizeof(client_sa);
|
|
|
|
kernel_accept(&connection_id, &portal_id,
|
|
|
|
(struct sockaddr *)&client_sa, &client_salen);
|
2014-09-05 14:48:06 +00:00
|
|
|
assert(client_salen >= client_sa.ss_len);
|
2013-09-14 15:29:06 +00:00
|
|
|
|
2014-04-16 10:29:34 +00:00
|
|
|
log_debugx("incoming connection, id %d, portal id %d",
|
|
|
|
connection_id, portal_id);
|
|
|
|
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
|
|
|
|
TAILQ_FOREACH(portal, &pg->pg_portals, p_next) {
|
|
|
|
if (portal->p_id == portal_id) {
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log_errx(1, "kernel returned invalid portal_id %d",
|
|
|
|
portal_id);
|
2014-04-16 10:06:37 +00:00
|
|
|
|
2014-04-16 10:29:34 +00:00
|
|
|
found:
|
2014-04-16 11:00:10 +00:00
|
|
|
handle_connection(portal, connection_id,
|
2014-07-28 12:47:09 +00:00
|
|
|
(struct sockaddr *)&client_sa, dont_fork);
|
2014-04-16 10:06:37 +00:00
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
assert(proxy_mode == false);
|
|
|
|
|
|
|
|
FD_ZERO(&fdset);
|
|
|
|
nfds = 0;
|
|
|
|
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
|
|
|
|
TAILQ_FOREACH(portal, &pg->pg_portals, p_next)
|
|
|
|
nfds = fd_add(portal->p_socket, &fdset, nfds);
|
|
|
|
}
|
|
|
|
error = select(nfds + 1, &fdset, NULL, NULL, NULL);
|
|
|
|
if (error <= 0) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
return;
|
|
|
|
log_err(1, "select");
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
2014-04-16 10:06:37 +00:00
|
|
|
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
|
|
|
|
TAILQ_FOREACH(portal, &pg->pg_portals, p_next) {
|
|
|
|
if (!FD_ISSET(portal->p_socket, &fdset))
|
|
|
|
continue;
|
2014-04-16 10:49:48 +00:00
|
|
|
client_salen = sizeof(client_sa);
|
|
|
|
client_fd = accept(portal->p_socket,
|
|
|
|
(struct sockaddr *)&client_sa,
|
|
|
|
&client_salen);
|
2014-04-16 10:06:37 +00:00
|
|
|
if (client_fd < 0)
|
|
|
|
log_err(1, "accept");
|
2014-09-05 14:48:06 +00:00
|
|
|
assert(client_salen >= client_sa.ss_len);
|
|
|
|
|
2014-04-16 10:49:48 +00:00
|
|
|
handle_connection(portal, client_fd,
|
2014-04-16 11:00:10 +00:00
|
|
|
(struct sockaddr *)&client_sa,
|
2014-07-28 12:47:09 +00:00
|
|
|
dont_fork);
|
2014-04-16 10:06:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef ICL_KERNEL_PROXY
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
2014-04-16 10:06:37 +00:00
|
|
|
#endif
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sighup_handler(int dummy __unused)
|
|
|
|
{
|
|
|
|
|
|
|
|
sighup_received = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sigterm_handler(int dummy __unused)
|
|
|
|
{
|
|
|
|
|
|
|
|
sigterm_received = true;
|
|
|
|
}
|
|
|
|
|
2014-02-11 11:33:44 +00:00
|
|
|
static void
|
|
|
|
sigchld_handler(int dummy __unused)
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The only purpose of this handler is to make SIGCHLD
|
|
|
|
* interrupt the ISCSIDWAIT ioctl(2), so we can call
|
|
|
|
* wait_for_children().
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
static void
|
|
|
|
register_signals(void)
|
|
|
|
{
|
|
|
|
struct sigaction sa;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
bzero(&sa, sizeof(sa));
|
|
|
|
sa.sa_handler = sighup_handler;
|
|
|
|
sigfillset(&sa.sa_mask);
|
|
|
|
error = sigaction(SIGHUP, &sa, NULL);
|
|
|
|
if (error != 0)
|
|
|
|
log_err(1, "sigaction");
|
|
|
|
|
|
|
|
sa.sa_handler = sigterm_handler;
|
|
|
|
error = sigaction(SIGTERM, &sa, NULL);
|
|
|
|
if (error != 0)
|
|
|
|
log_err(1, "sigaction");
|
|
|
|
|
|
|
|
sa.sa_handler = sigterm_handler;
|
|
|
|
error = sigaction(SIGINT, &sa, NULL);
|
|
|
|
if (error != 0)
|
|
|
|
log_err(1, "sigaction");
|
2014-02-11 11:33:44 +00:00
|
|
|
|
|
|
|
sa.sa_handler = sigchld_handler;
|
|
|
|
error = sigaction(SIGCHLD, &sa, NULL);
|
|
|
|
if (error != 0)
|
|
|
|
log_err(1, "sigaction");
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct conf *oldconf, *newconf, *tmpconf;
|
2014-10-25 12:50:26 +00:00
|
|
|
struct isns *newns;
|
2013-09-14 15:29:06 +00:00
|
|
|
const char *config_path = DEFAULT_CONFIG_PATH;
|
|
|
|
int debug = 0, ch, error;
|
|
|
|
bool dont_daemonize = false;
|
|
|
|
|
2014-04-16 10:06:37 +00:00
|
|
|
while ((ch = getopt(argc, argv, "df:R")) != -1) {
|
2013-09-14 15:29:06 +00:00
|
|
|
switch (ch) {
|
|
|
|
case 'd':
|
|
|
|
dont_daemonize = true;
|
|
|
|
debug++;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
config_path = optarg;
|
|
|
|
break;
|
2014-04-16 10:06:37 +00:00
|
|
|
case 'R':
|
|
|
|
#ifndef ICL_KERNEL_PROXY
|
|
|
|
log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY "
|
|
|
|
"does not support iSER protocol");
|
|
|
|
#endif
|
|
|
|
proxy_mode = true;
|
|
|
|
break;
|
2013-09-14 15:29:06 +00:00
|
|
|
case '?':
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
argc -= optind;
|
|
|
|
if (argc != 0)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
log_init(debug);
|
|
|
|
kernel_init();
|
|
|
|
|
|
|
|
oldconf = conf_new_from_kernel();
|
|
|
|
newconf = conf_new_from_file(config_path);
|
|
|
|
if (newconf == NULL)
|
2014-04-16 11:05:57 +00:00
|
|
|
log_errx(1, "configuration error; exiting");
|
2013-09-14 15:29:06 +00:00
|
|
|
if (debug > 0) {
|
|
|
|
oldconf->conf_debug = debug;
|
|
|
|
newconf->conf_debug = debug;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = conf_apply(oldconf, newconf);
|
|
|
|
if (error != 0)
|
2014-04-16 11:05:57 +00:00
|
|
|
log_errx(1, "failed to apply configuration; exiting");
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
conf_delete(oldconf);
|
|
|
|
oldconf = NULL;
|
|
|
|
|
|
|
|
register_signals();
|
|
|
|
|
2014-02-11 10:59:57 +00:00
|
|
|
if (dont_daemonize == false) {
|
|
|
|
log_debugx("daemonizing");
|
|
|
|
if (daemon(0, 0) == -1) {
|
|
|
|
log_warn("cannot daemonize");
|
|
|
|
pidfile_remove(newconf->conf_pidfh);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-25 12:50:26 +00:00
|
|
|
/* Schedule iSNS update */
|
|
|
|
if (!TAILQ_EMPTY(&newconf->conf_isns))
|
|
|
|
set_timeout((newconf->conf_isns_period + 2) / 3, false);
|
|
|
|
|
2013-09-14 15:29:06 +00:00
|
|
|
for (;;) {
|
|
|
|
main_loop(newconf, dont_daemonize);
|
|
|
|
if (sighup_received) {
|
|
|
|
sighup_received = false;
|
|
|
|
log_debugx("received SIGHUP, reloading configuration");
|
|
|
|
tmpconf = conf_new_from_file(config_path);
|
|
|
|
if (tmpconf == NULL) {
|
|
|
|
log_warnx("configuration error, "
|
|
|
|
"continuing with old configuration");
|
|
|
|
} else {
|
|
|
|
if (debug > 0)
|
|
|
|
tmpconf->conf_debug = debug;
|
|
|
|
oldconf = newconf;
|
|
|
|
newconf = tmpconf;
|
|
|
|
error = conf_apply(oldconf, newconf);
|
|
|
|
if (error != 0)
|
|
|
|
log_warnx("failed to reload "
|
|
|
|
"configuration");
|
|
|
|
conf_delete(oldconf);
|
|
|
|
oldconf = NULL;
|
|
|
|
}
|
|
|
|
} else if (sigterm_received) {
|
|
|
|
log_debugx("exiting on signal; "
|
|
|
|
"reloading empty configuration");
|
|
|
|
|
|
|
|
log_debugx("disabling CTL iSCSI port "
|
|
|
|
"and terminating all connections");
|
|
|
|
|
|
|
|
oldconf = newconf;
|
|
|
|
newconf = conf_new();
|
|
|
|
if (debug > 0)
|
|
|
|
newconf->conf_debug = debug;
|
|
|
|
error = conf_apply(oldconf, newconf);
|
|
|
|
if (error != 0)
|
|
|
|
log_warnx("failed to apply configuration");
|
2014-10-25 12:50:26 +00:00
|
|
|
conf_delete(oldconf);
|
|
|
|
oldconf = NULL;
|
2013-09-14 15:29:06 +00:00
|
|
|
|
|
|
|
log_warnx("exiting on signal");
|
|
|
|
exit(0);
|
|
|
|
} else {
|
|
|
|
nchildren -= wait_for_children(false);
|
|
|
|
assert(nchildren >= 0);
|
2014-10-25 12:50:26 +00:00
|
|
|
if (timed_out()) {
|
|
|
|
set_timeout(0, false);
|
|
|
|
TAILQ_FOREACH(newns, &newconf->conf_isns, i_next)
|
|
|
|
isns_check(newns);
|
|
|
|
/* Schedule iSNS update */
|
|
|
|
if (!TAILQ_EMPTY(&newconf->conf_isns)) {
|
|
|
|
set_timeout((newconf->conf_isns_period
|
|
|
|
+ 2) / 3,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
}
|
2013-09-14 15:29:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|