#!/usr/bin/perl use strict; use warnings; use Getopt::Std; my $BASEDIR = "/sys/class/net"; my $USAGE = "\n\n$0 [-v] -v verbose -t test-only, do not actually change configuration "; my %opts; getopts("vt", \%opts) or die $USAGE; if (@ARGV != 1) { die $USAGE; } my $config = load_config($ARGV[0]); my $devices = load_nics(); my @tasks; # will contain what to do after we examine *all* data my $temp_count = int(rand(10000)); # count for temporary nic names my $done = 1; STARTOVER: foreach my $deviceid (keys %$config) { my $name = $config->{$deviceid}; print "Attempting to setup '$name' to '$deviceid'\n" if ($opts{'v'}); my $actual_name = undef; # lookup which device name owns this device ID foreach my $name2 (keys %$devices) { unless (defined $devices->{$name2}) { die "Illegal state [$name2 is undefined in %devices]"; } my ($mac2, $device2) = @{$devices->{$name2}}; if ($device2 eq $deviceid) { print "Found '$deviceid' already assigned to '$name2'\n" if ($opts{'v'}); $actual_name = $name2; last; } } if (! defined($actual_name)) { # unable to find that PCI address die "Device ID '$deviceid' does not exist.\n"; } elsif ($actual_name eq $name) { # found the PCI address associated with that name already print "Device named '$name' is setup properly.\n" if ($opts{'v'}); } else { # found the PCI address, but it's associated with another name print "Device named '$name' needs the resources assigned to '$actual_name'\n" if ($opts{'v'}); # need to save our current resources to a temp name? if (defined $devices->{$name}) { my $tmp = "tmp_" . $temp_count; print "Saving resources of '$name' to '$tmp'.\n" if ($opts{'v'}); push @tasks, ["setnic", $name, $tmp]; $devices->{$tmp} = $devices->{$name}; } print "Assigning resources of '$actual_name' to '$name'\n" if ($opts{'v'}); push @tasks, ["setnic", $actual_name, $name]; $devices->{$name} = $devices->{$actual_name}; delete $devices->{$actual_name}; # no longer exists $temp_count += int(rand(1000) + 1); goto STARTOVER; } } if ($opts{'v'}) { if (@tasks > 0) { print "Task list:\n"; foreach my $task (@tasks) { print "\t[" . join ("] [", @$task) . "]\n"; } } else { print "Task list is empty.\n"; } } unless ($opts{'t'}) { foreach my $task (@tasks) { do_cmd(@$task); } } exit (0); # do_cmd -- do a command and die if unable to complete it # # @param @command sub do_cmd { system (@_); my $exit_value = $? >> 8; if ($exit_value != 0) { die "Unable to run command: " . join (" ", @_) . " [$!]"; } } # load_config # # @param path to config file # @return hash (key = device ID, value = name) sub load_config { my $file = shift; my $config = {}; my $seen = {}; open IN, $file or die "Unable to read '$file' : $!"; while (my $line = ) { $line =~ s/\s+$//; next unless ($line =~ /\S/); next if ($line =~ /^\#/); my ($deviceid, $name) = split (/\t/, $line); unless (defined $name) { die "Illegal NIC configuration file: $file\n\n$line\n\n"; } if (defined $config->{$deviceid}) { die "Device ID '$deviceid' appears multiple times in '$file'\n"; } if (defined $seen->{$name}) { die "Device name '$name' appears multiple times in '$file'\n"; } $config->{$deviceid} = $name; $seen->{$name} = 1; } close IN; return $config; } # load_nics # # @return hash (key = name of device, value = arrayref [ mac, device ID ] sub load_nics { my $devices = {}; open SHOW, "shownics -md |" or die "Unable to run shownics : $!"; while (my $line = ) { chop $line; my ($name, $mac, $device) = split (/\t/, $line); $devices->{$name} = [ $mac, $device ]; } close SHOW; return $devices; }