1
0
mirror of https://git.FreeBSD.org/src.git synced 2026-06-02 11:24:32 +00:00

ctld: Convert struct port to a hierarchy of C++ classes

The existing C struct port was used to describe three types of ports:
iSCSI ports associated with a portal_group, ioctl ports, and
"physical" ports associated with a kernel device.  This change chooses
to split these out into separate sub-classes of an abstract port base
class.  Virtual methods are used in a few places such as sending the
class-specific CTL ioctls for creating and removing CTL kernel ports.

For ownership purposes, a struct conf instance "owns" each port via a
std::unique_ptr<> in a std::unordered_map<> indexed by name.  Other
objects such as targets and portal_groups can also contain collections
of ports (targets hold a std::list of pointers, portal groups hold a
std::unordered_map<> indexed by target names).  One
not-so-straightforward case is that if a new port fails to register,
it is removed from the configuration.  In that case, these other
references also have to be removed explicitly.

Sponsored by:	Chelsio Communications
Pull Request:	https://github.com/freebsd/freebsd-src/pull/1794
This commit is contained in:
John Baldwin
2025-08-04 15:38:07 -04:00
parent 4b1aac9314
commit 6acc7afa34
6 changed files with 450 additions and 401 deletions
+1 -4
View File
@@ -571,7 +571,6 @@ target_add_portal_group(const char *pg_name, const char *ag_name)
{
struct portal_group *pg;
auth_group_sp ag;
struct port *p;
pg = portal_group_find(conf, pg_name);
if (pg == NULL) {
@@ -589,13 +588,11 @@ target_add_portal_group(const char *pg_name, const char *ag_name)
}
}
p = port_new(conf, target, pg);
if (p == NULL) {
if (!port_new(conf, target, pg, std::move(ag))) {
log_warnx("can't link portal-group \"%s\" to target \"%s\"",
pg_name, target->t_name);
return (false);
}
p->p_auth_group = std::move(ag);
return (true);
}
+163 -189
View File
@@ -103,7 +103,6 @@ conf_new(void)
conf = new struct conf();
TAILQ_INIT(&conf->conf_luns);
TAILQ_INIT(&conf->conf_targets);
TAILQ_INIT(&conf->conf_ports);
TAILQ_INIT(&conf->conf_portal_groups);
TAILQ_INIT(&conf->conf_isns);
@@ -134,7 +133,6 @@ conf_delete(struct conf *conf)
portal_group_delete(pg);
TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp)
isns_delete(is);
assert(TAILQ_EMPTY(&conf->conf_ports));
free(conf->conf_pidfile_path);
delete conf;
}
@@ -455,7 +453,6 @@ portal_group_new(struct conf *conf, const char *name)
pg = new portal_group();
pg->pg_name = checked_strdup(name);
pg->pg_options = nvlist_create(0);
TAILQ_INIT(&pg->pg_ports);
pg->pg_conf = conf;
pg->pg_tag = 0; /* Assigned later in conf_apply(). */
pg->pg_dscp = -1;
@@ -468,10 +465,6 @@ portal_group_new(struct conf *conf, const char *name)
void
portal_group_delete(struct portal_group *pg)
{
struct port *port, *tport;
TAILQ_FOREACH_SAFE(port, &pg->pg_ports, p_pgs, tport)
port_delete(port);
TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next);
nvlist_destroy(pg->pg_options);
@@ -625,7 +618,6 @@ isns_do_register(struct isns *isns, int s, const char *hostname)
struct conf *conf = isns->i_conf;
struct target *target;
struct portal_group *pg;
struct port *port;
uint32_t error;
isns_req req(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT);
@@ -647,8 +639,9 @@ isns_do_register(struct isns *isns, int s, const char *hostname)
req.add_32(33, 1); /* 1 -- Target*/
if (target->t_alias != NULL)
req.add_str(34, target->t_alias);
TAILQ_FOREACH(port, &target->t_ports, p_ts) {
if ((pg = port->p_portal_group) == NULL)
for (const port *port : target->t_ports) {
pg = port->portal_group();
if (pg == nullptr)
continue;
req.add_32(51, pg->pg_tag);
for (const portal_up &portal : pg->pg_portals) {
@@ -801,12 +794,6 @@ isns_deregister(struct isns *isns)
set_timeout(0, false);
}
pport::~pport()
{
if (pp_port != nullptr)
port_delete(pp_port);
}
bool
kports::add_port(const char *name, uint32_t ctl_port)
{
@@ -834,151 +821,129 @@ kports::find_port(std::string_view name)
return (&it->second);
}
struct port *
port_new(struct conf *conf, struct target *target, struct portal_group *pg)
port::port(struct target *target) :
p_target(target)
{
struct port *port;
char *name;
int ret;
ret = asprintf(&name, "%s-%s", pg->pg_name, target->t_name);
if (ret <= 0)
log_err(1, "asprintf");
if (port_find(conf, name) != NULL) {
log_warnx("duplicate port \"%s\"", name);
free(name);
return (NULL);
}
port = new struct port();
port->p_conf = conf;
port->p_name = name;
TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next);
TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts);
port->p_target = target;
TAILQ_INSERT_TAIL(&pg->pg_ports, port, p_pgs);
port->p_portal_group = pg;
return (port);
target->t_ports.push_back(this);
}
struct port *
void
port::clear_references()
{
p_target->t_ports.remove(this);
}
portal_group_port::portal_group_port(struct target *target,
struct portal_group *pg, auth_group_sp ag) :
port(target), p_auth_group(ag), p_portal_group(pg)
{
pg->pg_ports.emplace(target->t_name, this);
}
portal_group_port::portal_group_port(struct target *target,
struct portal_group *pg, uint32_t ctl_port) :
port(target), p_portal_group(pg)
{
p_ctl_port = ctl_port;
pg->pg_ports.emplace(target->t_name, this);
}
bool
portal_group_port::is_dummy() const
{
if (p_portal_group->pg_foreign)
return (true);
if (p_portal_group->pg_portals.empty())
return (true);
return (false);
}
void
portal_group_port::clear_references()
{
auto it = p_portal_group->pg_ports.find(p_target->t_name);
p_portal_group->pg_ports.erase(it);
port::clear_references();
}
bool
port_new(struct conf *conf, struct target *target, struct portal_group *pg,
auth_group_sp ag)
{
std::string name = freebsd::stringf("%s-%s", pg->pg_name,
target->t_name);
const auto &pair = conf->conf_ports.try_emplace(name,
std::make_unique<portal_group_port>(target, pg, ag));
if (!pair.second) {
log_warnx("duplicate port \"%s\"", name.c_str());
return (false);
}
return (true);
}
bool
port_new(struct conf *conf, struct target *target, struct portal_group *pg,
uint32_t ctl_port)
{
std::string name = freebsd::stringf("%s-%s", pg->pg_name,
target->t_name);
const auto &pair = conf->conf_ports.try_emplace(name,
std::make_unique<portal_group_port>(target, pg, ctl_port));
if (!pair.second) {
log_warnx("duplicate port \"%s\"", name.c_str());
return (false);
}
return (true);
}
static bool
port_new_pp(struct conf *conf, struct target *target, struct pport *pp)
{
std::string name = freebsd::stringf("%s-%s", pp->name(),
target->t_name);
const auto &pair = conf->conf_ports.try_emplace(name,
std::make_unique<kernel_port>(target, pp));
if (!pair.second) {
log_warnx("duplicate port \"%s\"", name.c_str());
return (false);
}
pp->link();
return (true);
}
static bool
port_new_ioctl(struct conf *conf, struct kports &kports, struct target *target,
int pp, int vp)
{
struct pport *pport;
struct port *port;
char *pname;
char *name;
int ret;
ret = asprintf(&pname, "ioctl/%d/%d", pp, vp);
if (ret <= 0) {
log_err(1, "asprintf");
return (NULL);
}
std::string pname = freebsd::stringf("ioctl/%d/%d", pp, vp);
pport = kports.find_port(pname);
if (pport != NULL) {
free(pname);
if (pport != NULL)
return (port_new_pp(conf, target, pport));
std::string name = pname + "-" + target->t_name;
const auto &pair = conf->conf_ports.try_emplace(name,
std::make_unique<ioctl_port>(target, pp, vp));
if (!pair.second) {
log_warnx("duplicate port \"%s\"", name.c_str());
return (false);
}
ret = asprintf(&name, "%s-%s", pname, target->t_name);
free(pname);
if (ret <= 0)
log_err(1, "asprintf");
if (port_find(conf, name) != NULL) {
log_warnx("duplicate port \"%s\"", name);
free(name);
return (NULL);
}
port = new struct port();
port->p_conf = conf;
port->p_name = name;
port->p_ioctl_port = true;
port->p_ioctl_pp = pp;
port->p_ioctl_vp = vp;
TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next);
TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts);
port->p_target = target;
return (port);
}
struct port *
port_new_pp(struct conf *conf, struct target *target, struct pport *pp)
{
struct port *port;
char *name;
int ret;
ret = asprintf(&name, "%s-%s", pp->name(), target->t_name);
if (ret <= 0)
log_err(1, "asprintf");
if (port_find(conf, name) != NULL) {
log_warnx("duplicate port \"%s\"", name);
free(name);
return (NULL);
}
port = new struct port();
port->p_conf = conf;
port->p_name = name;
TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next);
TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts);
port->p_target = target;
pp->link(port);
return (port);
}
struct port *
port_find(const struct conf *conf, const char *name)
{
struct port *port;
TAILQ_FOREACH(port, &conf->conf_ports, p_next) {
if (strcasecmp(port->p_name, name) == 0)
return (port);
}
return (NULL);
return (true);
}
struct port *
port_find_in_pg(const struct portal_group *pg, const char *target)
{
struct port *port;
TAILQ_FOREACH(port, &pg->pg_ports, p_pgs) {
if (strcasecmp(port->p_target->t_name, target) == 0)
return (port);
}
return (NULL);
}
void
port_delete(struct port *port)
{
if (port->p_portal_group)
TAILQ_REMOVE(&port->p_portal_group->pg_ports, port, p_pgs);
if (port->p_target)
TAILQ_REMOVE(&port->p_target->t_ports, port, p_ts);
TAILQ_REMOVE(&port->p_conf->conf_ports, port, p_next);
free(port->p_name);
free(port);
}
bool
port_is_dummy(struct port *port)
{
if (port->p_portal_group) {
if (port->p_portal_group->pg_foreign)
return (true);
if (port->p_portal_group->pg_portals.empty())
return (true);
}
return (false);
auto it = pg->pg_ports.find(target);
if (it == pg->pg_ports.end())
return (nullptr);
return (it->second);
}
struct target *
@@ -1006,7 +971,6 @@ target_new(struct conf *conf, const char *name)
targ->t_name[i] = tolower(targ->t_name[i]);
targ->t_conf = conf;
TAILQ_INIT(&targ->t_ports);
TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next);
return (targ);
@@ -1015,10 +979,6 @@ target_new(struct conf *conf, const char *name)
void
target_delete(struct target *targ)
{
struct port *port, *tport;
TAILQ_FOREACH_SAFE(port, &targ->t_ports, p_ts, tport)
port_delete(port);
TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next);
free(targ->t_pport);
@@ -1261,10 +1221,10 @@ conf_verify(struct conf *conf)
"default");
assert(targ->t_auth_group != NULL);
}
if (TAILQ_EMPTY(&targ->t_ports)) {
if (targ->t_ports.empty()) {
pg = portal_group_find(conf, "default");
assert(pg != NULL);
port_new(conf, targ, pg);
port_new(conf, targ, pg, nullptr);
}
found = false;
for (i = 0; i < MAX_LUNS; i++) {
@@ -1293,14 +1253,14 @@ conf_verify(struct conf *conf)
pg->pg_discovery_filter = PG_FILTER_NONE;
if (pg->pg_redirection != NULL) {
if (!TAILQ_EMPTY(&pg->pg_ports)) {
if (!pg->pg_ports.empty()) {
log_debugx("portal-group \"%s\" assigned "
"to target, but configured "
"for redirection",
pg->pg_name);
}
pg->pg_unassigned = false;
} else if (!TAILQ_EMPTY(&pg->pg_ports)) {
} else if (!pg->pg_ports.empty()) {
pg->pg_unassigned = false;
} else {
if (strcmp(pg->pg_name, "default") != 0)
@@ -1453,7 +1413,6 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
{
struct lun *oldlun, *newlun, *tmplun;
struct portal_group *oldpg, *newpg;
struct port *oldport, *newport, *tmpport;
struct isns *oldns, *newns;
int changed, cumulated_error = 0, error;
@@ -1517,17 +1476,19 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
* First, remove any ports present in the old configuration
* and missing in the new one.
*/
TAILQ_FOREACH_SAFE(oldport, &oldconf->conf_ports, p_next, tmpport) {
if (port_is_dummy(oldport))
for (const auto &kv : oldconf->conf_ports) {
const std::string &name = kv.first;
port *oldport = kv.second.get();
if (oldport->is_dummy())
continue;
newport = port_find(newconf, oldport->p_name);
if (newport != NULL && !port_is_dummy(newport))
const auto it = newconf->conf_ports.find(name);
if (it != newconf->conf_ports.end() &&
!it->second->is_dummy())
continue;
log_debugx("removing port \"%s\"", oldport->p_name);
error = kernel_port_remove(oldport);
if (error != 0) {
log_warnx("failed to remove port %s",
oldport->p_name);
log_debugx("removing port \"%s\"", name.c_str());
if (!oldport->kernel_remove()) {
log_warnx("failed to remove port %s", name.c_str());
/*
* XXX: Uncomment after fixing the root cause.
*
@@ -1640,30 +1601,46 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
/*
* Now add new ports or modify existing ones.
*/
TAILQ_FOREACH_SAFE(newport, &newconf->conf_ports, p_next, tmpport) {
if (port_is_dummy(newport))
continue;
oldport = port_find(oldconf, newport->p_name);
for (auto it = newconf->conf_ports.begin();
it != newconf->conf_ports.end(); ) {
const std::string &name = it->first;
port *newport = it->second.get();
if (oldport == NULL || port_is_dummy(oldport)) {
log_debugx("adding port \"%s\"", newport->p_name);
error = kernel_port_add(newport);
} else {
log_debugx("updating port \"%s\"", newport->p_name);
newport->p_ctl_port = oldport->p_ctl_port;
error = kernel_port_update(newport, oldport);
if (newport->is_dummy()) {
it++;
continue;
}
if (error != 0) {
log_warnx("failed to %s port %s",
(oldport == NULL) ? "add" : "update",
newport->p_name);
if (oldport == NULL || port_is_dummy(oldport))
port_delete(newport);
/*
* XXX: Uncomment after fixing the root cause.
*
* cumulated_error++;
*/
const auto oldit = oldconf->conf_ports.find(name);
if (oldit == oldconf->conf_ports.end() ||
oldit->second->is_dummy()) {
log_debugx("adding port \"%s\"", name.c_str());
if (!newport->kernel_add()) {
log_warnx("failed to add port %s",
name.c_str());
/*
* XXX: Uncomment after fixing the
* root cause.
*
* cumulated_error++;
*/
/*
* conf "owns" the port, but other
* objects contain pointers to this
* port that must be removed before
* deleting the port.
*/
newport->clear_references();
it = newconf->conf_ports.erase(it);
} else
it++;
} else {
log_debugx("updating port \"%s\"", name.c_str());
if (!newport->kernel_update(oldit->second.get()))
log_warnx("failed to update port %s",
name.c_str());
it++;
}
}
@@ -2134,7 +2111,6 @@ new_pports_from_conf(struct conf *conf, struct kports &kports)
{
struct target *targ;
struct pport *pp;
struct port *tp;
int ret, i_pp, i_vp;
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
@@ -2143,8 +2119,7 @@ new_pports_from_conf(struct conf *conf, struct kports &kports)
ret = sscanf(targ->t_pport, "ioctl/%d/%d", &i_pp, &i_vp);
if (ret > 0) {
tp = port_new_ioctl(conf, kports, targ, i_pp, i_vp);
if (tp == NULL) {
if (!port_new_ioctl(conf, kports, targ, i_pp, i_vp)) {
log_warnx("can't create new ioctl port "
"for target \"%s\"", targ->t_name);
return (false);
@@ -2165,8 +2140,7 @@ new_pports_from_conf(struct conf *conf, struct kports &kports)
targ->t_pport, targ->t_name);
return (false);
}
tp = port_new_pp(conf, targ, pp);
if (tp == NULL) {
if (!port_new_pp(conf, targ, pp)) {
log_warnx("can't link port \"%s\" to target \"%s\"",
targ->t_pport, targ->t_name);
return (false);
+80 -32
View File
@@ -57,6 +57,8 @@
#define MAX_LUNS 1024
#define SOCKBUF_SIZE 1048576
struct port;
struct auth {
auth(std::string_view secret) : a_secret(secret) {}
auth(std::string_view secret, std::string_view mutual_user,
@@ -168,7 +170,7 @@ struct portal_group {
bool pg_foreign = false;
bool pg_unassigned = false;
std::list<portal_up> pg_portals;
TAILQ_HEAD(, port) pg_ports;
std::unordered_map<std::string, port *> pg_ports;
char *pg_offload = nullptr;
char *pg_redirection = nullptr;
int pg_dscp;
@@ -178,22 +180,79 @@ struct portal_group {
};
struct port {
TAILQ_ENTRY(port) p_next;
TAILQ_ENTRY(port) p_pgs;
TAILQ_ENTRY(port) p_ts;
struct conf *p_conf;
char *p_name;
auth_group_sp p_auth_group;
struct portal_group *p_portal_group = nullptr;
struct pport *p_pport = nullptr;
port(struct target *target);
virtual ~port() = default;
struct target *target() const { return p_target; }
virtual struct auth_group *auth_group() const { return nullptr; }
virtual struct portal_group *portal_group() const { return nullptr; }
virtual bool is_dummy() const { return true; }
virtual void clear_references();
bool kernel_add();
bool kernel_update(const port *oport);
bool kernel_remove();
virtual bool kernel_create_port() = 0;
virtual bool kernel_remove_port() = 0;
protected:
struct target *p_target;
bool p_ioctl_port = false;
int p_ioctl_pp = 0;
int p_ioctl_vp = 0;
uint32_t p_ctl_port = 0;
};
struct portal_group_port final : 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,
uint32_t ctl_port);
~portal_group_port() override = default;
struct auth_group *auth_group() const override
{ return p_auth_group.get(); }
struct portal_group *portal_group() const override
{ return p_portal_group; }
bool is_dummy() const override;
void clear_references() override;
bool kernel_create_port() override;
bool kernel_remove_port() override;
private:
auth_group_sp p_auth_group;
struct portal_group *p_portal_group;
};
struct ioctl_port final : public port {
ioctl_port(struct target *target, int pp, int vp) :
port(target), p_ioctl_pp(pp), p_ioctl_vp(vp) {}
~ioctl_port() override = default;
bool kernel_create_port() override;
bool kernel_remove_port() override;
private:
int p_ioctl_pp;
int p_ioctl_vp;
};
struct kernel_port final : public port {
kernel_port(struct target *target, struct pport *pp) :
port(target), p_pport(pp) {}
~kernel_port() override = default;
bool kernel_create_port() override;
bool kernel_remove_port() override;
private:
struct pport *p_pport;
};
struct lun {
TAILQ_ENTRY(lun) l_next;
struct conf *l_conf;
@@ -216,7 +275,7 @@ struct target {
struct conf *t_conf;
struct lun *t_luns[MAX_LUNS] = {};
auth_group_sp t_auth_group;
TAILQ_HEAD(, port) t_ports;
std::list<port *> t_ports;
char *t_name;
char *t_alias;
char *t_redirection;
@@ -237,7 +296,7 @@ struct conf {
TAILQ_HEAD(, lun) conf_luns;
TAILQ_HEAD(, target) conf_targets;
std::unordered_map<std::string, auth_group_sp> conf_auth_groups;
TAILQ_HEAD(, port) conf_ports;
std::unordered_map<std::string, std::unique_ptr<port>> conf_ports;
TAILQ_HEAD(, portal_group) conf_portal_groups;
TAILQ_HEAD(, isns) conf_isns;
int conf_isns_period;
@@ -264,19 +323,17 @@ private:
struct pport {
pport(std::string_view name, uint32_t ctl_port) : pp_name(name),
pp_ctl_port(ctl_port) {}
~pport();
const char *name() const { return pp_name.c_str(); }
uint32_t ctl_port() const { return pp_ctl_port; }
bool linked() const { return pp_port != nullptr; }
void link(struct port *port) { pp_port = port; }
bool linked() const { return pp_linked; }
void link() { pp_linked = true; }
private:
struct port *pp_port;
std::string pp_name;
uint32_t pp_ctl_port;
bool pp_linked;
};
struct kports {
@@ -341,18 +398,12 @@ void isns_register(struct isns *isns, struct isns *oldisns);
void isns_check(struct isns *isns);
void isns_deregister(struct isns *isns);
struct port *port_new(struct conf *conf, struct target *target,
struct portal_group *pg);
struct port *port_new_ioctl(struct conf *conf,
struct kports &kports, struct target *target,
int pp, int vp);
struct port *port_new_pp(struct conf *conf, struct target *target,
struct pport *pp);
struct port *port_find(const struct conf *conf, const char *name);
bool port_new(struct conf *conf, struct target *target,
struct portal_group *pg, auth_group_sp ag);
bool port_new(struct conf *conf, struct target *target,
struct portal_group *pg, uint32_t ctl_port);
struct port *port_find_in_pg(const struct portal_group *pg,
const char *target);
void port_delete(struct port *port);
bool port_is_dummy(struct port *port);
struct target *target_new(struct conf *conf, const char *name);
void target_delete(struct target *target);
@@ -372,9 +423,6 @@ int kernel_lun_add(struct lun *lun);
int kernel_lun_modify(struct lun *lun);
int kernel_lun_remove(struct lun *lun);
void kernel_handoff(struct ctld_connection *conn);
int kernel_port_add(struct port *port);
int kernel_port_update(struct port *port, struct port *old);
int kernel_port_remove(struct port *port);
void kernel_capsicate(void);
#ifdef ICL_KERNEL_PROXY
+13 -11
View File
@@ -101,17 +101,17 @@ logout_new_response(struct pdu *request)
static void
discovery_add_target(struct keys *response_keys, const struct target *targ)
{
struct port *port;
char *buf;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
const struct addrinfo *ai;
int ret;
keys_add(response_keys, "TargetName", targ->t_name);
TAILQ_FOREACH(port, &targ->t_ports, p_ts) {
if (port->p_portal_group == NULL)
for (const port *port : targ->t_ports) {
const struct portal_group *pg = port->portal_group();
if (pg == nullptr)
continue;
for (portal_up &portal : port->p_portal_group->pg_portals) {
for (const portal_up &portal : pg->pg_portals) {
ai = portal->ai();
ret = getnameinfo(ai->ai_addr, ai->ai_addrlen,
hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
@@ -125,13 +125,13 @@ discovery_add_target(struct keys *response_keys, const struct target *targ)
if (strcmp(hbuf, "0.0.0.0") == 0)
continue;
ret = asprintf(&buf, "%s:%s,%d", hbuf, sbuf,
port->p_portal_group->pg_tag);
pg->pg_tag);
break;
case AF_INET6:
if (strcmp(hbuf, "::") == 0)
continue;
ret = asprintf(&buf, "[%s]:%s,%d", hbuf, sbuf,
port->p_portal_group->pg_tag);
pg->pg_tag);
break;
default:
continue;
@@ -154,8 +154,8 @@ discovery_target_filtered_out(const struct ctld_connection *conn,
const struct auth *auth;
int error;
targ = port->p_target;
ag = port->p_auth_group.get();
targ = port->target();
ag = port->auth_group();
if (ag == nullptr)
ag = targ->t_auth_group.get();
pg = conn->conn_portal->portal_group();
@@ -228,12 +228,13 @@ discovery(struct ctld_connection *conn)
response_keys = keys_new();
if (strcmp(send_targets, "All") == 0) {
TAILQ_FOREACH(port, &pg->pg_ports, p_pgs) {
for (const auto &kv : pg->pg_ports) {
port = kv.second;
if (discovery_target_filtered_out(conn, port)) {
/* Ignore this target. */
continue;
}
discovery_add_target(response_keys, port->p_target);
discovery_add_target(response_keys, port->target());
}
} else {
port = port_find_in_pg(pg, send_targets);
@@ -244,7 +245,8 @@ discovery(struct ctld_connection *conn)
if (discovery_target_filtered_out(conn, port)) {
/* Ignore this target. */
} else {
discovery_add_target(response_keys, port->p_target);
discovery_add_target(response_keys,
port->target());
}
}
}
+190 -162
View File
@@ -401,7 +401,6 @@ conf_new_from_kernel(struct kports &kports)
struct conf *conf = NULL;
struct target *targ;
struct portal_group *pg;
struct port *cp;
struct lun *cl;
struct ctl_lun_list list;
struct cctl_devlist_data devlist;
@@ -575,12 +574,10 @@ retry_port:
}
}
pg->pg_tag = port->cfiscsi_portal_group_tag;
cp = port_new(conf, targ, pg);
if (cp == NULL) {
if (!port_new(conf, targ, pg, port->port_id)) {
log_warnx("port_new failed");
continue;
}
cp->p_ctl_port = port->port_id;
}
while ((port = STAILQ_FIRST(&devlist.port_list))) {
STAILQ_REMOVE_HEAD(&devlist.port_list, links);
@@ -895,100 +892,118 @@ kernel_handoff(struct ctld_connection *conn)
}
}
int
kernel_port_add(struct port *port)
static bool
ctl_create_port(const char *driver, const nvlist_t *nvl, uint32_t *ctl_port)
{
struct ctl_port_entry entry;
struct ctl_req req;
struct ctl_lun_map lm;
struct target *targ = port->p_target;
struct portal_group *pg = port->p_portal_group;
char result_buf[NVLIST_BUFSIZE];
int error, i;
int error;
/* Create iSCSI port. */
if (port->p_portal_group || port->p_ioctl_port) {
bzero(&req, sizeof(req));
req.reqtype = CTL_REQ_CREATE;
bzero(&req, sizeof(req));
req.reqtype = CTL_REQ_CREATE;
if (port->p_portal_group) {
strlcpy(req.driver, "iscsi", sizeof(req.driver));
req.args_nvl = nvlist_clone(pg->pg_options);
nvlist_add_string(req.args_nvl, "cfiscsi_target",
targ->t_name);
nvlist_add_string(req.args_nvl,
"ctld_portal_group_name", pg->pg_name);
nvlist_add_stringf(req.args_nvl,
"cfiscsi_portal_group_tag", "%u", pg->pg_tag);
if (targ->t_alias) {
nvlist_add_string(req.args_nvl,
"cfiscsi_target_alias", targ->t_alias);
}
}
if (port->p_ioctl_port) {
strlcpy(req.driver, "ioctl", sizeof(req.driver));
req.args_nvl = nvlist_create(0);
nvlist_add_stringf(req.args_nvl, "pp", "%d",
port->p_ioctl_pp);
nvlist_add_stringf(req.args_nvl, "vp", "%d",
port->p_ioctl_vp);
}
req.args = nvlist_pack(req.args_nvl, &req.args_len);
if (req.args == NULL) {
nvlist_destroy(req.args_nvl);
log_warn("error packing nvlist");
return (1);
}
req.result = result_buf;
req.result_len = sizeof(result_buf);
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
free(req.args);
nvlist_destroy(req.args_nvl);
if (error != 0) {
log_warn("error issuing CTL_PORT_REQ ioctl");
return (1);
}
if (req.status == CTL_LUN_ERROR) {
log_warnx("error returned from port creation request: %s",
req.error_str);
return (1);
}
if (req.status != CTL_LUN_OK) {
log_warnx("unknown port creation request status %d",
req.status);
return (1);
}
req.result_nvl = nvlist_unpack(result_buf, req.result_len, 0);
if (req.result_nvl == NULL) {
log_warnx("error unpacking result nvlist");
return (1);
}
port->p_ctl_port = nvlist_get_number(req.result_nvl, "port_id");
nvlist_destroy(req.result_nvl);
} else if (port->p_pport) {
port->p_ctl_port = port->p_pport->ctl_port();
if (strncmp(targ->t_name, "naa.", 4) == 0 &&
strlen(targ->t_name) == 20) {
bzero(&entry, sizeof(entry));
entry.port_type = CTL_PORT_NONE;
entry.targ_port = port->p_ctl_port;
entry.flags |= CTL_PORT_WWNN_VALID;
entry.wwnn = strtoull(targ->t_name + 4, NULL, 16);
if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1)
log_warn("CTL_SET_PORT_WWNS ioctl failed");
}
strlcpy(req.driver, driver, sizeof(req.driver));
req.args = nvlist_pack(nvl, &req.args_len);
if (req.args == NULL) {
log_warn("error packing nvlist");
return (false);
}
req.result = result_buf;
req.result_len = sizeof(result_buf);
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
free(req.args);
if (error != 0) {
log_warn("error issuing CTL_PORT_REQ ioctl");
return (false);
}
if (req.status == CTL_LUN_ERROR) {
log_warnx("error returned from port creation request: %s",
req.error_str);
return (false);
}
if (req.status != CTL_LUN_OK) {
log_warnx("unknown port creation request status %d",
req.status);
return (false);
}
freebsd::nvlist_up result_nvl(nvlist_unpack(result_buf, req.result_len,
0));
if (result_nvl == NULL) {
log_warnx("error unpacking result nvlist");
return (false);
}
*ctl_port = nvlist_get_number(result_nvl.get(), "port_id");
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(nvlist_clone(pg->pg_options));
nvlist_add_string(nvl.get(), "cfiscsi_target", targ->t_name);
nvlist_add_string(nvl.get(), "ctld_portal_group_name", pg->pg_name);
nvlist_add_stringf(nvl.get(), "cfiscsi_portal_group_tag", "%u",
pg->pg_tag);
if (targ->t_alias) {
nvlist_add_string(nvl.get(), "cfiscsi_target_alias",
targ->t_alias);
}
return (ctl_create_port("iscsi", nvl.get(), &p_ctl_port));
}
bool
ioctl_port::kernel_create_port()
{
freebsd::nvlist_up nvl(nvlist_create(0));
nvlist_add_stringf(nvl.get(), "pp", "%d", p_ioctl_pp);
nvlist_add_stringf(nvl.get(), "vp", "%d", p_ioctl_vp);
return (ctl_create_port("ioctl", nvl.get(), &p_ctl_port));
}
bool
kernel_port::kernel_create_port()
{
struct ctl_port_entry entry;
struct target *targ = p_target;
p_ctl_port = p_pport->ctl_port();
if (strncmp(targ->t_name, "naa.", 4) == 0 &&
strlen(targ->t_name) == 20) {
bzero(&entry, sizeof(entry));
entry.port_type = CTL_PORT_NONE;
entry.targ_port = p_ctl_port;
entry.flags |= CTL_PORT_WWNN_VALID;
entry.wwnn = strtoull(targ->t_name + 4, NULL, 16);
if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1)
log_warn("CTL_SET_PORT_WWNS ioctl failed");
}
return (true);
}
bool
port::kernel_add()
{
struct ctl_port_entry entry;
struct ctl_lun_map lm;
struct target *targ = p_target;
int error, i;
if (!kernel_create_port())
return (false);
/* Explicitly enable mapping to block any access except allowed. */
lm.port = port->p_ctl_port;
lm.port = p_ctl_port;
lm.plun = UINT32_MAX;
lm.lun = 0;
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
@@ -999,7 +1014,7 @@ kernel_port_add(struct port *port)
for (i = 0; i < MAX_LUNS; i++) {
if (targ->t_luns[i] == NULL)
continue;
lm.port = port->p_ctl_port;
lm.port = p_ctl_port;
lm.plun = i;
lm.lun = targ->t_luns[i]->l_ctl_lun;
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
@@ -1009,28 +1024,30 @@ kernel_port_add(struct port *port)
/* Enable port */
bzero(&entry, sizeof(entry));
entry.targ_port = port->p_ctl_port;
entry.targ_port = p_ctl_port;
error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
if (error != 0) {
log_warn("CTL_ENABLE_PORT ioctl failed");
return (-1);
return (false);
}
return (0);
return (true);
}
int
kernel_port_update(struct port *port, struct port *oport)
bool
port::kernel_update(const struct port *oport)
{
struct ctl_lun_map lm;
struct target *targ = port->p_target;
struct target *targ = p_target;
struct target *otarg = oport->p_target;
int error, i;
uint32_t olun;
p_ctl_port = oport->p_ctl_port;
/* Map configured LUNs and unmap others */
for (i = 0; i < MAX_LUNS; i++) {
lm.port = port->p_ctl_port;
lm.port = p_ctl_port;
lm.plun = i;
if (targ->t_luns[i] == NULL)
lm.lun = UINT32_MAX;
@@ -1046,83 +1063,94 @@ kernel_port_update(struct port *port, struct port *oport)
if (error != 0)
log_warn("CTL_LUN_MAP ioctl failed");
}
return (0);
return (true);
}
int
kernel_port_remove(struct port *port)
bool
ctl_remove_port(const char *driver, nvlist_t *nvl)
{
struct ctl_req req;
int error;
strlcpy(req.driver, driver, sizeof(req.driver));
req.reqtype = CTL_REQ_REMOVE;
req.args = nvlist_pack(nvl, &req.args_len);
if (req.args == NULL) {
log_warn("error packing nvlist");
return (false);
}
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
free(req.args);
if (error != 0) {
log_warn("error issuing CTL_PORT_REQ ioctl");
return (false);
}
if (req.status == CTL_LUN_ERROR) {
log_warnx("error returned from port removal request: %s",
req.error_str);
return (false);
}
if (req.status != CTL_LUN_OK) {
log_warnx("unknown port removal request status %d", req.status);
return (false);
}
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->t_name);
nvlist_add_stringf(nvl.get(), "cfiscsi_portal_group_tag", "%u",
p_portal_group->pg_tag);
return (ctl_remove_port("iscsi", nvl.get()));
}
bool
ioctl_port::kernel_remove_port()
{
freebsd::nvlist_up nvl(nvlist_create(0));
nvlist_add_stringf(nvl.get(), "port_id", "%d", p_ctl_port);
return (ctl_remove_port("ioctl", nvl.get()));
}
bool
kernel_port::kernel_remove_port()
{
struct ctl_lun_map lm;
int error;
/* Disable LUN mapping. */
lm.port = p_ctl_port;
lm.plun = UINT32_MAX;
lm.lun = UINT32_MAX;
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
if (error != 0)
log_warn("CTL_LUN_MAP ioctl failed");
return (true);
}
bool
port::kernel_remove()
{
struct ctl_port_entry entry;
struct ctl_lun_map lm;
struct ctl_req req;
struct target *targ = port->p_target;
struct portal_group *pg = port->p_portal_group;
int error;
/* Disable port */
bzero(&entry, sizeof(entry));
entry.targ_port = port->p_ctl_port;
entry.targ_port = p_ctl_port;
error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
if (error != 0) {
log_warn("CTL_DISABLE_PORT ioctl failed");
return (-1);
return (false);
}
/* Remove iSCSI or ioctl port. */
if (port->p_portal_group || port->p_ioctl_port) {
bzero(&req, sizeof(req));
strlcpy(req.driver, port->p_ioctl_port ? "ioctl" : "iscsi",
sizeof(req.driver));
req.reqtype = CTL_REQ_REMOVE;
req.args_nvl = nvlist_create(0);
if (req.args_nvl == NULL)
log_err(1, "nvlist_create");
if (port->p_ioctl_port)
nvlist_add_stringf(req.args_nvl, "port_id", "%d",
port->p_ctl_port);
else {
nvlist_add_string(req.args_nvl, "cfiscsi_target",
targ->t_name);
nvlist_add_stringf(req.args_nvl,
"cfiscsi_portal_group_tag", "%u", pg->pg_tag);
}
req.args = nvlist_pack(req.args_nvl, &req.args_len);
if (req.args == NULL) {
nvlist_destroy(req.args_nvl);
log_warn("error packing nvlist");
return (1);
}
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
free(req.args);
nvlist_destroy(req.args_nvl);
if (error != 0) {
log_warn("error issuing CTL_PORT_REQ ioctl");
return (1);
}
if (req.status == CTL_LUN_ERROR) {
log_warnx("error returned from port removal request: %s",
req.error_str);
return (1);
}
if (req.status != CTL_LUN_OK) {
log_warnx("unknown port removal request status %d",
req.status);
return (1);
}
} else {
/* Disable LUN mapping. */
lm.port = port->p_ctl_port;
lm.plun = UINT32_MAX;
lm.lun = UINT32_MAX;
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
if (error != 0)
log_warn("CTL_LUN_MAP ioctl failed");
}
return (0);
return (kernel_remove_port());
}
#ifdef ICL_KERNEL_PROXY
+3 -3
View File
@@ -981,17 +981,17 @@ login(struct ctld_connection *conn)
log_errx(1, "requested target \"%s\" not found",
target_name);
}
conn->conn_target = conn->conn_port->p_target;
conn->conn_target = conn->conn_port->target();
}
/*
* At this point we know what kind of authentication we need.
*/
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
ag = conn->conn_port->p_auth_group.get();
ag = conn->conn_port->auth_group();
if (ag == nullptr)
ag = conn->conn_target->t_auth_group.get();
if (conn->conn_port->p_auth_group == nullptr &&
if (conn->conn_port->auth_group() == nullptr &&
conn->conn_target->t_private_auth) {
log_debugx("initiator requests to connect "
"to target \"%s\"", conn->conn_target->t_name);