2 * iSCSI Administration Utility
4 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
5 * Copyright (C) 2006 Mike Christie
6 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
7 * maintained by open-iscsi@googlegroups.com
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * See the file COPYING included with this distribution for more details.
31 #include "initiator.h"
32 #include "discovery.h"
36 #include "iscsi_util.h"
37 #include "transport.h"
39 #include "iscsi_sysfs.h"
41 #include "iscsi_settings.h"
42 #include "fw_context.h"
44 #include "session_info.h"
47 #include "idbm_fields.h"
48 #include "session_mgmt.h"
49 #include "iscsid_req.h"
50 #include "isns-proto.h"
52 struct iscsi_ipc
*ipc
= NULL
; /* dummy */
53 static char program_name
[] = "iscsiadm";
54 static char config_file
[TARGET_NAME_MAXLEN
];
71 OP_NONPERSISTENT
= 0x10
74 static struct option
const long_options
[] =
76 {"mode", required_argument
, NULL
, 'm'},
77 {"portal", required_argument
, NULL
, 'p'},
78 {"targetname", required_argument
, NULL
, 'T'},
79 {"interface", required_argument
, NULL
, 'I'},
80 {"op", required_argument
, NULL
, 'o'},
81 {"type", required_argument
, NULL
, 't'},
82 {"name", required_argument
, NULL
, 'n'},
83 {"value", required_argument
, NULL
, 'v'},
84 {"host", required_argument
, NULL
, 'H'},
85 {"sid", required_argument
, NULL
, 'r'},
86 {"rescan", no_argument
, NULL
, 'R'},
87 {"print", required_argument
, NULL
, 'P'},
88 {"login", no_argument
, NULL
, 'l'},
89 {"loginall", required_argument
, NULL
, 'L'},
90 {"logout", no_argument
, NULL
, 'u'},
91 {"logoutall", required_argument
, NULL
, 'U'},
92 {"stats", no_argument
, NULL
, 's'},
93 {"killiscsid", required_argument
, NULL
, 'k'},
94 {"debug", required_argument
, NULL
, 'd'},
95 {"show", no_argument
, NULL
, 'S'},
96 {"version", no_argument
, NULL
, 'V'},
97 {"help", no_argument
, NULL
, 'h'},
100 static char *short_options
= "RlVhm:p:P:T:H:I:U:k:L:d:r:n:v:o:sSt:u";
102 static void usage(int status
)
105 fprintf(stderr
, "Try `%s --help' for more information.\n",
109 iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -l ] ] | [ -p ip:port ] \
110 [ -o operation ] [ -n name ] [ -v value ]\n\
111 iscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I ifaceN ] [ -l | -u | -R | -s] ] \
112 [ [ -o operation ] [ -n name ] [ -v value ] ]\n\
113 iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\
114 iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n\
115 iscsiadm -m fw [ -l ]\n\
116 iscsiadm -m host [ -P printlevel ] [ -H hostno ]\n\
117 iscsiadm -k priority\n");
119 exit(status
== 0 ? 0 : -1);
127 if (!strcmp("new", str
))
129 else if (!strcmp("delete", str
))
131 else if (!strcmp("update", str
))
133 else if (!strcmp("show", str
))
135 else if (!strcmp("nonpersistent", str
))
136 op
= OP_NONPERSISTENT
;
144 str_to_mode(char *str
)
148 if (!strcmp("discovery", str
))
149 mode
= MODE_DISCOVERY
;
150 else if (!strcmp("node", str
))
152 else if (!strcmp("session", str
))
154 else if (!strcmp("iface", str
))
156 else if (!strcmp("fw", str
))
158 else if (!strcmp("host", str
))
167 str_to_type(char *str
)
171 if (!strcmp("sendtargets", str
) ||
173 type
= DISCOVERY_TYPE_SENDTARGETS
;
174 else if (!strcmp("slp", str
))
175 type
= DISCOVERY_TYPE_SLP
;
176 else if (!strcmp("isns", str
))
177 type
= DISCOVERY_TYPE_ISNS
;
178 else if (!strcmp("fw", str
))
179 type
= DISCOVERY_TYPE_FW
;
186 static void kill_iscsid(int priority
)
193 * We only support SIGTERM like stoppage of iscsid for now.
194 * In the future we can do something where we try go finish
195 * up operations like login, error handling, etc, before
196 * iscsid is stopped, and we can add different values to indicate
197 * that the user wants iscsid to log out existing sessions before
201 log_error("Invalid iscsid priority %d. Priority must be 0.",
206 memset(&req
, 0, sizeof(req
));
207 req
.command
= MGMT_IPC_IMMEDIATE_STOP
;
208 rc
= iscsid_exec_req(&req
, &rsp
, 0);
210 iscsid_handle_error(rc
);
211 log_error("Could not stop iscsid. Trying sending iscsid "
212 "SIGTERM or SIGKILL signals manually\n");
217 * TODO: we can display how the ifaces are related to node records.
218 * And we can add a scsi_host mode which would display how
219 * sessions are related to hosts
220 * (scsi_host and iscsi_sessions are the currently running instance of
221 * a iface or node record).
223 static int print_ifaces(struct iface_rec
*iface
, int info_level
)
225 int err
, num_found
= 0;
227 switch (info_level
) {
230 err
= iface_for_each_iface(NULL
, 0, &num_found
,
235 err
= iface_conf_read(iface
);
237 log_error("Could not read iface %s.\n",
241 iface_print_tree(NULL
, iface
);
244 err
= iface_for_each_iface(NULL
, 0, &num_found
,
248 log_error("Invalid info level %d. Try 0 - 1.", info_level
);
253 log_error("No interfaces found.");
260 match_startup_mode(node_rec_t
*rec
, char *mode
)
263 * we always skip onboot because this should be handled by
266 if (rec
->startup
== ISCSI_STARTUP_ONBOOT
)
269 if ((!strcmp(mode
, "automatic") &&
270 rec
->startup
== ISCSI_STARTUP_AUTOMATIC
) ||
271 (!strcmp(mode
, "manual") &&
272 rec
->startup
== ISCSI_STARTUP_MANUAL
) ||
273 !strcmp(mode
, "all"))
276 /* support conn or session startup params */
277 if ((!strcmp(mode
, "automatic") &&
278 rec
->conn
[0].startup
== ISCSI_STARTUP_AUTOMATIC
) ||
279 (!strcmp(mode
, "manual") &&
280 rec
->conn
[0].startup
== ISCSI_STARTUP_MANUAL
) ||
281 !strcmp(mode
, "all"))
288 for_each_session(struct node_rec
*rec
, iscsi_sysfs_session_op_fn
*fn
)
290 int err
, num_found
= 0;
292 err
= iscsi_sysfs_for_each_session(rec
, &num_found
, fn
);
294 log_error("Could not execute operation on all sessions. Err "
296 else if (!num_found
) {
297 log_error("No portal found.");
304 static int link_recs(void *data
, struct node_rec
*rec
)
306 struct list_head
*list
= data
;
307 struct node_rec
*rec_copy
;
309 rec_copy
= calloc(1, sizeof(*rec_copy
));
312 memcpy(rec_copy
, rec
, sizeof(*rec_copy
));
313 INIT_LIST_HEAD(&rec_copy
->list
);
314 list_add_tail(&rec_copy
->list
, list
);
319 __logout_by_startup(void *data
, struct list_head
*list
,
320 struct session_info
*info
)
326 memset(&rec
, 0, sizeof(node_rec_t
));
327 if (idbm_rec_read(&rec
, info
->targetname
, info
->tpgt
,
328 info
->persistent_address
,
329 info
->persistent_port
, &info
->iface
)) {
331 * this is due to a HW driver or some other driver
334 log_debug(7, "could not read data for [%s,%s.%d]\n",
335 info
->targetname
, info
->persistent_address
,
336 info
->persistent_port
);
340 /* multiple drivers could be connected to the same portal */
341 if (strcmp(rec
.iface
.transport_name
, info
->iface
.transport_name
))
344 * we always skip on boot because if the user killed this on
345 * they would not be able to do anything
347 if (rec
.startup
== ISCSI_STARTUP_ONBOOT
)
350 if (!match_startup_mode(&rec
, mode
))
351 rc
= iscsi_logout_portal(info
, list
);
356 logout_by_startup(char *mode
)
360 if (!mode
|| !(!strcmp(mode
, "automatic") || !strcmp(mode
, "all") ||
361 !strcmp(mode
,"manual"))) {
362 log_error("Invalid logoutall option %s.", mode
);
367 return iscsi_logout_portals(mode
, &nr_found
, 1, __logout_by_startup
);
371 * TODO: merged this and logout into the common for_each_rec by making
372 * the matching more generic
375 __login_by_startup(void *data
, struct list_head
*list
, struct node_rec
*rec
)
379 * we always skip onboot because this should be handled by
382 if (rec
->startup
== ISCSI_STARTUP_ONBOOT
)
385 if (match_startup_mode(rec
, mode
))
388 iscsi_login_portal(NULL
, list
, rec
);
393 login_by_startup(char *mode
)
395 int nr_found
= 0, rc
, err
;
396 struct list_head rec_list
;
398 if (!mode
|| !(!strcmp(mode
, "automatic") || !strcmp(mode
, "all") ||
399 !strcmp(mode
,"manual"))) {
400 log_error("Invalid loginall option %s.", mode
);
405 INIT_LIST_HEAD(&rec_list
);
406 rc
= idbm_for_each_rec(&nr_found
, &rec_list
, link_recs
);
407 err
= iscsi_login_portals(mode
, &nr_found
, 1, &rec_list
,
413 log_error("Could not log into all portals. Err %d.", rc
);
414 else if (!nr_found
) {
415 log_error("No records found!");
422 * iscsi_logout_matched_portal - logout of targets matching the rec info
423 * @data: record to session with
424 * @list: list to add logout rec to
425 * @info: session to match with rec
427 static int iscsi_logout_matched_portal(void *data
, struct list_head
*list
,
428 struct session_info
*info
)
430 struct node_rec
*pattern_rec
= data
;
431 struct iscsi_transport
*t
;
433 t
= iscsi_sysfs_get_transport_by_sid(info
->sid
);
437 if (!iscsi_match_session(pattern_rec
, info
))
440 /* we do not support this yet */
441 if (t
->caps
& CAP_FW_DB
) {
442 log_error("Could not logout session of [sid: %d, "
443 "target: %s, portal: %s,%d].", info
->sid
,
444 info
->targetname
, info
->persistent_address
,
446 log_error("Logout not supported for driver: %s.", t
->name
);
449 return iscsi_logout_portal(info
, list
);
452 static int iface_fn(void *data
, node_rec_t
*rec
)
454 struct rec_op_data
*op_data
= data
;
456 if (!__iscsi_match_session(op_data
->match_rec
, rec
->name
,
457 rec
->conn
[0].address
, rec
->conn
[0].port
,
460 return op_data
->fn(op_data
->data
, rec
);
463 static int __for_each_rec(int verbose
, struct node_rec
*rec
,
464 void *data
, idbm_iface_op_fn
*fn
)
466 struct rec_op_data op_data
;
467 int nr_found
= 0, rc
;
469 memset(&op_data
, 0, sizeof(struct rec_op_data
));
471 op_data
.match_rec
= rec
;
474 rc
= idbm_for_each_rec(&nr_found
, &op_data
, iface_fn
);
477 log_error("Could not execute operation on all "
478 "records. Err %d.", rc
);
479 } else if (!nr_found
) {
481 log_error("no records found!");
488 static int for_each_rec(struct node_rec
*rec
, void *data
,
489 idbm_iface_op_fn
*fn
)
491 return __for_each_rec(1, rec
, data
, fn
);
495 static int login_portals(struct node_rec
*pattern_rec
)
497 struct list_head rec_list
;
498 int err
, ret
, nr_found
;
500 INIT_LIST_HEAD(&rec_list
);
501 ret
= for_each_rec(pattern_rec
, &rec_list
, link_recs
);
502 err
= iscsi_login_portals(NULL
, &nr_found
, 1, &rec_list
,
509 static int print_nodes(int info_level
, struct node_rec
*rec
)
511 struct node_rec tmp_rec
;
514 switch (info_level
) {
517 if (for_each_rec(rec
, NULL
, idbm_print_node_flat
))
521 memset(&tmp_rec
, 0, sizeof(node_rec_t
));
522 if (for_each_rec(rec
, &tmp_rec
, idbm_print_node_and_iface_tree
))
526 log_error("Invalid info level %d. Try 0 or 1.", info_level
);
533 static char *get_config_file(void)
539 memset(&req
, 0, sizeof(req
));
540 req
.command
= MGMT_IPC_CONFIG_FILE
;
542 rc
= iscsid_exec_req(&req
, &rsp
, 1);
546 if (rsp
.u
.config
.var
[0] != '\0') {
547 strcpy(config_file
, rsp
.u
.config
.var
);
554 static int rescan_portal(void *data
, struct session_info
*info
)
558 if (!iscsi_match_session(data
, info
))
561 printf("Rescanning session [sid: %d, target: %s, portal: "
562 "%s,%d]\n", info
->sid
, info
->targetname
,
563 info
->persistent_address
, info
->port
);
565 host_no
= iscsi_sysfs_get_host_no_from_sid(info
->sid
, &err
);
567 log_error("Could not rescan session sid %d.", info
->sid
);
570 /* rescan each device to pick up size changes */
571 iscsi_sysfs_for_each_device(NULL
, host_no
, info
->sid
,
572 iscsi_sysfs_rescan_device
);
573 /* now scan for new devices */
574 iscsi_sysfs_scan_host(host_no
, 0);
579 session_stats(void *data
, struct session_info
*info
)
585 if (!iscsi_match_session(data
, info
))
588 memset(&req
, 0, sizeof(req
));
589 req
.command
= MGMT_IPC_SESSION_STATS
;
590 req
.u
.session
.sid
= info
->sid
;
592 rc
= iscsid_exec_req(&req
, &rsp
, 1);
596 printf("Stats for session [sid: %d, target: %s, portal: "
598 info
->sid
, info
->targetname
, info
->persistent_address
,
601 printf( "iSCSI SNMP:\n"
603 "\ttxdata_octets: %lld\n"
604 "\trxdata_octets: %lld\n"
607 "\tscsicmd_pdus: %u\n"
608 "\ttmfcmd_pdus: %u\n"
611 "\tdataout_pdus: %u\n"
612 "\tlogout_pdus: %u\n"
616 "\tscsirsp_pdus: %u\n"
617 "\ttmfrsp_pdus: %u\n"
618 "\ttextrsp_pdus: %u\n"
619 "\tdatain_pdus: %u\n"
620 "\tlogoutrsp_pdus: %u\n"
626 "\ttimeout_err: %u\n",
627 (unsigned long long)rsp
.u
.getstats
.stats
.txdata_octets
,
628 (unsigned long long)rsp
.u
.getstats
.stats
.rxdata_octets
,
630 rsp
.u
.getstats
.stats
.noptx_pdus
,
631 rsp
.u
.getstats
.stats
.scsicmd_pdus
,
632 rsp
.u
.getstats
.stats
.tmfcmd_pdus
,
633 rsp
.u
.getstats
.stats
.login_pdus
,
634 rsp
.u
.getstats
.stats
.text_pdus
,
635 rsp
.u
.getstats
.stats
.dataout_pdus
,
636 rsp
.u
.getstats
.stats
.logout_pdus
,
637 rsp
.u
.getstats
.stats
.snack_pdus
,
639 rsp
.u
.getstats
.stats
.noprx_pdus
,
640 rsp
.u
.getstats
.stats
.scsirsp_pdus
,
641 rsp
.u
.getstats
.stats
.tmfrsp_pdus
,
642 rsp
.u
.getstats
.stats
.textrsp_pdus
,
643 rsp
.u
.getstats
.stats
.datain_pdus
,
644 rsp
.u
.getstats
.stats
.logoutrsp_pdus
,
645 rsp
.u
.getstats
.stats
.r2t_pdus
,
646 rsp
.u
.getstats
.stats
.async_pdus
,
647 rsp
.u
.getstats
.stats
.rjt_pdus
,
649 rsp
.u
.getstats
.stats
.digest_err
,
650 rsp
.u
.getstats
.stats
.timeout_err
);
652 if (rsp
.u
.getstats
.stats
.custom_length
)
653 printf( "iSCSI Extended:\n");
655 for (i
= 0; i
< rsp
.u
.getstats
.stats
.custom_length
; i
++) {
656 printf("\t%s: %llu\n", rsp
.u
.getstats
.stats
.custom
[i
].desc
,
657 (unsigned long long)rsp
.u
.getstats
.stats
.custom
[i
].value
);
663 static int add_static_rec(int *found
, char *targetname
, int tpgt
,
664 char *ip
, int port
, struct iface_rec
*iface
)
667 discovery_rec_t
*drec
;
670 rec
= calloc(1, sizeof(*rec
));
672 log_error("Could not allocate memory for node addition");
677 drec
= calloc(1, sizeof(*drec
));
679 log_error("Could not allocate memory for node addition");
683 drec
->type
= DISCOVERY_TYPE_STATIC
;
685 idbm_node_setup_from_conf(rec
);
686 strlcpy(rec
->name
, targetname
, TARGET_NAME_MAXLEN
);
688 rec
->conn
[0].port
= port
;
689 strlcpy(rec
->conn
[0].address
, ip
, NI_MAXHOST
);
692 rc
= iface_conf_read(iface
);
694 log_error("Could not read iface %s. Error %d",
699 iface_copy(&rec
->iface
, iface
);
702 rc
= idbm_add_node(rec
, drec
, 1);
705 printf("New iSCSI node [%s:" iface_fmt
" %s,%d,%d %s] added\n",
706 rec
->iface
.transport_name
, iface_str(&rec
->iface
),
707 ip
, port
, tpgt
, targetname
);
716 static int add_static_portal(int *found
, void *data
,
717 char *targetname
, int tpgt
, char *ip
, int port
)
719 node_rec_t
*rec
= data
;
721 if (strlen(rec
->conn
[0].address
) &&
722 strcmp(rec
->conn
[0].address
, ip
))
725 if (rec
->conn
[0].port
!= -1 && rec
->conn
[0].port
!= port
)
728 return add_static_rec(found
, targetname
, tpgt
, ip
, port
,
732 static int add_static_node(int *found
, void *data
,
735 node_rec_t
*rec
= data
;
737 if (!strlen(rec
->name
))
740 if (strcmp(rec
->name
, targetname
))
743 if (!strlen(rec
->conn
[0].address
))
746 return add_static_rec(found
, targetname
, rec
->tpgt
,
747 rec
->conn
[0].address
,
748 rec
->conn
[0].port
, &rec
->iface
);
750 return idbm_for_each_portal(found
, data
, add_static_portal
,
754 static int add_static_recs(struct node_rec
*rec
)
756 int rc
, nr_found
= 0;
758 rc
= idbm_for_each_node(&nr_found
, rec
, add_static_node
);
760 log_error("Error while adding records. DB may be in an "
761 "inconsistent state. Err %d", rc
);
768 /* brand new target */
769 if (strlen(rec
->name
) && strlen(rec
->conn
[0].address
)) {
770 rc
= add_static_rec(&nr_found
, rec
->name
, rec
->tpgt
,
771 rec
->conn
[0].address
, rec
->conn
[0].port
,
778 printf("No records added.\n");
783 * start sendtargets discovery process based on the
787 do_offload_sendtargets(discovery_rec_t
*drec
, int host_no
, int do_login
)
789 drec
->type
= DISCOVERY_TYPE_OFFLOAD_SENDTARGETS
;
790 return discovery_offload_sendtargets(host_no
, do_login
, drec
);
793 static int delete_node(void *data
, struct node_rec
*rec
)
795 if (iscsi_check_for_running_session(rec
)) {
797 * We could log out the session for the user, but if
798 * the session is being used the user may get something
799 * they were not expecting (FS errors and a read only
802 log_error("This command will remove the record [iface: %s, "
803 "target: %s, portal: %s,%d], but a session is "
804 "using it. Logout session then rerun command to "
805 "remove record.", rec
->iface
.name
, rec
->name
,
806 rec
->conn
[0].address
, rec
->conn
[0].port
);
810 return idbm_delete_node(rec
);
813 static int delete_stale_rec(void *data
, struct node_rec
*rec
)
815 struct list_head
*new_rec_list
= data
;
816 struct node_rec
*new_rec
;
818 list_for_each_entry(new_rec
, new_rec_list
, list
) {
820 * We could also move this to idbm.c and instead of looping
821 * over every node just loop over disc to node links.
823 if (rec
->disc_type
!= new_rec
->disc_type
||
824 rec
->disc_port
!= new_rec
->disc_port
||
825 strcmp(rec
->disc_address
, new_rec
->disc_address
))
827 * if we are not from the same discovery source
832 if (__iscsi_match_session(rec
,
834 new_rec
->conn
[0].address
,
835 new_rec
->conn
[0].port
,
839 /* if there is a error we can continue on */
840 delete_node(NULL
, rec
);
845 exec_disc_op_on_recs(discovery_rec_t
*drec
, struct list_head
*rec_list
,
846 int info_level
, int do_login
, int op
)
848 int rc
= 0, err
, found
= 0;
849 struct node_rec
*new_rec
, tmp_rec
;
851 /* clean up node db */
853 idbm_for_each_rec(&found
, rec_list
, delete_stale_rec
);
855 if (op
& OP_NEW
|| op
& OP_UPDATE
) {
856 /* now add/update records */
857 list_for_each_entry(new_rec
, rec_list
, list
) {
858 rc
= idbm_add_node(new_rec
, drec
, op
& OP_UPDATE
);
860 log_error("Could not add/update "
861 "[%s:" iface_fmt
" %s,%d,%d %s]",
862 new_rec
->iface
.transport_name
,
863 iface_str(&new_rec
->iface
),
864 new_rec
->conn
[0].address
,
865 new_rec
->conn
[0].port
,
866 new_rec
->tpgt
, new_rec
->name
);
870 memset(&tmp_rec
, 0, sizeof(node_rec_t
));
871 list_for_each_entry(new_rec
, rec_list
, list
) {
872 switch (info_level
) {
875 idbm_print_node_flat(NULL
, new_rec
);
878 idbm_print_node_and_iface_tree(&tmp_rec
, new_rec
);
886 err
= iscsi_login_portals(NULL
, &found
, 1, rec_list
,
894 do_software_sendtargets(discovery_rec_t
*drec
, struct list_head
*ifaces
,
895 int info_level
, int do_login
, int op
)
897 struct list_head rec_list
;
898 struct node_rec
*rec
, *tmp
;
901 INIT_LIST_HEAD(&rec_list
);
903 * compat: if the user did not pass any op then we do all
907 op
= OP_NEW
| OP_DELETE
| OP_UPDATE
;
909 drec
->type
= DISCOVERY_TYPE_SENDTARGETS
;
911 * we will probably want to know how a specific iface and discovery
912 * DB lined up, but for now just put all the targets found from
913 * a discovery portal in one place
915 if (!(op
& OP_NONPERSISTENT
)) {
916 rc
= idbm_add_discovery(drec
);
918 log_error("Could not add new discovery record.");
923 rc
= idbm_bind_ifaces_to_nodes(discovery_sendtargets
, drec
, ifaces
,
926 log_error("Could not perform SendTargets discovery.");
930 rc
= exec_disc_op_on_recs(drec
, &rec_list
, info_level
, do_login
, op
);
932 list_for_each_entry_safe(rec
, tmp
, &rec_list
, list
) {
933 list_del(&rec
->list
);
941 do_sendtargets(discovery_rec_t
*drec
, struct list_head
*ifaces
,
942 int info_level
, int do_login
, int op
)
944 struct iface_rec
*tmp
, *iface
;
946 struct iscsi_transport
*t
;
948 if (list_empty(ifaces
)) {
953 /* we allow users to mix hw and sw iscsi so we have to sort it out */
954 list_for_each_entry_safe(iface
, tmp
, ifaces
, list
) {
955 rc
= iface_conf_read(iface
);
957 log_error("Could not read iface info for %s. "
958 "Make sure a iface config with the file "
959 "name and iface.iscsi_ifacename %s is in %s.",
960 iface
->name
, iface
->name
, IFACE_CONFIG_DIR
);
961 list_del(&iface
->list
);
966 host_no
= iscsi_sysfs_get_host_no_from_hwinfo(iface
, &rc
);
967 if (rc
|| host_no
== -1) {
968 log_debug(1, "Could not match iface" iface_fmt
" to "
969 "host.", iface_str(iface
));
970 /* try software iscsi */
974 t
= iscsi_sysfs_get_transport_by_hba(host_no
);
976 log_error("Could not match hostno %d to "
977 "transport. Dropping interface %s,"
979 host_no
, iface
->transport_name
,
980 iface_str(iface
), iface
->ipaddress
);
981 list_del(&iface
->list
);
986 if (t
->caps
& CAP_SENDTARGETS_OFFLOAD
) {
987 do_offload_sendtargets(drec
, host_no
, do_login
);
988 list_del(&iface
->list
);
993 if (list_empty(ifaces
))
997 return do_software_sendtargets(drec
, ifaces
, info_level
, do_login
,
1001 static int do_isns(discovery_rec_t
*drec
, struct list_head
*ifaces
,
1002 int info_level
, int do_login
, int op
)
1004 struct list_head rec_list
;
1005 struct node_rec
*rec
, *tmp
;
1008 INIT_LIST_HEAD(&rec_list
);
1010 * compat: if the user did not pass any op then we do all
1014 op
= OP_NEW
| OP_DELETE
| OP_UPDATE
;
1016 drec
->type
= DISCOVERY_TYPE_ISNS
;
1018 rc
= idbm_bind_ifaces_to_nodes(discovery_isns
, drec
, ifaces
,
1021 log_error("Could not perform iSNS discovery.");
1025 rc
= exec_disc_op_on_recs(drec
, &rec_list
, info_level
, do_login
, op
);
1027 list_for_each_entry_safe(rec
, tmp
, &rec_list
, list
) {
1028 list_del(&rec
->list
);
1036 verify_mode_params(int argc
, char **argv
, char *allowed
, int skip_m
)
1043 while ((ch
= getopt_long(argc
, argv
, short_options
,
1044 long_options
, &longindex
)) >= 0) {
1045 if (!strchr(allowed
, ch
)) {
1046 if (ch
== 'm' && skip_m
)
1056 static void catch_sigint( int signo
) {
1057 log_warning("caught SIGINT, exiting...");
1061 /* TODO: merge iter helpers and clean them up, so we can use them here */
1062 static int exec_iface_op(int op
, int do_show
, int info_level
,
1063 struct iface_rec
*iface
, char *name
, char *value
)
1065 struct db_set_param set_param
;
1066 struct node_rec
*rec
= NULL
;
1072 log_error("Could not add interface. No interface "
1077 rec
= idbm_create_rec(NULL
, -1, NULL
, -1, iface
, 0);
1078 if (rec
&& iscsi_check_for_running_session(rec
)) {
1083 iface_setup_defaults(iface
);
1084 rc
= iface_conf_write(iface
);
1087 printf("New interface %s added\n", iface
->name
);
1090 log_error("Could not create new interface %s.", iface
->name
);
1094 log_error("Could not delete interface. No interface "
1099 rec
= idbm_create_rec(NULL
, -1, NULL
, -1, iface
, 1);
1105 /* logout and delete records using it first */
1106 rc
= __for_each_rec(0, rec
, NULL
, delete_node
);
1107 if (rc
&& rc
!= ENODEV
)
1110 rc
= iface_conf_delete(iface
);
1114 printf("%s unbound and deleted.\n", iface
->name
);
1117 log_error("Could not delete iface %s. A session is "
1118 "is using it or it could not be found.",
1122 if (!iface
|| !name
|| !value
) {
1123 log_error("Update requires name, value, and iface.");
1128 rec
= idbm_create_rec(NULL
, -1, NULL
, -1, iface
, 1);
1134 if (iscsi_check_for_running_session(rec
))
1135 log_warning("Updating iface while iscsi sessions "
1136 "are using it. You must logout the running "
1137 "sessions then log back in for the "
1138 "new settings to take affect.");
1140 if (!strcmp(name
, IFACE_ISCSINAME
)) {
1141 log_error("Can not update "
1142 "iface.iscsi_ifacename. Delete it, "
1143 "and then create a new one.");
1148 if (iface_is_bound_by_hwaddr(&rec
->iface
) &&
1149 !strcmp(name
, IFACE_NETNAME
)) {
1150 log_error("Can not update interface binding "
1151 "from hwaddress to net_ifacename. ");
1152 log_error("You must delete the interface and "
1153 "create a new one");
1158 if (iface_is_bound_by_netdev(&rec
->iface
) &&
1159 !strcmp(name
, IFACE_HWADDR
)) {
1160 log_error("Can not update interface binding "
1161 "from net_ifacename to hwaddress. ");
1162 log_error("You must delete the interface and "
1163 "create a new one");
1167 set_param
.name
= name
;
1168 set_param
.value
= value
;
1170 /* pass rec's iface because it has the db values */
1171 rc
= iface_conf_update(&set_param
, &rec
->iface
);
1175 rc
= __for_each_rec(0, rec
, &set_param
, idbm_node_set_param
);
1176 if (rc
&& rc
!= ENODEV
)
1179 printf("%s updated.\n", iface
->name
);
1182 log_error("Could not update iface %s. A session is "
1183 "is using it or it could not be found.",
1187 if (!iface
|| (iface
&& info_level
> 0)) {
1188 if (op
== OP_NOOP
|| op
== OP_SHOW
)
1189 rc
= print_ifaces(iface
, info_level
);
1193 rc
= iface_conf_read(iface
);
1195 idbm_print_iface_info(&do_show
, iface
);
1197 log_error("Could not read iface %s (%d).",
1207 /* TODO cleanup arguments */
1208 static int exec_node_op(int op
, int do_login
, int do_logout
,
1209 int do_show
, int do_rescan
, int do_stats
,
1210 int info_level
, struct node_rec
*rec
,
1211 char *name
, char *value
)
1214 struct db_set_param set_param
;
1217 log_debug(2, "%s: %s:%s node [%s,%s,%d]", __FUNCTION__
,
1218 rec
->iface
.transport_name
, rec
->iface
.name
,
1219 rec
->name
, rec
->conn
[0].address
, rec
->conn
[0].port
);
1222 if (add_static_recs(rec
))
1228 if (for_each_session(rec
, rescan_portal
))
1234 if (for_each_session(rec
, session_stats
))
1239 if (do_login
&& do_logout
) {
1240 log_error("either login or logout at the time allowed!");
1245 if ((do_login
|| do_logout
) && op
> OP_NOOP
) {
1246 log_error("either operation or login/logout "
1247 "at the time allowed!");
1252 if ((!do_login
&& !do_logout
&& op
== OP_NOOP
) &&
1253 (!strlen(rec
->name
) && !strlen(rec
->conn
[0].address
) &&
1254 !strlen(rec
->iface
.name
))) {
1255 rc
= print_nodes(info_level
, rec
);
1260 if (login_portals(rec
))
1268 if (iscsi_logout_portals(rec
, &nr_found
, 1,
1269 iscsi_logout_matched_portal
))
1274 if (op
== OP_NOOP
|| (!do_login
&& !do_logout
&& op
== OP_SHOW
)) {
1275 if (for_each_rec(rec
, &do_show
, idbm_print_node_info
))
1280 if (op
== OP_UPDATE
) {
1281 if (!name
|| !value
) {
1282 log_error("update requires name and value");
1287 /* compat - old tools used node and iface transport name */
1288 if (!strncmp(name
, "iface.", 6) &&
1289 strcmp(name
, "iface.transport_name")) {
1290 log_error("Cannot modify %s. Use iface mode to update "
1291 "this value.", name
);
1296 if (!strcmp(name
, "node.transport_name"))
1297 name
= "iface.transport_name";
1299 * tmp hack - we added compat crap above for the transport,
1300 * but want to fix Doran's issue in this release too. However
1301 * his patch is too harsh on many settings and we do not have
1302 * time to update apps so we have this tmp hack until we
1303 * can settle on a good interface that distros can use
1304 * and we can mark stable.
1306 if (!strcmp(name
, "iface.transport_name")) {
1307 if (iscsi_check_for_running_session(rec
)) {
1308 log_warning("Cannot modify node/iface "
1309 "transport name while a session "
1310 "is using it. Log out the session "
1311 "then update record.");
1317 set_param
.name
= name
;
1318 set_param
.value
= value
;
1320 if (for_each_rec(rec
, &set_param
, idbm_node_set_param
))
1323 } else if (op
== OP_DELETE
) {
1324 if (for_each_rec(rec
, NULL
, delete_node
))
1328 log_error("operation is not supported.");
1336 static int exec_fw_disc_op(discovery_rec_t
*drec
, struct list_head
*ifaces
,
1337 int info_level
, int do_login
, int op
)
1339 struct list_head targets
, rec_list
, new_ifaces
;
1340 struct iface_rec
*iface
, *tmp_iface
;
1341 struct node_rec
*rec
, *tmp_rec
;
1344 INIT_LIST_HEAD(&targets
);
1345 INIT_LIST_HEAD(&rec_list
);
1346 INIT_LIST_HEAD(&new_ifaces
);
1348 * compat: if the user did not pass any op then we do all
1352 op
= OP_NEW
| OP_DELETE
| OP_UPDATE
;
1355 * if a user passed in ifaces then we use them and ignore the ibft
1358 if (!list_empty(ifaces
)) {
1359 list_for_each_entry_safe(iface
, tmp_iface
, ifaces
, list
) {
1360 rc
= iface_conf_read(iface
);
1362 log_error("Could not read iface info for %s. "
1363 "Make sure a iface config with the "
1364 "file name and iface.iscsi_ifacename "
1365 "%s is in %s.", iface
->name
,
1366 iface
->name
, IFACE_CONFIG_DIR
);
1367 list_del_init(&iface
->list
);
1372 goto discover_fw_tgts
;
1376 * Next, check if we see any offload cards. If we do then
1377 * we make a iface if needed.
1379 * Note1: if there is not a offload card we do not setup
1380 * software iscsi binding with the nic used for booting,
1381 * because we do not know if that was intended.
1383 * Note2: we assume that the user probably wanted to access
1384 * all targets through all the ifaces instead of being limited
1385 * to what you can export in ibft.
1387 rc
= fw_get_targets(&targets
);
1389 log_error("Could not get list of targets from firmware. "
1393 rc
= iface_create_ifaces_from_boot_contexts(&new_ifaces
, &targets
);
1396 if (!list_empty(&new_ifaces
))
1397 ifaces
= &new_ifaces
;
1400 rc
= idbm_bind_ifaces_to_nodes(discovery_fw
, drec
,
1403 log_error("Could not perform fw discovery.\n");
1405 rc
= exec_disc_op_on_recs(drec
, &rec_list
, info_level
,
1409 fw_free_targets(&targets
);
1411 list_for_each_entry_safe(iface
, tmp_iface
, &new_ifaces
, list
) {
1412 list_del(&iface
->list
);
1416 list_for_each_entry_safe(rec
, tmp_rec
, &rec_list
, list
) {
1417 list_del(&rec
->list
);
1423 static int exec_fw_op(discovery_rec_t
*drec
, struct list_head
*ifaces
,
1424 int info_level
, int do_login
, int op
)
1426 struct boot_context
*context
;
1427 struct list_head targets
, rec_list
;
1428 struct node_rec
*rec
;
1431 INIT_LIST_HEAD(&targets
);
1432 INIT_LIST_HEAD(&rec_list
);
1435 return exec_fw_disc_op(drec
, ifaces
, info_level
, do_login
, op
);
1437 /* The following ops do not interact with the DB */
1438 rc
= fw_get_targets(&targets
);
1440 log_error("Could not get list of targets from firmware. "
1446 list_for_each_entry(context
, &targets
, list
) {
1447 rec
= idbm_create_rec_from_boot_context(context
);
1449 log_error("Could not convert firmware info to "
1455 iscsi_login_portal(NULL
, NULL
, rec
);
1459 list_for_each_entry(context
, &targets
, list
)
1460 fw_print_entry(context
);
1463 fw_free_targets(&targets
);
1468 main(int argc
, char **argv
)
1470 char *ip
= NULL
, *name
= NULL
, *value
= NULL
;
1471 char *targetname
= NULL
, *group_session_mgmt_mode
= NULL
;
1472 int ch
, longindex
, mode
=-1, port
=-1, do_login
=0, do_rescan
=0;
1473 int rc
=0, sid
=-1, op
=OP_NOOP
, type
=-1, do_logout
=0, do_stats
=0;
1474 int do_login_all
=0, do_logout_all
=0, info_level
=-1, num_ifaces
= 0;
1475 int tpgt
= PORTAL_GROUP_TAG_UNKNOWN
, killiscsid
=-1, do_show
=0;
1476 struct sigaction sa_old
;
1477 struct sigaction sa_new
;
1478 discovery_rec_t drec
;
1479 struct list_head ifaces
;
1480 struct iface_rec
*iface
= NULL
, *tmp
;
1481 struct node_rec
*rec
= NULL
;
1482 uint32_t host_no
= -1;
1484 memset(&drec
, 0, sizeof(discovery_rec_t
));
1485 INIT_LIST_HEAD(&ifaces
);
1486 /* do not allow ctrl-c for now... */
1487 memset(&sa_old
, 0, sizeof(struct sigaction
));
1488 memset(&sa_new
, 0, sizeof(struct sigaction
));
1490 sa_new
.sa_handler
= catch_sigint
;
1491 sigemptyset(&sa_new
.sa_mask
);
1492 sa_new
.sa_flags
= 0;
1493 sigaction(SIGINT
, &sa_new
, &sa_old
);
1497 /* enable stdout logging */
1498 log_init(program_name
, 1024, log_do_log_std
, NULL
);
1502 while ((ch
= getopt_long(argc
, argv
, short_options
,
1503 long_options
, &longindex
)) >= 0) {
1506 killiscsid
= atoi(optarg
);
1507 if (killiscsid
< 0) {
1508 log_error("Invalid killiscsid priority %d "
1509 "Priority must be greater than or "
1510 "equal to zero.", killiscsid
);
1516 type
= str_to_type(optarg
);
1519 op
|= str_to_op(optarg
);
1520 if (op
== OP_NOOP
) {
1521 log_error("can not recognize operation: '%s'",
1535 host_no
= strtoul(optarg
, NULL
, 10);
1537 log_error("invalid host no %s. %s.",
1538 optarg
, strerror(errno
));
1544 sid
= iscsi_sysfs_get_sid_from_path(optarg
);
1546 log_error("invalid sid '%s'",
1556 info_level
= atoi(optarg
);
1566 group_session_mgmt_mode
= optarg
;
1570 group_session_mgmt_mode
= optarg
;
1579 log_level
= atoi(optarg
);
1582 mode
= str_to_mode(optarg
);
1585 targetname
= optarg
;
1588 ip
= str_to_ipport(optarg
, &port
, &tpgt
);
1591 iface
= iface_alloc(optarg
, &rc
);
1593 printf("Invalid iface name %s. Must be from "
1594 "1 to %d characters.\n",
1595 optarg
, ISCSI_MAX_IFACE_LEN
- 1);
1598 } else if (!iface
|| rc
) {
1599 printf("Could not add iface %s.", optarg
);
1604 list_add_tail(&iface
->list
, &ifaces
);
1608 printf("%s version %s\n", program_name
,
1617 log_error("unrecognized character '%c'", optopt
);
1622 if (killiscsid
>= 0) {
1623 kill_iscsid(killiscsid
);
1630 if (mode
== MODE_FW
) {
1631 if ((rc
= verify_mode_params(argc
, argv
, "ml", 0))) {
1632 log_error("fw mode: option '-%c' is not "
1633 "allowed/supported", rc
);
1638 rc
= exec_fw_op(NULL
, NULL
, info_level
, do_login
, op
);
1642 increase_max_files();
1643 if (idbm_init(get_config_file
)) {
1644 log_warning("exiting due to idbm configuration error");
1649 if (mode
!= MODE_DISCOVERY
&& ip
)
1650 port
= ISCSI_LISTEN_PORT
;
1654 if ((rc
= verify_mode_params(argc
, argv
, "HdmP", 0))) {
1655 log_error("host mode: option '-%c' is not "
1656 "allowed/supported", rc
);
1661 rc
= host_info_print(info_level
, host_no
);
1664 iface_setup_host_bindings();
1666 if ((rc
= verify_mode_params(argc
, argv
, "IdnvmPo", 0))) {
1667 log_error("iface mode: option '-%c' is not "
1668 "allowed/supported", rc
);
1673 if (!list_empty(&ifaces
)) {
1674 iface
= list_entry(ifaces
.next
, struct iface_rec
,
1677 log_error("iface mode only accepts one "
1678 "interface. Using the first one "
1679 "%s.", iface
->name
);
1681 rc
= exec_iface_op(op
, do_show
, info_level
, iface
,
1684 case MODE_DISCOVERY
:
1685 if ((rc
= verify_mode_params(argc
, argv
, "SIPdmntplov", 0))) {
1686 log_error("discovery mode: option '-%c' is not "
1687 "allowed/supported", rc
);
1692 case DISCOVERY_TYPE_SENDTARGETS
:
1694 port
= ISCSI_LISTEN_PORT
;
1697 log_error("please specify right portal as "
1698 "<ipaddr>[:<ipport>]");
1703 if (idbm_discovery_read(&drec
, ip
, port
)) {
1704 idbm_sendtargets_defaults(&drec
.u
.sendtargets
);
1705 strlcpy(drec
.address
, ip
, sizeof(drec
.address
));
1709 if (do_sendtargets(&drec
, &ifaces
, info_level
,
1715 case DISCOVERY_TYPE_SLP
:
1716 log_error("SLP discovery is not fully "
1717 "implemented yet.");
1720 case DISCOVERY_TYPE_ISNS
:
1722 log_error("please specify right portal as "
1723 "<ipaddr>:[<ipport>]");
1728 strlcpy(drec
.address
, ip
, sizeof(drec
.address
));
1730 drec
.port
= ISNS_DEFAULT_PORT
;
1734 if (do_isns(&drec
, &ifaces
, info_level
, do_login
, op
)) {
1739 case DISCOVERY_TYPE_FW
:
1740 drec
.type
= DISCOVERY_TYPE_FW
;
1741 if (exec_fw_op(&drec
, &ifaces
, info_level
, do_login
,
1747 if (idbm_discovery_read(&drec
, ip
, port
)) {
1748 log_error("discovery record [%s,%d] "
1749 "not found!", ip
, port
);
1754 drec
.type
== DISCOVERY_TYPE_SENDTARGETS
) {
1755 do_sendtargets(&drec
, &ifaces
,
1756 info_level
, do_login
,
1758 } else if (do_login
&&
1759 drec
.type
== DISCOVERY_TYPE_SLP
) {
1760 log_error("SLP discovery is not fully "
1761 "implemented yet.");
1764 } else if (do_login
&&
1765 drec
.type
== DISCOVERY_TYPE_ISNS
) {
1766 log_error("iSNS discovery is not fully "
1767 "implemented yet.");
1770 } else if (op
== OP_NOOP
|| op
== OP_SHOW
) {
1771 if (!idbm_print_discovery_info(&drec
,
1773 log_error("no records found!");
1776 } else if (op
== OP_DELETE
) {
1777 if (idbm_delete_discovery(&drec
)) {
1778 log_error("unable to delete "
1782 } else if (op
== OP_UPDATE
) {
1783 struct db_set_param set_param
;
1785 if (!name
|| !value
) {
1786 log_error("Update requires "
1791 set_param
.name
= name
;
1792 set_param
.value
= value
;
1793 if (idbm_discovery_set_param(&set_param
,
1797 log_error("operation is not supported.");
1802 } else if (op
== OP_NOOP
|| op
== OP_SHOW
) {
1803 if (!idbm_print_all_discovery(info_level
))
1806 } else if (op
== OP_DELETE
) {
1807 log_error("--record required for delete operation");
1811 log_error("Operations: new and "
1812 "update for node is not fully "
1813 "implemented yet.");
1821 if ((rc
= verify_mode_params(argc
, argv
, "RsPIdmlSonvupTUL",
1823 log_error("node mode: option '-%c' is not "
1824 "allowed/supported", rc
);
1830 rc
= login_by_startup(group_session_mgmt_mode
);
1834 if (do_logout_all
) {
1835 rc
= logout_by_startup(group_session_mgmt_mode
);
1839 if (!list_empty(&ifaces
)) {
1840 iface
= list_entry(ifaces
.next
, struct iface_rec
,
1843 log_error("NODE mode only accepts one "
1844 "interface. Using the first one "
1845 "driver %s hwaddress %s ipaddress "
1846 "%s.", iface
->transport_name
,
1847 iface
->hwaddress
, iface
->ipaddress
);
1850 rec
= idbm_create_rec(targetname
, tpgt
, ip
, port
, iface
, 1);
1856 rc
= exec_node_op(op
, do_login
, do_logout
, do_show
,
1857 do_rescan
, do_stats
, info_level
, rec
,
1861 if ((rc
= verify_mode_params(argc
, argv
,
1862 "PiRdrmusonuSv", 1))) {
1863 log_error("session mode: option '-%c' is not "
1864 "allowed or supported", rc
);
1870 struct session_info
*info
;
1872 snprintf(session
, 63, "session%d", sid
);
1875 info
= calloc(1, sizeof(*info
));
1881 rc
= iscsi_sysfs_get_sessioninfo_by_id(info
, session
);
1883 log_error("Could not get session info for sid "
1889 * We should be able to go on, but for now
1890 * we only support session mode ops if the module
1891 * is loaded and we support that module.
1893 if (!iscsi_sysfs_get_transport_by_sid(sid
))
1896 if (!do_logout
&& !do_rescan
&& !do_stats
&&
1897 op
== OP_NOOP
&& info_level
> 0) {
1898 rc
= session_info_print(info_level
, info
);
1904 rec
= idbm_create_rec(info
->targetname
,
1906 info
->persistent_address
,
1907 info
->persistent_port
,
1914 /* drop down to node ops */
1915 rc
= exec_node_op(op
, do_login
, do_logout
, do_show
,
1916 do_rescan
, do_stats
, info_level
,
1922 if (do_logout
|| do_rescan
|| do_stats
) {
1923 rc
= exec_node_op(op
, do_login
, do_logout
,
1924 do_show
, do_rescan
, do_stats
,
1925 info_level
, NULL
, name
, value
);
1929 rc
= session_info_print(info_level
, NULL
);
1933 log_error("This mode is not yet supported");
1942 list_for_each_entry_safe(iface
, tmp
, &ifaces
, list
) {
1943 list_del(&iface
->list
);