diff --git a/usr.sbin/ctld/Makefile b/usr.sbin/ctld/Makefile --- a/usr.sbin/ctld/Makefile +++ b/usr.sbin/ctld/Makefile @@ -5,7 +5,7 @@ PACKAGE= ctl PROG_CXX= ctld -SRCS= ctld.cc conf.cc discovery.cc isns.cc kernel.cc +SRCS= ctld.cc conf.cc discovery.cc iscsi.cc isns.cc kernel.cc SRCS+= login.cc parse.y token.l y.tab.h uclparse.cc CFLAGS+= -I${.CURDIR} CFLAGS+= -I${SRCTOP}/sys @@ -25,10 +25,6 @@ NO_WMISSING_VARIABLE_DECLARATIONS= -.if ${MK_ISCSI} != "no" -CFLAGS+= -DWANT_ISCSI -.endif - .include CXXWARNFLAGS.uclparse.cc= -Wno-shadow -Wno-cast-qual diff --git a/usr.sbin/ctld/conf.cc b/usr.sbin/ctld/conf.cc --- a/usr.sbin/ctld/conf.cc +++ b/usr.sbin/ctld/conf.cc @@ -175,7 +175,8 @@ bool portal_group_add_listen(const char *listen, bool iser) { - return (portal_group->add_portal(listen, iser)); + return (portal_group->add_portal(listen, iser ? portal_protocol::ISER : + portal_protocol::ISCSI)); } bool diff --git a/usr.sbin/ctld/ctld.hh b/usr.sbin/ctld/ctld.hh --- a/usr.sbin/ctld/ctld.hh +++ b/usr.sbin/ctld/ctld.hh @@ -56,7 +56,6 @@ #define DEFAULT_CD_BLOCKSIZE 2048 #define MAX_LUNS 1024 -#define SOCKBUF_SIZE 1048576 struct isns_req; struct port; @@ -130,18 +129,28 @@ using auth_group_sp = std::shared_ptr; +enum class portal_protocol { + ISCSI, + ISER +}; + struct portal { - portal(struct portal_group *pg, std::string_view listen, bool iser, - freebsd::addrinfo_up ai) : + portal(struct portal_group *pg, std::string_view listen, + portal_protocol protocol, freebsd::addrinfo_up ai) : p_portal_group(pg), p_listen(listen), p_ai(std::move(ai)), - p_iser(iser) {} + p_protocol(protocol) {} + virtual ~portal() = default; bool reuse_socket(portal &oldp); bool init_socket(); + virtual bool init_socket_options(int s __unused) { return true; } + virtual void handle_connection(int fd, const char *host, + const struct sockaddr *client_sa) = 0; portal_group *portal_group() { return p_portal_group; } const char *listen() const { return p_listen.c_str(); } const addrinfo *ai() const { return p_ai.get(); } + portal_protocol protocol() const { return p_protocol; } int socket() const { return p_socket; } void close() { p_socket.reset(); } @@ -149,12 +158,13 @@ struct portal_group *p_portal_group; std::string p_listen; freebsd::addrinfo_up p_ai; - bool p_iser; + portal_protocol p_protocol; freebsd::fd_up p_socket; }; using portal_up = std::unique_ptr; +using port_up = std::unique_ptr; enum class discovery_filter { UNKNOWN, @@ -166,8 +176,10 @@ struct portal_group { portal_group(struct conf *conf, std::string_view name); + virtual ~portal_group() = default; struct conf *conf() const { return pg_conf; } + virtual const char *keyword() const = 0; const char *name() const { return pg_name.c_str(); } bool assigned() const { return pg_assigned; } bool is_dummy() const; @@ -188,17 +200,25 @@ const std::unordered_map &ports() const { return pg_ports; } - bool add_portal(const char *value, bool iser); + virtual void allocate_tag() = 0; + virtual bool add_portal(const char *value, + portal_protocol protocol) = 0; + virtual void add_default_portals() = 0; bool add_option(const char *name, const char *value); bool set_discovery_auth_group(const char *name); bool set_dscp(u_int dscp); - bool set_filter(const char *str); + virtual bool set_filter(const char *str) = 0; void set_foreign(); bool set_offload(const char *offload); bool set_pcp(u_int pcp); bool set_redirection(const char *addr); void set_tag(uint16_t tag); + virtual port_up create_port(struct target *target, auth_group_sp ag) = + 0; + virtual port_up create_port(struct target *target, uint32_t ctl_port) = + 0; + void add_port(struct portal_group_port *port); const struct port *find_port(std::string_view target) const; void remove_port(struct portal_group_port *port); @@ -208,9 +228,10 @@ int open_sockets(struct conf &oldconf); void close_sockets(); -private: +protected: struct conf *pg_conf; freebsd::nvlist_up pg_options; + const char *pg_keyword; std::string pg_name; auth_group_sp pg_discovery_auth_group; enum discovery_filter pg_discovery_filter = @@ -254,7 +275,7 @@ uint32_t p_ctl_port = 0; }; -struct portal_group_port final : public port { +struct portal_group_port : public port { portal_group_port(struct target *target, struct portal_group *pg, auth_group_sp ag); portal_group_port(struct target *target, struct portal_group *pg, @@ -270,10 +291,7 @@ void clear_references() override; - bool kernel_create_port() override; - bool kernel_remove_port() override; - -private: +protected: auth_group_sp p_auth_group; struct portal_group *p_portal_group; }; @@ -348,14 +366,15 @@ }; struct target { - target(struct conf *conf, std::string_view name) : - t_conf(conf), t_name(name) {} + target(struct conf *conf, const char *keyword, std::string_view name); + virtual ~target() = default; bool has_alias() const { return !t_alias.empty(); } bool has_pport() const { return !t_pport.empty(); } bool has_redirection() const { return !t_redirection.empty(); } const char *alias() const { return t_alias.c_str(); } const char *name() const { return t_name.c_str(); } + const char *label() const { return t_label.c_str(); } const char *pport() const { return t_pport.c_str(); } bool private_auth() const { return t_private_auth; } const char *redirection() const { return t_redirection.c_str(); } @@ -367,30 +386,36 @@ bool add_chap(const char *user, const char *secret); bool add_chap_mutual(const char *user, const char *secret, const char *user2, const char *secret2); - bool add_initiator_name(std::string_view name); - bool add_initiator_portal(const char *addr); - bool add_lun(u_int id, const char *lun_name); - bool add_portal_group(const char *pg_name, const char *ag_name); + virtual bool add_initiator_name(std::string_view) { return false; } + virtual bool add_initiator_portal(const char *) { return false; } + virtual bool add_lun(u_int, const char *) { return false; } + virtual bool add_portal_group(const char *pg_name, + const char *ag_name) = 0; bool set_alias(std::string_view alias); bool set_auth_group(const char *ag_name); bool set_auth_type(const char *type); bool set_physical_port(std::string_view pport); bool set_redirection(const char *addr); - struct lun *start_lun(u_int id); + virtual struct lun *start_lun(u_int) { return nullptr; } void add_port(struct port *port); void remove_lun(struct lun *lun); void remove_port(struct port *port); void verify(); -private: +protected: bool use_private_auth(const char *keyword); + bool add_lun(u_int id, const char *lun_label, const char *lun_name); + struct lun *start_lun(u_int id, const char *lun_label, + const char *lun_name); + virtual struct portal_group *default_portal_group() = 0; struct conf *t_conf; std::array t_luns; auth_group_sp t_auth_group; std::list t_ports; std::string t_name; + std::string t_label; std::string t_alias; std::string t_redirection; /* Name of this target's physical port, if any, i.e. "isp0" */ @@ -398,6 +423,8 @@ bool t_private_auth; }; +using target_up = std::unique_ptr; + struct isns { isns(std::string_view addr, freebsd::addrinfo_up ai) : i_addr(addr), i_ai(std::move(ai)) {} @@ -528,50 +555,7 @@ std::unordered_map pports; }; -#define CONN_SESSION_TYPE_NONE 0 -#define CONN_SESSION_TYPE_DISCOVERY 1 -#define CONN_SESSION_TYPE_NORMAL 2 - -struct ctld_connection { - ctld_connection(struct portal *portal, int fd, const char *host, - const struct sockaddr *client_sa); - ~ctld_connection(); - - int session_type() const { return conn_session_type; } - - void login(); - void discovery(); - void kernel_handoff(); -private: - void login_chap(struct auth_group *ag); - void login_negotiate_key(struct pdu *request, const char *name, - const char *value, bool skipped_security, - struct keys *response_keys); - bool login_portal_redirect(struct pdu *request); - bool login_target_redirect(struct pdu *request); - void login_negotiate(struct pdu *request); - void login_wait_transition(); - - bool discovery_target_filtered_out(const struct port *port) const; - - struct connection conn; - struct portal *conn_portal = nullptr; - const struct port *conn_port = nullptr; - struct target *conn_target = nullptr; - int conn_session_type = CONN_SESSION_TYPE_NONE; - std::string conn_initiator_name; - std::string conn_initiator_addr; - std::string conn_initiator_alias; - uint8_t conn_initiator_isid[6]; - const struct sockaddr *conn_initiator_sa = nullptr; - int conn_max_recv_data_segment_limit = 0; - int conn_max_send_data_segment_limit = 0; - int conn_max_burst_limit = 0; - int conn_first_burst_limit = 0; - std::string conn_user; - struct chap *conn_chap = nullptr; -}; - +extern bool proxy_mode; extern int ctl_fd; bool parse_conf(const char *path); @@ -584,6 +568,9 @@ bool option_new(nvlist_t *nvl, const char *name, const char *value); +freebsd::addrinfo_up parse_addr_port(const char *address, + const char *def_port); + void kernel_init(void); void kernel_capsicate(void); @@ -597,7 +584,17 @@ void kernel_receive(struct pdu *pdu); #endif +bool ctl_create_port(const char *driver, + const nvlist_t *nvl, uint32_t *ctl_port); +bool ctl_remove_port(const char *driver, nvlist_t *nvl); + +portal_group_up iscsi_make_portal_group(struct conf *conf, + std::string_view name); +target_up iscsi_make_target(struct conf *conf, + std::string_view name); + void start_timer(int timeout, bool fatal = false); void stop_timer(); +bool timed_out(); #endif /* !__CTLD_HH__ */ diff --git a/usr.sbin/ctld/ctld.cc b/usr.sbin/ctld/ctld.cc --- a/usr.sbin/ctld/ctld.cc +++ b/usr.sbin/ctld/ctld.cc @@ -58,13 +58,6 @@ #include "ctld.hh" #include "isns.hh" -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; @@ -73,19 +66,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, -#else - .pdu_receive_proxy = nullptr, - .pdu_send_proxy = nullptr, -#endif - .fail = pdu_fail, -}; static void usage(void) @@ -477,8 +457,8 @@ return (it->second); } -portal_group::portal_group(struct conf *conf, std::string_view name) - : pg_conf(conf), pg_options(nvlist_create(0)), pg_name(name) +portal_group::portal_group(struct conf *conf, std::string_view name) : + pg_conf(conf), pg_options(nvlist_create(0)), pg_name(name) { } @@ -486,7 +466,7 @@ conf::add_portal_group(const char *name) { auto pair = conf_portal_groups.try_emplace(name, - std::make_unique(this, name)); + iscsi_make_portal_group(this, name)); if (!pair.second) { log_warnx("duplicated portal-group \"%s\"", name); return (nullptr); @@ -531,7 +511,7 @@ return (false); } -static freebsd::addrinfo_up +freebsd::addrinfo_up parse_addr_port(const char *address, const char *def_port) { struct addrinfo hints, *ai; @@ -598,25 +578,6 @@ return (freebsd::nvlist_up(nvlist_clone(pg_options.get()))); } -bool -portal_group::add_portal(const char *value, bool iser) -{ - freebsd::addrinfo_up ai = parse_addr_port(value, "3260"); - if (!ai) { - log_warnx("invalid listen address %s", value); - return (false); - } - - /* - * XXX: getaddrinfo(3) may return multiple addresses; we should turn - * those into multiple portals. - */ - - pg_portals.emplace_back(std::make_unique(this, value, iser, - std::move(ai))); - return (true); -} - bool portal_group::add_option(const char *name, const char *value) { @@ -627,14 +588,14 @@ portal_group::set_discovery_auth_group(const char *ag_name) { if (pg_discovery_auth_group != nullptr) { - log_warnx("discovery-auth-group for portal-group " - "\"%s\" specified more than once", name()); + log_warnx("discovery-auth-group for %s " + "\"%s\" specified more than once", keyword(), name()); return (false); } pg_discovery_auth_group = pg_conf->find_auth_group(ag_name); if (pg_discovery_auth_group == nullptr) { log_warnx("unknown discovery-auth-group \"%s\" " - "for portal-group \"%s\"", ag_name, name()); + "for %s \"%s\"", ag_name, keyword(), name()); return (false); } return (true); @@ -644,8 +605,8 @@ portal_group::set_dscp(u_int dscp) { if (dscp >= 0x40) { - log_warnx("invalid DSCP value %u for portal-group \"%s\"", - dscp, name()); + log_warnx("invalid DSCP value %u for %s \"%s\"", + dscp, keyword(), name()); return (false); } @@ -653,39 +614,6 @@ return (true); } -bool -portal_group::set_filter(const char *str) -{ - enum discovery_filter filter; - - if (strcmp(str, "none") == 0) { - filter = discovery_filter::NONE; - } else if (strcmp(str, "portal") == 0) { - filter = discovery_filter::PORTAL; - } else if (strcmp(str, "portal-name") == 0) { - filter = discovery_filter::PORTAL_NAME; - } else if (strcmp(str, "portal-name-auth") == 0) { - filter = discovery_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, name()); - return (false); - } - - if (pg_discovery_filter != discovery_filter::UNKNOWN && - pg_discovery_filter != filter) { - log_warnx("cannot set discovery-filter to \"%s\" for " - "portal-group \"%s\"; already has a different " - "value", str, name()); - return (false); - } - - pg_discovery_filter = filter; - return (true); -} - void portal_group::set_foreign() { @@ -697,8 +625,8 @@ { if (!pg_offload.empty()) { log_warnx("cannot set offload to \"%s\" for " - "portal-group \"%s\"; already defined", - offload, name()); + "%s \"%s\"; already defined", + offload, keyword(), name()); return (false); } @@ -710,8 +638,8 @@ portal_group::set_pcp(u_int pcp) { if (pcp > 7) { - log_warnx("invalid PCP value %u for portal-group \"%s\"", - pcp, name()); + log_warnx("invalid PCP value %u for %s \"%s\"", + pcp, keyword(), name()); return (false); } @@ -724,8 +652,8 @@ { if (!pg_redirection.empty()) { log_warnx("cannot set redirection to \"%s\" for " - "portal-group \"%s\"; already defined", - addr, name()); + "%s \"%s\"; already defined", + addr, keyword(), name()); return (false); } @@ -752,16 +680,17 @@ if (!pg_redirection.empty()) { if (!pg_ports.empty()) { - log_debugx("portal-group \"%s\" assigned to target, " - "but configured for redirection", name()); + log_debugx("%s \"%s\" assigned to target, " + "but configured for redirection", keyword(), + name()); } pg_assigned = true; } else if (!pg_ports.empty()) { pg_assigned = true; } else { if (pg_name != "default") - log_warnx("portal-group \"%s\" not assigned " - "to any target", name()); + log_warnx("%s \"%s\" not assigned " + "to any target", keyword(), name()); pg_assigned = false; } } @@ -789,8 +718,8 @@ return (0); if (!pg_assigned) { - log_debugx("not listening on portal-group \"%s\", " - "not assigned to any target", name()); + log_debugx("not listening on %s \"%s\", " + "not assigned to any target", keyword(), name()); return (0); } @@ -818,8 +747,8 @@ for (portal_up &portal : pg_portals) { if (portal->socket() < 0) continue; - log_debugx("closing socket for %s, portal-group \"%s\"", - portal->listen(), name()); + log_debugx("closing socket for %s, %s \"%s\"", + portal->listen(), keyword(), name()); portal->close(); } } @@ -1111,8 +1040,8 @@ { std::string name = freebsd::stringf("%s-%s", pg->name(), target->name()); - const auto &pair = conf_ports.try_emplace(name, - std::make_unique(target, pg, ag)); + const auto &pair = conf_ports.try_emplace(name, pg->create_port(target, + ag)); if (!pair.second) { log_warnx("duplicate port \"%s\"", name.c_str()); return (false); @@ -1127,8 +1056,8 @@ { std::string name = freebsd::stringf("%s-%s", pg->name(), target->name()); - const auto &pair = conf_ports.try_emplace(name, - std::make_unique(target, pg, ctl_port)); + const auto &pair = conf_ports.try_emplace(name, pg->create_port(target, + ctl_port)); if (!pair.second) { log_warnx("duplicate port \"%s\"", name.c_str()); return (false); @@ -1184,6 +1113,12 @@ return (it->second); } +target::target(struct conf *conf, const char *keyword, std::string_view name) : + t_conf(conf), t_name(name) +{ + t_label = freebsd::stringf("%s \"%s\"", keyword, t_name.c_str()); +} + struct target * conf::add_target(const char *name) { @@ -1198,7 +1133,7 @@ c = tolower(c); auto const &pair = conf_targets.try_emplace(t_name, - std::make_unique(this, t_name)); + iscsi_make_target(this, t_name)); if (!pair.second) { log_warnx("duplicated target \"%s\"", name); return (NULL); @@ -1225,13 +1160,12 @@ return (true); if (t_auth_group != nullptr) { - log_warnx("cannot use both auth-group and %s for target \"%s\"", - keyword, name()); + log_warnx("cannot use both auth-group and %s for %s", + keyword, label()); return (false); } - std::string label = freebsd::stringf("target \"%s\"", name()); - t_auth_group = std::make_shared(label); + t_auth_group = std::make_shared(t_label); t_private_auth = true; return (true); } @@ -1254,40 +1188,24 @@ } bool -target::add_initiator_name(std::string_view name) -{ - if (!use_private_auth("initiator-name")) - return (false); - return (t_auth_group->add_initiator_name(name)); -} - -bool -target::add_initiator_portal(const char *addr) -{ - if (!use_private_auth("initiator-portal")) - return (false); - return (t_auth_group->add_initiator_portal(addr)); -} - -bool -target::add_lun(u_int id, const char *lun_name) +target::add_lun(u_int id, const char *lun_label, const char *lun_name) { struct lun *t_lun; if (id >= MAX_LUNS) { - log_warnx("LUN %u too big for target \"%s\"", id, name()); + log_warnx("%s too big for %s", lun_label, label()); return (false); } if (t_luns[id] != NULL) { - log_warnx("duplicate LUN %u for target \"%s\"", id, name()); + log_warnx("duplicate %s for %s", lun_label, label()); return (false); } t_lun = t_conf->find_lun(lun_name); if (t_lun == NULL) { - log_warnx("unknown LUN named %s used for target \"%s\"", - lun_name, name()); + log_warnx("unknown LUN named %s used for %s", lun_name, + label()); return (false); } @@ -1295,42 +1213,11 @@ return (true); } -bool -target::add_portal_group(const char *pg_name, const char *ag_name) -{ - struct portal_group *pg; - auth_group_sp ag; - - pg = t_conf->find_portal_group(pg_name); - if (pg == NULL) { - log_warnx("unknown portal-group \"%s\" for target \"%s\"", - pg_name, name()); - return (false); - } - - if (ag_name != NULL) { - ag = t_conf->find_auth_group(ag_name); - if (ag == NULL) { - log_warnx("unknown auth-group \"%s\" for target \"%s\"", - ag_name, name()); - return (false); - } - } - - if (!t_conf->add_port(this, pg, std::move(ag))) { - log_warnx("can't link portal-group \"%s\" to target \"%s\"", - pg_name, name()); - return (false); - } - return (true); -} - bool target::set_alias(std::string_view alias) { if (has_alias()) { - log_warnx("alias for target \"%s\" specified more than once", - name()); + log_warnx("alias for %s specified more than once", label()); return (false); } t_alias = alias; @@ -1343,16 +1230,16 @@ if (t_auth_group != nullptr) { if (t_private_auth) log_warnx("cannot use both auth-group and explicit " - "authorisations for target \"%s\"", name()); + "authorisations for %s", label()); else - log_warnx("auth-group for target \"%s\" " - "specified more than once", name()); + log_warnx("auth-group for %s " + "specified more than once", label()); return (false); } t_auth_group = t_conf->find_auth_group(ag_name); if (t_auth_group == nullptr) { - log_warnx("unknown auth-group \"%s\" for target \"%s\"", - ag_name, name()); + log_warnx("unknown auth-group \"%s\" for %s", + ag_name, label()); return (false); } return (true); @@ -1383,8 +1270,8 @@ { if (!t_redirection.empty()) { log_warnx("cannot set redirection to \"%s\" for " - "target \"%s\"; already defined", - addr, name()); + "%s; already defined", + addr, label()); return (false); } @@ -1393,28 +1280,23 @@ } struct lun * -target::start_lun(u_int id) +target::start_lun(u_int id, const char *lun_label, const char *lun_name) { - struct lun *new_lun; - if (id >= MAX_LUNS) { - log_warnx("LUN %u too big for target \"%s\"", id, - name()); + log_warnx("%s too big for %s", lun_label, label()); return (nullptr); } if (t_luns[id] != NULL) { - log_warnx("duplicate LUN %u for target \"%s\"", id, - name()); + log_warnx("duplicate %s for %s", lun_label, label()); return (nullptr); } - std::string lun_name = freebsd::stringf("%s,lun,%u", name(), id); - new_lun = t_conf->add_lun(lun_name.c_str()); + struct lun *new_lun = t_conf->add_lun(lun_name); if (new_lun == nullptr) return (nullptr); - new_lun->set_scsiname(lun_name.c_str()); + new_lun->set_scsiname(lun_name); t_luns[id] = new_lun; @@ -1449,7 +1331,7 @@ assert(t_auth_group != nullptr); } if (t_ports.empty()) { - struct portal_group *pg = t_conf->find_portal_group("default"); + struct portal_group *pg = default_portal_group(); assert(pg != NULL); t_conf->add_port(this, pg, nullptr); } @@ -1457,10 +1339,10 @@ bool found = std::any_of(t_luns.begin(), t_luns.end(), [](struct lun *lun) { return (lun != nullptr); }); if (!found && t_redirection.empty()) - log_warnx("no LUNs defined for target \"%s\"", name()); + log_warnx("no LUNs defined for %s", label()); if (found && !t_redirection.empty()) - log_debugx("target \"%s\" contains luns, but configured " - "for redirection", name()); + log_debugx("%s contains LUNs, but configured " + "for redirection", label()); } lun::lun(struct conf *conf, std::string_view name) @@ -1714,59 +1596,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) -{ -} - -ctld_connection::ctld_connection(struct portal *portal, int fd, - const char *host, const struct sockaddr *client_sa) : - conn_portal(portal), conn_initiator_addr(host), - conn_initiator_sa(client_sa) -{ - connection_init(&conn, &conn_ops, proxy_mode); - conn.conn_socket = fd; -} - -ctld_connection::~ctld_connection() -{ - chap_delete(conn_chap); -} - bool lun::verify() { @@ -1882,23 +1711,23 @@ struct portal_group *pg = portal_group(); struct kevent kev; freebsd::fd_up s; - int error, sockbuf; + int error; int one = 1; #ifdef ICL_KERNEL_PROXY if (proxy_mode) { int id = pg->conf()->add_proxy_portal(this); - log_debugx("listening on %s, portal-group \"%s\", " - "portal id %d, using ICL proxy", listen(), pg->pg_name, - id); - kernel_listen(ai(), p_iser, id); + log_debugx("listening on %s, %s \"%s\", " + "portal id %d, using ICL proxy", listen(), pg->keyword(), + pg->name(), id); + kernel_listen(ai(), protocol() == ISER, id); return (true); } #endif assert(proxy_mode == false); - assert(p_iser == false); + assert(protocol() != portal_protocol::ISER); - log_debugx("listening on %s, portal-group \"%s\"", listen(), + log_debugx("listening on %s, %s \"%s\"", listen(), pg->keyword(), pg->name()); s = ::socket(p_ai->ai_family, p_ai->ai_socktype, p_ai->ai_protocol); if (!s) { @@ -1906,14 +1735,6 @@ return (false); } - sockbuf = SOCKBUF_SIZE; - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbuf, - sizeof(sockbuf)) == -1) - log_warn("setsockopt(SO_RCVBUF) failed for %s", listen()); - sockbuf = SOCKBUF_SIZE; - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbuf, - sizeof(sockbuf)) == -1) - log_warn("setsockopt(SO_SNDBUF) failed for %s", listen()); if (setsockopt(s, SOL_SOCKET, SO_NO_DDP, &one, sizeof(one)) == -1) log_warn("setsockopt(SO_NO_DDP) failed for %s", listen()); @@ -1960,6 +1781,9 @@ } } + if (!init_socket_options(s)) + return (false); + error = bind(s, p_ai->ai_addr, p_ai->ai_addrlen); if (error != 0) { log_warn("bind(2) failed for %s", listen()); @@ -2038,7 +1862,7 @@ if (it != oldconf->conf_portal_groups.end()) newpg.set_tag(it->second->tag()); else - newpg.set_tag(++last_portal_group_tag); + newpg.allocate_tag(); } /* Deregister on removed iSNS servers. */ @@ -2225,7 +2049,7 @@ return (cumulated_error); } -static bool +bool timed_out(void) { @@ -2390,17 +2214,7 @@ log_set_peer_addr(host); setproctitle("%s", host); - ctld_connection conn(portal, fd, host, client_sa); - start_timer(conf->timeout(), true); - kernel_capsicate(); - conn.login(); - if (conn.session_type() == CONN_SESSION_TYPE_NORMAL) { - conn.kernel_handoff(); - log_debugx("connection handed off to the kernel"); - } else { - assert(conn.session_type() == CONN_SESSION_TYPE_DISCOVERY); - conn.discovery(); - } + portal->handle_connection(fd, host, client_sa); log_debugx("nothing more to do; exiting"); exit(0); } @@ -2612,8 +2426,7 @@ "going with defaults"); pg = conf->find_portal_group("default"); assert(pg != NULL); - pg->add_portal("0.0.0.0", false); - pg->add_portal("[::]", false); + pg->add_default_portals(); } if (!conf->verify()) { @@ -2644,7 +2457,7 @@ if (ret > 0) { if (!add_port(kports, targ, i_pp, i_vp)) { log_warnx("can't create new ioctl port " - "for target \"%s\"", targ->name()); + "for %s", targ->label()); return (false); } @@ -2653,19 +2466,19 @@ pp = kports.find_port(targ->pport()); if (pp == NULL) { - log_warnx("unknown port \"%s\" for target \"%s\"", - targ->pport(), targ->name()); + log_warnx("unknown port \"%s\" for %s", + targ->pport(), targ->label()); return (false); } if (pp->linked()) { - log_warnx("can't link port \"%s\" to target \"%s\", " + log_warnx("can't link port \"%s\" to %s, " "port already linked to some target", - targ->pport(), targ->name()); + targ->pport(), targ->label()); return (false); } if (!add_port(targ, pp)) { - log_warnx("can't link port \"%s\" to target \"%s\"", - targ->pport(), targ->name()); + log_warnx("can't link port \"%s\" to %s", + targ->pport(), targ->label()); return (false); } } diff --git a/usr.sbin/ctld/discovery.cc b/usr.sbin/ctld/discovery.cc --- a/usr.sbin/ctld/discovery.cc +++ b/usr.sbin/ctld/discovery.cc @@ -39,6 +39,7 @@ #include #include "ctld.hh" +#include "iscsi.hh" #include "iscsi_proto.h" static struct pdu * @@ -145,7 +146,7 @@ } bool -ctld_connection::discovery_target_filtered_out(const struct port *port) const +iscsi_connection::discovery_target_filtered_out(const struct port *port) const { const struct auth_group *ag; const struct portal_group *pg; @@ -208,7 +209,7 @@ } void -ctld_connection::discovery() +iscsi_connection::discovery() { struct pdu *request, *response; struct keys *request_keys, *response_keys; diff --git a/usr.sbin/ctld/iscsi.hh b/usr.sbin/ctld/iscsi.hh new file mode 100644 --- /dev/null +++ b/usr.sbin/ctld/iscsi.hh @@ -0,0 +1,78 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2012 The FreeBSD Foundation + * + * 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. + */ + +#ifndef __ISCSI_HH__ +#define __ISCSI_HH__ + +#define CONN_SESSION_TYPE_NONE 0 +#define CONN_SESSION_TYPE_DISCOVERY 1 +#define CONN_SESSION_TYPE_NORMAL 2 + +struct iscsi_connection { + iscsi_connection(struct portal *portal, int fd, const char *host, + const struct sockaddr *client_sa); + ~iscsi_connection(); + + void handle(); +private: + void login(); + void login_chap(struct auth_group *ag); + void login_negotiate_key(struct pdu *request, const char *name, + const char *value, bool skipped_security, + struct keys *response_keys); + bool login_portal_redirect(struct pdu *request); + bool login_target_redirect(struct pdu *request); + void login_negotiate(struct pdu *request); + void login_wait_transition(); + + void discovery(); + bool discovery_target_filtered_out(const struct port *port) const; + + void kernel_handoff(); + + struct connection conn; + struct portal *conn_portal = nullptr; + const struct port *conn_port = nullptr; + struct target *conn_target = nullptr; + int conn_session_type = CONN_SESSION_TYPE_NONE; + std::string conn_initiator_name; + std::string conn_initiator_addr; + std::string conn_initiator_alias; + uint8_t conn_initiator_isid[6]; + const struct sockaddr *conn_initiator_sa = nullptr; + int conn_max_recv_data_segment_limit = 0; + int conn_max_send_data_segment_limit = 0; + int conn_max_burst_limit = 0; + int conn_first_burst_limit = 0; + std::string conn_user; + struct chap *conn_chap = nullptr; +}; + +#endif /* !__ISCSI_HH__ */ diff --git a/usr.sbin/ctld/iscsi.cc b/usr.sbin/ctld/iscsi.cc new file mode 100644 --- /dev/null +++ b/usr.sbin/ctld/iscsi.cc @@ -0,0 +1,508 @@ +/*- + * 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 "ctld.hh" +#include "iscsi.hh" + +#define SOCKBUF_SIZE 1048576 + +struct iscsi_portal final : public portal { + iscsi_portal(struct portal_group *pg, const char *listen, + portal_protocol protocol, freebsd::addrinfo_up ai) : + portal(pg, listen, protocol, std::move(ai)) {} + + bool init_socket_options(int s) override; + void handle_connection(int fd, const char *host, + const struct sockaddr *client_sa) override; +}; + +struct iscsi_portal_group final : public portal_group { + iscsi_portal_group(struct conf *conf, std::string_view name) : + portal_group(conf, name) {} + + const char *keyword() const override + { return "portal-group"; } + + void allocate_tag() override; + bool add_portal(const char *value, portal_protocol protocol) + override; + void add_default_portals() override; + bool set_filter(const char *str) override; + + virtual port_up create_port(struct target *target, auth_group_sp ag) + override; + virtual port_up create_port(struct target *target, uint32_t ctl_port) + override; +private: + static uint16_t last_portal_group_tag; +}; + +struct iscsi_port final : public portal_group_port { + iscsi_port(struct target *target, struct portal_group *pg, + auth_group_sp ag) : + portal_group_port(target, pg, ag) {} + iscsi_port(struct target *target, struct portal_group *pg, + uint32_t ctl_port) : + portal_group_port(target, pg, ctl_port) {} + + bool kernel_create_port() override; + bool kernel_remove_port() override; + +private: + static bool module_loaded; + static void load_kernel_module(); +}; + +struct iscsi_target final : public target { + iscsi_target(struct conf *conf, std::string_view name) : + target(conf, "target", name) {} + + bool add_initiator_name(std::string_view name) override; + bool add_initiator_portal(const char *addr) override; + bool add_lun(u_int id, const char *lun_name) override; + bool add_portal_group(const char *pg_name, const char *ag_name) + override; + struct lun *start_lun(u_int id) override; + +protected: + struct portal_group *default_portal_group() override; +}; + +#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); + +uint16_t iscsi_portal_group::last_portal_group_tag = 0xff; +bool iscsi_port::module_loaded = false; + +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, +#else + .pdu_receive_proxy = nullptr, + .pdu_send_proxy = nullptr, +#endif + .fail = pdu_fail, +}; + +portal_group_up +iscsi_make_portal_group(struct conf *conf, std::string_view name) +{ + return std::make_unique(conf, name); +} + +target_up +iscsi_make_target(struct conf *conf, std::string_view name) +{ + return std::make_unique(conf, name); +} + +void +iscsi_portal_group::allocate_tag() +{ + set_tag(++last_portal_group_tag); +} + +bool +iscsi_portal_group::add_portal(const char *value, portal_protocol protocol) +{ + switch (protocol) { + case portal_protocol::ISCSI: + case portal_protocol::ISER: + break; + default: + log_warnx("unsupported portal protocol for %s", value); + return (false); + } + + freebsd::addrinfo_up ai = parse_addr_port(value, "3260"); + if (!ai) { + log_warnx("invalid listen address %s", value); + return (false); + } + + /* + * XXX: getaddrinfo(3) may return multiple addresses; we should turn + * those into multiple portals. + */ + + pg_portals.emplace_back(std::make_unique(this, value, + protocol, std::move(ai))); + return (true); +} + +void +iscsi_portal_group::add_default_portals() +{ + add_portal("0.0.0.0", portal_protocol::ISCSI); + add_portal("[::]", portal_protocol::ISCSI); +} + +bool +iscsi_portal_group::set_filter(const char *str) +{ + enum discovery_filter filter; + + if (strcmp(str, "none") == 0) { + filter = discovery_filter::NONE; + } else if (strcmp(str, "portal") == 0) { + filter = discovery_filter::PORTAL; + } else if (strcmp(str, "portal-name") == 0) { + filter = discovery_filter::PORTAL_NAME; + } else if (strcmp(str, "portal-name-auth") == 0) { + filter = discovery_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, name()); + return (false); + } + + if (pg_discovery_filter != discovery_filter::UNKNOWN && + pg_discovery_filter != filter) { + log_warnx("cannot set discovery-filter to \"%s\" for " + "portal-group \"%s\"; already has a different " + "value", str, name()); + return (false); + } + + pg_discovery_filter = filter; + return (true); +} + +port_up +iscsi_portal_group::create_port(struct target *target, auth_group_sp ag) +{ + return std::make_unique(target, this, ag); +} + +port_up +iscsi_portal_group::create_port(struct target *target, uint32_t ctl_port) +{ + return std::make_unique(target, this, ctl_port); +} + +void +iscsi_port::load_kernel_module() +{ + int saved_errno; + + if (module_loaded) + return; + + saved_errno = errno; + if (modfind("cfiscsi") == -1 && kldload("cfiscsi") == -1) + log_warn("couldn't load cfiscsi"); + errno = saved_errno; + module_loaded = true; +} + +bool +iscsi_port::kernel_create_port() +{ + struct portal_group *pg = p_portal_group; + struct target *targ = p_target; + + load_kernel_module(); + + freebsd::nvlist_up nvl = pg->options(); + nvlist_add_string(nvl.get(), "cfiscsi_target", targ->name()); + nvlist_add_string(nvl.get(), "ctld_portal_group_name", pg->name()); + nvlist_add_stringf(nvl.get(), "cfiscsi_portal_group_tag", "%u", + pg->tag()); + + if (targ->has_alias()) { + nvlist_add_string(nvl.get(), "cfiscsi_target_alias", + targ->alias()); + } + + return (ctl_create_port("iscsi", nvl.get(), &p_ctl_port)); +} + +bool +iscsi_port::kernel_remove_port() +{ + freebsd::nvlist_up nvl(nvlist_create(0)); + nvlist_add_string(nvl.get(), "cfiscsi_target", p_target->name()); + nvlist_add_stringf(nvl.get(), "cfiscsi_portal_group_tag", "%u", + p_portal_group->tag()); + + return (ctl_remove_port("iscsi", nvl.get())); +} + +bool +iscsi_portal::init_socket_options(int s) +{ + int sockbuf; + + sockbuf = SOCKBUF_SIZE; + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbuf, + sizeof(sockbuf)) == -1) { + log_warn("setsockopt(SO_RCVBUF) failed for %s", listen()); + return (false); + } + sockbuf = SOCKBUF_SIZE; + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbuf, + sizeof(sockbuf)) == -1) { + log_warn("setsockopt(SO_SNDBUF) failed for %s", listen()); + return (false); + } + return (true); +} + +bool +iscsi_target::add_initiator_name(std::string_view name) +{ + if (!use_private_auth("initiator-name")) + return (false); + return (t_auth_group->add_initiator_name(name)); +} + +bool +iscsi_target::add_initiator_portal(const char *addr) +{ + if (!use_private_auth("initiator-portal")) + return (false); + return (t_auth_group->add_initiator_portal(addr)); +} + +bool +iscsi_target::add_lun(u_int id, const char *lun_name) +{ + std::string lun_label = "LUN " + std::to_string(id); + return target::add_lun(id, lun_label.c_str(), lun_name); +} + +bool +iscsi_target::add_portal_group(const char *pg_name, const char *ag_name) +{ + struct portal_group *pg; + auth_group_sp ag; + + pg = t_conf->find_portal_group(pg_name); + if (pg == NULL) { + log_warnx("unknown portal-group \"%s\" for %s", pg_name, + label()); + return (false); + } + + if (ag_name != NULL) { + ag = t_conf->find_auth_group(ag_name); + if (ag == NULL) { + log_warnx("unknown auth-group \"%s\" for %s", ag_name, + label()); + return (false); + } + } + + if (!t_conf->add_port(this, pg, std::move(ag))) { + log_warnx("can't link portal-group \"%s\" to %s", pg_name, + label()); + return (false); + } + return (true); +} + +struct lun * +iscsi_target::start_lun(u_int id) +{ + std::string lun_label = "LUN " + std::to_string(id); + std::string lun_name = freebsd::stringf("%s,lun,%u", name(), id); + return target::start_lun(id, lun_label.c_str(), lun_name.c_str()); +} + +struct portal_group * +iscsi_target::default_portal_group() +{ + return t_conf->find_portal_group("default"); +} + +#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) +{ +} + +iscsi_connection::iscsi_connection(struct portal *portal, int fd, + const char *host, const struct sockaddr *client_sa) : + conn_portal(portal), conn_initiator_addr(host), + conn_initiator_sa(client_sa) +{ + connection_init(&conn, &conn_ops, proxy_mode); + conn.conn_socket = fd; +} + +iscsi_connection::~iscsi_connection() +{ + chap_delete(conn_chap); +} + +void +iscsi_connection::kernel_handoff() +{ + struct portal_group *pg = conn_portal->portal_group(); + struct ctl_iscsi req; + + bzero(&req, sizeof(req)); + + req.type = CTL_ISCSI_HANDOFF; + strlcpy(req.data.handoff.initiator_name, conn_initiator_name.c_str(), + sizeof(req.data.handoff.initiator_name)); + strlcpy(req.data.handoff.initiator_addr, conn_initiator_addr.c_str(), + sizeof(req.data.handoff.initiator_addr)); + if (!conn_initiator_alias.empty()) { + strlcpy(req.data.handoff.initiator_alias, + conn_initiator_alias.c_str(), + sizeof(req.data.handoff.initiator_alias)); + } + memcpy(req.data.handoff.initiator_isid, conn_initiator_isid, + sizeof(req.data.handoff.initiator_isid)); + strlcpy(req.data.handoff.target_name, conn_target->name(), + sizeof(req.data.handoff.target_name)); + strlcpy(req.data.handoff.offload, pg->offload(), + sizeof(req.data.handoff.offload)); +#ifdef ICL_KERNEL_PROXY + if (proxy_mode) + req.data.handoff.connection_id = conn.conn_socket; + else + req.data.handoff.socket = conn.conn_socket; +#else + req.data.handoff.socket = conn.conn_socket; +#endif + req.data.handoff.portal_group_tag = pg->tag(); + if (conn.conn_header_digest == CONN_DIGEST_CRC32C) + req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; + if (conn.conn_data_digest == CONN_DIGEST_CRC32C) + req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; + req.data.handoff.cmdsn = conn.conn_cmdsn; + req.data.handoff.statsn = conn.conn_statsn; + req.data.handoff.max_recv_data_segment_length = + conn.conn_max_recv_data_segment_length; + req.data.handoff.max_send_data_segment_length = + conn.conn_max_send_data_segment_length; + req.data.handoff.max_burst_length = conn.conn_max_burst_length; + req.data.handoff.first_burst_length = conn.conn_first_burst_length; + req.data.handoff.immediate_data = 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); + } +} + +void +iscsi_connection::handle() +{ + login(); + if (conn_session_type == CONN_SESSION_TYPE_NORMAL) { + kernel_handoff(); + log_debugx("connection handed off to the kernel"); + } else { + assert(conn_session_type == CONN_SESSION_TYPE_DISCOVERY); + discovery(); + } +} + +void +iscsi_portal::handle_connection(int fd, const char *host, + const struct sockaddr *client_sa) +{ + struct conf *conf = portal_group()->conf(); + + iscsi_connection conn(this, fd, host, client_sa); + start_timer(conf->timeout(), true); + kernel_capsicate(); + conn.handle(); +} diff --git a/usr.sbin/ctld/kernel.cc b/usr.sbin/ctld/kernel.cc --- a/usr.sbin/ctld/kernel.cc +++ b/usr.sbin/ctld/kernel.cc @@ -75,8 +75,6 @@ #define NVLIST_BUFSIZE 1024 -extern bool proxy_mode; - int ctl_fd = 0; void @@ -432,6 +430,56 @@ return (true); } +void +add_iscsi_port(struct kports &kports, struct conf *conf, + const struct cctl_port &port, std::string &name) +{ + if (port.cfiscsi_target.empty()) { + log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", + port.port_id, name.c_str()); + if (!kports.has_port(name)) { + if (!kports.add_port(name, port.port_id)) { + log_warnx("kports::add_port failed"); + return; + } + } + return; + } + if (port.cfiscsi_state != 1) { + log_debugx("CTL port %ju is not active (%d); ignoring", + (uintmax_t)port.port_id, port.cfiscsi_state); + return; + } + + const char *t_name = port.cfiscsi_target.c_str(); + struct target *targ = conf->find_target(t_name); + if (targ == nullptr) { + targ = conf->add_target(t_name); + if (targ == nullptr) { + log_warnx("Failed to add target \"%s\"", t_name); + return; + } + } + + if (port.ctld_portal_group_name.empty()) + return; + + const char *pg_name = port.ctld_portal_group_name.c_str(); + struct portal_group *pg = conf->find_portal_group(pg_name); + if (pg == nullptr) { + pg = conf->add_portal_group(pg_name); + if (pg == nullptr) { + log_warnx("Failed to add portal_group \"%s\"", pg_name); + return; + } + } + pg->set_tag(port.cfiscsi_portal_group_tag); + if (!conf->add_port(targ, pg, port.port_id)) { + log_warnx("Failed to add port for target \"%s\" and portal-group \"%s\"", + t_name, pg_name); + } +} + conf_up conf_new_from_kernel(struct kports &kports) { @@ -455,51 +503,11 @@ name += "/" + std::to_string(port.vp); } - if (port.cfiscsi_target.empty()) { - log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", - port.port_id, name.c_str()); - if (!kports.has_port(name)) { - if (!kports.add_port(name, port.port_id)) { - log_warnx("kports::add_port failed"); - continue; - } - } - continue; - } - if (port.cfiscsi_state != 1) { - log_debugx("CTL port %ju is not active (%d); ignoring", - (uintmax_t)port.port_id, port.cfiscsi_state); - continue; - } - - const char *t_name = port.cfiscsi_target.c_str(); - struct target *targ = conf->find_target(t_name); - if (targ == NULL) { - targ = conf->add_target(t_name); - if (targ == NULL) { - log_warnx("Failed to add target \"%s\"", - t_name); - continue; - } - } - - if (port.ctld_portal_group_name.empty()) - continue; - const char *pg_name = port.ctld_portal_group_name.c_str(); - struct portal_group *pg = conf->find_portal_group(pg_name); - if (pg == NULL) { - pg = conf->add_portal_group(pg_name); - if (pg == NULL) { - log_warnx("Failed to add portal_group \"%s\"", - pg_name); - continue; - } - } - pg->set_tag(port.cfiscsi_portal_group_tag); - if (!conf->add_port(targ, pg, port.port_id)) { - log_warnx("Failed to add port for target \"%s\" and portal-group \"%s\"", - t_name, pg_name); - continue; + if (port.port_frontend == "iscsi") { + add_iscsi_port(kports, conf.get(), port, name); + } else { + /* XXX: Treat all unknown ports as iSCSI? */ + add_iscsi_port(kports, conf.get(), port, name); } } @@ -705,65 +713,7 @@ return (true); } -void -ctld_connection::kernel_handoff() -{ - struct portal_group *pg = conn_portal->portal_group(); - struct ctl_iscsi req; - - bzero(&req, sizeof(req)); - - req.type = CTL_ISCSI_HANDOFF; - strlcpy(req.data.handoff.initiator_name, conn_initiator_name.c_str(), - sizeof(req.data.handoff.initiator_name)); - strlcpy(req.data.handoff.initiator_addr, conn_initiator_addr.c_str(), - sizeof(req.data.handoff.initiator_addr)); - if (!conn_initiator_alias.empty()) { - strlcpy(req.data.handoff.initiator_alias, - conn_initiator_alias.c_str(), - sizeof(req.data.handoff.initiator_alias)); - } - memcpy(req.data.handoff.initiator_isid, conn_initiator_isid, - sizeof(req.data.handoff.initiator_isid)); - strlcpy(req.data.handoff.target_name, conn_target->name(), - sizeof(req.data.handoff.target_name)); - strlcpy(req.data.handoff.offload, pg->offload(), - sizeof(req.data.handoff.offload)); -#ifdef ICL_KERNEL_PROXY - if (proxy_mode) - req.data.handoff.connection_id = conn.conn_socket; - else - req.data.handoff.socket = conn.conn_socket; -#else - req.data.handoff.socket = conn.conn_socket; -#endif - req.data.handoff.portal_group_tag = pg->tag(); - if (conn.conn_header_digest == CONN_DIGEST_CRC32C) - req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; - if (conn.conn_data_digest == CONN_DIGEST_CRC32C) - req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; - req.data.handoff.cmdsn = conn.conn_cmdsn; - req.data.handoff.statsn = conn.conn_statsn; - req.data.handoff.max_recv_data_segment_length = - conn.conn_max_recv_data_segment_length; - req.data.handoff.max_send_data_segment_length = - conn.conn_max_send_data_segment_length; - req.data.handoff.max_burst_length = conn.conn_max_burst_length; - req.data.handoff.first_burst_length = conn.conn_first_burst_length; - req.data.handoff.immediate_data = 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 bool +bool ctl_create_port(const char *driver, const nvlist_t *nvl, uint32_t *ctl_port) { struct ctl_req req; @@ -811,26 +761,6 @@ return (true); } -bool -portal_group_port::kernel_create_port() -{ - struct portal_group *pg = p_portal_group; - struct target *targ = p_target; - - freebsd::nvlist_up nvl = pg->options(); - nvlist_add_string(nvl.get(), "cfiscsi_target", targ->name()); - nvlist_add_string(nvl.get(), "ctld_portal_group_name", pg->name()); - nvlist_add_stringf(nvl.get(), "cfiscsi_portal_group_tag", "%u", - pg->tag()); - - if (targ->has_alias()) { - nvlist_add_string(nvl.get(), "cfiscsi_target_alias", - targ->alias()); - } - - return (ctl_create_port("iscsi", nvl.get(), &p_ctl_port)); -} - bool ioctl_port::kernel_create_port() { @@ -970,17 +900,6 @@ return (true); } -bool -portal_group_port::kernel_remove_port() -{ - freebsd::nvlist_up nvl(nvlist_create(0)); - nvlist_add_string(nvl.get(), "cfiscsi_target", p_target->name()); - nvlist_add_stringf(nvl.get(), "cfiscsi_portal_group_tag", "%u", - p_portal_group->tag()); - - return (ctl_remove_port("iscsi", nvl.get())); -} - bool ioctl_port::kernel_remove_port() { diff --git a/usr.sbin/ctld/login.cc b/usr.sbin/ctld/login.cc --- a/usr.sbin/ctld/login.cc +++ b/usr.sbin/ctld/login.cc @@ -42,6 +42,7 @@ #include #include "ctld.hh" +#include "iscsi.hh" #include "iscsi_proto.h" #define MAX_DATA_SEGMENT_LENGTH (128 * 1024) @@ -455,7 +456,7 @@ } void -ctld_connection::login_chap(struct auth_group *ag) +iscsi_connection::login_chap(struct auth_group *ag) { std::string user; const struct auth *auth; @@ -503,7 +504,7 @@ } void -ctld_connection::login_negotiate_key(struct pdu *request, const char *name, +iscsi_connection::login_negotiate_key(struct pdu *request, const char *name, const char *value, bool skipped_security, struct keys *response_keys) { int which; @@ -694,7 +695,7 @@ } bool -ctld_connection::login_portal_redirect(struct pdu *request) +iscsi_connection::login_portal_redirect(struct pdu *request) { const struct portal_group *pg; @@ -710,7 +711,7 @@ } bool -ctld_connection::login_target_redirect(struct pdu *request) +iscsi_connection::login_target_redirect(struct pdu *request) { const char *target_address; @@ -731,7 +732,7 @@ } void -ctld_connection::login_negotiate(struct pdu *request) +iscsi_connection::login_negotiate(struct pdu *request) { struct portal_group *pg = conn_portal->portal_group(); struct pdu *response; @@ -860,7 +861,7 @@ } void -ctld_connection::login_wait_transition() +iscsi_connection::login_wait_transition() { struct pdu *request, *response; struct iscsi_bhs_login_request *bhslr; @@ -884,7 +885,7 @@ } void -ctld_connection::login() +iscsi_connection::login() { struct pdu *request, *response; struct iscsi_bhs_login_request *bhslr;