Bonjour,
Voici le fichier vyatta-interfaces.pl
#!/usr/bin/perl
#
# Module: vyatta-interfaces.pl
#
# **** License ****
# 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.
#
# A copy of the GNU General Public License is available as
# `/usr/share/common-licenses/GPL' in the Debian GNU/Linux distribution
# or on the World Wide Web at `http://www.gnu.org/copyleft/gpl.html'.
# You can also obtain it by writing to the Free Software Foundation,
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
# This code was originally developed by Vyatta, Inc.
# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
# All Rights Reserved.
#
# Author: Stig Thormodsrud
# Date: November 2007
# Description: Script to assign addresses to interfaces.
#
# **** End License ****
#
use lib "/opt/vyatta/share/perl5/";
use Vyatta::Config;
use Vyatta::Misc qw(generate_dhclient_intf_files
getInterfaces getIP get_sysfs_value
is_address_enabled is_dhcp_enabled is_ip_v4_or_v6);
use Vyatta::File qw(touch);
use Vyatta::Interface;
use Getopt::Long;
use POSIX;
use strict;
use warnings;
my $dhcp_daemon = '/sbin/dhclient';
my $ETHTOOL = '/sbin/ethtool';
my ($dev, $mac, $mac_update);
my %skip_interface;
my ($check_name, $show_names, $vif_name, $warn_name, $check_non_switched);
my ($check_up, $dhcp_command, $allowed_speed, $restore_ipv6);
my (@speed_duplex, @addr_commit, @check_speed);
sub usage {
print <<EOF;
Usage: $0 --dev=<interface> --check=<type>
$0 --dev=<interface> --warn
$0 --dev=<interface> --valid-mac=<aa:aa:aa:aa:aa:aa>
$0 --dev=<interface> --valid-addr-commit={addr1 addr2 ...}
$0 --dev=<interface> --speed-duplex=speed,duplex
$0 --dev=<interface> --check-speed=speed,duplex
$0 --dev=<interface> --allowed-speed
$0 --dev=<interface> --isup
$0 --dev=<interface> --restore-ipv6
$0 --dev=<interface> --check-non-switched
$0 --show=<type>
EOF
exit 1;
}
GetOptions("valid-addr-commit=s{,}" => \@addr_commit,
"dev=s" => \$dev,
"valid-mac=s" => \$mac,
"set-mac=s" => \$mac_update,
"dhcp=s" => \$dhcp_command,
"check=s" => \$check_name,
"show=s" => \$show_names,
"skip=s" => sub { $skip_interface{$_[1]} = 1 },
"vif=s" => \$vif_name,
"warn" => \$warn_name,
"isup" => \$check_up,
"speed-duplex=s{2}" => \@speed_duplex,
"check-speed=s{2}" => \@check_speed,
"allowed-speed" => \$allowed_speed,
"restore-ipv6" => \$restore_ipv6,
"check-non-switched" => \$check_non_switched,
) or usage();
is_valid_addr_commit($dev, @addr_commit) if (@addr_commit);
is_valid_mac($mac, $dev) if ($mac);
update_mac($mac_update, $dev) if ($mac_update);
dhcp($dhcp_command, $dev) if ($dhcp_command);
is_valid_name($check_name, $dev) if ($check_name);
exists_name($dev) if ($warn_name);
show_interfaces($show_names) if ($show_names);
is_up($dev) if ($check_up);
set_speed_duplex($dev, @speed_duplex) if (@speed_duplex);
check_speed_duplex($dev, @check_speed) if (@check_speed);
allowed_speed($dev) if ($allowed_speed);
restore_ipv6_addr($dev) if ($restore_ipv6);
check_non_switched($dev) if ($check_non_switched);
exit 0;
sub is_ip_configured {
my ($intf, $ip) = @_;
my $found = grep { $_ eq $ip } Vyatta::Misc::getIP($intf);
return ($found > 0);
}
sub is_ipv4 {
return index($_[0],':') < 0;
}
sub is_up {
my $name = shift;
my $intf = new Vyatta::Interface($name);
die "Unknown interface type for $name" unless $intf;
exit 0 if ($intf->up());
exit 1;
}
sub dhcp_write_file {
my ($file, $data) = @_;
open(my $fh, '>', $file) || die "Couldn't open $file - $!";
print $fh $data;
close $fh;
}
sub dhcp_conf_header {
my $output;
my $date = `date`;
chomp $date;
$output = "#\n# autogenerated by vyatta-interfaces.pl on $date\n#\n";
return $output;
}
sub get_hostname {
my $config = new Vyatta::Config;
$config->setLevel("system");
return $config->returnValue("host-name");
}
sub is_domain_name_set {
my $config = new Vyatta::Config;
$config->setLevel("system");
return $config->returnValue("domain-name");
}
sub get_mtu {
my $name = shift;
my $intf = new Vyatta::Interface($name);
return $intf->mtu();
}
sub replace_quot {
my $line = shift;
my $count = $line =~ s/\"/\"/g;
if ( $count ne '' and $count % 2 ) {
print "Error: unbalanced quotes [$line]\n";
exit 1;
}
return $line;
}
sub get_client_options {
my $name = shift;
my $config = new Vyatta::Config;
my $intf = new Vyatta::Interface($name);
my $path = $intf->path();
$config->setLevel("$path dhcp-options");
my @options = $config->returnValues('client-option');
my $output = '';
foreach my $line (@options) {
my $decoded_line = replace_quot($line);
$output .= "\t$decoded_line\n";
}
return $output;
}
sub dhcp_update_config {
my ($conf_file, $intf) = @_;
my $output = dhcp_conf_header();
my $hostname = get_hostname();
$output .= "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n\n";
#-- FD ligne ajoutà©e pour LIVEBOX ORANGE Option 90
$output .= "option rfc3118-auth code 90 = string;\n\n";
$output .= "interface \"$intf\" {\n";
if (defined($hostname)) {
$output .= "\tsend host-name \"$hostname\";\n";
}
$output .= "\trequest subnet-mask, broadcast-address, routers, domain-name-servers";
my $domainname = is_domain_name_set();
if (!defined($domainname)) {
$output .= ", domain-name";
}
my $mtu = get_mtu($intf);
$output .= ", interface-mtu" unless $mtu;
$output .= ";\n";
$output .= get_client_options($intf);
$output .= "}\n\n";
dhcp_write_file($conf_file, $output);
}
# Is interface disabled in configuration (only valid in config mode)
sub is_intf_disabled {
my $name = shift;
my $intf = new Vyatta::Interface($name);
$intf or die "Unknown interface name/type: $name\n";
my $config = new Vyatta::Config;
$config->setLevel($intf->path());
return $config->exists("disable");
}
sub run_dhclient {
my ($intf, $op_mode) = @_;
my ($intf_config_file, $intf_process_id_file, $intf_leases_file)
= generate_dhclient_intf_files($intf);
# perform config mode actions if not called from op-mode
if (!defined $op_mode) {
dhcp_update_config($intf_config_file, $intf);
return if is_intf_disabled($intf);
}
my $cmd = '';
if ( -e $intf_process_id_file) {
my $pid = `cat $intf_process_id_file`; chomp $pid;
$cmd = "kill $pid 2> /dev/null; rm -f $intf_process_id_file 2> /dev/null;";
}
$cmd .= "$dhcp_daemon -q -nw -cf $intf_config_file -pf $intf_process_id_file -lf $intf_leases_file $intf 2> /dev/null &";
# adding & at the end to make the process into a daemon immediately
system ($cmd) == 0
or warn "start $dhcp_daemon failed: $?\n";
}
sub stop_dhclient {
my ($intf, $op_mode) = @_;
# perform config mode actions if not called from op-mode
if (!defined $op_mode) {
return if is_intf_disabled($intf);
}
my ($intf_config_file, $intf_process_id_file, $intf_leases_file)
= generate_dhclient_intf_files($intf);
my $release_cmd = "$dhcp_daemon -q -cf $intf_config_file -pf $intf_process_id_file -lf $intf_leases_file -r $intf 2> /dev/null;";
$release_cmd .= "rm -f $intf_process_id_file 2> /dev/null";
system ($release_cmd) == 0
or warn "stop $dhcp_daemon failed: $?\n";
}
sub update_mac {
my ($mac, $intf) = @_;
open my $fh, "<", "/sys/class/net/$intf/flags"
or die "Error: $intf is not a network device\n";
my $flags = <$fh>;
chomp $flags;
close $fh or die "Error: can't read state\n";
if (POSIX::strtoul($flags) & 1) {
# NB: Perl 5 system return value is bass-ackwards
system "ip link set $intf down"
and die "Could not set $intf down ($!)\n";
system "ip link set $intf address $mac"
and die "Could not set $intf address ($!)\n";
system "ip link set $intf up"
and die "Could not set $intf up ($!)\n";
} else {
system "ip link set $intf address $mac"
and die "Could not set $intf address ($!)\n";
}
exit 0;
}
sub is_valid_mac {
my ($mac, $intf) = @_;
my @octets = split /:/, $mac;
($#octets == 5) or die "Error: wrong number of octets: $#octets\n";
((hex($octets[0]) & 1) == 0) or die "Error: $mac is a multicast address\n";
my $sum = 0;
$sum += hex( $_) foreach @octets;
( $sum != 0 ) or die "Error: zero is not a valid address\n";
exit 0;
}
# Validate the set of address values configured on an interface at commit
# Check that full set of address address values are consistent.
# 1. Interface may not be part of bridge or bonding group
# 2. Can not have both DHCP and a static IPv4 address.
sub is_valid_addr_commit {
my ($ifname, @addrs) = @_;
my $intf = new Vyatta::Interface($ifname);
$intf or die "Unknown interface name/type: $ifname\n";
my $config = new Vyatta::Config;
$config->setLevel($intf->path());
my $bridge = $config->returnValue("bridge-group bridge");
die "Can't configure address on interface that is port of bridge.\n"
if (defined($bridge));
my $bond = $config->returnValue("bond-group");
die "Can't configure address on interface that is slaved to bonding interface.\n"
if (defined($bond));
# Map of all the ip addresses
my %ipaddr_hash = map { $_ => 1 } getIP();
my ($dhcp, $static_v4);
foreach my $addr (@addrs) {
next if ($addr eq 'dhcpv6');
if ($addr eq 'dhcp') {
$dhcp = 1;
} elsif (!Vyatta::Interface::is_uniq_address($addr)) {
my $h = Vyatta::Misc::get_ipnet_intf_hash();
print "Error: duplicate address $addr on $h->{$addr}\n";
exit 1;
} elsif ( is_ipv4($addr) ) {
$static_v4 = 1;
}
}
die "Can't configure static IPv4 address and DHCP on the same interface.\n"
if ($static_v4 && $dhcp);
exit 0;
}
# Is interface currently in admin down state?
sub is_intf_down {
my $name = shift;
my $intf = new Vyatta::Interface($name);
return 1 unless $intf;
return ! $intf->up();
}
sub dhcp {
my ($request, $intf) = @_;
die "$intf is not using DHCP to get an IP address\n"
unless ($request eq 'start' || is_dhcp_enabled($intf));
die "$intf is disabled.\n"
if ($request ne 'stop' && is_intf_down($intf));
my $tmp_dhclient_dir = '/var/run/vyatta/dhclient/';
my $release_file = $tmp_dhclient_dir . 'dhclient_release_' . $intf;
if ($request eq "release") {
die "IP address for $intf has already been released.\n"
if (-e $release_file);
print "Releasing DHCP lease on $intf ...\n";
stop_dhclient($intf, 'op_mode');
mkdir ($tmp_dhclient_dir) if (! -d $tmp_dhclient_dir );
touch ($release_file);
} elsif ($request eq "renew") {
print "Renewing DHCP lease on $intf ...\n";
run_dhclient($intf, 'op_mode');
unlink ($release_file);
} elsif ($request eq "start") {
print "Starting DHCP client on $intf ...\n";
touch("/var/run/$intf");
run_dhclient($intf);
} elsif ($request eq "stop") {
print "Stopping DHCP client on $intf ...\n";
stop_dhclient($intf);
unlink("/var/run/dhclient_$intf\_lease");
unlink("/var/run/$intf");
unlink("/var/run/vyatta/dhclient/dhclient_release_$intf");
unlink("/var/run/dhclient_$intf\.conf");
} else {
die "Unknown DHCP request: $request\n";
}
exit 0;
}
sub is_valid_name {
my ($type, $name) = @_;
die "Missing --dev argument\n" unless $name;
my $intf = new Vyatta::Interface($name);
die "$name does not match any known interface name type\n"
unless $intf;
my $vif = $intf->vif();
die "$name is the name of VIF interface\n" ,
"Need to use \"interface ",$intf->physicalDevice()," vif $vif\"\n"
if $vif;
die "$name is a ", $intf->type(), " interface not an $type interface\n"
if ($type ne 'all' and $intf->type() ne $type);
die "$type interface $name does not exist on system\n"
unless grep { $name eq $_ } getInterfaces();
exit 0;
}
sub exists_name {
my $name = shift;
die "Missing --dev argument\n" unless $name;
warn "interface $name does not exist on system\n"
unless grep { $name eq $_ } getInterfaces();
exit 0;
}
# generate one line with all known interfaces (for allowed)
sub show_interfaces {
my $type = shift;
my @interfaces = getInterfaces();
my @match;
foreach my $name (@interfaces) {
my $intf = new Vyatta::Interface($name);
next unless $intf; # skip unknown types
next if $skip_interface{$name};
next unless ($type eq 'all' || $type eq $intf->type());
if ($vif_name) {
next unless $intf->vif();
push @match, $intf->vif()
if ($vif_name eq $intf->physicalDevice());
} else {
push @match, $name
unless $intf->vif() and $type ne 'all';
}
}
print join(' ', @match), "\n";
}
# Determine current values for autoneg, speed, duplex
sub get_ethtool {
my $dev = shift;
open( my $ethtool, '-|', "$ETHTOOL $dev 2>&1" )
or die "ethtool failed: $!\n";
# ethtool produces:
#
# Settings for eth1:
# Supported ports: [ TP ]
# ...
# Speed: 1000Mb/s
# Duplex: Full
# ...
# Auto-negotiation: on
my ($rate, $duplex);
my $autoneg = 0;
while (<$ethtool>) {
chomp;
return if ( /^Cannot get device settings/ );
if ( /^\s+Speed: (\d+)Mb/ ) {
$rate = $1;
} elsif ( /^\s+Duplex:\s(.*)$/ ) {
$duplex = lc $1;
} elsif ( /^\s+Auto-negotiation: on/ ) {
$autoneg = 1;
}
}
close $ethtool;
return ($autoneg, $rate, $duplex);
}
sub set_speed_duplex {
my ($intf, $nspeed, $nduplex) = @_;
die "Missing --dev argument\n" unless $intf;
# read old values to avoid meaningless speed changes
my ($autoneg, $ospeed, $oduplex) = get_ethtool($intf);
if (defined($autoneg) && $autoneg == 1) {
# Device is already in autonegotiation mode
return if ($nspeed eq 'auto');
} elsif (defined($ospeed) && defined($oduplex)) {
# Device has explicit speed/duplex but they already match
return if (($nspeed eq $ospeed) && ($nduplex eq $oduplex));
}
my $cmd = "$ETHTOOL -s $intf";
if ($nspeed eq 'auto') {
$cmd .= " autoneg on";
} else {
$cmd .= " speed $nspeed duplex $nduplex autoneg off";
}
exec $cmd;
die "exec of $ETHTOOL failed: $!";
}
# Check if speed and duplex value is supported by device
sub is_supported_speed {
my ($dev, $speed, $duplex) = @_;
my $wanted = sprintf("%dbase%s/%s", $speed,
($speed == 2500) ? 'X' : 'T', ucfirst($duplex));
open( my $ethtool, '-|', "$ETHTOOL $dev 2>/dev/null" )
or die "ethtool failed: $!\n";
# ethtool output:
#
# Settings for eth1:
# Supported ports: [ TP ]
# Supported link modes: 10baseT/Half 10baseT/Full
# 100baseT/Half 100baseT/Full
# 1000baseT/Half 1000baseT/Full
# Supports auto-negotiation: Yes
my $mode;
while (<$ethtool>) {
chomp;
if ($mode) {
last unless /^\t /;
} else {
next unless /^\tSupported link modes: /;
$mode = 1;
}
return 1 if /$wanted/;
}
close $ethtool;
return;
}
# Validate speed and duplex settings prior to commit
sub check_speed_duplex {
my ($dev, $speed, $duplex) = @_;
# most basic and default case
exit 0 if ($speed eq 'auto' && $duplex eq 'auto');
die "If speed is hardcoded, duplex must also be hardcoded\n"
if ($duplex eq 'auto');
die "If duplex is hardcoded, speed must also be hardcoded\n"
if ($speed eq 'auto');
die "Speed $speed, duplex $duplex not supported on $dev\n"
unless is_supported_speed($dev, $speed, $duplex);
exit 0;
}
# Produce list of valid speed values for device
sub allowed_speed {
my ($dev) = @_;
open( my $ethtool, '-|', "$ETHTOOL $dev 2>/dev/null" )
or die "ethtool failed: $!\n";
my %speeds;
my $first = 1;
while (<$ethtool>) {
chomp;
if ($first) {
next unless s/\tSupported link modes:\s//;
$first = 0;
} else {
last unless /^\t /;
}
foreach my $val (split / /) {
$speeds{$1} = 1 if $val =~ /(\d+)base/;
}
}
close $ethtool;
print 'auto ', join(' ', sort keys %speeds), "\n";
}
sub _restore_ipv6_addr {
my ($name, @addrs) = @_;
foreach my $addr (@addrs) {
next if ($addr eq 'dhcp');
next if ($addr eq 'dhcpv6');
my $version = is_ip_v4_or_v6($addr);
next unless $version;
next unless ($version == 6);
system("sudo ip -6 addr add $addr dev $name") == 0
or die "restoring $addr failed: $!\n";
}
}
# work around for loss of ipv6 addresses on admin done
sub restore_ipv6_addr {
my $name = shift;
my $config = new Vyatta::Config;
# No longer need to restore
return;
my $intf = new Vyatta::Interface($name);
die "$name does not match any known interface name type\n"
unless $intf;
my $path = $intf->path();
$config->setLevel($path);
my @addrs = $config->returnValues('address');
_restore_ipv6_addr($name, @addrs);
if ($config->exists('vif')) {
my @vifs = $config->listNodes('vif');
foreach my $vif (@vifs) {
$config->setLevel("$path vif $vif");
@addrs = $config->returnValues('address');
_restore_ipv6_addr("$name.$vif", @addrs);
}
}
}
sub check_non_switched {
my $i_intf = shift;
my $config = new Vyatta::Config;
$config->setLevel("interfaces switch switch0 switch-port");
my $intfs = [$config->returnValues("interface")];
foreach my $intf ( @{$intfs} ) {
exit 1 if ($intf eq $i_intf);
}
}
Non il s'agit d'une offre fibre grand public jet fibre