summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/vyatta-bonding.pl123
1 files changed, 106 insertions, 17 deletions
diff --git a/scripts/vyatta-bonding.pl b/scripts/vyatta-bonding.pl
index a0bdbd6e..66417f9f 100755
--- a/scripts/vyatta-bonding.pl
+++ b/scripts/vyatta-bonding.pl
@@ -46,45 +46,134 @@ my %modes = (
);
sub set_mode {
- my ($intf, $mode) = @_;
+ my ( $intf, $mode ) = @_;
my $val = $modes{$mode};
die "Unknown bonding mode $mode\n" unless defined($val);
open my $fm, '>', "/sys/class/net/$intf/bonding/mode"
- or die "Error: $intf is not a bonding device:$!\n";
+ or die "Error: $intf is not a bonding device:$!\n";
print {$fm} $val, "\n";
close $fm
- or die "Error: $intf can not set mode $val:$!\n";
+ or die "Error: $intf can not set mode $val:$!\n";
}
+sub get_slaves {
+ my $intf = shift;
+
+ open my $f, '<', "/sys/class/net/$intf/bonding/slaves"
+ or die "$intf is not a bonding interface";
+ my $slaves = <$f>;
+ close $f;
+ return unless $slaves;
+
+ chomp $slaves;
+ return split( ' ', $slaves );
+}
+
+sub add_slave {
+ my ( $intf, $slave ) = @_;
+
+ open my $f, '>', "/sys/class/net/$intf/bonding/slaves"
+ or die "$intf is not a bonding interface";
+
+ print {$f} "+$slave\n";
+ close $f;
+}
+
+sub remove_slave {
+ my ( $intf, $slave ) = @_;
+
+ open my $f, '>', "/sys/class/net/$intf/bonding/slaves"
+ or die "$intf is not a bonding interface";
+
+ print {$f} "-$slave\n";
+ close $f;
+}
+
+# Go dumpster diving to figure out which ethernet interface (if any)
+# gave it's address to be used by all bonding devices.
+sub primary_slave {
+ my ( $intf, $bond_addr ) = @_;
+
+ open my $p, '<', "/proc/net/bonding/$intf"
+ or die "Can't open /proc/net/bonding/$intf : $!";
+
+ my ( $dev, $match );
+ while ( my $line = <$p> ) {
+ chomp $line;
+ if ( $line =~ m/^Slave Interface: (.*)$/ ) {
+ $dev = $1;
+ }
+ elsif ( $line =~ m/^Permanent HW addr: (.*)$/ ) {
+ if ( $1 eq $bond_addr ) {
+ $match = $dev;
+ last;
+ }
+ }
+ }
+ close $p;
+
+ return $match;
+}
+
+sub if_down {
+ my $intf = shift;
+ system "ip link set dev $intf down"
+ and die "Could not set $intf up ($!)\n";
+}
+
+sub if_up {
+ my $intf = shift;
+ system "ip link set dev $intf up"
+ and die "Could not set $intf up ($!)\n";
+}
sub change_mode {
- my ($intf, $mode) = @_;
+ my ( $intf, $mode ) = @_;
my $interface = new Vyatta::Interface($intf);
-
die "$intf is not a valid interface" unless $interface;
- if ($interface->up()) {
- system "sudo ip link set $intf down"
- and die "Could not set $intf down ($!)\n";
+ my $primary = primary_slave( $intf, $interface->hw_address() );
+
+ my @slaves = get_slaves($intf);
+ foreach my $slave (@slaves) {
+ if_down($slave);
+ remove_slave( $intf, $slave ) unless ( $primary && $slave eq $primary );
+ }
+ if ($primary) {
+ if_down($primary);
+ remove_slave( $intf, $primary );
+ }
- set_mode($intf, $mode);
+ my $bond_up = $interface->up();
+ if_down($intf) if $bond_up;
+ set_mode( $intf, $mode );
+ if_up($intf) if $bond_up;
- system "sudo ip link set $intf up"
- and die "Could not set $intf up ($!)\n";
- } else {
- set_mode($intf, $mode);
+ foreach my $slave ( @slaves ) {
+ add_slave( $intf, $slave );
}
}
sub usage {
- print "Usage: $0 --set-mode=s{2}\n";
+ print "Usage: $0 --dev=bondX --mode={mode}\n";
+ print " $0 --dev=bondX --add-port=ethX\n";
+ print " $0 --dev=bondX --remove-port=ethX\n";
+ print print "modes := ", join( ',', sort( keys %modes ) ), "\n";
+
exit 1;
}
-my @mode_change;
+my ( $dev, $mode, $add_port, $rem_port );
GetOptions(
- 'set-mode=s{2}' => \@mode_change,
+ 'dev=s' => \$dev,
+ 'mode=s' => \$mode,
+ 'add=s' => \$add_port,
+ 'remove=s' => \$rem_port,
) or usage();
-change_mode( @mode_change ) if @mode_change;
+die "$0: device not specified\n" unless $dev;
+
+change_mode( $dev, $mode ) if $mode;
+add_slave( $dev, $add_port ) if $add_port;
+remove_slave( $dev, $rem_port ) if $rem_port;