All,

Please ignore the patch in my previous email and use the one attached instead.

I fixed a bug in the previous patch where "iscsistart -n" was assuming that the 
interface being configured was already up.

Regards,

Alex

Alex Zeffertt wrote:
> Please could the attached patch be considered for inclusion in the 
> open-iscsi
> source.  Note: this patch depends on support-multidisk-ibft.patch sent 
> earlier.
> 
> Regards,
> 
> Alex Zeffertt
> 
> Changelog:
> ---------
> 
> For each target listed, iSCSI Boot Firmware Tables specify which NIC to 
> use and how it should be configured.  Until now this information has 
> been ignored by open-iscsi.
> 
> This patch enables this information to be listed by iscsiadm/iscsistart, 
> and it also enables iscsistart to apply the configuration.
> 
> The existing commands "iscsiadm -m fw" and "iscsistart -f" now list the 
> NIC configuration from the iBFT in addition to the other information.
> 
> The new command "iscsiadm -n" applies the NIC configuration specified in 
> the iBFT for each valid target.
> 
> The primary benefit of this is that it allows the initrd to extract 
> networking information from the iBFT rather than hard code it.  If the 
> initrd uses the iBFT for networking info then when the setup is modified 
> via the BIOS it is not necessary to rebuild the initrd.
> 
> 

--

You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To post to this group, send email to open-is...@googlegroups.com.
To unsubscribe from this group, send email to 
open-iscsi+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/open-iscsi?hl=en.


diff -r 64c9bc1babc0 include/fw_context.h
--- a/include/fw_context.h	Thu Dec 17 12:49:46 2009 +0000
+++ b/include/fw_context.h	Fri Dec 18 14:49:36 2009 +0000
@@ -35,6 +35,7 @@
 	char mac[18];
 	char ipaddr[18];
 	char mask[18];
+	char gateway[18];
 	char lun[17];
 	char vlan[15];
 	char isid[10];
diff -r 64c9bc1babc0 usr/iscsi_sysfs.c
--- a/usr/iscsi_sysfs.c	Thu Dec 17 12:49:46 2009 +0000
+++ b/usr/iscsi_sysfs.c	Fri Dec 18 14:49:36 2009 +0000
@@ -40,6 +40,7 @@
 #define ISCSI_TRANSPORT_DIR	"/sys/class/iscsi_transport"
 #define ISCSI_SESSION_DIR	"/sys/class/iscsi_session"
 #define ISCSI_HOST_DIR		"/sys/class/iscsi_host"
+#define NETDEV_DIR			"/sys/class/net"
 
 #define ISCSI_SYSFS_INVALID_VALUE	"<NULL>"
 #define ISCSI_SESSION_SUBSYS		"iscsi_session"
@@ -49,6 +50,7 @@
 #define SCSI_HOST_SUBSYS		"scsi_host"
 #define SCSI_DEVICE_SUBSYS		"scsi_device"
 #define SCSI_SUBSYS			"scsi"
+#define NET_SUBSYS			"net"
 
 #define ISCSI_MAX_SYSFS_BUFFER NI_MAXHOST
 
@@ -121,6 +123,7 @@
 
 iscsi_sysfs_get_param_by_str(transport, ISCSI_TRANSPORT_SUBSYS);
 iscsi_sysfs_get_param_by_str(scsi_dev, SCSI_SUBSYS);
+iscsi_sysfs_get_param_by_str(netdev, NET_SUBSYS);
 
 static int iscsi_sysfs_set_param(char *id, char *subsys, char *attr_name,
 				 char *write_buf, ssize_t buf_size)
@@ -657,6 +660,46 @@
 	return ret;
 }
 
