4 * Copyright (C) 2010 Mike Christie
5 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <net/route.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <sys/socket.h>
29 #include <linux/sockios.h>
32 #include "ethtool-copy.h"
33 #include "iscsi_net_util.h"
36 struct iscsi_net_driver
{
37 const char *net_drv_name
;
38 const char *iscsi_transport
;
41 static struct iscsi_net_driver net_drivers
[] = {
42 #ifdef OFFLOAD_BOOT_SUPPORTED
52 * net_get_transport_name_from_netdev - get name of transport to use for iface
53 * @netdev: netdev iface name
54 * @transport: buffer to hold transport name
56 * transport buffer should be ISCSI_TRANSPORT_NAME_MAXLEN bytes
58 int net_get_transport_name_from_netdev(char *netdev
, char *transport
)
60 struct ethtool_drvinfo drvinfo
;
64 memset(&ifr
, 0, sizeof(ifr
));
65 strcpy(ifr
.ifr_name
, netdev
);
67 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
69 log_error("Could not open socket for ioctl.");
73 drvinfo
.cmd
= ETHTOOL_GDRVINFO
;
74 ifr
.ifr_data
= (caddr_t
)&drvinfo
;
75 err
= ioctl(fd
, SIOCETHTOOL
, &ifr
);
77 log_error("Could not get driver.");
82 for (i
= 0; net_drivers
[i
].net_drv_name
!= NULL
; i
++) {
83 struct iscsi_net_driver
*net_driver
= &net_drivers
[i
];
85 if (!strcmp(net_driver
->net_drv_name
, drvinfo
.driver
)) {
86 strcpy(transport
, net_driver
->iscsi_transport
);
99 * net_get_netdev_from_hwaddress - given a hwaddress return the ethX
100 * @hwaddress: hw address no larger than ISCSI_HWADDRESS_BUF_SIZE
101 * @netdev: buffer of IFNAMSIZ size that will hold the ethX
103 * Does not support interfaces like a bond or alias because
104 * multiple interfaces will have the same hwaddress.
106 int net_get_netdev_from_hwaddress(char *hwaddress
, char *netdev
)
108 struct if_nameindex
*ifni
;
109 struct ifreq if_hwaddr
;
110 int found
= 0, sockfd
, i
= 0;
111 unsigned char *hwaddr
;
112 char tmp_hwaddress
[ISCSI_HWADDRESS_BUF_SIZE
];
114 ifni
= if_nameindex();
116 log_error("Could not match hwaddress %s to netdev. "
117 "getifaddrs failed %d", hwaddress
, errno
);
121 /* Open a basic socket. */
122 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
124 log_error("Could not open socket for ioctl.");
128 for (i
= 0; ifni
[i
].if_index
&& ifni
[i
].if_name
; i
++) {
129 struct if_nameindex
*n
= &ifni
[i
];
131 strlcpy(if_hwaddr
.ifr_name
, n
->if_name
, IFNAMSIZ
);
132 if (ioctl(sockfd
, SIOCGIFHWADDR
, &if_hwaddr
) < 0) {
133 log_error("Could not match %s to netdevice.",
138 /* check for ARPHRD_ETHER (ethernet) */
139 if (if_hwaddr
.ifr_hwaddr
.sa_family
!= 1)
141 hwaddr
= (unsigned char *)if_hwaddr
.ifr_hwaddr
.sa_data
;
143 memset(tmp_hwaddress
, 0, ISCSI_HWADDRESS_BUF_SIZE
);
144 /* TODO should look and covert so we do not need tmp buf */
145 sprintf(tmp_hwaddress
, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
146 hwaddr
[0], hwaddr
[1], hwaddr
[2], hwaddr
[3],
147 hwaddr
[4], hwaddr
[5]);
148 log_debug(4, "Found hardware address %s", tmp_hwaddress
);
149 if (!strcasecmp(tmp_hwaddress
, hwaddress
)) {
150 log_debug(4, "Matches %s to %s", hwaddress
,
152 memset(netdev
, 0, IFNAMSIZ
);
153 strlcpy(netdev
, n
->if_name
, IFNAMSIZ
);
161 if_freenameindex(ifni
);
168 * net_setup_netdev - bring up NIC
169 * @netdev: network device name
170 * @local: ip address for netdev
173 * @remote_ip: target portal ip
174 * @needs_bringup: bool indicating if the netdev needs to be started
176 * Bring up required NIC and use routing
177 * to force iSCSI traffic through correct NIC.
179 int net_setup_netdev(char *netdev
, char *local_ip
, char *mask
, char *gateway
,
180 char *remote_ip
, int needs_bringup
)
182 struct sockaddr_in sk_ipaddr
= { .sin_family
= AF_INET
};
183 struct sockaddr_in sk_netmask
= { .sin_family
= AF_INET
};
184 struct sockaddr_in sk_hostmask
= { .sin_family
= AF_INET
};
185 struct sockaddr_in sk_gateway
= { .sin_family
= AF_INET
};
186 struct sockaddr_in sk_tgt_ipaddr
= { .sin_family
= AF_INET
};
192 if (!strlen(netdev
)) {
193 log_error("No netdev name in fw entry.\n");
197 /* Create socket for making networking changes */
198 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
199 log_error("Could not open socket to manage network "
200 "(err %d - %s)", errno
, strerror(errno
));
204 /* Bring up NIC with correct address - unless it
205 * has already been handled (2 targets in IBFT may share one NIC)
207 if (!inet_aton(local_ip
, &sk_ipaddr
.sin_addr
)) {
208 log_error("Invalid or missing ipaddr in fw entry\n");
213 if (!inet_aton(mask
, &sk_netmask
.sin_addr
)) {
214 log_error("Invalid or missing netmask in fw entry\n");
219 inet_aton("255.255.255.255", &sk_hostmask
.sin_addr
);
221 if (!inet_aton(remote_ip
, &sk_tgt_ipaddr
.sin_addr
)) {
222 log_error("Invalid or missing target ipaddr in fw entry\n");
227 /* Only set IP/NM if this is a new interface */
229 /* TODO: create vlan if strlen(vlan) */
231 /* Bring up interface */
232 memset(&ifr
, 0, sizeof(ifr
));
233 strncpy(ifr
.ifr_name
, netdev
, IFNAMSIZ
);
234 ifr
.ifr_flags
= IFF_UP
| IFF_RUNNING
;
235 if (ioctl(sock
, SIOCSIFFLAGS
, &ifr
) < 0) {
236 log_error("Could not bring up netdev %s (err %d - %s)",
237 netdev
, errno
, strerror(errno
));
242 memset(&ifr
, 0, sizeof(ifr
));
243 strncpy(ifr
.ifr_name
, netdev
, IFNAMSIZ
);
244 memcpy(&ifr
.ifr_addr
, &sk_ipaddr
, sizeof(struct sockaddr
));
245 if (ioctl(sock
, SIOCSIFADDR
, &ifr
) < 0) {
246 log_error("Could not set ip for %s (err %d - %s)",
247 netdev
, errno
, strerror(errno
));
253 memset(&ifr
, 0, sizeof(ifr
));
254 strncpy(ifr
.ifr_name
, netdev
, IFNAMSIZ
);
255 memcpy(&ifr
.ifr_addr
, &sk_netmask
, sizeof(struct sockaddr
));
256 if (ioctl(sock
, SIOCSIFNETMASK
, &ifr
) < 0) {
257 log_error("Could not set ip for %s (err %d - %s)",
258 netdev
, errno
, strerror(errno
));
264 /* Set static route to target via this interface */
265 memset((char *) &rt
, 0, sizeof(rt
));
266 memcpy(&rt
.rt_dst
, &sk_tgt_ipaddr
, sizeof(sk_tgt_ipaddr
));
267 memcpy(&rt
.rt_genmask
, &sk_hostmask
, sizeof(sk_hostmask
));
268 rt
.rt_flags
= RTF_UP
| RTF_HOST
;
271 if ((sk_tgt_ipaddr
.sin_addr
.s_addr
& sk_netmask
.sin_addr
.s_addr
) ==
272 (sk_ipaddr
.sin_addr
.s_addr
& sk_netmask
.sin_addr
.s_addr
)) {
274 if (ioctl(sock
, SIOCADDRT
, &rt
) < 0) {
275 if (errno
!= EEXIST
) {
276 log_error("Could not set ip for %s "
277 "(err %d - %s)", netdev
,
278 errno
, strerror(errno
));
284 /* Different subnet. Use gateway */
285 rt
.rt_flags
|= RTF_GATEWAY
;
286 if (!inet_aton(gateway
, &sk_gateway
.sin_addr
)) {
287 log_error("Invalid or missing gateway for %s "
289 netdev
, errno
, strerror(errno
));
293 memcpy(&rt
.rt_gateway
, &sk_gateway
, sizeof(sk_gateway
));
294 if (ioctl(sock
, SIOCADDRT
, &rt
) < 0) {
295 if (errno
!= EEXIST
) {
296 log_error("Could not set gateway for %s "
297 "(err %d - %s)", netdev
,
298 errno
, strerror(errno
));