Network boot: ignore interfaces without a carrier
Also skip interfaces which can't be brought up for some reason (i.e. missing firmware). Thus the system can boot automatically when exactly one interface has a carrier. Closes: #40616
This commit is contained in:
parent
dd58d27275
commit
110ac7dff1
63
probing.c
63
probing.c
@ -269,6 +269,38 @@ void get_medias(enum media_type media, char *** names, char *** models)
|
||||
#endif /* DISABLE_MEDIAS */
|
||||
|
||||
#ifndef DISABLE_NETWORK
|
||||
|
||||
static int net_device_has_carrier(const char *device) {
|
||||
int fd = -1;
|
||||
char *p = NULL;
|
||||
int ret = 0;
|
||||
char state = '\0';
|
||||
if (asprintf(&p, "/sys/class/net/%s/carrier", device) == -1) {
|
||||
log_message("net_device_has_carrier: OOM");
|
||||
return 0;
|
||||
}
|
||||
fd = open(p, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
log_perror("net_device_has_carrier: failed to open sysfs knob");
|
||||
goto out;
|
||||
}
|
||||
if (read(fd, &state, 1) != 1) {
|
||||
log_perror("net_device_has_carrier: failed to read sysfs knob");
|
||||
goto out;
|
||||
}
|
||||
ret = !!(state == '1');
|
||||
out:
|
||||
if (p) {
|
||||
free(p);
|
||||
p = NULL;
|
||||
}
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int net_device_available(char * device)
|
||||
{
|
||||
struct ifreq req;
|
||||
@ -285,8 +317,37 @@ static int net_device_available(char * device)
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
if (!(req.ifr_flags & IFF_UP)) {
|
||||
req.ifr_flags |= IFF_UP;
|
||||
if (ioctl(s, SIOCSIFFLAGS, &req)) {
|
||||
log_perror("ifup");
|
||||
/* skip the interface we can't bring up */
|
||||
}
|
||||
/* XXX: we want to report only interfaces with carrier as available.
|
||||
* However calling net_device_has_carrier right after ifup is useless:
|
||||
* the kernel needs some time to figure out if the carrier is present.
|
||||
* Therefore report that this interface is *not* available.
|
||||
* intf_select_and_up will wait a second and retry if necessary
|
||||
* (i.e. no interfaces with carrier have been found), and on the next
|
||||
* attempt `device` will be already up, and we'll check if `device`
|
||||
* has the carrier.
|
||||
*
|
||||
* Sounds a bit tricky? A simple solution is to put sleep(1) after
|
||||
* ifup, but there might be quite a number of interfaces (I've got
|
||||
* boards with 4 and 6 Ethernets), and sleeping for O(N) seconds
|
||||
* for no good reason might be annoying.
|
||||
* Oh, alternatively we could setup a full-fledged event loop and
|
||||
* wait for netlink notifications, but that's too much code and
|
||||
* *complexity*.
|
||||
*/
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
/* `device` was already up (perhaps we've brought it up during
|
||||
* previous calls), check if it has the carrier
|
||||
*/
|
||||
close(s);
|
||||
return 1;
|
||||
return net_device_has_carrier(device);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user