|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* net helpers
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Copyright (C) 2010 Mike Christie
|
|
Packit |
eace71 |
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
eace71 |
* it under the terms of the GNU General Public License as published
|
|
Packit |
eace71 |
* by the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
eace71 |
* (at your option) any later version.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
eace71 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
eace71 |
* General Public License for more details.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <net/if.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <netinet/in.h>
|
|
Packit |
eace71 |
#include <arpa/inet.h>
|
|
Packit |
eace71 |
#include <net/route.h>
|
|
Packit |
eace71 |
#include <sys/types.h>
|
|
Packit |
eace71 |
#include <sys/socket.h>
|
|
Packit |
eace71 |
#include <sys/stat.h>
|
|
Packit |
eace71 |
#include <sys/ioctl.h>
|
|
Packit |
eace71 |
#include <sys/socket.h>
|
|
Packit |
eace71 |
#include <linux/sockios.h>
|
|
Packit |
eace71 |
#include <linux/if_vlan.h>
|
|
Packit |
eace71 |
#include <net/if_arp.h>
|
|
Packit |
eace71 |
#include <linux/if_ether.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "sysdeps.h"
|
|
Packit |
eace71 |
#include "ethtool-copy.h"
|
|
Packit |
eace71 |
#include "iscsi_net_util.h"
|
|
Packit |
eace71 |
#include "log.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_net_driver {
|
|
Packit |
eace71 |
const char *net_drv_name;
|
|
Packit |
eace71 |
const char *iscsi_transport;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static struct iscsi_net_driver net_drivers[] = {
|
|
Packit |
eace71 |
{"cxgb3", "cxgb3i" },
|
|
Packit |
eace71 |
{"cxgb4", "cxgb4i" },
|
|
Packit |
eace71 |
{"bnx2", "bnx2i" },
|
|
Packit |
eace71 |
{"bnx2x", "bnx2i"},
|
|
Packit |
eace71 |
{NULL, NULL}
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* net_get_transport_name_from_netdev - get name of transport to use for iface
|
|
Packit |
eace71 |
* @netdev: netdev iface name
|
|
Packit |
eace71 |
* @transport: buffer to hold transport name
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* transport buffer should be ISCSI_TRANSPORT_NAME_MAXLEN bytes
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int net_get_transport_name_from_netdev(char *netdev, char *transport)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct ethtool_drvinfo drvinfo;
|
|
Packit |
eace71 |
struct ifreq ifr;
|
|
Packit |
eace71 |
int err, fd, i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ifr, 0, sizeof(ifr));
|
|
Packit |
eace71 |
strcpy(ifr.ifr_name, netdev);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
Packit |
eace71 |
if (fd < 0) {
|
|
Packit |
eace71 |
log_error("Could not open socket for ioctl.");
|
|
Packit |
eace71 |
return errno;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
drvinfo.cmd = ETHTOOL_GDRVINFO;
|
|
Packit |
eace71 |
ifr.ifr_data = (caddr_t)&drvinfo;
|
|
Packit |
eace71 |
err = ioctl(fd, SIOCETHTOOL, &ifr);
|
|
Packit |
eace71 |
if (err < 0) {
|
|
Packit |
eace71 |
log_error("Could not get driver %s.", netdev);
|
|
Packit |
eace71 |
err = errno;
|
|
Packit |
eace71 |
goto close_sock;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iSCSI hardware offload for bnx2{,x} is only supported if the
|
|
Packit |
eace71 |
* iscsiuio executable is available.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!strcmp(drvinfo.driver, "bnx2x") ||
|
|
Packit |
eace71 |
!strcmp(drvinfo.driver, "bnx2")) {
|
|
Packit |
eace71 |
struct stat buf;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (stat(ISCSIUIO_PATH, &buf)) {
|
|
Packit |
eace71 |
log_debug(1, "ISCSI offload not supported "
|
|
Packit |
eace71 |
"(%s not found).", ISCSIUIO_PATH);
|
|
Packit |
eace71 |
err = ENODEV;
|
|
Packit |
eace71 |
goto close_sock;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; net_drivers[i].net_drv_name != NULL; i++) {
|
|
Packit |
eace71 |
struct iscsi_net_driver *net_driver = &net_drivers[i];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!strcmp(net_driver->net_drv_name, drvinfo.driver)) {
|
|
Packit |
eace71 |
strcpy(transport, net_driver->iscsi_transport);
|
|
Packit |
eace71 |
err = 0;
|
|
Packit |
eace71 |
goto close_sock;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
err = ENODEV;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
close_sock:
|
|
Packit |
eace71 |
close(fd);
|
|
Packit |
eace71 |
return err;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* net_get_netdev_from_hwaddress - given a hwaddress return the ethX
|
|
Packit |
eace71 |
* @hwaddress: hw address no larger than ISCSI_HWADDRESS_BUF_SIZE
|
|
Packit |
eace71 |
* @netdev: buffer of IFNAMSIZ size that will hold the ethX
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Does not support interfaces like a bond or alias because
|
|
Packit |
eace71 |
* multiple interfaces will have the same hwaddress.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int net_get_netdev_from_hwaddress(char *hwaddress, char *netdev)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct if_nameindex *ifni;
|
|
Packit |
eace71 |
struct ifreq if_hwaddr;
|
|
Packit |
eace71 |
int found = 0, sockfd, i = 0;
|
|
Packit |
eace71 |
unsigned char *hwaddr;
|
|
Packit |
eace71 |
char tmp_hwaddress[ISCSI_HWADDRESS_BUF_SIZE];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ifni = if_nameindex();
|
|
Packit |
eace71 |
if (ifni == NULL) {
|
|
Packit |
eace71 |
log_error("Could not match hwaddress %s to netdev. "
|
|
Packit |
eace71 |
"getifaddrs failed %d", hwaddress, errno);
|
|
Packit |
eace71 |
return errno;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Open a basic socket. */
|
|
Packit |
eace71 |
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
Packit |
eace71 |
if (sockfd < 0) {
|
|
Packit |
eace71 |
log_error("Could not open socket for ioctl.");
|
|
Packit |
eace71 |
goto free_ifni;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) {
|
|
Packit |
eace71 |
struct if_nameindex *n = &ifni[i];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strlcpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ);
|
|
Packit |
eace71 |
if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
|
|
Packit |
eace71 |
log_error("Could not match %s to netdevice.",
|
|
Packit |
eace71 |
hwaddress);
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* check for ARPHRD_ETHER (ethernet) */
|
|
Packit |
eace71 |
if (if_hwaddr.ifr_hwaddr.sa_family != 1)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(tmp_hwaddress, 0, ISCSI_HWADDRESS_BUF_SIZE);
|
|
Packit |
eace71 |
/* TODO should look and covert so we do not need tmp buf */
|
|
Packit |
eace71 |
sprintf(tmp_hwaddress, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
|
|
Packit |
eace71 |
hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3],
|
|
Packit |
eace71 |
hwaddr[4], hwaddr[5]);
|
|
Packit |
eace71 |
log_debug(4, "Found hardware address %s", tmp_hwaddress);
|
|
Packit |
eace71 |
if (!strcasecmp(tmp_hwaddress, hwaddress)) {
|
|
Packit |
eace71 |
log_debug(4, "Matches %s to %s", hwaddress,
|
|
Packit |
eace71 |
n->if_name);
|
|
Packit |
eace71 |
memset(netdev, 0, IFNAMSIZ);
|
|
Packit |
eace71 |
strlcpy(netdev, n->if_name, IFNAMSIZ);
|
|
Packit |
eace71 |
found = 1;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
close(sockfd);
|
|
Packit |
eace71 |
free_ifni:
|
|
Packit |
eace71 |
if_freenameindex(ifni);
|
|
Packit |
eace71 |
if (!found)
|
|
Packit |
eace71 |
return ENODEV;
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static char *find_vlan_dev(char *netdev, int vlan_id) {
|
|
Packit |
eace71 |
struct ifreq if_hwaddr;
|
|
Packit |
eace71 |
struct ifreq vlan_hwaddr;
|
|
Packit |
eace71 |
struct vlan_ioctl_args vlanrq = { .cmd = GET_VLAN_VID_CMD, };
|
|
Packit |
eace71 |
struct if_nameindex *ifni;
|
|
Packit |
eace71 |
char *vlan = NULL;
|
|
Packit |
eace71 |
int sockfd, i, rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strlcpy(if_hwaddr.ifr_name, netdev, IFNAMSIZ);
|
|
Packit |
eace71 |
ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (if_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
|
|
Packit |
eace71 |
close(sockfd);
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ifni = if_nameindex();
|
|
Packit |
eace71 |
for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) {
|
|
Packit |
eace71 |
strlcpy(vlan_hwaddr.ifr_name, ifni[i].if_name, IFNAMSIZ);
|
|
Packit |
eace71 |
ioctl(sockfd, SIOCGIFHWADDR, &vlan_hwaddr);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (vlan_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!memcmp(if_hwaddr.ifr_hwaddr.sa_data, vlan_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN)) {
|
|
Packit |
eace71 |
strlcpy(vlanrq.device1, ifni[i].if_name, IFNAMSIZ);
|
|
Packit |
eace71 |
rc = ioctl(sockfd, SIOCGIFVLAN, &vlanrq);
|
|
Packit |
eace71 |
if ((rc == 0) && (vlanrq.u.VID == vlan_id)) {
|
|
Packit |
eace71 |
vlan = strdup(vlanrq.device1);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if_freenameindex(ifni);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
close(sockfd);
|
|
Packit |
eace71 |
return vlan;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* net_setup_netdev - bring up NIC
|
|
Packit |
eace71 |
* @netdev: network device name
|
|
Packit |
eace71 |
* @local: ip address for netdev
|
|
Packit |
eace71 |
* @mask: net mask
|
|
Packit |
eace71 |
* @gateway: gateway
|
|
Packit |
eace71 |
* @remote_ip: target portal ip
|
|
Packit |
eace71 |
* @needs_bringup: bool indicating if the netdev needs to be started
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Bring up required NIC and use routing
|
|
Packit |
eace71 |
* to force iSCSI traffic through correct NIC.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
|
|
Packit |
eace71 |
char *vlan, char *remote_ip, int needs_bringup)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct sockaddr_in sk_ipaddr = { .sin_family = AF_INET };
|
|
Packit |
eace71 |
struct sockaddr_in sk_netmask = { .sin_family = AF_INET };
|
|
Packit |
eace71 |
struct sockaddr_in sk_hostmask = { .sin_family = AF_INET };
|
|
Packit |
eace71 |
struct sockaddr_in sk_gateway = { .sin_family = AF_INET };
|
|
Packit |
eace71 |
struct sockaddr_in sk_tgt_ipaddr = { .sin_family = AF_INET };
|
|
Packit |
eace71 |
struct rtentry rt;
|
|
Packit |
eace71 |
struct ifreq ifr;
|
|
Packit |
eace71 |
char *physdev = NULL;
|
|
Packit |
eace71 |
int sock;
|
|
Packit |
eace71 |
int ret;
|
|
Packit |
eace71 |
int vlan_id;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!strlen(netdev)) {
|
|
Packit |
eace71 |
log_error("No netdev name in fw entry.");
|
|
Packit |
eace71 |
return EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
vlan_id = atoi(vlan);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (vlan_id != 0) {
|
|
Packit |
eace71 |
physdev = netdev;
|
|
Packit |
eace71 |
netdev = find_vlan_dev(physdev, vlan_id);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (vlan_id && !netdev) {
|
|
Packit |
eace71 |
/* TODO: create vlan if not found */
|
|
Packit |
eace71 |
log_error("No matching vlan found for fw entry.");
|
|
Packit |
eace71 |
return EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Create socket for making networking changes */
|
|
Packit |
eace71 |
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
|
Packit |
eace71 |
log_error("Could not open socket to manage network "
|
|
Packit |
eace71 |
"(err %d - %s)", errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Bring up NIC with correct address - unless it
|
|
Packit |
eace71 |
* has already been handled (2 targets in IBFT may share one NIC)
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!inet_aton(local_ip, &sk_ipaddr.sin_addr)) {
|
|
Packit |
eace71 |
log_error("Invalid or missing ipaddr in fw entry");
|
|
Packit |
eace71 |
ret = EINVAL;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!inet_aton(mask, &sk_netmask.sin_addr)) {
|
|
Packit |
eace71 |
log_error("Invalid or missing netmask in fw entry");
|
|
Packit |
eace71 |
ret = EINVAL;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
inet_aton("255.255.255.255", &sk_hostmask.sin_addr);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!inet_aton(remote_ip, &sk_tgt_ipaddr.sin_addr)) {
|
|
Packit |
eace71 |
log_error("Invalid or missing target ipaddr in fw entry");
|
|
Packit |
eace71 |
ret = EINVAL;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Only set IP/NM if this is a new interface */
|
|
Packit |
eace71 |
if (needs_bringup) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (physdev) {
|
|
Packit |
eace71 |
/* Bring up interface */
|
|
Packit |
eace71 |
memset(&ifr, 0, sizeof(ifr));
|
|
Packit |
eace71 |
strlcpy(ifr.ifr_name, physdev, IFNAMSIZ);
|
|
Packit |
eace71 |
ifr.ifr_flags = IFF_UP | IFF_RUNNING;
|
|
Packit |
eace71 |
if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
|
|
Packit |
eace71 |
log_error("Could not bring up netdev %s (err %d - %s)",
|
|
Packit |
eace71 |
physdev, errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Bring up interface */
|
|
Packit |
eace71 |
memset(&ifr, 0, sizeof(ifr));
|
|
Packit |
eace71 |
strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
|
|
Packit |
eace71 |
ifr.ifr_flags = IFF_UP | IFF_RUNNING;
|
|
Packit |
eace71 |
if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
|
|
Packit |
eace71 |
log_error("Could not bring up netdev %s (err %d - %s)",
|
|
Packit |
eace71 |
netdev, errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
/* Set IP address */
|
|
Packit |
eace71 |
memset(&ifr, 0, sizeof(ifr));
|
|
Packit |
eace71 |
strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
|
|
Packit |
eace71 |
memcpy(&ifr.ifr_addr, &sk_ipaddr, sizeof(struct sockaddr));
|
|
Packit |
eace71 |
if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
|
|
Packit |
eace71 |
log_error("Could not set ip for %s (err %d - %s)",
|
|
Packit |
eace71 |
netdev, errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Set netmask */
|
|
Packit |
eace71 |
memset(&ifr, 0, sizeof(ifr));
|
|
Packit |
eace71 |
strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
|
|
Packit |
eace71 |
memcpy(&ifr.ifr_addr, &sk_netmask, sizeof(struct sockaddr));
|
|
Packit |
eace71 |
if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) {
|
|
Packit |
eace71 |
log_error("Could not set ip for %s (err %d - %s)",
|
|
Packit |
eace71 |
netdev, errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Set static route to target via this interface */
|
|
Packit |
eace71 |
memset((char *) &rt, 0, sizeof(rt));
|
|
Packit |
eace71 |
memcpy(&rt.rt_dst, &sk_tgt_ipaddr, sizeof(sk_tgt_ipaddr));
|
|
Packit |
eace71 |
memcpy(&rt.rt_genmask, &sk_hostmask, sizeof(sk_hostmask));
|
|
Packit |
eace71 |
rt.rt_flags = RTF_UP | RTF_HOST;
|
|
Packit |
eace71 |
rt.rt_dev = netdev;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((sk_tgt_ipaddr.sin_addr.s_addr & sk_netmask.sin_addr.s_addr) ==
|
|
Packit |
eace71 |
(sk_ipaddr.sin_addr.s_addr & sk_netmask.sin_addr.s_addr)) {
|
|
Packit |
eace71 |
/* Same subnet */
|
|
Packit |
eace71 |
if (ioctl(sock, SIOCADDRT, &rt) < 0) {
|
|
Packit |
eace71 |
if (errno != EEXIST) {
|
|
Packit |
eace71 |
log_error("Could not set ip for %s "
|
|
Packit |
eace71 |
"(err %d - %s)", netdev,
|
|
Packit |
eace71 |
errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
/* Different subnet. Use gateway */
|
|
Packit |
eace71 |
rt.rt_flags |= RTF_GATEWAY;
|
|
Packit |
eace71 |
if (!inet_aton(gateway, &sk_gateway.sin_addr)) {
|
|
Packit |
eace71 |
log_error("Invalid or missing gateway for %s "
|
|
Packit |
eace71 |
"(err %d - %s)",
|
|
Packit |
eace71 |
netdev, errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
memcpy(&rt.rt_gateway, &sk_gateway, sizeof(sk_gateway));
|
|
Packit |
eace71 |
if (ioctl(sock, SIOCADDRT, &rt) < 0) {
|
|
Packit |
eace71 |
if (errno != EEXIST) {
|
|
Packit |
eace71 |
log_error("Could not set gateway for %s "
|
|
Packit |
eace71 |
"(err %d - %s)", netdev,
|
|
Packit |
eace71 |
errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
ret = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
if (sock >= 0)
|
|
Packit |
eace71 |
close(sock);
|
|
Packit |
eace71 |
if (vlan_id)
|
|
Packit |
eace71 |
free(netdev);
|
|
Packit |
eace71 |
return ret;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* net_ifup_netdev - bring up network interface
|
|
Packit |
eace71 |
* @netdev: netdevice to bring up.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int net_ifup_netdev(char *netdev)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct ifreq ifr;
|
|
Packit |
eace71 |
int sock;
|
|
Packit |
eace71 |
int ret = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!strlen(netdev)) {
|
|
Packit |
eace71 |
log_error("No netdev name in fw entry.");
|
|
Packit |
eace71 |
return EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Create socket for making networking changes */
|
|
Packit |
eace71 |
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
|
Packit |
eace71 |
log_error("Could not open socket to manage network "
|
|
Packit |
eace71 |
"(err %d - %s)", errno, strerror(errno));
|
|
Packit |
eace71 |
return errno;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ifr, 0, sizeof(ifr));
|
|
Packit |
eace71 |
strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
|
|
Packit |
eace71 |
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
|
Packit |
eace71 |
log_error("Could not bring up netdev %s (err %d - %s)",
|
|
Packit |
eace71 |
netdev, errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ifr.ifr_flags & IFF_UP) {
|
|
Packit |
eace71 |
log_debug(3, "%s up", netdev);
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(3, "bringing %s up", netdev);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Bring up interface */
|
|
Packit |
eace71 |
memset(&ifr, 0, sizeof(ifr));
|
|
Packit |
eace71 |
strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
|
|
Packit |
eace71 |
ifr.ifr_flags = IFF_UP;
|
|
Packit |
eace71 |
if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
|
|
Packit |
eace71 |
log_error("Could not bring up netdev %s (err %d - %s)",
|
|
Packit |
eace71 |
netdev, errno, strerror(errno));
|
|
Packit |
eace71 |
ret = errno;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
close(sock);
|
|
Packit |
eace71 |
return ret;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
|