+static int get_netdev_mac(char *netdev, char mac[18])
+{
+	return iscsi_sysfs_get_netdev_param(netdev, "address", mac, "%s");
+}
+
+int iscsi_sysfs_get_netdev_by_mac(char mac[18], char netdev[], int len)
+{
+	struct dirent **namelist;
+	int n, i;
+	int retval = -1;
+
+	n = scandir(NETDEV_DIR, &namelist, NULL, direntcmp);
+	if (n <= 0)
+		return n;
+
+	for (i = 0; i < n; i++) {
+		char *name = namelist[i]->d_name;
+		char buf[18];
+        if (!strcmp(name, ".") || !strcmp(name, ".."))
+			continue;
+		
+		if (get_netdev_mac(name, buf)) {
+			log_error("could not find mac address for %s", name);
+			continue;
+		}
+		
+		if (strncasecmp(buf, mac, 17) == 0) {
+			strlcpy(netdev, name, len);
+			retval = 0;
+			break;
+		}
+	}
+
+	for (i = 0; i < n; i++)
+		free(namelist[i]);
+	free(namelist);
+
+	return retval;	
+}
+
 int iscsi_sysfs_for_each_host(void *data, int *nr_found,
 			      iscsi_sysfs_host_op_fn *fn)
 {
diff -r 64c9bc1babc0 usr/iscsi_sysfs.h
--- a/usr/iscsi_sysfs.h	Thu Dec 17 12:49:46 2009 +0000
+++ b/usr/iscsi_sysfs.h	Fri Dec 18 14:49:36 2009 +0000
@@ -97,6 +97,7 @@
 extern struct iscsi_transport *iscsi_sysfs_get_transport_by_session(char *sys_session);
 extern struct iscsi_transport *iscsi_sysfs_get_transport_by_sid(uint32_t sid);
 extern struct iscsi_transport *iscsi_sysfs_get_transport_by_name(char *transport_name);
+extern int iscsi_sysfs_get_netdev_by_mac(char mac[18], char netdev[], int len);
 
 extern struct list_head transports;
 
diff -r 64c9bc1babc0 usr/iscsistart.c
--- a/usr/iscsistart.c	Thu Dec 17 12:49:46 2009 +0000
+++ b/usr/iscsistart.c	Fri Dec 18 14:49:36 2009 +0000
@@ -24,6 +24,7 @@
 #include <getopt.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stddef.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
@@ -32,6 +33,11 @@
 #include <sys/signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/route.h>
 
 #include "initiator.h"
 #include "iscsi_ipc.h"
@@ -93,7 +99,8 @@
   -U, --username_in=N      set incoming username to N (optional)\n\
   -W, --password_in=N      set incoming password to N (optional\n\
   -d, --debug debuglevel   print debugging information \n\
-  -b, --fwparam_connect    create a session to the target\n\
+  -b, --fwparam_connect    create a session to the target using iBFT\n\
+  -n, --fwparam_network    bring up the network as specified by iBFT\n\
   -f, --fwparam_print      print the iBFT to STDOUT \n\
   -h, --help               display this help and exit\n\
   -v, --version            display version and exit\n\
@@ -206,13 +213,14 @@
 	struct utsname host_info; /* will use to compound initiator alias */
 	struct iscsi_auth_config *auth;
 	char *initiatorname = NULL;
-	int ch, longindex, entries;
+	int ch, longindex, entries, rc;
 	struct sigaction sa_old;
 	struct sigaction sa_new;
 	struct boot_context context[FWPARAM_MAX_ENTRIES];
 	struct boot_context *pcontext;
 	node_rec_t *config_rec;
 	pid_t pid;
+	int i;
 
 	config_rec = alloc_node();
 	list_add_tail(&config_rec->list, &node_list);
@@ -223,7 +231,7 @@
 	sa_new.sa_flags = 0;
 	sigaction(SIGINT, &sa_new, &sa_old );
 
-	while ((ch = getopt_long(argc, argv, "i:t:g:a:p:d:u:w:U:W:bfvh",
+	while ((ch = getopt_long(argc, argv, "i:t:g:a:p:d:u:w:U:W:bnfvh",
 				 long_options, &longindex)) >= 0) {
 		switch (ch) {
 		case 'i':
@@ -314,6 +322,126 @@
 				}
 			}
 			break;
+		case 'n':
+			/* 
+			 * Bring up NICs required by targets in iBFT 
+			 * using IP addresses and routing info from iBFT.
+			 */ 
+			rc = 0;
+			entries = fw_get_entry(context, FWPARAM_MAX_ENTRIES, NULL);
+			if (entries == 0) {
+				printf("Could not find fw values.\n");
+				exit(-1);
+			}
+			for (i = 0; i < entries; i++) {
+					
+				/* Bring up NIC with correct address  - unless it
+				 * has already been handled (2 targets in IBFT may share one NIC)
+				 */
+
+				struct sockaddr_in ipaddr = { .sin_family = AF_INET };
+				struct sockaddr_in netmask = { .sin_family = AF_INET };
+				struct sockaddr_in hostmask = { .sin_family = AF_INET };
+				struct sockaddr_in gateway = { .sin_family = AF_INET };
+				struct sockaddr_in tgt_ipaddr = { .sin_family = AF_INET };
+				struct rtentry rt;
+				struct ifreq ifr;
+				int sock;
+
+				if (!strlen(context[i].iface)) {
+					printf("No iface in fw entry %d\n", i);
+					rc = -1;
+					continue;
+				}
+				if (!inet_aton(context[i].ipaddr, &ipaddr.sin_addr)) {
+					printf("Invalid or no ipaddr in fw entry %d\n", i);
+					rc = -1;
+					continue;
+				}
+
+				if (!inet_aton(context[i].mask, &netmask.sin_addr)) {
+					printf("Invalid or no netmask in fw entry %d\n", i);
+					rc = -1;
+					continue;
+				}
+				inet_aton("255.255.255.255", &hostmask.sin_addr);
+
+				if (!inet_aton(context[i].target_ipaddr, &tgt_ipaddr.sin_addr)) {
+					printf("Invalid or no target ipaddr in fw entry %d\n", i);
+					rc = -1;
+					continue;
+				}
+
+				/* Got iface, IP address and netmask, and tgt_ip */
+				sock = socket(AF_INET, SOCK_DGRAM, 0);
+				
+				/* Only set IP/NM if this is a new interface */
+				if (!(i == 1 && strcmp(context[0].iface, context[1].iface) == 0)) {
+					
+					/* TODO: create vlan if strlen(context[i].vlan) */
+
+					/* Bring up interface */
+					memset(&ifr, 0, sizeof(ifr));
+					strncpy(ifr.ifr_name, context[i].iface, IFNAMSIZ);
+					ifr.ifr_flags = IFF_UP | IFF_RUNNING;
+					if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+						perror("ioctl(SIOCSIFFLAGS)");
+						exit(-1);
+					}
+
+					/* Set IP address */
+					memset(&ifr, 0, sizeof(ifr));
+					strncpy(ifr.ifr_name, context[i].iface, IFNAMSIZ);
+					memcpy(&ifr.ifr_addr, &ipaddr, sizeof(struct sockaddr));
+					if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
+						perror("ioctl(SIOCSIFADDR)");
+						exit(-1);
+					}
+					/* Set netmask */
+					memset(&ifr, 0, sizeof(ifr));
+					strncpy(ifr.ifr_name, context[i].iface, IFNAMSIZ);
+					memcpy(&ifr.ifr_addr, &netmask, sizeof(struct sockaddr));
+					if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) {
+						perror("ioctl(SIOCSIFNETMASK)");
+						exit(-1);
+					}
+				}
+
+				/* Set static route to target via this interface */
+				memset((char *) &rt, 0, sizeof(rt));
+				memcpy(&rt.rt_dst, &tgt_ipaddr, sizeof(tgt_ipaddr));
+				memcpy(&rt.rt_genmask, &hostmask, sizeof(hostmask));
+				rt.rt_flags = RTF_UP | RTF_HOST;
+				rt.rt_dev = context[i].iface;
+
+				if ((tgt_ipaddr.sin_addr.s_addr & netmask.sin_addr.s_addr) == 
+					(    ipaddr.sin_addr.s_addr & netmask.sin_addr.s_addr)) {
+					/* Same subnet */
+					if (ioctl(sock, SIOCADDRT, &rt) < 0) {
+						if (errno != EEXIST) {
+							perror("ioctl(SIOCADDRT)");
+							exit(-1);
+						}
+					}
+				} else {
+					/* Different subnet.  Use gateway */
+					rt.rt_flags |= RTF_GATEWAY;
+					if (!inet_aton(context[i].gateway, &gateway.sin_addr)) {
+						printf("Invalid or no gateway in fw entry %d\n", i);
+						exit(-1);
+					}
+					memcpy(&rt.rt_gateway, &gateway, sizeof(gateway));
+					if (ioctl(sock, SIOCADDRT, &rt) < 0) {
+						if (errno != EEXIST) {
+							perror("ioctl(SIOCADDRT)");
+							exit(-1);
+						}
+					}
+				}
+				close(sock);
+			}
+			exit(rc);
+			break;
 		case 'f':
 			entries = fw_get_entry(context, FWPARAM_MAX_ENTRIES, NULL);
 			if (entries == 0) {
diff -r 64c9bc1babc0 utils/fwparam_ibft/fw_entry.c
--- a/utils/fwparam_ibft/fw_entry.c	Thu Dec 17 12:49:46 2009 +0000
+++ b/utils/fwparam_ibft/fw_entry.c	Fri Dec 18 14:49:36 2009 +0000
@@ -82,9 +82,37 @@
 		       context->chap_password_in);
 }
 
+static void dump_nic(struct boot_context *context)
+{
+
+	if (strlen(context->iface))
+		printf("iface.net_ifacename = %s\n", context->iface);
+	else
+		printf("iface.net_ifacename = default\n");
+
+	if (strlen(context->mac))
+		printf("iface.hwaddress = %s\n", context->mac);
+	else
+		printf("iface.hwaddress = default\n");
+
+	if (strlen(context->ipaddr))
+		printf("iface.ipaddress = %s\n", context->ipaddr);
+	else
+		printf("iface.ipaddress = default\n");
+
+	/* These next two are not standard open-iscsi attributes */
+	if (strlen(context->mask))
+		printf("iface.ibft_net_mask = %s\n", context->mask);
+	if (strlen(context->gateway))
+		printf("iface.ibft_gateway = %s\n", context->gateway);
+	if (strlen(context->vlan))
+		printf("iface.ibft_net_vlan = %s\n", context->vlan);
+}
+
 void fw_print_entry(struct boot_context *context)
 {
 	dump_initiator(context);
 	dump_mac(context);
 	dump_target(context);
+	dump_nic(context);
 }
diff -r 64c9bc1babc0 utils/fwparam_ibft/fwparam_ibft.c
--- a/utils/fwparam_ibft/fwparam_ibft.c	Thu Dec 17 12:49:46 2009 +0000
+++ b/utils/fwparam_ibft/fwparam_ibft.c	Fri Dec 18 14:49:36 2009 +0000
@@ -30,9 +30,13 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
 
 #include "fwparam_ibft.h"
 #include "fw_context.h"
+#include "../usr/iscsi_sysfs.h" /* for iscsi_sysfs_get_netdev_by_mac */
 
 char *progname = "fwparam_ibft";
 int debug;
@@ -145,6 +149,38 @@
 
 }
 
