diff --git a/Makefile.am b/Makefile.am index 66204496c..db1102e84 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,7 +14,6 @@ bin_SCRIPTS += scripts/restricted-shell sbin_SCRIPTS += scripts/vyatta-grub-setup sbin_SCRIPTS += scripts/snmp/if-mib-alias -sbin_SCRIPTS += scripts/vyatta-interfaces.pl sbin_SCRIPTS += scripts/install/install-get-partition sbin_SCRIPTS += scripts/install/install-functions sbin_SCRIPTS += scripts/install/install-image-new diff --git a/scripts/vyatta-interfaces.pl b/scripts/vyatta-interfaces.pl deleted file mode 100755 index 91e48d963..000000000 --- a/scripts/vyatta-interfaces.pl +++ /dev/null @@ -1,676 +0,0 @@ -#!/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 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); -my ($check_up, $dhcp_command, $allowed_speed); -my (@speed_duplex, @addr_commit, @check_speed, @offload_option); - -sub usage { - print < --check= - $0 --dev= --warn - $0 --dev= --valid-mac= - $0 --dev= --valid-addr-commit={addr1 addr2 ...} - $0 --dev= --speed-duplex=speed,duplex - $0 --dev= --check-speed=speed,duplex - $0 --dev= --allowed-speed - $0 --dev= --isup - $0 --dev= --offload-option={tcp-segmention,udp-fragmentation} {value} - $0 --dev= --offload-option={generic-segmentation,generic-receive} {value} - $0 --dev= --offload-option={scatter-gather} {value} - $0 --show= -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, - "offload-option=s{2}" => \@offload_option, -) 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); -set_offload_option($dev, @offload_option) if (@offload_option); -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 get_dhcp_client_id { - my $name = shift; - my $intf = new Vyatta::Interface($name); - my $config = new Vyatta::Config; - $config->setLevel($intf->path()); - return $config->returnValue("dhcp-options client-id"); -} - -sub get_dhcp_hostname { - my $name = shift; - my $intf = new Vyatta::Interface($name); - my $config = new Vyatta::Config; - $config->setLevel($intf->path()); - return $config->returnValue("dhcp-options host-name"); -} - -sub dhcp_update_config { - my ($conf_file, $intf) = @_; - - my $output = dhcp_conf_header(); - my $hostname = get_dhcp_hostname($intf); - if (!defined($hostname)) { - $hostname = get_hostname(); - } - - $output .= "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"; - - $output .= "interface \"$intf\" {\n"; - if (defined($hostname)) { - $output .= "\tsend host-name \"$hostname\";\n"; - } - - my $client_id = get_dhcp_client_id($intf); - if (defined($client_id)) { - $output .= "\tsend dhcp-client-identifier \"$client_id\";\n"; - } - - $output .= "\trequest subnet-mask, broadcast-address, routers, domain-name-servers, rfc3442-classless-static-routes"; - 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 .= "}\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 = "$dhcp_daemon -pf $intf_process_id_file -x $intf 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, $name) = @_; - my $intf = new Vyatta::Interface($name); - $intf or die "Unknown interface name/type: $name\n"; - - # maybe nothing needs to change - my $oldmac = $intf->hw_address(); - exit 0 if (lc($oldmac) eq lc($mac)); - - # try the direct approach - if (system("sudo ip link set $name address $mac") == 0) { - exit 0; - } elsif ($intf->up()) { - - # some hardware can not change MAC address if up - system "sudo ip link set $name down" - and die "Could not set $name down\n"; - system "sudo ip link set $name address $mac" - and die "Could not set $name address\n"; - system "sudo ip link set $name up" - and die "Could not set $name up\n"; - } else { - die "Could not set mac address for $name\n"; - } - - exit 0; -} - -sub is_vrrp_mac { - my @octets = @_; - return 1 if ( hex($octets[0]) == 0 - && hex($octets[1]) == 0 - && hex($octets[2]) == 94 - && hex($octets[3]) == 0 - && hex($octets[4]) == 1); - return 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"; - - is_vrrp_mac(@octets) and die "Error: $mac is a vrrp mac 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)); - - my $addrmap = Vyatta::Interface::get_cfg_addresses(); - - my ($dhcp, $static_v4); - foreach my $addr (@addrs) { - next if ($addr eq 'dhcpv6'); - - if ($addr eq 'dhcp') { - $dhcp = 1; - next; - } - - $static_v4 = 1 - if (is_ipv4($addr)); - } - - 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/lib/dhcp/$intf"); - run_dhclient($intf); - } elsif ($request eq "stop") { - print "Stopping DHCP client on $intf ...\n"; - stop_dhclient($intf); - unlink("/var/lib/dhcp/dhclient_$intf\_lease"); - unlink("/var/lib/dhcp/$intf"); - unlink("/var/run/vyatta/dhclient/dhclient_release_$intf"); - unlink("/var/lib/dhcp/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 ($intf->vrid()){ - push @match, $name; # add all vrrp interfaces - } elsif ($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) = (1000, "full"); - 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; - - $duplex = "full" if $duplex =~ /unknown.*/; - - return ($autoneg, $rate, $duplex); -} - -sub set_speed_duplex { - my ($intf, $nspeed, $nduplex) = @_; - die "Missing --dev argument\n" unless $intf; - - ## if driver virtio, speed and duplex are unknown per default coming fromthe driver itself - ## if that's the case we always run ethtool and set the values - - open(my $ethtool, '-|', "$ETHTOOL -i $dev 2>&1") - or die "ethtool failed: $!\n"; - my $drv = 0; - while (<$ethtool>) - { - chomp; - return if (/^Cannot get device driver settings/); - $drv = 1 if (/^driver:.*/); - last; - } - - if ($drv != 1) - { - # 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) = @_; - - open(my $if_drv, '-|', "$ETHTOOL -i $dev 2>/dev/null") - or die "ethtool -i failed: $!\n"; - - ### check if virtualized NIC - return 1 if <$if_drv> =~ /virtio_net/; - - 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 get_offload_option { - my ($dev, $option) = @_; - my $val; - my $ethtool_option; - - if ($option ne 'scatter-gather') { - $ethtool_option = "$option-offload"; - } else { - $ethtool_option = $option; - } - - open(my $ethtool, '-|', "$ETHTOOL -k $dev 2>&1") or die "ethtool failed: $!\n"; - while (<$ethtool>) { - next if ($_ !~ m/$ethtool_option:/); - chomp; - $val = (split(/: /, $_))[1]; - } - close $ethtool; - return $val; - -} - -sub set_offload_option { - my ($intf, $option, $nvalue) = @_; - die "Missing --dev argument\n" unless $intf; - - my $ovalue = get_offload_option($intf, $option); - - my %ethtool_opts = ( - 'generic-receive' => 'gro', - 'generic-segmentation' => 'gso', - 'tcp-segmentation' => 'tso', - 'udp-fragmentation' => 'ufo', - 'scatter-gather' => 'sg', - ); - - if (defined($nvalue) && $nvalue ne $ovalue) { - my $cmd = "$ETHTOOL -K $intf $ethtool_opts{$option} $nvalue"; - - system($cmd); - if ($? >> 8) { - die "Offload option for $option is not supported on $intf\n"; - } - } - -} -