|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iSCSI Initiator discovery daemon
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Copyright (C) 2010 Mike Christie
|
|
Packit |
eace71 |
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
* maintained by open-iscsi@googlegroups.com
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
eace71 |
* it under the terms of the GNU General Public License as published
|
|
Packit |
eace71 |
* by the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
eace71 |
* (at your option) any later version.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
eace71 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
eace71 |
* General Public License for more details.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* See the file COPYING included with this distribution for more details.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <signal.h>
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <time.h>
|
|
Packit |
eace71 |
#include <sys/types.h>
|
|
Packit |
eace71 |
#include <sys/wait.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "discovery.h"
|
|
Packit |
eace71 |
#include "idbm.h"
|
|
Packit |
eace71 |
#include "list.h"
|
|
Packit |
eace71 |
#include "iscsi_proto.h"
|
|
Packit |
eace71 |
#include "sysdeps.h"
|
|
Packit |
eace71 |
#include "log.h"
|
|
Packit |
eace71 |
#include "session_mgmt.h"
|
|
Packit |
eace71 |
#include "iscsi_util.h"
|
|
Packit |
eace71 |
#include "event_poll.h"
|
|
Packit |
eace71 |
#include "iface.h"
|
|
Packit |
eace71 |
#include "session_mgmt.h"
|
|
Packit |
eace71 |
#include "session_info.h"
|
|
Packit |
eace71 |
#include "iscsi_err.h"
|
|
Packit |
eace71 |
#include <libisns/isns-proto.h>
|
|
Packit |
eace71 |
#include <libisns/isns.h>
|
|
Packit |
eace71 |
#include <libisns/paths.h>
|
|
Packit |
eace71 |
#include <libisns/message.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define DISC_DEF_POLL_INVL 30
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static LIST_HEAD(iscsi_targets);
|
|
Packit |
eace71 |
static int stop_discoveryd;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static LIST_HEAD(isns_initiators);
|
|
Packit |
eace71 |
static LIST_HEAD(isns_refresh_list);
|
|
Packit |
eace71 |
static char *isns_entity_id = NULL;
|
|
Packit |
eace71 |
static uint32_t isns_refresh_interval;
|
|
Packit |
eace71 |
static int isns_register_nodes = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void isns_reg_refresh_by_eid_qry(void *data);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
typedef void (do_disc_and_login_fn)(const char *def_iname,
|
|
Packit |
eace71 |
struct discovery_rec *drec, int poll_inval);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int logout_session(void *data, struct list_head *list,
|
|
Packit |
eace71 |
struct session_info *info)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct list_head *rec_list = data;
|
|
Packit |
eace71 |
struct node_rec *rec;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(rec, rec_list, list) {
|
|
Packit |
eace71 |
if (iscsi_match_session(rec, info))
|
|
Packit |
eace71 |
return iscsi_logout_portal(info, list);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return -1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void discoveryd_stop(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct node_rec *rec, *tmp_rec;
|
|
Packit |
eace71 |
int nr_found = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (list_empty(&iscsi_targets))
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* User requested to just login and exit.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!stop_discoveryd)
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iscsi_logout_portals(&iscsi_targets, &nr_found, 1, logout_session);
|
|
Packit |
eace71 |
list_for_each_entry_safe(rec, tmp_rec, &iscsi_targets, list) {
|
|
Packit |
eace71 |
list_del(&rec->list);
|
|
Packit |
eace71 |
free(rec);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
exit(0);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void catch_signal(int signo)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
log_debug(1, "%d caught signal -%d...", signo, getpid());
|
|
Packit |
eace71 |
switch (signo) {
|
|
Packit |
eace71 |
case SIGTERM:
|
|
Packit |
eace71 |
stop_discoveryd = 1;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void setup_signal_handler(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct sigaction sa_old;
|
|
Packit |
eace71 |
struct sigaction sa_new;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sa_new.sa_handler = catch_signal;
|
|
Packit |
eace71 |
sigemptyset(&sa_new.sa_mask);
|
|
Packit |
eace71 |
sa_new.sa_flags = 0;
|
|
Packit |
eace71 |
sigaction(SIGTERM, &sa_new, &sa_old );
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* update_sessions - login/logout sessions
|
|
Packit |
eace71 |
* @new_rec_list: new target portals recs bound to ifaces
|
|
Packit |
eace71 |
* @targetname: if set we only update sessions for this target
|
|
Packit |
eace71 |
* @iname: if set we only update session for that initiator
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This will login/logout of portals. When it returns the recs on
|
|
Packit |
eace71 |
* new_rec_list will be freed or put on the iscsi_targets list.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* FIXME: if we are hitting a per problem this may be it. With targets
|
|
Packit |
eace71 |
* that do a target per lun this could get ugly.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static void update_sessions(struct list_head *new_rec_list,
|
|
Packit |
eace71 |
const char *targetname, const char *iname)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct node_rec *rec, *tmp_rec;
|
|
Packit |
eace71 |
struct list_head stale_rec_list;
|
|
Packit |
eace71 |
int nr_found;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&stale_rec_list);
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Check if a target portal is no longer being sent.
|
|
Packit |
eace71 |
* Note: Due to how we reread ifaces this will also detect
|
|
Packit |
eace71 |
* changes in ifaces being access through portals.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
list_for_each_entry_safe(rec, tmp_rec, &iscsi_targets, list) {
|
|
Packit |
eace71 |
log_debug(7, "Trying to match %s %s to %s %s %s",
|
|
Packit |
eace71 |
targetname, iname, rec->name, rec->conn[0].address,
|
|
Packit |
eace71 |
rec->iface.name);
|
|
Packit |
eace71 |
if (targetname && strcmp(rec->name, targetname))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (iname) {
|
|
Packit |
eace71 |
if (strlen(rec->iface.iname) &&
|
|
Packit |
eace71 |
strcmp(rec->iface.iname, iname))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
else if (strcmp(iname, isns_config.ic_source_name))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(5, "Matched %s %s, checking if in new targets.",
|
|
Packit |
eace71 |
targetname, iname);
|
|
Packit |
eace71 |
if (!idbm_find_rec_in_list(new_rec_list, rec->name,
|
|
Packit |
eace71 |
rec->conn[0].address,
|
|
Packit |
eace71 |
rec->conn[0].port, &rec->iface)) {
|
|
Packit |
eace71 |
log_debug(5, "Not found. Marking for logout");
|
|
Packit |
eace71 |
list_move_tail(&rec->list, &stale_rec_list);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry_safe(rec, tmp_rec, new_rec_list, list) {
|
|
Packit |
eace71 |
if (!iscsi_check_for_running_session(rec))
|
|
Packit |
eace71 |
iscsi_login_portal_nowait(rec);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!idbm_find_rec_in_list(&iscsi_targets, rec->name,
|
|
Packit |
eace71 |
rec->conn[0].address,
|
|
Packit |
eace71 |
rec->conn[0].port, &rec->iface)) {
|
|
Packit |
eace71 |
log_debug(5, "%s %s %s %s not on curr target list. "
|
|
Packit |
eace71 |
"Adding.", rec->name, rec->conn[0].address,
|
|
Packit |
eace71 |
rec->iface.name, rec->iface.iname);
|
|
Packit |
eace71 |
list_move_tail(&rec->list, &iscsi_targets);
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
list_del(&rec->list);
|
|
Packit |
eace71 |
free(rec);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!list_empty(&stale_rec_list)) {
|
|
Packit |
eace71 |
iscsi_logout_portals(&stale_rec_list, &nr_found, 0,
|
|
Packit |
eace71 |
logout_session);
|
|
Packit |
eace71 |
list_for_each_entry_safe(rec, tmp_rec, &stale_rec_list, list) {
|
|
Packit |
eace71 |
list_del(&rec->list);
|
|
Packit |
eace71 |
free(rec);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void fork_disc(const char *def_iname, struct discovery_rec *drec,
|
|
Packit |
eace71 |
int poll_inval, do_disc_and_login_fn *do_disc_and_login)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
pid_t pid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pid = fork();
|
|
Packit |
eace71 |
if (pid == 0) {
|
|
Packit |
eace71 |
setup_signal_handler();
|
|
Packit |
eace71 |
do_disc_and_login(def_iname, drec, poll_inval);
|
|
Packit |
eace71 |
exit(0);
|
|
Packit |
eace71 |
} else if (pid < 0)
|
|
Packit |
eace71 |
log_error("Fork failed (err %d - %s). Will not be able "
|
|
Packit |
eace71 |
"to perform discovery to %s.",
|
|
Packit |
eace71 |
errno, strerror(errno), drec->address);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
shutdown_callback(pid);
|
|
Packit |
eace71 |
log_debug(1, "iSCSI disc and login helper pid=%d", pid);
|
|
Packit |
eace71 |
reap_inc();
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct isns_node_list {
|
|
Packit |
eace71 |
isns_source_t *source;
|
|
Packit |
eace71 |
struct list_head list;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* iSNS */
|
|
Packit |
eace71 |
static int isns_build_objs(isns_portal_info_t *portal_info,
|
|
Packit |
eace71 |
isns_object_list_t *objs)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct isns_node_list *node;
|
|
Packit |
eace71 |
isns_object_t *inode, *entity;
|
|
Packit |
eace71 |
unsigned int i, nportals = 1;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "isns_build_objs");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* we currently just use all portals */
|
|
Packit |
eace71 |
if (isns_portal_is_wildcard(portal_info)) {
|
|
Packit |
eace71 |
static isns_portal_info_t *iflist;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nportals = isns_get_nr_portals();
|
|
Packit |
eace71 |
log_debug(4, "got %d portals", nportals);
|
|
Packit |
eace71 |
if (!nportals)
|
|
Packit |
eace71 |
return ISCSI_ERR_NO_OBJS_FOUND;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iflist = calloc(nportals, sizeof(isns_portal_info_t));
|
|
Packit |
eace71 |
if (!iflist) {
|
|
Packit |
eace71 |
log_error("Unable to allocate %d portals.", nportals);
|
|
Packit |
eace71 |
return ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nportals = isns_enumerate_portals(iflist, nportals);
|
|
Packit |
eace71 |
if (nportals == 0) {
|
|
Packit |
eace71 |
log_error("Unable to enumerate portals - "
|
|
Packit |
eace71 |
"no usable interfaces found");
|
|
Packit |
eace71 |
free(iflist);
|
|
Packit |
eace71 |
return ISCSI_ERR_NO_OBJS_FOUND;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
for (i = 0; i < nportals; ++i) {
|
|
Packit |
eace71 |
iflist[i].addr.sin6_port = portal_info->addr.sin6_port;
|
|
Packit |
eace71 |
iflist[i].proto = portal_info->proto;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
portal_info = iflist;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!isns_entity_id) {
|
|
Packit |
eace71 |
isns_entity_id = calloc(1, 256);
|
|
Packit |
eace71 |
if (!isns_entity_id)
|
|
Packit |
eace71 |
return ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = getnameinfo((struct sockaddr *) &portal_info->addr,
|
|
Packit |
eace71 |
sizeof(portal_info->addr),
|
|
Packit |
eace71 |
isns_entity_id, 256, NULL, 0, 0);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
free(isns_entity_id);
|
|
Packit |
eace71 |
isns_entity_id = NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_error("Could not get hostname for EID.");
|
|
Packit |
eace71 |
return ISCSI_ERR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
entity = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, isns_entity_id);
|
|
Packit |
eace71 |
if (!entity) {
|
|
Packit |
eace71 |
log_error("Could not create iSNS entity.");
|
|
Packit |
eace71 |
return ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
isns_object_list_append(objs, entity);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < nportals; ++i, ++portal_info) {
|
|
Packit |
eace71 |
isns_object_t *portal;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
portal = isns_create_portal(portal_info, entity);
|
|
Packit |
eace71 |
if (!portal) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
isns_object_list_append(objs, portal);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!isns_object_set_uint32(portal, ISNS_TAG_SCN_PORT,
|
|
Packit |
eace71 |
isns_portal_tcpudp_port(portal_info))) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_INVAL;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(node, &isns_initiators, list) {
|
|
Packit |
eace71 |
inode = isns_create_storage_node2(node->source,
|
|
Packit |
eace71 |
ISNS_ISCSI_INITIATOR_MASK,
|
|
Packit |
eace71 |
NULL);
|
|
Packit |
eace71 |
if (!inode) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
isns_object_list_append(objs, inode);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
fail:
|
|
Packit |
eace71 |
isns_object_list_destroy(objs);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct isns_qry_data {
|
|
Packit |
eace71 |
const char *iname;
|
|
Packit |
eace71 |
const char *targetname;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_query_node(void *data, struct iface_rec *iface,
|
|
Packit |
eace71 |
struct list_head *recs)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct isns_qry_data *qry_data = data;
|
|
Packit |
eace71 |
int is_def_iname = 0;
|
|
Packit |
eace71 |
const char *iname;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (qry_data->iname) {
|
|
Packit |
eace71 |
if (!strcmp(qry_data->iname, isns_config.ic_source_name))
|
|
Packit |
eace71 |
is_def_iname = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((!is_def_iname || strlen(iface->iname)) &&
|
|
Packit |
eace71 |
strcmp(iface->iname, qry_data->iname))
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iname = qry_data->iname;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
if (strlen(iface->iname))
|
|
Packit |
eace71 |
iname = iface->iname;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
iname = isns_config.ic_source_name;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return discovery_isns_query(NULL, iname, qry_data->targetname, recs);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_disc_new_portals(const char *targetname, const char *iname)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct list_head ifaces, rec_list;
|
|
Packit |
eace71 |
struct iface_rec *iface, *tmp_iface;
|
|
Packit |
eace71 |
struct isns_qry_data qry_data;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&rec_list);
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&ifaces);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
qry_data.targetname = targetname;
|
|
Packit |
eace71 |
qry_data.iname = iname;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iface_link_ifaces(&ifaces);
|
|
Packit |
eace71 |
rc = idbm_bind_ifaces_to_nodes(isns_query_node, &qry_data, &ifaces,
|
|
Packit |
eace71 |
&rec_list);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_error("Could not perform iSNS DevAttrQuery for node %s.",
|
|
Packit |
eace71 |
targetname);
|
|
Packit |
eace71 |
goto free_ifaces;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
update_sessions(&rec_list, targetname, iname);
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
free_ifaces:
|
|
Packit |
eace71 |
list_for_each_entry_safe(iface, tmp_iface, &ifaces, list) {
|
|
Packit |
eace71 |
list_del(&iface->list);
|
|
Packit |
eace71 |
free(iface);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void isns_reg_refresh_with_disc(void *data)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int retries = 0, rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(1, "Refresh registration using DevAttrQuery");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* it is ok to block here since we are not expecting SCNs
|
|
Packit |
eace71 |
* from the server.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
do {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Some servers do not support SCNs so we ping
|
|
Packit |
eace71 |
* the server by doing discovery.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
rc = isns_disc_new_portals(NULL, NULL);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_debug(4, "Registration refresh using DevAttrQuery "
|
|
Packit |
eace71 |
"failed (retires %d) err %d", retries, rc);
|
|
Packit |
eace71 |
sleep(1);
|
|
Packit |
eace71 |
retries++;
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} while (rc && retries < 3);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Try to reregister from scratch.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
isns_register_nodes = 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct isns_refresh_data {
|
|
Packit |
eace71 |
isns_client_t *clnt;
|
|
Packit |
eace71 |
isns_simple_t *qry;
|
|
Packit |
eace71 |
uint32_t xid;
|
|
Packit |
eace71 |
uint32_t interval;
|
|
Packit |
eace71 |
time_t start_time;
|
|
Packit |
eace71 |
struct list_head list;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void isns_free_refresh_data(struct isns_refresh_data *refresh_data)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
list_del(&refresh_data->list);
|
|
Packit |
eace71 |
if (refresh_data->qry)
|
|
Packit |
eace71 |
isns_simple_free(refresh_data->qry);
|
|
Packit |
eace71 |
if (refresh_data->clnt)
|
|
Packit |
eace71 |
isns_client_destroy(refresh_data->clnt);
|
|
Packit |
eace71 |
free(refresh_data);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static struct isns_refresh_data *isns_find_refresh_data(uint32_t xid)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct isns_refresh_data *refresh_data;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(refresh_data, &isns_refresh_list, list) {
|
|
Packit |
eace71 |
if (refresh_data->xid == xid)
|
|
Packit |
eace71 |
return refresh_data;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void isns_eid_qry_rsp(uint32_t xid, int status, isns_simple_t *rsp)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct isns_refresh_data *refresh_data;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
refresh_data = isns_find_refresh_data(xid);
|
|
Packit |
eace71 |
if (!refresh_data) {
|
|
Packit |
eace71 |
log_error("EID Query respond could not match xid");
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (refresh_data->clnt) {
|
|
Packit |
eace71 |
isns_client_destroy(refresh_data->clnt);
|
|
Packit |
eace71 |
refresh_data->clnt = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!rsp || status != ISNS_SUCCESS) {
|
|
Packit |
eace71 |
log_debug(1, "Registration refresh using eid qry failed: %s",
|
|
Packit |
eace71 |
isns_strerror(status));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
isns_add_oneshot_timer(2, isns_reg_refresh_by_eid_qry,
|
|
Packit |
eace71 |
refresh_data);
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(1, "eid qry successful");
|
|
Packit |
eace71 |
refresh_data->start_time = time(NULL);
|
|
Packit |
eace71 |
isns_add_oneshot_timer(isns_refresh_interval,
|
|
Packit |
eace71 |
isns_reg_refresh_by_eid_qry, refresh_data);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void isns_reg_refresh_by_eid_qry(void *data)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct isns_refresh_data *refresh_data = data;
|
|
Packit |
eace71 |
isns_attr_list_t qry_key = ISNS_ATTR_LIST_INIT;
|
|
Packit |
eace71 |
isns_simple_t *qry;
|
|
Packit |
eace71 |
isns_client_t *clnt;
|
|
Packit |
eace71 |
int status, timeout;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(1, "Refresh registration using eid qry");
|
|
Packit |
eace71 |
if (refresh_data->start_time + refresh_data->interval <= time(NULL)) {
|
|
Packit |
eace71 |
log_error("Could not refresh registration with server "
|
|
Packit |
eace71 |
"before registration period. Starting new "
|
|
Packit |
eace71 |
"registration.");
|
|
Packit |
eace71 |
isns_free_refresh_data(refresh_data);
|
|
Packit |
eace71 |
isns_register_nodes = 1;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
clnt = isns_create_default_client(NULL);
|
|
Packit |
eace71 |
if (!clnt) {
|
|
Packit |
eace71 |
log_error("iSNS registration refresh failed. Could not "
|
|
Packit |
eace71 |
"connect to server.");
|
|
Packit |
eace71 |
goto rearm;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
refresh_data->clnt = clnt;
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* if a operation has failed we will want to adjust timers
|
|
Packit |
eace71 |
* and possibly reregister.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
isns_socket_set_report_failure(clnt->ic_socket);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* if this is a retry or re-refresh then there will be a qry
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
qry = refresh_data->qry;
|
|
Packit |
eace71 |
if (qry)
|
|
Packit |
eace71 |
goto send;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
isns_attr_list_append_string(&qry_key, ISNS_TAG_ENTITY_IDENTIFIER,
|
|
Packit |
eace71 |
isns_entity_id);
|
|
Packit |
eace71 |
qry = isns_create_query(clnt, &qry_key);
|
|
Packit |
eace71 |
isns_attr_list_destroy(&qry_key);
|
|
Packit |
eace71 |
if (!qry)
|
|
Packit |
eace71 |
goto rearm;
|
|
Packit |
eace71 |
isns_query_request_attr_tag(qry, ISNS_TAG_ENTITY_PROTOCOL);
|
|
Packit |
eace71 |
refresh_data->qry = qry;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
send:
|
|
Packit |
eace71 |
timeout = (refresh_data->start_time + refresh_data->interval) -
|
|
Packit |
eace71 |
time(NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = isns_simple_transmit(clnt->ic_socket, qry, NULL,
|
|
Packit |
eace71 |
timeout, isns_eid_qry_rsp);
|
|
Packit |
eace71 |
if (status == ISNS_SUCCESS) {
|
|
Packit |
eace71 |
log_debug(7, "sent eid qry with xid %u", qry->is_xid);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
refresh_data->xid = qry->is_xid;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
rearm:
|
|
Packit |
eace71 |
if (refresh_data->clnt) {
|
|
Packit |
eace71 |
isns_client_destroy(refresh_data->clnt);
|
|
Packit |
eace71 |
refresh_data->clnt = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
log_debug(1, "Could not send eid qry to refresh registration.");
|
|
Packit |
eace71 |
isns_add_oneshot_timer(2, isns_reg_refresh_by_eid_qry, refresh_data);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_setup_registration_refresh(isns_simple_t *rsp, int poll_inval)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
isns_object_list_t objs = ISNS_OBJECT_LIST_INIT;
|
|
Packit |
eace71 |
struct isns_refresh_data *refresh_data;
|
|
Packit |
eace71 |
int status, i, rc = 0;
|
|
Packit |
eace71 |
uint32_t interval = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = isns_query_response_get_objects(rsp, &objs);
|
|
Packit |
eace71 |
if (status) {
|
|
Packit |
eace71 |
log_error("Unable to extract object list from "
|
|
Packit |
eace71 |
"registration response: %s",
|
|
Packit |
eace71 |
isns_strerror(status));
|
|
Packit |
eace71 |
return ISCSI_ERR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < objs.iol_count; ++i) {
|
|
Packit |
eace71 |
isns_object_t *obj = objs.iol_data[i];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!isns_object_is_entity(obj))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (isns_object_get_uint32(obj, ISNS_TAG_REGISTRATION_PERIOD,
|
|
Packit |
eace71 |
&interval))
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!interval)
|
|
Packit |
eace71 |
goto free_objs;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
refresh_data = calloc(1, sizeof(*refresh_data));
|
|
Packit |
eace71 |
if (!refresh_data) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
goto free_objs;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&refresh_data->list);
|
|
Packit |
eace71 |
list_add_tail(&refresh_data->list, &isns_refresh_list);
|
|
Packit |
eace71 |
refresh_data->start_time = time(NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Several servers do not support SCNs properly, so for the
|
|
Packit |
eace71 |
* registration period refresh we do a DevAttrQuery for all targets
|
|
Packit |
eace71 |
* if the poll_inval is greater than 0.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* If the target does support SCNs then we just send a query
|
|
Packit |
eace71 |
* for our entity's protocol.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* we cut in half to give us time to handle errors */
|
|
Packit |
eace71 |
isns_refresh_interval = interval / 2;
|
|
Packit |
eace71 |
if (!isns_refresh_interval) {
|
|
Packit |
eace71 |
log_warning("iSNS Registration Period only %d seconds.",
|
|
Packit |
eace71 |
interval);
|
|
Packit |
eace71 |
isns_refresh_interval = interval;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
refresh_data->interval = interval;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (poll_inval > 0) {
|
|
Packit |
eace71 |
/* user wants to override server and do disc */
|
|
Packit |
eace71 |
if (isns_refresh_interval > poll_inval)
|
|
Packit |
eace71 |
isns_refresh_interval = poll_inval;
|
|
Packit |
eace71 |
isns_add_timer(isns_refresh_interval,
|
|
Packit |
eace71 |
isns_reg_refresh_with_disc,
|
|
Packit |
eace71 |
refresh_data);
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* user wants to use server value so we just ping
|
|
Packit |
eace71 |
* with a simple qry
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
isns_add_oneshot_timer(isns_refresh_interval,
|
|
Packit |
eace71 |
isns_reg_refresh_by_eid_qry,
|
|
Packit |
eace71 |
refresh_data);
|
|
Packit |
eace71 |
log_debug(5, "Got registration period of %u "
|
|
Packit |
eace71 |
"internval. Using interval of %u",
|
|
Packit |
eace71 |
interval, isns_refresh_interval);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
free_objs:
|
|
Packit |
eace71 |
isns_flush_events();
|
|
Packit |
eace71 |
isns_object_list_destroy(&objs);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void isns_cancel_refresh_timers(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
isns_cancel_timer(isns_reg_refresh_with_disc, NULL);
|
|
Packit |
eace71 |
isns_cancel_timer(isns_reg_refresh_by_eid_qry, NULL);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_register_objs(isns_client_t *clnt, isns_object_list_t *objs,
|
|
Packit |
eace71 |
int poll_inval)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct isns_node_list *node;
|
|
Packit |
eace71 |
isns_object_t *entity = NULL;
|
|
Packit |
eace71 |
isns_simple_t *reg;
|
|
Packit |
eace71 |
unsigned int i;
|
|
Packit |
eace71 |
int status, rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "isns_register_objs");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < objs->iol_count; ++i) {
|
|
Packit |
eace71 |
if (isns_object_is_entity(objs->iol_data[i])) {
|
|
Packit |
eace71 |
entity = objs->iol_data[i];
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
reg = isns_create_registration(clnt, entity);
|
|
Packit |
eace71 |
if (!reg)
|
|
Packit |
eace71 |
return ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < objs->iol_count; ++i)
|
|
Packit |
eace71 |
isns_registration_add_object(reg, objs->iol_data[i]);
|
|
Packit |
eace71 |
isns_registration_set_replace(reg, 1);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = isns_simple_call(clnt->ic_socket, ®);
|
|
Packit |
eace71 |
if (status != ISNS_SUCCESS) {
|
|
Packit |
eace71 |
log_error("Could not register with iSNS server: %s",
|
|
Packit |
eace71 |
isns_strerror(status));
|
|
Packit |
eace71 |
rc = ISCSI_ERR;
|
|
Packit |
eace71 |
goto free_reg;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
log_debug(4, "Registered objs");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!poll_inval)
|
|
Packit |
eace71 |
goto free_reg;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = isns_setup_registration_refresh(reg, poll_inval);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto free_reg;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(node, &isns_initiators, list) {
|
|
Packit |
eace71 |
isns_simple_free(reg);
|
|
Packit |
eace71 |
reg = isns_create_scn_registration2(clnt,
|
|
Packit |
eace71 |
ISNS_SCN_OBJECT_UPDATED_MASK |
|
|
Packit |
eace71 |
ISNS_SCN_OBJECT_ADDED_MASK |
|
|
Packit |
eace71 |
ISNS_SCN_OBJECT_REMOVED_MASK |
|
|
Packit |
eace71 |
ISNS_SCN_TARGET_AND_SELF_ONLY_MASK,
|
|
Packit |
eace71 |
node->source);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!reg) {
|
|
Packit |
eace71 |
isns_cancel_refresh_timers();
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = isns_simple_call(clnt->ic_socket, ®);
|
|
Packit |
eace71 |
if (status != ISNS_SUCCESS) {
|
|
Packit |
eace71 |
log_error("SCN registration for node %s failed: %s",
|
|
Packit |
eace71 |
isns_source_name(node->source),
|
|
Packit |
eace71 |
isns_strerror(status));
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* if the user was going to poll then ignore error
|
|
Packit |
eace71 |
* since user was probably using polling because SCNs
|
|
Packit |
eace71 |
* were not supported by server
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (poll_inval < 0) {
|
|
Packit |
eace71 |
isns_cancel_refresh_timers();
|
|
Packit |
eace71 |
rc = ISCSI_ERR;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
log_debug(4, "Registered %s for SCNs",
|
|
Packit |
eace71 |
isns_source_name(node->source));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
free_reg:
|
|
Packit |
eace71 |
isns_simple_free(reg);
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_scn_register(isns_socket_t *svr_sock, int poll_inval)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
isns_object_list_t objs = ISNS_OBJECT_LIST_INIT;
|
|
Packit |
eace71 |
isns_portal_info_t portal_info;
|
|
Packit |
eace71 |
isns_client_t *clnt;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
clnt = isns_create_default_client(NULL);
|
|
Packit |
eace71 |
if (!clnt) {
|
|
Packit |
eace71 |
log_error("iSNS setup failed. Could not connect to server.");
|
|
Packit |
eace71 |
return ISCSI_ERR_TRANS;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
isns_socket_set_disconnect_fatal(clnt->ic_socket);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "isns_scn_register");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!isns_socket_get_portal_info(svr_sock, &portal_info)) {
|
|
Packit |
eace71 |
log_error("Could not get portal info for iSNS registration.");
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NO_OBJS_FOUND;
|
|
Packit |
eace71 |
goto destroy_clnt;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = isns_build_objs(&portal_info, &objs);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto destroy_clnt;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = isns_register_objs(clnt, &objs, poll_inval);
|
|
Packit |
eace71 |
isns_object_list_destroy(&objs);
|
|
Packit |
eace71 |
if (!rc)
|
|
Packit |
eace71 |
log_warning("iSNS: Registered network entity with EID %s with "
|
|
Packit |
eace71 |
"server.", isns_entity_id);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
destroy_clnt:
|
|
Packit |
eace71 |
isns_client_destroy(clnt);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static isns_source_t *isns_lookup_node(char *iname)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct isns_node_list *node;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(node, &isns_initiators, list) {
|
|
Packit |
eace71 |
if (!strcmp(iname, isns_source_name(node->source)))
|
|
Packit |
eace71 |
return node->source;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static struct isns_node_list *isns_create_node(const char *iname)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
isns_source_t *source;
|
|
Packit |
eace71 |
struct isns_node_list *node;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
source = isns_source_create_iscsi(iname);
|
|
Packit |
eace71 |
if (!source)
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
node = calloc(1, sizeof(*node));
|
|
Packit |
eace71 |
if (!node) {
|
|
Packit |
eace71 |
isns_source_release(source);
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&node->list);
|
|
Packit |
eace71 |
node->source = source;
|
|
Packit |
eace71 |
return node;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_create_node_list(const char *def_iname)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iface_rec *iface, *tmp_iface;
|
|
Packit |
eace71 |
struct list_head ifaces;
|
|
Packit |
eace71 |
struct isns_node_list *node, *tmp_node;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&ifaces);
|
|
Packit |
eace71 |
iface_link_ifaces(&ifaces);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (def_iname) {
|
|
Packit |
eace71 |
node = isns_create_node(def_iname);
|
|
Packit |
eace71 |
if (!node) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
list_add_tail(&node->list, &isns_initiators);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(iface, &ifaces, list) {
|
|
Packit |
eace71 |
if (strlen(iface->iname) &&
|
|
Packit |
eace71 |
!isns_lookup_node(iface->iname)) {
|
|
Packit |
eace71 |
node = isns_create_node(iface->iname);
|
|
Packit |
eace71 |
if (!node) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
list_add_tail(&node->list, &isns_initiators);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
/* fix me */
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
fail:
|
|
Packit |
eace71 |
list_for_each_entry_safe(node, tmp_node, &isns_initiators, list) {
|
|
Packit |
eace71 |
list_del(&node->list);
|
|
Packit |
eace71 |
free(node);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
list_for_each_entry_safe(iface, tmp_iface, &ifaces, list) {
|
|
Packit |
eace71 |
list_del(&iface->list);
|
|
Packit |
eace71 |
free(iface);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void isns_scn_callback(isns_db_t *db, uint32_t bitmap,
|
|
Packit |
eace71 |
isns_object_template_t *node_type,
|
|
Packit |
eace71 |
const char *node_name, const char *dst_name)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
log_error("SCN for initiator: %s (Target: %s, Event: %s.)",
|
|
Packit |
eace71 |
dst_name, node_name, isns_event_string(bitmap));
|
|
Packit |
eace71 |
isns_disc_new_portals(node_name, dst_name);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void isns_clear_refresh_list(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct isns_refresh_data *refresh_data, *tmp_refresh;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry_safe(refresh_data, tmp_refresh, &isns_refresh_list,
|
|
Packit |
eace71 |
list)
|
|
Packit |
eace71 |
isns_free_refresh_data(refresh_data);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_scn_recv(isns_server_t *svr, isns_socket_t *svr_sock,
|
|
Packit |
eace71 |
int poll_inval)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
isns_message_t *msg, *rsp;
|
|
Packit |
eace71 |
struct timeval timeout = { 0, 0 };
|
|
Packit |
eace71 |
time_t now, then, next_timeout;
|
|
Packit |
eace71 |
unsigned int function;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(1, "isns_scn_recv");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (!stop_discoveryd) {
|
|
Packit |
eace71 |
/* reap disc/login procs */
|
|
Packit |
eace71 |
reap_proc();
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* timer func could force a scn registration so check timers
|
|
Packit |
eace71 |
* first
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
then = isns_run_timers();
|
|
Packit |
eace71 |
now = time(NULL);
|
|
Packit |
eace71 |
next_timeout = now + 3600;
|
|
Packit |
eace71 |
if (then && then < next_timeout)
|
|
Packit |
eace71 |
next_timeout = then;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (isns_register_nodes) {
|
|
Packit |
eace71 |
isns_clear_refresh_list();
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* it is ok to block here, because the server
|
|
Packit |
eace71 |
* should have unregistered us or this is our
|
|
Packit |
eace71 |
* first time registerting.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
rc = isns_scn_register(svr_sock, poll_inval);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
sleep(5);
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
isns_disc_new_portals(NULL, NULL);
|
|
Packit |
eace71 |
if (!poll_inval)
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
isns_register_nodes = 0;
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* the scn reg may have added timers or changed
|
|
Packit |
eace71 |
* timeout values so recheck.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Determine how long we can sleep */
|
|
Packit |
eace71 |
if (next_timeout <= now)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
timeout.tv_sec = next_timeout - now;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((msg = isns_recv_message(&timeout)) == NULL)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
function = isns_message_function(msg);
|
|
Packit |
eace71 |
if (function != ISNS_STATE_CHANGE_NOTIFICATION) {
|
|
Packit |
eace71 |
log_warning("Discarding unexpected %s message",
|
|
Packit |
eace71 |
isns_function_name(function));
|
|
Packit |
eace71 |
isns_message_release(msg);
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rsp = isns_process_message(svr, msg)) != NULL) {
|
|
Packit |
eace71 |
isns_socket_t *sock = isns_message_socket(msg);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
isns_socket_send(sock, rsp);
|
|
Packit |
eace71 |
isns_message_release(rsp);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
isns_message_release(msg);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(1, "isns_scn_recv done");
|
|
Packit |
eace71 |
reap_proc();
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define ISNS_EVENTD_PIDFILE ISNS_RUNDIR"/iscsid.isns.pid"
|
|
Packit |
eace71 |
#define ISNS_EVENTD_CTL ISNS_RUNDIR"/iscsid.isns.isnsctl"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_eventd(const char *def_iname, char *disc_addr, int port,
|
|
Packit |
eace71 |
int poll_inval)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
static isns_socket_t *svr_sock;
|
|
Packit |
eace71 |
isns_server_t *svr;
|
|
Packit |
eace71 |
isns_db_t *db;
|
|
Packit |
eace71 |
struct isns_node_list *tmp_node, *node;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
isns_create_node_list(def_iname);
|
|
Packit |
eace71 |
if (list_empty(&isns_initiators)) {
|
|
Packit |
eace71 |
log_error("iSNS registration failed. Initiatorname not set.");
|
|
Packit |
eace71 |
return ISCSI_ERR_INVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* use def_iname or if not set the first iface's iname for the src */
|
|
Packit |
eace71 |
node = list_entry(isns_initiators.next, struct isns_node_list, list);
|
|
Packit |
eace71 |
isns_assign_string(&isns_config.ic_source_name,
|
|
Packit |
eace71 |
isns_source_name(node->source));
|
|
Packit |
eace71 |
isns_config.ic_security = 0;
|
|
Packit |
eace71 |
isns_config.ic_pidfile = ISNS_EVENTD_PIDFILE;
|
|
Packit |
eace71 |
isns_config.ic_control_socket = ISNS_EVENTD_CTL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (discovery_isns_set_servername(disc_addr, port)) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
isns_write_pidfile(isns_config.ic_pidfile);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
db = isns_db_open(NULL);
|
|
Packit |
eace71 |
if (!db) {
|
|
Packit |
eace71 |
log_error("iSNS setup failed. Could not create db.");
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
svr = isns_create_server(node->source, db, &isns_callback_service_ops);
|
|
Packit |
eace71 |
if (!svr) {
|
|
Packit |
eace71 |
log_error("iSNS setup failed. Could not create server.");
|
|
Packit |
eace71 |
rc = ISCSI_ERR_TRANS;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
isns_server_set_scn_callback(svr, isns_scn_callback);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
svr_sock = isns_create_server_socket(NULL, NULL, AF_INET6, SOCK_DGRAM);
|
|
Packit |
eace71 |
if (!svr_sock) {
|
|
Packit |
eace71 |
log_error("iSNS setup failed. Could not create server socket.");
|
|
Packit |
eace71 |
rc = ISCSI_ERR_TRANS;
|
|
Packit |
eace71 |
goto fail;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = isns_scn_recv(svr, svr_sock, poll_inval);
|
|
Packit |
eace71 |
isns_cancel_refresh_timers();
|
|
Packit |
eace71 |
fail:
|
|
Packit |
eace71 |
isns_clear_refresh_list();
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry_safe(node, tmp_node, &isns_initiators, list) {
|
|
Packit |
eace71 |
list_del(&node->list);
|
|
Packit |
eace71 |
free(node);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (isns_entity_id)
|
|
Packit |
eace71 |
free(isns_entity_id);
|
|
Packit |
eace71 |
isns_entity_id = NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
discovery_isns_free_servername();
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (isns_config.ic_source_name)
|
|
Packit |
eace71 |
free(isns_config.ic_source_name);
|
|
Packit |
eace71 |
isns_config.ic_source_name = NULL;
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void start_isns(const char *def_iname, struct discovery_rec *drec,
|
|
Packit |
eace71 |
int poll_inval)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc, port = drec->port;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (port < 0)
|
|
Packit |
eace71 |
port = ISNS_DEFAULT_PORT;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = isns_eventd(def_iname, drec->address, port, poll_inval);
|
|
Packit |
eace71 |
log_debug(1, "start isns done %d.", rc);
|
|
Packit |
eace71 |
discoveryd_stop();
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* SendTargets */
|
|
Packit |
eace71 |
static void __do_st_disc_and_login(struct discovery_rec *drec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct list_head rec_list, setup_ifaces;
|
|
Packit |
eace71 |
struct iface_rec *iface, *tmp_iface;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&rec_list);
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&setup_ifaces);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* The disc daemon will try again in poll_interval secs
|
|
Packit |
eace71 |
* so no need to retry here
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
drec->u.sendtargets.reopen_max = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iface_link_ifaces(&setup_ifaces);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = idbm_bind_ifaces_to_nodes(discovery_sendtargets, drec,
|
|
Packit |
eace71 |
&setup_ifaces, &rec_list);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_error("Could not perform SendTargets to %s:%d.",
|
|
Packit |
eace71 |
drec->address, drec->port);
|
|
Packit |
eace71 |
goto free_ifaces;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
update_sessions(&rec_list, NULL, NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
free_ifaces:
|
|
Packit |
eace71 |
list_for_each_entry_safe(iface, tmp_iface, &setup_ifaces, list) {
|
|
Packit |
eace71 |
list_del(&iface->list);
|
|
Packit |
eace71 |
free(iface);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void do_st_disc_and_login(const char *def_iname,
|
|
Packit |
eace71 |
struct discovery_rec *drec, int poll_inval)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (poll_inval < 0)
|
|
Packit |
eace71 |
poll_inval = DISC_DEF_POLL_INVL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
do {
|
|
Packit |
eace71 |
__do_st_disc_and_login(drec);
|
|
Packit |
eace71 |
if (!poll_inval)
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
} while (!stop_discoveryd && !sleep(poll_inval));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
discoveryd_stop();
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int st_start(void *data, struct discovery_rec *drec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
log_debug(1, "st_start %s:%d %d", drec->address, drec->port,
|
|
Packit |
eace71 |
drec->u.sendtargets.use_discoveryd);
|
|
Packit |
eace71 |
if (!drec->u.sendtargets.use_discoveryd)
|
|
Packit |
eace71 |
return ISCSI_ERR_INVAL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fork_disc(NULL, drec, drec->u.sendtargets.discoveryd_poll_inval,
|
|
Packit |
eace71 |
do_st_disc_and_login);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void discoveryd_st_start(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
idbm_for_each_st_drec(NULL, st_start);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int isns_start(void *data, struct discovery_rec *drec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
log_debug(1, "isns_start %s:%d %d", drec->address, drec->port,
|
|
Packit |
eace71 |
drec->u.isns.use_discoveryd);
|
|
Packit |
eace71 |
if (!drec->u.isns.use_discoveryd)
|
|
Packit |
eace71 |
return ISCSI_ERR_INVAL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fork_disc(data, drec, drec->u.isns.discoveryd_poll_inval, start_isns);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void discoveryd_isns_start(const char *def_iname)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
idbm_for_each_isns_drec((void *)def_iname, isns_start);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void discoveryd_start(const char *def_iname)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
discoveryd_isns_start(def_iname);
|
|
Packit |
eace71 |
discoveryd_st_start();
|
|
Packit |
eace71 |
}
|