+void
+format_netmask(char *buf, size_t size, uint8_t prefix)
+{
+	int i;
+	int len = 0;
+	for (i = 0; i < 4; i++) {
+		uint8_t byte_prefix = (prefix > 8) ? 8 : prefix;
+		uint8_t mask = (1<<byte_prefix) - 1;
+		int rc;
+		rc = snprintf(&buf[len], size, "%s%d", i ? "." : "", mask);
+		size -= rc;
+		len += rc;
+		prefix -= byte_prefix;
+	}
+}
+
+void
+format_mac(char *buf, size_t size, uint8_t *mac)
+{
+	int i = 0;
+	int len = 0;
+	int rc;
+	rc = snprintf(&buf[len], size, "%02x", mac[i++]);
+	size -= rc;
+	len += rc;
+	while (i < 6) {
+		rc = snprintf(&buf[len], size, ":%02x", mac[i++]);
+		size -= rc;
+		len += rc;
+	}
+}
+
 /*
  * Dump the 16 byte ipaddr, as IPV6 or IPV4.
  */
@@ -314,8 +350,9 @@
 	struct ibft_initiator *initiator = NULL;
 	struct ibft_nic *nic0 = NULL, *nic1 = NULL;
 	struct ibft_tgt *tgt0 = NULL, *tgt1 = NULL;
