diff --git a/net/linux-lib.pl b/net/linux-lib.pl index 06a7014b9..e87b47251 100755 --- a/net/linux-lib.pl +++ b/net/linux-lib.pl @@ -258,7 +258,44 @@ if (&has_command("ip") && $a->{'virtual'} ne '' && !$a->{'up'}) { return; } -if (!&has_command("ifconfig") && &has_command("ip")) { +if (&has_command("ip") && $a->{'bond'} && $a->{'up'} && !$old) { + # Create the bond before assigning addresses to it. + my $bcmd = "ip link add ".quotemeta($a->{'name'})." type bond"; + if (defined($a->{'mode'}) && $a->{'mode'} ne '') { + $bcmd .= " mode ".quotemeta(&bond_mode_name($a->{'mode'})); + } + if ($a->{'miimon'}) { + $bcmd .= " miimon ".quotemeta($a->{'miimon'}); + } + if ($a->{'updelay'}) { + $bcmd .= " updelay ".quotemeta($a->{'updelay'}); + } + if ($a->{'downdelay'}) { + $bcmd .= " downdelay ".quotemeta($a->{'downdelay'}); + } + my $out = &backquote_logged("$bcmd 2>&1"); + &error("Failed to create bond device : $out") if ($?); + foreach my $slave (grep { $_ ne '' } split(/\s+/, $a->{'partner'})) { + $bcmd = "ip link set dev ".quotemeta($slave)." down"; + $out = &backquote_logged("$bcmd 2>&1"); + &error("Failed to bring down bond slave : $out") if ($?); + $bcmd = "ip link set dev ".quotemeta($slave)." master ". + quotemeta($a->{'name'}); + $out = &backquote_logged("$bcmd 2>&1"); + &error("Failed to add bond slave : $out") if ($?); + $bcmd = "ip link set dev ".quotemeta($slave)." up"; + $out = &backquote_logged("$bcmd 2>&1"); + &error("Failed to bring up bond slave : $out") if ($?); + } + if ($a->{'primary'}) { + $bcmd = "ip link set dev ".quotemeta($a->{'name'}). + " type bond primary ".quotemeta($a->{'primary'}); + $out = &backquote_logged("$bcmd 2>&1"); + &error("Failed to set bond primary interface : $out") if ($?); + } + } + +if (($a->{'bond'} || !&has_command("ifconfig")) && &has_command("ip")) { # For a real interface, activate or de-activate the link if ($a->{'virtual'} eq '' && $a->{'up'} && (!$old || !$old->{'up'})) { # Bring up @@ -646,6 +683,19 @@ local $out = &backquote_logged("$cmd 2>&1"); &error($out) if ($?); } +# bond_mode_name(mode) +# Convert Webmin's numeric bonding mode to the name expected by ip(8). +sub bond_mode_name +{ +my ($mode) = @_; +my @modes = ("balance-rr", "active-backup", "balance-xor", "broadcast", + "802.3ad", "balance-tlb", "balance-alb"); +if ($mode =~ /^\d+$/ && defined($modes[$mode])) { + return $modes[$mode]; + } +return $mode eq "activebackup" ? "active-backup" : $mode; +} + # Tries to unload the module # unload_module(name) sub unload_module diff --git a/net/save_bifc.cgi b/net/save_bifc.cgi index e41231e82..ae2fc7fa4 100755 --- a/net/save_bifc.cgi +++ b/net/save_bifc.cgi @@ -377,7 +377,7 @@ else { $err && &error("
$err
"); } else { - if ($in{'bond'}) { + if ($in{'bond'} && !&has_command("ip")) { if (($gconfig{'os_type'} eq 'debian-linux') && ($gconfig{'os_version'} >= 5)) {} else {&load_module($b);} @@ -389,4 +389,3 @@ else { "bifc", $b->{'fullname'}, $b); } &redirect("list_ifcs.cgi?mode=boot"); - diff --git a/net/t/run-tests.t b/net/t/run-tests.t index 4431deeed..14685ab9e 100644 --- a/net/t/run-tests.t +++ b/net/t/run-tests.t @@ -617,4 +617,47 @@ is_deeply(\@commands, [ "ip addr del 10\\.211\\.55\\.25\\/24 dev enp0s5 2>&1" ], "Linux active virtual interface is removed when saved down"); +@commands = ( ); +{ + no warnings 'redefine'; + no warnings 'once'; + local *main::has_command = sub { + return $_[0] eq "ip" ? "/sbin/ip" : + $_[0] eq "ifconfig" ? "/sbin/ifconfig" : undef; + }; + local *main::active_interfaces = sub { + return ( ); + }; + local *main::backquote_command = sub { + return ""; + }; + main::activate_interface({ 'name' => 'bond0', + 'fullname' => 'bond0', + 'virtual' => '', + 'bond' => 1, + 'partner' => 'eth0 eth1', + 'mode' => '1', + 'primary' => 'eth0', + 'miimon' => '100', + 'updelay' => '200', + 'downdelay' => '200', + 'address' => '10.0.0.2', + 'netmask' => '255.255.255.0', + 'address6' => [ ], + 'netmask6' => [ ], + 'up' => 1 }); + } +is_deeply(\@commands, + [ "ip link add bond0 type bond mode active\\-backup miimon 100 updelay 200 downdelay 200 2>&1", + "ip link set dev eth0 down 2>&1", + "ip link set dev eth0 master bond0 2>&1", + "ip link set dev eth0 up 2>&1", + "ip link set dev eth1 down 2>&1", + "ip link set dev eth1 master bond0 2>&1", + "ip link set dev eth1 up 2>&1", + "ip link set dev bond0 type bond primary eth0 2>&1", + "ip link set dev bond0 up 2>&1", + "cd / ; ip addr add 10\\.0\\.0\\.2/24 dev bond0 2>&1" ], + "Linux active bond interface is created before assigning an address"); + done_testing();