-
Notifications
You must be signed in to change notification settings - Fork 277
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3693928
commit 61be745
Showing
3 changed files
with
499 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
name: extra_tests_network_bonding | ||
description: > | ||
Maintainer: vkatkalov. | ||
Extra bonding tests | ||
conditional_schedule: | ||
bonding: | ||
HOSTNAME: | ||
'client': | ||
- network/network_bonding | ||
'server': | ||
schedule: | ||
- boot/boot_to_desktop | ||
- installation/bootloader_start | ||
- network/network_bonding_setup | ||
- '{{bonding}}' | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,368 @@ | ||
# SUSE's openQA tests | ||
# | ||
# Copyright 2016-2023 SUSE LLC | ||
# SPDX-License-Identifier: FSFAP | ||
|
||
# Summary: Test network bonding capability and connectivity | ||
# Maintainer: QE Core <[email protected]> | ||
|
||
use base "consoletest"; | ||
use strict; | ||
use warnings; | ||
use testapi; | ||
use power_action_utils "power_action"; | ||
use utils qw(validate_script_output_retry); | ||
use serial_terminal qw(select_serial_terminal); | ||
use lockapi; | ||
use utils; | ||
use console::ovs_utils; | ||
use version_utils; | ||
|
||
my $BARRIER_BONDING_TESTS_DONE = 'BONDING_TESTS_DONE'; | ||
|
||
my $server_ip = "10.0.2.101"; | ||
my $client_ip = "10.0.2.102"; | ||
my $subnet = "/24"; | ||
|
||
my $use_nm; | ||
|
||
sub cidr_to_netmask { | ||
my ($cidr_str) = @_; | ||
|
||
# Extract the numeric part from the string (e.g., "/32" -> 32) | ||
$cidr_str =~ /(\d+)/; | ||
my $cidr = $1; | ||
|
||
my $binmask = '1' x $cidr . '0' x (32 - $cidr); | ||
my @octets = unpack("C4", pack("B32", $binmask)); | ||
return join('.', @octets); | ||
} | ||
|
||
sub set_nics_link_speed_duplex { | ||
my ($nics_ref) = @_; | ||
my @nics = @$nics_ref; | ||
|
||
for my $nic (@nics) { | ||
record_info("SET $nic link speed and duplex", "ethtool -s $nic speed 1000 duplex full autoneg off"); | ||
assert_script_run("ethtool -s $nic speed 1000 duplex full autoneg off"); | ||
} | ||
} | ||
|
||
sub is_nm_used { | ||
return script_run("systemctl is-active NetworkManager") == 0; | ||
} | ||
|
||
sub is_wicked_used { | ||
return script_run("systemctl is-active wicked") == 0; | ||
} | ||
|
||
sub check_connectivity { | ||
my ($bond_name) = @_; | ||
my $ping_host = $server_ip; | ||
my $ping_command = "ping -c1 -I $bond_name $ping_host"; | ||
|
||
validate_script_output_retry( | ||
$ping_command, | ||
sub { m/1 packets transmitted, 1 received, 0% packet loss,/ } | ||
); | ||
} | ||
|
||
sub get_nics_nm { | ||
my ($bond_name) = @_; | ||
my @devices; | ||
|
||
# Use nmcli to get the list of network interfaces and their states | ||
my @nmcli_output = split(/\n/, script_output('nmcli -f DEVICE,STATE device')); | ||
|
||
foreach my $line (@nmcli_output) { | ||
# Skip the header line | ||
next if $line =~ /^DEVICE\s+STATE$/; | ||
|
||
# Split each line into device and state | ||
my ($device, $state) = split(/\s+/, $line, 2); | ||
|
||
# Skip if the device is 'connected (externally)' or is the loopback or bond interface | ||
next if ($state =~ /^connected \(externally\)/ || $device eq 'lo' || $device eq $bond_name); | ||
|
||
# Include the device if it's 'connected' or any 'connecting' state (e.g., 'connecting (getting IP configuration)') | ||
push @devices, $device if ($state =~ /^connected\b/ || $state =~ /^connecting\b/); | ||
} | ||
|
||
return @devices; | ||
} | ||
|
||
sub get_nics_wicked { | ||
my ($bond_name) = @_; | ||
my @devices; | ||
my $within_interface_block = 0; | ||
|
||
# Use wicked show-xml to get the list of network interfaces | ||
my @xml_output = split(/\n/, script_output('wicked show-xml')); | ||
|
||
foreach my $line (@xml_output) { | ||
# Check if we are entering an <interface> block | ||
if ($line =~ /<interface>/) { | ||
$within_interface_block = 1; | ||
} | ||
|
||
# Check if we are exiting an <interface> block | ||
if ($line =~ /<\/interface>/) { | ||
$within_interface_block = 0; | ||
} | ||
|
||
# If inside an <interface> block and we find a <name> tag, capture the interface name | ||
if ($within_interface_block && $line =~ /<name>([^<]+)<\/name>/) { | ||
$within_interface_block = 0; | ||
my $device = $1; | ||
# Skip the loopback device 'lo' and any bond interface | ||
next if $device eq 'lo'; | ||
next if $device eq $bond_name; | ||
# Add the device to the list | ||
push @devices, $device; | ||
# We found the <name> within this block, no need to look further in this block | ||
} | ||
} | ||
|
||
return @devices; | ||
} | ||
|
||
sub get_nics { | ||
my ($bond_name) = @_; | ||
|
||
if ($use_nm) { | ||
return get_nics_nm($bond_name); | ||
} else { | ||
return get_nics_wicked($bond_name); | ||
} | ||
} | ||
|
||
sub delete_existing_connections_nm { | ||
my $output = script_output('nmcli -g DEVICE,UUID conn show'); | ||
my %seen_uuids; | ||
|
||
foreach my $line (split "\n", $output) { | ||
next if $line =~ /^\s*$/; | ||
|
||
my ($device, $uuid) = split /:/, $line; | ||
next if defined $device && $device eq 'lo'; | ||
next if exists $seen_uuids{$uuid}; | ||
|
||
$seen_uuids{$uuid} = 1; | ||
script_run "nmcli con delete uuid '$uuid'"; | ||
} | ||
} | ||
|
||
sub delete_existing_connections_wicked { | ||
script_run "wicked ifdown all"; | ||
script_run "rm -f /etc/sysconfig/network/ifcfg-*"; | ||
} | ||
|
||
sub delete_existing_connections { | ||
if ($use_nm) { | ||
delete_existing_connections_nm(); | ||
} else { | ||
delete_existing_connections_wicked(); | ||
} | ||
} | ||
|
||
sub create_bond_nm { | ||
my ($bond_name, $bond_mode, $miimon) = @_; | ||
assert_script_run "nmcli con add type bond ifname $bond_name con-name $bond_name bond.options \"mode=$bond_mode, miimon=$miimon\""; | ||
assert_script_run "nmcli connection modify $bond_name connection.autoconnect-slaves 1"; | ||
} | ||
|
||
sub create_and_configure_bond_wicked { | ||
my ($bond_name, $bond_mode, $miimon, $ip_addr, $subnet, $gateway, @devices) = @_; | ||
|
||
# Remove the old configuration file if it exists | ||
script_run "rm -f /etc/sysconfig/network/ifcfg-$bond_name"; | ||
|
||
# Assuming $subnet holds the CIDR notation like '/24' | ||
my $ifcfg_subnet = cidr_to_netmask $subnet; | ||
|
||
# Create the new configuration file | ||
script_run "echo 'BOOTPROTO=static' > /etc/sysconfig/network/ifcfg-$bond_name"; | ||
script_run "echo 'STARTMODE=auto' >> /etc/sysconfig/network/ifcfg-$bond_name"; | ||
script_run "echo 'BONDING_MASTER=yes' >> /etc/sysconfig/network/ifcfg-$bond_name"; | ||
script_run "echo 'BONDING_SLAVE=no' >> /etc/sysconfig/network/ifcfg-$bond_name"; | ||
script_run "echo 'BONDING_MODULE_OPTS=\"mode=$bond_mode miimon=$miimon\"' >> /etc/sysconfig/network/ifcfg-$bond_name"; | ||
script_run "echo 'IPADDR=$ip_addr' >> /etc/sysconfig/network/ifcfg-$bond_name"; | ||
script_run "echo 'NETMASK=$ifcfg_subnet' >> /etc/sysconfig/network/ifcfg-$bond_name"; | ||
script_run "echo 'GATEWAY=$gateway' >> /etc/sysconfig/network/ifcfg-$bond_name"; | ||
|
||
# Append slave interfaces to the bond configuration | ||
my $index = 1; | ||
foreach my $device (@devices) { | ||
script_run "echo 'BONDING_SLAVE_$index=$device' >> /etc/sysconfig/network/ifcfg-$bond_name"; | ||
$index++; | ||
} | ||
} | ||
|
||
sub configure_device_route_wicked { | ||
my ($bond_name, $gateway) = @_; | ||
my $route_config_file = "/etc/sysconfig/network/ifroute-$bond_name"; | ||
|
||
# Delete existing route configuration if it exists | ||
script_run "rm -f $route_config_file"; | ||
|
||
# Create a new route configuration file | ||
script_run "echo 'default $gateway dev $bond_name' > $route_config_file"; | ||
} | ||
|
||
sub configure_device_route { | ||
my ($bond_name, $gateway) = @_; | ||
if ($use_nm) { | ||
} else { | ||
configure_device_route_wicked($bond_name, $gateway); | ||
} | ||
} | ||
|
||
sub create_bond { | ||
my ($bond_name, $bond_mode, $miimon, @nics) = @_; | ||
if ($use_nm) { | ||
create_bond_nm($bond_name, $bond_mode, $miimon); | ||
} else { | ||
create_and_configure_bond_wicked($bond_name, $bond_mode, $miimon, $client_ip, $subnet, $server_ip, @nics); | ||
} | ||
} | ||
|
||
sub add_devices_to_bond_nm { | ||
my ($bond_name, @devices) = @_; | ||
foreach my $device (@devices) { | ||
assert_script_run "nmcli con add type ethernet ifname $device master $bond_name"; | ||
} | ||
} | ||
|
||
sub add_devices_to_bond_wicked { | ||
my ($bond_name, @devices) = @_; | ||
|
||
foreach my $device (@devices) { | ||
# Remove the old configuration file for the device if it exists | ||
script_run "rm -f /etc/sysconfig/network/ifcfg-$device"; | ||
|
||
# Create the new configuration file for the device | ||
script_run "echo 'BOOTPROTO=static' > /etc/sysconfig/network/ifcfg-$device"; | ||
script_run "echo 'STARTMODE=auto' >> /etc/sysconfig/network/ifcfg-$device"; | ||
script_run "echo 'BONDING_MASTER=no' >> /etc/sysconfig/network/ifcfg-$device"; | ||
script_run "echo 'BONDING_SLAVE=yes' >> /etc/sysconfig/network/ifcfg-$device"; | ||
script_run "echo 'BONDING_MASTER_IF=$bond_name' >> /etc/sysconfig/network/ifcfg-$device"; | ||
} | ||
} | ||
|
||
sub add_devices_to_bond { | ||
my ($bond_name, @devices) = @_; | ||
if ($use_nm) { | ||
add_devices_to_bond_nm($bond_name, @devices); | ||
} else { | ||
add_devices_to_bond_wicked($bond_name, @devices); | ||
} | ||
} | ||
|
||
sub configure_client_ip { | ||
my ($bond_name) = @_; | ||
if ($use_nm) { | ||
assert_script_run "nmcli con modify $bond_name ipv4.addresses ${client_ip}${subnet}"; | ||
assert_script_run "nmcli con modify $bond_name ipv4.gateway $server_ip"; | ||
assert_script_run "nmcli con modify $bond_name ipv4.method manual"; | ||
assert_script_run "nmcli con up $bond_name"; | ||
} else { | ||
# No need to handle wicked configuration here, as it's done in create_and_configure_bond_wicked | ||
systemctl 'restart apparmor'; | ||
} | ||
} | ||
|
||
sub test_failover { | ||
my ($bond_mode, $bond_name, $device, $description, $nics_ref) = @_; | ||
my @nics_status = map { [$_, $_ eq $device ? 0 : 1] } @$nics_ref; | ||
|
||
record_info("Testing Failover for Mode: $bond_mode", "NIC: $device"); | ||
|
||
assert_script_run "ip link set dev $device down"; | ||
script_run 'ip a'; | ||
|
||
# Validate bond mode and NIC statuses (the downed NIC should be "down") | ||
validate_bond_mode_and_slaves($bond_name, $description, \@nics_status); | ||
|
||
check_connectivity $bond_name; | ||
|
||
assert_script_run "ip link set dev $device up"; | ||
systemctl 'restart wicked' unless $use_nm; | ||
} | ||
|
||
sub validate_bond_mode_and_slaves { | ||
my ($bond_name, $description, $devices_ref) = @_; | ||
|
||
assert_script_run "cat /proc/net/bonding/$bond_name | grep 'Mode:' | grep '$description'"; | ||
|
||
foreach my $device_info (@$devices_ref) { | ||
my ($device, $status_up) = @$device_info; | ||
my $expected_status = $status_up ? 'up' : 'down'; | ||
|
||
validate_script_output_retry( | ||
"grep -A 1 'Slave Interface: $device' /proc/net/bonding/$bond_name", | ||
sub { m/MII Status: $expected_status/ } | ||
); | ||
} | ||
} | ||
|
||
sub test_bonding_mode { | ||
my ($self, $nics_ref, $miimon, $bond_name, $bond_mode, $description) = @_; | ||
my @nics = @$nics_ref; | ||
|
||
select_serial_terminal; | ||
|
||
delete_existing_connections; | ||
|
||
create_bond($bond_name, $bond_mode, $miimon, @nics); | ||
add_devices_to_bond($bond_name, @nics); | ||
configure_device_route($bond_name, $server_ip); | ||
|
||
configure_client_ip($bond_name); | ||
|
||
power_action('reboot', textmode => 1); | ||
$self->wait_boot; | ||
select_serial_terminal; | ||
set_nics_link_speed_duplex(\@nics); | ||
check_connectivity $bond_name; | ||
|
||
# Validate that all NICs are "up" | ||
validate_bond_mode_and_slaves($bond_name, $description, [map { [$_, 1] } @nics]); | ||
|
||
# Testing failover for each NIC | ||
test_failover($bond_mode, $bond_name, $_, $description, \@nics) for @nics; | ||
|
||
delete_existing_connections; | ||
} | ||
|
||
sub run { | ||
my ($self) = @_; | ||
select_serial_terminal; | ||
|
||
$use_nm = is_nm_used(); | ||
|
||
my $bond_name = "bond0"; | ||
my $miimon = 200; | ||
my @nics = get_nics($bond_name); | ||
|
||
record_info(scalar(@nics) . " NICs Detected", join(', ', @nics)); | ||
|
||
my @bond_modes = ( | ||
['balance-rr', 'load balancing (round-robin)'], | ||
['active-backup', 'fault-tolerance (active-backup)'], | ||
['balance-xor', 'load balancing (xor)'], | ||
['broadcast', 'fault-tolerance (broadcast)'], | ||
['802.3ad', 'IEEE 802.3ad Dynamic link aggregation'], | ||
['balance-tlb', 'transmit load balancing'], | ||
['balance-alb', 'adaptive load balancing'] | ||
); | ||
|
||
foreach my $mode_info (@bond_modes) { | ||
my ($bond_mode, $description) = @$mode_info; | ||
record_info("Testing Bonding Mode: $bond_mode", $description); | ||
test_bonding_mode($self, \@nics, $miimon, $bond_name, $bond_mode, $description); | ||
} | ||
|
||
barrier_wait $BARRIER_BONDING_TESTS_DONE; | ||
} | ||
|
||
1; |
Oops, something went wrong.