Mike Christie wrote:

Thanks for doing this. Sorry for the late reply.


Just one comment on the patch. Could you move the code in the 'n' case

+               case 'n':
+                       /*
+                        * Bring up NICs required by targets in iBFT
+                        * using IP addresses and routing info from iBFT.
+                        */

......


to some helper function, so it is not so crowed and a little easier to read?


No problem.  Please find a new patch attached.

Regards,

Alex
-- 
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.


iscsistart option to bring up NICs using configuration in iBFT.

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 iscsistart to apply the NIC configuration.

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 this info is modified via the BIOS it is not
necessary to rebuild the initrd.

Signed-off-by<alex.zeffe...@eu.citrix.com>

diff --git a/usr/iscsistart.c b/usr/iscsistart.c
index 8482ad5..2ee2674 100644
--- a/usr/iscsistart.c
+++ b/usr/iscsistart.c
@@ -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"
@@ -73,6 +79,7 @@ static struct option const long_options[] = {
 	{"password_in", required_argument, NULL, 'W'},
 	{"debug", required_argument, NULL, 'd'},
 	{"fwparam_connect", no_argument, NULL, 'b'},
+	{"fwparam_network", no_argument, NULL, 'n'},
 	{"fwparam_print", no_argument, NULL, 'f'},
 	{"help", no_argument, NULL, 'h'},
 	{"version", no_argument, NULL, 'v'},
@@ -99,6 +106,7 @@ Open-iSCSI initiator.\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\
+  -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\
@@ -199,6 +207,140 @@ static int setup_session(void)
 	return rc;
 }
 
+static int setup_nics(void)
+{
+	struct boot_context *context;
+	char *iface_prev = NULL;
+	int sock;
+	int ret;
+
+	/* Create socket for making networking changes */
+	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+		perror("socket(AF_INET, SOCK_DGRAM, 0)");
+		exit(1);
+	}
+			
+	/* 
+	 * For each target in iBFT bring up required NIC and use routing
+	 * to force iSCSI traffic through correct NIC
+	 */
+	list_for_each_entry(context, &targets, list) {
+					
+		/* 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;
+
+		if (!strlen(context->iface)) {
+			printf("No iface in fw entry\n");
+			ret = -1;
+			continue;
+		}
+		if (!inet_aton(context->ipaddr, &ipaddr.sin_addr)) {
+			printf("Invalid or no ipaddr in fw entry\n");
+			ret = -1;
+			continue;
+		}
+
+		if (!inet_aton(context->mask, &netmask.sin_addr)) {
+			printf("Invalid or no netmask in fw entry\n");
+			ret = -1;
+			continue;
+		}
+		inet_aton("255.255.255.255", &hostmask.sin_addr);
+
+		if (!inet_aton(context->target_ipaddr, &tgt_ipaddr.sin_addr)) {
+			printf("Invalid or no target ipaddr in fw entry\n");
+			ret = -1;
+			continue;
+		}
+
+		/* Only set IP/NM if this is a new interface */
+		if (iface_prev == NULL || strcmp(context->iface, iface_prev)) {
+					
+			/* Note: test above works because there is a maximum of two targets in the iBFT */
+			iface_prev = context->iface;
+
+			/* TODO: create vlan if strlen(context->vlan) */
+
+			/* Bring up interface */
+			memset(&ifr, 0, sizeof(ifr));
+			strncpy(ifr.ifr_name, context->iface, IFNAMSIZ);
+			ifr.ifr_flags = IFF_UP | IFF_RUNNING;
+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+				perror("ioctl(SIOCSIFFLAGS)");
+				ret = -1;
+				continue;
+			}
+			/* Set IP address */
+			memset(&ifr, 0, sizeof(ifr));
+			strncpy(ifr.ifr_name, context->iface, IFNAMSIZ);
+			memcpy(&ifr.ifr_addr, &ipaddr, sizeof(struct sockaddr));
+			if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
+				perror("ioctl(SIOCSIFADDR)");
+				ret = -1;
+				continue;
+			}
+			/* Set netmask */
+			memset(&ifr, 0, sizeof(ifr));
+			strncpy(ifr.ifr_name, context->iface, IFNAMSIZ);
+			memcpy(&ifr.ifr_addr, &netmask, sizeof(struct sockaddr));
+			if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) {
+				perror("ioctl(SIOCSIFNETMASK)");
+				ret = -1;
+				continue;
+			}
+		}
+
+		/* 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->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)");
+					ret = -1;
+					continue;
+				}
+			}
+		} else {
+			/* Different subnet.  Use gateway */
+			rt.rt_flags |= RTF_GATEWAY;
+			if (!inet_aton(context->gateway, &gateway.sin_addr)) {
+				printf("Invalid or no gateway in fw entry\n");
+				ret = -1;
+				continue;
+			}
+			memcpy(&rt.rt_gateway, &gateway, sizeof(gateway));
+			if (ioctl(sock, SIOCADDRT, &rt) < 0) {
+				if (errno != EEXIST) {
+					perror("ioctl(SIOCADDRT)");
+					ret = -1;
+					continue;
+				}
+			}
+		}
+		/* This target handled */
+	}
+			
+	close(sock);
+	fw_free_targets(&targets);
+	return ret;
+}
+
+
 static void catch_signal(int signo)
 {
 	log_warning("pid %d caught signal -%d", getpid(), signo);
@@ -268,7 +410,7 @@ int main(int argc, char *argv[])
 	if (iscsi_sysfs_check_class_version())
 		exit(1);
 
-	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':
@@ -332,6 +474,14 @@ int main(int argc, char *argv[])
 				exit(1);
 			}
 			break;
