#!/usr/bin/perl -w # # This program is used to stress test the LANforge system, and may be used as # an example for others who wish to automate LANforge tests. # This script sets up connections of types: # lf, lf_udp, lf_tcp, custom_ether, custom_udp, custom_tcp, l4 (http, https, ftp and fileIO) # across real ports and MACVLAN ports on one or more machines. # It then continously starts and stops the connections. package main; $| = 1; # Un-buffer output use strict; use warnings; use Carp; use Net::Telnet (); $SIG{ __DIE__ } = sub { Carp::confess( @_ ) }; use Scalar::Util; #::looks_like_number; use lib '/home/lanforge/scripts'; # this is pedantic necessity for the following use statements use LANforge::Port; use LANforge::Utils; use LANforge::Endpoint; use Net::Telnet (); use Net::Ping; use Getopt::Long; use Time::HiRes ('sleep'); use Socket; use POSIX; ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## package variables below use constant NL => "\n"; use constant NA => "NA"; use constant AUTO => "AUTO"; use constant READ => "read"; use constant WRITE => "write"; ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- our $report_timer = 8000; # Set report timer for all tests created in ms, i.e. 8 seconds our $lfmgr_host = undef; our $lfmgr_port = 4001; our $resource = 1; our $quiet = 1; our $group = undef; our $tmp_group = undef; our $tmp_group_min = 0; our $tmp_group_max = 0; our $action = undef; our $nfs_mnt = undef; our $nfs_list = undef; our $local_mnt = AUTO; our $first_mvlan_ip = undef; #"10.26.1.10"; our $netmask = "255.255.255.0"; our $parent_port = undef; our $utils = undef; our $shelf_num = 1; our $DEBUG = 0; our $sleep_after_wo = 15; # Second to sleep after starting writers (before starting readers) our $D_PAUSE = 3; ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- # File-IO configuration constants our $quiesce_after_files = 0; our $min_rw_size = "512"; our $max_rw_size = "65536"; our $use_crc = "yes"; our $min_read_bps = "1000000"; # 1Mbps our $max_read_bps = "2000000"; # 2Mbps our $num_files = 2; our $min_file_size = 1024 * 1024; our $max_file_size = 1024 * 1024 * 2; our $min_write_bps = "3000000"; # 3Mbps our $max_write_bps = "4000000"; # 4Mbps our $mount_options = "NONE"; our $skip_writers = 0; our $skip_readers = 0; ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- # below are sorted names and associated endpoints # the third argument can be used as the default parent # port for the mac-vlans for that group our %group_names = ( #"group1" => [ 1, 20, 'eth1'], #"group2" => [ 21, 40, 'eth1'], #"group3" => [ 41, 60, 'eth1'], #"group4" => [ 1, 1, 'eth1'], #"group5" => [ 2, 2, 'eth1'] ); our $fast_forward_ep = 0; # set this to 1 to leave exiting file endpoints alone ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- our %mnt_map = (); our %file_endpoints = (); our %cross_connects = (); our %test_groups = (); our %all_file_ep = (); our %mac_vlans = (); our %vlan_ips = (); # These are set based on group chosen. our $qty_mac_vlans = 0; our $start = 0; # First idx, inclusive our $stop = 0; # Last idx sub ipSummary { my $first; if((!defined $::first_mvlan_ip ) || ("$::first_mvlan_ip" eq "")) { $first = "0.0.0.0"; } else { $first = $::first_mvlan_ip; } my $linestart = " # "; my $summary = NL; for my $name (sort keys %::group_names) { $summary .= $linestart.$name.": "; my $a = addrtoint( $first ) + $::group_names{ $name }->[0] -1; my $b = addrtoint( $first ) + $::group_names{ $name }->[1] -1; $summary .= inttoaddr( $a )." - ".inttoaddr( $b ).NL; } return $summary; } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## Usage == ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- my $first = ($::first_mvlan_ip) ? $::first_mvlan_ip : "0.0.0.0"; my $usage = "$0 [--mgr {host-name | IP}] [--mgr_port {ip port ($lfmgr_port)}] [--resource {resource ($resource)}] [--nfs_mnt {[IP|host-name]:/path}] # 192.168.1.1:/foo # filehost:/home/fileio [--nfs_list {local file}]\t# list of nfs mountpoints # Will be modulo distributed among groups mac vlans # Obviates --nfs_mnt; examples: # --nfs_list ./my-list-of-mounts # --nfs_list /tmp/mnt-list # File format: # 10.20.30.40:/a/b/c # filehost:/z/y [--parent_port {parent eth port}]\t# parent of mac vlans [--first-mvlan-ip {ip ($first)}]\t# mvlan ips: ".ipSummary()." [--netmask {mask ($netmask)}]\t#mac-vlan netmask [--action {list_groups|run_group|stop_group|del_group}] # list_groups: list test groups # run_group: assemble and start writer then reader group # stop_group: quiece writer then reader group # del_group: delete reader then writer file endpoints [--group {name}] # test group base name, creates: # _wo for writers and # _ro for readers [--min_rw_size ($min_rw_size)]\t# in bytes [--max_rw_size ($max_rw_size)]\t# in bytes [--use_crc {yes|no}] [--min_read_bps ($min_read_bps)]\t# in bps, 2000000 = 1Mbps [--max_read_bps ($max_read_bps)]\t# in bps, 2000000 = 2Mbps [--num_files ($num_files)]\t# files per writer [--quiesce_after_files ($quiesce_after_files)]\t# files to read/write before stopping test. O == infinite (default) [--skip_readers ($skip_readers)]\t# Should we not create reader connections: 0 | 1 [--skip_writers ($skip_readers)]\t# Should we not create writer connections: 0 | 1 [--min_file_size ($min_file_size)]\t# in bytes [--max_file_size ($max_file_size)]\t# in bytes [--min_write_bps ($min_write_bps)]\t# in bps, 3000000 = 3Mbps [--max_write_bps ($max_write_bps)]\t# in bps, 4000000 = 4Mbps [--mount_options ($mount_options)]\t# as per nfs(1) [--tmp_group {name}]\t# for specifying ad-hoc group, you will see group [--min 1-n]\t first macvlan in tmp group [--max 1-n]\t last macvlan in tmp group Examples: $0 --mgr 10.0.0.1 --resource 1 --action list_groups $0 --mgr 10.0.0.1 --resource 1 --action run_group --group group1 \\ --parent_port eth2 --netmask 255.255.0.0 \\ --nfs_mnt 192.168.99.99:/fire $0 --mgr 10.0.0.1 --resource 1 \\ --action stop_group --group group1 $0 --mgr 10.0.0.1 --resource 1 \\ --action del_group --group group1 $0 --mgr 10.0.0.1 --resource 1 \\ --action run_group --group group2 --parent_port eth9 \\ --first_mvlan_ip 172.168.90.1 --netmask 255.255.0.0 \\ --nfs_list ./nfsexports.txt \\ --num_files 20 --min_file_size 4096 --max_file_size 524288 \\ --min_write_bps 1000000 --max_write 900000000 $0 --mgr 10.0.0.1 --resource 1 \\ --action run_group --group group1 \\ --nfs_mnt 192.168.99.99:/fire \\ --mount_options sync,hard,timeo=120,retrans=4 $0 --mgr 10.0.0.1 --resource 1 --action run_group \\ --tmp_group lag1 --min 1 --max 2 --parent_port eth1 \\ --first_mvlan_ip 10.30.0.10 \\ --nfs_mnt 10.30.0.1:/tmp $0 --mgr 10.0.0.1 --resource 1 \\ --action stop_group --tmp_group lag1 --min 1 --max 2 --parent_port eth1 "; ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## ip_to_a/a_to_ip ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub addrtoint { return( unpack( "N", pack( "C4", split( /[.]/,$_[0]) ) ) ); }; sub inttoaddr { return( join( ".", unpack( "C4", pack( "N", $_[0] ) ) ) ); }; ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## Open connection to the LANforge server, configure our utils. ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub init { my $conn = new Net::Telnet(Timeout => 20, Prompt => '/default\@btbits\>\>/'); $conn->open(Host => $::lfmgr_host, Port => $::lfmgr_port, Timeout => 10); $conn->waitfor("/btbits\>\>/"); $conn->max_buffer_length(1024 * 1024 * 10); # 10M buffer $::utils = new LANforge::Utils(); $::utils->telnet($conn); # Set our telnet object. $::utils->cli_send_silent($::DEBUG ? 0 : 1); # Do show input to CLI $::utils->cli_rcv_silent($::DEBUG ? 0 : 1); # Repress output from CLI ?? if ($::group && $::group ne "") { my $ra_bounds = $::group_names{ $::group }; $::start = @$ra_bounds[0]; $::stop = @$ra_bounds[1]; $::qty_mac_vlans = ($::stop - $::start) + 1; print "group [$group] vlans: $::stop - $::start = $::qty_mac_vlans\n" if($::DEBUG); } } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## set a port or mvlan up or down ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub fmt_port_up_down { my ($resource, $port_id, $state) = @_; my $cur_flags = 0; if ($state eq "down") { $cur_flags |= 0x1; # port down } # Specify the interest flags so LANforge knows which flag bits to pay attention to. my $ist_flags = 0; $ist_flags |= 0x2; # check current flags $ist_flags |= 0x800000; # port down my $cmd = $::utils->fmt_cmd("set_port", 1, $resource, $port_id, NA, NA, NA, NA, "$cur_flags", NA, NA, NA, NA, "$ist_flags"); return $cmd; } # ~port up/down ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## Create mac_vlans if they do not exist. ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub preparePorts { do_err_exit("First mac vlan IP is not set. Please set --first_mvlan_ip.") unless ((defined $::first_mvlan_ip) && ("$::first_mvlan_ip" ne "")); do_err_exit( "preparePorts: Unnamed parent port. Please set \$parent_port") unless((defined $::parent_port) && ("$::parent_port" ne "")); my $sleep_after = 0; my %all_ports = (); # build list of MAC VLANS print "shelf_num $::shelf_num, resource $::resource\n" if ($::DEBUG); my @ports = $::utils->getPortListing( 1, $::resource +0); for my $rh_port (@ports) { print "added port $rh_port->{'dev'}".NL if($::DEBUG); $all_ports{ $rh_port->{'dev'} } = $rh_port; next unless ( $rh_port->{'dev'} eq $::parent_port ); } do_err_exit("preparePorts: Failed to populate ports list, please debug.") unless (keys %all_ports > 0); my $i; my %new_items = (); my $ra_bounds = $::group_names{ $group }; my $start_str = $::first_mvlan_ip; my $start_int = addrtoint($start_str); my $next_ip; if (($::qty_mac_vlans + $::start) < 1) { do_err_exit("preparePorts: expects a positive, non-zero number of mvlans to create. Cannot continue."); } for ($i = 0 + $::start; $i < $::qty_mac_vlans + $::start; $i++) { my $devname = $::parent_port."#".$i; print "start_str[$start_str] start_int[$start_int] i[$i]\n" if ($::DEBUG); my $next_ip = inttoaddr( $start_int + $i -1); print "next_ip[$next_ip]\n" if ($::DEBUG); $::vlan_ips{ $devname } = $next_ip; $::mac_vlans{ $devname } = 0; if ( defined $all_ports{ $devname }) { $::mac_vlans{ $devname } = 1; } else { # create mac_vlan my $mac_addr = mac(); my $cmd = $::utils->fmt_cmd( "add_mvlan", $::shelf_num, $::resource, $::parent_port, $mac_addr, $i); print " + ".$cmd.NL if ($::DEBUG); $::utils->doCmd($cmd); sleep(0.1); } $new_items{ $devname } = 1; $sleep_after++; } #~for if ( keys %new_items > 0 ) { print "Creating ".(keys %new_items)." new ports:..."; # set the port IP for my $new_item (keys(%new_items)) { my $ip = $::vlan_ips{ $new_item }; my $cmd_flags = 0x0; my $current = 0x0; my $interesting = 0x0 | 0x4 | 0x8; my $cmd = $::utils->fmt_cmd("set_port", $::shelf_num, $::resource, $new_item, $ip, $::netmask, NA, $cmd_flags, $current, NA, NA, NA, NA, $interesting, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA); if ($::DEBUG) { print NL." $new_item $ip: $cmd "; } else { print "."; } $::utils->doCmd($cmd); sleep(0.1); $sleep_after++; my @ports = $::utils->getPortListing($::shelf_num, $::resource); for my $rh_port (@ports) { $::all_ports{ $rh_port->{'dev'} } = $rh_port; #reset ports } } print NL."Created ".(keys %new_items)." new mac vlans".NL; } if ($sleep_after > 10) { $sleep_after = $sleep_after / 2; } if ($sleep_after) { print "\nSleeping: $sleep_after seconds to allow ports to be created and configured.\n"; for $i (1..$sleep_after) { sleep(1); print "."; } print NL; } # check that the port is up by trying to run a ping from it if ( defined $::nfs_mnt && "$::nfs_mnt" ne "") { my ($nfs_name) = split(/:/, $::nfs_mnt ); print "Emitting one ping from each mvlan reduces failed mounts:"; foreach my $name (reverse sort keys %new_items) { my $rh_p = $::all_ports{ $name }; my $ip = $rh_p->{'ip_addr'}; #my $ping = "ping -n -c1 -w1 -W1 -I $ip $nfs_name"; print "ping $ip".NL if ($::DEBUG); my $ping = Net::Ping->new('tcp', 1); $ping->bind($ip); $ping->port_number(scalar(getservbyname("nfs", "tcp"))); my $counter = 5; while( $counter > 0 ) { if ($ping->ping($nfs_name)) { print "."; $counter = 0; } else { print "$nfs_name did not ack nfs packet from $ip".NL; $counter --; sleep(0.2); } } $ping->close(); undef($ping); #$ping->close(); } } print NL; } # ~preparePorts sub notBlank { my ($name, $value) = @_; if((!defined $name) || ("$name" eq "")) { print "Name itself is blank, value[$value]".NL; } if((!defined $value) || ("$value" eq "")) { print "Value of $name is blank".NL; } #die if($::DEBUG); } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## prepareFileEndp - creates requested file endpoints if they do not exist, ## creates implied FIO endpoints if they dont exist and adds endpoints ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub prepareFileEndpoints { do_err_exit("prepareFileEndpoints: Unnamed parent port. Please set \$parent_port") unless((defined $::parent_port) && ("$::parent_port" ne "")); do_err_exit("prepareFileEndpoints: Blank all_ports array. Please run preparePorts() first.") unless( keys %::all_ports > 1 ); do_err_exit("prepareFileEndpoints: Blank mac_vlans array. Please run preparePorts() first.") unless( keys %::mac_vlans > 0 ); if((defined $::nfs_list) && ("$::nfs_list" ne "")) { if((keys %::mnt_map) < 1) { do_err_exit("prepareFileEndpoints: empty --nfs_list. Provide mountpoints in [$::nfs_list]"); } } elsif((! defined $::nfs_mnt) || ("$::nfs_mnt" eq "")) { do_err_exit("prepareFileEndpoints: undefined --nfs_mnt. Please specify --nfs_mnt first"); } my %all_file_endpoints = (); my %all_cross_connects = (); my %endpoints_mvlans = (); my @new_file_endpoints = (); my @new_cross_connects = (); my $ep_name = undef; for my $grp (sort(keys %::group_names)) { my $ra_bounds = $::group_names{ $grp }; print "skip_writers[$::skip_writers] skip_readers[$::skip_readers]" if ($::DEBUG); sleep(3) if($::DEBUG); for my $i (@$ra_bounds[0]..@$ra_bounds[1]) { if (! $::skip_writers) { $ep_name = $grp ."_wo_".sprintf( "%03d", $i); $all_file_endpoints{ $ep_name } = 0; $endpoints_mvlans{ $ep_name } = $::parent_port."#".$i; $all_cross_connects{ $ep_name } = 0; } if (! $::skip_readers) { $ep_name = $grp ."_ro_".sprintf( "%03d", $i); $all_file_endpoints{ $ep_name } = 0; $endpoints_mvlans{ $ep_name } = $::parent_port."#".$i; $all_cross_connects{ $ep_name } = 0; } } } print NL."Reading endpoints..."; my $endpoint_str = $::utils->doCmd("nc_show_endpoints all all"); my @endpoint_lines = split(/\n/, $endpoint_str); if ($::fast_forward_ep) { for my $line (@endpoint_lines) { $line =~ m/Endpoint \[(.*?)\]/; # proves this ep exists next if(! $1); $all_file_endpoints{ $1 } = 1; } } for my $ep_name (sort(keys %all_file_endpoints)) { print " $ep_name [".$all_file_endpoints{$ep_name}."] " if ($::DEBUG); if ($all_file_endpoints{$ep_name} == 0 ){ my $begins = $::group."_"; if( $ep_name =~ /^$begins/ ){ push( @new_file_endpoints, $ep_name ); } } } # assert we have sufficient remote_mnt entries for my $ep_name (@new_file_endpoints) { my $mvlan = $endpoints_mvlans{ $ep_name }; my $remote_mnt = $::mnt_map{ $mvlan }; notBlank( $mvlan, $remote_mnt ); } if (@new_file_endpoints > 0) { print "Creating ".@new_file_endpoints." new file endpoints..."; my $endpoint_type = "lf"; my $ip_port = "-1"; my $bursty = "no"; my $rand_pkt_sz = "no"; my $remote_mnt = undef; for my $ep_name (@new_file_endpoints) { my $mvlan = $endpoints_mvlans{ $ep_name }; $remote_mnt = $::mnt_map{ $mvlan }; my $read_write = ($ep_name =~ /_ro_/)? READ : WRITE; my $rw_prefix = $ep_name; $rw_prefix =~ s/_ro_/_wo_/; my $prefix = ($read_write eq WRITE) ? AUTO : $rw_prefix; my $directory = ($read_write eq WRITE) ? AUTO : '/mnt/lf/'.$rw_prefix; my $min_write_rt = ($read_write eq READ ) ? "0" : $::min_write_bps; my $max_write_rt = ($read_write eq READ ) ? "0" : $::max_write_bps; my $min_read_rt = ($read_write eq WRITE ) ? "0" : $::min_read_bps; my $max_read_rt = ($read_write eq WRITE ) ? "0" : $::max_read_bps; my $pattern = "increasing"; #($read_write eq "read" ) ? NA : "increasing"; my $mount_retry_nap = 3500; my $mount_dir = "NA"; # we do not want anything 'blank' in this my @names=qw(ep_name ::shelf_num ::resource mvlan min_read_rt max_read_rt min_write_rt max_write_rt pattern directory prefix remote_mnt mount_options mount_dir mount_retry_nap); my @values=($ep_name, $::shelf_num, $::resource, $mvlan, $min_read_rt, $max_read_rt, $min_write_rt, $max_write_rt, $pattern, $directory, $prefix, $remote_mnt, $mount_options, $mount_dir, $mount_retry_nap); for (my $i=0; $i<@names; $i++) { notBlank($names[$i], $values[$i]); } my $cmd = $::utils->fmt_cmd( "add_file_endp", $ep_name, $::shelf_num, $::resource, $mvlan, 'fe_nfs', $min_read_rt , $max_read_rt, $min_write_rt, $max_write_rt, $pattern, $directory, $prefix, $remote_mnt, $mount_options, "7", $mount_dir, NA, $mount_retry_nap); print " + " . $cmd.NL if ($::DEBUG); $::utils->doCmd($cmd); sleep(0.1); # if ($::DEBUG); print "."; $cmd = $::utils->fmt_cmd( "set_fe_info", $ep_name, $min_rw_size, $max_rw_size, $num_files, $min_file_size, $max_file_size, $directory, $prefix, $read_write, $quiesce_after_files); print " + " . $cmd.NL if ($::DEBUG); $::utils->doCmd($cmd); sleep(0.1); # if ($::DEBUG); print "\bo"; $::utils->doCmd($::utils->fmt_cmd( "set_endp_quiesce", $ep_name, 5)); sleep(0.1); print "\bO"; $::utils->doCmd($::utils->fmt_cmd( "set_endp_report_timer", $ep_name, 1000)); sleep(0.1); print "\b*"; $::utils->doCmd($::utils->fmt_cmd( "set_endp_flag", $ep_name, "ClearPortOnStart", 0)); sleep(0.1); print "\b|"; my $cx_name = "CX_".$ep_name; my $tg_name = $::group.(($read_write eq READ) ? "_ro" : "_wo"); my $tm_name = "default_tm"; #= $::group.(($read_write eq READ) ? "_ro" : "_wo"); my $tx_endp = $ep_name; my $rx_endp = NA; my $add_cx = $::utils->fmt_cmd( "add_cx", $cx_name, $tm_name, $tx_endp, $rx_endp ); my $set_cx = $::utils->fmt_cmd( "set_cx_report_timer", $tm_name, $cx_name, "1000", "cxonly"); my $add_tgcx = $::utils->fmt_cmd( "add_tgcx", $tg_name, $cx_name ); print $add_tgcx.NL if ($::DEBUG); print $add_cx.NL if ($::DEBUG); print $set_cx.NL if ($::DEBUG); $::utils->doCmd($add_cx); sleep(0.1); print "\bi"; $::utils->doCmd($set_cx); sleep(0.1); print "\b:"; $::utils->doCmd($add_tgcx); sleep(0.1); print "\b."; } #~for print "\nAdded ".@new_file_endpoints." endpoints to group $::group\n"; sleep(3); } #~if need to create file endpoints } #~prepareFileEndpoints ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## prepareExportList - assemble the list of nfs exports from either ## the nfs_list resource or the nfs_mnt option ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub prepareExportList { if ((defined $::nfs_list) && ("$::nfs_list" ne "")) { open(my $fh, "<", $::nfs_list) or do_err_exit("Unable to open [$::nfs_list]. Cannot continue."); my @lines = (); while(<$fh>) { chomp; next if (/^\s*[#;]/); next if (/^\s*$/); s/^\s+//; s/\s+$//; if (/[0-9a-zA-Z.-]+:\/.*$/) { push( @lines, $_ ); } } close($fh); if (@lines < 1) { do_err_exit("Unable to find lines that look like nfs mount points in [$::nfs_list]. Cannot continue."); } my $i = 0; for my $mvlan (sort keys %::mac_vlans) { $::mnt_map{ $mvlan } = $lines[ $i ]; print " mapping $mvlan => ".$lines[ $i ].NL if($::DEBUG); $i = ++$i % @lines; } } elsif ((defined $::nfs_mnt) && ("$::nfs_mnt" ne "")) { for my $mvlan (sort keys %::mac_vlans) { $::mnt_map{ $mvlan } = $::nfs_mnt; } } else { do_err_exit("Niether --nfs_list or --nfs_mnt are specified. Cannot continue."); } if ((keys %::mnt_map) < 1) { do_err_exit("prepareExportList: unable to build map of mount entries. Cannot continue."); } } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## prepareGroups - creates requested test group if it does not exist, ## file-endpoints will be created expecting these refs ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub prepareTestGroups { my @new_items = (); my $test_group_str = $::utils->doCmd("show_group all"); my @test_group_lines = split(/\n/, $test_group_str ); my %test_groups = (); for my $group_name (sort(keys %::group_names)) { $test_groups{ $group_name } = 0; } for my $line ( @test_group_lines) { if ($line =~ /TestGroup name: ([^\[]+)\s*\[.*$/) { $test_groups{ $1 } = 1; } } for my $group_name (keys %test_groups) { if ($test_groups{$group_name} == 0 ) { push(@new_items, $group_name); } } if (@new_items > 0 ) { sleep(5); for my $group_name (@new_items) { $::utils->doCmd($::utils->fmt_cmd("add_group", $group_name."_wo", NA, NA)) if (!$::skip_writers); $::utils->doCmd($::utils->fmt_cmd("add_group", $group_name."_ro", NA, NA)) if (!$::skip_readers); #print " + tg $group_name "; } } } # ~prepareTestGroups ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## generates random mac address ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub mac { my $rv = "00:"; for (my $i=0; $i<5; $i++) { $rv.=sprintf("%02X",int(rand(255))).(($i<4)?':':''); } return $rv; } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## list ports ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub showGroups { my @ports = $::utils->getPortListing($::shelf_num, $::resource); print "in show groups, found $#ports ports\n" if ($::DEBUG); for my $group_name ( sort(keys(%::group_names))) { print "show groups, $group_name _ro\n" if ($::DEBUG); my $cmd = $::utils->fmt_cmd("show_group", $group_name."_ro"); print $::utils->doCmd($cmd); print "show groups, $group_name _wo\n" if ($::DEBUG); $cmd = $::utils->fmt_cmd("show_group", $group_name."_wo"); print $::utils->doCmd($cmd); } print "\n"; } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## start the writers then start the readers ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub runGroup { my $cmd; if (!$::skip_writers) { $cmd = "start_group ".$::group."_wo"; $::utils->doCmd($cmd); print "Starting ".$::group."_wo..."; for my $i ( 1..$sleep_after_wo ) { sleep(1); print "."; } print "...started".NL; } if (!$::skip_readers) { $cmd = "start_group ".$::group."_ro"; $::utils->doCmd($cmd); print "Starting ".$::group."_ro ..."; for my $i ( 1..3 ) { sleep(1); print "."; } print "...started".NL; } } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## stop writers then stop readers ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub stopGroup { my $cmd; if (!($::skip_writers || $skip_readers)) { print NL."Quiesceing all connections..."; $cmd = "quiesce_group all"; $::utils->doCmd($cmd); } if (!$::skip_writers) { print NL."Quiesceing writers..."; $cmd = "quiesce_group ".$::group."_wo"; $::utils->doCmd($cmd); } if (!$::skip_readers) { print NL."Quiesceing readers..."; $cmd = "quiesce_group ".$::group."_ro"; $::utils->doCmd($cmd); } } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## poll the set of connections to see if they are 'stopped' ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub pollCxForStop { my $cmd; my $lines; my $num_lines = 0; my $num_counted = 0; my $num_stopped = 0; my $upper_limit = 60; my $attempts = 0; while( $num_counted == 0 || ($num_counted != $num_stopped)) { return 0 if ($attempts > $upper_limit); sleep(2); $attempts++; $cmd = $::utils->fmt_cmd("show_cx", "all", "all"); $lines = $::utils->doCmd($cmd); $num_counted = 0; $num_stopped = 0; for my $line (split(NL, $lines)) { next unless ($line =~ /CX_.*?_[wr]o_\d+/); $num_counted ++; my @h = split(/ +/, $line); $num_stopped += ($h[10] eq "STOPPED") ? 1 : 0; print "${h[2]} target:${h[8]} reported:${h[10]} counted:$num_counted stopped:$num_stopped attempts: $attempts".NL if ($::DEBUG); } print " counted:$num_counted stopped:$num_stopped attempts: $attempts".NL if ($::DEBUG); } return 1; } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## stop the group, ## delete the file endpoints from the group, ## then delete the group ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub deleteGroup { if ((!defined $::group) || ("$::group" eq "")) { do_err_exit("Cannot delete group if --group unspecified."); } my $group_name = undef; if( @_ < 1 ) { if ( $::skip_readers || $::skip_writers) { if (!$::skip_readers) { print "send Delete Group $group_name to $::group _ro \n" if ($::DEBUG); deleteGroup( $::group."_ro") ; } if (!$::skip_writers) { print "send Delete Group $group_name to $::group _wo \n" if ($::DEBUG); deleteGroup( $::group."_wo"); } return; } $group_name = $::group; } else { ($group_name) = @_; } print "Delete Group $group_name\n" if ($::DEBUG); my %cx_names = (); my %endp_names = (); my %portlist = (); my $cx_prefix = "CX_".$group_name."_"; my $should_stop_group = 0; my $cmd; my $resp; my $endp_name; my $cx_name; if ("$group_name" eq "$::group") { $cmd = $::utils->fmt_cmd("show_group", $group_name."_wo"); $resp = $::utils->doCmd($cmd); $cmd = $::utils->fmt_cmd("show_group", $group_name."_ro"); $resp .= $resp.NL.$::utils->doCmd($cmd); } else { $cmd = $::utils->fmt_cmd("show_group", $group_name); $resp = $::utils->doCmd($cmd); } # collect cross connect names for my $line (split(NL, $resp)) { chomp $line; $should_stop_group = 1 if ($line =~ /TestGroup name:.*?\[RUNNING/); if( $line =~ / $cx_prefix/ ) { for my $tg_name_hunk (sort split(/\s+/, $line )) { next if ( $tg_name_hunk =~ /^ *$/); print "$tg_name_hunk " if ($::DEBUG); $cx_names{$tg_name_hunk}++ if ($tg_name_hunk =~ /^CX_/); } } } if ($should_stop_group) { stopGroup(); if (! pollCxForStop()) { stopGroup(); print "Not all connections have stopped. Continuing.".NL; } } # I'm not getting output here for many seconds after polling for stop foreach my $x (1..10) { sleep(1); print "."; } print NL; # build endpoint names and find ports for $cx_name (reverse sort keys %cx_names) { next if( $cx_name !~ /^CX_/); my $endp_name = $cx_name; $endp_name =~ s/CX_//; print "."; sleep(0.2); my $lines = $::utils->doCmd("nc_show_endp $endp_name"); for my $line (split(NL, $lines)) { if ($line =~ /Shelf: /) { $line =~ s/,//g; my @hunks = split(/\s+/, $line); my $port = $hunks[2]." ".$hunks[4]." ".$hunks[6]; #print "PORT: $port\n"; $portlist{$port}++; } } } print NL; die "Error making portlist" if (length(keys %portlist) < 1); # remove cross connects and endpoints immediately after each print "Removing Cross Connects and endpoints: "; for $cx_name (reverse sort keys %cx_names) { next if( $cx_name !~ /^CX_/); $cmd = $::utils->fmt_cmd("rm_cx", "all", $cx_name); print "** $cmd **".NL if ($::DEBUG); $::utils->doCmd($cmd); print "0"; #$cx_name "; sleep(0.5); my $endp_name = $cx_name; $endp_name =~ s/CX_//; $cmd = $::utils->fmt_cmd("rm_endp", $endp_name); $::utils->doCmd($cmd); print "o"; #$endp_name "; sleep(0.1); } print NL; sleep(1); # remove group if ( "$group_name" eq "$::group" ) { $cmd = $::utils->fmt_cmd("rm_group", $group_name."_wo"); print " + $cmd".NL if ($::DEBUG); $::utils->doCmd($cmd); print "Removed ".$group_name."_wo".NL; sleep(0.2); $cmd = $::utils->fmt_cmd("rm_group", $group_name."_ro"); print " + $cmd".NL if ($::DEBUG); $::utils->doCmd($cmd); print "Removed ".$group_name."_ro".NL; sleep(0.2); } else { $cmd = $::utils->fmt_cmd("rm_group", $group_name); print " + $cmd".NL if ($::DEBUG); $::utils->doCmd($cmd); print "Removed ".$group_name.NL; } sleep(2); # set those vlans admin down print "Setting mvlans down: "; for my $port (reverse sort keys %portlist) { my @h = split(/\s+/, $port); $cmd = fmt_port_up_down($h[1], $h[2], "down"); print "$cmd".NL if ($::DEBUG); $::utils->doCmd($cmd); print "o"; # $port "; sleep(0.4); } print NL; sleep(0.2 * length(keys %portlist)); # remove macvlans print "Removing mvlans ports: "; for my $port (reverse sort keys %portlist) { $cmd = "rm_vlan $port"; print "Remove VLAN: $cmd".NL if ($::DEBUG); $::utils->doCmd($cmd); print "*"; #$port "; sleep(0.2); } print "...done.".NL; } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ## use this method to find the user prefix for each ip last octet ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- sub get_prefix_for_octet { my($octet) = @_; die "get_prefix_for_octet called without octet as argument" if ((!defined $octet) || ("$octet" eq "")); for my $name (sort( keys %::group_names)) { my $ra_bounds = $::group_names{ $name }; if (($octet >= @$ra_bounds[0]) && ($octet <= @$ra_bounds[1])) { return $name; } } die "get_prefix_for_octet: no prefix found for octet [$octet]"; } sub do_err_exit { my $msg = shift; print $msg.NL; exit(1); } ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- == ## == ## M A I N == ## == ## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- == GetOptions ( 'mgr|m=s' => \$lfmgr_host, 'mgr_port|mp=i' => \$lfmgr_port, 'resource|r=i' => \$resource, 'quiet|q=s' => \$quiet, 'action|a=s' => \$action, 'nfs_mnt|h=s' => \$nfs_mnt, 'nfs_list|e=s' => \$nfs_list, 'first_mvlan_ip|n=s' => \$first_mvlan_ip, 'group|g=s' => \$group, 'debug' => \$DEBUG, 'dbg_nap|dp=i' => \$D_PAUSE, 'parent_port|pp=s' => \$parent_port, 'min_rw_size|nws=i' => \$min_rw_size, 'max_rw_size|xws=i' => \$max_rw_size, 'use_crc|crc=s' => \$use_crc, 'min_read_bps|nrbps=i' => \$min_read_bps, 'max_read_bps|xrbps=i' => \$max_read_bps, 'num_files|nf=i' => \$num_files, 'quiesce_after_files|qaf=i' => \$quiesce_after_files, 'skip_readers|sr=i' => \$skip_readers, 'skip_writers|sw=i' => \$skip_writers, 'min_file_size|nsz=i' => \$min_file_size, 'max_file_size|xsz=i' => \$max_file_size, 'min_write_bps|nwbps=i' => \$min_write_bps, 'max_write_bps|xwbps=i' => \$max_write_bps, 'mount_options|mo=s' => \$mount_options, 'netmask|nm=s' => \$netmask, 'tmp_group|tmp=s' => \$tmp_group, 'min|ga=i' => \$tmp_group_min, 'max|gb=i' => \$tmp_group_max, ) || do_err_exit("$usage"); if ((!defined $action) || ($action eq "")) { do_err_exit("Please specify an action to perform.\n$usage"); } if ( ! ( $action eq "list_groups" || $action eq "run_group" || $action eq "stop_group" || $action eq "del_group" )) { do_err_exit("Unknown action $action:\n$usage"); } if ((defined $tmp_group) && ($tmp_group ne "")) { print "Using temporary group [$tmp_group]\n"; do_err_exit("Please set --min when using tmp_group") if ($tmp_group_min <= 0); do_err_exit("Please set --max when using tmp_group") if ($tmp_group_max <= 0); $group = $tmp_group; } elsif ( !(defined $group) || ("$group" eq "")) { do_err_exit("Blank or unknown group. Cannot continue."); } if ( $group eq $tmp_group ) { if ( !defined $parent_port || "$parent_port" eq "" ) { do_err_exit("Undefined --parent_port value. Cannot continue."); } $group_names{ $tmp_group } = [ $tmp_group_min, $tmp_group_max, $parent_port ]; print "assigned values to group name [$group]\n" if ($::DEBUG); my $ra = $group_names{ $tmp_group }; print "values: [".join(':', @$ra)."]\n" if ($::DEBUG); } if ( !defined $parent_port || "$parent_port" eq "" ) { $parent_port = $group_names{ $group }[2]; if ( !defined $parent_port || "$parent_port" eq "" ) { do_err_exit("Undefined --parent_port value. Cannot continue."); } } init(); if ( $action eq "list_groups" ) { showGroups(); exit(0); } print "checking group name [$group]\n" if ($::DEBUG); if ( !defined $group || $group eq "" || ! $group_names{ $group }) { $group = "" if ( !defined $group ); do_err_exit("Blank or unknown group [$group]" .NL."Known groups: ".join(', ', sort(keys(%group_names)))); } print "Using group [$group]\n"; if ( $action eq "stop_group" ) { stopGroup(); } elsif ( $action eq "run_group" ) { prepareTestGroups(); preparePorts(); prepareExportList(); prepareFileEndpoints(); runGroup(); } elsif ( $action eq "del_group" ) { if ( $::skip_readers || $::skip_writers ) { deleteGroup(); } else { deleteGroup( $::group ); } } else { die "Unknown action $action:\n$usage"; } #eof