diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/add_bootfile_eth_hwid | 29 | ||||
-rwxr-xr-x | scripts/mod_bootfile_eth_hwid | 36 | ||||
-rwxr-xr-x | scripts/rl-system.init | 20 | ||||
-rwxr-xr-x | scripts/system/vyatta_interface_rescan | 137 | ||||
-rwxr-xr-x | scripts/vyatta_net_name | 512 |
5 files changed, 325 insertions, 409 deletions
diff --git a/scripts/add_bootfile_eth_hwid b/scripts/add_bootfile_eth_hwid deleted file mode 100755 index 61deea56..00000000 --- a/scripts/add_bootfile_eth_hwid +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# add ethnet interface sub-block to configure file - -shopt -s extglob - -if [[ "$*" == *--help* ]] ; then - echo ${0##*/} [test_]FILE INTERFACE HWID - exit 0 -fi - -if [[ "$1" == test_* ]] ; then - origfile=$1 - bootfile=/tmp/${1##*/}_$$ - cp $origfile $bootfile - trap "diff -c $origfile $bootfile; rm -f $bootfile; exit 0" $? -else - origfile= - bootfile=$1 -fi -eth=$2 -hwid=$3 - -sed -i '/^interfaces {$/,/^}$/ { - /^}$/i\ - ethernet '"$eth"' {\ - hw-id '"$hwid"'\ - } - }' $bootfile diff --git a/scripts/mod_bootfile_eth_hwid b/scripts/mod_bootfile_eth_hwid deleted file mode 100755 index feab64f1..00000000 --- a/scripts/mod_bootfile_eth_hwid +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# modify interface sub-block - -shopt -s extglob - -if [[ "$*" == *--help* ]] ; then - echo ${0##*/} [test_]FILE INTERFACE HWID - exit 0 -fi - -if [[ "$1" == test_* ]] ; then - origfile=$1 - bootfile=/tmp/${1##*/}_$$ - cp $origfile $bootfile - trap "diff -c $origfile $bootfile; rm -f $bootfile; exit 0" $? -else - origfile= - bootfile=$1 -fi -eth=$2 -hwid=$3 - -sed -i '/^interfaces {$/,/^}$/ { - /^ ethernet '"$eth"' {$/ { - :join - /\n }$/ { - /hw-id:\? / s/\(hw-id\):\? [0-9a-fA-F:]\+/\1 '"$hwid"'/ - /hw-id:\? /! s/}$/ hw-id '"$hwid"'\n }/ - b - } - N - b join - } -}' $bootfile - diff --git a/scripts/rl-system.init b/scripts/rl-system.init index 3e07e11e..989c51e4 100755 --- a/scripts/rl-system.init +++ b/scripts/rl-system.init @@ -105,20 +105,10 @@ clear_or_override_config_files () done } -udev_rescan () -{ - rm -f /tmp/vyatta_net_name_* - udevadm trigger --subsystem-match=net && udevadm settle --quiet - for ff in /tmp/vyatta_net_name_* ; do - f=${ff##*/} - cmd_name_hwid=${f/vyatta_net_name_/} - cmd=${cmd_name_hwid%%_*} - name_hwid=${cmd_name_hwid#*_} - name=${name_hwid%_*} - hwid=${name_hwid#*_} - syslog $cmd $name $hwid - $vyatta_sbindir/${cmd}_bootfile_eth_hwid $BOOTFILE $name $hwid - done +update_interface_config () { + if [ -d /dev/.udev/vyatta ]; then + $vyatta_sbindir/vyatta_interface_rescan /dev/.udev/vyatta $BOOTFILE + fi } create_ssh_host_keys () { @@ -190,7 +180,7 @@ start () { mkdir -p /var/run/vyatta mkdir -p /var/log/vyatta - udev_rescan + update_interface_config create_ssh_host_keys || \ log_failure_msg "can't initialize ssh host keys" clear_or_override_config_files || \ diff --git a/scripts/system/vyatta_interface_rescan b/scripts/system/vyatta_interface_rescan new file mode 100755 index 00000000..62d550bf --- /dev/null +++ b/scripts/system/vyatta_interface_rescan @@ -0,0 +1,137 @@ +#! /usr/bin/perl + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# This code was originally developed by Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2010 Vyatta, Inc. +# All Rights Reserved. + +# Thus updates the configuration to add new interfaces. +# It is run on boot after udev and before vyatta configuration. + +use strict; +use lib "/opt/vyatta/share/perl5/"; +use Sys::Syslog qw(:standard :macros); +use XorpConfigParser; +use File::Copy; + +my $TMPFILE = "/tmp/config.boot.$$"; + +# These vendors are known to violate the local MAC address assignment convention +my %whitelist = ( + '02:07:01' => 'Interlan', + '02:60:60' => '3Com', + '02:60:8c' => '3Com', + '02:a0:c9' => 'Intel', + '02:aa:3c' => 'Olivetti', + '02:cf:1f' => 'CMC', + '02:e0:3b' => 'Prominet', + '02:e6:d3' => 'BTI', + '52:54:00' => 'Realtek', + '52:54:4c' => 'Novell 2000', + '52:54:ab' => 'Realtec', + 'e2:0c:0f' => 'Kingston Technologies', +); + +# Ignore devices with local assigned or invalid mac address, +# these devices don't have a persistent address +sub persistent_address { + my $mac = shift; + + # is local assignment bit (IEEE802) not set? + return 1 unless ($mac =~ /^.[2367abef]:/); + + # is address bogus? + return if ($mac eq '00:00:00:00:00:00'); + + # unless it is in whitelist, it is non persistent + $mac =~ /^([0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f])/; + return $whitelist{$1}; +} + +# Map from eth0 to ethernet +# TODO make smarter if more types +sub interface_type { + my $ifname = shift; + + return "ethernet" if ($ifname =~ /^eth/); + return "wireless" if ($ifname =~ /^wlan/); + + die "unknown interface name %s\n", $ifname; +} + +sub get_hwid { + my $name = shift; + + open (my $f, '<', $name) + or die "Can't open $name : $!"; + + my $hwaddr = <$f>; + chomp $hwaddr; + close $f; + + return $hwaddr; +} + +# vyatta_net_name leaves files in /dev/.udev/vyatta +# the filename is the interface and the contents are the hardware id +sub interface_rescan { + my ($VYATTAUDEV, $BOOTFILE) = @_; + + # parse existing config + my $xcp = new XorpConfigParser(); + $xcp->parse($BOOTFILE); + + opendir( my $dir, $VYATTAUDEV ) + or die "Can't open $VYATTAUDEV : $!"; + + foreach my $ifname (grep { ! /^\./ } readdir($dir)) { + my $ifpath = interface_type($ifname) . " $ifname"; + if ($xcp->get_node(['interfaces', $ifpath])) { + syslog(LOG_INFO, "%s: is already in config file", $ifname); + next; + } + + my $hwaddr = get_hwid("$VYATTAUDEV/$ifname"); + unless (persistent_address($hwaddr)) { + syslog(LOG_INFO, "%s: skipping address %s is not persistent", + $ifname, $hwaddr); + next; + } + + # Add new entry to config + syslog(LOG_INFO, "add config for %s hw-id %s", $ifname, $hwaddr); + $xcp->create_node(['interfaces',$ifpath,"hw-id $hwaddr"]); + } + + # Rewrite new config file + open (my $tmp, '>', $TMPFILE) + or die "Can't open $TMPFILE : $!"; + + select $tmp; + $xcp->output(0); + select STDOUT; + close $tmp; + + copy($TMPFILE, $BOOTFILE) + or die "Can't copy $TMPFILE to $BOOTFILE : $!"; + + unlink($TMPFILE); +} + +# main +die "vyatta_interface_rescan called with wrong args" + unless ($#ARGV == 1); + +openlog("vyatta-interface-rescan", "", LOG_DAEMON); + +interface_rescan(@ARGV); +exit 0; + diff --git a/scripts/vyatta_net_name b/scripts/vyatta_net_name index de1fbcbf..c7b217d9 100755 --- a/scripts/vyatta_net_name +++ b/scripts/vyatta_net_name @@ -1,5 +1,5 @@ -#!/bin/bash -# **** License **** +#! /usr/bin/perl + # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. @@ -10,349 +10,203 @@ # General Public License for more details. # # This code was originally developed by Vyatta, Inc. -# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2010 Vyatta, Inc. # All Rights Reserved. -# -# Authors: Tom Grennan <tgrennan@vyatta.com> -# Bob Gilligan <gilligan@vyatta.com> -# Description: search Vyatta config for interface name given address -# -# **** End License **** - -progname=${0##*/} -debug= -match= -attr_address=0:0:0:0:0:0 -declare -i ethn=0 -udev_persistent_net_rules_file="/etc/udev/rules.d/70-persistent-net.rules" - -# Set log_file to "/dev/null" to turn off debugging -log_file="/tmp/vnn_log" - -test -r /etc/default/vyatta && source /etc/default/vyatta - -# process command line variable overrides - -for arg ; do - case "$arg" in - --debug ) - debug=echo - ;; - --*=* ) - arg=${arg#--} - eval ${arg%=*}=\"${arg#*=}\" - ;; - *=* ) - eval ${arg%=*}=\"${arg#*=}\" - ;; - *:*:*:*:*:* ) - attr_address=$arg - ;; - * ) - orig_kname=$arg - ;; - esac -done - -: ${vyatta_prefix:=/opt/vyatta} -: ${vyatta_sbindir:=${vyatta_prefix}/sbin} -: ${vyatta_sysconfdir:=${vyatta_prefix}/etc} -: ${BOOTFILE:=${vyatta_sysconfdir:-/opt/vyatta/etc}/config/config.boot} -: ${DEFAULT_BOOTFILE:=${vyatta_sysconfdir:-/opt/vyatta/etc}/config.boot.default} - -shopt -s extglob nullglob - -# load cfg_eth_hwid array from the Vyatta config file by looking -# for entries formatted as follows: -# -# interface { -# ... -# ethernet eth# { -# ... -# hw-id XX:XX:XX:XX:XX:XX -# ... -# } -# } -# -# The result is an array named "cfg_net_hwid". Each element of the -# array is formatted like this: -# -# eth#=xx:xx:xx:xx:xx:xx -# -declare -a cfg_net_hwid=( $( sed -ne ' - /^interfaces {/,/^}/ { - /^ *ethernet eth[0-9]* {/,/^ $/ { - /^ *ethernet/ { - s/\r// - s/.* eth\([0-9]\+\) {$/ eth\1=/ -# hold interface name - h - } - /^.*hw-id:\?/ { -# translate field name - s/\r// - s/.*hw-id:\? *// -# tolower hex mac address - y/ABCDEF/abcdef/ -# exchange hold and pattern space - x -# concatenate hold and pattern - G - s/\n//p +use strict; +use lib "/opt/vyatta/share/perl5/"; +use XorpConfigParser; +use Vyatta::Config; +use Sys::Syslog qw(:standard :macros); +use Fcntl qw(:flock); + +my $BOOTFILE = "/opt/vyatta/etc/config/config.boot"; +my $UDEVDIR = "/dev/.udev"; + +my $VYATTAUDEV = $UDEVDIR . "/vyatta"; +my $LOCKFILE = $UDEVDIR . "/.vyatta-lock"; +my $VYATTACFG = "/opt/vyatta/config/active"; + +# Check if interface name is free to use +sub is_available { + my ($interfaces, $ifname) = @_; + + my $count = grep { $_ eq $ifname } values %$interfaces; + return ($count == 0); +} + +# Find next available interface name +sub find_available { + my ($interfaces, $ifprefix) = @_; + $ifprefix =~ s/\d+$//; + + for (my $id = 0; ; $id++) { + my $ifname = sprintf("%s%d", $ifprefix, $id); + + # is it in Vyatta config? + return $ifname if (is_available($interfaces, $ifname)); + } +} + +# Find the hardware id in the parsed config node for interface +sub get_hwid_from_children { + my $children = shift; + + foreach my $attr (@$children) { + next unless ($attr->{'name'} =~ /^hw-id ([0-9a-f:]+)/); + return $1; + } + + return; # not found +} + + +# Leave file for vyatta_interface_rescan +sub leave_rescan_hint { + my ($ifname, $hwaddr) = @_; + my $name = "$VYATTAUDEV/$ifname"; + + mkdir($VYATTAUDEV); + open (my $f, '>', $name) + or die "Can't create $name : $!"; + + print {$f} "$hwaddr\n"; + close $f; + return 1; +} + +# Determine network name to use based on Vyatta config during boot +sub coldplug { + my ($ifname, $hwaddr) = @_; + my $xcp = new XorpConfigParser(); + $xcp->parse($BOOTFILE); + + my $interfaces = { }; + my $inode = $xcp->get_node(['interfaces']); + if ($inode) { + foreach my $child (@{$inode->{'children'}}) { + next unless ($child->{'name'} =~ /^ethernet (.*)|^wireless (.*)/); + + my $intf = $1; + my $hwid = get_hwid_from_children($child->{'children'}); + next unless $hwid; + + # TBD this could be a hash with name and path? + $interfaces->{$hwid} = $intf; + } + } + + # is name already in config file + my $newname = $interfaces->{$hwaddr}; + return $newname if ($newname); + + # add already assigned names + if (opendir(my $dir, $VYATTAUDEV)) { + foreach my $intf (grep { ! /^\./ } readdir($dir)) { + if (open (my $f, '<', "$VYATTAUDEV/$intf")) { + my $hwid = <$f>; + close $f; + chomp $hwid; + + $interfaces->{$hwid} = $intf; } } - }' $BOOTFILE )) + } + + # Does biosdevname have a suggestion? + my $biosname = `/sbin/biosdevname -i $ifname`; + chomp $biosname; + if ($biosname ne '') { + $newname = $biosname; + } else { + $newname = $ifname; + } + + $newname = find_available($interfaces, $newname) + unless (is_available($interfaces, $newname)); + + leave_rescan_hint($newname, $hwaddr); + + return $newname; +} + +# Determine name from active config +sub hotplug { + my ($ifname, $hwaddr) = @_; + + openlog("vyatta-net-name", "", LOG_DAEMON); + + # Parse active config + my $cfg = new Vyatta::Config; + $cfg->setLevel('interfaces'); + + my $interfaces = {}; + foreach my $type ($cfg->listOrigNodes()) { + next unless ($type eq 'ethernet') || ($type eq 'wireless'); + foreach my $intf ($cfg->listOrigNodes($type)) { + my $hwid = $cfg->returnOrigValue("$type $intf hw-id"); + next unless $hwid; + # TBD this could be a hash with name and path? + $interfaces->{$hwid} = $intf; + } + } -finish () -{ - local cmd=$1 name=$2 address=$3 + my $newname = $interfaces->{$hwaddr}; + return $newname if ($newname); - # The output from this program tells udev what name to give this device - echo $name + # Does biosdevname have a suggestion? + my $biosname = `/sbin/biosdevname -i $ifname`; + chomp $biosname; + syslog(LOG_DEBUG, "biosdevname for '%s' => '%s'", $ifname, $biosname); - # This file tells rl_system startup script how to update the Vyatta - # config file. - touch /tmp/${progname}_${cmd}_${name}_${address} &> /dev/null + if ($biosname && ($biosname ne '')) { + $newname = $biosname; + } else { + $newname = $ifname; + } - # Remove entry for this MAC addr from the standard udev generated - # config file, if it exists, so it doesn't rename the interface - # out from under us. Remove the subject line plus the comment - # line above it - if [ -e $udev_persistent_net_rules_file ]; then - sed -i -e "/^#/N;/${address}.*NAME/d" $udev_persistent_net_rules_file - fi + $newname = find_available($interfaces, $ifname) + unless is_available($interfaces, $biosname); - exit $? + syslog(LOG_INFO, "new name for '%s' is '%s'", $ifname, $newname); + + return $newname; } -# Determine whether variable "ethn" conflicts with an ethernet unit -# number that was assigned in previous runs of this script -ethn_conflicts() -{ - # Return value 1 (failure) means no conflicts found. - # Return value 0 (success) means conflicts were found. - conflicts=1 - - echo "`date`: ethn_conflicts is checking if $ethn has conflicts" >> $log_file - # Generate list of ethernet unit numbers assigned previously by this script - used_ethn="" - for filename in /tmp/vyatta_net_name* ; do - if [ -e $filename ]; then - # strip off everything before the unit number - unit=${filename##*vyatta_net_name_*_eth} - # strip off everything after the unit number - unit=${unit%%_*} - # add unit number from this file to the list - used_ethn="$used_ethn $unit" - fi - done - - echo "`date`: ethn_conflicts: about to run check" >> $log_file - - for this_ethn in $used_ethn ; do - if [ $ethn -eq $this_ethn ]; then - echo "`date`: ethn $ethn conflicts with previously configured $this_ethn" >> $log_file - conflicts=0 - break - fi - done - - echo "`date`: ethn_conflicts for ethn $ethn returns $conflicts" >> $log_file - # return value (exit status) is true, i.e. 0, if there is a conflict - return $conflicts +my $LOCKF; +sub lock_file { + open ($LOCKF, '>', $LOCKFILE) + or die "Can't open $LOCKFILE : $!"; + + flock ($LOCKF, LOCK_EX) + or die "Can't lock $LOCKFILE : $!"; + } +sub unlock_file { + close $LOCKF; + $LOCKF = undef; +} -# -# Find an ethernet unit number that is neither listed in the config -# file nor assigned by this script in earlier runs. -get_free_ethn() -{ - # list of ethernet unit numbers assigned previously by this script - used_ethn="" - for filename in /tmp/vyatta_net_name* ; do - if [ -e $filename ]; then - # strip off everything before the unit number - unit=${filename##*vyatta_net_name_*_eth} - # strip off everything after the unit number - unit=${unit%%_*} - # add unit number from this file to the list - used_ethn="$used_ethn $unit" - fi - done - - # Counting up from 0, try to find a free ethernet unit number - found=0 - for ((ethn_to_use=0 ; ; ethn_to_use+=1)) ; do - found=1 - # Check to see if this one is in the config file - - echo "`date`: get_free_ethn: cfg_net_hwid is ${cfg_net_hwid[@]}" >> $log_file - - for name_hwid in ${cfg_net_hwid[@]} ; do - name=${name_hwid%=*} - this_ethn=${name/eth/} - echo "`date`: get_free_ethn 1 comparing $ethn_to_use vs $this_ethn" >> $log_file - if [ $ethn_to_use -eq $this_ethn ]; then - found=0 - break - fi - done - - if [ $found -eq 0 ]; then - continue - fi - - echo "`date`: get_free_ethn: used_ethn is $used_ethn" >> $log_file - - # Check to see if this script has assigned this unit number already - for this_ethn in $used_ethn ; do - echo "`date`: get_free_ethn 2 comparing $ethn_to_use vs $this_ethn" >> $log_file - if [ $ethn_to_use -eq $this_ethn ]; then - found=0 - break - fi - done - - if [ $found -eq 1 ]; then - break - fi - done - - # The return value - ethn=$ethn_to_use - - echo "`date`: get_free_ethn found $ethn_to_use" >> $log_file +# This script is called from udev with two arguments +# it outputs the new name (if any) to stdout +if ($#ARGV != 1) { + die "vyatta_net_name called with wrong args(%d) : %s", + $#ARGV, join(' ', @ARGV); } -# -# Main Section -# -# Run with lock held to protect atomicity of access to assigned ethn file -( flock 200 +my $ifname = $ARGV[0]; +my $hwaddr = $ARGV[1]; -touch $log_file +lock_file; +my $newname; +if ( -d $VYATTACFG ) { + $newname = hotplug($ifname, $hwaddr); +} else { + $newname = coldplug($ifname, $hwaddr); +} +unlock_file; -echo "`date`: vyatta_net_name $orig_kname $attr_address" >> $log_file +print "$newname\n" if ($newname); -# The biosdevname program determines the "recommended" name for the NIC -# based on information such its place in the bus topology, and whether it -# resides on the motherboard or not. The ensures deterministic NIC naming. -# -if [ ! -z "$orig_kname" ]; then - if [ -e /sbin/biosdevname ]; then - kname=`/sbin/biosdevname -i $orig_kname` - echo "`date`: /sbin/biosdevname maps $orig_kname to $kname" >> $log_file - else - echo "`date`: /sbin/biosdevname is not present on this system" >> $log_file - kname=$orig_kname - fi -else - kname="" -fi - -if [ ! -f $BOOTFILE ] ; then - cp $DEFAULT_BOOTFILE $BOOTFILE - chgrp vyattacfg $BOOTFILE - chmod 660 $BOOTFILE -fi - -for name_hwid in ${cfg_net_hwid[@]} ; do - name=${name_hwid%=*} - hwid=${name_hwid#*=} - ethn=${name/eth/} - echo "`date`: Checking $name_hwid against $kname $attr_address" >> $log_file - - if [ "$hwid" == "$attr_address" ] ; then - # The MAC addr of this interface matches an entry in the config - # file. We mod the config file interface sub-block in case it - # is missing. - - echo "`date`: finish 1: mod $name $attr_address" >> $log_file - - finish mod $name $attr_address - fi - - if [ "$name" = "$kname" ]; then - # The kernel name matches an entry in the config file. Save the - # config file entry for later examination. - - match=$name_hwid - fi -done - -if [ -z "$kname" ]; then - echo "`date`: Error: interface name not specified by caller" >> $log_file - exit 1 -fi - -# We have not found a matching hwid in the config file. See if we can use -# the kernel name. - -if [ -z "$match" ] ; then - # The kernel interface name is not listed in the config file. - # If the kernel's name is in the standard "ethN" format, and doesn't - # conflict with any other name we've used, then - # we can just go ahead and use the kernel's name. If not, then - # we will generate a name in the standard format that does not - # conflict with any names in the config file, or any other names - # that we have seen. - - non_std_kname=${kname##eth+([0-9])} - if [ -z "$non_std_kname" ]; then - # kname is in standard format, so we get the unit number from it. - ethn=${kname/eth/} - - # We can use this unit number unless it happens to conflict - # with one we have already assigned. - if ethn_conflicts ; then - echo "`date`: kname $kname conflicts with already assigned unit" >> $log_file - get_free_ethn - fi - else - # kname is not in standard format, so we have to generate - # a unit number - echo "`date`: kname $kname is non-standard format" >> $log_file - get_free_ethn - fi - - echo "`date`: finish 2: add eth$ethn $attr_address" >> $log_file - - finish add eth$ethn $attr_address - -elif [ -z "${match#*=}" ] ; then - # The config file has this interface but the sub-block is missing the hwid - # field, so we use the kernel name. In this case, we know that the - # kernel name is in the standard format because it matched an entry - # in the config file, and all entries in the config file are in standard - # format. This will cause the hwid for this NIC to be added to the - # entry in the config file. - - echo "`date`: finish 3: mod $kname $attr_address" >> $log_file - - finish mod $kname $attr_address - -else - # The config file has this interface name, but the mac address is not - # that of this NIC. This indicates that the device is either a - # replacement or new NIC that is being detected earlier than the device - # configured with this name. Since we don't know which case it is, - # we must generate a new unit number. - get_free_ethn - - echo "`date`: finish 4: add eth$ethn $attr_address" >> $log_file - - finish add eth$ethn $attr_address -fi - -# Should never get here. If this shows up in the log file, something -# is wrong! -echo "`date`: no finish: kname = $kname, attr_attr = $attr_address, match = $match" >> $log_file - -) 200> /tmp/vnn_lock - -# Local Variables: -# mode: shell-script -# sh-indentation: 4 -# End: +exit 0; |