Hi all,

I've now rebased this patch so that it applies to the top of the open-iscsi git 
tree, as requested.

Please let me know if there is anything you would like me to alter before it is 
applied.

Regards,

Alex

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

--

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 --git a/usr/iscsistart.c b/usr/iscsistart.c
index 8482ad5..fe89e95 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\
@@ -248,6 +256,8 @@ int main(int argc, char *argv[])
 	struct sigaction sa_old;
 	struct sigaction sa_new;
 	pid_t pid;
+	char *iface_prev = NULL;
+	int sock;
 
 	idbm_node_setup_defaults(&config_rec);
 	config_rec.name[0] = '\0';
@@ -268,7 +278,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 +342,145 @@ int main(int argc, char *argv[])
 				exit(1);
 			}
 			break;
+		case 'n':
+			/* 
+			 * Bring up NICs required by targets in iBFT 
+			 * using IP addresses and routing info from iBFT.
+			 */ 
+			memset(&boot_context, 0, sizeof(boot_context));
+			ret = fw_get_entry(&boot_context);
+			if (ret) {
+				printf("Could not get boot entry.\n");
+				exit(1);
+			}
+
+			ret = fw_get_targets(&targets);
+			if (ret || list_empty(&targets)) {
+				printf("Could not setup fw entries.\n");
+				exit(1);
+			}
+
+			/* Create socket for making networking changes */
+			if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+				perror("socket(AF_INET, SOCK_DGRAM, 0)");
+				exit(1);
+			}
+				
+			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);
+			exit(ret);
+			break;
 		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