Mercurial > illumos > onarm
view usr/src/cmd/iscsi/iscsitgtd/isns_client.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
line wrap: on
line source
/* * 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 * or http://www.opensolaris.org/os/licensing. * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #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 <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <iscsitgt_impl.h> #include "isns_protocol.h" #include "isns_client.h" #include "target.h" #include "queue.h" typedef struct { uint32_t pf_family; uint32_t ip_len; uint32_t ai_addrlen; union { in_addr_t in; in6_addr_t in6; } ip_adr; } ip_t; #define ISNS_TGT_LOGOUT 54321 extern target_queue_t *mgmtq; /* * Global * Parameters for ESI/SCN processing. * scn_port: ESI/SCN port to receive ISNS_ESI & ISNS_SCN messages * isns_args: * eid_ip: Entity IP info */ static int scn_port = 0; static esi_scn_arg_t isns_args; static ip_t eid_ip; static int num_reg = 0; static pthread_t scn_tid = 0; static Boolean_t isns_shutdown = False; Boolean_t isns_initialized = False; sema_t isns_sema; target_queue_t *mgmtq = NULL; static int get_ip_addr(char *node, ip_t *sa); static int isns_op_all(uint16_t); static int append_tpgt(tgt_node_t *, isns_pdu_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 process_rsp(isns_pdu_t *, isns_rsp_t *); 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 int isns_scn_dereg(int so, char *node); static tgt_node_t *find_tgt_by_name(char *, char **); static tgt_node_t *find_next_tgt(tgt_node_t *, char **); /* * 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 * find_tgt_by_name(char *targ, char **iname) { tgt_node_t *tgt = NULL; while ((tgt = tgt_node_next(targets_config, XML_ELEMENT_TARG, tgt)) != NULL) { if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname) == FALSE) { syslog(LOG_ALERT, "ISNS: Missing iscsi name\n"); break; } /* match either iscsi name or local name */ if (strcmp(targ, tgt->x_value) == 0 || strcmp(targ, *iname) == 0) { return (tgt); } free(*iname); } return (NULL); } static tgt_node_t * find_next_tgt(tgt_node_t *tgt, char **iname) { while ((tgt = tgt_node_next(targets_config, XML_ELEMENT_TARG, tgt)) != NULL) { if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname) == 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 append_tpgt(tgt_node_t *tgt, isns_pdu_t *cmd) { tgt_node_t *t, *x; tgt_node_t *pgt = NULL; tgt_node_t *ip = NULL; tgt_node_t *tpgt = NULL; ip_t eid; /* Always add the default TPGT (1) */ isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID, ISNS_PG_TAG_SZ, NULL, 1); if (isns_append_attr(cmd, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr, eid_ip.ip_len) != 0) { return (-1); } if (isns_append_attr(cmd, ISNS_PG_PORTAL_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, iscsi_port) != 0) { return (-1); } /* Get the remainning TPGT-LIST */ if ((t = tgt_node_next(tgt, XML_ELEMENT_TPGTLIST, NULL)) != NULL) { /* find tgpt from tpgt-list */ while ((pgt = tgt_node_next(t, XML_ELEMENT_TPGT, pgt)) != NULL) { /* update isns only if TPGT contains ip_addr */ while ((tpgt = tgt_node_next(main_config, XML_ELEMENT_TPGT, tpgt)) != NULL) { if (strcmp(pgt->x_value, tpgt->x_value) != 0) continue; if ((ip = tgt_node_next(tpgt, XML_ELEMENT_IPADDR, NULL)) != NULL) break; } if (tpgt == NULL || ip == NULL) continue; if (isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID, ISNS_PG_TAG_SZ, NULL, strtol(pgt->x_value, NULL, 0)) != 0) { return (-1); } /* get ip-addr & port */ for (x = tpgt->x_child; x; x = x->x_sibling) { get_ip_addr(x->x_value, &eid); if (isns_append_attr(cmd, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, eid.ai_addrlen, (void *)&eid.ip_adr, eid.ip_len) != 0) { return (-1); } if (isns_append_attr(cmd, ISNS_PG_PORTAL_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, iscsi_port) != 0) { return (-1); } } } } return (0); } /* * process_scn() * -Added/Updated object: nop, initiator is verified during connect * * -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 process_scn(int so, isns_pdu_t *scn) { uint8_t *ptr = scn->payload; isns_tlv_t *tlv; uint16_t cnt = 0; uint32_t got_dest = 0; uint32_t got_source = 0; uint32_t bitmap = 0; uint32_t got_bitmap = 0; char dest[MAXNAMELEN]; char source[MAXNAMELEN]; queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u\n", scn->payload_len); if (scn->payload_len < TAG_LEN_SZ) { syslog(LOG_ALERT, "ISNS SCN message error\n"); return; } while (cnt < scn->payload_len) { /* LINTED */ tlv = (isns_tlv_t *)ptr; tlv->attr_id = ntohl(tlv->attr_id); tlv->attr_len = ntohl(tlv->attr_len); queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u %u\n", tlv->attr_id, tlv->attr_len); /* * devAttrQry the source attribute, process if node_type * is initiator */ switch (tlv->attr_id) { case ISNS_ISCSI_NAME_ATTR_ID: if (got_dest == 0) { bcopy(tlv->attr_value, dest, tlv->attr_len); queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN dest %s\n", dest); got_dest = 1; } else { bcopy(tlv->attr_value, source, tlv->attr_len); queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN source %s\n", source); got_source = 1; } break; case ISNS_ISCSI_SCN_BITMAP_ATTR_ID: bcopy(tlv->attr_value, &bitmap, tlv->attr_len); bitmap = ntohl(bitmap); queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN bitmap %u\n", bitmap); got_bitmap = 1; break; default: queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN DEFAULT\n"); break; } if (got_source && !got_bitmap) { queue_prt(mgmtq, Q_ISNS_DBG, "process_scn: message out-of-order\n"); return; } if (got_source && got_bitmap) { switch (bitmap) { case ISNS_OBJ_ADDED: case ISNS_OBJ_UPDATED: queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN OBJ ADDED"); isns_update(); break; case ISNS_OBJ_REMOVED: queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN OBJ REMOVED"); /* logout target */ if (got_dest == 0) { syslog(LOG_ALERT, "ISNS protocol error\n"); continue; } logout_targ(dest); break; default: break; } /* clear got_xxx */ got_source = 0; got_bitmap = 1; } /* next attribute */ cnt += ISNS_ATTR_SZ(tlv->attr_len); ptr += ISNS_ATTR_SZ(tlv->attr_len); } queue_prt(mgmtq, Q_ISNS_DBG, "DONE PROCESS_SCN\n"); } /* * Process ESI requires a success response only */ static void process_esi(int so, isns_pdu_t *esi) { isns_rsp_t *cmd; int pl_len; if (isns_create_pdu(ISNS_ESI_RSP, 0, (isns_pdu_t **)&cmd) != 0) { return; } pl_len = esi->payload_len + ISNS_STATUS_SZ; if (pl_len > MAX_PDU_PAYLOAD_SZ) { syslog(LOG_ALERT, "process_esi: payload size exceeded"); isns_free_pdu(cmd); return; } /* change the xid to the request xid */ cmd->xid = htons(esi->xid); cmd->status = htonl(ISNS_RSP_SUCCESSFUL); /* copy original data */ bcopy(esi->payload, cmd->data, esi->payload_len); cmd->pdu_len = htons(pl_len); if (isns_send(so, (isns_pdu_t *)cmd) < 0) { syslog(LOG_ALERT, "process_esi failed to isns_send"); } isns_free_pdu(cmd); } /* * 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 sa, *ai; struct sockaddr_in sin; struct sockaddr_in6 sin6; int so, fd; socklen_t len; char strport[NI_MAXSERV]; int pf; esi_scn_arg_t *args = (esi_scn_arg_t *)arg; isns_pdu_t *scn = NULL; /* * open isns server connect and determine which PF_INET * to use */ if ((so = isns_open(args->server)) < 0) { syslog(LOG_ERR, "esi_scn_thr: isns server %s not found", args->server); return (NULL); } len = sizeof (sa); if (getsockname(so, &sa, &len) < 0) { isns_close(so); syslog(LOG_ALERT, "getsockname failed"); return (NULL); } pf = sa.sa_family; isns_close(so); if (pf != PF_INET && pf != PF_INET6) { syslog(LOG_ERR, "esi_scn_thr: unknown domain type"); return (NULL); } /* * create and bind SCN socket * save the scn port info */ if ((so = socket(pf, SOCK_STREAM, 0)) == -1) { syslog(LOG_ALERT, "socket failed"); return (NULL); } if (pf == PF_INET) { bzero(&sin, sizeof (sin)); sin.sin_family = PF_INET; sin.sin_port = htons(0); sin.sin_addr.s_addr = INADDR_ANY; ai = (struct sockaddr *)&sin; len = sizeof (sin); } else { bzero(&sin6, sizeof (sin6)); sin6.sin6_family = PF_INET6; sin6.sin6_port = htons(0); sin6.sin6_addr = in6addr_any; ai = (struct sockaddr *)&sin6; len = sizeof (sin6); } (void) setsockopt(so, SOL_SOCKET, SO_REUSEADDR, 0, 0); if (bind(so, ai, len) < 0) { syslog(LOG_ALERT, "esi_scn_thr: bind failed"); return (NULL); } /* get scn port info */ len = sizeof (sa); if (getsockname(so, &sa, &len) < 0) { syslog(LOG_ALERT, "getsockname failed"); return (NULL); } if (getnameinfo(&sa, len, NULL, 0, strport, NI_MAXSERV, NI_NUMERICSERV) != 0) { syslog(LOG_ALERT, "getnameinfo failed"); return (NULL); } scn_port = atoi(strport); sema_post(&isns_sema); if (listen(so, 5) < 0) { syslog(LOG_ALERT, "esi_scn_thr: failed listen"); return (NULL); } /* listen for esi or scn messages */ while (isns_shutdown == False) { if ((fd = accept(so, &sa, &len)) < 0) { syslog(LOG_ALERT, "esi_scn_thr: failed accept"); continue; } if (isns_recv(fd, (isns_rsp_t **)&scn) == 0) { /* Just return success for ESI */ switch (scn->func_id) { case ISNS_ESI: process_esi(fd, scn); break; case ISNS_SCN: /* call the SCN process function */ process_scn(fd, scn); break; default: syslog(LOG_ERR, "esi_scn_thr: Invalid funcid %d\n", scn->func_id); break; } /* free response resource */ isns_free_pdu(scn); } else { syslog(LOG_ALERT, "esi_scn_thr fails isns_recv "); } close(fd); } return (NULL); } /* * Perform operation on all targets */ static int isns_op_all(uint16_t op) { int so; tgt_node_t *tgt = NULL; char *iname; if ((so = isns_open(isns_args.server)) == -1) { syslog(LOG_ERR, "isns_reg failed"); return (-1); } while ((tgt = tgt_node_next(targets_config, XML_ELEMENT_TARG, tgt)) != NULL) { if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &iname) == FALSE) { continue; } switch (op) { case ISNS_DEV_DEREG: if (isns_dev_attr_dereg(so, iname) == -1) { syslog(LOG_ERR, "ISNS de-register failed\n"); } num_reg = 0; break; case ISNS_SCN_DEREG: if (isns_scn_dereg(so, iname) == -1) { syslog(LOG_ERR, "ISNS SCN de-register failed\n"); } break; case ISNS_SCN_REG: if (isns_scn_reg(so, iname) == -1) { syslog(LOG_ERR, "ISNS SCN register failed\n"); } break; case ISNS_TGT_LOGOUT: logout_targ(iname); break; default: break; } free(iname); } isns_close(so); return (0); } /* * 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 isns_init(target_queue_t *q) { char *isns_srv, *isns_port; if (q != NULL) mgmtq = q; if (isns_enabled() == False) return (0); /* initialize */ sema_init(&isns_sema, 0, USYNC_THREAD, NULL); /* get isns server info */ tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV, &isns_srv); isns_port = strchr(isns_srv, ':'); if (isns_port == NULL) { isns_args.isns_port = ISNS_DEFAULT_SERVER_PORT; } else { isns_args.isns_port = strtoul(isns_port + 1, NULL, 0); if (isns_args.isns_port == 0) { isns_args.isns_port = ISNS_DEFAULT_SERVER_PORT; } *isns_port = '\0'; } bcopy(isns_srv, isns_args.server, MAXHOSTNAMELEN); free(isns_srv); /* get local hostname for entity usage */ if ((gethostname(isns_args.entity, MAXHOSTNAMELEN) < 0) || (get_ip_addr(isns_args.entity, &eid_ip) < 0)) { syslog(LOG_ERR, "ISNS fails to get ENTITY properties"); return (-1); } if (pthread_create(&scn_tid, NULL, esi_scn_thr, (void *)&isns_args) != 0) { syslog(LOG_ALERT, "isns_init failed to pthread_create"); return (-1); } if (sema_wait(&isns_sema) != 0) { syslog(LOG_ERR, "sema_wait error\n"); } isns_initialized = True; /* * 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) { syslog(LOG_ERR, "SCN registrations failed\n"); isns_op_all(ISNS_DEV_DEREG); return (-1); } } return (0); } /* * isns_update gets call on modify_admin, this is changes to * isns access and/or isns server */ int isns_update() { char *isns_srv = NULL, *isns_port; if (isns_initialized == False) { /* isns enabled after iscsi started */ if (isns_enabled() == True) { isns_init(NULL); } return (0); } /* * isns is disabled after enabled, * log off all targets and fini isns service */ if (isns_initialized == True && isns_enabled() == False) { isns_fini(); return (0); } /* * isns is already initialized and isns_access is still enabled, * let's update the isns_server name */ tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV, &isns_srv); isns_port = strchr(isns_srv, ':'); if (isns_port == NULL) { isns_args.isns_port = ISNS_DEFAULT_SERVER_PORT; } else { isns_args.isns_port = strtoul(isns_port + 1, NULL, 0); if (isns_args.isns_port == 0) { isns_args.isns_port = ISNS_DEFAULT_SERVER_PORT; } *isns_port = '\0'; } /* * If the iSNS server is different, then dregister all from * the old iSNS server, and register all to the new iSNS server */ if (strcmp(isns_srv, isns_args.server) != 0) { /* de-reg from old iSNS server */ (void) isns_dereg_all(); bcopy(isns_srv, isns_args.server, MAXHOSTNAMELEN); if (isns_reg_all() == 0) { /* scn register all targets */ if (isns_op_all(ISNS_SCN_REG) != 0) { syslog(LOG_ERR, "SCN registrations failed\n"); isns_op_all(ISNS_DEV_DEREG); return (-1); } } } if (isns_srv != NULL) free(isns_srv); return (0); } /* * isns_fini is called when isns access is disable */ void isns_fini() { /* * de-register all targets 1st, this prevents initiator from * logging back in */ isns_op_all(ISNS_SCN_DEREG); isns_op_all(ISNS_DEV_DEREG); /* log off all targets */ isns_op_all(ISNS_TGT_LOGOUT); isns_initialized = False; } static int get_ip_addr(char *node, ip_t *sa) { struct addrinfo *ai = NULL, *aip; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; if (getaddrinfo(node, NULL, NULL, &ai) != 0) { syslog(LOG_ALERT, "ISNS server not found"); return (-1); } bzero(sa, sizeof (ip_t)); aip = ai; do { sa->ai_addrlen = aip->ai_addrlen; sa->pf_family = aip->ai_family; switch (aip->ai_family) { case PF_INET: /* LINTED */ sin = (struct sockaddr_in *)aip->ai_addr; sa->ip_len = sizeof (in_addr_t); bcopy(&sin->sin_addr, (void *)&sa->ip_adr.in, sa->ip_len); freeaddrinfo(ai); return (0); case PF_INET6: /* LINTED */ sin6 = (struct sockaddr_in6 *)aip->ai_addr; sa->ip_len = sizeof (in6_addr_t); bcopy(&sin6->sin6_addr, &sa->ip_adr.in6, sa->ip_len); freeaddrinfo(ai); return (0); default: continue; } } while ((aip = aip->ai_next) != NULL); freeaddrinfo(ai); 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_rsp(isns_pdu_t *cmd, isns_rsp_t *rsp) { queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_RSP"); /* * 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. */ rsp->status = ntohl(rsp->status); if (rsp->status != ISNS_RSP_SUCCESSFUL || rsp->xid != ntohs(cmd->xid) || rsp->func_id != (ntohs(cmd->func_id) | 0x8000)) { queue_prt(mgmtq, Q_ISNS_DBG, "cmd failed with: status= %d xid= %d %d "\ "response attribute %x\n", rsp->status, rsp->xid,\ ntohs(cmd->xid), rsp->func_id); return (-1); } return (0); } /* * DevAttrDereg */ static int isns_dev_attr_dereg(int so, char *node) { isns_pdu_t *cmd = NULL; isns_rsp_t *rsp = NULL; uint32_t flags = 0; int ret = -1; queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_DEREG"); if (isns_create_pdu(ISNS_DEV_DEREG, flags, &cmd) != 0) { return (-1); } /* add source attribute */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(node), node, 0) != 0) { goto error; } /* add delimiter */ if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) { goto error; } /* add operation attributes */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(node), node, 0) != 0) { goto error; } /* send pdu */ if (isns_send(so, cmd) == -1) { syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_send"); goto error; } /* get isns response */ if (isns_recv(so, &rsp) == -1) { syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_recv "); goto error; } /* process response */ if (process_rsp(cmd, rsp) == 0) { num_reg--; ret = 0; } error: /* Free all resouces here */ if (cmd) isns_free_pdu(cmd); if (rsp) isns_free_pdu(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 isns_dev_attr_reg(int so, tgt_node_t *tgt, char *node, char *alias) { isns_pdu_t *cmd = NULL; isns_rsp_t *rsp = NULL; uint32_t flags = 0; int ret = 0; Boolean_t found = False; tgt_node_t *src = NULL; char *src_nm = NULL; queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_REG"); if ((so = isns_open(isns_args.server)) == -1) { return (-1); } if (num_reg == 0) { flags |= ISNS_FLAG_REPLACE_REG; } if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) { return (-1); } if (num_reg == 0) { /* add new node to source attribute */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(node), node, 0) != 0) { goto error; } } else { /* find a registered node to use */ do { src = find_next_tgt(src, &src_nm); if (src == NULL) { syslog(LOG_ALERT, "ISNS out of sync\n"); goto error; } if (tgt == src) { free(src_nm); continue; } else { found = True; } } while (found == False); if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(src_nm), src_nm, 0) != 0) { goto error; } } /* add message key attribute */ if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { goto error; } /* add delimiter */ if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) { goto error; } /* add operation attributes */ /* entity id */ if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { goto error; } /* entity type */ if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID, ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) { goto error; } /* * Register entity portal properties the 1st time */ if (num_reg == 0) { /* portal ip-addr */ if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID, eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr, eid_ip.ip_len) != 0) { goto error; } /* portal port */ if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, iscsi_port) != 0) { goto error; } /* ESI interval */ if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID, ISNS_ESI_TICK_SZ, NULL, 10) != 0) { goto error; } /* scn port */ if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, scn_port) != 0) { goto error; } /* esi port */ if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, scn_port) != 0) { goto error; } } /* iscsi node name */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(node), node, 0) != 0) { goto error; } /* iscsi node type */ if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, ISNS_NODE_TYP_SZ, NULL, ISNS_TARGET_NODE_TYPE) != 0) { goto error; } /* iscsi node alias */ if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID, STRLEN(alias), alias, 0) != 0) { goto error; } /* PGT */ if (append_tpgt(tgt, cmd) != 0) { goto error; } /* send pdu */ if (isns_send(so, cmd) == -1) { goto error; } /* get isns response */ if (isns_recv(so, &rsp) == -1) { goto error; } /* process response */ if ((ret = process_rsp(cmd, rsp)) == 0) { num_reg++; } error: /* Free all resouces here */ if (cmd) isns_free_pdu(cmd); if (rsp) isns_free_pdu(rsp); if (src_nm) free(src_nm); return (ret); } /* * DevAttrQry for iscsi initiator * See RFC 4171 Sect. 5.6.5.2 for query detail */ static int isns_dev_attr_qry(int so, char *target, char *initiator) { isns_pdu_t *cmd; isns_rsp_t *rsp; uint32_t flags = 0; int ret = -1; size_t remain; isns_tlv_t *tlv; uint8_t *ptr; queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_QRY"); if (isns_create_pdu(ISNS_DEV_ATTR_QRY, flags, &cmd) != 0) { return (-1); } /* source attribute */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(target), target, 0) == -1) { goto error; } /* message key attribute */ /* iscsi initiator node type */ if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, ISNS_NODE_TYP_SZ, NULL, ISNS_INITIATOR_NODE_TYPE) == -1) { goto error; } /* delimiter */ if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) { goto error; } /* * operating attributes * Query Iscsi initiator with zero length TLV operating * attribute */ /* iscsi name */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, 0, NULL, 0) != 0) { goto error; } if (isns_send(so, cmd) == -1) { syslog(LOG_ERR, "isns_dev_attr_qry fails isns_send"); goto error; } /* recv response */ if (isns_recv(so, &rsp) == -1) { syslog(LOG_ERR, "isns_dev_attr_qry fails isns_recv "); goto error; } /* process response */ if ((ret = process_rsp(cmd, rsp)) == 0) { /* compare initiator name to the response, success if found */ /* subtract out status word */ remain = rsp->pdu_len - ISNS_STATUS_SZ; ptr = rsp->data; while (remain > 0) { /* LINTED */ tlv = (isns_tlv_t *)ptr; /* debug only */ print_ntoh_tlv(tlv); /* process tag-len-value */ ntoh_tlv(tlv); /* * let's process the data, only interested * in iscsi name, skip everything else for * now. */ if (tlv->attr_id == ISNS_ISCSI_NAME_ATTR_ID) { if (strncmp((char *)tlv->attr_value, initiator, tlv->attr_len) == 0) { break; } } /* next tlv */ remain -= ISNS_ATTR_SZ(tlv->attr_len); ptr += ISNS_ATTR_SZ(tlv->attr_len); } ret = (remain > 0) ? 1 : 0; } error: if (cmd) isns_free_pdu(cmd); if (rsp) isns_free_pdu(rsp); return (ret); } /* * SCNReg * See RFC 4171 Section 5.6.5.5 */ static int isns_scn_reg(int so, char *node) { isns_pdu_t *cmd; isns_rsp_t *rsp; uint32_t flags = 0; uint32_t bitmap = 0; int ret = -1; queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_SCN_REG"); if (isns_create_pdu(ISNS_SCN_REG, flags, &cmd) != 0) { return (-1); } /* source attribute */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(node), node, 0) == -1) { goto error; } /* message key attribute */ /* iscsi initiator node name */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(node), node, 0) != 0) { goto error; } /* delimiter */ if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) { goto error; } /* SCN bitmap */ bitmap = ISNS_INIT_SELF_INFO_ONLY | ISNS_OBJ_REMOVED | ISNS_OBJ_ADDED | ISNS_OBJ_UPDATED; if (isns_append_attr(cmd, ISNS_ISCSI_SCN_BITMAP_ATTR_ID, ISNS_SCN_BITMAP_SZ, NULL, bitmap) == -1) { goto error; } if (isns_send(so, cmd) == -1) { syslog(LOG_ERR, "isns_scn_reg fails isns_send"); goto error; } if (isns_recv(so, &rsp) == -1) { syslog(LOG_ERR, "isns_scn_reg fails isns_recv "); goto error; } /* process response */ if (process_rsp(cmd, rsp) == 0) { ret = 0; } error: if (cmd) isns_free_pdu(cmd); if (rsp) isns_free_pdu(rsp); return (ret); } /* * SCNDereg */ static int isns_scn_dereg(int so, char *node) { isns_pdu_t *cmd = NULL; isns_rsp_t *rsp = NULL; uint32_t flags = 0; int ret = -1; queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_SCN_DEREG"); if (isns_create_pdu(ISNS_SCN_DEREG, flags, &cmd) != 0) { return (-1); } /* source attribute */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(node), node, 0) == -1) { goto error; } /* message key attribute */ /* iscsi initiator node name */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(node), node, 0) != 0) { goto error; } if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) { goto error; } if (isns_send(so, cmd) == -1) { syslog(LOG_ERR, "isns_scn_reg fails isns_send"); goto error; } if (isns_recv(so, &rsp) == -1) { syslog(LOG_ERR, "isns_scn_reg fails isns_recv "); goto error; } /* process response */ if (process_rsp(cmd, rsp) == 0) { ret = 0; } error: if (cmd) isns_free_pdu(cmd); if (rsp) isns_free_pdu(rsp); return (ret); } /* * isns_reg is called to register new target */ int isns_reg(char *targ) { int so; tgt_node_t *tgt; char *iqn; if ((so = isns_open(isns_args.server)) == -1) { syslog(LOG_ERR, "isns_reg failed"); return (-1); } /* * Open targets_config and devAttrReg all nodes */ if ((tgt = find_tgt_by_name(targ, &iqn)) != NULL) { if (isns_dev_attr_reg(so, tgt, iqn, tgt->x_value) != 0) { syslog(LOG_ALERT, "ISNS registration failed %s\n", tgt->x_value); } if (isns_scn_reg(so, iqn) == -1) { syslog(LOG_ERR, "ISNS SCN register failed\n"); } free(iqn); } isns_close(so); return (0); } /* * Register all iscsi target nodes from the XML database * Alway use the ISNS_FLAG_REPLACE_REG flag */ int isns_reg_all() { int so; uint32_t flags = ISNS_FLAG_REPLACE_REG; isns_pdu_t *cmd; isns_rsp_t *rsp; char *n = NULL; char *a = NULL; char alias[MAXNAMELEN]; char iname[MAXNAMELEN]; tgt_node_t *tgt = NULL; int ret = -1; int tgt_cnt = 0; /* * get the 1st target and use it for the source attribute */ if ((tgt = tgt_node_next(targets_config, XML_ELEMENT_TARG, tgt)) == NULL) { return (0); } if (tgt->x_value == NULL) { syslog(LOG_ALERT, "ISNS: target with NULL local name\n"); return (-1); } if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n) == FALSE) { syslog(LOG_ALERT, "ISNS: no XML_ELEMENT_INAME found\n"); return (-1); } strcpy(iname, n); free(n); if ((so = isns_open(isns_args.server)) == -1) { syslog(LOG_ALERT, "ISNS: fails to connect to %s\n", isns_args.server); return (-1); } if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) { goto error; } /* source attribute */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(iname), iname, 0) != 0) { goto error; } /* add message key attribute */ if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { goto error; } /* add delimiter */ if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) { goto error; } /* entity id */ if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { goto error; } /* entity type */ if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID, ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) { goto error; } /* portal ip-addr */ if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID, eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr, eid_ip.ip_len) != 0) { goto error; } /* portal port */ if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, iscsi_port) != 0) { goto error; } /* ESI interval */ if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID, ISNS_ESI_TICK_SZ, NULL, 10) != 0) { goto error; } /* scn port */ if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, scn_port) != 0) { goto error; } /* esi port */ if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, scn_port) != 0) { goto error; } /* * Open targets_config and devAttrReg all nodes */ tgt = NULL; while ((tgt = tgt_node_next(targets_config, XML_ELEMENT_TARG, tgt)) != NULL) { if (tgt->x_value == NULL) { syslog(LOG_ALERT, "ISNS: target with NULL name\n"); continue; } /* use this value as alias if alias is not set */ strcpy(alias, tgt->x_value); if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n) == FALSE) { continue; } strcpy(iname, n); free(n); /* find alias */ if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &a) == TRUE) { strcpy(alias, a); free(a); } tgt_cnt++; /* increment target count */ /* operation attributes */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(iname), iname, 0) != 0) { goto error; } if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, NULL, ISNS_TARGET_NODE_TYPE) != 0) { goto error; } if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID, STRLEN(alias), alias, 0) != 0) { goto error; } if (append_tpgt(tgt, cmd) != 0) { goto error; } } /* send pdu */ if (isns_send(so, cmd) == -1) { goto error; } /* get isns response */ if (isns_recv(so, &rsp) == -1) { goto error; } /* process response */ if (process_rsp(cmd, rsp) == 0) { ret = 0; num_reg = tgt_cnt; queue_prt(mgmtq, Q_ISNS_DBG, "DevAttrRegAll successful"); } else { syslog(LOG_ALERT, "DevAttrReg failed"); } error: if (cmd) isns_free_pdu(cmd); if (rsp) isns_free_pdu(rsp); isns_close(so); return (ret); } /* * Deregister an iscsi target node */ int isns_dereg(char *name) { int so; int ret; if ((so = isns_open(isns_args.server)) == -1) { return (-1); } ret = isns_dev_attr_dereg(so, name); isns_close(so); return (ret); } /* * Update an existing iscsi target property */ int isns_dev_update(char *targ, uint32_t mods) { int so; int flags = 0; /* update only */ char *iname = NULL; char *dummy = NULL; char alias[MAXNAMELEN]; tgt_node_t *tgt = NULL; isns_pdu_t *cmd; isns_rsp_t *rsp; int ret = -1; if (mods == 0) return (0); if ((tgt = find_tgt_by_name(targ, &iname)) != NULL) { if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &dummy) == True) { strcpy(alias, dummy); free(dummy); } else strcpy(alias, tgt->x_value); if ((so = isns_open(isns_args.server)) < 0) { goto error; } if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd)) { goto error; } /* source attr, msg key, delimiter */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(iname), iname, 0) != 0) { goto error; } if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { goto error; } if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) { goto error; } /* * get current operating attributes, alias & portal group * objects, these should be the only things that get change */ isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(iname), iname, 0); isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, ISNS_NODE_TYP_SZ, NULL, ISNS_TARGET_NODE_TYPE); if (mods & ISNS_MOD_ALIAS) if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID, STRLEN(alias), alias, 0) != 0) { goto error; } if (mods & ISNS_MOD_TPGT) if (append_tpgt(tgt, cmd) != 0) { goto error; } if (isns_send(so, (isns_pdu_t *)cmd) < 0) { goto error; } if (isns_recv(so, &rsp) == -1) { goto error; } /* process response, if failed do a isns_reg_all */ if ((ret = process_rsp(cmd, rsp)) == -1) { if (isns_reg_all() != 0 || isns_scn_reg_all() != 0) { syslog(LOG_ALERT, "ISNS register failed\n"); goto error; } ret = 0; } else { if (isns_scn_reg(so, iname) == -1) { syslog(LOG_ERR, "ISNS SCN register failed\n"); goto error; } ret = 0; } } else { syslog(LOG_ERR, "ISNS: fails to update target %s\n", alias); } error: if (cmd) isns_free_pdu(cmd); if (rsp) isns_free_pdu(rsp); if (iname) free(iname); isns_close(so); return (ret); } /* * Deregister all iscsi target nodes from the XML database */ int isns_dereg_all() { return (isns_op_all(ISNS_DEV_DEREG)); } int isns_scn_reg_all() { return (isns_op_all(ISNS_SCN_REG)); } int isns_scn_dereg_all() { return (isns_op_all(ISNS_SCN_DEREG)); } /* * Query an iscsi initiator node */ Boolean_t isns_qry_initiator(char *target, char *initiator) { int so; int ret; if ((so = isns_open(isns_args.server)) == -1) { syslog(LOG_ERR, "isns_qry failed"); return (-1); } ret = isns_dev_attr_qry(so, target, initiator); isns_close(so); return (ret == 1 ? True : False); } Boolean_t isns_enabled() { Boolean_t isns_access = False; char *isns_srv = NULL; (void) tgt_find_value_boolean(main_config, XML_ELEMENT_ISNS_ACCESS, &isns_access); /* get isns server info */ if (isns_access == True) { if (tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV, &isns_srv) == True) { free(isns_srv); return (True); } } return (False); }