summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2010-03-22 17:42:50 -0500
committerMike Christie <michaelc@cs.wisc.edu>2010-03-22 17:42:50 -0500
commitc94bb3206d8816f9d13c8d971513202d94cbb9ea (patch)
treec9983e982f849150741fbb8d2ed1b61816cbc2da
parentdbc5d37682103a8e3b578fdea743eb41ff46ff3c (diff)
downloadopen-iscsi-c94bb3206d8816f9d13c8d971513202d94cbb9ea.tar.gz
iscsid: add isns discovery daemon and SCN support
This adds the following params to iscsid.conf discovery.daemon.isns.addresses discovery.daemon.isns.poll_interval These work like SendTargets where if you the param iscsid will do discovery and log into the portals found. This also adds iSNS SCN support. Like the other code it only supports login of new targets. Some notes: - It does not appear to work with the Microsoft iSNS server shipping with Windows 2008 rc. I have not tested 2003. The server does not seem to be sending any SCNs and at the same time when we register for SCNs it tells us the operation was successful. From the Microsoft docs it appears that the server does not support SCN events. - Linux-isns is not working with our code. The Linux-isns code appears to be sending iSNS SCN pdus with an incorrect format. - It is working with open-isns.git.
-rw-r--r--README32
-rw-r--r--etc/iscsid.conf48
-rw-r--r--usr/discovery.c231
-rw-r--r--usr/discovery.h12
-rw-r--r--usr/discoveryd.c999
-rw-r--r--usr/discoveryd.h3
-rw-r--r--usr/event_poll.c11
-rw-r--r--usr/event_poll.h3
-rw-r--r--usr/idbm.c42
-rw-r--r--usr/idbm.h6
-rw-r--r--usr/initiator.c2
-rw-r--r--usr/iscsiadm.c3
-rw-r--r--usr/iscsid.c4
-rw-r--r--usr/session_mgmt.c29
-rw-r--r--utils/open-isns/esi.c5
-rw-r--r--utils/open-isns/isns-proto.h1
-rw-r--r--utils/open-isns/isns.h5
-rw-r--r--utils/open-isns/scn.c2
-rw-r--r--utils/open-isns/simple.c16
-rw-r--r--utils/open-isns/socket.c35
-rw-r--r--utils/open-isns/sysdep-unix.c54
21 files changed, 1348 insertions, 195 deletions
diff --git a/README b/README
index b6fd1eb..3ff6726 100644
--- a/README
+++ b/README
@@ -799,9 +799,13 @@ There are three steps needed to set up a system to use iSCSI storage:
7.3. Automate target logins for future system reboots.
The init scripts will start the iSCSI daemon and log into any
-connections or nodes that are set up for automatic login. If your distro
-does not have a init script, then you will have to start the daemon
-and log into the targets manually.
+portals that are set up for automatic login (discussed in 7.2)
+or discovered through the discover daemon iscsid.conf params
+(discussed in 7.1.2).
+
+If your distro does not have a init script, then you will have to start the
+daemon and log into the targets manually.
+
7.1.1 iSCSI startup using the init script
-----------------------------------------------
@@ -832,6 +836,28 @@ gets installed with "make install"
will usually get you started.
+
+7.1.2 Automatic Discovery and Login
+-----------------------------------
+
+When iscsid starts it will check iscsid.conf for:
+
+discovery.daemon.sendtargets.addresses =
+discovery.daemon.sendtargets.poll_interval =
+
+discovery.daemon.isns.addresses =
+discovery.daemon.isns.poll_interval =
+
+being set. If an address or addresses are set, iscsid will perform discovery
+to the address every poll_interval seconds, and it will log into any portals
+found from the discovery source using the ifaces in /etc/iscsi/ifaces.
+
+Note: iscsid will login into new portals, but does not yet support logging
+out of portals that are no longer returned during discovery.
+
+See the iscsid.conf for more examples.
+
+
7.1.2 Manual Startup:
---------------------
diff --git a/etc/iscsid.conf b/etc/iscsid.conf
index e8f83fb..78c225c 100644
--- a/etc/iscsid.conf
+++ b/etc/iscsid.conf
@@ -22,6 +22,12 @@
# Default for upstream open-iscsi scripts (uncomment to activate).
iscsid.startup = /sbin/iscsid
+
+
+
+##############################
+# SendTargets Discovery Daemon
+##############################
# If instead of doing discovery with iscsiadm and then logging
# into the targets stored in the node db, set the following value
# to have iscsid perform SendTargets discovery and log into all
@@ -35,6 +41,7 @@ iscsid.startup = /sbin/iscsid
# default 3260 will be used.
#
# Example (first address has a port and the final two use the default 3260):
+#
# discovery.daemon.sendtargets.addresses = 192.168.0.21,1234 192.168.1.20 192.168.10.10
#
# By default iscsid will check the discovery addresses above every 30
@@ -49,6 +56,47 @@ iscsid.startup = /sbin/iscsid
# To remove them run "iscsiadm -m session -r $SID -u"
+
+#######################
+# iSNS Discovery Daemon
+#######################
+
+
+# iSNS can also be used by setting:
+#
+# discovery.daemon.isns.addresses = 192.168.0.21,1234 192.168.1.20 192.168.10.10
+#
+# The default port is 3205.
+#
+# By default iscsid will perform iSNS discovery to the addresses, register
+# for State Change Notifications (SCNs) and then login/logout of portals
+# depending on the SCN.
+#
+# To change the default behavior the following setting can be used:
+#
+# discovery.daemon.isns.poll_interval = 30
+#
+# - If set to 0, it will perform discovery once then exit.
+# - If set to greater than 0 then it will perform discovery every X seconds.
+# It will still attempt to register for SCNs, but will still poll with
+# a DevAttrQuery for all targets.
+#
+#
+# ALERT
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# This is needed for servers like Microsofts where they allow SCN
+# registrations, but do not send SCN events. To auto discover new targets
+# we have to poll. It is also useful for servers like linux-isns where it
+# sometimes does not send SCN events in the proper format, so they
+# may not get handled.
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#
+# - If set to less than zero (or not set at all) it will perform the default
+# behavior.
+#
+# Note: like with SendTargets, logout of portals is not yet supported.
+
+
#############################
# NIC/HBA and driver settings
#############################
diff --git a/usr/discovery.c b/usr/discovery.c
index e78177c..381f825 100644
--- a/usr/discovery.c
+++ b/usr/discovery.c
@@ -93,80 +93,93 @@ static int request_initiator_name(void)
return 0;
}
-int discovery_isns(struct discovery_rec *drec, struct iface_rec *iface,
- struct list_head *rec_list)
+void discovery_isns_free_servername(void)
{
- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT;
- isns_simple_t *qry;
- isns_client_t *clnt;
- isns_attr_list_t *attrs;
- char *server;
- uint32_t status;
- int rc, i;
-
- isns_config.ic_security = 0;
+ if (isns_config.ic_server_name)
+ free(isns_config.ic_server_name);
+ isns_config.ic_server_name = NULL;
+}
- if (iface && strlen(iface->iname))
- isns_assign_string(&isns_config.ic_source_name, iface->iname);
- else {
- if (request_initiator_name() || initiator_name[0] == '\0') {
- log_error("Cannot perform discovery. Initiatorname "
- "required.");
- return EINVAL;
- }
- isns_assign_string(&isns_config.ic_source_name, initiator_name);
- }
+int discovery_isns_set_servername(char *address, int port)
+{
+ char *server;
+ int len;
- if (drec->port > USHRT_MAX) {
- log_error("Invalid port %d\n", drec->port);
- rc = EINVAL;
- goto free_mem;
+ if (port > USHRT_MAX) {
+ log_error("Invalid port %d\n", port);
+ return EINVAL;
}
/* 5 for port and 1 for colon and 1 for null */
- i = strlen(drec->address) + 7;
- server = calloc(1, i);
- if (!server) {
- rc = ENOMEM;
- goto free_mem;
- }
+ len = strlen(address) + 7;
+ server = calloc(1, len);
+ if (!server)
+ return ENOMEM;
- snprintf(server, i, "%s:%d", drec->address, drec->port);
+ snprintf(server, len, "%s:%d", address, port);
isns_assign_string(&isns_config.ic_server_name, server);
free(server);
+ return 0;
+}
+
+int discovery_isns_query(struct discovery_rec *drec, const char *iname,
+ const char *targetname, struct list_head *rec_list)
+{
+ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT;
+ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT;
+ isns_source_t *source;
+ isns_simple_t *qry;
+ isns_client_t *clnt;
+ uint32_t status;
+ int rc, i;
- clnt = isns_create_default_client(NULL);
+ isns_config.ic_security = 0;
+ source = isns_source_create_iscsi(iname);
+ if (!source)
+ return ENOMEM;
+
+ clnt = isns_create_client(NULL, iname);
if (!clnt) {
rc = ENOMEM;
- goto free_mem;
+ goto free_src;
}
/* do not retry forever */
isns_socket_set_disconnect_fatal(clnt->ic_socket);
- qry = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_QUERY,
- clnt->ic_source, NULL);
+ if (targetname)
+ isns_attr_list_append_string(&key_attrs, ISNS_TAG_ISCSI_NAME,
+ targetname);
+ else
+ /* Query for all visible targets */
+ isns_attr_list_append_uint32(&key_attrs,
+ ISNS_TAG_ISCSI_NODE_TYPE,
+ ISNS_ISCSI_TARGET_MASK);
+
+ qry = isns_create_query2(clnt, &key_attrs, source);
if (!qry) {
rc = ENOMEM;
goto free_clnt;
}
- attrs = &qry->is_message_attrs;
- isns_attr_list_append_uint32(attrs, ISNS_TAG_ISCSI_NODE_TYPE,
- ISNS_ISCSI_TARGET_MASK);
-
- attrs = &qry->is_operating_attrs;
- isns_attr_list_append_nil(attrs, ISNS_TAG_ISCSI_NAME);
- isns_attr_list_append_nil(attrs, ISNS_TAG_ISCSI_NODE_TYPE);
- isns_attr_list_append_nil(attrs, ISNS_TAG_PORTAL_IP_ADDRESS);
- isns_attr_list_append_nil(attrs, ISNS_TAG_PORTAL_TCP_UDP_PORT);
- isns_attr_list_append_nil(attrs, ISNS_TAG_PG_ISCSI_NAME);
- isns_attr_list_append_nil(attrs, ISNS_TAG_PG_PORTAL_IP_ADDR);
- isns_attr_list_append_nil(attrs, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT);
- isns_attr_list_append_nil(attrs, ISNS_TAG_PG_TAG);
+ isns_query_request_attr_tag(qry, ISNS_TAG_ISCSI_NAME);
+ isns_query_request_attr_tag(qry, ISNS_TAG_ISCSI_NODE_TYPE);
+ isns_query_request_attr_tag(qry, ISNS_TAG_PORTAL_IP_ADDRESS);
+ isns_query_request_attr_tag(qry, ISNS_TAG_PORTAL_TCP_UDP_PORT);
+ isns_query_request_attr_tag(qry, ISNS_TAG_PG_ISCSI_NAME);
+ isns_query_request_attr_tag(qry, ISNS_TAG_PG_PORTAL_IP_ADDR);
+ isns_query_request_attr_tag(qry, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT);
+ isns_query_request_attr_tag(qry, ISNS_TAG_PG_TAG);
status = isns_client_call(clnt, &qry);
- if (status != ISNS_SUCCESS) {
+ switch (status) {
+ case ISNS_SUCCESS:
+ break;
+ case ISNS_SOURCE_UNKNOWN:
+ /* server requires that we are registered but we are not */
+ rc = ENOENT;
+ goto free_query;
+ default:
log_error("iSNS discovery failed: %s", isns_strerror(status));
rc = EIO;
goto free_query;
@@ -231,15 +244,16 @@ int discovery_isns(struct discovery_rec *drec, struct iface_rec *iface,
}
idbm_node_setup_from_conf(rec);
- rec->disc_type = drec->type;
- rec->disc_port = drec->port;
- strcpy(rec->disc_address, drec->address);
+ if (drec) {
+ rec->disc_type = drec->type;
+ rec->disc_port = drec->port;
+ strcpy(rec->disc_address, drec->address);
+ }
strlcpy(rec->name, pg_tgt, TARGET_NAME_MAXLEN);
rec->tpgt = pg_tag;
rec->conn[0].port = pg_port;
strlcpy(rec->conn[0].address, pg_addr, NI_MAXHOST);
-
list_add_tail(&rec->list, rec_list);
}
rc = 0;
@@ -251,22 +265,112 @@ free_query:
isns_simple_free(qry);
free_clnt:
isns_client_destroy(clnt);
-free_mem:
- if (isns_config.ic_source_name)
- free(isns_config.ic_source_name);
- isns_config.ic_source_name = NULL;
+free_src:
+ isns_source_release(source);
+ return rc;
+}
- if (isns_config.ic_server_name)
- free(isns_config.ic_server_name);
- isns_config.ic_server_name = NULL;
+/*
+ * discovery_isns_reg_node - register/deregister node
+ * @iname: initiator name
+ * @reg: bool indicating if we are supposed to register or deregister node.
+ *
+ * We do a very simple registration just so we can query.
+ */
+static int discovery_isns_reg_node(const char *iname, int op_reg)
+{
+ isns_simple_t *reg;
+ isns_client_t *clnt;
+ isns_source_t *source;
+ int rc = 0, status;
+
+ isns_config.ic_security = 0;
+
+ log_debug(1, "trying to %s %s with iSNS server.",
+ op_reg ? "register" : "deregister", iname);
+
+ source = isns_source_create_iscsi(iname);
+ if (!source)
+ return ENOMEM;
+
+ clnt = isns_create_client(NULL, iname);
+ if (!clnt) {
+ rc = ENOMEM;
+ goto free_src;
+ }
+
+ reg = isns_simple_create(op_reg ? ISNS_DEVICE_ATTRIBUTE_REGISTER :
+ ISNS_DEVICE_DEREGISTER,
+ source, NULL);
+ if (!reg) {
+ rc = ENOMEM;
+ goto free_clnt;
+ }
+
+ isns_attr_list_append_string(&reg->is_operating_attrs,
+ ISNS_TAG_ISCSI_NAME, iname);
+ if (op_reg)
+ isns_attr_list_append_uint32(&reg->is_operating_attrs,
+ ISNS_TAG_ISCSI_NODE_TYPE,
+ ISNS_ISCSI_INITIATOR_MASK);
+ status = isns_client_call(clnt, &reg);
+ if (status != ISNS_SUCCESS) {
+ log_error("Could not %s %s with iSNS server: %s.",
+ reg ? "register" : "deregister", iname,
+ isns_strerror(status));
+ rc = EIO;
+ } else
+ log_debug(1, "%s %s with iSNS server successful.",
+ op_reg ? "register" : "deregister", iname);
+free_clnt:
+ isns_client_destroy(clnt);
+free_src:
+ isns_source_release(source);
return rc;
}
+int discovery_isns(void *data, struct iface_rec *iface,
+ struct list_head *rec_list)
+{
+ struct discovery_rec *drec = data;
+ char *iname;
+ int rc, registered = 0;
+ if (iface && strlen(iface->iname))
+ iname = iface->iname;
+ else {
+ if (request_initiator_name() || initiator_name[0] == '\0') {
+ log_error("Cannot perform discovery. Initiatorname "
+ "required.");
+ return EINVAL;
+ }
+ iname = initiator_name;
+ }
+
+ rc = discovery_isns_set_servername(drec->address, drec->port);
+ if (rc)
+ return rc;
+retry:
+ rc = discovery_isns_query(drec, iname, NULL, rec_list);
+ if (!registered && rc == ENOENT) {
+ rc = discovery_isns_reg_node(iname, 1);
+ if (!rc) {
+ registered = 1;
+ goto retry;
+ }
+ }
+
+ if (registered)
+ discovery_isns_reg_node(iname, 0);
+
+ discovery_isns_free_servername();
+ return rc;
+}
-int discovery_fw(struct discovery_rec *drec, struct iface_rec *iface,
+int discovery_fw(void *data, struct iface_rec *iface,
struct list_head *rec_list)
{
+ struct discovery_rec *drec = data;
struct boot_context *bcontext;
struct list_head targets;
struct node_rec *rec;
@@ -1050,9 +1154,10 @@ done:
iscsi_io_disconnect(&session->conn[0]);
}
-int discovery_sendtargets(discovery_rec_t *drec, struct iface_rec *iface,
+int discovery_sendtargets(void *fndata, struct iface_rec *iface,
struct list_head *rec_list)
{
+ discovery_rec_t *drec = fndata;
iscsi_session_t *session;
struct pollfd pfd;
struct iscsi_hdr pdu_buffer;
diff --git a/usr/discovery.h b/usr/discovery.h
index 3d65fb7..0575e2a 100644
--- a/usr/discovery.h
+++ b/usr/discovery.h
@@ -27,12 +27,16 @@ struct iface_rec;
struct node_rec;
struct boot_context;
-extern int discovery_isns(struct discovery_rec *drec, struct iface_rec *iface,
+extern int discovery_isns_query(struct discovery_rec *drec, const char *iname,
+ const char *targetname,
+ struct list_head *rec_list);
+extern void discovery_isns_free_servername(void);
+extern int discovery_isns_set_servername(char *address, int port);
+extern int discovery_isns(void *data, struct iface_rec *iface,
struct list_head *rec_list);
-extern int discovery_fw(struct discovery_rec *drec, struct iface_rec *iface,
+extern int discovery_fw(void *data, struct iface_rec *iface,
struct list_head *rec_list);
-extern int discovery_sendtargets(struct discovery_rec *drec,
- struct iface_rec *iface,
+extern int discovery_sendtargets(void *data, struct iface_rec *iface,
struct list_head *rec_list);
extern int discovery_offload_sendtargets(int host_no, int do_login,
struct discovery_rec *drec);
diff --git a/usr/discoveryd.c b/usr/discoveryd.c
index 2986122..4d01b7a 100644
--- a/usr/discoveryd.c
+++ b/usr/discoveryd.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <signal.h>
#include <stdlib.h>
+#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -37,25 +38,44 @@
#include "iscsi_util.h"
#include "event_poll.h"
#include "iface.h"
+#include "session_mgmt.h"
+#include "session_info.h"
+#include "isns-proto.h"
+#include "isns.h"
+#include "paths.h"
+#include "message.h"
+
+#define DISC_ISNS_ADDR_CFG_STR "discovery.daemon.isns.addresses"
+#define DISC_ISNS_POLL_INVL "discovery.daemon.isns.poll_interval"
+
+#define DISC_ST_ADDR_CFG_STR "discovery.daemon.sendtargets.addresses"
+#define DISC_ST_POLL_INVL "discovery.daemon.sendtargets.poll_interval"
-#define DISC_ST_ADDR_CFG_STR "discovery.daemon.sendtargets.addresses"
-#define DISC_ST_POLL_INVL "discovery.daemon.sendtargets.poll_interval"
+#define DISC_DEF_POLL_INVL 30
-#define DISC_DEF_POLL_INVL 30
+static LIST_HEAD(isns_nodes);
+static LIST_HEAD(isns_refresh_list);
+static char *isns_entity_id = NULL;
+static uint32_t isns_refresh_interval;
+static int isns_register_nodes = 1;
-typedef void (do_disc_and_login_fn)(char *addr, int port);
+static void isns_reg_refresh_by_eid_qry(void *data);
-static int do_disc_to_addrs(char *disc_addrs,
- do_disc_and_login_fn *do_disc_and_login)
+typedef void (do_disc_and_login_fn)(const char *def_iname, char *addr,
+ int port, int poll_inval);
+
+static void do_disc_to_addrs(const char *def_iname, char *disc_addrs,
+ int poll_inval,
+ do_disc_and_login_fn *do_disc_and_login)
{
pid_t pid;
- int nr_procs = 0, portn;
+ int portn;
char *saveptr1, *saveptr2;
char *ip_str, *addr, *port_str;
addr = strtok_r(disc_addrs, " ", &saveptr1);
if (!addr)
- return 0;
+ return;
do {
ip_str = strtok_r(addr, ",", &saveptr2);
@@ -66,13 +86,13 @@ static int do_disc_to_addrs(char *disc_addrs,
port_str = strtok_r(NULL, " ", &saveptr2);
if (!port_str)
- portn = ISCSI_LISTEN_PORT;
+ portn = -1;
else
portn = atoi(port_str);
pid = fork();
if (pid == 0) {
- do_disc_and_login(ip_str, portn);
+ do_disc_and_login(def_iname, ip_str, portn, poll_inval);
exit(0);
} else if (pid < 0)
log_error("Fork failed (err %d - %s). Will not be able "
@@ -80,90 +100,932 @@ static int do_disc_to_addrs(char *disc_addrs,
errno, strerror(errno), ip_str);
else {
log_debug(1, "iSCSI disc and login helper pid=%d", pid);
- nr_procs++;
+ reap_inc();
}
-
-
} while ((addr = strtok_r(NULL, " ", &saveptr1)));
-
- return nr_procs;
}
-static void discoveryd_start(char *addr_cfg_str, char *poll_cfg_str,
- do_disc_and_login_fn *do_disc_and_login)
+static void __discoveryd_start(const char *def_iname, char *addr_cfg_str,
+ char *poll_cfg_str,
+ do_disc_and_login_fn *do_disc_and_login)
{
char *disc_addrs, *disc_poll_param;
- int disc_poll_invl = DISC_DEF_POLL_INVL;
- pid_t pid;
+ int disc_poll_invl = -1;
disc_addrs = cfg_get_string_param(CONFIG_FILE, addr_cfg_str);
if (!disc_addrs)
return;
+
+ disc_poll_param = cfg_get_string_param(CONFIG_FILE, poll_cfg_str);
+ if (disc_poll_param) {
+ disc_poll_invl = atoi(disc_poll_param);
+ free(disc_poll_param);
+ }
+
+ log_debug(1, "%s=%s poll interval %d", addr_cfg_str,
+ disc_addrs, disc_poll_invl);
+
+ do_disc_to_addrs(def_iname, disc_addrs, disc_poll_invl,
+ do_disc_and_login);
free(disc_addrs);
+}
- pid = fork();
- if (pid == 0) {
- do {
- /* check for updates */
- disc_addrs = cfg_get_string_param(CONFIG_FILE,
- addr_cfg_str);
- if (!disc_addrs)
- continue;
+/* iSNS */
+static void do_isns_disc_and_login(char *disc_addr, int port)
+{
+ discovery_rec_t drec;
+ struct list_head rec_list, setup_ifaces;
+ int rc, nr_found;
+ struct node_rec *rec, *tmp_rec;
+ struct iface_rec *iface, *tmp_iface;
+
+ log_debug(1, "iSNS: do_isns_disc_and_login to %s,%d.",
+ disc_addr, port);
+
+ INIT_LIST_HEAD(&rec_list);
+ INIT_LIST_HEAD(&setup_ifaces);
+
+ drec.type = DISCOVERY_TYPE_ISNS;
+ strlcpy(drec.address, disc_addr, sizeof(drec.address));
+ drec.port = port;
+
+ iface_link_ifaces(&setup_ifaces);
+ rc = idbm_bind_ifaces_to_nodes(discovery_isns, &drec,
+ &setup_ifaces, &rec_list);
+ if (rc) {
+ log_error("Could not perform iSNS DevAttrQuery to %s.",
+ disc_addr);
+ goto free_ifaces;
+ }
+
+ list_for_each_entry_safe(rec, tmp_rec, &rec_list, list) {
+ if (iscsi_check_for_running_session(rec)) {
+ list_del(&rec->list);
+ free(rec);
+ }
+
+ /* no need to retry since the disc daemon will retry */
+ rec->session.initial_login_retry_max = 0;
+ }
+
+ iscsi_login_portals(NULL, &nr_found, &rec_list, iscsi_login_portal);
+
+free_ifaces:
+ list_for_each_entry_safe(iface, tmp_iface, &setup_ifaces, list) {
+ list_del(&iface->list);
+ free(iface);
+ }
+}
+
+struct isns_node_list {
+ isns_source_t *source;
+ struct list_head list;
+};
+
+static int isns_build_objs(isns_portal_info_t *portal_info,
+ isns_object_list_t *objs)
+{
+ struct isns_node_list *node;
+ isns_object_t *inode, *entity;
+ unsigned int i, nportals = 1;
+ int rc = 0;
+
+ log_debug(7, "isns_build_objs");
+
+ /* we currently just use all portals */
+ if (isns_portal_is_wildcard(portal_info)) {
+ static isns_portal_info_t *iflist;
+
+ nportals = isns_get_nr_portals();
+ log_debug(4, "got %d portals", nportals);
+ if (!nportals)
+ return ENODEV;
+
+ iflist = calloc(nportals, sizeof(isns_portal_info_t));
+ if (!iflist) {
+ log_error("Unable to allocate %d portals.", nportals);
+ return ENOMEM;
+ }
+
+ nportals = isns_enumerate_portals(iflist, nportals);
+ if (nportals == 0) {
+ log_error("Unable to enumerate portals - "
+ "no usable interfaces found\n");
+ free(iflist);
+ return ENODEV;
+ }
+ for (i = 0; i < nportals; ++i) {
+ iflist[i].addr.sin6_port = portal_info->addr.sin6_port;
+ iflist[i].proto = portal_info->proto;
+ }
+ portal_info = iflist;
+ }
+
+ if (!isns_entity_id) {
+ isns_entity_id = calloc(1, 256);
+ if (!isns_entity_id)
+ return ENOMEM;
+
+ rc = getnameinfo((struct sockaddr *) &portal_info->addr,
+ sizeof(portal_info->addr),
+ isns_entity_id, 256, NULL, 0, 0);
+ if (rc) {
+ free(isns_entity_id);
+ isns_entity_id = NULL;
+
+ log_error("Could not get hostname for EID.");
+ return EIO;
+ }
+ }
+
+ entity = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, isns_entity_id);
+ if (!entity) {
+ log_error("Could not create iSNS entity.");
+ return ENOMEM;
+ }
+ isns_object_list_append(objs, entity);
+
+ for (i = 0; i < nportals; ++i, ++portal_info) {
+ isns_object_t *portal;
+
+ portal = isns_create_portal(portal_info, entity);
+ if (!portal) {
+ rc = ENOMEM;
+ goto fail;
+ }
+ isns_object_list_append(objs, portal);
+
+ if (!isns_object_set_uint32(portal, ISNS_TAG_SCN_PORT,
+ isns_portal_tcpudp_port(portal_info))) {
+ rc = EINVAL;
+ goto fail;
+ }
+ }
+
+ list_for_each_entry(node, &isns_nodes, list) {
+ inode = isns_create_storage_node2(node->source,
+ ISNS_ISCSI_INITIATOR_MASK,
+ NULL);
+ if (!inode) {
+ rc = ENOMEM;
+ goto fail;
+ }
+ isns_object_list_append(objs, inode);
+ }
+
+ return 0;
+fail:
+ isns_object_list_destroy(objs);
+ return rc;
+}
+
+struct isns_qry_data {
+ const char *iname;
+ const char *targetname;
+};
+
+static int isns_query_node(void *data, struct iface_rec *iface,
+ struct list_head *recs)
+{
+ struct isns_qry_data *qry_data = data;
+ int is_def_iname = 0;
+ const char *iname;
+
+ if (qry_data->iname) {
+ if (!strcmp(qry_data->iname, isns_config.ic_source_name))
+ is_def_iname = 1;
+
+ if ((!is_def_iname || strlen(iface->iname)) &&
+ strcmp(iface->iname, qry_data->iname))
+ return 0;
+
+ iname = qry_data->iname;
+ } else {
+ if (strlen(iface->iname))
+ iname = iface->iname;
+ else
+ iname = isns_config.ic_source_name;
+ }
+
+ return discovery_isns_query(NULL, iname, qry_data->targetname, recs);
+}
+
+static int __isns_disc_new_portals(const char *targetname, const char *iname)
+{
+ struct list_head ifaces, rec_list;
+ struct iface_rec *iface, *tmp_iface;
+ struct node_rec *rec, *tmp_rec;
+ struct isns_qry_data qry_data;
+ int nr_found = 0, rc;
+
+ INIT_LIST_HEAD(&rec_list);
+ INIT_LIST_HEAD(&ifaces);
+
+ qry_data.targetname = targetname;
+ qry_data.iname = iname;
+
+ iface_link_ifaces(&ifaces);
+ rc = idbm_bind_ifaces_to_nodes(isns_query_node, &qry_data, &ifaces,
+ &rec_list);
+ if (rc) {
+ log_error("Could not perform iSNS DevAttrQuery for node %s.",
+ targetname);
+ goto free_ifaces;
+ }
+
+ list_for_each_entry_safe(rec, tmp_rec, &rec_list, list) {
+ if (iscsi_check_for_running_session(rec)) {
+ list_del(&rec->list);
+ free(rec);
+ }
+ }
+
+ iscsi_login_portals(NULL, &nr_found, &rec_list, iscsi_login_portal);
+ rc = 0;
+
+free_ifaces:
+ list_for_each_entry_safe(iface, tmp_iface, &ifaces, list) {
+ list_del(&iface->list);
+ free(iface);
+ }
+
+ return rc;
+}
+
+static void isns_reg_refresh_with_disc(void *data)
+{
+ int retries = 0, rc;
+
+ log_debug(1, "Refresh registration using DevAttrQuery");
+
+ /*
+ * it is ok to block here since we are not expecting SCNs
+ * from the server.
+ */
+ do {
+ /*
+ * Some servers do not support SCNs so we ping
+ * the server by doing discovery.
+ */
+ rc = __isns_disc_new_portals(NULL, NULL);
+ if (rc) {
+ log_debug(4, "Registration refresh using DevAttrQuery "
+ "failed (retires %d) err %d", retries, rc);
+ sleep(1);
+ retries++;
+ continue;
+ }
+ } while (rc && retries < 3);
+
+ if (rc)
+ /*
+ * Try to reregister from scratch.
+ */
+ isns_register_nodes = 1;
+}
+
+struct isns_refresh_data {
+ isns_client_t *clnt;
+ isns_simple_t *qry;
+ uint32_t xid;
+ uint32_t interval;
+ time_t start_time;
+ struct list_head list;
+};
+
+static void isns_free_refresh_data(struct isns_refresh_data *refresh_data)
+{
+ list_del(&refresh_data->list);
+ if (refresh_data->qry)
+ isns_simple_free(refresh_data->qry);
+ if (refresh_data->clnt)
+ isns_client_destroy(refresh_data->clnt);
+ free(refresh_data);
+}
+
+static struct isns_refresh_data *isns_find_refresh_data(uint32_t xid)
+{
+ struct isns_refresh_data *refresh_data;
+
+ list_for_each_entry(refresh_data, &isns_refresh_list, list) {
+ if (refresh_data->xid == xid)
+ return refresh_data;
+ }
+ return NULL;
+}
+
+static void isns_eid_qry_rsp(uint32_t xid, int status, isns_simple_t *rsp)
+{
+ struct isns_refresh_data *refresh_data;
+
+ refresh_data = isns_find_refresh_data(xid);
+ if (!refresh_data) {
+ log_error("EID Query respond could not match xid");
+ return;
+ }
+
+ if (refresh_data->clnt) {
+ isns_client_destroy(refresh_data->clnt);
+ refresh_data->clnt = NULL;
+ }
+
+ if (!rsp || status != ISNS_SUCCESS) {
+ log_debug(1, "Registration refresh using eid qry failed: %s",
+ isns_strerror(status));
+
+ isns_add_oneshot_timer(2, isns_reg_refresh_by_eid_qry,
+ refresh_data);
+ return;
+ }
+
+ log_debug(1, "eid qry successful");
+ refresh_data->start_time = time(NULL);
+ isns_add_oneshot_timer(isns_refresh_interval,
+ isns_reg_refresh_by_eid_qry, refresh_data);
+}
+
+static void isns_reg_refresh_by_eid_qry(void *data)
+{
+ struct isns_refresh_data *refresh_data = data;
+ isns_attr_list_t qry_key = ISNS_ATTR_LIST_INIT;
+ isns_simple_t *qry;
+ isns_client_t *clnt;
+ int status, timeout;
+
+ log_debug(1, "Refresh registration using eid qry");
+ if (refresh_data->start_time + refresh_data->interval <= time(NULL)) {
+ log_error("Could not refresh registration with server "
+ "before registration period. Starting new "
+ "registration.");
+ isns_free_refresh_data(refresh_data);
+ isns_register_nodes = 1;
+ return;
+ }
+
+ clnt = isns_create_default_client(NULL);
+ if (!clnt) {
+ log_error("iSNS registration refresh failed. Could not "
+ "connect to server.");
+ goto rearm;
+ }
+ refresh_data->clnt = clnt;
+ /*
+ * if a operation has failed we will want to adjust timers
+ * and possibly reregister.
+ */
+ isns_socket_set_report_failure(clnt->ic_socket);
+
+ /*
+ * if this is a retry or re-refresh then there will be a qry
+ */
+ qry = refresh_data->qry;
+ if (qry)
+ goto send;
+
+ isns_attr_list_append_string(&qry_key, ISNS_TAG_ENTITY_IDENTIFIER,
+ isns_entity_id);
+ qry = isns_create_query(clnt, &qry_key);
+ isns_attr_list_destroy(&qry_key);
+ if (!qry)
+ goto rearm;
+ isns_query_request_attr_tag(qry, ISNS_TAG_ENTITY_PROTOCOL);
+ refresh_data->qry = qry;
+
+send:
+ timeout = (refresh_data->start_time + refresh_data->interval) -
+ time(NULL);
+
+ status = isns_simple_transmit(clnt->ic_socket, qry, NULL,
+ timeout, isns_eid_qry_rsp);
+ if (status == ISNS_SUCCESS) {
+ log_debug(7, "sent eid qry with xid %u", qry->is_xid);
- disc_poll_param = cfg_get_string_param(CONFIG_FILE,
- poll_cfg_str);
- if (disc_poll_param) {
- disc_poll_invl = atoi(disc_poll_param);
- free(disc_poll_param);
+ refresh_data->xid = qry->is_xid;
+ return;
+ }
+rearm:
+ if (refresh_data->clnt) {
+ isns_client_destroy(refresh_data->clnt);
+ refresh_data->clnt = NULL;
+ }
+ log_debug(1, "Could not send eid qry to refresh registration.");
+ isns_add_oneshot_timer(2, isns_reg_refresh_by_eid_qry, refresh_data);
+}
+
+static int isns_setup_registration_refresh(isns_simple_t *rsp, int poll_inval)
+{
+ isns_object_list_t objs = ISNS_OBJECT_LIST_INIT;
+ struct isns_refresh_data *refresh_data;
+ int status, i, rc = 0;
+ uint32_t interval = 0;
+
+ status = isns_query_response_get_objects(rsp, &objs);
+ if (status) {
+ log_error("Unable to extract object list from "
+ "registration response: %s\n",
+ isns_strerror(status));
+ return EIO;
+ }
+
+ for (i = 0; i < objs.iol_count; ++i) {
+ isns_object_t *obj = objs.iol_data[i];
+
+ if (!isns_object_is_entity(obj))
+ continue;
+
+ if (isns_object_get_uint32(obj, ISNS_TAG_REGISTRATION_PERIOD,
+ &interval))
+ break;
+ }
+
+ if (!interval)
+ goto free_objs;
+
+ refresh_data = calloc(1, sizeof(*refresh_data));
+ if (!refresh_data) {
+ rc = ENOMEM;
+ goto free_objs;
+ }
+ INIT_LIST_HEAD(&refresh_data->list);
+ list_add_tail(&refresh_data->list, &isns_refresh_list);
+ refresh_data->start_time = time(NULL);
+
+ /*
+ * Several servers do not support SCNs properly, so for the
+ * registration period refresh we do a DevAttrQuery for all targets
+ * if the poll_inval is greater than 0.
+ *
+ * If the target does support SCNs then we just send a query
+ * for our entity's protocol.
+ */
+
+ /* we cut in half to give us time to handle errors */
+ isns_refresh_interval = interval / 2;
+ if (!isns_refresh_interval) {
+ log_warning("iSNS Registration Period only %d seconds.",
+ interval);
+ isns_refresh_interval = interval;
+ }
+ refresh_data->interval = interval;
+
+ if (poll_inval > 0) {
+ /* user wants to override server and do disc */
+ if (isns_refresh_interval > poll_inval)
+ isns_refresh_interval = poll_inval;
+ isns_add_timer(isns_refresh_interval,
+ isns_reg_refresh_with_disc,
+ refresh_data);
+ } else
+ /*
+ * user wants to use server value so we just ping
+ * with a simple qry
+ */
+ isns_add_oneshot_timer(isns_refresh_interval,
+ isns_reg_refresh_by_eid_qry,
+ refresh_data);
+ log_debug(5, "Got registration period of %u "
+ "internval. Using interval of %u",
+ interval, isns_refresh_interval);
+
+free_objs:
+ isns_flush_events();
+ isns_object_list_destroy(&objs);
+ return rc;
+}
+
+static void isns_cancel_refresh_timers(void)
+{
+ isns_cancel_timer(isns_reg_refresh_with_disc, NULL);
+ isns_cancel_timer(isns_reg_refresh_by_eid_qry, NULL);
+}
+
+static int isns_register_objs(isns_client_t *clnt, isns_object_list_t *objs,
+ int poll_inval)
+{
+ struct isns_node_list *node;
+ isns_object_t *entity = NULL;
+ isns_simple_t *reg;
+ unsigned int i;
+ int status, rc = 0;
+
+ log_debug(7, "isns_register_objs");
+
+ for (i = 0; i < objs->iol_count; ++i) {
+ if (isns_object_is_entity(objs->iol_data[i])) {
+ entity = objs->iol_data[i];
+ break;
+ }
+ }
+
+ reg = isns_create_registration(clnt, entity);
+ if (!reg)
+ return ENOMEM;
+
+ for (i = 0; i < objs->iol_count; ++i)
+ isns_registration_add_object(reg, objs->iol_data[i]);
+ isns_registration_set_replace(reg, 1);
+
+ status = isns_simple_call(clnt->ic_socket, &reg);
+ if (status != ISNS_SUCCESS) {
+ log_error("Could not register with iSNS server: %s",
+ isns_strerror(status));
+ rc = EIO;
+ goto free_reg;
+ }
+ log_debug(4, "Registered objs");
+
+ if (!poll_inval)
+ goto free_reg;
+
+ rc = isns_setup_registration_refresh(reg, poll_inval);
+ if (rc)
+ goto free_reg;
+
+ list_for_each_entry(node, &isns_nodes, list) {
+ isns_simple_free(reg);
+ reg = isns_create_scn_registration2(clnt,
+ ISNS_SCN_OBJECT_UPDATED_MASK |
+ ISNS_SCN_OBJECT_ADDED_MASK |
+ ISNS_SCN_OBJECT_REMOVED_MASK |
+ ISNS_SCN_TARGET_AND_SELF_ONLY_MASK,
+ node->source);
+
+ if (!reg) {
+ isns_cancel_refresh_timers();
+ rc = ENOMEM;
+ goto done;
+ }
+
+ status = isns_simple_call(clnt->ic_socket, &reg);
+ if (status != ISNS_SUCCESS) {
+ log_error("SCN registration for node %s failed: %s\n",
+ isns_source_name(node->source),
+ isns_strerror(status));
+ /*
+ * if the user was going to poll then ignore error
+ * since user was probably using polling because SCNs
+ * were not supported by server
+ */
+ if (poll_inval < 0) {
+ isns_cancel_refresh_timers();
+ rc = EIO;
+ break;
+ }
+ }
+ log_debug(4, "Registered %s for SCNs",
+ isns_source_name(node->source));
+ }
+
+free_reg:
+ isns_simple_free(reg);
+done:
+ return rc;
+}
+
+static int isns_scn_register(isns_socket_t *svr_sock, int poll_inval)
+{
+ isns_object_list_t objs = ISNS_OBJECT_LIST_INIT;
+ isns_portal_info_t portal_info;
+ isns_client_t *clnt;
+ int rc;
+
+ clnt = isns_create_default_client(NULL);
+ if (!clnt) {
+ log_error("iSNS setup failed. Could not connect to server.");
+ return ENOTCONN;
+ }
+ isns_socket_set_disconnect_fatal(clnt->ic_socket);
+
+ log_debug(7, "isns_scn_register");
+
+ if (!isns_socket_get_portal_info(svr_sock, &portal_info)) {
+ log_error("Could not get portal info for iSNS registration.");
+ rc = ENODEV;
+ goto destroy_clnt;
+ }
+
+ rc = isns_build_objs(&portal_info, &objs);
+ if (rc)
+ goto destroy_clnt;
+
+ rc = isns_register_objs(clnt, &objs, poll_inval);
+ isns_object_list_destroy(&objs);
+ if (!rc)
+ log_warning("iSNS: Registered network entity with EID %s with "
+ "server.", isns_entity_id);
+
+destroy_clnt:
+ isns_client_destroy(clnt);
+ return rc;
+}
+
+static isns_source_t *isns_lookup_node(char *iname)
+{
+ struct isns_node_list *node;
+
+ list_for_each_entry(node, &isns_nodes, list) {
+ if (!strcmp(iname, isns_source_name(node->source)))
+ return node->source;
+ }
+ return NULL;
+}
+
+static struct isns_node_list *isns_create_node(const char *iname)
+{
+ isns_source_t *source;
+ struct isns_node_list *node;
+
+ source = isns_source_create_iscsi(iname);
+ if (!source)
+ return NULL;
+
+ node = calloc(1, sizeof(*node));
+ if (!node) {
+ isns_source_release(source);
+ return NULL;
+ }
+ INIT_LIST_HEAD(&node->list);
+ node->source = source;
+ return node;
+}
+
+static int isns_create_node_list(const char *def_iname)
+{
+ struct iface_rec *iface, *tmp_iface;
+ struct list_head ifaces;
+ struct isns_node_list *node, *tmp_node;
+ int rc = 0;
+
+ INIT_LIST_HEAD(&ifaces);
+ iface_link_ifaces(&ifaces);
+
+ if (def_iname) {
+ node = isns_create_node(def_iname);
+ if (!node) {
+ rc = ENOMEM;
+ goto fail;
+ }
+ list_add_tail(&node->list, &isns_nodes);
+ }
+
+ list_for_each_entry(iface, &ifaces, list) {
+ if (strlen(iface->iname) &&
+ !isns_lookup_node(iface->iname)) {
+ node = isns_create_node(iface->iname);
+ if (!node) {
+ rc = ENOMEM;
+ goto fail;
}
+ list_add_tail(&node->list, &isns_nodes);
+ }
+ }
+ /* fix me */
+ rc = 0;
+ goto done;
+fail:
+ list_for_each_entry_safe(node, tmp_node, &isns_nodes, list) {
+ list_del(&node->list);
+ free(node);
+ }
+
+done:
+ list_for_each_entry_safe(iface, tmp_iface, &ifaces, list) {
+ list_del(&iface->list);
+ free(iface);
+ }
+ return rc;
+}
+
+static void isns_disc_new_portals(const char *targetname, const char *iname)
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid < 0) {
+ log_error("Could not fork process to discover new portals.");
+ return;
+ } else if (pid > 0) {
+ log_debug(1, "iSNS SCN handler for initiator %s (target %s). "
+ "pid=%d", iname, targetname, pid);
+ reap_inc();
+ return;
+ }
+
+ __isns_disc_new_portals(targetname, iname);
+ exit(0);
+}
+
+static void isns_scn_callback(isns_db_t *db, uint32_t bitmap,
+ isns_object_template_t *node_type,
+ const char *node_name, const char *dst_name)
+{
+ log_error("SCN for initiator: %s (Target: %s, Event: %s.)",
+ dst_name, node_name, isns_event_string(bitmap));
+
+ if (bitmap & ISNS_SCN_OBJECT_REMOVED_MASK) {
+ log_error("Auto removal not supported. Manually logout of "
+ "portals on %s", node_name);
+ } else if (bitmap & ISNS_SCN_OBJECT_ADDED_MASK)
+ isns_disc_new_portals(node_name, dst_name);
+}
+
+static void isns_clear_refresh_list(void)
+{
+ struct isns_refresh_data *refresh_data, *tmp_refresh;
+
+ list_for_each_entry_safe(refresh_data, tmp_refresh, &isns_refresh_list,
+ list)
+ isns_free_refresh_data(refresh_data);
+}
- log_debug(1, "%s=%s poll interval %d", addr_cfg_str,
- disc_addrs, disc_poll_invl);
+static int isns_scn_recv(isns_server_t *svr, isns_socket_t *svr_sock,
+ int poll_inval)
+{
+ isns_message_t *msg, *rsp;
+ struct timeval timeout = { 0, 0 };
+ time_t now, then, next_timeout;
+ unsigned int function;
+ int rc = 0;
+
+ log_debug(1, "isns_scn_recv");
+
+ while (1) {
- do_disc_to_addrs(disc_addrs, do_disc_and_login);
- free(disc_addrs);
+ /* reap disc/login procs */
+ reap_proc();
+ /*
+ * timer func could force a scn registration so check timers
+ * first
+ */
+ then = isns_run_timers();
+ now = time(NULL);
+ next_timeout = now + 3600;
+ if (then && then < next_timeout)
+ next_timeout = then;
+ if (isns_register_nodes) {
+ isns_clear_refresh_list();
/*
- * wait for the procs to complete, or we could
- * end up flooding the targets with pdus.
+ * it is ok to block here, because the server
+ * should have unregistered us or this is our
+ * first time registerting.
*/
- while ((pid = waitpid(0, NULL, 0)) > 0)
- log_debug(7, "disc cleaned up pid %d", pid);
+ rc = isns_scn_register(svr_sock, poll_inval);
+ if (rc) {
+ sleep(5);
+ continue;
+ }
- if (!disc_poll_invl)
+ __isns_disc_new_portals(NULL, NULL);
+ if (!poll_inval)
break;
- } while (!sleep(disc_poll_invl));
+ isns_register_nodes = 0;
+ /*
+ * the scn reg may have added timers or changed
+ * timeout values so recheck.
+ */
+ continue;
+ }
+
+ /* Determine how long we can sleep */
+ if (next_timeout <= now)
+ continue;
+ timeout.tv_sec = next_timeout - now;
+
+ if ((msg = isns_recv_message(&timeout)) == NULL)
+ continue;
- log_debug(1, "disc process done");
- exit(0);
- } else if (pid < 0)
- log_error("Fork failed (err %d - %s). Will not be able "
- "to perform discovery.\n",
- errno, strerror(errno));
- else
- need_reap();
+ function = isns_message_function(msg);
+ if (function != ISNS_STATE_CHANGE_NOTIFICATION) {
+ log_warning("Discarding unexpected %s message\n",
+ isns_function_name(function));
+ isns_message_release(msg);
+ continue;
+ }
- log_debug(1, "iSCSI discovery daemon for %s pid=%d",
- addr_cfg_str, pid);
+ if ((rsp = isns_process_message(svr, msg)) != NULL) {
+ isns_socket_t *sock = isns_message_socket(msg);
+
+ isns_socket_send(sock, rsp);
+ isns_message_release(rsp);
+ }
+
+ isns_message_release(msg);
+ }
+
+ log_debug(1, "isns_scn_recv done");
+ reap_proc();
+ return rc;
+}
+
+#define ISNS_EVENTD_PIDFILE ISNS_RUNDIR"/iscsid.isns.pid"
+#define ISNS_EVENTD_CTL ISNS_RUNDIR"/iscsid.isns.isnsctl"
+
+static int isns_eventd(const char *def_iname, char *disc_addr, int port,
+ int poll_inval)
+{
+ static isns_socket_t *svr_sock;
+ isns_server_t *svr;
+ isns_db_t *db;
+ struct isns_node_list *tmp_node, *node;
+ int rc = 0;
+
+ isns_create_node_list(def_iname);
+ if (list_empty(&isns_nodes)) {
+ log_error("iSNS registration failed. Initiatorname not set.");
+ return EINVAL;
+ }
+
+ /* use def_iname or if not set the first iface's iname for the src */
+ node = list_entry(isns_nodes.next, struct isns_node_list, list);
+ isns_assign_string(&isns_config.ic_source_name,
+ isns_source_name(node->source));
+ isns_config.ic_security = 0;
+ isns_config.ic_pidfile = ISNS_EVENTD_PIDFILE;
+ isns_config.ic_control_socket = ISNS_EVENTD_CTL;
+
+ if (discovery_isns_set_servername(disc_addr, port)) {
+ rc = ENOMEM;
+ goto fail;
+ }
+
+ isns_write_pidfile(isns_config.ic_pidfile);
+
+ db = isns_db_open(NULL);
+ if (!db) {
+ log_error("iSNS setup failed. Could not create db.");
+ rc = ENOMEM;
+ goto fail;
+ }
+ svr = isns_create_server(node->source, db, &isns_callback_service_ops);
+ if (!svr) {
+ log_error("iSNS setup failed. Could not create server.");
+ rc = ENOTCONN;
+ goto fail;
+ }
+ isns_server_set_scn_callback(svr, isns_scn_callback);
+
+ svr_sock = isns_create_server_socket(NULL, NULL, AF_INET6, SOCK_DGRAM);
+ if (!svr_sock) {
+ log_error("iSNS setup failed. Could not create server socket.");
+ rc = ENOTCONN;
+ goto fail;
+ }
+
+ rc = isns_scn_recv(svr, svr_sock, poll_inval);
+ isns_cancel_refresh_timers();
+fail:
+ isns_clear_refresh_list();
+
+ list_for_each_entry_safe(node, tmp_node, &isns_nodes, list) {
+ list_del(&node->list);
+ free(node);
+ }
+
+ if (isns_entity_id)
+ free(isns_entity_id);
+ isns_entity_id = NULL;
+
+ discovery_isns_free_servername();
+
+ if (isns_config.ic_source_name)
+ free(isns_config.ic_source_name);
+ isns_config.ic_source_name = NULL;
+ return rc;
+}
+
+static void start_isns(const char *def_iname, char *disc_addr, int port,
+ int poll_inval)
+{
+ int rc;
+
+ if (port < 0)
+ port = ISNS_DEFAULT_PORT;
+
+ rc = isns_eventd(def_iname, disc_addr, port, poll_inval);
+ log_debug(1, "start isns done %d.", rc);
}
/* SendTargets */
-static void do_st_disc_and_login(char *disc_addr, int port)
+static void __do_st_disc_and_login(char *disc_addr, int port)
{
discovery_rec_t drec;
struct list_head rec_list, setup_ifaces;
int rc, nr_found;
struct node_rec *rec, *tmp_rec;
+ struct iface_rec *iface, *tmp_iface;
INIT_LIST_HEAD(&rec_list);
INIT_LIST_HEAD(&setup_ifaces);
idbm_sendtargets_defaults(&drec.u.sendtargets);
strlcpy(drec.address, disc_addr, sizeof(drec.address));
+ if (port < 0)
+ port = ISCSI_LISTEN_PORT;
drec.port = port;
/*
- * The disc daemon will try agin in poll_interval secs
+ * The disc daemon will try again in poll_interval secs
* so no need to retry here
*/
drec.u.sendtargets.reopen_max = 0;
@@ -180,7 +1042,7 @@ static void do_st_disc_and_login(char *disc_addr, int port)
if (rc) {
log_error("Could not perform SendTargets to %s.",
disc_addr);
- return;
+ goto free_ifaces;
}
list_for_each_entry_safe(rec, tmp_rec, &rec_list, list) {
@@ -194,10 +1056,31 @@ static void do_st_disc_and_login(char *disc_addr, int port)
}
iscsi_login_portals(NULL, &nr_found, &rec_list, iscsi_login_portal);
+
+free_ifaces:
+ list_for_each_entry_safe(iface, tmp_iface, &setup_ifaces, list) {
+ list_del(&iface->list);
+ free(iface);
+ }
+}
+
+static void do_st_disc_and_login(const char *def_iname, char *disc_addr,
+ int port, int poll_inval)
+{
+ if (poll_inval < 0)
+ poll_inval = DISC_DEF_POLL_INVL;
+
+ do {
+ __do_st_disc_and_login(disc_addr, port);
+ if (!poll_inval)
+ break;
+ } while (!sleep(poll_inval));
}
-void discoveryd_start_st(void)
+void discoveryd_start(const char *def_iname)
{
- discoveryd_start(DISC_ST_ADDR_CFG_STR, DISC_ST_POLL_INVL,
- do_st_disc_and_login);
+ __discoveryd_start(def_iname, DISC_ISNS_ADDR_CFG_STR,
+ DISC_ISNS_POLL_INVL, start_isns);
+ __discoveryd_start(def_iname, DISC_ST_ADDR_CFG_STR, DISC_ST_POLL_INVL,
+ do_st_disc_and_login);
}
diff --git a/usr/discoveryd.h b/usr/discoveryd.h
index e68bd70..9437ae9 100644
--- a/usr/discoveryd.h
+++ b/usr/discoveryd.h
@@ -1,7 +1,6 @@
#ifndef _DISC_DAEMON_H
#define _DISC_DAEMON_H
-extern void discoveryd_start_st(void);
-extern void discoveryd_start_isns(void);
+extern void discoveryd_start(const char *def_iname);
#endif
diff --git a/usr/event_poll.c b/usr/event_poll.c
index 8e6d3d2..33a01b8 100644
--- a/usr/event_poll.c
+++ b/usr/event_poll.c
@@ -38,20 +38,21 @@
static int reap_count;
-void need_reap(void)
+void reap_inc(void)
{
reap_count++;
}
-static void reaper(void)
+void reap_proc(void)
{
- int rc;
+ int rc, i, max_reaps;
/*
* We don't really need reap_count, but calling wait() all the
* time seems execessive.
*/
- if (reap_count) {
+ max_reaps = reap_count;
+ for (i = 0; i < max_reaps; i++) {
rc = waitpid(0, NULL, WNOHANG);
if (rc > 0) {
reap_count--;
@@ -102,7 +103,7 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd)
}
} else
actor_poll();
- reaper();
+ reap_proc();
/*
* flush sysfs cache since kernel objs may
* have changed as a result of handling op
diff --git a/usr/event_poll.h b/usr/event_poll.h
index d1e0285..460fd46 100644
--- a/usr/event_poll.h
+++ b/usr/event_poll.h
@@ -21,7 +21,8 @@
struct iscsi_ipc;
-void need_reap(void);
+void reap_proc(void);
+void reap_inc(void);
void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd);
void event_loop_exit(void);
diff --git a/usr/idbm.c b/usr/idbm.c
index db71d12..f4b5a0f 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -1663,15 +1663,14 @@ free_portal:
}
static int idbm_bind_iface_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
- struct discovery_rec *drec,
- struct iface_rec *iface,
+ void *data, struct iface_rec *iface,
struct list_head *bound_recs)
{
struct node_rec *rec, *tmp;
struct list_head new_recs;
INIT_LIST_HEAD(&new_recs);
- if (disc_node_fn(drec, iface, &new_recs))
+ if (disc_node_fn(data, iface, &new_recs))
return ENODEV;
list_for_each_entry_safe(rec, tmp, &new_recs, list) {
@@ -1683,21 +1682,21 @@ static int idbm_bind_iface_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
}
int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
- struct discovery_rec *drec,
- struct list_head *ifaces,
+ void *data, struct list_head *ifaces,
struct list_head *bound_recs)
{
- struct iface_rec *iface, *tmp;
+ struct list_head def_ifaces;
+ struct node_rec *rec, *tmp_rec;
+ struct iface_rec *iface, *tmp_iface;
struct iscsi_transport *t;
int rc = 0, found = 0;
- if (!ifaces || list_empty(ifaces)) {
- struct list_head def_ifaces;
+ INIT_LIST_HEAD(&def_ifaces);
- INIT_LIST_HEAD(&def_ifaces);
+ if (!ifaces || list_empty(ifaces)) {
iface_link_ifaces(&def_ifaces);
- list_for_each_entry_safe(iface, tmp, &def_ifaces, list) {
+ list_for_each_entry_safe(iface, tmp_iface, &def_ifaces, list) {
list_del(&iface->list);
t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
/*
@@ -1710,11 +1709,11 @@ int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
continue;
}
- rc = idbm_bind_iface_to_nodes(disc_node_fn, drec, iface,
+ rc = idbm_bind_iface_to_nodes(disc_node_fn, data, iface,
bound_recs);
free(iface);
if (rc)
- return rc;
+ goto fail;
found = 1;
}
@@ -1722,10 +1721,9 @@ int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
if (!found) {
struct iface_rec def_iface;
- //log_error("no ifaces using default\n");
memset(&def_iface, 0, sizeof(struct iface_rec));
iface_setup_defaults(&def_iface);
- return idbm_bind_iface_to_nodes(disc_node_fn, drec,
+ return idbm_bind_iface_to_nodes(disc_node_fn, data,
&def_iface, bound_recs);
}
} else {
@@ -1739,13 +1737,25 @@ int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
continue;
}
- rc = idbm_bind_iface_to_nodes(disc_node_fn, drec, iface,
+ rc = idbm_bind_iface_to_nodes(disc_node_fn, data, iface,
bound_recs);
if (rc)
- return rc;
+ goto fail;
}
}
return 0;
+
+fail:
+ list_for_each_entry_safe(iface, tmp_iface, &def_ifaces, list) {
+ list_del(&iface->list);
+ free(iface);
+ }
+
+ list_for_each_entry_safe(rec, tmp_rec, bound_recs, list) {
+ list_del(&rec->list);
+ free(rec);
+ }
+ return rc;
}
static void idbm_rm_disc_node_links(char *disc_dir)
diff --git a/usr/idbm.h b/usr/idbm.h
index b1ed347..7417967 100644
--- a/usr/idbm.h
+++ b/usr/idbm.h
@@ -121,12 +121,10 @@ extern int idbm_delete_node(node_rec_t *rec);
extern int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec,
int overwrite);
struct list_head;
-typedef int (idbm_disc_nodes_fn)(struct discovery_rec *drec,
- struct iface_rec *iface,
+typedef int (idbm_disc_nodes_fn)(void *data, struct iface_rec *iface,
struct list_head *recs);
extern int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
- struct discovery_rec *drec,
- struct list_head *ifaces,
+ void *data, struct list_head *ifaces,
struct list_head *bound_recs);
extern int idbm_add_discovery(discovery_rec_t *newrec);
extern void idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg);
diff --git a/usr/initiator.c b/usr/initiator.c
index 80ace4b..5c7270a 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -1171,7 +1171,7 @@ static void session_scan_host(struct iscsi_session *session, int hostno,
iscsi_sysfs_set_queue_depth);
exit(0);
} else if (pid > 0) {
- need_reap();
+ reap_inc();
if (qtask) {
close(qtask->mgmt_ipc_fd);
free(qtask);
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index 50d63c4..fe9cad7 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -47,6 +47,7 @@
#include "idbm_fields.h"
#include "session_mgmt.h"
#include "iscsid_req.h"
+#include "isns-proto.h"
struct iscsi_ipc *ipc = NULL; /* dummy */
static char program_name[] = "iscsiadm";
@@ -1727,7 +1728,7 @@ main(int argc, char **argv)
strlcpy(drec.address, ip, sizeof(drec.address));
if (port < 0)
- drec.port = 3205;
+ drec.port = ISNS_DEFAULT_PORT;
else
drec.port = port;
diff --git a/usr/iscsid.c b/usr/iscsid.c
index 147b00d..fcb5eb3 100644
--- a/usr/iscsid.c
+++ b/usr/iscsid.c
@@ -494,10 +494,10 @@ int main(int argc, char *argv[])
log_error("Fork failed error %d: existing sessions"
" will not be synced", errno);
} else
- need_reap();
+ reap_inc();
increase_max_files();
- discoveryd_start_st();
+ discoveryd_start(daemon_config.initiator_name);
/* oom-killer will not kill us at the night... */
if (oom_adjust())
diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c
index f02eeb8..99543b3 100644
--- a/usr/session_mgmt.c
+++ b/usr/session_mgmt.c
@@ -41,10 +41,10 @@ static void log_login_msg(struct node_rec *rec, int rc)
rec->conn[0].port);
iscsid_handle_error(rc);
} else
- printf("Login to [iface: %s, target: %s, portal: "
- "%s,%d] successful.\n", rec->iface.name,
- rec->name, rec->conn[0].address,
- rec->conn[0].port);
+ log_warning("Login to [iface: %s, target: %s, portal: "
+ "%s,%d] successful.", rec->iface.name,
+ rec->name, rec->conn[0].address,
+ rec->conn[0].port);
}
struct iscsid_async_req {
@@ -82,9 +82,9 @@ int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec)
struct iscsid_async_req *async_req = NULL;
int rc = 0, fd;
- printf("Logging in to [iface: %s, target: %s, portal: %s,%d]\n",
- rec->iface.name, rec->name, rec->conn[0].address,
- rec->conn[0].port);
+ log_warning("Logging in to [iface: %s, target: %s, portal: %s,%d]",
+ rec->iface.name, rec->name, rec->conn[0].address,
+ rec->conn[0].port);
if (list) {
async_req = calloc(1, sizeof(*async_req));
@@ -173,10 +173,10 @@ static void log_logout_msg(struct session_info *info, int rc)
info->persistent_address, info->port);
iscsid_handle_error(rc);
} else
- printf("Logout of [sid: %d, target: %s, "
- "portal: %s,%d] successful.\n",
- info->sid, info->targetname,
- info->persistent_address, info->port);
+ log_warning("Logout of [sid: %d, target: %s, "
+ "portal: %s,%d] successful.",
+ info->sid, info->targetname,
+ info->persistent_address, info->port);
}
static int iscsid_logout_reqs_wait(struct list_head *list)
@@ -210,9 +210,10 @@ int iscsi_logout_portal(struct session_info *info, struct list_head *list)
int fd, rc;
/* TODO: add fn to add session prefix info like dev_printk */
- printf("Logging out of session [sid: %d, target: %s, portal: %s,%d]\n",
- info->sid, info->targetname, info->persistent_address,
- info->port);
+ log_warning("Logging out of session [sid: %d, target: %s, portal: "
+ "%s,%d]",
+ info->sid, info->targetname, info->persistent_address,
+ info->port);
if (list) {
async_req = calloc(1, sizeof(*async_req));
diff --git a/utils/open-isns/esi.c b/utils/open-isns/esi.c
index 3fe62ac..47d52c6 100644
--- a/utils/open-isns/esi.c
+++ b/utils/open-isns/esi.c
@@ -49,7 +49,8 @@ static ISNS_LIST_DECLARE(isns_esi_list);
static void isns_esi_transmit(void *);
static void isns_esi_sendto(isns_esi_t *, isns_esi_portal_t *);
-static void isns_process_esi_response(uint32_t, isns_simple_t *);
+static void isns_process_esi_response(uint32_t, int,
+ isns_simple_t *);
static void isns_esi_disconnect(isns_esi_portal_t *);
static void isns_esi_restart(isns_esi_portal_t *);
static void isns_esi_drop_portal(isns_esi_portal_t *, isns_db_t *, int);
@@ -465,7 +466,7 @@ isns_process_esi(isns_server_t *srv, isns_simple_t *call, isns_simple_t **reply)
}
void
-isns_process_esi_response(uint32_t xid, isns_simple_t *msg)
+isns_process_esi_response(uint32_t xid, int status, isns_simple_t *msg)
{
isns_portal_info_t portal_info;
isns_esi_portal_t *esp;
diff --git a/utils/open-isns/isns-proto.h b/utils/open-isns/isns-proto.h
index 1e2f682..fbc3376 100644
--- a/utils/open-isns/isns-proto.h
+++ b/utils/open-isns/isns-proto.h
@@ -20,6 +20,7 @@ struct isns_hdr {
#define ISNS_VERSION 0x0001
#define ISNS_MAX_PDU_SIZE 65535
+#define ISNS_DEFAULT_PORT 3205
/*
* Values for the i_flags field:
diff --git a/utils/open-isns/isns.h b/utils/open-isns/isns.h
index 73d4a45..53c22d5 100644
--- a/utils/open-isns/isns.h
+++ b/utils/open-isns/isns.h
@@ -125,7 +125,8 @@ extern int isns_simple_transmit(isns_socket_t *,
isns_simple_t *,
const isns_portal_info_t *,
unsigned int,
- void (*callback)(uint32_t, isns_simple_t *));
+ void (*callback)(uint32_t, int,
+ isns_simple_t *));
extern void isns_simple_free(isns_simple_t *);
extern const isns_attr_list_t *isns_simple_get_attrs(isns_simple_t *);
@@ -488,6 +489,7 @@ extern isns_socket_t * isns_create_bound_client_socket(const char *myaddr,
const char *hostname, const char *portname,
int af_hint, int sock_type);
extern isns_socket_t * isns_connect_to_portal(const isns_portal_info_t *);
+extern void isns_socket_set_report_failure(isns_socket_t *);
extern void isns_socket_set_disconnect_fatal(isns_socket_t *);
extern int isns_socket_get_local_addr(const isns_socket_t *,
struct sockaddr_storage *);
@@ -652,6 +654,7 @@ extern int isns_portal_equal(const isns_portal_info_t *,
const isns_portal_info_t *);
extern int isns_enumerate_portals(isns_portal_info_t *,
unsigned int);
+extern int isns_get_nr_portals(void);
/* Local registry stuff */
extern int isns_local_registry_load(const char *, pid_t, isns_object_list_t *);
diff --git a/utils/open-isns/scn.c b/utils/open-isns/scn.c
index d8fda1d..51fcba3 100644
--- a/utils/open-isns/scn.c
+++ b/utils/open-isns/scn.c
@@ -738,7 +738,7 @@ again:
* comes in, or when the message timed out.
*/
static void
-isns_process_scn_response(uint32_t xid, isns_simple_t *msg)
+isns_process_scn_response(uint32_t xid, int status, isns_simple_t *msg)
{
isns_scn_t *scn;
diff --git a/utils/open-isns/simple.c b/utils/open-isns/simple.c
index 97e181f..1af89fd 100644
--- a/utils/open-isns/simple.c
+++ b/utils/open-isns/simple.c
@@ -15,7 +15,7 @@
#include "socket.h"
#include "util.h"
-typedef void isns_simple_callback_fn_t(uint32_t, isns_simple_t *);
+typedef void isns_simple_callback_fn_t(uint32_t, int status, isns_simple_t *);
static int isns_attr_list_scanner_get_pg(struct isns_attr_list_scanner *st);
@@ -124,7 +124,7 @@ isns_simple_recv_response(isns_message_t *cmsg, isns_message_t *rmsg)
{
isns_simple_callback_fn_t *user_callback;
isns_simple_t *resp = NULL;
- int status;
+ int status = ISNS_INTERNAL_ERROR;
/* rmsg being NULL means the call timed out. */
if (rmsg == NULL)
@@ -133,15 +133,16 @@ isns_simple_recv_response(isns_message_t *cmsg, isns_message_t *rmsg)
status = isns_message_status(rmsg);
if (status != ISNS_SUCCESS) {
isns_error("Server flags error: %s (status 0x%04x)\n",
- isns_strerror(status), status);
- return;
+ isns_strerror(status), status);
+ goto callback;
}
status = isns_simple_decode(rmsg, &resp);
if (status) {
isns_error("Unable to decode server response: %s (status 0x%04x)\n",
isns_strerror(status), status);
- return;
+ resp = NULL;
+ goto callback;
}
isns_simple_print(resp, isns_debug_message);
@@ -149,8 +150,9 @@ isns_simple_recv_response(isns_message_t *cmsg, isns_message_t *rmsg)
callback:
user_callback = cmsg->im_calldata;
if (user_callback)
- user_callback(cmsg->im_xid, resp);
- isns_simple_free(resp);
+ user_callback(cmsg->im_xid, status, resp);
+ if (resp)
+ isns_simple_free(resp);
}
/*
diff --git a/utils/open-isns/socket.c b/utils/open-isns/socket.c
index f0a758b..baed13c 100644
--- a/utils/open-isns/socket.c
+++ b/utils/open-isns/socket.c
@@ -1320,6 +1320,12 @@ isns_socket_set_disconnect_fatal(isns_socket_t *sock)
sock->is_disconnect_fatal = 1;
}
+void
+isns_socket_set_report_failure(isns_socket_t *sock)
+{
+ sock->is_report_failure = 1;
+}
+
/*
* Set the socket's security context
*/
@@ -1688,17 +1694,13 @@ again:
isns_assert(!sock->is_destroy);
isns_socket_release(sock);
return msg;
-
default:
isns_message_release(msg);
+ isns_socket_release(sock);
+ return NULL;
}
}
- /* This will return 0 if the socket was marked for
- * destruction. */
- if (!isns_socket_release(sock))
- continue;
-
isns_print_socket(sock);
/* This handles reconnect, idle disconnect etc. */
@@ -1721,16 +1723,18 @@ again:
}
/* Check whether pending messages have timed out. */
- while (sock->is_state == ISNS_SOCK_IDLE
- && (msg = isns_message_queue_head(&sock->is_pending)) != NULL) {
+ while ((msg = isns_message_queue_head(&sock->is_pending)) !=
+ NULL) {
if (__timeout_expired(&now, &msg->im_timeout)) {
isns_debug_socket("sock %p message %04x timed out\n",
sock, msg->im_xid);
isns_message_unlink(msg);
if (msg == watch_msg) {
isns_message_release(msg);
+ isns_socket_release(sock);
return NULL;
}
+
isns_net_timeout(sock, msg);
continue;
}
@@ -1774,22 +1778,33 @@ again:
if (sock->is_state == ISNS_SOCK_FAILED) {
if (sock->is_disconnect_fatal)
goto kill_socket;
- if (sock->is_report_failure)
+ if (sock->is_report_failure) {
+ isns_socket_release(sock);
return NULL;
+ }
sock->is_state = ISNS_SOCK_DISCONNECTED;
+ isns_socket_release(sock);
continue;
}
if (sock->is_state == ISNS_SOCK_DEAD) {
kill_socket:
isns_list_del(&sock->is_list);
- if (sock->is_report_failure)
+ if (sock->is_report_failure) {
+ isns_socket_release(sock);
return NULL;
+ }
if (!sock->is_client)
isns_socket_free(sock);
+ isns_socket_release(sock);
continue;
}
+ /* This will return 0 if the socket was marked for
+ * destruction. */
+ if (!isns_socket_release(sock))
+ continue;
+
/* should not happen */
if (i >= max_sockets)
break;
diff --git a/utils/open-isns/sysdep-unix.c b/utils/open-isns/sysdep-unix.c
index 8c601a7..d2a9532 100644
--- a/utils/open-isns/sysdep-unix.c
+++ b/utils/open-isns/sysdep-unix.c
@@ -11,6 +11,60 @@
#include "isns.h"
#include "util.h"
+int isns_get_nr_portals(void)
+{
+ char buffer[8192], *end, *ptr;
+ struct ifconf ifc;
+ unsigned int nportals = 0;
+ int fd = -1;
+
+ if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+ isns_error("%s: no socket - %m\n", __FUNCTION__);
+ return 0;
+ }
+
+ ifc.ifc_buf = buffer;
+ ifc.ifc_len = sizeof(buffer);
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+ isns_error("ioctl(SIOCGIFCONF): %m\n");
+ goto out;
+ }
+
+ ptr = buffer;
+ end = buffer + ifc.ifc_len;
+ while (ptr < end) {
+ struct ifreq ifr;
+ struct sockaddr_storage ifaddr;
+ int ifflags;
+
+ memcpy(&ifr, ptr, sizeof(ifr));
+ ptr += sizeof(ifr);
+
+ /* Get the interface addr */
+ memcpy(&ifaddr, &ifr.ifr_addr, sizeof(ifr.ifr_addr));
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ isns_error("ioctl(%s, SIOCGIFFLAGS): %m\n",
+ ifr.ifr_name);
+ continue;
+ }
+ ifflags = ifr.ifr_flags;
+
+ if ((ifflags & IFF_UP) == 0)
+ continue;
+ if ((ifflags & IFF_LOOPBACK) != 0)
+ continue;
+
+ if (ifaddr.ss_family == AF_INET6 || ifaddr.ss_family == AF_INET)
+ nportals++;
+ }
+
+out:
+ if (fd >= 0)
+ close(fd);
+ return nportals;
+}
+
int
isns_enumerate_portals(isns_portal_info_t *result, unsigned int max)
{