-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
#! /usr/bin/perl | ||
use strict; | ||
use warnings; | ||
|
||
use Getopt::Long; | ||
|
||
# options | ||
|
||
our ($opt_quiet,$opt_noop,$opt_ignore_hw); | ||
use constant OPTIONS => ( | ||
'quiet' => \$opt_quiet, | ||
'noop' => \$opt_noop, | ||
); | ||
|
||
sub USAGE { | ||
return <<"__EOF__"; | ||
usage: $0 | ||
start [options] | ||
stop [options] # (ignored) | ||
upgrade # switch from eth to net | ||
options: | ||
--quiet : do not log actions | ||
--noop : dry run | ||
__EOF__ | ||
} | ||
|
||
sub scandir { | ||
my ($dirname)=@_; | ||
opendir my $dir,$dirname or die "$dirname: $!\n"; | ||
return sort grep !/^\./,readdir $dir; | ||
} | ||
|
||
sub slurpfile { | ||
my ($path)=@_; | ||
open my $fh,'<',$path or die "$path: $!\n"; | ||
return join ('',<$fh>); | ||
} | ||
|
||
sub slurpfile_chomp { | ||
my $data=slurpfile($_[0]); | ||
chomp($data); | ||
return $data; | ||
} | ||
|
||
sub network_devices { # -> ( 'bond0','dummy0','eth0','eth1','eth2','eth2.43','eth3','eth4','eth5','lo','sit0' ) | ||
return grep -d "/sys/class/net/$_",scandir('/sys/class/net'); | ||
} | ||
|
||
sub network_hardware_devices { # -> ( eth0','eth1','eth2','eth3','eth4','eth5' ) | ||
return grep -e "/sys/class/net/$_/device",network_devices(); | ||
} | ||
|
||
|
||
sub get_hw_address { # 'eth1' -> '00:1b:21:79:76:67' | ||
my ($dev)=@_; | ||
my $path="/sys/class/net/$dev/address"; | ||
return slurpfile_chomp($path); | ||
} | ||
|
||
|
||
our %HW_TO_DEV; # ( '00:1b:21:79:76:67' => 'net02' , ... ) | ||
our %DEV_TO_HW; # ('net02'=>'00:1b:21:79:76:67', ... ) | ||
our $CHANGES; | ||
|
||
|
||
sub register_stable { | ||
my ($hw,$dev)=@_; | ||
|
||
# force one-to-one mapping, even if file is erroneus | ||
|
||
exists $DEV_TO_HW{$dev} and delete $HW_TO_DEV{$DEV_TO_HW{$dev}}; | ||
exists $HW_TO_DEV{$dev} and delete $DEV_TO_HW{$HW_TO_DEV{$hw}}; | ||
|
||
|
||
$HW_TO_DEV{$hw}=$dev; | ||
$DEV_TO_HW{$dev}=$hw; | ||
$CHANGES++; | ||
} | ||
|
||
|
||
sub read_mxnet { | ||
%HW_TO_DEV=(); | ||
%DEV_TO_HW=(); | ||
-r '/etc/local/mxnet' or return; | ||
open my $file,'<','/etc/local/mxnet' or die "/etc/local/mxnet: $!\n"; | ||
while (<$file>) { | ||
s/#.*//; | ||
/\S/ or next; | ||
my ($hw,$dev)=split; | ||
register_stable($hw,$dev); | ||
} | ||
$CHANGES=0; | ||
} | ||
|
||
sub write_mxnet { | ||
my $mxnet; | ||
unless ($opt_noop) { | ||
open my $mxnet,'>',"/etc/local/mxnet" or die "/etc/local/mxnet: $!\n"; | ||
print $mxnet "# generated ".scalar(localtime)." by $0\n\n"; | ||
for my $dev (sort keys %DEV_TO_HW) { | ||
print $mxnet $DEV_TO_HW{$dev},' ',$dev."\n"; | ||
} | ||
print $mxnet "\n"; | ||
|
||
# open my $out,'>',"/etc/local/mxnet-udev.rules" or die "/etc/local/mxnet-udev.rules: $!\n"; | ||
# print $out "# generated ".scalar(localtime)." by $0\n\n"; | ||
# for my $dev (sort keys %DEV_TO_HW) { | ||
# print $out qq'SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="$DEV_TO_HW{$dev}", NAME="$dev"\n'; | ||
# } | ||
} | ||
} | ||
|
||
sub get_unused_name { | ||
my $next_name=0; | ||
while(1) { | ||
my $name=sprintf 'net%02d',$next_name++; | ||
exists $DEV_TO_HW{$name} or return $name; | ||
} | ||
} | ||
|
||
|
||
sub rename_if { | ||
my ($src,$dst)=@_; | ||
warn "rename $src to $dst\n" unless $opt_quiet; | ||
unless ($opt_noop) { | ||
if (defined $src =~ /^eth/) { | ||
system 'ip','link','set',$src,'name',$dst,'alias',$src; # continue on error | ||
$? and warn "failed to rename $src to $dst\n"; | ||
} else { | ||
system 'ip','link','set',$src,'name',$dst; # continue on error | ||
$? and warn "failed to rename $src to $dst\n"; | ||
} | ||
} | ||
} | ||
|
||
|
||
sub preferred_device_name { | ||
my ($dev,$hw)=@_; | ||
|
||
exists $HW_TO_DEV{$hw} and return $HW_TO_DEV{$hw}; # configured | ||
$dev =~ /(\d+)/; | ||
|
||
my $new_dev=sprintf 'net%02d',$1; # stable number if free | ||
unless (exists $DEV_TO_HW{$new_dev}) { | ||
register_stable($hw,$new_dev); | ||
return $new_dev; | ||
} | ||
|
||
$new_dev=get_unused_name(); # any free new number | ||
register_stable($hw,$new_dev); | ||
return $new_dev; | ||
} | ||
|
||
|
||
|
||
our $TMP_NUM=0; | ||
sub out_of_the_way { | ||
my ($dev)=@_; # only 'netXX' or 'ethX' - never 'tmpXX' | ||
|
||
-e "/sys/class/net/$dev/device" or return; | ||
|
||
my $i = $dev=~/(\d+)/; | ||
rename_if($dev,sprintf('tmpnet%02d',$TMP_NUM++)); | ||
} | ||
|
||
sub start { | ||
read_mxnet(); | ||
|
||
# 1: rename configured ethX and netXX devices to configured netXX - move away conflicting devices | ||
|
||
for my $dev (grep /^(eth|net)(\d+)/,network_hardware_devices()) { | ||
my $hw=get_hw_address($dev); | ||
my $new_dev=preferred_device_name($dev,$hw); | ||
if ($dev ne $new_dev) { | ||
out_of_the_way($new_dev); | ||
rename_if($dev,$new_dev); | ||
} | ||
} | ||
|
||
# 2 : rename moved away devices to netXX | ||
|
||
for my $dev (grep /^(tmpnet)(\d+)/,network_hardware_devices()) { | ||
my $hw=get_hw_address($dev); | ||
my $new_dev=preferred_device_name($dev,$hw); | ||
rename_if($dev,$new_dev); | ||
} | ||
|
||
#if ($CHANGES || ! -e "/etc/local/mxnet-udev.rules") { | ||
if ($CHANGES) { | ||
write_mxnet(); | ||
} | ||
} | ||
|
||
|
||
|
||
sub upgrade { | ||
umask 022; | ||
|
||
-d '/etc/local' or mkdir '/etc/local' or die "/etc/local: $!\n"; | ||
|
||
read_mxnet(); | ||
for my $dev (grep /^(eth|net)(\d+)/,network_hardware_devices()) { | ||
my $hw=get_hw_address($dev); | ||
my $new_dev=preferred_device_name($dev,$hw); | ||
} | ||
write_mxnet(); | ||
|
||
unlink "/etc/udev/rules.d/70-persistent-net.rules"; | ||
|
||
my $data=slurpfile('/etc/systemd/system/network.service'); | ||
unless ($data=~/mxnetctl/) { | ||
$data=~s#^ExecStart#ExecStart=/usr/sbin/mxnetctl start\nExecStart#m; | ||
$data=~s/eth(\d+)/sprintf 'net%02d',$1/eg; | ||
open my $out,'>','/etc/systemd/system/network.service' or die "/etc/systemd/system/network.service: $!\n"; | ||
print $out $data; | ||
close $out; | ||
} | ||
|
||
warn "updated /etc/local/mxnet , /etc/systemd/system/network.service , /etc/udev/rules.d/70-persistent-net.rules - reboot to activate\n"; | ||
} | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
GetOptions(OPTIONS) or die USAGE; | ||
|
||
@ARGV>=1 or die USAGE; | ||
|
||
my ($cmd)=@ARGV; | ||
|
||
|
||
if ($cmd eq 'start') { | ||
start(); | ||
} elsif ($cmd eq 'stop') { | ||
; | ||
} elsif ($cmd eq 'upgrade') { | ||
upgrade(); | ||
; | ||
} else { | ||
die USAGE; | ||
} | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|