diff --git a/etc/systemd/system/network.service b/etc/systemd/system/network.service index 6eba6542..e4a81677 100644 --- a/etc/systemd/system/network.service +++ b/etc/systemd/system/network.service @@ -8,6 +8,10 @@ Wants=network.target EnvironmentFile=/etc/local/mxhost.conf Type=oneshot RemainAfterExit=yes +# The NIC driver may still be probing when we get here (short userspace +# startup after kexec outruns e.g. the ~1 s ixgbe probe, issue #556), so +# wait for the device before renaming and configuring it. +ExecStartPre=/usr/sbin/mxnetctl wait ${MX_NETDEV} ExecStart=/usr/sbin/mxnetctl start ExecStart=/sbin/ip addr add ${MX_IPADDR}/20 broadcast 141.14.31.255 dev ${MX_NETDEV} ExecStart=/sbin/ip link set up dev ${MX_NETDEV} diff --git a/mxnetctl/mxnetctl b/mxnetctl/mxnetctl index 3f41d553..981bc189 100755 --- a/mxnetctl/mxnetctl +++ b/mxnetctl/mxnetctl @@ -4,10 +4,11 @@ use warnings; use Getopt::Long; -our ($opt_quiet,$opt_noop,$opt_ignore_hw); +our ($opt_quiet,$opt_noop,$opt_ignore_hw,$opt_timeout); use constant OPTIONS => ( 'quiet' => \$opt_quiet, 'noop' => \$opt_noop, + 'timeout=i' => \$opt_timeout, ); sub USAGE { @@ -15,10 +16,12 @@ sub USAGE { usage: $0 start [options] stop [options] # (ignored) + wait [options] DEVICE options: --quiet : do not log actions --noop : dry run + --timeout=S : seconds to wait for DEVICE (wait only, default 30) __EOF__ } @@ -175,7 +178,26 @@ sub start { } } +sub wait_for_device { # 'net04' -> 1 if device (or its configured hardware) is present, 0 on timeout + my ($dev)=@_; + read_mxnet(); + my $hw=$DEV_TO_HW{$dev}; + my $deadline=time+$opt_timeout; + while (1) { + -d "/sys/class/net/$dev" and return 1; + if (defined $hw) { + for my $d (network_hardware_devices()) { + my $addr=eval { get_hw_address($d) } // next; + lc($addr) eq lc($hw) and return 1; + } + } + time>=$deadline and return 0; + select undef,undef,undef,0.1; + } +} + GetOptions(OPTIONS) or die USAGE; +$opt_timeout //= 30; # default documented in USAGE @ARGV>=1 or die USAGE; @@ -185,6 +207,13 @@ if ($cmd eq 'start') { start(); } elsif ($cmd eq 'stop') { ; +} elsif ($cmd eq 'wait') { + @ARGV>=2 or die USAGE; + my $dev=$ARGV[1]; + unless (wait_for_device($dev)) { + warn "timeout waiting for network device $dev after ${opt_timeout}s\n"; + exit 1; + } } else { die USAGE; }