From bea3e68d7a242ff50714332598fabaf4975712a2 Mon Sep 17 00:00:00 2001 From: Chris Leech 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 #include #include +#include #include #include #include @@ -27,6 +28,9 @@ #include #include #include +#include +#include +#include #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