#! /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; return if ($mac eq '00:00:00:00:00:00'); # zero address is reserved # get first octet return unless ($mac =~ /^([0-9a-f][0-9a-f]):/); my $oct0 = hex($1); return if ($oct0 & 0x1); # skip it is a multicast address return 1 unless ($oct0 & 0x2); # this is good, not locally assigned return 1 if ( -d '/proc/xen' ); # workaround Xen breakage # 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; } # Determine phy for wlan device # (This is ugly) sub get_phy { my $wlan = shift; my $phypath = "/sys/class/net/$wlan/phy80211"; # link should be: ../../ieee80211/phy0 return unless (readlink($phypath) =~ m!../../ieee80211/(phy[0-9]+)$!); return $1; } # 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); # get list of changed interfaces opendir( my $dir, $VYATTAUDEV ) or die "Can't open $VYATTAUDEV : $!"; my @interfaces = grep { ! /^\./ } readdir($dir); close $dir; foreach my $ifname (sort @interfaces) { my $hwaddr = get_hwid("$VYATTAUDEV/$ifname"); unless (persistent_address($hwaddr)) { syslog(LOG_NOTICE, "%s: skipping address %s is not persistent", $ifname, $hwaddr); next; } # Add new entry to config my $ifpath = interface_type($ifname) . " $ifname"; syslog(LOG_INFO, "add config for %s hw-id %s", $ifname, $hwaddr); $xcp->create_node(['interfaces',$ifpath,"hw-id $hwaddr"]); # Add existing phy entry for wireless if ($ifname =~ /^wlan/) { my $phy = get_phy($ifname); $xcp->create_node(['interfaces',$ifpath,"physical-device $phy"]) if $phy; } } # 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;