-	char ipbuf[32];
+	char buf[32];
 	struct boot_context *pcontext = context;
+	int i;	
 
 	control = ibft_loc + sizeof(*ibft_hdr);
 	CHECK_HDR(control, control);
@@ -357,59 +394,58 @@
 	
 	/* TODO: how should we treat the boot failover flag?
 	 */
-	if (pcontext < &context[max_entries] && 
-		tgt0 && (tgt0->hdr.flags & INIT_FLAG_FW_SEL_BOOT)) {
-		strncpy(pcontext->initiatorname,
-				(char *)ibft_loc+initiator->initiator_name_off,
-				initiator->initiator_name_len + 1);
-		strncpy((char *)pcontext->targetname,
-			(char *)(ibft_loc+tgt0->tgt_name_off),
-			tgt0->tgt_name_len);
-		format_ipaddr(ipbuf, sizeof(ipbuf),
-			      tgt0->ip_addr);
-		strncpy((char *)pcontext->target_ipaddr, ipbuf,
-			sizeof(ipbuf));
-		pcontext->target_port = tgt0->port;
-		strncpy(pcontext->chap_name,
-			(char *)(ibft_loc + tgt0->chap_name_off),
-			tgt0->chap_name_len);
-		strncpy(pcontext->chap_password,
-			(char*)(ibft_loc + tgt0->chap_secret_off),
-			tgt0->chap_secret_len);
-		strncpy(pcontext->chap_name_in,
-			(char *)(ibft_loc + tgt0->rev_chap_name_off),
-			tgt0->rev_chap_name_len);
-		strncpy(pcontext->chap_password_in,
-			(char *)(ibft_loc + tgt0->rev_chap_secret_off),
-			tgt0->rev_chap_secret_len);
-		pcontext++;
-	} 
-	if (pcontext < &context[max_entries] && 
-		tgt1 && (tgt1->hdr.flags & INIT_FLAG_FW_SEL_BOOT)) {
-		strncpy(pcontext->initiatorname,
-				(char *)ibft_loc+initiator->initiator_name_off,
-				initiator->initiator_name_len + 1);
-		strncpy((char *)pcontext->targetname,
-			(char *)(ibft_loc+tgt1->tgt_name_off),
-			tgt1->tgt_name_len);
-		format_ipaddr(ipbuf, sizeof(ipbuf),
-			      tgt1->ip_addr);
-		strncpy((char *)pcontext->target_ipaddr,ipbuf,
-			sizeof(ipbuf));
-		pcontext->target_port = tgt1->port;
-		strncpy(pcontext->chap_name,
-			(char *)(ibft_loc + tgt1->chap_name_off),
-			tgt1->chap_name_len);
-		strncpy(pcontext->chap_password,
-			(char*)(ibft_loc + tgt1->chap_secret_off),
-			tgt1->chap_secret_len);
-		strncpy(pcontext->chap_name_in,
-			(char *)(ibft_loc + tgt1->rev_chap_name_off),
-			tgt1->rev_chap_name_len);
-		strncpy(pcontext->chap_password_in,
-			(char *)(ibft_loc + tgt1->rev_chap_secret_off),
-			tgt1->rev_chap_secret_len);
-		pcontext++;
+	for (i = 0; i < 2; i++) {
+		struct ibft_tgt *tgt = i ? tgt1 : tgt0;
+		struct ibft_nic *nic = tgt->nic_assoc ? nic1 : nic0;
+		int tgt_valid = tgt && (tgt->hdr.flags & INIT_FLAG_FW_SEL_BOOT);
+		int nic_valid = nic && (nic->hdr.flags & NIC_FLAG_FW_SEL_BOOT);
+
+		if (pcontext < &context[max_entries]) {
+			if (tgt_valid) {
+				strncpy(pcontext->initiatorname,
+						(char *)ibft_loc+initiator->initiator_name_off,
+						initiator->initiator_name_len + 1);
+				strncpy((char *)pcontext->targetname,
+						(char *)(ibft_loc+tgt->tgt_name_off),
+						tgt->tgt_name_len);
+				format_ipaddr(buf, sizeof(buf),
+							  tgt->ip_addr);
+				strncpy((char *)pcontext->target_ipaddr, buf,
+						sizeof(buf));
+				pcontext->target_port = tgt->port;
+				strncpy(pcontext->chap_name,
+						(char *)(ibft_loc + tgt->chap_name_off),
+						tgt->chap_name_len);
+				strncpy(pcontext->chap_password,
+						(char*)(ibft_loc + tgt->chap_secret_off),
+						tgt->chap_secret_len);
+				strncpy(pcontext->chap_name_in,
+						(char *)(ibft_loc + tgt->rev_chap_name_off),
+						tgt->rev_chap_name_len);
+				strncpy(pcontext->chap_password_in,
+						(char *)(ibft_loc + tgt->rev_chap_secret_off),
+						tgt->rev_chap_secret_len);
+			}
+			if (nic_valid) {
+				format_mac(buf, sizeof(buf), nic->mac);
+				strncpy(pcontext->mac, buf, sizeof(buf));
+				/* initialise iface in case next call fails */
+				pcontext->iface[0] = 0;
+				sysfs_init();
+				iscsi_sysfs_get_netdev_by_mac(pcontext->mac, 
+											  pcontext->iface, 
+											  sizeof(pcontext->iface));
+				format_ipaddr(buf, sizeof(buf), nic->ip_addr);
+				strncpy(pcontext->ipaddr, buf, sizeof(buf));
+				format_netmask(buf, sizeof(buf), nic->subnet_mask_prefix);
+				strncpy(pcontext->mask, buf, sizeof(buf));
+				format_ipaddr(buf, sizeof(buf), nic->gateway);
+				strncpy(pcontext->gateway, buf, sizeof(buf));
+				snprintf(pcontext->vlan, sizeof(pcontext->vlan),
+						 "%d", nic->vlan);
+			}
+			pcontext++;
+		}
 	}
 
 	return pcontext - context;

Reply via email to