summaryrefslogtreecommitdiff
path: root/scripts/vyatta_net_name
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/vyatta_net_name')
-rwxr-xr-xscripts/vyatta_net_name512
1 files changed, 183 insertions, 329 deletions
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;