[Pkg-iscsi-maintainers] [SCM] Debian Open-iSCSI Packaging branch, upstream-mnc, updated. 2.0-872-193-gde2c0e7

Mike Christie michaelc at cs.wisc.edu
Sat Apr 7 15:44:03 UTC 2012


The following commit has been merged in the upstream-mnc branch:
commit de3e77f4c432198502696790ff444d5b33f9d8ab
Author: Mike Christie <michaelc at cs.wisc.edu>
Date:   Tue Mar 6 05:08:36 2012 -0600

    iscsi tools: added ping support
    
    From: Vikas Chaudhary <vikas.chaudhary at qlogic.com>
    
    Added ping support for network connection diagnostics.
    
    [cleaned up output by Mike Christie]
    Signed-off-by: Vikas Chaudhary <vikas.chaudhary at qlogic.com>

diff --git a/include/iscsi_err.h b/include/iscsi_err.h
index d1d94b5..e038f1c 100644
--- a/include/iscsi_err.h
+++ b/include/iscsi_err.h
@@ -58,6 +58,8 @@ enum {
 	ISCSI_ERR_ISNS_QUERY		= 25,
 	/* iSNS registration/deregistration failed */
 	ISCSI_ERR_ISNS_REG_FAILED	= 26,
+	/* operation not supported */
+	ISCSI_ERR_OP_NOT_SUPP		= 27,
 
 	/* Always last. Indicates end of error code space */
 	ISCSI_MAX_ERR_VAL,
diff --git a/include/iscsi_if.h b/include/iscsi_if.h
index 540cd8d..26182aa 100644
--- a/include/iscsi_if.h
+++ b/include/iscsi_if.h
@@ -65,8 +65,9 @@ enum iscsi_uevent_e {
 
 	ISCSI_UEVENT_PATH_UPDATE	= UEVENT_BASE + 20,
 	ISCSI_UEVENT_SET_IFACE_PARAMS	= UEVENT_BASE + 21,
+	ISCSI_UEVENT_PING		= UEVENT_BASE + 22,
 
-	ISCSI_UEVENT_MAX		= ISCSI_UEVENT_SET_IFACE_PARAMS,
+	ISCSI_UEVENT_MAX		= ISCSI_UEVENT_PING,
 
 	/* up events */
 	ISCSI_KEVENT_RECV_PDU		= KEVENT_BASE + 1,
@@ -80,8 +81,9 @@ enum iscsi_uevent_e {
 	ISCSI_KEVENT_IF_DOWN		= KEVENT_BASE + 8,
 	ISCSI_KEVENT_CONN_LOGIN_STATE   = KEVENT_BASE + 9,
 	ISCSI_KEVENT_HOST_EVENT		= KEVENT_BASE + 10,
+	ISCSI_KEVENT_PING_COMP		= KEVENT_BASE + 11,
 
-	ISCSI_KEVENT_MAX		= ISCSI_KEVENT_HOST_EVENT,
+	ISCSI_KEVENT_MAX		= ISCSI_KEVENT_PING_COMP,
 };
 
 enum iscsi_tgt_dscvr {
@@ -195,6 +197,14 @@ struct iscsi_uevent {
 			uint32_t	host_no;
 			uint32_t	count;
 		} set_iface_params;
+		struct msg_iscsi_ping {
+			uint32_t	host_no;
+			uint32_t	iface_num;
+			uint32_t	iface_type;
+			uint32_t	payload_size;
+			uint32_t	pid;	/* unique ping id associated
+						   with each ping request */
+		} iscsi_ping;
 	} u;
 	union {
 		/* messages k -> u */
@@ -244,6 +254,13 @@ struct iscsi_uevent {
 			uint32_t	data_size;
 			enum iscsi_host_event_code code;
 		} host_event;
+		struct msg_ping_comp {
+			uint32_t	host_no;
+			uint32_t	status;
+			uint32_t	pid;	/* unique ping id associated
+						   with each ping request */
+			uint32_t	data_size;
+		} ping_comp;
 	} r;
 } __attribute__ ((aligned (sizeof(uint64_t))));
 
diff --git a/usr/iface.c b/usr/iface.c
index 730820c..1e7f46a 100644
--- a/usr/iface.c
+++ b/usr/iface.c
@@ -425,12 +425,23 @@ int iface_get_by_net_binding(struct iface_rec *pattern,
 	return ISCSI_ERR_NO_OBJS_FOUND;
 }
 
-static int iface_get_iptype(struct iface_rec *iface)
+int iface_get_iptype(struct iface_rec *iface)
 {
-	if (strcmp(iface->bootproto, "dhcp") && !strstr(iface->ipaddress, "."))
-		return ISCSI_IFACE_TYPE_IPV6;
-	else
-		return ISCSI_IFACE_TYPE_IPV4;
+	/* address might not be set if user config with another tool */
+	if (!strlen(iface->ipaddress) ||
+	    !strcmp(UNKNOWN_VALUE, iface->ipaddress)) {
+		/* try to figure out by name */
+		if (strstr(iface->name, "ipv4"))
+			return ISCSI_IFACE_TYPE_IPV4;
+		else
+			return ISCSI_IFACE_TYPE_IPV6;
+	} else {
+		if (strcmp(iface->bootproto, "dhcp") &&
+		    !strstr(iface->ipaddress, "."))
+			return ISCSI_IFACE_TYPE_IPV6;
+		else
+			return ISCSI_IFACE_TYPE_IPV4;
+	}
 }
 
 static int iface_setup_binding_from_kern_iface(void *data,
diff --git a/usr/iface.h b/usr/iface.h
index 3ba2a4e..f6c2c33 100644
--- a/usr/iface.h
+++ b/usr/iface.h
@@ -58,6 +58,7 @@ extern int iface_get_param_count(struct iface_rec *iface_primary,
 				 int iface_all);
 extern int iface_build_net_config(struct iface_rec *iface_primary,
 				  int iface_all, struct iovec *iovs);
+extern int iface_get_iptype(struct iface_rec *iface);
 
 #define iface_fmt "[hw=%s,ip=%s,net_if=%s,iscsi_if=%s]"
 #define iface_str(_iface) \
diff --git a/usr/iscsi_err.c b/usr/iscsi_err.c
index 9b27239..4936e45 100644
--- a/usr/iscsi_err.c
+++ b/usr/iscsi_err.c
@@ -49,6 +49,7 @@ static char *iscsi_err_msgs[] = {
 	/* 24 */ "iSCSI login failed due to authorization failure",
 	/* 25 */ "iSNS query failed",
 	/* 26 */ "iSNS registration failed",
+	/* 27 */ "operation not supported",
 };
 
 char *iscsi_err_to_str(int err)
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
index fc67c4a..a00135f 100644
--- a/usr/iscsi_ipc.h
+++ b/usr/iscsi_ipc.h
@@ -134,6 +134,10 @@ struct iscsi_ipc {
 			       struct iovec *iovs, uint32_t param_count);
 
 	int (*recv_conn_state) (struct iscsi_conn *conn, uint32_t *state);
+
+	int (*exec_ping) (uint64_t transport_handle, uint32_t host_no,
+			  struct sockaddr *addr, uint32_t iface_num,
+			  uint32_t iface_type, uint32_t size);
 };
 
 #endif /* ISCSI_IPC_H */
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index 03b779e..7ff8728 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
+#include <time.h>
 #include <sys/stat.h>
 
 #include "initiator.h"
@@ -51,6 +52,7 @@
 #include "isns-proto.h"
 #include "iscsi_err.h"
 #include "iscsi_ipc.h"
+#include "iscsi_timer.h"
 
 static char program_name[] = "iscsiadm";
 static char config_file[TARGET_NAME_MAXLEN];
@@ -64,6 +66,7 @@ enum iscsiadm_mode {
 	MODE_HOST,
 	MODE_IFACE,
 	MODE_FW,
+	MODE_PING,
 };
 
 enum iscsiadm_op {
@@ -102,9 +105,13 @@ static struct option const long_options[] =
 	{"show", no_argument, NULL, 'S'},
 	{"version", no_argument, NULL, 'V'},
 	{"help", no_argument, NULL, 'h'},
+	{"submode", required_argument, NULL, 'C'},
+	{"ip", required_argument, NULL, 'a'},
+	{"packetsize", required_argument, NULL, 'b'},
+	{"count", required_argument, NULL, 'c'},
 	{NULL, 0, NULL, 0},
 };
-static char *short_options = "RlDVhm:p:P:T:H:I:U:k:L:d:r:n:v:o:sSt:u";
+static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:u";
 
 static void usage(int status)
 {
@@ -116,10 +123,10 @@ static void usage(int status)
 iscsiadm -m discoverydb [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -Dl ] ] | [ [ -p ip:port -t type] \
 [ -o operation ] [ -n name ] [ -v value ] [ -lD ] ] \n\
 iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -l ] ] | [ [ -p ip:port ] [ -l | -D ] ] \n\