+		case 'n':
+			ret = fw_get_targets(&targets);
+			if (ret || list_empty(&targets)) {
+				printf("Could not setup fw entries.\n");
+				exit(1);
+			}
+			ret = setup_nics();
+			exit(ret);
 		case 'f':
 			ret = fw_get_targets(&targets);
 			if (ret || list_empty(&targets)) {
diff --git a/utils/fwparam_ibft/fwparam_ibft_sysfs.c b/utils/fwparam_ibft/fwparam_ibft_sysfs.c
index 98e29a6..013c436 100644
--- a/utils/fwparam_ibft/fwparam_ibft_sysfs.c
+++ b/utils/fwparam_ibft/fwparam_ibft_sysfs.c
@@ -19,6 +19,7 @@
  */
 
 #define  _XOPEN_SOURCE 500
+#define _SVID_SOURCE
 #include <ftw.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -28,6 +29,7 @@
 #include <errno.h>
 #include <dirent.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 
 #include "sysfs.h"
 #include "fw_context.h"
@@ -36,6 +38,7 @@
 
 #define IBFT_MAX 255
 #define IBFT_SYSFS_ROOT "/sys/firmware/ibft/"
+#define NET_SYSFS_ROOT "/sys/class/net/"
 #define IBFT_SUBSYS "ibft"
 
 static char *target_list[IBFT_MAX];
@@ -156,6 +159,67 @@ static int get_iface_from_device(char *id, struct boot_context *context)
 	return rc;
 }
 
+static int get_iface_from_mac(char *id, struct boot_context *context)
+{
+	char mac_fname[FILENAMESZ];
+	char mac[18] = {0};
+	int rc = ENODEV;
+	int fd;
+	int retval;
+	struct dirent **namelist;
+	int n, i;
+
+	memset(mac_fname, 0, FILENAMESZ);
+	snprintf(mac_fname, FILENAMESZ, IBFT_SYSFS_ROOT"/%s/mac", id);
+
+	if (!file_exist(mac_fname))
+		return 0;
+
+	fd = open(mac_fname, O_RDONLY);
+	if (fd == -1)
+		return errno;
+
+	retval = read(fd, mac, 17);
+	if (retval == -1)
+		return errno;
+	if (retval != 17) {
+		printf("Couldn't read whole mac address from %s\n", mac_fname);
+		return EINVAL;
+	}
+	close(fd);
+
+	n = scandir(NET_SYSFS_ROOT, &namelist, NULL, alphasort);
+	if (n <= 0)
+		return -n;
+
+	for (i = 0; i < n; i++) {
+		char name[256];
+		char *dir = namelist[i]->d_name;
+		char buf[18] = {0};
+        if (!strcmp(name, ".") || !strcmp(name, ".."))
+			continue;
+		
+		snprintf(name, sizeof(name), "%s%s/address", NET_SYSFS_ROOT, dir);
+		fd = open(name, O_RDONLY);
+		if (fd == -1)
+			continue;
+		retval = read(fd, buf, 17);
+		close(fd);
+
+		if (strncasecmp(buf, mac, 17) == 0) {
+			strlcpy(context->iface, dir, sizeof(context->iface));
+			rc = 0;
+			break;
+		}
+	}
+
+	for (i = 0; i < n; i++)
+		free(namelist[i]);
+	free(namelist);
+
+	return rc;
+}
+
 /*
  * Routines to fill in the context values.
  */
@@ -170,6 +234,9 @@ static int fill_nic_context(char *id, struct boot_context *context)
 
 	rc = get_iface_from_device(id, context);
 	if (rc)
+		rc = get_iface_from_mac(id, context);
+
+	if (rc)
 		return rc;
 
 	sysfs_get_str(id, IBFT_SUBSYS, "ip-addr", context->ipaddr,

Reply via email to