isns_client.c revision aedf2b3bb56b025fcaf87b49ec6c8aeea07f16d7
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <syslog.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include <iscsitgt_impl.h>
#include "isns_protocol.h"
#include "isns_client.h"
#include "target.h"
#include "queue.h"
typedef struct {
union {
} ip_adr;
} ip_t;
#define ISNS_TGT_LOGOUT 54321
extern target_queue_t *mgmtq;
/*
* Global
* isns_args:
* eid_ip: Entity IP info
*/
static int scn_port = 0;
static esi_scn_arg_t isns_args = {{0}, {0}, 0};
static int num_reg = 0;
static int ISNS_SLEEP_SECS = 20;
static int isns_op_all(uint16_t);
static void process_esi(int, isns_pdu_t *);
static void process_scn(int, isns_pdu_t *);
static void *esi_scn_thr(void *);
static int isns_dev_attr_reg(int, tgt_node_t *, char *, char *);
static int isns_dev_attr_dereg(int, char *);
static int isns_scn_reg(int, char *);
static tgt_node_t *find_tgt_by_name(char *, char **);
static int get_addr_family(char *node);
/*
* find_tgt_by_name searches DB by iscsi name or local name, if found
* returns tgt_node_t. iname needs to be free by caller.
*/
static tgt_node_t *
{
== FALSE) {
break;
}
/* match either iscsi name or local name */
return (tgt);
}
}
return (NULL);
}
static tgt_node_t *
{
== FALSE) {
continue;
}
return (tgt);
}
return (NULL);
}
/*
* Find ip-addr associated with TPGT, don't send if no ip-addr is
* found for a TPGT
*/
static int
{
tgt_node_t *t, *x;
/* Always add the default TPGT (1) */
1);
return (-1);
}
return (-1);
}
/* Get the remainning TPGT-LIST */
!= NULL) {
/* find tgpt from tpgt-list */
!= NULL) {
/* update isns only if TPGT contains ip_addr */
continue;
break;
}
continue;
return (-1);
}
/* get ip-addr & port */
continue;
if (isns_append_attr(cmd,
return (-1);
}
if (isns_append_attr(cmd,
return (-1);
}
}
}
}
return (0);
}
/*
* process_scn()
*
* -Removed object: logout_targ if still connected
*
* RFC 4171 section 5.6.5.9
* destination attribute is always the 1st attribute in the SCN message,
* then follows by SCN_BITMAP(35) & Source_Attribute(32)
*/
static void
{
uint32_t got_source = 0;
uint32_t got_bitmap = 0;
char dest[MAXNAMELEN];
char source[MAXNAMELEN];
scn->payload_len);
return;
}
/* LINTED */
/*
* devAttrQry the source attribute, process if node_type
* is initiator
*/
case ISNS_ISCSI_NAME_ATTR_ID:
if (got_dest == 0) {
"PROCESS_SCN dest %s\n", dest);
got_dest = 1;
} else {
"PROCESS_SCN source %s\n", source);
got_source = 1;
}
break;
"PROCESS_SCN bitmap %u\n", bitmap);
got_bitmap = 1;
break;
default:
"PROCESS_SCN DEFAULT\n");
break;
}
if (got_source && !got_bitmap) {
"process_scn: message out-of-order\n");
return;
}
if (got_source && got_bitmap) {
switch (bitmap) {
case ISNS_OBJ_ADDED:
case ISNS_OBJ_UPDATED:
"PROCESS_SCN OBJ ADDED");
(void) isns_update();
break;
case ISNS_OBJ_REMOVED:
"PROCESS_SCN OBJ REMOVED");
/* logout target */
if (got_dest == 0) {
"ISNS protocol error\n");
continue;
}
break;
default:
break;
}
/* clear got_xxx */
got_source = 0;
got_bitmap = 1;
}
/* next attribute */
}
}
/*
* Process ESI requires a success response only
*/
static void
{
int pl_len;
return;
}
if (pl_len > MAX_PDU_PAYLOAD_SZ) {
return;
}
/* change the xid to the request xid */
/* copy original data */
}
}
static int
is_isns_server_up(char *server) {
int so;
/* no server specified */
return (-1);
}
/*
* open isns server connect and determine which PF_INET to use
*/
"isns server %s not found",
server);
return (-1);
}
isns_close(so);
"isns getsockname failed");
return (-1);
}
isns_close(so);
"isns unknown domain type");
return (-1);
}
return (0);
}
/*
* This thread sit's in a loop and ensures that it keeps checking for
* connection to isns_server. Once the connection works it registers
* with the isns and bails out.
* We expect the isns server to be fault taulerant and has persistence
* for the registered entries.
*/
static void *
isns_server_connection_thr(void *arg)
{
while (isns_shutdown == False &&
connection_thr_bail_out == False) {
/* current server */
if (is_isns_server_up(server) == 0) {
if (registered_targets == False) {
/*
* register all targets, what happens if
* no targets are created yet? this should
* not be a failure, when new target gets
* created, update gets call. what if SCN
* register fails?
*/
if (isns_reg_all() == 0) {
/* scn register all targets */
if (isns_op_all(ISNS_SCN_REG) != 0) {
"SCN registrations"
" failed\n");
(void) isns_op_all(
} else {
break;
}
}
}
} else {
"isns server %s is not reachable",
server);
}
(void) sleep(ISNS_SLEEP_SECS);
/* If isns was disabled, deregister and close the thread */
if (isns_enabled() == False) {
"isns server is disabled, dergister target");
isns_fini();
break;
}
}
(void *)(uintptr_t)pthread_self());
return (NULL);
}
/*
* esi_scn_thr() is the thread creates an end point to receive and process
* ESI & SCN messages. This thread is created when isns_access is enabled
* and for the duration of the iscsi daemon
*/
static void *
esi_scn_thr(void *arg)
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
char strport[NI_MAXSERV];
int socket_ready = 0;
} else {
return (NULL);
}
/*
* create and bind SCN socket
* save the scn port info
*/
return (NULL);
}
return (NULL);
}
/* get scn port info */
return (NULL);
}
NI_NUMERICSERV) != 0) {
return (NULL);
}
return (NULL);
}
/* listen for esi or scn messages */
while (isns_shutdown == False) {
/* ISNS_ESI_INTERVAL_ATTR_ID is set to 10s */
/* If disabled bail out, dont care about packets */
if (isns_enabled() == False) {
"isns server is disabled, dergister target");
isns_fini();
return (NULL);
}
if (socket_ready < 0) {
"esi_scn_thr: select failed, retrying.");
continue;
} else if (socket_ready == 0) { /* timeout */
continue;
} else {
/* Socket is ready */
continue;
}
}
/* Just return success for ESI */
case ISNS_ESI:
break;
case ISNS_SCN:
/* call the SCN process function */
break;
default:
"esi_scn_thr: Invalid funcid %d\n",
break;
}
/* free response resource */
} else {
}
}
return (NULL);
}
/*
* Perform operation on all targets
*/
static int
{
int so;
char *iname;
if (isns_server_connection_thr_running == False) {
"isns_op_all: iSNS discovery is not running."
" Check the previous iSNS initialization error.");
return (-1);
}
return (-1);
}
== FALSE) {
continue;
}
switch (op) {
case ISNS_DEV_DEREG:
"ISNS de-register failed\n");
}
num_reg = 0;
break;
case ISNS_SCN_DEREG:
"ISNS SCN de-register failed\n");
}
break;
case ISNS_SCN_REG:
"ISNS SCN register failed\n");
}
break;
case ISNS_TGT_LOGOUT:
break;
default:
break;
}
}
isns_close(so);
return (0);
}
static int
int retcode = 0;
/* get isns server info */
&isns_srv);
"The server has not been setup, "
"but enabling the isns access");
retcode = -1;
return (retcode);
}
} else {
}
*isns_port = '\0';
}
/* isns_server changed */
/* de-reg from old iSNS server if it is setup */
"Detected a new isns server, deregistering"
(void) isns_dereg_all();
/* Register with the new server */
if (isns_reg_all() == 0) {
/* scn register all targets */
if (isns_op_all(ISNS_SCN_REG) != 0) {
"SCN registrations failed\n");
(void) isns_op_all(ISNS_DEV_DEREG);
retcode = -1;
}
}
}
} else {
}
return (retcode);
}
/*
* isns_init() needs to be call before all ISNS operations.
* Save the isns_server & entity name.
* Start esi_scn_thr to receive ESI & SCN messages
*/
int
{
if (q != NULL)
mgmtq = q;
if (isns_enabled() == False)
return (0);
/* get local hostname for entity usage */
" address for ENTITY properties");
return (-1);
}
esi_scn_thr, (void *)&isns_args) !=
0) {
return (-1);
}
(void *)NULL) != 0) {
"isns_init failed to create the "
"isns connection thr");
return (-1);
}
return (0);
}
/*
* isns_update gets call on modify_admin, this is changes to
*/
int
{
/*
* If the isns thread was not started before and we are going
* enabled from disabled start the threads.
*/
if (isns_server_connection_thr_running == False) {
if (is_isns_enabled == True) {
return (-1);
} else {
return (0);
}
} else {
"isns_update: isns is disabled");
}
} else {
/*
* isns is disabled after enabled,
* log off all targets and fini isns service
*/
if (is_isns_enabled == False) {
/* pthread_join for the isns thread */
} else {
/*
* Incase the original thread is still running
* we should reap it
*/
/*
* Read the configuration file incase the server
* has changed.
*/
return (-1);
}
}
}
return (0);
}
/*
* isns_fini is called when isns access is disabled
*/
void
{
/*
* de-register all targets 1st, this prevents initiator from
* logging back in
*/
(void) isns_op_all(ISNS_SCN_DEREG);
(void) isns_op_all(ISNS_DEV_DEREG);
/* log off all targets */
(void) isns_op_all(ISNS_TGT_LOGOUT);
}
static int
get_addr_family(char *node) {
int ret;
return (-1);
}
return (ret);
}
static int
{
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
int ret;
return (-1);
}
do {
case PF_INET:
/* LINTED */
return (0);
case PF_INET6:
/* LINTED */
return (0);
default:
continue;
}
return (-1);
}
/*
* Process isns response, need to verify same transaction id, func_id
* as the isns command, the isns command is in network byte order,
* the isns response is in host byte order
*/
static int
{
/*
* Process responses:
* -verify sucessful response
* -verify match xid
* -process operating attributes
* For DevAttrReg & DevAttrQry and most isns command,
* the response func_id is command_func_id | 0x8000.
*/
"cmd failed with: status= %d xid= %d %d "\
return (-1);
}
return (0);
}
/*
* DevAttrDereg
*/
static int
{
int ret = -1;
return (-1);
}
/* add source attribute */
goto error;
}
/* add delimiter */
goto error;
}
/* add operation attributes */
goto error;
}
/* send pdu */
goto error;
}
/* get isns response */
goto error;
}
/* process response */
/*
* Keep the num_reg to a non-negative number.
* num_reg is used to keep track of whether there was
* any registration occurred or not. Deregstration should
* be followed by registration but in case dereg occurs
* and somehow it is succeeded keeping num_reg to 0 prevent
* any negative effect on subsequent registration.
*/
ret = 0;
}
/* Free all resouces here */
if (cmd)
if (rsp)
return (ret);
}
/*
* Register a new node, need to find another node that is already registered
* DevAttrReg
* RFC 4171 Section 5.6.5.5 indicated SCN-port-tag (23) needed to be
* included in the registration
* Also need to register ESI-port-tag (20) see Section 6.3.5
*/
static int
{
int ret = 0;
return (-1);
}
if (num_reg == 0) {
}
return (-1);
}
if (num_reg == 0) {
/* add new node to source attribute */
goto error;
}
} else {
/* find a registered node to use */
do {
goto error;
}
continue;
} else {
}
goto error;
}
}
/* add message key attribute */
goto error;
}
/* add delimiter */
goto error;
}
/* add operation attributes */
/* entity id */
goto error;
}
/* entity type */
goto error;
}
/*
* Register entity portal properties the 1st time
*/
if (num_reg == 0) {
/* portal ip-addr */
goto error;
}
/* portal port */
goto error;
}
/* ESI interval */
goto error;
}
/* scn port */
goto error;
}
/* esi port */
goto error;
}
}
/* iscsi node name */
goto error;
}
/* iscsi node type */
goto error;
}
/* iscsi node alias */
goto error;
}
/* PGT */
goto error;
}
/* send pdu */
goto error;
}
/* get isns response */
goto error;
}
/* process response */
num_reg++;
}
/* Free all resouces here */
if (cmd)
if (rsp)
if (src_nm)
return (ret);
}
/*
* DevAttrQry for iscsi initiator
* See RFC 4171 Sect. 5.6.5.2 for query detail
*/
static int
{
int ret = -1;
return (-1);
}
/* source attribute */
goto error;
}
/* message key attribute */
/* iscsi initiator node type */
goto error;
}
/* delimiter */
goto error;
}
/*
* operating attributes
* Query Iscsi initiator with zero length TLV operating
* attribute
*/
/* iscsi name */
0, NULL, 0) != 0) {
goto error;
}
goto error;
}
/* recv response */
goto error;
}
/* process response */
/* compare initiator name to the response, success if found */
/* subtract out status word */
while (remain > 0) {
/* LINTED */
/* debug only */
/* process tag-len-value */
/*
* let's process the data, only interested
* in iscsi name, skip everything else for
* now.
*/
break;
}
}
/* next tlv */
}
}
if (cmd)
if (rsp)
return (ret);
}
/*
* SCNReg
* See RFC 4171 Section 5.6.5.5
*/
static int
{
int ret = -1;
return (-1);
}
/* source attribute */
goto error;
}
/* message key attribute */
/* iscsi initiator node name */
goto error;
}
/* delimiter */
goto error;
}
/* SCN bitmap */
goto error;
}
goto error;
}
goto error;
}
/* process response */
ret = 0;
}
if (cmd)
if (rsp)
return (ret);
}
/*
* SCNDereg
*/
static int
{
int ret = -1;
return (-1);
}
/* source attribute */
goto error;
}
/* message key attribute */
/* iscsi initiator node name */
goto error;
}
goto error;
}
goto error;
}
goto error;
}
/* process response */
ret = 0;
}
if (cmd)
if (rsp)
return (ret);
}
/*
* isns_reg is called to register new target
*/
int
{
int so;
if (isns_server_connection_thr_running == False) {
"isns_reg: iSNS discovery is not running."
" Check the previous iSNS initialization error.");
return (-1);
}
return (-1);
}
/*
* Open targets_config and devAttrReg all nodes
*/
goto error;
}
}
}
if (iqn)
isns_close(so);
return (0);
}
/*
* Register all iscsi target nodes from the XML database
* Alway use the ISNS_FLAG_REPLACE_REG flag
*/
int
{
int so;
char *n = NULL;
char *a = NULL;
char alias[MAXNAMELEN];
char iname[MAXNAMELEN];
int ret = -1;
int tgt_cnt = 0;
if (isns_server_connection_thr_running == False) {
"isns_reg_all: iSNS discovery is not running."
" Check the previous iSNS initialization error.");
return (-1);
}
/*
* get the 1st target and use it for the source attribute
*/
== NULL) {
return (0);
}
return (-1);
}
== FALSE) {
return (-1);
}
free(n);
return (-1);
}
goto error;
}
/* source attribute */
goto error;
}
/* add message key attribute */
goto error;
}
/* add delimiter */
goto error;
}
/* entity id */
goto error;
}
/* entity type */
goto error;
}
/* portal ip-addr */
goto error;
}
/* portal port */
goto error;
}
/* ESI interval */
goto error;
}
/* scn port */
goto error;
}
/* esi port */
goto error;
}
/*
* Open targets_config and devAttrReg all nodes
*/
continue;
}
/* use this value as alias if alias is not set */
== FALSE) {
continue;
}
free(n);
/* find alias */
== TRUE) {
free(a);
}
tgt_cnt++; /* increment target count */
/* operation attributes */
goto error;
}
goto error;
}
goto error;
}
goto error;
}
}
/* send pdu */
goto error;
}
/* get isns response */
goto error;
}
/* process response */
ret = 0;
} else {
}
if (cmd)
if (rsp)
isns_close(so);
return (ret);
}
/*
* Deregister an iscsi target node
*/
int
isns_dereg(char *name)
{
int so;
int ret;
if (isns_server_connection_thr_running == False) {
"isns_dereg: iSNS discovery is not running."
" Check the previous iSNS initialization error.");
return (-1);
}
return (-1);
}
isns_close(so);
return (ret);
}
/*
* Update an existing iscsi target property
*/
int
{
int so;
int flags = 0; /* update only */
char alias[MAXNAMELEN];
int ret = -1;
if (mods == 0)
return (0);
if (isns_server_connection_thr_running == False) {
"isns_dev_update: iSNS discovery is not running."
" Check the previous iSNS initialization error.");
return (-1);
}
True) {
} else
goto error;
}
goto error;
}
/* source attr, msg key, delimiter */
goto error;
}
goto error;
}
!= 0) {
goto error;
}
/*
* get current operating attributes, alias & portal group
* objects, these should be the only things that get change
*/
if (mods & ISNS_MOD_ALIAS)
goto error;
}
if (mods & ISNS_MOD_TPGT)
goto error;
}
goto error;
}
goto error;
}
/* process response, if failed do a isns_reg_all */
if (isns_reg_all() != 0 || isns_scn_reg_all() != 0) {
goto error;
}
ret = 0;
} else {
goto error;
}
ret = 0;
}
} else {
}
if (cmd)
if (rsp)
if (iname)
isns_close(so);
return (ret);
}
/*
* Deregister all iscsi target nodes from the XML database
*/
int
{
return (isns_op_all(ISNS_DEV_DEREG));
}
int
{
return (isns_op_all(ISNS_SCN_REG));
}
int
{
return (isns_op_all(ISNS_SCN_DEREG));
}
/*
* Query an iscsi initiator node
*/
{
int so;
int ret;
if (isns_server_connection_thr_running == False) {
"isns_qry_initiator: iSNS discovery is not running"
" Check the previous iSNS initialization error.");
return (-1);
}
return (-1);
}
isns_close(so);
}
{
&isns_access);
/* get isns server info */
if (isns_access == True) {
return (True);
}
}
return (False);
}