-iiscsiadm -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] ] \
+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] ] \
 [ [ -o  operation  ] [ -n name ] [ -v value ] ]\n\
 iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P  printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\
-iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o  operation  ] [ -n name ] [ -v value ] ]\n\
+iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o  operation  ] [ -n name ] [ -v value ] ] [ -C ping [ -a ip ] [ -b packetsize ] [ -c count ] [ -i interval ] ]\n\
 iscsiadm -m fw [ -l ]\n\
 iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ]\n\
 iscsiadm -k priority\n");
@@ -178,6 +185,19 @@ str_to_mode(char *str)
 }
 
 static int
+str_to_submode(char *str)
+{
+	int sub_mode;
+
+	if (!strcmp("ping", str))
+		sub_mode = MODE_PING;
+	else
+		sub_mode = -1;
+
+	return sub_mode;
+}
+
+static int
 str_to_type(char *str)
 {
 	int type;
@@ -2082,6 +2102,101 @@ static uint32_t parse_host_info(char *optarg, int *rc)
 	return host_no;
 }
 
+static int exec_ping_op(struct iface_rec *iface, char *ip, int size, int count,
+			int interval)
+{
+	int rc = ISCSI_ERR;
+	uint32_t iface_type = ISCSI_IFACE_TYPE_IPV4;
+	struct iscsi_transport *t = NULL;
+	uint32_t host_no;
+	struct sockaddr_storage addr;
+	int i;
+
+	if (!iface) {
+		log_error("Ping requires iface.");
+		rc = ISCSI_ERR_INVAL;
+		goto ping_exit;
+	}
+
+	if (!ip) {
+		log_error("Ping requires destination ipaddress.");
+		rc = ISCSI_ERR_INVAL;
+		goto ping_exit;
+	}
+
+	if (size <= 0) {
+		log_error("Invalid packet size: %d.", size);
+		rc = ISCSI_ERR_INVAL;
+		goto ping_exit;
+	}
+
+	if (count <= 0) {
+		log_error("Invalid number of packets to transmit: %d.", count);
+		rc = ISCSI_ERR_INVAL;
+		goto ping_exit;
+	}
+
+	if (interval < 0) {
+		log_error("Invalid timing interval: %d.", interval);
+		rc = ISCSI_ERR_INVAL;
+		goto ping_exit;
+	}
+
+	rc = iface_conf_read(iface);
+	if (rc) {
+		log_error("Could not read iface %s (%d).", iface->name, rc);
+		goto ping_exit;
+	}
+
+
+	iface_type = iface_get_iptype(iface);
+
+	t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
+	if (!t) {
+		log_error("Can't find transport.");
+		rc = ISCSI_ERR_INVAL;
+		goto ping_exit;
+	}
+
+	host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
+	if (host_no == -1) {
+		log_error("Can't find host_no.");
+		rc = ISCSI_ERR_INVAL;
+		goto ping_exit;
+	}
+
+	rc = resolve_address(ip, NULL, &addr);
+	if (rc) {
+		log_error("Invalid IP address.");
+		rc = ISCSI_ERR_INVAL;
+		goto ping_exit;
+	}
+
+	/* TODO: move this. It is needed by interface for pid */
+	srand(time(NULL));
+
+	for (i = 1; i <= count; i++) {
+		/*
+		 * To support drivers like bnx2i that do not use
+		 * the iscsi if to send a ping, we can add a transport
+		 * callout here.
+		 */
+		rc = ipc->exec_ping(t->handle, host_no,
+				    (struct sockaddr *)&addr, iface->iface_num,
+				    iface_type, size);
+		if (!rc)
+			printf("Ping %d completed\n", i);
+		else
+			printf("Ping %d failed: %s\n", i, iscsi_err_to_str(rc));
+
+		if (i < count)
+			sleep(interval);
+	}
+
+ping_exit:
+	return rc;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -2091,7 +2206,8 @@ main(int argc, char **argv)
 	int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0;
 	int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0;
 	int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0;
-	int do_discover = 0;
+	int packet_size=32, ping_count=1, ping_interval=0;
+	int do_discover = 0, sub_mode = -1;
 	struct sigaction sa_old;
 	struct sigaction sa_new;
 	struct list_head ifaces;
@@ -2196,12 +2312,27 @@ main(int argc, char **argv)
 		case 'm':
 			mode = str_to_mode(optarg);
 			break;
+		case 'C':
+			sub_mode = str_to_submode(optarg);
+			break;
 		case 'T':
 			targetname = optarg;
 			break;
 		case 'p':
 			ip = str_to_ipport(optarg, &port, &tpgt);
 			break;
+		case 'a':
+			ip = optarg;
+			break;
+		case 'b':
+			packet_size = atoi(optarg);
+			break;
+		case 'c':
+			ping_count = atoi(optarg);
+			break;
+		case 'i':
+			ping_interval = atoi(optarg);
+			break;
 		case 'I':
 			iface = iface_alloc(optarg, &rc);
 			if (rc == ISCSI_ERR_INVAL) {
@@ -2274,7 +2405,7 @@ main(int argc, char **argv)
 	case MODE_IFACE:
 		iface_setup_host_bindings();
 
-		if ((rc = verify_mode_params(argc, argv, "HIdnvmPo", 0))) {
+		if ((rc = verify_mode_params(argc, argv, "HIdnvmPoCabci", 0))) {
 			log_error("iface mode: option '-%c' is not "
 				  "allowed/supported", rc);
 			rc = ISCSI_ERR_INVAL;
@@ -2289,8 +2420,14 @@ main(int argc, char **argv)
 					  "interface. Using the first one "
 					  "%s.", iface->name);
 		}
-		rc = exec_iface_op(op, do_show, info_level, iface, host_no,
-				   name, value);
+
+		if (sub_mode == MODE_PING)
+			rc = exec_ping_op(iface, ip, packet_size, ping_count,
+					  ping_interval);
+		else
+			rc = exec_iface_op(op, do_show, info_level, iface,
+					   host_no, name, value);
+
 		break;
 	case MODE_DISCOVERYDB:
 		if ((rc = verify_mode_params(argc, argv, "DSIPdmntplov", 0))) {
diff --git a/usr/netlink.c b/usr/netlink.c
index 0e842b5..f680b31 100644
--- a/usr/netlink.c
+++ b/usr/netlink.c
@@ -25,10 +25,12 @@
 #include <unistd.h>
 #include <stdint.h>
 #include <errno.h>
+#include <time.h>
 #include <inttypes.h>
 #include <asm/types.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <sys/poll.h>
 #include <linux/netlink.h>
 
 #include "types.h"
@@ -39,6 +41,8 @@
 #include "iscsi_sysfs.h"
 #include "transport.h"
 #include "iscsi_netlink.h"
+#include "iscsi_err.h"
+#include "iscsi_timer.h"
 
 static int ctrl_fd;
 static struct sockaddr_nl src_addr, dest_addr;
@@ -64,6 +68,15 @@ static int ctldev_handle(void);
 
 #define NLM_SETPARAM_DEFAULT_MAX (NI_MAXHOST + 1 + sizeof(struct iscsi_uevent))
 
+struct iscsi_ping_event {
+	uint32_t host_no;
+	uint32_t pid;
+	int32_t status;
+	int active;
+};
+
+struct iscsi_ping_event ping_event;
+
 struct nlattr *iscsi_nla_alloc(uint16_t type, uint16_t len)
 {
 	struct nlattr *attr;
@@ -1024,6 +1037,149 @@ exit:
 	return rc;
 }
 
+
+
+
+static int
+ksend_ping(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr,
+	   uint32_t iface_num, uint32_t iface_type, uint32_t pid, uint32_t size)
+{
+	int rc, addrlen;
+	struct iscsi_uevent *ev;
+	struct iovec iov[2];
+
+	log_debug(8, "in %s", __FUNCTION__);
+
+	memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
+	ev = (struct iscsi_uevent *)setparam_buf;
+	ev->type = ISCSI_UEVENT_PING;
+	ev->transport_handle = transport_handle;
+	ev->u.iscsi_ping.host_no = host_no;
+	ev->u.iscsi_ping.iface_num = iface_num;
+	ev->u.iscsi_ping.iface_type = iface_type;
+	ev->u.iscsi_ping.payload_size = size;
+	ev->u.iscsi_ping.pid = pid;
+
+	if (addr->sa_family == PF_INET)
+		addrlen = sizeof(struct sockaddr_in);
+	else if (addr->sa_family == PF_INET6)
+		addrlen = sizeof(struct sockaddr_in6);
+	else {
+		log_error("%s unknown addr family %d\n",
+			  __FUNCTION__, addr->sa_family);
+		return -EINVAL;
+	}
+	memcpy(setparam_buf + sizeof(*ev), addr, addrlen);
+
+	iov[1].iov_base = ev;
+	iov[1].iov_len = sizeof(*ev) + addrlen;
+	rc = __kipc_call(iov, 2);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int kexec_ping(uint64_t transport_handle, uint32_t host_no,
+		      struct sockaddr *addr, uint32_t iface_num,
+		      uint32_t iface_type, uint32_t size)
+{
+	struct pollfd pfd;
+	struct timeval ping_timer;
+	int timeout, fd, rc;
+	uint32_t pid;
+
+	fd = ipc->ctldev_open();
+	if (fd < 0) {
+		log_error("Could not open netlink socket.");
+		return ISCSI_ERR;
+	}
+
+	/* prepare to poll */
+	memset(&pfd, 0, sizeof(pfd));
+	pfd.fd = fd;
+	pfd.events = POLLIN | POLLPRI;
+
+	/* get unique ping id */
+	pid = rand();
+
+	rc = ksend_ping(transport_handle, host_no, addr, iface_num,
+			iface_type, pid, size);
+	if (rc != 0) {
+		switch (rc) {
+		case -ENOSYS:
+			rc = ISCSI_ERR_OP_NOT_SUPP;
+			break;
+		case -EINVAL:
+			rc = ISCSI_ERR_INVAL;
+			break;
+		default:
+			rc = ISCSI_ERR;
+		}
+		goto close_nl;
+	}
+
+	ping_event.host_no = -1;
+	ping_event.pid = -1;
+	ping_event.status = -1;
+	ping_event.active = -1;
+
+	iscsi_timer_set(&ping_timer, 30);
+
+	timeout = iscsi_timer_msecs_until(&ping_timer);
+
+	while (1) {
+		pfd.revents = 0;
+		rc = poll(&pfd, 1, timeout);
+
+		if (iscsi_timer_expired(&ping_timer)) {
+			rc = ISCSI_ERR_TRANS_TIMEOUT;
+			break;
+		}
+
+		if (rc > 0) {
+			if (pfd.revents & (POLLIN | POLLPRI)) {
+				timeout = iscsi_timer_msecs_until(&ping_timer);
+				rc = ipc->ctldev_handle();
+
+				if (ping_event.active != 1)
+					continue;
+
+				if (pid != ping_event.pid)
+					continue;
+
+				if (ping_event.status == 0)
+					rc = 0;
+				else
+					rc = ISCSI_ERR;
+				break;
+			}
+
+			if (pfd.revents & POLLHUP) {
+				rc = ISCSI_ERR_TRANS;
+				break;
+			}
+
+			if (pfd.revents & POLLNVAL) {
+				rc = ISCSI_ERR_INTERNAL;
+				break;
+			}
+
+			if (pfd.revents & POLLERR) {
+				rc = ISCSI_ERR_INTERNAL;
+				break;
+			}
+		} else if (rc < 0) {
+			rc = ISCSI_ERR_INTERNAL;
+			break;
+		}
+	}
+
+close_nl:
+	ipc->ctldev_close();
+	return rc;
+}
+
 static void drop_data(struct nlmsghdr *nlh)
 {
 	int ev_size;
@@ -1106,6 +1262,14 @@ static int ctldev_handle(void)
 
 		drop_data(nlh);
 		return 0;
+	case ISCSI_KEVENT_PING_COMP:
+		ping_event.host_no = ev->r.ping_comp.host_no;
+		ping_event.pid = ev->r.ping_comp.pid;
+		ping_event.status = ev->r.ping_comp.status;
+		ping_event.active = 1;
+
+		drop_data(nlh);
+		return 0;
 	default:
 		if ((ev->type > ISCSI_UEVENT_MAX && ev->type < KEVENT_BASE) ||
 		    (ev->type > ISCSI_KEVENT_MAX))
@@ -1299,6 +1463,7 @@ struct iscsi_ipc nl_ipc = {
 	.recv_pdu_end           = krecv_pdu_end,
 	.set_net_config         = kset_net_config,
 	.recv_conn_state        = krecv_conn_state,
+	.exec_ping		= kexec_ping,
 };
 struct iscsi_ipc *ipc = &nl_ipc;
 

-- 
Debian Open-iSCSI Packaging



More information about the Pkg-iscsi-maintainers mailing list