Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152537228
D48772.id159895.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
53 KB
Referenced Files
None
Subscribers
None
D48772.id159895.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D48772: ctld: Add abstractions to support multiple target protocols
Attached
Detach File
Event Timeline
Log In to Comment