diff --git a/usr.sbin/ctld/Makefile b/usr.sbin/ctld/Makefile --- a/usr.sbin/ctld/Makefile +++ b/usr.sbin/ctld/Makefile @@ -5,8 +5,8 @@ PACKAGE= iscsi PROG= ctld -SRCS= ctld.c discovery.c isns.c kernel.c -SRCS+= login.c parse.y token.l y.tab.h uclparse.c +SRCS= ctld.c isns.c kernel.c +SRCS+= parse.y token.l y.tab.h uclparse.c CFLAGS+= -I${.CURDIR} CFLAGS+= -I${SRCTOP}/sys CFLAGS+= -I${SRCTOP}/sys/cam/ctl @@ -25,6 +25,7 @@ .if ${MK_ISCSI} != "no" CFLAGS+= -DWANT_ISCSI +SRCS+= discovery.c iscsi.c login.c .endif .include diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -47,8 +47,10 @@ #define DEFAULT_CD_BLOCKSIZE 2048 #define MAX_LUNS 1024 -#define MAX_DATA_SEGMENT_LENGTH (128 * 1024) -#define SOCKBUF_SIZE 1048576 + +struct ctl_req; +struct port; +struct target_protocol_ops; struct auth { TAILQ_ENTRY(auth) a_next; @@ -62,16 +64,20 @@ struct auth_name { TAILQ_ENTRY(auth_name) an_next; struct auth_group *an_auth_group; - char *an_initiator_name; + char *an_name; + int an_protocol; }; +TAILQ_HEAD(auth_name_head, auth_name); struct auth_portal { TAILQ_ENTRY(auth_portal) ap_next; struct auth_group *ap_auth_group; - char *ap_initiator_portal; + char *ap_portal; struct sockaddr_storage ap_sa; int ap_mask; + int ap_protocol; }; +TAILQ_HEAD(auth_portal_head, auth_portal); #define AG_TYPE_UNKNOWN 0 #define AG_TYPE_DENY 1 @@ -86,16 +92,19 @@ struct target *ag_target; int ag_type; TAILQ_HEAD(, auth) ag_auths; - TAILQ_HEAD(, auth_name) ag_names; - TAILQ_HEAD(, auth_portal) ag_portals; + struct auth_name_head ag_initiator_names; + struct auth_portal_head ag_initiator_portals; }; +#define PORTAL_PROTOCOL_ISCSI 0 +#define PORTAL_PROTOCOL_ISER 1 + struct portal { TAILQ_ENTRY(portal) p_next; struct portal_group *p_portal_group; - bool p_iser; char *p_listen; struct addrinfo *p_ai; + int p_protocol; #ifdef ICL_KERNEL_PROXY int p_id; #endif @@ -104,6 +113,35 @@ int p_socket; }; +#define TARGET_PROTOCOL_ISCSI 0 + +struct target_protocol_ops { + /* Initialize protocol-specific state for a new portal group. */ + void (*portal_group_init)(struct portal_group *pg); + + /* Copy protocol-specific state from oldpg to a new portal group. */ + void (*portal_group_copy)(struct portal_group *oldpg, + struct portal_group *newpg); + + /* Initialize protocol-specific state for a new portal. */ + void (*portal_init)(struct portal *p); + + /* Set protocol-specific socket options for a new socket. */ + void (*portal_init_socket)(struct portal *p); + + /* Initialize protocol-specific state for a new portal. */ + void (*portal_delete)(struct portal *p); + + /* Set req->driver and add fields to req->args_nvl. */ + void (*kernel_port_add)(struct port *port, struct ctl_req *req); + void (*kernel_port_remove)(struct port *port, struct ctl_req *req); + + char *(*validate_target_name)(const char *name); + + void (*handle_connection)(struct portal *portal, int fd, + const char *host, const struct sockaddr *client_sa); +}; + #define PG_FILTER_UNKNOWN 0 #define PG_FILTER_NONE 1 #define PG_FILTER_PORTAL 2 @@ -118,6 +156,8 @@ struct auth_group *pg_discovery_auth_group; int pg_discovery_filter; int pg_foreign; + struct target_protocol_ops *pg_ops; + int pg_protocol; bool pg_unassigned; TAILQ_HEAD(, portal) pg_portals; TAILQ_HEAD(, port) pg_ports; @@ -185,6 +225,8 @@ char *t_redirection; /* Name of this target's physical port, if any, i.e. "isp0" */ char *t_pport; + struct target_protocol_ops *t_ops; + int t_protocol; }; struct isns { @@ -246,6 +288,10 @@ struct chap *conn_chap; }; +extern bool proxy_mode; +extern int ctl_fd; +extern struct target_protocol_ops target_iscsi; + int parse_conf(struct conf *newconf, const char *path); int uclparse_conf(struct conf *conf, const char *path); @@ -269,28 +315,33 @@ const struct auth *auth_find(const struct auth_group *ag, const char *user); -const struct auth_name *auth_name_new(struct auth_group *ag, - const char *initiator_name); -bool auth_name_defined(const struct auth_group *ag); +const struct auth_name *auth_name_new(struct auth_group *ag, int protocol, + const char *name); +bool auth_name_defined(const struct auth_group *ag, + int protocol); const struct auth_name *auth_name_find(const struct auth_group *ag, - const char *initiator_name); + int protocol, const char *name); int auth_name_check(const struct auth_group *ag, - const char *initiator_name); + int protocol, const char *name); const struct auth_portal *auth_portal_new(struct auth_group *ag, - const char *initiator_portal); -bool auth_portal_defined(const struct auth_group *ag); + int protocol, const char *portal); +bool auth_portal_defined(const struct auth_group *ag, + int protocol); const struct auth_portal *auth_portal_find(const struct auth_group *ag, + int protocol, const struct sockaddr_storage *sa); int auth_portal_check(const struct auth_group *ag, + int protocol, const struct sockaddr_storage *sa); -struct portal_group *portal_group_new(struct conf *conf, const char *name); +struct portal_group *portal_group_new(struct conf *conf, int protocol, + const char *name); void portal_group_delete(struct portal_group *pg); struct portal_group *portal_group_find(const struct conf *conf, - const char *name); + int protocol, const char *name); int portal_group_add_listen(struct portal_group *pg, - const char *listen, bool iser); + const char *listen, int protocol); int portal_group_set_filter(struct portal_group *pg, const char *filter); int portal_group_set_offload(struct portal_group *pg, @@ -324,7 +375,8 @@ void port_delete(struct port *port); int port_is_dummy(struct port *port); -struct target *target_new(struct conf *conf, const char *name); +struct target *target_new(struct conf *conf, const char *name, + int protocol); void target_delete(struct target *target); struct target *target_find(struct conf *conf, const char *name); @@ -351,7 +403,6 @@ int kernel_lun_add(struct lun *lun); int kernel_lun_modify(struct lun *lun); int kernel_lun_remove(struct lun *lun); -void kernel_handoff(struct ctld_connection *conn); int kernel_port_add(struct port *port); int kernel_port_update(struct port *port, struct port *old); int kernel_port_remove(struct port *port); @@ -367,6 +418,8 @@ void kernel_receive(struct pdu *pdu); #endif +bool timed_out(void); + void login(struct ctld_connection *conn); void discovery(struct ctld_connection *conn); diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -53,13 +53,6 @@ #include "ctld.h" #include "isns.h" -static bool timed_out(void); -#ifdef ICL_KERNEL_PROXY -static void pdu_receive_proxy(struct pdu *pdu); -static void pdu_send_proxy(struct pdu *pdu); -#endif /* ICL_KERNEL_PROXY */ -static void pdu_fail(const struct connection *conn, const char *reason); - bool proxy_mode = false; static volatile bool sighup_received = false; @@ -68,16 +61,6 @@ static int kqfd; static int nchildren = 0; -static uint16_t last_portal_group_tag = 0xff; - -static struct connection_ops conn_ops = { - .timed_out = timed_out, -#ifdef ICL_KERNEL_PROXY - .pdu_receive_proxy = pdu_receive_proxy, - .pdu_send_proxy = pdu_send_proxy, -#endif - .fail = pdu_fail, -}; static void usage(void) @@ -296,44 +279,74 @@ return (auth); } +static struct auth_name_head * +auth_name_head(struct auth_group *ag, int protocol) +{ + switch (protocol) { + case TARGET_PROTOCOL_ISCSI: + return (&ag->ag_initiator_names); + default: + __assert_unreachable(); + } +} + +static const struct auth_name_head * +auth_name_const_head(const struct auth_group *ag, int protocol) +{ + switch (protocol) { + case TARGET_PROTOCOL_ISCSI: + return (&ag->ag_initiator_names); + default: + __assert_unreachable(); + } +} + const struct auth_name * -auth_name_new(struct auth_group *ag, const char *name) +auth_name_new(struct auth_group *ag, int protocol, const char *name) { + struct auth_name_head *head = auth_name_head(ag, protocol); struct auth_name *an; an = calloc(1, sizeof(*an)); if (an == NULL) log_err(1, "calloc"); an->an_auth_group = ag; - an->an_initiator_name = checked_strdup(name); - TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next); + an->an_name = checked_strdup(name); + an->an_protocol = protocol; + TAILQ_INSERT_TAIL(head, 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); + struct auth_name_head *head; - free(an->an_initiator_name); + head = auth_name_head(an->an_auth_group, an->an_protocol); + TAILQ_REMOVE(head, an, an_next); + + free(an->an_name); free(an); } bool -auth_name_defined(const struct auth_group *ag) +auth_name_defined(const struct auth_group *ag, int protocol) { - if (TAILQ_EMPTY(&ag->ag_names)) + const struct auth_name_head *head = auth_name_const_head(ag, protocol); + + if (TAILQ_EMPTY(head)) return (false); return (true); } const struct auth_name * -auth_name_find(const struct auth_group *ag, const char *name) +auth_name_find(const struct auth_group *ag, int protocol, const char *name) { + const struct auth_name_head *head = auth_name_const_head(ag, protocol); const struct auth_name *auth_name; - TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) { - if (strcmp(auth_name->an_initiator_name, name) == 0) + TAILQ_FOREACH(auth_name, head, an_next) { + if (strcmp(auth_name->an_name, name) == 0) return (auth_name); } @@ -341,20 +354,43 @@ } int -auth_name_check(const struct auth_group *ag, const char *initiator_name) +auth_name_check(const struct auth_group *ag, int protocol, const char *name) { - if (!auth_name_defined(ag)) + if (!auth_name_defined(ag, protocol)) return (0); - if (auth_name_find(ag, initiator_name) == NULL) + if (auth_name_find(ag, protocol, name) == NULL) return (1); return (0); } +static struct auth_portal_head * +auth_portal_head(struct auth_group *ag, int protocol) +{ + switch (protocol) { + case TARGET_PROTOCOL_ISCSI: + return (&ag->ag_initiator_portals); + default: + __assert_unreachable(); + } +} + +static const struct auth_portal_head * +auth_portal_const_head(const struct auth_group *ag, int protocol) +{ + switch (protocol) { + case TARGET_PROTOCOL_ISCSI: + return (&ag->ag_initiator_portals); + default: + __assert_unreachable(); + } +} + const struct auth_portal * -auth_portal_new(struct auth_group *ag, const char *portal) +auth_portal_new(struct auth_group *ag, int protocol, const char *portal) { + struct auth_portal_head *head = auth_portal_head(ag, protocol); struct auth_portal *ap; char *net, *mask, *str, *tmp; int len, dm, m; @@ -363,7 +399,7 @@ if (ap == NULL) log_err(1, "calloc"); ap->ap_auth_group = ag; - ap->ap_initiator_portal = checked_strdup(portal); + ap->ap_portal = checked_strdup(portal); mask = str = checked_strdup(portal); net = strsep(&mask, "/"); if (net[0] == '[') @@ -399,8 +435,9 @@ } else m = dm; ap->ap_mask = m; + ap->ap_protocol = protocol; free(str); - TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next); + TAILQ_INSERT_TAIL(head, ap, ap_next); return (ap); error: @@ -413,29 +450,38 @@ static void auth_portal_delete(struct auth_portal *ap) { - TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next); + struct auth_portal_head *head; - free(ap->ap_initiator_portal); + head = auth_portal_head(ap->ap_auth_group, ap->ap_protocol); + TAILQ_REMOVE(head, ap, ap_next); + + free(ap->ap_portal); free(ap); } bool -auth_portal_defined(const struct auth_group *ag) +auth_portal_defined(const struct auth_group *ag, int protocol) { - if (TAILQ_EMPTY(&ag->ag_portals)) + const struct auth_portal_head *head; + + head = auth_portal_const_head(ag, protocol); + if (TAILQ_EMPTY(head)) return (false); return (true); } const struct auth_portal * -auth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss) +auth_portal_find(const struct auth_group *ag, int protocol, + const struct sockaddr_storage *ss) { + const struct auth_portal_head *head; const struct auth_portal *ap; const uint8_t *a, *b; int i; uint8_t bmask; - TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) { + head = auth_portal_const_head(ag, protocol); + TAILQ_FOREACH(ap, head, ap_next) { if (ap->ap_sa.ss_family != ss->ss_family) continue; if (ss->ss_family == AF_INET) { @@ -467,13 +513,14 @@ } int -auth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa) +auth_portal_check(const struct auth_group *ag, int protocol, + const struct sockaddr_storage *sa) { - if (!auth_portal_defined(ag)) + if (!auth_portal_defined(ag, protocol)) return (0); - if (auth_portal_find(ag, sa) == NULL) + if (auth_portal_find(ag, protocol, sa) == NULL) return (1); return (0); @@ -498,8 +545,8 @@ if (name != NULL) ag->ag_name = checked_strdup(name); TAILQ_INIT(&ag->ag_auths); - TAILQ_INIT(&ag->ag_names); - TAILQ_INIT(&ag->ag_portals); + TAILQ_INIT(&ag->ag_initiator_names); + TAILQ_INIT(&ag->ag_initiator_portals); ag->ag_conf = conf; TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); @@ -517,9 +564,10 @@ TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp) auth_delete(auth); - TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp) + TAILQ_FOREACH_SAFE(auth_name, &ag->ag_initiator_names, an_next, + auth_name_tmp) auth_name_delete(auth_name); - TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next, + TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_initiator_portals, ap_next, auth_portal_tmp) auth_portal_delete(auth_portal); free(ag->ag_name); @@ -598,7 +646,7 @@ static void portal_delete(struct portal *portal) { - + portal->p_portal_group->pg_ops->portal_delete(portal); TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); if (portal->p_ai != NULL) freeaddrinfo(portal->p_ai); @@ -606,14 +654,39 @@ free(portal); } +static struct target_protocol_ops * +target_ops(int protocol) +{ + switch (protocol) { +#ifdef WANT_ISCSI + case TARGET_PROTOCOL_ISCSI: + return (&target_iscsi); +#endif + default: + return (NULL); + } +} + +static const char * +portal_group_keyword(int protocol) +{ + switch (protocol) { + case TARGET_PROTOCOL_ISCSI: + return "portal-group"; + default: + __assert_unreachable(); + } +} + struct portal_group * -portal_group_new(struct conf *conf, const char *name) +portal_group_new(struct conf *conf, int protocol, const char *name) { struct portal_group *pg; - pg = portal_group_find(conf, name); + pg = portal_group_find(conf, protocol, name); if (pg != NULL) { - log_warnx("duplicated portal-group \"%s\"", name); + log_warnx("duplicated %s \"%s\"", + portal_group_keyword(protocol), name); return (NULL); } @@ -624,6 +697,8 @@ pg->pg_options = nvlist_create(0); TAILQ_INIT(&pg->pg_portals); TAILQ_INIT(&pg->pg_ports); + pg->pg_protocol = protocol; + pg->pg_ops = target_ops(protocol); pg->pg_conf = conf; pg->pg_tag = 0; /* Assigned later in conf_apply(). */ pg->pg_dscp = -1; @@ -653,12 +728,13 @@ } struct portal_group * -portal_group_find(const struct conf *conf, const char *name) +portal_group_find(const struct conf *conf, int protocol, const char *name) { struct portal_group *pg; TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { - if (strcmp(pg->pg_name, name) == 0) + if (pg->pg_protocol == protocol && + strcmp(pg->pg_name, name) == 0) return (pg); } @@ -723,15 +799,26 @@ } int -portal_group_add_listen(struct portal_group *pg, const char *value, bool iser) +portal_group_add_listen(struct portal_group *pg, const char *value, + int protocol) { struct portal *portal; + const char *def_port; portal = portal_new(pg); portal->p_listen = checked_strdup(value); - portal->p_iser = iser; + portal->p_protocol = protocol; - if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) { + switch (protocol) { + case PORTAL_PROTOCOL_ISER: + case PORTAL_PROTOCOL_ISCSI: + def_port = "3260"; + break; + default: + __builtin_unreachable(); + } + + if (parse_addr_port(portal->p_listen, def_port, &portal->p_ai)) { log_warnx("invalid listen address %s", portal->p_listen); portal_delete(portal); return (1); @@ -742,6 +829,7 @@ * those into multiple portals. */ + pg->pg_ops->portal_init(portal); return (0); } @@ -828,6 +916,8 @@ } } TAILQ_FOREACH(target, &conf->conf_targets, t_next) { + if (target->t_protocol != TARGET_PROTOCOL_ISCSI) + continue; isns_req_add_str(req, 32, target->t_name); isns_req_add_32(req, 33, 1); /* 1 -- Target*/ if (target->t_alias != NULL) @@ -1280,31 +1370,31 @@ } struct target * -target_new(struct conf *conf, const char *name) +target_new(struct conf *conf, const char *name, int protocol) { + struct target_protocol_ops *ops; struct target *targ; - int i, len; + char *t_name; targ = target_find(conf, name); if (targ != NULL) { log_warnx("duplicated target \"%s\"", name); return (NULL); } - if (valid_iscsi_name(name, log_warnx) == false) { + ops = target_ops(protocol); + if (ops == NULL) { + log_warnx("unsupported protocol for target \"%s\"", name); return (NULL); } + t_name = ops->validate_target_name(name); + if (t_name == NULL) + return (NULL); targ = calloc(1, sizeof(*targ)); if (targ == NULL) log_err(1, "calloc"); - targ->t_name = checked_strdup(name); - - /* - * RFC 3722 requires us to normalize the name to lowercase. - */ - len = strlen(name); - for (i = 0; i < len; i++) - targ->t_name[i] = tolower(targ->t_name[i]); - + targ->t_name = t_name; + targ->t_ops = ops; + targ->t_protocol = protocol; targ->t_conf = conf; TAILQ_INIT(&targ->t_ports); TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); @@ -1498,63 +1588,6 @@ return (true); } -#ifdef ICL_KERNEL_PROXY - -static void -pdu_receive_proxy(struct pdu *pdu) -{ - struct connection *conn; - size_t len; - - assert(proxy_mode); - conn = pdu->pdu_connection; - - kernel_receive(pdu); - - len = pdu_ahs_length(pdu); - if (len > 0) - log_errx(1, "protocol error: non-empty AHS"); - - len = pdu_data_segment_length(pdu); - assert(len <= (size_t)conn->conn_max_recv_data_segment_length); - pdu->pdu_data_len = len; -} - -static void -pdu_send_proxy(struct pdu *pdu) -{ - - assert(proxy_mode); - - pdu_set_data_segment_length(pdu, pdu->pdu_data_len); - kernel_send(pdu); -} - -#endif /* ICL_KERNEL_PROXY */ - -static void -pdu_fail(const struct connection *conn __unused, const char *reason __unused) -{ -} - -static struct ctld_connection * -connection_new(struct portal *portal, int fd, const char *host, - const struct sockaddr *client_sa) -{ - struct ctld_connection *conn; - - conn = calloc(1, sizeof(*conn)); - if (conn == NULL) - log_err(1, "calloc"); - connection_init(&conn->conn, &conn_ops, proxy_mode); - conn->conn.conn_socket = fd; - conn->conn_portal = portal; - conn->conn_initiator_addr = checked_strdup(host); - memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); - - return (conn); -} - #if 0 static void options_print(const char *prefix, nvlist_t *nvl) @@ -1587,16 +1620,17 @@ fprintf(stderr, "\t chap-mutual %s %s %s %s\n", auth->a_user, auth->a_secret, auth->a_mutual_user, auth->a_mutual_secret); - TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) + TAILQ_FOREACH(auth_name, &ag->ag_initiator_names, an_next) fprintf(stderr, "\t initiator-name %s\n", - auth_name->an_initiator_name); - TAILQ_FOREACH(auth_portal, &ag->ag_portals, ap_next) + auth_name->an_name); + TAILQ_FOREACH(auth_portal, &ag->ag_initiator_portals, ap_next) fprintf(stderr, "\t initiator-portal %s\n", - auth_portal->ap_initiator_portal); + auth_portal->ap_portal); fprintf(stderr, "}\n"); } TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { - fprintf(stderr, "portal-group %s {\n", pg->pg_name); + fprintf(stderr, "%s %s {\n", + portal_group_keyword(pg->pg_protocol), pg->pg_name); TAILQ_FOREACH(portal, &pg->pg_portals, p_next) fprintf(stderr, "\t listen %s\n", portal->p_listen); options_print("\t", pg->pg_options); @@ -1699,7 +1733,8 @@ assert(targ->t_auth_group != NULL); } if (TAILQ_EMPTY(&targ->t_ports)) { - pg = portal_group_find(conf, "default"); + pg = portal_group_find(conf, targ->t_protocol, + "default"); assert(pg != NULL); port_new(conf, targ, pg); } @@ -1741,8 +1776,10 @@ pg->pg_unassigned = false; } else { if (strcmp(pg->pg_name, "default") != 0) - log_warnx("portal-group \"%s\" not assigned " - "to any target", pg->pg_name); + log_warnx("%s \"%s\" not assigned " + "to any target", + portal_group_keyword(pg->pg_protocol), + pg->pg_name); pg->pg_unassigned = true; } } @@ -1808,7 +1845,7 @@ { struct portal_group *pg = p->p_portal_group; struct kevent kev; - int error, sockbuf; + int error; int one = 1; log_debugx("listening on %s, portal-group \"%s\"", @@ -1821,15 +1858,6 @@ return (false); } - sockbuf = SOCKBUF_SIZE; - if (setsockopt(p->p_socket, SOL_SOCKET, SO_RCVBUF, &sockbuf, - sizeof(sockbuf)) == -1) - log_warn("setsockopt(SO_RCVBUF) failed for %s", - p->p_listen); - sockbuf = SOCKBUF_SIZE; - if (setsockopt(p->p_socket, SOL_SOCKET, SO_SNDBUF, &sockbuf, - sizeof(sockbuf)) == -1) - log_warn("setsockopt(SO_SNDBUF) failed for %s", p->p_listen); if (setsockopt(p->p_socket, SOL_SOCKET, SO_NO_DDP, &one, sizeof(one)) == -1) log_warn("setsockopt(SO_NO_DDP) failed for %s", p->p_listen); @@ -1878,6 +1906,8 @@ } } + pg->pg_ops->portal_init_socket(p); + error = bind(p->p_socket, p->p_ai->ai_addr, p->p_ai->ai_addrlen); if (error != 0) { @@ -1946,11 +1976,12 @@ TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { if (newpg->pg_tag != 0) continue; - oldpg = portal_group_find(oldconf, newpg->pg_name); + oldpg = portal_group_find(oldconf, newpg->pg_protocol, + newpg->pg_name); if (oldpg != NULL) - newpg->pg_tag = oldpg->pg_tag; + newpg->pg_ops->portal_group_copy(oldpg, newpg); else - newpg->pg_tag = ++last_portal_group_tag; + newpg->pg_ops->portal_group_init(newpg); } /* Deregister on removed iSNS servers. */ @@ -2131,8 +2162,9 @@ if (newpg->pg_foreign) continue; if (newpg->pg_unassigned) { - log_debugx("not listening on portal-group \"%s\", " + log_debugx("not listening on %s \"%s\", " "not assigned to any target", + portal_group_keyword(newpg->pg_protocol), newpg->pg_name); continue; } @@ -2172,7 +2204,7 @@ } #endif assert(proxy_mode == false); - assert(newp->p_iser == false); + assert(newp->p_protocol != PORTAL_PROTOCOL_ISER); if (!portal_init_socket(newp)) { cumulated_error++; @@ -2188,8 +2220,10 @@ 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); + log_debugx("closing socket for %s, %s \"%s\"", + oldp->p_listen, + portal_group_keyword(oldpg->pg_protocol), + oldpg->pg_name); close(oldp->p_socket); oldp->p_socket = 0; } @@ -2211,7 +2245,7 @@ return (cumulated_error); } -static bool +bool timed_out(void) { @@ -2322,13 +2356,13 @@ handle_connection(struct portal *portal, int fd, const struct sockaddr *client_sa, bool dont_fork) { - struct ctld_connection *conn; + struct portal_group *pg = portal->p_portal_group; int error; pid_t pid; char host[NI_MAXHOST + 1]; struct conf *conf; - conf = portal->p_portal_group->pg_conf; + conf = pg->pg_conf; if (dont_fork) { log_debugx("incoming connection; not forking due to -d flag"); @@ -2360,22 +2394,12 @@ 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_debugx("accepted connection from %s; %s \"%s\"", + host, portal_group_keyword(pg->pg_protocol), pg->pg_name); log_set_peer_addr(host); setproctitle("%s", host); - conn = connection_new(portal, fd, host, client_sa); - set_timeout(conf->conf_timeout, true); - 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); - } + pg->pg_ops->handle_connection(portal, fd, host, client_sa); log_debugx("nothing more to do; exiting"); exit(0); } @@ -2564,7 +2588,7 @@ assert(ag != NULL); ag->ag_type = AG_TYPE_DENY; - pg = portal_group_new(conf, "default"); + pg = portal_group_new(conf, TARGET_PROTOCOL_ISCSI, "default"); assert(pg != NULL); if (ucl) @@ -2590,10 +2614,10 @@ if (conf->conf_default_pg_defined == false) { log_debugx("portal-group \"default\" not defined; " "going with defaults"); - pg = portal_group_find(conf, "default"); + pg = portal_group_find(conf, TARGET_PROTOCOL_ISCSI, "default"); assert(pg != NULL); - portal_group_add_listen(pg, "0.0.0.0", false); - portal_group_add_listen(pg, "[::]", false); + portal_group_add_listen(pg, "0.0.0.0", PORTAL_PROTOCOL_ISCSI); + portal_group_add_listen(pg, "[::]", PORTAL_PROTOCOL_ISCSI); } conf->conf_kernel_port_on = true; diff --git a/usr.sbin/ctld/discovery.c b/usr.sbin/ctld/discovery.c --- a/usr.sbin/ctld/discovery.c +++ b/usr.sbin/ctld/discovery.c @@ -164,14 +164,16 @@ assert(pg->pg_discovery_filter != PG_FILTER_UNKNOWN); if (pg->pg_discovery_filter >= PG_FILTER_PORTAL && - auth_portal_check(ag, &conn->conn_initiator_sa) != 0) { + auth_portal_check(ag, TARGET_PROTOCOL_ISCSI, + &conn->conn_initiator_sa) != 0) { log_debugx("initiator does not match initiator portals " "allowed for target \"%s\"; skipping", targ->t_name); return (true); } if (pg->pg_discovery_filter >= PG_FILTER_PORTAL_NAME && - auth_name_check(ag, conn->conn_initiator_name) != 0) { + auth_name_check(ag, TARGET_PROTOCOL_ISCSI, + conn->conn_initiator_name) != 0) { log_debugx("initiator does not match initiator names " "allowed for target \"%s\"; skipping", targ->t_name); return (true); diff --git a/usr.sbin/ctld/iscsi.c b/usr.sbin/ctld/iscsi.c new file mode 100644 --- /dev/null +++ b/usr.sbin/ctld/iscsi.c @@ -0,0 +1,341 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2003, 2004 Silicon Graphics International Corp. + * Copyright (c) 1997-2007 Kenneth D. Merry + * Copyright (c) 2012 The FreeBSD Foundation + * Copyright (c) 2017 Jakub Wojciech Klama + * All rights reserved. + * Copyright (c) 2025 Chelsio Communications, Inc. + * + * Portions of this software were 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, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ctld.h" + +#define SOCKBUF_SIZE 1048576 + +#ifdef ICL_KERNEL_PROXY +static void pdu_receive_proxy(struct pdu *pdu); +static void pdu_send_proxy(struct pdu *pdu); +#endif /* ICL_KERNEL_PROXY */ +static void pdu_fail(const struct connection *conn, const char *reason); + +static uint16_t scsi_last_portal_group_tag = 0xff; + +static struct connection_ops conn_ops = { + .timed_out = timed_out, +#ifdef ICL_KERNEL_PROXY + .pdu_receive_proxy = pdu_receive_proxy, + .pdu_send_proxy = pdu_send_proxy, +#endif + .fail = pdu_fail, +}; + +static void +iscsi_portal_group_init(struct portal_group *pg) +{ + pg->pg_tag = ++scsi_last_portal_group_tag; +} + +static void +iscsi_portal_group_copy(struct portal_group *oldpg, struct portal_group *newpg) +{ + newpg->pg_tag = oldpg->pg_tag; +} + +static void +iscsi_portal_init(struct portal *p __unused) +{ +} + +static void +iscsi_portal_init_socket(struct portal *p) +{ + int sockbuf; + + sockbuf = SOCKBUF_SIZE; + if (setsockopt(p->p_socket, SOL_SOCKET, SO_RCVBUF, &sockbuf, + sizeof(sockbuf)) == -1) + log_warn("setsockopt(SO_RCVBUF) failed for %s", p->p_listen); + sockbuf = SOCKBUF_SIZE; + if (setsockopt(p->p_socket, SOL_SOCKET, SO_SNDBUF, &sockbuf, + sizeof(sockbuf)) == -1) + log_warn("setsockopt(SO_SNDBUF) failed for %s", p->p_listen); +} + +static void +iscsi_portal_delete(struct portal *p __unused) +{ +} + +static void +iscsi_load_kernel_module(void) +{ + static bool loaded; + int saved_errno; + + if (loaded) + return; + + saved_errno = errno; + if (modfind("cfiscsi") == -1 && kldload("cfiscsi") == -1) + log_warn("couldn't load cfiscsi"); + errno = saved_errno; + loaded = true; +} + +static void +iscsi_kernel_port_add(struct port *port, struct ctl_req *req) +{ + struct target *targ = port->p_target; + struct portal_group *pg = port->p_portal_group; + + iscsi_load_kernel_module(); + + strlcpy(req->driver, "iscsi", sizeof(req->driver)); + + nvlist_add_string(req->args_nvl, "cfiscsi_target", targ->t_name); + nvlist_add_string(req->args_nvl, "ctld_portal_group_name", pg->pg_name); + nvlist_add_stringf(req->args_nvl, "cfiscsi_portal_group_tag", "%u", + pg->pg_tag); + + if (targ->t_alias != NULL) { + nvlist_add_string(req->args_nvl, "cfiscsi_target_alias", + targ->t_alias); + } +} + +static void +iscsi_kernel_port_remove(struct port *port, struct ctl_req *req) +{ + struct target *targ = port->p_target; + struct portal_group *pg = port->p_portal_group; + + strlcpy(req->driver, "iscsi", sizeof(req->driver)); + + nvlist_add_string(req->args_nvl, "cfiscsi_target", targ->t_name); + nvlist_add_stringf(req->args_nvl, "cfiscsi_portal_group_tag", + "%u", pg->pg_tag); +} + +static char * +iscsi_validate_target_name(const char *name) +{ + char *t_name; + size_t i, len; + + if (valid_iscsi_name(name, log_warnx) == false) { + log_warnx("target name \"%s\" is invalid for iSCSI", name); + return (NULL); + } + + t_name = strdup(name); + if (t_name == NULL) { + log_warn("strdup"); + return (NULL); + } + + /* + * RFC 3722 requires us to normalize the name to lowercase. + */ + len = strlen(t_name); + for (i = 0; i < len; i++) + t_name[i] = tolower(t_name[i]); + + return (t_name); +} + +#ifdef ICL_KERNEL_PROXY + +static void +pdu_receive_proxy(struct pdu *pdu) +{ + struct connection *conn; + size_t len; + + assert(proxy_mode); + conn = pdu->pdu_connection; + + kernel_receive(pdu); + + len = pdu_ahs_length(pdu); + if (len > 0) + log_errx(1, "protocol error: non-empty AHS"); + + len = pdu_data_segment_length(pdu); + assert(len <= (size_t)conn->conn_max_recv_data_segment_length); + pdu->pdu_data_len = len; +} + +static void +pdu_send_proxy(struct pdu *pdu) +{ + + assert(proxy_mode); + + pdu_set_data_segment_length(pdu, pdu->pdu_data_len); + kernel_send(pdu); +} + +#endif /* ICL_KERNEL_PROXY */ + +static void +pdu_fail(const struct connection *conn __unused, const char *reason __unused) +{ +} + +static struct ctld_connection * +connection_new(struct portal *portal, int fd, const char *host, + const struct sockaddr *client_sa) +{ + struct ctld_connection *conn; + + conn = calloc(1, sizeof(*conn)); + if (conn == NULL) + log_err(1, "calloc"); + connection_init(&conn->conn, &conn_ops, proxy_mode); + conn->conn.conn_socket = fd; + conn->conn_portal = portal; + conn->conn_initiator_addr = checked_strdup(host); + memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); + + return (conn); +} + +static void +kernel_handoff(struct ctld_connection *conn) +{ + struct ctl_iscsi req; + + bzero(&req, sizeof(req)); + + req.type = CTL_ISCSI_HANDOFF; + strlcpy(req.data.handoff.initiator_name, + conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name)); + strlcpy(req.data.handoff.initiator_addr, + conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr)); + if (conn->conn_initiator_alias != NULL) { + strlcpy(req.data.handoff.initiator_alias, + conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias)); + } + memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid, + sizeof(req.data.handoff.initiator_isid)); + strlcpy(req.data.handoff.target_name, + conn->conn_target->t_name, sizeof(req.data.handoff.target_name)); + if (conn->conn_portal->p_portal_group->pg_offload != NULL) { + strlcpy(req.data.handoff.offload, + conn->conn_portal->p_portal_group->pg_offload, + sizeof(req.data.handoff.offload)); + } +#ifdef ICL_KERNEL_PROXY + if (proxy_mode) + req.data.handoff.connection_id = conn->conn.conn_socket; + else + req.data.handoff.socket = conn->conn.conn_socket; +#else + req.data.handoff.socket = conn->conn.conn_socket; +#endif + req.data.handoff.portal_group_tag = + conn->conn_portal->p_portal_group->pg_tag; + if (conn->conn.conn_header_digest == CONN_DIGEST_CRC32C) + req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; + if (conn->conn.conn_data_digest == CONN_DIGEST_CRC32C) + req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; + req.data.handoff.cmdsn = conn->conn.conn_cmdsn; + req.data.handoff.statsn = conn->conn.conn_statsn; + req.data.handoff.max_recv_data_segment_length = + conn->conn.conn_max_recv_data_segment_length; + req.data.handoff.max_send_data_segment_length = + conn->conn.conn_max_send_data_segment_length; + req.data.handoff.max_burst_length = conn->conn.conn_max_burst_length; + req.data.handoff.first_burst_length = + conn->conn.conn_first_burst_length; + req.data.handoff.immediate_data = conn->conn.conn_immediate_data; + + if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { + log_err(1, "error issuing CTL_ISCSI ioctl; " + "dropping connection"); + } + + if (req.status != CTL_ISCSI_OK) { + log_errx(1, "error returned from CTL iSCSI handoff request: " + "%s; dropping connection", req.error_str); + } +} + +static void +iscsi_handle_connection(struct portal *portal, int fd, const char *host, + const struct sockaddr *client_sa) +{ + struct portal_group *pg = portal->p_portal_group; + struct conf *conf = pg->pg_conf; + struct ctld_connection *conn; + + conn = connection_new(portal, fd, host, client_sa); + set_timeout(conf->conf_timeout, true); + 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); + } +} + +struct target_protocol_ops target_iscsi = { + .portal_group_init = iscsi_portal_group_init, + .portal_group_copy = iscsi_portal_group_copy, + .portal_init = iscsi_portal_init, + .portal_init_socket = iscsi_portal_init_socket, + .portal_delete = iscsi_portal_delete, + .kernel_port_add = iscsi_kernel_port_add, + .kernel_port_remove = iscsi_kernel_port_remove, + .validate_target_name = iscsi_validate_target_name, + .handle_connection = iscsi_handle_connection, +}; diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c --- a/usr.sbin/ctld/kernel.c +++ b/usr.sbin/ctld/kernel.c @@ -75,9 +75,7 @@ #define NVLIST_BUFSIZE 1024 -extern bool proxy_mode; - -static int ctl_fd = 0; +int ctl_fd = 0; void kernel_init(void) @@ -95,14 +93,6 @@ } if (ctl_fd < 0) log_err(1, "failed to open %s", CTL_DEFAULT_DEV); -#ifdef WANT_ISCSI - else { - saved_errno = errno; - if (modfind("cfiscsi") == -1 && kldload("cfiscsi") == -1) - log_warn("couldn't load cfiscsi"); - errno = saved_errno; - } -#endif } /* @@ -409,9 +399,9 @@ struct cctl_port *port; XML_Parser parser; const char *key; - char *str, *name; + char *str, *name, *target_name; void *cookie; - int error, len, retval; + int error, len, protocol, retval; bzero(&devlist, sizeof(devlist)); STAILQ_INIT(&devlist.lun_list); @@ -523,6 +513,11 @@ STAILQ_FOREACH(port, &devlist.port_list, links) { if (strcmp(port->port_frontend, "ha") == 0) continue; + if (strcmp(port->port_frontend, "iscsi") == 0) + protocol = TARGET_PROTOCOL_ISCSI; + else + /* XXX: Treat all unknown ports as iSCSI? */ + protocol = TARGET_PROTOCOL_ISCSI; free(name); if (port->pp == 0 && port->vp == 0) { name = checked_strdup(port->port_name); @@ -538,7 +533,15 @@ log_err(1, "asprintf"); } - if (port->cfiscsi_target == NULL) { + switch (protocol) { + case TARGET_PROTOCOL_ISCSI: + target_name = port->cfiscsi_target; + break; + default: + __assert_unreachable(); + break; + } + if (target_name == NULL) { log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", port->port_id, name); pp = pport_find(kports, name); @@ -555,19 +558,20 @@ } continue; } - if (port->cfiscsi_state != 1) { + if (protocol == TARGET_PROTOCOL_ISCSI && + port->cfiscsi_state != 1) { log_debugx("CTL port %ju is not active (%d); ignoring", (uintmax_t)port->port_id, port->cfiscsi_state); continue; } - targ = target_find(conf, port->cfiscsi_target); + targ = target_find(conf, target_name); if (targ == NULL) { #if 0 log_debugx("found new kernel target %s for CTL port %ld", - port->cfiscsi_target, port->port_id); + target_name, port->port_id); #endif - targ = target_new(conf, port->cfiscsi_target); + targ = target_new(conf, target_name, protocol); if (targ == NULL) { log_warnx("target_new failed"); continue; @@ -576,19 +580,28 @@ if (port->ctld_portal_group_name == NULL) continue; - pg = portal_group_find(conf, port->ctld_portal_group_name); + pg = portal_group_find(conf, protocol, + port->ctld_portal_group_name); if (pg == NULL) { #if 0 log_debugx("found new kernel portal group %s for CTL port %ld", port->ctld_portal_group_name, port->port_id); #endif - pg = portal_group_new(conf, port->ctld_portal_group_name); + pg = portal_group_new(conf, protocol, + port->ctld_portal_group_name); if (pg == NULL) { log_warnx("portal_group_new failed"); continue; } } - pg->pg_tag = port->cfiscsi_portal_group_tag; + switch (protocol) { + case TARGET_PROTOCOL_ISCSI: + pg->pg_tag = port->cfiscsi_portal_group_tag; + break; + default: + __assert_unreachable(); + break; + } cp = port_new(conf, targ, pg); if (cp == NULL) { log_warnx("port_new failed"); @@ -846,67 +859,6 @@ return (0); } -void -kernel_handoff(struct ctld_connection *conn) -{ - struct ctl_iscsi req; - - bzero(&req, sizeof(req)); - - req.type = CTL_ISCSI_HANDOFF; - strlcpy(req.data.handoff.initiator_name, - conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name)); - strlcpy(req.data.handoff.initiator_addr, - conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr)); - if (conn->conn_initiator_alias != NULL) { - strlcpy(req.data.handoff.initiator_alias, - conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias)); - } - memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid, - sizeof(req.data.handoff.initiator_isid)); - strlcpy(req.data.handoff.target_name, - conn->conn_target->t_name, sizeof(req.data.handoff.target_name)); - if (conn->conn_portal->p_portal_group->pg_offload != NULL) { - strlcpy(req.data.handoff.offload, - conn->conn_portal->p_portal_group->pg_offload, - sizeof(req.data.handoff.offload)); - } -#ifdef ICL_KERNEL_PROXY - if (proxy_mode) - req.data.handoff.connection_id = conn->conn.conn_socket; - else - req.data.handoff.socket = conn->conn.conn_socket; -#else - req.data.handoff.socket = conn->conn.conn_socket; -#endif - req.data.handoff.portal_group_tag = - conn->conn_portal->p_portal_group->pg_tag; - if (conn->conn.conn_header_digest == CONN_DIGEST_CRC32C) - req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; - if (conn->conn.conn_data_digest == CONN_DIGEST_CRC32C) - req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; - req.data.handoff.cmdsn = conn->conn.conn_cmdsn; - req.data.handoff.statsn = conn->conn.conn_statsn; - req.data.handoff.max_recv_data_segment_length = - conn->conn.conn_max_recv_data_segment_length; - req.data.handoff.max_send_data_segment_length = - conn->conn.conn_max_send_data_segment_length; - req.data.handoff.max_burst_length = conn->conn.conn_max_burst_length; - req.data.handoff.first_burst_length = - conn->conn.conn_first_burst_length; - req.data.handoff.immediate_data = conn->conn.conn_immediate_data; - - if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { - log_err(1, "error issuing CTL_ISCSI ioctl; " - "dropping connection"); - } - - if (req.status != CTL_ISCSI_OK) { - log_errx(1, "error returned from CTL iSCSI handoff request: " - "%s; dropping connection", req.error_str); - } -} - int kernel_port_add(struct port *port) { @@ -923,29 +875,16 @@ bzero(&req, sizeof(req)); req.reqtype = CTL_REQ_CREATE; - if (port->p_portal_group) { - strlcpy(req.driver, "iscsi", sizeof(req.driver)); - req.args_nvl = nvlist_clone(pg->pg_options); - nvlist_add_string(req.args_nvl, "cfiscsi_target", - targ->t_name); - nvlist_add_string(req.args_nvl, - "ctld_portal_group_name", pg->pg_name); - nvlist_add_stringf(req.args_nvl, - "cfiscsi_portal_group_tag", "%u", pg->pg_tag); - - if (targ->t_alias) { - nvlist_add_string(req.args_nvl, - "cfiscsi_target_alias", targ->t_alias); - } - } - if (port->p_ioctl_port) { - strlcpy(req.driver, "ioctl", sizeof(req.driver)); req.args_nvl = nvlist_create(0); + strlcpy(req.driver, "ioctl", sizeof(req.driver)); nvlist_add_stringf(req.args_nvl, "pp", "%d", port->p_ioctl_pp); nvlist_add_stringf(req.args_nvl, "vp", "%d", port->p_ioctl_vp); + } else { + req.args_nvl = nvlist_clone(pg->pg_options); + pg->pg_ops->kernel_port_add(port, &req); } req.args = nvlist_pack(req.args_nvl, &req.args_len); @@ -1067,7 +1006,6 @@ struct ctl_port_entry entry; struct ctl_lun_map lm; struct ctl_req req; - struct target *targ = port->p_target; struct portal_group *pg = port->p_portal_group; int error; @@ -1083,22 +1021,18 @@ /* Remove iSCSI or ioctl port. */ if (port->p_portal_group || port->p_ioctl_port) { bzero(&req, sizeof(req)); - strlcpy(req.driver, port->p_ioctl_port ? "ioctl" : "iscsi", - sizeof(req.driver)); req.reqtype = CTL_REQ_REMOVE; req.args_nvl = nvlist_create(0); if (req.args_nvl == NULL) log_err(1, "nvlist_create"); - if (port->p_ioctl_port) + if (port->p_ioctl_port) { + strlcpy(req.driver, "ioctl", sizeof(req.driver)); + nvlist_add_stringf(req.args_nvl, "port_id", "%d", port->p_ctl_port); - else { - nvlist_add_string(req.args_nvl, "cfiscsi_target", - targ->t_name); - nvlist_add_stringf(req.args_nvl, - "cfiscsi_portal_group_tag", "%u", pg->pg_tag); - } + } else + pg->pg_ops->kernel_port_remove(port, &req); req.args = nvlist_pack(req.args_nvl, &req.args_len); if (req.args == NULL) { diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c --- a/usr.sbin/ctld/login.c +++ b/usr.sbin/ctld/login.c @@ -1027,12 +1027,13 @@ /* * Enforce initiator-name and initiator-portal. */ - if (auth_name_check(ag, initiator_name) != 0) { + if (auth_name_check(ag, TARGET_PROTOCOL_ISCSI, initiator_name) != 0) { login_send_error(request, 0x02, 0x02); log_errx(1, "initiator does not match allowed initiator names"); } - if (auth_portal_check(ag, &conn->conn_initiator_sa) != 0) { + if (auth_portal_check(ag, TARGET_PROTOCOL_ISCSI, + &conn->conn_initiator_sa) != 0) { login_send_error(request, 0x02, 0x02); log_errx(1, "initiator does not match allowed " "initiator portals"); diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y --- a/usr.sbin/ctld/parse.y +++ b/usr.sbin/ctld/parse.y @@ -285,7 +285,7 @@ { const struct auth_name *an; - an = auth_name_new(auth_group, $2); + an = auth_name_new(auth_group, TARGET_PROTOCOL_ISCSI, $2); free($2); if (an == NULL) return (1); @@ -296,7 +296,7 @@ { const struct auth_portal *ap; - ap = auth_portal_new(auth_group, $2); + ap = auth_portal_new(auth_group, TARGET_PROTOCOL_ISCSI, $2); free($2); if (ap == NULL) return (1); @@ -313,15 +313,17 @@ portal_group_name: STR { /* - * Make it possible to redefine default + * Make it possible to redefine default iSCSI * portal-group. but only once. */ if (strcmp($1, "default") == 0 && conf->conf_default_pg_defined == false) { - portal_group = portal_group_find(conf, $1); + portal_group = portal_group_find(conf, + TARGET_PROTOCOL_ISCSI, $1); conf->conf_default_pg_defined = true; } else { - portal_group = portal_group_new(conf, $1); + portal_group = portal_group_new(conf, + TARGET_PROTOCOL_ISCSI, $1); } free($1); if (portal_group == NULL) @@ -402,7 +404,8 @@ { int error; - error = portal_group_add_listen(portal_group, $2, false); + error = portal_group_add_listen(portal_group, $2, + PORTAL_PROTOCOL_ISCSI); free($2); if (error != 0) return (1); @@ -413,7 +416,8 @@ { int error; - error = portal_group_add_listen(portal_group, $2, true); + error = portal_group_add_listen(portal_group, $2, + PORTAL_PROTOCOL_ISER); free($2); if (error != 0) return (1); @@ -555,7 +559,7 @@ target_name: STR { - target = target_new(conf, $1); + target = target_new(conf, $1, TARGET_PROTOCOL_ISCSI); free($1); if (target == NULL) return (1); @@ -741,7 +745,8 @@ } target->t_auth_group->ag_target = target; } - an = auth_name_new(target->t_auth_group, $2); + an = auth_name_new(target->t_auth_group, TARGET_PROTOCOL_ISCSI, + $2); free($2); if (an == NULL) return (1); @@ -768,7 +773,8 @@ } target->t_auth_group->ag_target = target; } - ap = auth_portal_new(target->t_auth_group, $2); + ap = auth_portal_new(target->t_auth_group, + TARGET_PROTOCOL_ISCSI, $2); free($2); if (ap == NULL) return (1); @@ -781,7 +787,7 @@ struct auth_group *tag; struct port *tp; - tpg = portal_group_find(conf, $2); + tpg = portal_group_find(conf, TARGET_PROTOCOL_ISCSI, $2); if (tpg == NULL) { log_warnx("unknown portal-group \"%s\" for target " "\"%s\"", $2, target->t_name); @@ -813,7 +819,7 @@ struct portal_group *tpg; struct port *tp; - tpg = portal_group_find(conf, $2); + tpg = portal_group_find(conf, TARGET_PROTOCOL_ISCSI, $2); if (tpg == NULL) { log_warnx("unknown portal-group \"%s\" for target " "\"%s\"", $2, target->t_name); diff --git a/usr.sbin/ctld/uclparse.c b/usr.sbin/ctld/uclparse.c --- a/usr.sbin/ctld/uclparse.c +++ b/usr.sbin/ctld/uclparse.c @@ -156,7 +156,8 @@ } - tpg = portal_group_find(conf, ucl_object_tostring(portal_group)); + tpg = portal_group_find(conf, TARGET_PROTOCOL_ISCSI, + ucl_object_tostring(portal_group)); if (tpg == NULL) { log_warnx("unknown portal-group \"%s\" for target " "\"%s\"", ucl_object_tostring(portal_group), target->t_name); @@ -464,7 +465,8 @@ while ((tmp = ucl_iterate_object(obj, &it2, true))) { const char *value = ucl_object_tostring(tmp); - an = auth_name_new(auth_group, value); + an = auth_name_new(auth_group, + TARGET_PROTOCOL_ISCSI, value); if (an == NULL) return (false); } @@ -482,7 +484,8 @@ while ((tmp = ucl_iterate_object(obj, &it2, true))) { const char *value = ucl_object_tostring(tmp); - ap = auth_portal_new(auth_group, value); + ap = auth_portal_new(auth_group, + TARGET_PROTOCOL_ISCSI, value); if (ap == NULL) return (false); } @@ -589,10 +592,12 @@ if (strcmp(name, "default") == 0 && conf->conf_default_pg_defined == false) { - portal_group = portal_group_find(conf, name); + portal_group = portal_group_find(conf, TARGET_PROTOCOL_ISCSI, + name); conf->conf_default_pg_defined = true; } else { - portal_group = portal_group_new(conf, name); + portal_group = portal_group_new(conf, TARGET_PROTOCOL_ISCSI, + name); } if (portal_group == NULL) @@ -629,7 +634,8 @@ if (!strcmp(key, "listen")) { if (obj->type == UCL_STRING) { if (portal_group_add_listen(portal_group, - ucl_object_tostring(obj), false) != 0) + ucl_object_tostring(obj), + PORTAL_PROTOCOL_ISCSI) != 0) return (false); } else if (obj->type == UCL_ARRAY) { while ((tmp = ucl_iterate_object(obj, &it2, @@ -637,7 +643,7 @@ if (portal_group_add_listen( portal_group, ucl_object_tostring(tmp), - false) != 0) + PORTAL_PROTOCOL_ISCSI) != 0) return (false); } } else { @@ -651,7 +657,7 @@ if (!strcmp(key, "listen-iser")) { if (obj->type == UCL_STRING) { if (portal_group_add_listen(portal_group, - ucl_object_tostring(obj), true) != 0) + ucl_object_tostring(obj), PORTAL_PROTOCOL_ISER) != 0) return (false); } else if (obj->type == UCL_ARRAY) { while ((tmp = ucl_iterate_object(obj, &it2, @@ -659,7 +665,7 @@ if (portal_group_add_listen( portal_group, ucl_object_tostring(tmp), - true) != 0) + PORTAL_PROTOCOL_ISER) != 0) return (false); } } else { @@ -721,7 +727,7 @@ const ucl_object_t *obj = NULL, *tmp = NULL; const char *key; - target = target_new(conf, name); + target = target_new(conf, name, TARGET_PROTOCOL_ISCSI); if (target == NULL) return (false); @@ -831,7 +837,7 @@ target->t_auth_group->ag_target = target; } an = auth_name_new(target->t_auth_group, - ucl_object_tostring(obj)); + TARGET_PROTOCOL_ISCSI, ucl_object_tostring(obj)); if (an == NULL) return (false); } @@ -854,7 +860,7 @@ target->t_auth_group->ag_target = target; } ap = auth_portal_new(target->t_auth_group, - ucl_object_tostring(obj)); + TARGET_PROTOCOL_ISCSI, ucl_object_tostring(obj)); if (ap == NULL) return (false); }