summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2010-11-08 13:35:07 -0800
committerStephen Hemminger <stephen.hemminger@vyatta.com>2010-11-08 13:58:17 -0800
commit1df58b23bac61caf78f28f549e180a3189986689 (patch)
tree55d43e25973a7373989b439e3dcc5e36602da63c
parent6285193ed1a9b4cf2b85ce6d4f44942663137c48 (diff)
downloadvyatta-cfg-system-1df58b23bac61caf78f28f549e180a3189986689.tar.gz
vyatta-cfg-system-1df58b23bac61caf78f28f549e180a3189986689.zip
Check speed and duplex settings on Ethernet interfaces
Bug 4994 Use ethtool to check for supported speed and duplex values on link.
-rwxr-xr-xscripts/vyatta-interfaces.pl92
-rw-r--r--templates/interfaces/ethernet/node.tag/duplex/node.def7
-rw-r--r--templates/interfaces/ethernet/node.tag/speed/node.def7
3 files changed, 98 insertions, 8 deletions
diff --git a/scripts/vyatta-interfaces.pl b/scripts/vyatta-interfaces.pl
index 2d91a5c0..c8d6f263 100755
--- a/scripts/vyatta-interfaces.pl
+++ b/scripts/vyatta-interfaces.pl
@@ -51,8 +51,8 @@ my $ETHTOOL = '/sbin/ethtool';
my ($eth_update, $eth_delete, $addr_set, $dev, $mac, $mac_update);
my %skip_interface;
my ($check_name, $show_names, $vif_name, $warn_name);
-my ($check_up, $dhcp_command);
-my (@speed_duplex, @addr_commit);
+my ($check_up, $dhcp_command, $allowed_speed);
+my (@speed_duplex, @addr_commit, @check_speed);
sub usage {
print <<EOF;
@@ -64,6 +64,8 @@ Usage: $0 --dev=<interface> --check=<type>
$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> --check-speed=speed,duplex
+ $0 --dev=<interface> --allowed-speed
$0 --dev=<interface> --isup
$0 --show=<type>
EOF
@@ -86,6 +88,8 @@ GetOptions("eth-addr-update=s" => \$eth_update,
"warn" => \$warn_name,
"isup" => \$check_up,
"speed-duplex=s{2}" => \@speed_duplex,
+ "check-speed=s{2}" => \@check_speed,
+ "allowed-speed" => \$allowed_speed,
) or usage();
update_eth_addrs($eth_update, $dev) if ($eth_update);
@@ -100,6 +104,8 @@ 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);
exit 0;
sub is_ip_configured {
@@ -621,3 +627,85 @@ sub set_speed_duplex {
$cmd .= " 2>/dev/null";
system ($cmd);
}
+
+# Check if speed and duplex value is supported by device
+sub is_supported_speed {
+ my ($dev, $speed, $duplex) = @_;
+
+ my $wanted = sprintf("%dbase%c/%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 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";
+}
diff --git a/templates/interfaces/ethernet/node.tag/duplex/node.def b/templates/interfaces/ethernet/node.tag/duplex/node.def
index 0351365f..023a8a08 100644
--- a/templates/interfaces/ethernet/node.tag/duplex/node.def
+++ b/templates/interfaces/ethernet/node.tag/duplex/node.def
@@ -4,9 +4,10 @@ default: "auto"
syntax:expression: $VAR(@) in "auto", "half", "full"; "duplex must be auto, half or full"
allowed: echo auto half full
-commit:expression: ( $VAR(@) == "auto" && $VAR(../speed/@) == "auto" ) || \
- ( $VAR(@) != "auto" && $VAR(../speed/@) != "auto" ) ; \
- "if duplex is hardcoded, speed must also be hardcoded"
+commit:expression: exec " \
+ /opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(../@) \
+ --check-speed $VAR(../speed/@) $VAR(@)"
+
update: /opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(../@) \
--speed-duplex $VAR(../speed/@) $VAR(@)
diff --git a/templates/interfaces/ethernet/node.tag/speed/node.def b/templates/interfaces/ethernet/node.tag/speed/node.def
index fbdc5893..fad248af 100644
--- a/templates/interfaces/ethernet/node.tag/speed/node.def
+++ b/templates/interfaces/ethernet/node.tag/speed/node.def
@@ -4,9 +4,10 @@ default: "auto"
syntax:expression: $VAR(@) in "auto", "10", "100", "1000", "2500", "10000"; "Speed must be auto, 10, 100, 1000, 2500, or 10000"
allowed: echo auto 10 100 1000 2500 10000
-commit:expression: ( $VAR(@) == "auto" && $VAR(../duplex/@) == "auto" ) || \
- ( $VAR(@) != "auto" && $VAR(../duplex/@) != "auto" ) ; \
- "if speed is hardcoded, duplex must also be hardcoded"
+commit:expression: exec "\
+ /opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(../@) \
+ --check-speed $VAR(@) $VAR(../duplex/@)"
+
update: /opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(../@) \
--speed-duplex $VAR(@) $VAR(../duplex/@)