mirror of
https://github.com/Telecominfraproject/wlan-lanforge-scripts.git
synced 2025-10-28 17:32:35 +00:00
The 'use lib' logic happens in the pre-compile stage, so one cannot use normal 'if' logic to use a particular INC. Instead, just make sure that best dir is added to 'use lib' last since it prepends to INC.
410 lines
13 KiB
Perl
Executable File
410 lines
13 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
#
|
|
# Use this script to generate a batch of Generic lfping endpoints
|
|
#
|
|
# Examples:
|
|
# ./lf_generic_ping.pl --mgr 192.168.1.100 --resource 1 --dest 10.1.1.1 -i wlan0 -i sta1 -i eth1
|
|
# You should be able to place 1000 interfaces in the list
|
|
#
|
|
# Or all interfaces on a radio
|
|
# ./lf_generic_ping.pl --mgr $mgr --resource 1 --dest 10.1.1.1 --radio wiphy0
|
|
#
|
|
# Or all macvlan on an ethernet port
|
|
# ./lf_generic_ping.pl --mgr $mgr --resource 1 --dest 10.1.1.1 --parent eth1
|
|
#
|
|
# Or all interfaces matching a prefix:
|
|
# ./lf_generic_ping.pl -m $mgr -r 1 -d 10.1.1.1 --match sta3
|
|
#
|
|
# The default name will be lfping_$endp name, use the --name
|
|
# switch to alter the generic endpoint name, This allows multiple
|
|
# generic connections to be created per port:
|
|
#
|
|
# for n in one two three four five six seven eight nine ten; do
|
|
# ./lf_generic_ping.pl -m 192.168.1.100 -r 1 -d 10.1.1.1 --match sta -name $n
|
|
# done
|
|
package main;
|
|
use strict;
|
|
use warnings;
|
|
use diagnostics;
|
|
use Carp;
|
|
use Data::Dumper;
|
|
$SIG{ __DIE__ } = sub { Carp::confess( @_ )};
|
|
$SIG{ __WARN__ } = sub { Carp::confess( @_ )};
|
|
use Getopt::Long;
|
|
use Cwd qw(getcwd);
|
|
my $cwd = getcwd();
|
|
|
|
# use lib prepends to @INC, so put lower priority first
|
|
# This is before run-time, so cannot condition this with normal 'if' logic.
|
|
use lib '/home/lanforge/scripts';
|
|
use lib "./";
|
|
|
|
use List::Util qw(first);
|
|
use LANforge::Endpoint;
|
|
use LANforge::Port;
|
|
use LANforge::Utils qw(fmt_cmd);
|
|
use Net::Telnet ();
|
|
|
|
our $dest_ip_addr = "0.0.0.0";
|
|
our $log_cli = "unset"; # use ENV{'LOG_CLI'}
|
|
|
|
our $usage = qq(Usage:
|
|
$0 --mgr {host-name | IP}
|
|
--mgr_port {ip port}
|
|
--resource {resource}
|
|
--dest {destination IP}
|
|
--interface|-intf|-int|-i {source interface}
|
|
# You should be able to place 1000 interfaces in the list
|
|
--radio {wiphy} | --parent {eth}
|
|
--match {simple prefix, no stars or questions marks}
|
|
--cmd {"double quoted command"} # can contain special parameters
|
|
--name {prefix to name connection, appended with padded number}
|
|
|
|
Examples:
|
|
$0 --mgr localhost --resource 1 --dest 192.168.0.1 -i wlan0 -i sta3000 --name "wlan_ping"
|
|
This will match just sta3000
|
|
|
|
All interfaces on a parent radio or MAC VLANs on parent Ethernet port:
|
|
$0 --mgr localhost --resource 1 --dest 192.168.0.1 --radio wiphy0
|
|
This will match all stations whos parent is wiphy0: sta3 wlan0
|
|
|
|
$0 --mgr localhost --resource 1 --dest 192.168.0.1 --parent eth1
|
|
This will match all MAC VLANs with parent eth1: eth1#0 eth1#1 eth1#2
|
|
|
|
All interfaces matching a prefix:
|
|
$0 -m localhost -r 1 -d 192.168.0.1 --match sta3
|
|
This will match sta3 sta30 sta31 sta3000
|
|
|
|
Please don't put single quotes in a command. A command can have these expansions:
|
|
%d destination ip or hostname
|
|
%i port IPv4 address
|
|
%p port name
|
|
|
|
Example with curl wrapper provides better feedback to LANforge:
|
|
$0 --mgr cholla-f19 -r 2 -n curl_ex_ --match 'eth2#' \\
|
|
--cmd './scripts/lf_curl.sh -n 10 -o /tmp/curl_%p.out -i %i -p %p -d %d' --dest http://localhost/
|
|
|
|
Example curl command doesn't provide good feedback to LANforge:
|
|
$0 --cmd "curl -sqL --dns-ipv4-addr %i --dns-interface %p \\
|
|
--interface %p --localaddr %i -o /tmp/results-%p http://%d/"
|
|
|
|
The default name of the generic endpoints given will be "lfping_[port]".
|
|
You can create multiple generic connections per port by altering
|
|
the endpoint name with the --name switch.
|
|
Example of creating multiple connections per port in a loop:
|
|
for n in one two three four five six seven eight nine ten; do
|
|
$0 -m localhost -r 1 -d 10.1.1.1 --match sta -name \$n
|
|
done
|
|
|
|
Example iperf3 server on eth1, 10.1.1.2:
|
|
iperf3 --forceflush --format k --precision 4 -s \\
|
|
--bind_dev %p -i 1 --pidfile /tmp/lf_helper_iperf_%p.pid
|
|
|
|
Example iperf3 client on sta0 as 10.1.1.3:
|
|
iperf3 --forceflush --format k --precision 4 -c %d -t 60 --tos 0 -b 1K \\
|
|
--bind_dev %p -i 1 --pidfile /tmp/lf_helper_iperf_%p.pid
|
|
|
|
If only a few of your generic commands start, check journalctl for
|
|
errors containing: 'cgroup: fork rejected by pids controller'
|
|
You want to set DefaultTasksMax=65535 in /etc/systemd/system.conf
|
|
then do a systemctl daemon-reload.
|
|
https://www.novell.com/support/kb/doc.php?id=7018594
|
|
);
|
|
|
|
our $shelf_num = 1;
|
|
our $report_timer = 1000;
|
|
our $test_mgr = "default_tm";
|
|
our $resource = 1;
|
|
our $lfmgr_host = "localhost";
|
|
our $lfmgr_port = 4001;
|
|
our $quiet = "yes";
|
|
our $quiesce = 3;
|
|
our $clear_on_start = 0;
|
|
our $dest_ip;
|
|
our @interfaces = ();
|
|
our $radio = '';
|
|
our $pattern = '';
|
|
our $name_pref = "lfping";
|
|
our $ref_cmd = ''; # user supplied command
|
|
our $ref_name = '';
|
|
our $verbose = ((defined $ENV{'DEBUG'}) && ($ENV{'DEBUG'} eq "1")) ? 1:0;
|
|
my $help;
|
|
|
|
if (@ARGV < 2) {
|
|
print $usage;
|
|
exit 0;
|
|
}
|
|
GetOptions
|
|
(
|
|
'mgr|m=s' => \$::lfmgr_host,
|
|
'mgr_port|p=i' => \$lfmgr_port,
|
|
'resource|r=i' => \$::resource,
|
|
'quiet|q' => \$::quiet,
|
|
'verbose|v' => \$::verbose,
|
|
'radio|parent|o=s' => \$::radio,
|
|
'match=s' => \$::pattern,
|
|
'interface|intf|int|i=s' => \@::interfaces,
|
|
'dest_ip|dest|d=s' => \$::dest_ip,
|
|
'name_pref|name|n=s' => \$::name_pref,
|
|
'cmd|c=s' => \$::ref_cmd,
|
|
'help|h|?' => \$help,
|
|
) || (print($usage), exit(1));
|
|
|
|
#print "radio: $::radio, match: $::pattern, $::quiet, $::resource, $::dest_ip\n";
|
|
|
|
if ($help) {
|
|
print($usage) && exit(0);
|
|
}
|
|
if ($::quiet eq "0") {
|
|
$::quiet = "no";
|
|
}
|
|
elsif ($::quiet eq "1") {
|
|
$::quiet = "yes";
|
|
}
|
|
|
|
# Open connection to the LANforge server.
|
|
if (defined $log_cli) {
|
|
if ($log_cli ne "unset") {
|
|
# here is how we reset the variable if it was used as a flag
|
|
if ($log_cli eq "") {
|
|
$ENV{'LOG_CLI'} = 1;
|
|
}
|
|
else {
|
|
$ENV{'LOG_CLI'} = $log_cli;
|
|
}
|
|
}
|
|
}
|
|
our $t = new Net::Telnet(Prompt => '/default\@btbits\>\>/',
|
|
Timeout => 20);
|
|
$t->open(Host => $lfmgr_host,
|
|
Port => $lfmgr_port,
|
|
Timeout => 10);
|
|
$t->waitfor("/btbits\>\>/");
|
|
|
|
# Configure our utils.
|
|
our $utils = new LANforge::Utils();
|
|
$utils->telnet($t); # Set our telnet object.
|
|
|
|
if ($utils->isQuiet()) {
|
|
if (defined $ENV{'LOG_CLI'} && $ENV{'LOG_CLI'} ne "") {
|
|
$utils->cli_send_silent(0);
|
|
}
|
|
else {
|
|
$utils->cli_send_silent(1); # Do not show input to telnet
|
|
}
|
|
$utils->cli_rcv_silent(1); # Repress output from telnet
|
|
}
|
|
else {
|
|
$utils->cli_send_silent(0); # Show input to telnet
|
|
$utils->cli_rcv_silent(0); # Show output from telnet
|
|
}
|
|
$utils->log_cli("# $0 ".`date "+%Y-%m-%d %H:%M:%S"`);
|
|
|
|
our @ports_lines = split("\n", $::utils->doAsyncCmd("nc_show_ports 1 $::resource ALL"));
|
|
chomp(@ports_lines);
|
|
our %eid_map = ();
|
|
my ($eid, $card, $port, $type, $mac, $dev, $parent, $ip);
|
|
foreach my $line (@ports_lines) {
|
|
# collect all stations on that radio add them to @interfaces
|
|
if ($line =~ /^Shelf: /) {
|
|
$card = undef; $port = undef;
|
|
$type = undef; $parent = undef;
|
|
$eid = undef; $mac = undef;
|
|
$dev = undef;
|
|
$ip = undef;
|
|
}
|
|
|
|
# careful about that comma after card!
|
|
# NO EID for Shelf: 1, Card: 1, Port: 2 Type: WIFI-Radio Alias:
|
|
($card, $port, $type) = $line =~ m/^Shelf: 1, Card: (\d+),\s+Port: (\d+)\s+Type: (\w+)/;
|
|
if ((defined $card) && ($card ne "") && (defined $port) && ($port ne "")) {
|
|
$eid = "1.${card}.${port}";
|
|
my $rh_eid = {
|
|
eid => $eid,
|
|
type => $type,
|
|
parent => undef,
|
|
dev => undef,
|
|
};
|
|
$::eid_map{$eid} = $rh_eid;
|
|
#print "\nfound eid $eid\n";
|
|
}
|
|
#elsif ($line =~ /^Shelf/) {
|
|
# #print "NO EID for $line\n";
|
|
#}
|
|
|
|
if (!(defined $eid) || ($eid eq "")) {
|
|
#print "NO EID for $line\n";
|
|
next;
|
|
}
|
|
($mac, $dev) = $line =~ / MAC: ([0-9:a-fA-F]+)\s+DEV: (\S+)/;
|
|
if ((defined $mac) && ($mac ne "")) {
|
|
#print "$eid MAC: $line\n";
|
|
$::eid_map{$eid}->{mac} = $mac;
|
|
$::eid_map{$eid}->{dev} = $dev;
|
|
}
|
|
|
|
($parent) = $line =~ / Parent.Peer: (\S+) /;
|
|
if ((defined $parent) && ($parent ne "")) {
|
|
#print "$eid PARENT: $line\n";
|
|
$::eid_map{$eid}->{parent} = $parent;
|
|
}
|
|
|
|
($ip) = $line =~ m/ IP: *([^ ]+) */;
|
|
if ((defined $ip) && ($ip ne "")) {
|
|
#print "$eid IP: $line\n";
|
|
$::eid_map{$eid}->{ip} = $ip;
|
|
}
|
|
} # foreach
|
|
|
|
#foreach $eid (keys %eid_map) {
|
|
# print "eid $eid ";
|
|
#}
|
|
|
|
|
|
if (defined $::radio) {
|
|
while (my ($eid, $rh_eid) = each %::eid_map) {
|
|
if ((defined $rh_eid->{parent}) && ($rh_eid->{parent} eq $::radio)) {
|
|
push(@interfaces, $rh_eid->{dev});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (defined $::pattern && $pattern ne "") {
|
|
my $pat = $::pattern;
|
|
$pat =~ s/[+]//g;
|
|
# collect all stations on that resource add them to @interfaces
|
|
while (my($eid, $rh_eid) = each %::eid_map) {
|
|
if ((defined $rh_eid->{dev}) && ($rh_eid->{dev} =~ /$pat/)) {
|
|
push(@interfaces, $rh_eid->{dev});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (@interfaces < 1) {
|
|
print STDERR "One or more interfaces required.\n";
|
|
print $usage;
|
|
exit(1);
|
|
}
|
|
|
|
print "Creating generic lfping endpoints using these interfaces: \n";
|
|
print " ".join(", ", @interfaces)."\n";
|
|
|
|
=pod
|
|
Example of generic created by GUI:
|
|
add_gen_endp test-1 1 3 sta3000 gen_generic
|
|
set_gen_cmd test-1 lfping -p deadbeef -I sta3000 10.41.1.2
|
|
set_endp_quiesce test-1 3
|
|
set_endp_report_timer test-1 1000
|
|
set_endp_flag test-1 ClearPortOnStart 0
|
|
add_gen_endp D_test-1 1 3 sta3000 gen_generic
|
|
set_endp_flag D_test-1 unmanaged 1
|
|
set_endp_quiesce D_test-1 3
|
|
set_endp_report_timer D_test-1 1000
|
|
set_endp_flag D_test-1 ClearPortOnStart 0
|
|
|
|
Parameters that can be replaced:
|
|
%d destination ip or hostname
|
|
%i port IPv4 address
|
|
%p port name
|
|
|
|
curl -sqL --dns-ipv4-addr %i --dns-interface %p --interface %p --localaddr %i -o /dev/null http://%d/
|
|
|
|
=cut
|
|
sub create_generic {
|
|
my ($name, $port_name, $eid)=@_;
|
|
#print "= 1 =====================================================\n";
|
|
#print Dumper($eid);
|
|
my $endp_name = "${name_pref}_${port_name}";
|
|
my $type = "gen_generic";
|
|
my $rh_idr = $::eid_map{$eid};
|
|
my $port_ip = $rh_idr->{'ip'};
|
|
#print Dumper($rh_idr);
|
|
#print Dumper($rh_idr->{'ip'});
|
|
#print "$endp_name PORT_IP $port_ip \n";
|
|
#print "= 2 =====================================================\n";
|
|
my $ping_cmd = "lfping -I $port_name $::dest_ip";
|
|
if ((defined $::ref_cmd) && ($::ref_cmd ne "")) {
|
|
$ping_cmd = $::ref_cmd;
|
|
my $d_ip = '';
|
|
$d_ip = $::dest_ip if (defined $::dest_ip && $::dest_ip ne "");
|
|
$ping_cmd =~ s/%d/$::dest_ip/g if ($ping_cmd =~ /%d/);
|
|
|
|
if (defined $port_name && $port_name ne "") {
|
|
$ping_cmd =~ s/%p/$port_name/g if ($ping_cmd =~ /%p/);
|
|
}
|
|
else {
|
|
print "no name for port $port_name\n";
|
|
return;
|
|
}
|
|
|
|
if (defined $port_ip && $port_ip ne "") {
|
|
$ping_cmd =~ s/%i/$port_ip/g if ($ping_cmd =~ /%i/);
|
|
}
|
|
else {
|
|
print "no ip for port $port_name\n";
|
|
return;
|
|
}
|
|
}
|
|
$::command_map{$eid} = $ping_cmd;
|
|
|
|
print "CMD: $ping_cmd\n" if ($::verbose);
|
|
|
|
$::utils->doCmd($::utils->fmt_cmd("add_gen_endp", $endp_name, 1, $::resource, $port_name, $type));
|
|
$::utils->doCmd("set_gen_cmd $endp_name $ping_cmd");
|
|
$::utils->doCmd("set_endp_quiesce $endp_name $::quiesce");
|
|
$::utils->doCmd("set_endp_flag $endp_name ClearPortOnStart $::clear_on_start");
|
|
$::utils->doCmd("set_endp_report_timer $endp_name $::report_timer");
|
|
|
|
# we also need to add the opposite unmanaged endpoint
|
|
$::utils->doCmd("add_gen_endp D_$endp_name 1 $::resource $port_name gen_generic");
|
|
$::utils->doCmd("set_endp_flag D_$endp_name unmanaged 1");
|
|
$::utils->doCmd("set_endp_quiesce D_$endp_name $::quiesce");
|
|
$::utils->doCmd("set_endp_flag D_$endp_name ClearPortOnStart $::clear_on_start");
|
|
$::utils->doCmd("set_endp_report_timer D_$endp_name $::report_timer");
|
|
|
|
# tie the knot with a CX
|
|
$::utils->doCmd("add_cx CX_$endp_name default_tm $endp_name D_$endp_name");
|
|
$::utils->doCmd("set_cx_report_timer default_tm CX_$endp_name $::report_timer cxonly");
|
|
}
|
|
|
|
#print Dumper(\@interfaces);
|
|
#print Dumper(\%::eid_map);
|
|
our %command_map = ();
|
|
my @map_keys = sort keys %eid_map;
|
|
for my $port (sort @interfaces) {
|
|
my $endp_name = "${name_pref}_$port";
|
|
my $matching_eid = "";
|
|
#print "Searching for port $port ";
|
|
#while (my ($eid, $rh_pid) = each %eid_map) {
|
|
for my $eid (@map_keys) {
|
|
my $rh_pid = $eid_map{$eid};
|
|
#print " $port/$rh_pid->{dev} ";
|
|
if ("$port" eq "$rh_pid->{dev}") {
|
|
#print " ** ";
|
|
$matching_eid = $eid;
|
|
last;
|
|
}
|
|
}
|
|
if ($matching_eid eq "") {
|
|
print "\nSkipping $port no eid [$matching_eid]\n";
|
|
next;
|
|
}
|
|
#print "\n= 3 =====================================================\n";
|
|
#print " $matching_eid => ".$eid_map{$matching_eid}->{dev}."\n";
|
|
#print Dumper($eid_map{$matching_eid});
|
|
#print "= 4 =====================================================\n";
|
|
|
|
|
|
if (! (defined $eid_map{$matching_eid}->{ip})
|
|
|| $eid_map{$matching_eid}->{ip} eq ""
|
|
|| $eid_map{$matching_eid}->{ip} eq "0.0.0.0") {
|
|
print "\nSkipping $port: ".$eid_map{$matching_eid}->{ip}."\n";
|
|
sleep 1;
|
|
next;
|
|
}
|
|
create_generic($endp_name, $port, $matching_eid);
|
|
}
|
|
#print Dumper(\%command_map);
|
|
|
|
#
|