summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2009-12-21 10:52:40 -0800
committerStephen Hemminger <stephen.hemminger@vyatta.com>2009-12-21 10:52:40 -0800
commitd234dbf62a065de2b799f9b57c1b476c07a6bc17 (patch)
tree276dcc9e0854cb549e1f42ae29b6ee518c823e48
parent7f58b680525bcf9a07f9f1e4c1a6fc4aa7815dae (diff)
downloadvyatta-cfg-system-d234dbf62a065de2b799f9b57c1b476c07a6bc17.tar.gz
vyatta-cfg-system-d234dbf62a065de2b799f9b57c1b476c07a6bc17.zip
Move interface support from vyatta-cfg to vyatta-cfg-system
All the other interface types are in vyatta-cfg-system, only loopback and ethernet were in vyatta-cfg
-rwxr-xr-xscripts/vyatta-interfaces.pl596
-rw-r--r--templates/interfaces/ethernet/node.def11
-rw-r--r--templates/interfaces/ethernet/node.tag/address/node.def28
-rw-r--r--templates/interfaces/ethernet/node.tag/description/node.def4
-rw-r--r--templates/interfaces/ethernet/node.tag/disable-flow-control/node.def4
-rw-r--r--templates/interfaces/ethernet/node.tag/disable-link-detect/node.def3
-rw-r--r--templates/interfaces/ethernet/node.tag/disable/node.def12
-rw-r--r--templates/interfaces/ethernet/node.tag/duplex/node.def13
-rw-r--r--templates/interfaces/ethernet/node.tag/hw-id/node.def2
-rw-r--r--templates/interfaces/ethernet/node.tag/mac/node.def8
-rw-r--r--templates/interfaces/ethernet/node.tag/mtu/node.def8
-rw-r--r--templates/interfaces/ethernet/node.tag/smp_affinity/node.def45
-rw-r--r--templates/interfaces/ethernet/node.tag/speed/node.def16
-rw-r--r--templates/interfaces/ethernet/node.tag/vif/node.def18
-rw-r--r--templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def27
-rw-r--r--templates/interfaces/ethernet/node.tag/vif/node.tag/description/node.def4
-rw-r--r--templates/interfaces/ethernet/node.tag/vif/node.tag/disable-link-detect/node.def3
-rw-r--r--templates/interfaces/ethernet/node.tag/vif/node.tag/disable/node.def11
-rw-r--r--templates/interfaces/loopback/node.def8
-rw-r--r--templates/interfaces/loopback/node.tag/address/node.def18
-rw-r--r--templates/interfaces/loopback/node.tag/description/node.def4
-rw-r--r--templates/interfaces/node.def2
-rw-r--r--tests/interface.pl52
-rw-r--r--tests/isip.pl23
24 files changed, 920 insertions, 0 deletions
diff --git a/scripts/vyatta-interfaces.pl b/scripts/vyatta-interfaces.pl
new file mode 100755
index 00000000..a496e66b
--- /dev/null
+++ b/scripts/vyatta-interfaces.pl
@@ -0,0 +1,596 @@
+#!/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::Interface;
+
+use Getopt::Long;
+use POSIX;
+use NetAddr::IP;
+use Fcntl;
+
+use strict;
+use warnings;
+
+my $dhcp_daemon = '/sbin/dhclient';
+
+my ($eth_update, $eth_delete, $addr_set, @addr_commit, $dev, $mac, $mac_update);
+my ($check_name, $show_names, $intf_cli_path, $vif_name, $warn_name);
+my ($check_up, $show_path, $dhcp_command);
+my @speed_duplex;
+
+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> --eth-addr-update=<aa:aa:aa:aa:aa:aa>
+ $0 --dev=<interface> --eth-addr-delete=<aa:aa:aa:aa:aa:aa>
+ $0 --dev=<interface> --valid-addr-set={<a.b.c.d>|dhcp}
+ $0 --dev=<interface> --valid-addr-commit={addr1 addr2 ...}
+ $0 --dev=<interface> --speed-duplex=speed,duplex
+ $0 --dev=<interface> --path
+ $0 --dev=<interface> --isup
+ $0 --show=<type>
+EOF
+ exit 1;
+}
+
+GetOptions("eth-addr-update=s" => \$eth_update,
+ "eth-addr-delete=s" => \$eth_delete,
+ "valid-addr=s" => \$addr_set,
+ "valid-addr-set=s" => \$addr_set,
+ "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,
+ "vif=s" => \$vif_name,
+ "warn" => \$warn_name,
+ "path" => \$show_path,
+ "isup" => \$check_up,
+ "speed-duplex=s{2}" => \@speed_duplex,
+) or usage();
+
+update_eth_addrs($eth_update, $dev) if ($eth_update);
+delete_eth_addrs($eth_delete, $dev) if ($eth_delete);
+is_valid_addr_set($addr_set, $dev) if ($addr_set);
+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);
+show_config_path($dev) if ($show_path);
+is_up($dev) if ($check_up);
+set_speed_duplex($dev, @speed_duplex) if (@speed_duplex);
+exit 0;
+
+sub is_ip_configured {
+ my ($intf, $ip) = @_;
+ my $found = grep { $_ eq $ip } Vyatta::Misc::getIP($intf);
+ return ($found > 0);
+}
+
+sub is_ip_duplicate {
+ my ($intf, $ip) = @_;
+
+ # get a map of all ipv4 and ipv6 addresses
+ my %ipaddrs_hash = map { $_ => 1 } getIP();
+
+ return unless($ipaddrs_hash{$ip});
+
+ # allow dup if it's the same interface
+ return !is_ip_configured($intf, $ip);
+}
+
+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 touch {
+ my $file = shift;
+ my $t = time;
+
+ sysopen (my $f, $file, O_RDWR|O_CREAT)
+ or die "Can't touch $file: $!";
+ close $f;
+ utime $t, $t, $file;
+}
+
+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 dhcp_update_config {
+ my ($conf_file, $intf) = @_;
+
+ my $output = dhcp_conf_header();
+ my $hostname = get_hostname();
+
+ $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 .= "}\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 = shift;
+
+ my ($intf_config_file, $intf_process_id_file, $intf_leases_file)
+ = generate_dhclient_intf_files($intf);
+ dhcp_update_config($intf_config_file, $intf);
+
+ return 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 = shift;
+
+ 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_eth_addrs {
+ my ($addr, $intf) = @_;
+
+ if ($addr eq "dhcp") {
+ touch("/var/lib/dhcp3/$intf");
+ run_dhclient($intf);
+ return;
+ }
+ my $version = is_ip_v4_or_v6($addr);
+ die "Unknown address not IPV4 or IPV6" unless $version;
+
+ if (is_ip_configured($intf, $addr)) {
+ #
+ # treat this as informational, don't fail
+ #
+ print "Address $addr already configured on $intf\n";
+ exit 0;
+ }
+
+ if ($version == 4) {
+ exec (qw(ip addr add),$addr,qw(broadcast + dev), $intf)
+ or die "ip addr command failed: $!";
+ }
+ if ($version == 6) {
+ exec (qw(ip -6 addr add), $addr, 'dev', $intf)
+ or die "ip addr command failed: $!";
+ }
+ die "Error: Invalid address/prefix [$addr] for interface $intf\n";
+}
+
+sub delete_eth_addrs {
+ my ($addr, $intf) = @_;
+
+ if ($addr eq "dhcp") {
+ stop_dhclient($intf);
+ unlink("/var/lib/dhcp3/dhclient_$intf\_lease");
+ unlink("/var/lib/dhcp3/$intf");
+ unlink("/var/run/vyatta/dhclient/dhclient_release_$intf");
+ unlink("/var/lib/dhcp3/dhclient_$intf\.conf");
+ exit 0;
+ }
+ my $version = is_ip_v4_or_v6($addr);
+ if ($version == 6) {
+ exec 'ip', '-6', 'addr', 'del', $addr, 'dev', $intf
+ or die "Could not exec ip?";
+ }
+
+ ($version == 4) or die "Bad ip version";
+
+ if (is_ip_configured($intf, $addr)) {
+ # Link is up, so just delete address
+ # Zebra is watching for netlink events and will handle it
+ exec 'ip', 'addr', 'del', $addr, 'dev', $intf
+ or die "Could not exec ip?";
+ }
+
+ exit 0;
+}
+
+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 "sudo ip link set $intf down"
+ and die "Could not set $intf down ($!)\n";
+ system "sudo ip link set $intf address $mac"
+ and die "Could not set $intf address ($!)\n";
+ system "sudo ip link set $intf up"
+ and die "Could not set $intf up ($!)\n";
+ } else {
+ system "sudo 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";
+
+ (($octets[0] & 1) == 0) or die "Error: $mac is a multicast address\n";
+
+ my $sum = 0;
+ $sum += strtoul('0x' . $_) foreach @octets;
+ ( $sum != 0 ) or die "Error: zero is not a valid address\n";
+
+ exit 0;
+}
+
+# Validate an address parameter at the time the user enters it via
+# a "set" command. This validates the parameter for syntax only.
+# It does not validate it in combination with other parameters.
+# Valid values are: "dhcp", <ipv4-address>/<prefix-len>, or
+# <ipv6-address>/<prefix-len>
+#
+sub is_valid_addr_set {
+ my ($addr_net, $intf) = @_;
+
+ if ($addr_net eq "dhcp") {
+ if ($intf eq "lo") {
+ print "Error: can't use dhcp client on loopback interface\n";
+ exit 1;
+ }
+ exit 0;
+ }
+
+ my ($addr, $net);
+ if ($addr_net =~ m/^([0-9a-fA-F\.\:]+)\/(\d+)$/) {
+ $addr = $1;
+ $net = $2;
+ } else {
+ exit 1;
+ }
+
+ my $version = is_ip_v4_or_v6($addr_net);
+ if (!defined $version) {
+ exit 1;
+ }
+
+ my $ip = NetAddr::IP->new($addr_net);
+ my $network = $ip->network();
+ my $bcast = $ip->broadcast();
+
+ if ($ip->version == 4 and $ip->masklen() == 31) {
+ #
+ # RFC3021 allows for /31 to treat both address as host addresses
+ #
+ } elsif ($ip->masklen() != $ip->bits()) {
+ #
+ # allow /32 for ivp4 and /128 for ipv6
+ #
+ if ($ip->addr() eq $network->addr()) {
+ print "Can not assign network address as the IP address\n";
+ exit 1;
+ }
+ if ($ip->addr() eq $bcast->addr()) {
+ print "Can not assign broadcast address as the IP address\n";
+ exit 1;
+ }
+ }
+
+ if (is_ip_duplicate($intf, $addr_net)) {
+ print "Error: duplicate address/prefix [$addr_net]\n";
+ exit 1;
+ }
+
+ if ($version == 4) {
+ if ($net > 0 && $net <= 32) {
+ exit 0;
+ }
+ }
+ if ($version == 6) {
+ if ($net > 1 && $net <= 128) {
+ exit 0;
+ }
+ }
+
+ exit 1;
+}
+
+# Validate the set of address values configured on an interface at commit
+# time. Syntax of address values is checked at set time, so is not
+# checked here. Instead, we check that full set of address address
+# values are consistent. The only rule that we enforce here is that
+# one may not configure an interface with both a DHCP address and a static
+# IPv4 address.
+#
+sub is_valid_addr_commit {
+ my ($intf, @addrs) = @_;
+
+ my $static_v4 = 0;
+ my $dhcp = 0;
+
+ foreach my $addr (@addrs) {
+ if ($addr eq "dhcp") {
+ $dhcp = 1;
+ } else {
+ my $version = is_ip_v4_or_v6($addr);
+ if ($version == 4) {
+ $static_v4 = 1;
+ }
+ }
+ }
+
+ if ($static_v4 == 1 && $dhcp == 1) {
+ printf("Error configuring interface $intf: Can't configure static\n");
+ printf("IPv4 address and DHCP on the same interface.\n");
+ exit 1;
+ }
+
+ 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 is_dhcp_enabled($intf);
+
+ die "$intf is disabled. Unable to release/renew lease\n"
+ if 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);
+ 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);
+ unlink ($release_file);
+ } 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;
+ 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 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";
+}
+
+sub show_config_path {
+ my $name = shift;
+ 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 $level = $intf->path();
+ $level =~ s/ /\//g;
+ print "/opt/vyatta/config/active/$level\n";
+}
+
+sub get_ethtool {
+ my $dev = shift;
+
+ open( my $ethtool, "sudo /usr/sbin/ethtool $dev 2>/dev/null |" )
+ or die "ethtool failed: $!\n";
+
+ # ethtool produces:
+ #
+ # Settings for eth1:
+ # Supported ports: [ TP ]
+ # ...
+ # Speed: 1000Mb/s
+ # Duplex: Full
+ # ...
+ # Auto-negotiation: on
+ my ($rate, $duplex, $autoneg);
+ while (<$ethtool>) {
+ chomp;
+ if ( /^\s+Speed:\s([0-9]+)Mb\/s/ ) {
+ $rate = $1;
+ } elsif ( /^\s+Duplex:\s(.*)$/ ) {
+ $duplex = lc $1;
+ } elsif ( /^\s+Auto-negotiation: on/ ) {
+ $autoneg = 1;
+ }
+ }
+ close $ethtool;
+ return ($rate, $duplex, $autoneg);
+}
+
+sub set_speed_duplex {
+ my ($intf, $nspeed, $nduplex) = @_;
+ die "Missing --dev argument\n" unless $intf;
+
+ my ($ospeed, $oduplex, $autoneg) = get_ethtool($intf);
+
+ # Don't change settings if already okay.
+ if ($autoneg) {
+ return if ($nspeed eq 'auto');
+ } else {
+ return if (defined $ospeed && defined $oduplex &&
+ $nspeed eq $ospeed && $nduplex eq $oduplex);
+ }
+
+ my @cmd = ('sudo', 'ethtool', '-s', $intf );
+ if ($nspeed eq 'auto') {
+ push @cmd, qw(autoneg on);
+ } else {
+ push @cmd, 'speed', $nspeed, 'duplex', $nduplex, 'autoneg', 'off';
+ }
+ exec @cmd;
+
+ die "Command failed: ", join(' ', @cmd);
+}
diff --git a/templates/interfaces/ethernet/node.def b/templates/interfaces/ethernet/node.def
new file mode 100644
index 00000000..a46ae722
--- /dev/null
+++ b/templates/interfaces/ethernet/node.def
@@ -0,0 +1,11 @@
+tag:
+priority: 318
+type: txt
+help: Set ethernet interface
+syntax:expression: exec \
+ "/opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(@) --check=ethernet"
+allowed: /opt/vyatta/sbin/vyatta-interfaces.pl --show=ethernet
+create: sudo ip link set "$VAR(@)" up
+ /opt/vyatta/sbin/vyatta-link-detect $VAR(@) on
+delete: [ -d /sys/class/net/$VAR(../@) ] || exit 0
+ sudo ip link set $VAR(@) down
diff --git a/templates/interfaces/ethernet/node.tag/address/node.def b/templates/interfaces/ethernet/node.tag/address/node.def
new file mode 100644
index 00000000..db87ff05
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/address/node.def
@@ -0,0 +1,28 @@
+multi:
+
+type: txt
+
+help: Set an IP address for this interface
+
+# Syntax check at "set" time. Give curent address value to script
+# so that it can perform syntax check.
+#
+syntax:expression: exec "/opt/vyatta/sbin/vyatta-interfaces.pl --valid-addr-set $VAR(@) --dev $VAR(../@)"\
+ ; "Invalid IP address/prefix [$VAR(@)] for interface $VAR(../@)"
+
+# Syntax check at "commit" time. Pass all address values to script so that
+# it can perform consistency check.
+#
+commit:expression: exec "/opt/vyatta/sbin/vyatta-interfaces.pl --valid-addr-commit $VAR(@@) --dev $VAR(../@)"
+
+create:sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-update $VAR(@) --dev $VAR(../@)
+
+delete:sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-delete $VAR(@) --dev $VAR(../@)
+
+allowed: echo "dhcp <>"
+
+comp_help:Possible completions:
+ <x.x.x.x/x> Set the IP address and prefix length
+ <h:h:h:h:h:h:h:h/x> Set the IPv6 address and prefix length
+ dhcp Set the IP address and prefix length via DHCP
+
diff --git a/templates/interfaces/ethernet/node.tag/description/node.def b/templates/interfaces/ethernet/node.tag/description/node.def
new file mode 100644
index 00000000..7f64c788
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/description/node.def
@@ -0,0 +1,4 @@
+type: txt
+help: Set description for this interface
+update: sudo sh -c "echo \"$VAR(@)\" >/sys/class/net/$VAR(../@)/ifalias"
+delete: sudo sh -c "echo '' >/sys/class/net/$VAR(../@)/ifalias"
diff --git a/templates/interfaces/ethernet/node.tag/disable-flow-control/node.def b/templates/interfaces/ethernet/node.tag/disable-flow-control/node.def
new file mode 100644
index 00000000..10c6c066
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/disable-flow-control/node.def
@@ -0,0 +1,4 @@
+help: Set to disable Ethernet flow control (pause frames)
+create: sudo ethtool --pause $VAR(../@) autoneg off tx off rx off
+delete: [ -d /sys/class/net/$VAR(../@) ] || exit 0
+ sudo ethtool --pause $VAR(../@) autoneg on tx on rx on
diff --git a/templates/interfaces/ethernet/node.tag/disable-link-detect/node.def b/templates/interfaces/ethernet/node.tag/disable-link-detect/node.def
new file mode 100644
index 00000000..83858ec1
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/disable-link-detect/node.def
@@ -0,0 +1,3 @@
+help: Set to ignore link state changes on this interface
+update:/opt/vyatta/sbin/vyatta-link-detect $VAR(../@) on
+delete:/opt/vyatta/sbin/vyatta-link-detect $VAR(../@) off
diff --git a/templates/interfaces/ethernet/node.tag/disable/node.def b/templates/interfaces/ethernet/node.tag/disable/node.def
new file mode 100644
index 00000000..fbfb155a
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/disable/node.def
@@ -0,0 +1,12 @@
+help: Set interface disabled
+create: /etc/netplug/linkdown.d/dhclient $VAR(../@)
+ if ! sudo ip link set $VAR(../@) down 2>/dev/null; then
+ echo "Error disabling dev $VAR(../@)"
+ /etc/netplug/linkup.d/dhclient $VAR(../@)
+ exit 1
+ fi
+delete: [ -d /sys/class/net/$VAR(../@) ] || exit 0
+ if ! sudo ip link set $VAR(../@) up; then
+ echo "Error enabling dev $VAR(../@)"
+ exit 1
+ fi
diff --git a/templates/interfaces/ethernet/node.tag/duplex/node.def b/templates/interfaces/ethernet/node.tag/duplex/node.def
new file mode 100644
index 00000000..9277729d
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/duplex/node.def
@@ -0,0 +1,13 @@
+type: txt
+help: Set the duplex mode for this interface
+default: "auto"
+syntax:expression: $VAR(@) in "auto", "half", "full"; "duplex must be auto, half or full"
+commit:expression: ( $VAR(@) == "auto" && $VAR(../speed/@) == "auto" ) || \
+ ( $VAR(@) != "auto" && $VAR(../speed/@) != "auto" ) ; \
+ "if duplex is hardcoded, speed must also be hardcoded"
+update: /opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(../@) \
+ --speed-duplex $VAR(../speed/@) $VAR(@)
+comp_help:Possible completions:
+ auto\t\tAuto negotiation (default)
+ half\t\tHalf duplex
+ full\t\tFull duplex
diff --git a/templates/interfaces/ethernet/node.tag/hw-id/node.def b/templates/interfaces/ethernet/node.tag/hw-id/node.def
new file mode 100644
index 00000000..6c559f89
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/hw-id/node.def
@@ -0,0 +1,2 @@
+type: macaddr
+help: Set the Media Access Control (MAC) address of this interface
diff --git a/templates/interfaces/ethernet/node.tag/mac/node.def b/templates/interfaces/ethernet/node.tag/mac/node.def
new file mode 100644
index 00000000..55264cf7
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/mac/node.def
@@ -0,0 +1,8 @@
+type: macaddr
+help: Set the Media Access Control (MAC) address of this interface
+syntax:expression: exec "\
+ /opt/vyatta/sbin/vyatta-interfaces.pl --dev $VAR(../@) --valid-mac $VAR(@)"
+update: /opt/vyatta/sbin/vyatta-interfaces.pl --dev $VAR(../@) --set-mac $VAR(@)
+delete: [ -d /sys/class/net/$VAR(../@) ] || exit 0
+ /opt/vyatta/sbin/vyatta-interfaces.pl --dev $VAR(../@) --set-mac $VAR(../hw-id/@)
+
diff --git a/templates/interfaces/ethernet/node.tag/mtu/node.def b/templates/interfaces/ethernet/node.tag/mtu/node.def
new file mode 100644
index 00000000..dc03ae16
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/mtu/node.def
@@ -0,0 +1,8 @@
+type: u32
+help: Set the Maximum Transmission Unit (MTU) for this interface
+syntax:expression: $VAR(@) >= 68 && $VAR(@) <= 9000; "MTU must be between 68 and 9000"
+update: if ! sudo ip link set $VAR(../@) mtu $VAR(@)
+ then echo "Error setting MTU on dev $VAR(../@)"; exit 1
+ fi
+delete: [ -d /sys/class/net/$VAR(../@) ] || exit 0
+ sudo ip link set $VAR(../@) mtu 1500
diff --git a/templates/interfaces/ethernet/node.tag/smp_affinity/node.def b/templates/interfaces/ethernet/node.tag/smp_affinity/node.def
new file mode 100644
index 00000000..a444ae92
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/smp_affinity/node.def
@@ -0,0 +1,45 @@
+#
+#
+# Configuration template for interface.ethernet.name.smp_affinity
+#
+# Configure the CPUs that the associated interface will interrupt.
+# SMP affinity is configured by a hexidecimal bitmask that specifies the
+# CPUs that the system can interrupt. The SMP affinity bitmask must contain
+# at least one bits, and may only contain as many bits as there are CPUs on
+# the system.
+#
+
+type: txt
+
+help: Set CPU interrupt affinity mask for this interface
+
+comp_help: Possible completions:
+ XX\tHexidecimal bitmask representing CPUs that this NIC will interrupt
+ auto\tSet affinity automatically
+
+default: "auto"
+
+syntax:expression: exec " \
+ if [ $VAR(@) = auto ]; then \
+ exit 0;
+ else \
+ /opt/vyatta/sbin/vyatta-irqaffin check $VAR(../@) $VAR(@); \
+ fi"
+
+update:
+ if [ "$VAR(@)" = "auto" ]; then
+ echo "Setting SMP affinity for $VAR(../@) automatically."
+ sudo /opt/vyatta/sbin/vyatta-auto-irqaffin.pl --setup $VAR(../@)
+ else
+ sudo /opt/vyatta/sbin/vyatta-irqaffin set $VAR(../@) $VAR(@)
+ if [ $? -ne 0 ]; then
+ echo "Error setting CPU affinity mask $VAR(@) on interface $VAR(../@)"
+ exit 1
+ fi
+ fi
+
+delete: [ -d /sys/class/net/$VAR(../@) ] || exit 0
+ if ! sudo /opt/vyatta/sbin/vyatta-irqaffin reset $VAR(../@); then
+ echo "Error deleting CPU affinity mask on interface $VAR(../@)"
+ exit 1
+ fi
diff --git a/templates/interfaces/ethernet/node.tag/speed/node.def b/templates/interfaces/ethernet/node.tag/speed/node.def
new file mode 100644
index 00000000..e822df9f
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/speed/node.def
@@ -0,0 +1,16 @@
+type: txt
+help: Set the speed for this interface
+default: "auto"
+syntax:expression: $VAR(@) in "auto", "10", "100", "1000", "2500", "10000"; "Speed must be auto, 10, 100, 1000, 2500, or 10000"
+commit:expression: ( $VAR(@) == "auto" && $VAR(../duplex/@) == "auto" ) || \
+ ( $VAR(@) != "auto" && $VAR(../duplex/@) != "auto" ) ; \
+ "if speed is hardcoded, duplex must also be hardcoded"
+update: /opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(../@) \
+ --speed-duplex $VAR(@) $VAR(../duplex/@)
+comp_help:Possible completions:
+ auto\t\tAuto negotiation (default)
+ 10 \t\t10 Mbit/sec
+ 100 \t\t100 Mbit/sec
+ 1000\t\t1 Gbit/sec
+ 2500\t\t2.5 Gbit/sec
+ 10000\t10 Gbit/sec
diff --git a/templates/interfaces/ethernet/node.tag/vif/node.def b/templates/interfaces/ethernet/node.tag/vif/node.def
new file mode 100644
index 00000000..610c0e5e
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/vif/node.def
@@ -0,0 +1,18 @@
+tag:
+priority: 319
+type: u32
+help: Set Virtual Local Area Network (VLAN) ID
+syntax:expression: $VAR(@) >= 0 && $VAR(@) <= 4094; "VLAN ID must be between 0 and 4094"
+create: if ! sudo ip link add link $VAR(../@) name "$VAR(../@).$VAR(@)" type vlan id $VAR(@)
+ then echo "Error creating VLAN device $VAR(../@).$VAR(@)"
+ exit 1
+ fi
+ if /opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(../@) --isup
+ then
+ sudo ip link set "$VAR(../@).$VAR(@)" up
+ fi
+ /opt/vyatta/sbin/vyatta-link-detect "$VAR(../@).$VAR(@)" on
+delete: [ -d /sys/class/net/$VAR(../@) ] || exit 0
+ sudo ip link delete dev "$VAR(../@).$VAR(@)" type vlan id $VAR(@)
+comp_help: possible completions:
+ <0-4094> Set VLAN ID
diff --git a/templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def b/templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def
new file mode 100644
index 00000000..a5edef6d
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def
@@ -0,0 +1,27 @@
+multi:
+
+type: txt
+
+help: Set an IP address for this interface
+
+# Syntax check at "set" time. Give curent address value to script
+# so that it can perform syntax check.
+#
+syntax:expression: exec "/opt/vyatta/sbin/vyatta-interfaces.pl --valid-addr-set $VAR(@) --dev $VAR(../../@).$VAR(../@) "\
+ ; "Invalid IP address/prefix [$VAR(@)] for interface $VAR(../../@).$VAR(../@)"
+
+# Syntax check at "commit" time. Pass all address values to script so that
+# it can perform consistency check.
+#
+commit:expression: exec "/opt/vyatta/sbin/vyatta-interfaces.pl --valid-addr-commit $VAR(@@) --dev $VAR(../../@).$VAR(../@)"
+
+create:sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-update $VAR(@) --dev $VAR(../../@).$VAR(../@)
+
+delete:sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-delete $VAR(@) --dev $VAR(../../@).$VAR(../@)
+
+allowed: echo "dhcp <>"
+
+comp_help:Possible completions:
+ <x.x.x.x/x> Set the IP address and prefix length
+ <h:h:h:h:h:h:h:h/x> Set the IPv6 address and prefix length
+ dhcp Set the IP address and prefix length via DHCP
diff --git a/templates/interfaces/ethernet/node.tag/vif/node.tag/description/node.def b/templates/interfaces/ethernet/node.tag/vif/node.tag/description/node.def
new file mode 100644
index 00000000..0ef54891
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/vif/node.tag/description/node.def
@@ -0,0 +1,4 @@
+type: txt
+help: Set description for this interface
+update: sudo sh -c "echo \"$VAR(@)\" >/sys/class/net/$VAR(../../@).$VAR(../@)/ifalias"
+delete: sudo sh -c "echo '' >/sys/class/net/$VAR(../../@).$VAR(../@)/ifalias"
diff --git a/templates/interfaces/ethernet/node.tag/vif/node.tag/disable-link-detect/node.def b/templates/interfaces/ethernet/node.tag/vif/node.tag/disable-link-detect/node.def
new file mode 100644
index 00000000..897113de
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/vif/node.tag/disable-link-detect/node.def
@@ -0,0 +1,3 @@
+help: Set to ignore link state changes on this interface
+update:/opt/vyatta/sbin/vyatta-link-detect $VAR(../../@).$VAR(../@) on
+delete:/opt/vyatta/sbin/vyatta-link-detect $VAR(../../@).$VAR(../@) off
diff --git a/templates/interfaces/ethernet/node.tag/vif/node.tag/disable/node.def b/templates/interfaces/ethernet/node.tag/vif/node.tag/disable/node.def
new file mode 100644
index 00000000..78b24870
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/vif/node.tag/disable/node.def
@@ -0,0 +1,11 @@
+help: Set interface disabled
+update: /etc/netplug/linkdown.d/dhclient $VAR(../../@).$VAR(../@)
+ if ! sudo ip link set $VAR(../../@).$VAR(../@) down 2>/dev/null; then
+ echo "Error disabling dev $VAR(../../@).$VAR(../@)"
+ /etc/netplug/linkup.d/dhclient $VAR(../../@).$VAR(../@)
+ exit 1
+ fi
+delete: if ! sudo ip link set $VAR(../../@).$VAR(../@) up; then
+ echo "Error enabling dev $VAR(../../@).$VAR(../@)"
+ exit 1
+ fi
diff --git a/templates/interfaces/loopback/node.def b/templates/interfaces/loopback/node.def
new file mode 100644
index 00000000..64485e54
--- /dev/null
+++ b/templates/interfaces/loopback/node.def
@@ -0,0 +1,8 @@
+tag:
+priority: 320
+type: txt
+help: Set loopback interface
+syntax:expression: exec \
+ "/opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(@) --check=loopback"
+allowed: /opt/vyatta/sbin/vyatta-interfaces.pl --show=loopback
+create: sudo ip link set $VAR(@) up
diff --git a/templates/interfaces/loopback/node.tag/address/node.def b/templates/interfaces/loopback/node.tag/address/node.def
new file mode 100644
index 00000000..76c2e76e
--- /dev/null
+++ b/templates/interfaces/loopback/node.tag/address/node.def
@@ -0,0 +1,18 @@
+multi:
+
+type: txt
+
+help: Set an IP address for this interface
+
+syntax:expression: exec "/opt/vyatta/sbin/vyatta-interfaces.pl --valid-addr-set $VAR(@) --dev $VAR(../@)"; \
+ "Invalid IP address/prefix [$VAR(@)] for interface $VAR(../@)"
+
+create:expression: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-update $VAR(@) --dev $VAR(../@)"; \
+ "Error setting address $VAR(@) on interface $VAR(../@)"
+
+delete:expression: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-delete $VAR(@) --dev $VAR(../@)"; \
+ "Error deleting address $VAR(@) on interface $VAR(../@)"
+
+comp_help:Possible completions:
+ <x.x.x.x/x> Set the IP address and prefix length
+ <h:h:h:h:h:h:h:h/x> Set the IPv6 address and prefix length
diff --git a/templates/interfaces/loopback/node.tag/description/node.def b/templates/interfaces/loopback/node.tag/description/node.def
new file mode 100644
index 00000000..7f64c788
--- /dev/null
+++ b/templates/interfaces/loopback/node.tag/description/node.def
@@ -0,0 +1,4 @@
+type: txt
+help: Set description for this interface
+update: sudo sh -c "echo \"$VAR(@)\" >/sys/class/net/$VAR(../@)/ifalias"
+delete: sudo sh -c "echo '' >/sys/class/net/$VAR(../@)/ifalias"
diff --git a/templates/interfaces/node.def b/templates/interfaces/node.def
new file mode 100644
index 00000000..286b8786
--- /dev/null
+++ b/templates/interfaces/node.def
@@ -0,0 +1,2 @@
+priority: 850
+help: Configure network interfaces
diff --git a/tests/interface.pl b/tests/interface.pl
new file mode 100644
index 00000000..9ebeb60b
--- /dev/null
+++ b/tests/interface.pl
@@ -0,0 +1,52 @@
+#! /usr/bin/perl
+
+# Standalone test for Vyatta::Interface, not intended to be used
+# directly
+
+
+use strict;
+use warnings;
+use Vyatta::Interface;
+use Vyatta::Misc;
+
+my @interfaces = getInterfaces();
+print "Interfaces: ", join(' ',@interfaces),"\n";
+
+print "IP\n";
+foreach my $type (qw/all broadcast multicast pointtopoint loopback/) {
+ print "\t$type = ";
+ foreach my $addr (Vyatta::Misc::getInterfacesIPadresses($type)) {
+ print $addr, '(', is_ip_v4_or_v6($addr), ') ';
+ }
+ print "\n";
+}
+
+
+foreach my $arg (@interfaces) {
+ print "$arg : ";
+ my $intf = new Vyatta::Interface($arg);
+
+ if (! $intf) {
+ print "undefined\n";
+ next;
+ }
+
+ my $vif = $intf->vif();
+ print "vif=$vif " if $vif;
+ printf "path = '%s'\ndevice=%s\n", $intf->path(), $intf->physicalDevice();
+
+ my @addresses = $intf->address();
+ if ($#addresses eq -1) {
+ print "address is no set\n";
+ } else {
+ print "address ", join(' ',@addresses), "\n";
+ }
+
+ foreach my $attr (qw(exists configured disabled using_dhcp flags up running)) {
+ my $val = $intf->$attr();
+ print " $attr=$val" if ($val);
+ }
+ print "\n";
+}
+
+exit 0;
diff --git a/tests/isip.pl b/tests/isip.pl
new file mode 100644
index 00000000..35a04b7a
--- /dev/null
+++ b/tests/isip.pl
@@ -0,0 +1,23 @@
+#! /usr/bin/perl
+
+# Standalone test for Vyatta::Misc::isIPInterfaces
+
+use strict;
+use warnings;
+use Vyatta::Misc;
+use Vyatta::Interface;
+
+my $vc;
+my @interfaces = getInterfaces();
+print "Interfaces: ", join(' ',@interfaces),"\n";
+
+foreach my $lip (@ARGV) {
+ print $lip, " is";
+ if (Vyatta::Misc::isIPinInterfaces($vc, $lip, @interfaces)) {
+ print " in\n";
+ } else {
+ print " not in\n";
+ }
+}
+
+exit 0;