Blob Blame History Raw
From bea3e68d7a242ff50714332598fabaf4975712a2 Mon Sep 17 00:00:00 2001
From: Chris Leech <cleech@redhat.com>
Date: Wed, 17 Jun 2015 15:07:53 -0700
Subject: [PATCH v2 6/9] iscsistart: support booting over a VLAN

Adds code to check for VLAN devices if the boot configuration specifies
a VLAN ID.

Does not create VLANs, they need to already be in place.
---
 include/iscsi_net_util.h      |  3 +-
 usr/iscsi_net_util.c          | 78 +++++++++++++++++++++++++++++++++++++++++--
 utils/fwparam_ibft/fw_entry.c |  3 +-
 3 files changed, 78 insertions(+), 6 deletions(-)

diff --git a/include/iscsi_net_util.h b/include/iscsi_net_util.h
index 31b80ad..cbf3637 100644
--- a/include/iscsi_net_util.h
+++ b/include/iscsi_net_util.h
@@ -6,7 +6,8 @@
 extern int net_get_transport_name_from_netdev(char *netdev, char *transport);
 extern int net_get_netdev_from_hwaddress(char *hwaddress, char *netdev);
 extern int net_setup_netdev(char *netdev, char *local_ip, char *mask,
-			    char *gateway, char *remote_ip, int needs_bringup);
+			    char *gateway, char *vlan, char *remote_ip,
+			    int needs_bringup);
 extern int net_ifup_netdev(char *netdev);
 
 #endif
diff --git a/usr/iscsi_net_util.c b/usr/iscsi_net_util.c
index 848b4c6..06df9b3 100644
--- a/usr/iscsi_net_util.c
+++ b/usr/iscsi_net_util.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <net/if.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <net/route.h>
@@ -27,6 +28,9 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
 
 #include "sysdeps.h"
 #include "ethtool-copy.h"
@@ -162,6 +166,45 @@ free_ifni:
 	return 0;
 }
 
+static char *find_vlan_dev(char *netdev, int vlan_id) {
+	struct ifreq if_hwaddr;
+	struct ifreq vlan_hwaddr;
+	struct vlan_ioctl_args vlanrq = { .cmd = GET_VLAN_VID_CMD, };
+	struct if_nameindex *ifni;
+	char *vlan = NULL;
+	int sockfd, i, rc;
+
+	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	strncpy(if_hwaddr.ifr_name, netdev, IFNAMSIZ);
+	ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr);
+
+	if (if_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
+		return NULL;
+
+	ifni = if_nameindex();
+	for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) {
+		strncpy(vlan_hwaddr.ifr_name, ifni[i].if_name, IFNAMSIZ);
+		ioctl(sockfd, SIOCGIFHWADDR, &vlan_hwaddr);
+
+		if (vlan_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
+			continue;
+
+		if (!memcmp(if_hwaddr.ifr_hwaddr.sa_data, vlan_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN)) {
+			strncpy(vlanrq.device1, ifni[i].if_name, IFNAMSIZ);
+			rc = ioctl(sockfd, SIOCGIFVLAN, &vlanrq);
+			if ((rc == 0) && (vlanrq.u.VID == vlan_id)) {
+				vlan = strdup(vlanrq.device1);
+				break;
+			}
+		}
+	}
+	if_freenameindex(ifni);
+
+	close(sockfd);
+	return vlan;
+}
+
 /**
  * net_setup_netdev - bring up NIC
  * @netdev: network device name
@@ -175,7 +218,7 @@ free_ifni:
  * to force iSCSI traffic through correct NIC.
  */
 int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
-		     char *remote_ip, int needs_bringup)
+		     char *vlan, char *remote_ip, int needs_bringup)
 {
 	struct sockaddr_in sk_ipaddr = { .sin_family = AF_INET };
 	struct sockaddr_in sk_netmask = { .sin_family = AF_INET };
@@ -184,14 +227,29 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
 	struct sockaddr_in sk_tgt_ipaddr = { .sin_family = AF_INET };
 	struct rtentry rt;
 	struct ifreq ifr;
+	char *physdev = NULL;
 	int sock;
 	int ret;
+	int vlan_id;
 
 	if (!strlen(netdev)) {
 		log_error("No netdev name in fw entry.");
 		return EINVAL;
 	}		
 
+	vlan_id = atoi(vlan);
+
+	if (vlan_id != 0) {
+		physdev = netdev;
+		netdev = find_vlan_dev(physdev, vlan_id);
+	}
+
+	if (vlan_id && !netdev) {
+		/* TODO: create vlan if not found */
+		log_error("No matching vlan found for fw entry.");
+		return EINVAL;
+	}
+
 	/* Create socket for making networking changes */
 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
 		log_error("Could not open socket to manage network "
@@ -224,7 +282,19 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
 
 	/* Only set IP/NM if this is a new interface */
 	if (needs_bringup) {
-		/* TODO: create vlan if strlen(vlan) */
+
+		if (physdev) {
+			/* Bring up interface */
+			memset(&ifr, 0, sizeof(ifr));
+			strlcpy(ifr.ifr_name, physdev, IFNAMSIZ);
+			ifr.ifr_flags = IFF_UP | IFF_RUNNING;
+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+				log_error("Could not bring up netdev %s (err %d - %s)",
+					  physdev, errno, strerror(errno));
+				ret = errno;
+				goto done;
+			}
+		}
 
 		/* Bring up interface */
 		memset(&ifr, 0, sizeof(ifr));
@@ -246,7 +316,7 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
 			ret = errno;
 			goto done;
 		}
-	
+
 		/* Set netmask */
 		memset(&ifr, 0, sizeof(ifr));
 		strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
@@ -303,6 +373,8 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
 
 done:
 	close(sock);
+	if (vlan_id)
+		free(netdev);
 	return ret;
 }
 
diff --git a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c
index f94a035..0a1b46b 100644
--- a/utils/fwparam_ibft/fw_entry.c
+++ b/utils/fwparam_ibft/fw_entry.c
@@ -41,8 +41,6 @@
 /**
  * fw_setup_nics - setup nics (ethXs) based on ibft net info
  *
- * Currently does not support vlans.
- *
  * If this is a offload card, this function does nothing. The
  * net info is used by the iscsi iface settings for the iscsi
  * function.
@@ -82,6 +80,7 @@ int fw_setup_nics(void)
 
 		err = net_setup_netdev(context->iface, context->ipaddr,
 				       context->mask, context->gateway,
+				       context->vlan,
 				       context->target_ipaddr, needs_bringup);
 		if (err)
 			ret = err;
-- 
2.5.5