Page MenuHomeFreeBSD

D48772.id159895.diff
No OneTemporary

D48772.id159895.diff

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 <bsd.prog.mk>
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<auth_group>;
+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<portal>;
+using port_up = std::unique_ptr<port>;
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<std::string, port *> &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<struct lun *, MAX_LUNS> t_luns;
auth_group_sp t_auth_group;
std::list<port *> 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<target>;
+
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<std::string, struct pport> 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<portal_group>(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<portal>(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<portal_group_port>(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<portal_group_port>(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<target>(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<struct auth_group>(label);
+ t_auth_group = std::make_shared<struct auth_group>(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 <sys/socket.h>
#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 <jceel@FreeBSD.org>
+ * 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 <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <assert.h>
+#include <libiscsiutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cam/ctl/ctl.h>
+#include <cam/ctl/ctl_io.h>
+#include <cam/ctl/ctl_ioctl.h>
+
+#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<iscsi_portal_group>(conf, name);
+}
+
+target_up
+iscsi_make_target(struct conf *conf, std::string_view name)
+{
+ return std::make_unique<iscsi_target>(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<iscsi_portal>(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<iscsi_port>(target, this, ag);
+}
+
+port_up
+iscsi_portal_group::create_port(struct target *target, uint32_t ctl_port)
+{
+ return std::make_unique<iscsi_port>(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 <cam/ctl/ctl_ioctl.h>
#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;

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 16, 1:34 PM (15 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31565265
Default Alt Text
D48772.id159895.diff (53 KB)

Event Timeline