Candela Technologies Logo
Network Testing and Emulation Solutions

LANforge Scripting Cookbook

The LANforge Scripting Cookbook provides a series of detailed examples of how to craft testing scripts for unattended/automated operation. Each example intends to give the reader a runnable test script and a better understanding of how to use the LANforge Scripting.

Places to Run CLI Commands

You do not need to operate scripts directly from the LANforge server, and this allows you to code scripts in your preferred text editing environment. Likewise, you do not need to run a copy of LANforge Server on your desktop. Scripts will create a plain-text connection to the LANforger server you specify.

Windows Desktop
You can install a copy of the LANforge Server on your windows desktop (without a license) so that you have access to the Perl scripting libraries. Edit scripts and run them from your C:\Program Files\LANforge-Server\scripts directory.
Linux Desktop
You can copy the LANforge scripts folder directly from your LANforge server to your Documents directory with scp.
SSH or VNC connection to LANforge Server
Using vncviewer, rdesktop or ssh are all fine options to connect to the LANforge server to write and operate scripts. The LANforge server comes with a basic Linux desktop and you can use emacs, vim, pluma, or gedit text editors installed by default. When editing scripts on the LANforge server itself, be careful to back up your work before you upgrade LANforge. The LANforge install process will over-write scripts of the same name in the scripts directory.

Requirements for Scripts

Your desktop (or other computer) running CLI scripts needs to have a reliable (wired) connection to the management port of your LANforge server. If you are engaging in long running tests, you might consider running the scripts from the LANforge manager itself if your desktop machine needs to be powered off.

Script Libraries
CLI scripts are written using Perl. They require the libraries in /home/lanforge/scripts/LANforge Users may write scripts in other programming languages, such as python, but in that case, they will not be able to take direct avantage of the Perl scripts included in LANforge.
On Windows
LANforge is more fully featured on Linux, but basic support exists on Windows as well.

You can run CLI scripts from any Windows desktop as long as you have Perl installed. You can use ActiveState Perl or Perl from the Cygwin project. We also highly suggest installing PuTTY ssh client to access your LANforge server.

On Linux/OS X
Most Linux distributions come with and ssh client and Perl already installed.
LANforge Server Requirements
The following examples will create test scenarios that work on LANforge Linux systems running the LANforge software with the LANforge kernel and a sufficient license. If you are running LANforge server using another Linux kernel, you may not be able to operate some of the examples. (Features like Armageddon, operation of WiFi-AC radios, and WanLinks all require drivers included only in Candela provided kernels.)

Please contact us at support@candelatech.com if you have any questions.

Before Starting LANforge-CLI Traffic Generation

Before attempting the examples below, ensure that you have successfully followed these software installation guides:

It is also recommended that you back up your current running LANforge Server database so that you may safely return to your current operating state.

For instance:
     su - root
     cd /home/lanforge
     tar -cvzf my_db_backup.tar.gz DB
     

LANforge-CLI Detailed Cookbook Examples

  1. Basics: Introduction
  2. Basics: Operating LANforge scripts from Windows
  3. Perl: Monitor and Reset Ports with the portmod Script
  4. Perl: Cross Connects and Endpoints Tutorial
  5. Perl: Creating Connections with the FIREmod Script
  6. Perl: Operating Endpoint Hunt Scripts with the CLI
  7. Perl: Generating WiFi Traffic with the Associate Script
  8. Perl: Changing Station WiFi SSID with the CLI API
  9. CLI: Changing Station POST_IFUP Script with the CLI API
  10. CLI: Scripting Attenuation with CSV data
  11. Basics: LANforge Entity IDs
  12. JSON: Querying the LANforge GUI for JSON Data
  13. CLI: Station CLI Operations
  14. Basics: Generic Endpoint Scripts
  15. Perl: Chamber View: Automated tests with script
  16. JSON: Querying the LANforge JSON API using Python
  17. JSON: Managing WANlinks using JSON and Python
  18. Perl: Control a chamber with the lf_chamber.pl Script
  19. Perl: Emulating Video Transmission with Layer 3 connections

Introduction to CLI Scripts

Goal: You will be able to execute LANforge testing scripts from the command line from Windows, Linux, remote desktop or ssh connection.

Traffic emulation may be run unattended and automated using Perl scripts provided with the LANforge Server. These scripts can be run from within the LANforge server or outside the LANforge Server (on a Windows or other desktop). The output of the scripts should be redirected into a text file for you to process the results.

Where Do I Find Scripts?

On Windows

On most versions of windows, the LANforge Server installs scripts in

C:\Program Files (x86)\LANforge-Server\scripts

On Linux

In the home directory for user LANforge:

/home/lanforge/scripts

How to Run Scripts

Starting a script on Windows:
  1. Make sure that perl is in your PATH. (See Inspecting DOS PATH)
  2. Open a CMD window (or a PowerShell window)
  3. and change directory to C:\Program Files (x86)\LANforge-Server\scripts
  4. Type perl .\script_name.plENTER to run the script.
Generally, the script will tell you that it needs more switches.
Finding Help
Most scripts have a -h or --help switch that explain what switches they expect.
Script Conventions
In general, scripts will expect you to tell them a few things, regardless of the script:
  • The manager IP address to connect to:--mgr 127.0.0.1 or --manager 192.168.100.1. This often defaults to 127.0.0.1, but when connecting from outside the machine, please use the IP of the LANforge management port (often eth0).
  • The manager port to connect to:--port 4001 or --mgr_port 4001. This often defaults to 4001.
  • Which resource to direct the command to. The manager is always resource 1. Resource 2 would be your second LANforge server. --resource 2. Some scripts use the older term card: --card
  • If you need debugging output, turn off quiet mode: -q no or --quiet no. Some older scripts want you to turn quiet on explicitly: --quiet 1
  • To capture the output, use the > operator to redirect the text output into a text file.
  • Scripts are often executed from within a shell script (or batch file). Often the formatting of the commands includes '\' characters which indicate 'continue this command on the next line of input.' Here is an example of formatting a single script command on multipl lines:
     $ ./lf_portmod.pl \
       --manager 192.168.100.1 \
       --card 3 \
       --show_port
  • Comments begin with '#'. They are lines ignored by the shell, and they are also comments in perl.
Running on local LANforge manager
You can use ssh, VNC or Rdesktop to connect from your desktop to your LANforge manager server. (When using VNC, assume display :1). From there, in a terminal, you will execute your script from the /home/lanforge/scripts directory as shown in the example below:
 $ cd /home/lanforge/scripts
 $  ./lf_portmod.pl --help
#...help appears...
 $ ./lf_portmod.pl --manager 192.168.100.1 --card 1 --show_port
# ... displays port info
         
Running on local LANforge resource
If you connect to a LANforge resource and want to run a script, you must direct the script at the LANforge manager server and specify the resource you are interested in. For example, you might be on resource 2 (192.168.100.2) and desire to run tests on resource 3 (192.168.100.3):
 $ cd /home/lanforge/scripts
 $  ./lf_portmod.pl --manager 192.168.100.1 --card 3 --show_port
# ... displays port info
Running on a Linux Desktop to a Remote LANforge
A more detailed set of steps follows. When running LANforge CLI scripts on a Linux desktop, you normally want to download and un-zip a copy of the LANforge-Server install file found on the Candela Technologies downloads page. Use a link similar to: http://www.candelatech.com/private/downloads/r5.3.2/LANforgeServer-5.3.2_Linux-F21-x64.tar.gz. For best results, use the scripts packaged with the version of LANforge to which your scripts will be connecting.
  1. Open a terminal on your desktop, cd to your Downloads folder
  2. use wget or curl to download the tar file:
     wget "http://guest:guest@www.candelatech.com/private/downloads/r5.3.2/LANforgeServer-5.3.2_Linux-F21-x64.tar.gz"
  3. Create a scripts directory in your Documents folder:
     $ cd ~/Documents/scripts
  4. Expand the tar file in your Downloads directory:
     $ tar xf LANforgeServer*tar.gz
  5. Copy the scripts file into your Documents folder:
     $ cp -r LANforgeServer-5.3.2/scripts/. ~/Documents/scripts/

To use your scripts, in your terminal, change directories to ~/Documents/scripts and they will operate similar to the above examples.

 $ cd ~/Documents/scripts
 $ ./lf_portmod.pl --manager 192.168.100.1 --card 3 --show_port
Running on a Windows Desktop to a Remote LANforge
The process for running CLI scripts on a Windows desktop is roughly similar, but involves running the Windows LANforge Server installer. This process does not require a Windows license as we will not be running the windows LANforge server. Perl is required to run Windows scripts. Start by installing that. You can use the perl that comes with the Cygwin project or if you just want perl, install the ActiveState ActivePerl package. ActivePerl should install update your environment %PATH% variable. If it does not immediately, you might need to log out and log back in.
  1. Download the Windows version of the LANforge Server installer using your browser: http://www.candelatech.com/private/downloads/r5.3.2/LANforge-Server-5.3.2-Installer.exe. Use username guest, password guest.
  2. In your Downloads folder, double click and install the LANforge-Server-Installer.exe. Do not configure it, do not run LANforgeServer. You will not need to be running the LANforge GUI to do this install.
  3. The installation scripts folder will be system-protected, so you want to copy the folder over to your desktop Documents directory.
  4. Open a DOS terminal, either using Run→cmdEnter or Run→powershellEnter
  5. Change to the new copy of the scripts directory, and then you can run scripts by giving them to perl:
     C:> cd C:\Users\bob\Documents\scripts
     C:> perl .\lf_portmod.pl --manager 192.168.100.1 --card 3 --show_port --port_name eth1 --quiet 1
  6. To capture output from a script, use the shell redirect operator: >. This example shows redirecting and browsing the results with Notepad:
     C:> perl .\lf_portmod.pl --manager 192.168.100.1 --card 3 --show_port --port_name eth1 --quiet 1 > results.txt
     C:> notepad.exe results.txt

Operate LANforge Scripts from Windows.

Goal: Use an installation of LANforge and Perl on a Windows computer to operate tests and manage connections on remote LANforge computers.

You do not need to connect to your LANforge manager using ssh or VNC to manage connections or operate tests. In this cookbook, you will see an example of using the lf_firemod.pl script which can give you port information. This example will require a Windows desktop with Java, ActiveState Perl, the LANforge Server and the LANforge GUI installed. You will not need to start the LANforge server on your Windows computer, so no licenses will be required for operating on the Windows computer. This cookbook assumes connectivity between the Windows computer and a running LANforge manager computer.
 
  1. Prepare your Windows computer:
  2. Install LANforge Server
    1. You do not need to configure or start this server. Only the perl scripts directory of this installation will be used.
    2. You can download it from our current releases page.

      For more information see LANforge Server Installation

  3. Install LANforge GUI
    1. You can download it from the same location.
    2. Make sure you can connect to your LANforge manager. In this example, the LANforge manager will be at 192.168.100.26
    3. Open the LANforge GUI screenshot
    4. ... and click Discover screenshot
    5. If you are able to connect you should be able to browse your ports and connections. screenshot

    For more information see LANforge GUI Installation

  4. Install ActiveState Perl
    1. Please download it from the ActiveState downloads page.
    2. Begin and press next... screenshot
    3. ...press next... screenshot
    4. ...press next... screenshot
    5. ...and then wait a few minutes... screenshot
    6. Now, you are done, press Finish. screenshot
    7. For advanced GUI scripting in Windows, you may also wish to view the Win32::GuiTest perl module page.
  5. Using scripts from Windows
    1. The scripts installed on your Windows computer will communicate with the LANforge manager over the management port (TCP 4001).
    2. Open a cmd window. Click Start->Run, type cmd and press Enter
      1. screenshot
      2. screenshot
    3. Change directory to C:\Program Files\LANforge-Server\scripts screenshot
    4. List the script files: dir *.pl screenshot
    5. Your installation of Perl should have put it into your path variable (%PATH%). Please verify that it did with this command: perl -v screenshot
    6. If perl is not found (Command not found) then you might need to close your DOS window and open a new one, or your Windows computer might need a reboot for the PATH variable to take effect.
    7. Start the lf_firemod.pl script with the --help switch to see the options. screenshot
      1. perl lf_firemod.pl --help
    8. Open a second cmd window so that you can see the help text in the first window. Change directory to C:\Program Files\LANforge-Server\Scripts
    9. Use this command to list ports available on 192.168.100.26:
      1. perl lf_firemod.pl --mgr 192.168.100.26 --resource 1 --action list_ports
      2. screenshot
    10. Most command output shows considerably more text than the output of the previous command. You may want to pipe it to a file. In this example, the output is redirected to C:\tmp\port-vap0.txt and shown with Notepad.
      1. Query the port stats using: perl lf_firemod.pl --mgr 192.168.100.26 --resource 1 --action show_port --port vap0 > c:\tmp\port-vap0.txt screenshot
      2. Show the output with: notepad c:\tmp\port-vap0.txt screenshot

Inspecting Ports (Network Interfaces) using lf_portmod

Goal: You will be able to report and reset ports on your LANforge server.

Port statistics can be programatically monitored using the script lf_portmod.pl. This script can also reset ports, alter WiFi station settings, and pass arbitrary LANforge CLI commands directly to the LANforge manager.

Ports of all kinds can be viewed with the lf_portmod.pl perl script. You can also do some limited manipulation of ports as well.

Listing Ports
You can show statistic on a port with the --show_port argument:
 C:\> perl .\lf_portmod.pl --quiet 1 --manager jedtest --card 1 --port_name eth1 --show_port
You can right-click to paste these commands into your DOS window
Produces:
Listing Port Attributes
Individual port attributes can also be shown, which often makes automating reporting easier.
perl .\lf_portmod.pl --manager jedtest --card 1 --quiet 1 --port_name eth1 --show_port "RxDrop,Rxp,IP"
Produces: Consider that is a lot of text to type. If we want, we can reformat that command.
Long DOS commands and be continued on the next line with the ^ character.
perl .\lf_portmod.pl --manager jedtest ^
 --card 1 --quiet 1 --port_name eth1 ^
 --show_port "RxDrop,Rxp,IP"
Produces the same output:
Loading a test scenario
Saved test scenarios are often referred to as 'databases'
lf_portmod.pl --load day_238
This matches the same database name seen in the Status tab database dropdown.
Admin-down a port
lf_portmod.pl --manager 192.168.1.101 --card 1 --port_name eth2 --set_ifstate down
Resetting a Port
Resetting a port forces a port to unload and reload its configuration.
lf_portmod.pl --manager 192.168.1.101 --card 1 --port_name eth2 --cmd reset
Sending a specific CLI command to the LANforge manager:
It is possible to directly pass a command to the LANforge manager:
lf_portmod.pl --manager 192.168.1.101 --cli_cmd "scan 1 1 sta0"

Cross Connects and Endpoints Tutorial

Goal: Gain a better understanding on how you will use Cross connects, Connections and Endpoints to use the LANforge CLI scripts knowlegably.

Creating connections in the LANforgeGUI implies creating endpoints. These endpoint entities are created with predictable names and are usually created in pairs. Understanding these naming conventions and how they are created is fundamental to your proficiency with creating connections with LANforge CLI scripts.

Most examples in our cookbooks assume a dual-ended connection, also known as a cross-connect or abbreviated as CX.

Building Endpoints and Connections

Let's follow the creation of a Connection:

Using a terminal on the LANforge machine, we look at the /home/lanforge/DB/DFLT/endps.db file and inspect the commands issued that create that connection:

That's a lot of commands. We will point out what is particularly necessary when using our Perl scripts.

Endpoints and Connections Naming Convention

The connection we created above is named tutorial-cx. Two endpoints also have names, tutorial-cx-A and tutorial-cx-B. The A-side of a connection is always managed. A B-side endpoint may be unmanaged. When you write CLI scripts that create connections, name your endpoints using a similar convention.

Endpoints are Created First

We can use the lf_firemod.pl script to create endpoints and a cross connect in this order:

$ ./lf_firemod.pl --action create_endp --endp_name tutorial2-cx-A \
      --speed 256000 --endp_type lf_tcp --port_name sta301

$ ./lf_firemod.pl --action create_endp --endp_name tutorial2-cx-B \
      --speed 256000 --endp_type lf_tcp --port_name eth1

$ ./lf_firemod.pl --action create_cx --cx_name tutorial2-cx \
      --cx_endps tutorial2-cx-A,tutorial2-cx-B

We can see the results of those script commands in our Layer-3 and L3 Endps tabs:

Multiple Windows can be displayed using the Tear Offs menu.
Clicking on the Layer-3 connection automatically highlights the two endpoints.

Starting and Stopping: Connections have State

When a connection is first created, it is STOPPED. When you start it, it becomes RUNNING. When you set a connection to STOPPED, both endpoints immediately stop sending and recieving. That can have a consequence of leaving unacknowledged packets in flight. The safest way is to QUIECE the connection, which first stops the endpoints transmitting, waits a short time, and then stops the endpoints from recieving.

When there is just one Endpoint

Normally, if you see one endpoint, it should only be a multicast endpoint. A single endpoint can be seen in these situations:

  • You have paused between creating the first and second endpoint for a connection. Continue working.
  • Created by a script mistakenly, through a typo or other misconfiguration
  • Left over from an interrupted script that deleted the cross-connect and one of two endpoints

A single endpoint is not an illegal entity, but lonely endpoints can add confusion. If you find endpoints that do not match any existing connections, we suggest deleting them.

A Cross-Connect can be one-sided, that is, have one unmanaged endpoint. The A side endpoint is a LANforge managed port transmitting to another device that's not a LANforge machine. Some connection types create this style of endpoint pairs, like File-endpoints and Layer 4-7 connections.

Multicast

Multicast endpoints are created differently both in the GUI and in the CLI scripting environment. This tutorial does not focus on multicast, but see the section Creating Endpoints section of Creating Connections with FIREMod Script and the chapter on WiFi Multicast Download.

Creating Connections with the FIREmod Script

Goal: Create, destroy, start and stop connections and endpoints without needing to use the LANforge GUI.

Traffic emulation can be run unattended and using automated tools without use of the LANforgeGUI using Perl scripts provided with the LANforge Server. These scripts can be run from within the LANforge server or outside the LANforge Server (on a Windows desktop). The output of the scripts needs to be redirected into a text file for you to process the results.

Script Capabilities

The lf_firemod.pl script has a lot of options because endpoints have a lot of features. Basic actions:

  • Creating and Deleting Endpoints and Cross Connects: create_endp, delte_endp, create_cx, delete_cx
  • Modifying an Endpoints TX Speed: set_endp
  • Listing and Monitoring Ports, Endpoints and Cross Connects: list_ports, show_endp, list_cx, show_cx
  • Reporting on Ports, Endpoints and Cross Connects: show_port, show_endp, show_cx
  • Controlling Traffic: do_cli, start_endp, stop_endp. To start bi-directional traffic, start both endpoints.
  • Pass direct CLI commands: do_cmd. Use this to help configure aspects of your testing scenario that are options presented in this script. Like secondary IPs on a port.

Creating a basic cross connect requires two endpoints, and each endpoint requires a port (network interface). Script options often begin by stating the manager, resource and action:

C:\> perl .\lf_firemod.pl --mgr 192.168.100.1 --resource 2 --action create_endp ...more options...

Script Actions, arguments to --action

Creating Endoints: create_endp

We use these parameters when creating and endpoint:

--endp_name
name this endpoint
--port_name
name of the port this endpoint uses
--speed
speed of the endpoint transmission in bps
--tos
type of service
--max_speed
Maximum port speed if different than minimum speed of port, in bps
--endp_type
Endpoint Types: tcp, udp, tcp6, udp6. To create multicast endpoint types, use mc_udp and mc_udp6.
--min_pkt_sz/--max_pkt_sz
Minimum and maximum packet sizes
--use_csums
Enable checksums
--ttl
packet Time To Live
--report_timer
the update interval for the endpoint

Example of creating a tcp connection endpoint with debugging:

 lf_firemod.pl   --action create_endp \
   --mgr 192.168.45.34        --mgr_port 4002 \
   --endp_name web_1          --speed 154000 \
   --endp_type tcp            --port_name eth1 \
   --quiet no

Creating a multicast udp connection:

 lf_firemod.pl   --action create_endp \
   --mgr 192.168.45.34        --mgr_port 4002 \
   --endp_name mcast_xmit_1   --speed 154000 \
   --endp_type mc_udp         --mcast_addr 224.9.9.8 --mcast_port 9998 \
   --rcv_mcast NO             --port_name eth1 \
   --min_pkt_sz 1072          --max_pkt_sz 1472 \
   --use_csums NO             --ttl 32 \
   --quiet no                 --report_timer 1000 

Create a connection with specific test-manager

 lf_firemod.pl  --action create_endp \
   --mgr 192.168.45.34     --mgr_port 4002 \
   --endp_name web_1       --speed 154000 \
   --endp_type tcp         --port_name eth1 \
   --quiet no              --test_manager web_tm

Show Endpoint Stats: show_endp

By default, using the show_endp action shows all endpoints. It might be useful to place output like this right into a file or to immediate use grep to find the rows you want.

 $ ./lf_firemod.pl --action show_endp --mgr cholla-f19

 RSLT: 0  Cmd: 'nc_show_endp'


FileEndp [e2#0-nfs-100] (NOT_RUNNING, WRITING, WRITE_RATE_BURSTY, CHECK_MOUNT, AUTO_MOUNT, UN_MOUNT, O_TRUNC)
     Shelf: 1, Card: 1  Port: 10  Endpoint: 1  Type: FILE_NFS  Pattern: INCREASING
     MinWriteRate: 1544000bps  MaxWriteRate: 0bps  MinRead/WriteSz: 4096B  MaxRead/WriteSz: 32768B
     MinReadRate:  1544000bps  MaxReadRate:  1544000bps  QuiesceAfterFiles: -1
     NumFiles: 2  MinFileSize: 26214400B  MaxFileSize: 26214400B
     Directory: AUTO  Prefix: AUTO  Volume:
     Server-Mount: 10.41.0.1:/tank/tmp  Mount-Dir: AUTO  Mount-Options:
     RptTimer: 1000ms  RunningFor: 0s  StopIn: 0s  Quiesce: 3
     LastRpt: 0.000 secs ago     RealWriteRate: 0bps   RealReadRate: 0bps
     RetryTimer: 1000ms  InFailedIO: 0ms
       Buffers Read:     Total: 0           Time: 0s    Cur: 0         0/s
       Bytes Read:       Total: 0           Time: 0s    Cur: 0         0/s
       Files Read:       Total: 0           Time: 0s    Cur: 0         0/s
       Bytes Written:    Total: 0           Time: 0s    Cur: 0         0/s
       Buffers Written:  Total: 0           Time: 0s    Cur: 0         0/s
       Files Written:    Total: 0           Time: 0s    Cur: 0         0/s
       Read CRC Failed:  Total: 0           Time: 0s    Cur: 0         0/s

FileEndp [e2#0-nfs-101] (NOT_RUNNING, WRITING, WRITE_RATE_BURSTY, CHECK_MOUNT, AUTO_MOUNT, UN_MOUNT, O_TRUNC)
     Shelf: 1, Card: 1  Port: 12  Endpoint: 2  Type: FILE_NFS  Pattern: INCREASING
     MinWriteRate: 1544000bps  MaxWriteRate: 0bps  MinRead/WriteSz: 4096B  MaxRead/WriteSz: 32768B
     MinReadRate:  1544000bps  MaxReadRate:  1544000bps  QuiesceAfterFiles: -1
     NumFiles: 2  MinFileSize: 26214400B  MaxFileSize: 26214400B
     Directory: AUTO  Prefix: AUTO  Volume:
     Server-Mount: 10.41.0.1:/tank/tmp  Mount-Dir: AUTO  Mount-Options:
     RptTimer: 1000ms  RunningFor: 0s  StopIn: 0s  Quiesce: 3
     LastRpt: 0.000 secs ago     RealWriteRate: 0bps   RealReadRate: 0bps
     RetryTimer: 1000ms  InFailedIO: 0ms
       Buffers Read:     Total: 0           Time: 0s    Cur: 0         0/s
       Bytes Read:       Total: 0           Time: 0s    Cur: 0         0/s
       Files Read:       Total: 0           Time: 0s    Cur: 0         0/s
       Bytes Written:    Total: 0           Time: 0s    Cur: 0         0/s
       Buffers Written:  Total: 0           Time: 0s    Cur: 0         0/s
       Files Written:    Total: 0           Time: 0s    Cur: 0         0/s
       Read CRC Failed:  Total: 0           Time: 0s    Cur: 0         0/s

You can redirect all output into a file:

 $ ./lf_firemod.pl --action show_endp --mgr cholla-f19 > /var/tmp/endp-stats.txt 

It is possible to print out one-word attributes, such as MaxWriteRate tx_bps or rx_bps:

./lf_firemod.pl --mgr 127.0.0.1 --quiet 1 --action show_endp --endp_name cx_0-B --endp_vals tx_bps,rx_bps
Rx Bytes: 99938104
Tx Bytes: 99993112

Configure Endpoint: set_endp

This is for changing the attributes of an endpoint, such as endpoint TX rate.

 $ ./lf_firemod.pl --mgr cholla-f19 --action set_endp --endp_name cx_0-A --speed 2000000

Show Port Stats: show_port

This is pretty useful for getting transmit rate on ports during a connection while not having to use the lf_portmod script. If you do not specify --port_name, all ports will be listed.

 $ ./lf_firemod.pl --action show_port --mgr cholla-f19 --port_name eth2#0

Shelf: 1, Card: 1, Port: 10  Type: MacVLAN  Alias:
  Win32-Name:   Win32-Desc:   Parent/Peer: eth2  Rpt-Timer: 8000  CPU-Mask: 0
   Current:	UP LINK-UP TSO UFO GSO GRO PROBE_ERROR
   Supported:	UP SEND_TO_SELF
   Partner:	UP
   Advertising:	10bt-HD 10bt-FD 100bt-HD 100bt-FD 1000-FD TSO-ENABLED UFO-ENABLED GSO-ENABLED GRO-ENABLED
   IP: 10.41.0.10  MASK: 255.255.255.0  GW: 0.0.0.0  VID: 0  ResetState: COMPLETE
   DNS Servers:
   IPv6-Global: DELETED
   IPv6-Link: fe80::a00:27ff:fe09:183d/64
   IPv6-Gateway: DELETED
   MAC: 08:00:27:09:18:3d  DEV: eth2#0  MTU: 1500  TX Queue Len: 0
   LastDHCP: 0ms  Driver: macvlan Tx-Rate: 1000000Kbps
   Bus-Speed: 0/0  Bus-Width: 0/0
   Bridge-Port-Cost: Ignore  Prio: Ignore  Aging: 0
   DHCP-Client-ID: NONE  DHCP-Vendor-ID: NONE
     pps_tx: 0  pps_rx: 0  bps_tx: 0  bps_rx: 0
     Rxp: 5652  Txp: 21  Rxb: 1932984  Txb: 1826  RxERR: 0  TxERR: 0
     RxDrop: 0  TxDrop: 0  Multi: 5652  Coll: 0  RxLenERR: 0  RxOverFlow: 0
     RxCRC: 0  RxFrame: 0  RxFifo: 0  RxMissed: 0  TxAbort: 0  TxCarrier: 0
     TxFifo: 0  TxHeartBeat: 0  TxWindow: 0  RxBytesLL: 2068632  TxBytesLL: 2330

      

List Ports, action: list_ports

This is the same as --show_port without the port_name option.

Direct LANforge Command: do_cmd

In case you wanted to pass a CLI command directly in. Below is an example of setting the TOS flag for an endpoint:

C:\> perl .\lf_firemod.pl --mgr 192.168.100.1 --action do_cmd \
   --cmd "set_endp_tos cx_01-A LOWDELAY 10"

See the LANforge CLI User Guide for more info.

Remove endpoint: delete_endp

Remember to remove the cross connect before removing the endpoint.

 $ ./lf_firemod.pl --action delete_endp  --mgr cholla-f19 --endp_name cx-0-A

Create Cross-connect: create_cx

First you want to create two endpoints. You will add those endpoints to your cross connect. This example below shows all three steps:

 $ ./lf_firemod.pl --action create_endp --mgr cholla-f19 --port_name eth2#0 \
      --endp_name cx_0-A --speed 1000000 --endp_type tcp --min_pkt_sz 1462 --report_timer 1000

 $ ./lf_firemod.pl --action create_endp --mgr cholla-f19 --port_name eth2#1 \
      --endp_name cx_0-B --speed 1000000 --endp_type tcp --min_pkt_sz 1462 --report_timer 1000

 $ ./lf_firemod.pl --action create_cx --mgr cholla-f19 --cx_name  cx_0 \
      --cx_endps cx_0-A,cx_0-B --report_timer 1000

Below we see the endpoints created: and the CX details screen:

Show Cross Connects: list_cx

This shows the cross connects and their enpoints:

 $ ./lf_firemod.pl --action list_cx --mgr cholla-f19
CX cx_0, endpoint cx_0-A, endpoint cx_0-B

Show Cross Connect Stats: show_cx

The output of this command begins with the basic stats for the CX and includes the statistics of each endpoint.

$ ./lf_firemod.pl --action show_endp  --mgr cholla-f19 --endp_name cx_0-A
 LANFORGE_TCP CX:  cx_0  id: 12  type: LANFORGE_TCP  DesiredState: UN_INITIALIZED RealState: STOPPED
   tx_endpoint: cx_0-A  rx_endpoint: cx_0-B report_timer: 1.000000s  TestMgr: default_tm

Endpoint [cx_0-A] (NOT_RUNNING, FIXED_PLD_SIZE, RATE_BURSTY, IP_PORT_AUTO)
     Shelf: 1, Card: 1  Port: 10  Endpoint: 11 Type: LANFORGE_TCP  Pattern: INCREASING
     MinTxRate: 1000000bps  MaxTxRate: 1000000bps  MinPktSize: 1462B  MaxPktSize: 1462B
     DestMAC: 08:00:27:69:1a:3d  DestIpAddr: 10.41.0.11  DestIpPort: 0  Quiesce: 3
     SrcMAC:  08:00:27:09:18:3d  SrcIp:  0.0.0.0  IpPort:  0-0  IpTOS: DONT-SET  Priority: 0
     Role: CONNECT  RptTimer: 1000ms  RunningFor: 0s  StopIn: 0s  Avg-Jitter: 0ms
     Latency: 0 -:0:- 0  [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] (1)
     Pkt-Gaps: 0 -:0:- 0  [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] (1)
     Last-Rpt: 0.000 secs ago  RealTxRate: 0bps  RealRxRate: 0bps  TTL: 0  Conn-Timeout: 10000
     FileName:   SendBadCrc: 0  RcvBuf: 0  SndBuf: 0  CWND: 0 SND-MSS: 0
     RxDrop%-SEQ:  0.0000  RxDrop%-CX: 0.0000  Conn-Timer: -1-0ms  Conn-Pause: 0-0ms
     PktsToSend: 0
  Multi-Conn: 0  Active-Connections: 0  Files-Played: 0
     RunningInGroup: NONE  Script-steps-completed: 0  Steps-Failed: 0
     First-Rx: -1ms  Mcast-Source: 0.0.0.0:0
       Rx Pkts:            Total: 0           Time: 60s   Cur: 0         0/s
       Rx Pkts (On Wire):  Total: 0           Time: 60s   Cur: 0         0/s
       Rx Bytes:           Total: 0           Time: 60s   Cur: 0         0/s
       Rx Bytes (On Wire): Total: 0           Time: 60s   Cur: 0         0/s
       Rx OOO Pkts:        Total: 0           Time: 60s   Cur: 0         0/s
       RX Wrong Dev:       Total: 0           Time: 60s   Cur: 0         0/s
       RX CRC Failed:      Total: 0           Time: 60s   Cur: 0         0/s
       RX Bit Errors:      Total: 0           Time: 3s    Cur: 0         0/s
       Rx Dropped Pkts:    Total: 0           Time: 3s    Cur: 0         0/s
          Cx Detected:     0
       Rx Duplicate Pkts:  Total: 0           Time: 60s   Cur: 0         0/s
       Tx Pkts:            Total: 0           Time: 60s   Cur: 0         0/s
       Tx Pkts (On Wire):  Total: 0           Time: 60s   Cur: 0         0/s
       Tx Bytes:           Total: 0           Time: 60s   Cur: 0         0/s
       Tx Bytes (On Wire): Total: 0           Time: 3s    Cur: 0         0/s
       Tx Failed Pkts:     Total: 0           Time: 60s   Cur: 0         0/s
       Tx Failed Bytes:    Total: 0           Time: 60s   Cur: 0         0/s
       Conn Established:   Total: 0           Time: 30s   Cur: 0         0/s
       TCP Retransmits:    Total: 0           Time: 3s    Cur: 0         0/s
       Conn Timeouts:      Total: 0           Time: 30s   Cur: 0         0/s

Endpoint [cx_0-B] (NOT_RUNNING, FIXED_PLD_SIZE, RATE_BURSTY, IP_PORT_AUTO)
     Shelf: 1, Card: 1  Port: 12  Endpoint: 12 Type: LANFORGE_TCP  Pattern: INCREASING
     MinTxRate: 1000000bps  MaxTxRate: 1000000bps  MinPktSize: 1462B  MaxPktSize: 1462B
     DestMAC: 08:00:27:09:18:3d  DestIpAddr: 10.41.0.10  DestIpPort: 0  Quiesce: 3
     SrcMAC:  08:00:27:69:1a:3d  SrcIp:  0.0.0.0  IpPort:  0-0  IpTOS: DONT-SET  Priority: 0
     Role: ACCEPT  RptTimer: 1000ms  RunningFor: 0s  StopIn: 0s  Avg-Jitter: 0ms
     Latency: 0 -:0:- 0  [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] (1)
     Pkt-Gaps: 0 -:0:- 0  [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] (1)
     Last-Rpt: 0.000 secs ago  RealTxRate: 0bps  RealRxRate: 0bps  TTL: 0  Conn-Timeout: 10000
     FileName:   SendBadCrc: 0  RcvBuf: 0  SndBuf: 0  CWND: 0 SND-MSS: 0
     RxDrop%-SEQ:  0.0000  RxDrop%-CX: 0.0000  Conn-Timer: -1-0ms  Conn-Pause: 0-0ms
     PktsToSend: 0
  Multi-Conn: 0  Active-Connections: 0  Files-Played: 0
     RunningInGroup: NONE  Script-steps-completed: 0  Steps-Failed: 0
     First-Rx: -1ms  Mcast-Source: 0.0.0.0:0
       Rx Pkts:            Total: 0           Time: 60s   Cur: 0         0/s
       Rx Pkts (On Wire):  Total: 0           Time: 60s   Cur: 0         0/s
       Rx Bytes:           Total: 0           Time: 60s   Cur: 0         0/s
       Rx Bytes (On Wire): Total: 0           Time: 60s   Cur: 0         0/s
       Rx OOO Pkts:        Total: 0           Time: 60s   Cur: 0         0/s
       RX Wrong Dev:       Total: 0           Time: 60s   Cur: 0         0/s
       RX CRC Failed:      Total: 0           Time: 60s   Cur: 0         0/s
       RX Bit Errors:      Total: 0           Time: 3s    Cur: 0         0/s
       Rx Dropped Pkts:    Total: 0           Time: 3s    Cur: 0         0/s
          Cx Detected:     0
       Rx Duplicate Pkts:  Total: 0           Time: 60s   Cur: 0         0/s
       Tx Pkts:            Total: 0           Time: 60s   Cur: 0         0/s
       Tx Pkts (On Wire):  Total: 0           Time: 60s   Cur: 0         0/s
       Tx Bytes:           Total: 0           Time: 60s   Cur: 0         0/s
       Tx Bytes (On Wire): Total: 0           Time: 3s    Cur: 0         0/s
       Tx Failed Pkts:     Total: 0           Time: 60s   Cur: 0         0/s
       Tx Failed Bytes:    Total: 0           Time: 60s   Cur: 0         0/s
       Conn Established:   Total: 0           Time: 30s   Cur: 0         0/s
       TCP Retransmits:    Total: 0           Time: 3s    Cur: 0         0/s
       Conn Timeouts:      Total: 0           Time: 30s   Cur: 0         0/s

Remove Cross Connect: delete_cx

Remember to delete a cross connect before you delete its endpoints.

 $ ./lf_firemod.pl --action delete_cx  --mgr cholla-f19 --cx_name cx_0

Controlling Traffic

You need to use do_cmd to control Unicast traffic.

By default, cross connects are created in the default_tm test manager. To control them, you want to specify default_tm in your set_cx_state CLI command.

 ./lf_firemod.pl --mgr 127.0.0.1 --quiet 0 --action do_cmd --cmd "set_cx_state default_tm cx_0 RUNNING"

The format of the command is specified in the CLI User Guide: set_cx_state. Possible CX states include:

  • RUNNING
  • SWITCH
  • QUIECE
  • STOPPED
  • DELETED

For Multicast traffic, use start_endp/stop_endp

 $ ./lf_firemod.pl --mgr cholla-f19 --action stop_endp --endp_name cx_0-A

Multicast Endpoints

There are different options for creating multicast endpoints.

 $ ./lf_firemod.pl --action create_endp --endp_name mcast_xmit_1 \
   --endp_type mc_udp      --speed 154000 \
   --mcast_addr 224.9.9.8  --mcast_port 9998 \
   --rcv_mcast NO          --port_name eth1 \
   --min_pkt_sz 1072       --max_pkt_sz 1472 \
   --use_csums NO          --ttl 32 

Add secondary IPs to a Port

This is not a default script option, so we use the do_cmd action:

 C:\> perl .\lf_firemod.pl --mgr 192.168.100.1
   --action do_cmd "set_sec_ip 1 1 eth1 10.26.0.20-250/24"

See the LANforge CLI User Guide for more info.

Present Options

This is the output of lf_firemod.pl --help:

./lf_firemod.pl  --action { create_endp | show_endp | set_endp | show_port | list_ports
                            | do_cmd | start_endp | stop_endp | delete_endp
                            | create_cx | list_cx | show_cx | delete_cx } ]
  [--endp_vals {key,key,key,key}]
      # show_endp output can be narrowed with key-value arguments
      # Examples:
      #  --action show_endp --endp_vals MinTxRate,DestMAC,Avg-Jitter
      # Not available: Latency,Pkt-Gaps, or rows below steps-failed.
      # Special Keys:
      #  --endp_vals tx_bps         (Tx Bytes)
      #  --endp_vals rx_bps         (Rx Bytes)
  [--mgr       {host-name | IP}]
  [--mgr_port  {ip port}]
  [--cmd       {lf-cli-command text}]
  [--endp_name {name}]
  [--port_name {name}]
  [--resource  {number}]
  [--speed     {speed in bps}]
  [--tos       { DONT-SET | LOWDELAY | THROUGHPUT | RELIABILITY | LOWCOST },{priority}]
  [--max_speed {speed in bps}]
  [--quiet     { yes | no }]
  [--endp_type { lf_udp | lf_udp6 | lf_tcp | lf_tcp6 | mc_udp | mc_udp6 }]
  [--mcast_addr {multicast address, for example: 224.4.5.6}]
  [--mcast_port {multicast port number}]
  [--min_pkt_sz {minimum payload size in bytes}]
  [--max_pkt_sz {maximum payload size in bytes}]
  [--rcv_mcast { yes (receiver) | no (transmitter) }]
  [--use_csums { yes | no, should we checksum the payload }]
  [--ttl       {time-to-live}]
  [--report_timer {miliseconds}]
  [--cx_name   {connection name}]
  [--cx_endps  {endp1},{endp2}]
  [--test_mgr  {default_tm|all|other-tm-name}]

Example:
 ./lf_firemod.pl --action set_endp --endp_name udp1-A --speed 154000

 ./lf_firemod.pl --action create_endp --endp_name mcast_xmit_1 --speed 154000 \
   --endp_type mc_udp   --mcast_addr 224.9.9.8 --mcast_port 9998 \
   --rcv_mcast NO       --port_name eth1 \
   --min_pkt_sz 1072    --max_pkt_sz 1472 \
   --use_csums NO       --ttl 32 \
   --quiet no --report_timer 1000

 ./lf_firemod.pl --action create_endp --endp_name bc1 --speed 256000 \
   --endp_type lf_tcp   --tos THROUGHPUT,100 --port_name rd0#1

 ./lf_firemod.pl --action list_cx --test_mgr all --cx_name all

 ./lf_firemod.pl --action create_cx --cx_name L301 \
   --cx_endps ep_rd0a,ep_rd1a --report_timer 1000

Creating Endpoint Hunt Scripts with CLI API

Goal: Use the the CLI to operate the Endpoint Scripting features of the Layer-3 Endpoints you create.

Layer-3 endpoints can manipulate their own transmission parameters using a variety of internal scripts, known as Endpoint Scripts. Using the lf_endp_script.pl CLI script, you can operate those internal endpoints behaviours.
This cookbook talks about Endpoint Scripts and CLI scripts at the same time. In this chapter, if the term script is used, assume Endpoint Script. Additionally, the terms operating and running can also be confusing. To keep the activities distinct, a LANforge user will operate a CLI script from a terminal. The LANforge server will run the Endpoint Script. A CLI script is a user-space perl script that issues CLI commands to a LANforge server. A CLI command is an instruction obeyed by the LANforge server.

The Forces at Play

There are a number of subsystems running while we operate an automated Endpoint Script, so let's review them:

  • There will be Layer-3 connect constructed using lf_firemod.pl. (Don't forget: create the endpoints before creating the cross connect.)
  • A managed endpoint of that connection will be configured with an Endpoint Script.
  • The attending engineer will operate a CLI script that changes state the Layer-3 connection to Running
  • The Layer-3 connection starts both endpoints transmitting, one of them starts running it's Endpoint Script that sets it's transmit parameters.
  • Remember: Endpoint Scripts run inside the LANforge server process. CLI scripts run from the client side.

Let's Walk Thru Putting One Together

We recommend starting your first script off by the LANforge GUI to save an endpoint with an Endpoint Script. Next, inspect the LANforge database on the server for the script parameters. Take those parameters and adapt them to the operator's CLI script.

  1. From the Layer-3 tab, open a connection tutorial-cx, and navigate to box 2. Click on the Script button.
  2. Name your script
  3. Select your Script type, here we choose ScriptHunt
  4. We immediately see the parameters for the script:
  5. Let's modify the parameters to match our CLI command example below:
  6. In a LANforge terminal, let's look at at /home/lanforge/DB/DFLT/endps.db We will search for bunny-script and we'll inspect the resulting CLI command.
  7. set_script tutorial-cx-A bunny-script 37120 ScriptHunt
       '5000 5000 100000,20000,100000,20,56000,30000,1,100000, 60,128,256,512,1024,1280,1460,1472,1514 1472 0,100,300,500,550,600,650,700,750,850,900,950 NONE' ALL 20
  8. Now we can craft this command into a CLI script. In a CMD window, we can write the formatted CLI script arguments:
  9. C:\> .\lf_endp_script.pl --mgr jedtest --resource 1 ^
     --action set_script --script_type Hunt --script_name bunny-script ^
     --endp_name tutorial-CX-A -loops 1 --flags 37120 ^
     --private "5000 5000 100000,20000,100000,20,56000,30000,1,100000, 60,128,256,512,1024,1280,1460,1472,1514 1472 0,100,300,500,550,600,650,700,750,850,900,950 NONE"
    In the CMD window, use double-quotes " for quoted script arguments. Using single-quotes will break your command.

    In a Linux terminal, we can use double " or single ' quotes:

    $ ./lf_endp_script.pl --mgr jedtest --resource 1 \
     --action set_script --script_type Hunt --script_name bunny-script \
     --endp_name tutorial-CX-A -loops 1 --flags 37120 \
     --private '5000 5000 100000,20000,100000,20,56000,30000,1,100000, 60,128,256,512,1024,1280,1460,1472,1514 1472 0,100,300,500,550,600,650,700,750,850,900,950 NONE'
  10. We can start the connection and the Endpoint Script will immediately begin running:
  11. lf_endp_script --mgr jedtest --resource 1 --action start_cx --cx_name tutorial-CX
  12. If the number of loops is fixed, it will eventually quiesce and stop itself. If we need to stop it and let in-flight packets come to rest, we can quiesce it:
  13. lf_endp_script --mgr jedtest --resource 1 --action quiesce_cx --cx_name tutorial-CX

    We could also use action stop_cx to immediately stop the connection.

  14. If you have a LANforge GUI running, the Endpoint Script report will automatically display in a GUI window as soon as the connection starts. To display it to the terminal, you need to enable debug output:
  15. lf_endp_script.pl --action show_report --endp_name tutorial-CX-A --quiet no

    Or to save it to a text file:

    lf_endp_script.pl --action show_report --endp_name tutorial-CX-A --quiet no > /home/lanforge/Documents/report.txt
  16. To remove the script:
  17. lf_endp_script.pl --action remove_script --endp_name tutorial-CX-A

At the CLI Command Level

Review of the set_script CLI command

We have covered creating endpoints in earlier cookbooks. The perl script lf_endp_script.pl was created to modify endpoints and operate their Endpoint Scripts. That script is using the set_script CLI command (documented here). A call to it looks like:

set_script tutorial-cx-A bunny-script 37120 ScriptHunt '...' ALL 20

Endpoint Scripting Uses Large Parameters

That vague '...' section is the private parameter which is a parameter list each script type requires. The private parameter combines a series of constraints (sub-parameters). For the ScriptHunt, we might use:

run_duration pause_duration constraints payload_sizes_a payload_sizes_b attenuations attenuator
 5000          |             |               |                  |              |          |
             5000            |               |                  |              |          |
100000,20000,100000,20,56000,30000,1,100000  |                  |              |          |
                  | 60,128,256,512,1024,1280,1460,1472,1514     |              |          |
                  |                                            1472            |          |
                  |                    0,100,300,500,550,600,650,700,750,850,900,950      |
                  v                                                                    1.1.14
      drops,jitter_us,latency_us,max_steps,start_rate,accuracy,is_bps,max_tx_slowdown

Accuracy is also Threshold, max_tx_slowdown is also Underrun. The result is a very long line that has to be surrounded the the CLI level by one pair of single quotes:

'5000 5000 100000,20000,100000,20,56000,30000,1,100000, 60,128,256,512,1024,1280,1460,1472,1514 1472 0,100,300,500,550,600,650,700,750,850,900,950 NONE'
Write these parameters very carefully! Your first mistake is likely going to involve misplaced apostrophes.

Associating stations with the lf_associate_ap script.

Goal: Create, destroy, start and stop virtual stations without needing to use the LANforge GUI.

Automated wireless traffic is possible using the lf_associate_ap.pl script. This script can be run within the LANforge server or outside the LANforge Server (on a windows desktop). The output of the script should be redirected to a text file if you want to review the resuts. Use this file in conjunction with the lf_firemod.pl script to create traffic. Requires a LANforge CT520 (or better) system and an access point.

Script Capabilities

The lf_assocatiate_ap.pl script has many options, but here are the basic actions:

  • Create stations and cross connects with them, running traffic for a specified amount of time (action: step1)
  • Generate stress on the AP by repeatedly bringing up stations and taking them down (action: step2).

Before you begin

  1. We assume you have a separate WiFi access point in routed mode. These examples can be used on a CT523 (or better) system with more than one radio if you want to practice the techniques. You would dedicate a radio to be a virtual AP (see cookbook).
  2. For these examples, our AP will be open with no username or password, and the SSID will be jedtest
  3. If you want to run scripts from your Windows desktop, you have ActivePerl installed.

Creating a virtual station with traffic

Using lf_associate_ap on Windows

  1. In the LANforge GUI, we will inspect our wiphy0 radio. And the radio should be set to channel -1 AUTO
  2. CMD window shortcut: R cmd
    LANforge Scripts are at C:\Program Files\LANforge-Server\scripts
  3. cd C:\Program Files\LANforge-Server\scripts
  4. perl .\lf_associate_ap.pl --help Will show you the script options.
  5. We can create a virtual station with this command:
  6. perl .\lf_associate_ap.pl --resource 1  --resource 1 --mgr jedtest ^
       --action step1       --radio wiphy0    --ssid jedtest ^
       --first_sta sta100   --num_stations 1  --duration 20 ^
       --first_ip DHCP      --upstream eth1 --security wpa2 --passphrase jedtest1
    Long DOS commands and be continued on the next line with the ^ character.
  7. We can see the port appear in the LANforge GUI: and we can inspect it.

Using lf_associate_ap on Linux

  1. Double click on your PuTTY icon and open a connection to your LANforge machine.
  2. The lf_associate_ap.pl script is in the scripts sub directory.
  3. Our command is basically the same.
  4. Long shell commands and be continued on the next line with the \ character.
    ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 1  --duration 20 \
       --first_ip DHCP      --upstream eth1   --security wpa2 --passphrase jedtest1
          
  5. We will see similar output:

More Traffic Examples

  1. Creating Multiple stations that transm
  2. ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100 --num_stations 10 --duration 20 \
       --first_ip DHCP      --upstream eth1   --security wpa2 --passphrase jedtest1
  3. Creating TCP/IP bursty traffic from 30Mbps to 450 Mbps
  4. ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 10 --duration 120 \
       --first_ip DHCP      --upstream eth1   --security wpa2 --passphrase jedtest1 \
       --cxtype tcp --bps-min 30Mpbs \
       --bps-max 450Mbps
  5. Capturing that report with redirection
  6. ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 10 --duration 120 \
       --first_ip DHCP      --upstream eth1   --security wpa2 --passphrase jedtest1 \
       --cxtype tcp --bps-min 30Mpbs --bps-max 450Mbps &> report.txt
    Both DOS and Linux command output can be saved to a file with the &> operator.
    Both DOS and Linux files can be viewed with the more command.
  7. Creating steady UDP traffic to at 450Mbps
  8. $ ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 10 --duration 120 \
       --first_ip DHCP      --upstream eth1   --security wpa2 --passphrase jedtest1 \
       --cxtype udp --bps-min 450Mpbs \
       --bps-max SAME &> report.txt
    $  more report.txt
  9. Associating to an open AP
  10. ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 10 --duration 120 \
       --first_ip DHCP      --upstream eth1   --security open
  11. Connecting a station at 802.11/abg speeds
  12. ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 10 --duration 120 \
       --first_ip DHCP      --upstream eth1 --security open \
       --wifi_mode abg
  13. Initializing your test secenario by pre-loading a database. The database is the same name as the dropdown in the GUI Status tab.
  14. ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 10 --duration 120 \
       --first_ip DHCP      --upstream eth1 --security open \
       --db_preload day_236
  15. Saving your test state after completing a traffic run
  16. ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 10 --duration 120 \
       --first_ip DHCP      --upstream eth1 --security open \
       --db_preload day_236 --db_save station_results
  17. Cleaning out your scenario settings after completing a traffic run. We can do this by loading the EMPTY database with the db_postload switch.
  18. ./lf_associate_ap.pl --resource 1 --mgr localhost \
       --action step1       --radio wiphy0    --ssid jedtest \
       --first_sta sta100   --num_stations 10 --duration 120 \
       --first_ip DHCP      --upstream eth1 --security open \
       --db_preload day_236 --db_save station_results --db_postload EMPTY

Using lf_associate_ap to stress test an AP

We can have a series of stations associate and unassociate over and over. This can be quite a bit of exercise for an AP. Below is a command that tests five clients connecting.

./lf_associate_ap.pl --mgr jedtest --action step2 \
 --ssid jedtest --first_sta sta100 --first_ip DHCP \
 --num_stations 10 --security wpa2 --passphrase jedtest1
      
This will create set of ten stations bring them up and then take them down.

Script Options

These might have been update since publication, please check --help output for your version of the script.

./lf_associate_ap.pl   [--mgr {host-name | IP}]
      [--mgr_port {ip port}]     # use if on non-default management port
      [--resource {resource}]    # use if multiple lanforge systems; defaults to 1
      [--quiet { yes | no }]     # debug output; -q

      ##       AP selection
      [--radio {name}]           # e.g. wiphy2
      [--ssid {ssid}]            # e.g. jedtest
      [--security {open|wep|wpa|wpa2}] # station authentication type
      [--passphrase {...}]       # implies wpa2 if --security not set
      [--wifi_mode {a|abg|abgn|abgnAC|an|anAC|b|bg|bgn|g}]

      ##       station configuration
      [--num_stations {10}]
      [--first_sta {sta100}]
      [--first_ip {DHCP |ip address}]
      [--netmask {255.255.0.0}]

      ##       connection configuration
      [--cxtype {tcp/tcp6/udp/udp6}]   # use a tcp/udp connection, default tcp
      [--upstream {name|eth1}]
         # could be AP or could be port on LANforge
         # connected to WAN side of AP
      [--bps-min {10000000}]         # minimum tx bps
      [--bps-max {SAME|bps-value}]  # maximum tx bps, use SAME or omit for SAME
      [--duration {30}]      # connection duration, seconds, default 60
      [--poll-time {5}]    # nap time between connection displays
      [--action {step1,step2}]
         # step1: creates [num_stations] stations and L3 connections
         # step2: does bringup test

      [--traffic_type {separate|concurrent}]
         # for step1: separate does download then upload
         # concurrent does upload and download at same time

      [--db_preload {scenario name}]
         # load this database before creating stations
         # option intended as a cleanup step

      [--db_save {name}]
         # save the state of this test scenario after running the
         # connections, before --db_postload

      [--db_postload {scenario name}]
         # load this database after running connections,
         # option intended as a cleanup step

Changing Station WiFi SSID with the CLI API

Goal: Programmatically change a stations SSID

Programatically creating LANforge virtual stations requires using the add_sta command. If you already have a station and need to change the SSID, you still use the add_sta command.

The general sequence of commands is:

  1. if port is up, set port down with:
  2. cur_flags=0x1 interest_flags=0x800002
  3. issue add_port with changed SSID
  4. issue set_port to bring it up with:
  5. cur_flags=0x0 interest_flags=0x800002

We can create a station using this script command:

./lf_associate_ap.pl --action step2 --mgr jedtest \
   --resource 1 --radio wiphy0 \
   --ssid jedtest --first_sta sta100 \
   --num_stations 1 --first_ip=DHCP \
   --wifi_mode abgn --security wpa2 \
   --passphrase jedtest1 --quiet=0
   

The format of the add_sta command is listed in the CLI User's Guide. When we watch the debug output of the lf_associate_ap script, we see this add_sta command executed:

'add_sta' '1' '1' 'wiphy0' 'sta100' '1024' 'jedtest'
   'NA' 'jedtest1' 'AUTO' 'NA' '00:E3:F7:91:4A:1A' '5' 'NA'
   'NA' 'NA' 'NA' 'NA' '1024' 'NA' 'NA' 'NA' 'NA'
   

Looking at an example in the lf_associate_ap.pl script we see it being formatted here:

   my $sta1_cmd   = fmt_vsta_cmd($::resource, $::sta_wiphy, $sta_name,
                                 "$flags", "$::ssid", "$::passphrase",
                                 $mac_addr, "$flagsmask", $wifi_m);
   doCmd($sta1_cmd);
   

We format the parameters:

      return fmt_cmd("add_sta", 1, $resource, $sta_wiphy, $sta_name, "$flags",
                  "$ssid", "NA", "$key", $ap, $cfg_file, $mac,
                  $mode, $rate, $amsdu, $ampdu_factor, $ampdu_density,
                  $sta_br_id, "$flags_mask" );
   

Changing Station POST_IFUP field with the CLI API

Goal: Programmatically change a station's POST_IFUP field.

Creating a series of scripts using the lf_associate_ap.pl script is not adequate for negotiating a captive-portal environment, that script does not set the POST_IFUP parameter for the station. However, stations can be modified to gain that field.

Creating a station that negotiates a Captive Portal environment requires the POST_IFUP field to name a script. (Usually a portal-bot.pl script.) We can assign that port parameter with the set_wifi_extra2 command. At the time of this writing, there are no perl scripts using this CLI command, but I will show an example here:

set_wifi_extra2,
   1,       # resource number
   sta100,  # port name
   0,       # flush-to-kernel
   NA,      # ignore probe
   NA,      # ignore auth
   NA,      # ignore assoc
   NA,      # ignore_reassoc
   NA,      # corrupt_gtk_rekey_mic
   NA,      # radius_ip
   NA,      # radius_port
   NA,      # freq_24
   NA,      # freq_5

   # post_ifup_script
   './portal-bot.pl --bot bp.pm --user "username" --pass "secret" --start_url "http://www.google.com/"  --ap_url "http://localhost/" --login_form "login.php" --login_action "login.php" --logout_form  "logout.php"',
   NA       # ocsp
   

The above command would never actually be formatted in in the way it appears above. It would all appear on one line without commentds.

In a perl script, the command could be formatted like:

my $cmd = fmt_cmd("set_wifi_extra2", 1,
         "sta100",  # port name
         0,         # flush-to-kernel
         "NA",      # ignore probe
         "NA",      # ignore auth
         "NA",      # ignore assoc
         "NA",      # ignore_reassoc
         "NA",      # corrupt_gtk_rekey_mic
         "NA",      # radius_ip
         "NA",      # radius_port
         "NA",      # freq_24
         "NA",      # freq_5
   qq(./portal-bot.pl --bot bp.pm ) # post_ifup_script
   .qq(--user "username" --pass "secret" )
   .qq(--start_url "http://www.google.com/" )
   .qq(--ap_url "http://localhost/" )
   .qq(--login_form "login.php" )
   .qq(--login_action "login.php" )
   .qq(--logout_form "logout.php"),
         "NA"       # ocsp );
   

Important Notes

  1. the LANforge server treats single-quotes (apostrophes, ') as command delimiters. Use only double-quotes (") to quote the arguments to the script.
  2. Do not use newlines (\n or carriage-returns (\r\n). That will truncate the command and LANforge will process it immedately.
  3. These parameters will be provided by the server:
    • --mgt The management FIFO
    • --ip4 The IP address of the port
    • --ip6 The IPv6 address of the port
    • --dnsv A comma-separated list of DNS addresses
    • --logout Signals logout

Generating a series of attenuations using data in a CSV file.

Goal: Using the script and a specially formatted csv file, you will be able to re-play an arbitrary series of attenuations.

Playing back a series of WiFi attenuation levels using the attenuator_series.pl and a CSV file of attenuations make it possible to emulate the motion of a station (or stations) moving among a series APs. Or it could emulate interference in a crowd of moving people. Requires a LANforge CT703 (or better) and a LANforge CT520 (or better) system, and an access point.

Testing 1x1 with one attenuator

Our LANforge manager (resource 1.1) has an attenuator serial number 3 (resource 1.1.3) connected to the Device Under Test. The attenuator will be 1.1.1.3. There will be station sta100 on LANforge resource 1 and AP vap0 on LANforge resource 2. Cables connect the radios to the the attenator. The radios are configured in 1x1 mode. The corresponding channel on the attenuator is 1.1.3.0

[See LANforge Entity IDs for more on numbering.]

Let's script it with a simple data file: /home/lanforge/atten_test1.csv

channels,1.1.3.0
delay,5000
attenuate,250
attenuate,320
attenuate,450
attenuate,520
attenuate,820

We run the script in our terminal:

$ cd /home/lanforge/scripts
$ ./attenuate_series.pl -f ../atten_test1.csv

Watching a Layer-3 connection in the Dynamic Display, we will see a dip, rise and dip at 10 second intervals.

Testing 2x2 with One Attenuator

Next we cable up the second channel (1.1.3.1). We can update the csv test file, by adding a new column for the channel.

channels,1.1.3.0,1.1.3.1
delay,5000
attenuate,250,250
attenuate,320,250
attenuate,450,250
attenuate,520,520
attenuate,820,820

We can run the same command and watch the dynamic reports window to see a similar graph.

A 2x2 Example with Two Attenuators

The first radio on each LANforge is connected in 2x2 mode to both attenuators. This example is drawn to illustrate how you design the connection of your channels independently of their radios. Obviously, you don't need two attenuators for this scenario. However, if you had a CT523 with three radios and want to perform 2x2 testing with three client radios, it is possible to do so with only two CT703 attenuators.

We change the data file to specify the first channel on attenuator 14 (1.1.14.0): /home/lanforge/atten_test3.csv

channels,1.1.3.0,1.1.14.0
delay,5000
attenuate,250,250
attenuate,320,320
attenuate,450,450
attenuate,520,520
attenuate,820,820

We can run the script once in our terminal:

$ cd /home/lanforge/scripts
$ ./attenuate_series.pl -f ../atten_test3.csv

Watching the port signal in the dynamic display we will see a rise and dip at 10 second intervals.

Connecting up Multiple Radios

There is no different in attenuator control whether you have one radio in 3x3 or three radios in 1x1 to control. If you are testing multiple radios, you will be monitoring their RX Signal in the dynamic report.

File Format

Editing the test data file with a basic spreadsheet program than can save to CSV format is possible. You will want to save with comma format, without double-quoting the cells. These directives are converted to lower-case, so you can type them in UPPER-CASE or Mixed-Case if necessary.

The format of the CSV file allows you to specify many options that might also be specified on the command line.

Directives

# comments
Rows that begin with a comment sign (#, ;, !) will be entirely ignored. Cells in column B or beyond will be ignored.
channels
Each cell following this directive specifies an attenuator channel to control.
sleep, nap
The following cell specifies a one-time wait time in milliseconds
delay, naptime
The following cell specifies a standard wait time in milliseconds between each attenuate command
attenuate, _, ,
The following cells specify an attenuation value for channels specified by the last channels command.
minimum, min
Sets the minimum attenuation permitted. Values below this will be set to the minimum directed.
maximum, max
Sets the maximum attenuation permitted. Values above this will be set to the maximum directed.

Attenuation Values

  • Inherently Positive Values, like 200 are absolute attenuation values, in deci-decibels. 200 means 20.0dB. The smallest unit of resolution is 0.5dB, so all your values will end in zero or five. E.G. (0, 5, 105, 200, 955). Values range between zero and 955.
  • Explicitly Positive Values, that begin with @+, ++, + are increments with respect to the last value set on the channel.
    attenuate,250
    attenuate,@+50
    Results in the channel at 30.0dB. Spreadsheets often omit signed values when saving, so @+ will force a text type cell.
  • Explicitly Negative Values, that begin with @-, --, - are decrements with respect to the last value set on the channel.
    attenuate,300
    attenuate,@-50
    Results in the channel at 25.0dB. Spreadsheets often omit signed values when saving, so @- will force a text type cell.
  • Basic Cell Math can be performed, but only against absolute cell values.
    attenuate,500,400
    attenuate,=B1+50,=C1-50,   # results in 550, 350
    attenuate,=B2+5,=C2-5,     # fails: B2 and C2 were formulas.
    This feature is unlikely to be as useful as it sounds, because pasting a column of forumae will be pretty useless, since a spreadsheet processes them recursively. Also, most spreadsheets saved to CSV typically don't save formulae by default, you probably will get the computed values in your CSV file.
  • Shortcuts include _, NA, and ,,. You can skip a computation on a cell by leaving a blank cell, underscore, or 'NA'. Careful: the value +0 will likely be truncated to 0, and set the channel to 0.0dB attenuation.

Script Options

The attenuate_series.pl script uses these arguments. They support long and short argument switch names:

   -m
   --mgr             LANforge manager host, like localhost or 192.168.101.1
   
   -f
   --file            CSV file with attenuation data
   
   -d
   --delay           Override of DELAY variable, milliseconds between applying rows
   
   -l
   --loop            Repeat indefinitely
   
   -c
   --channel         Override of channels variable, eg: 1.2.3.1,2.3.4.3
   
   -i
   --min
   --minimum         Set minimum attenuation value (not lower than zero)
   
   -x
   --max
   --maximum         Set maximum attenuation value (not higher than 955)
   
   -n
   --dry
   --dryrun
   --dry_run         Do not apply attenuation, just parse file, ignore nap times

Example CSV File

This CSV shows a working example that gives warnings.

  1. # example csv
  2. channels, 1.1.14.0, 1.1.14.1, 1.1.14.2, 1.1.3.0, 1.1.3.1, 1.1.3.2,
  3. DELAY,2000,,,,,,
  4. ATTENUATE,950,850,750,950,850,750,
  5. attenuate,940,-10,-10,-10,-10,-10,
  6. attenuate,930,-10,NA,-10,-10,,
  7. attenuate,=B4-10,=C4+10,NA,-15,-15,,
  8. attenuate,-15,_,-15,,NA,-15,
  9. sleep,1000,,,,,,
  10. attenuate,110,115,215,315,415,515,
  11. _,=B10-20,=C10+20,=D10+20,=E10+20,=F10+20,=G10-20,
  12. _,@+10,@+10,@-10,10,10,10,
  13. # eof

Attenuators Tab

Here's the Attenuators tab used for the examples:

Opening and Saving CSV

Here are options used for the open dialog in LibreOffice Calc:

Here are the options used for the save dialog in LibreOffice Calc:

LANforge Entity IDs

Goal: Gain a better understanding of LANforge Entitiy IDs (EIDs)

Every port, radio, virtual port, endpoint and connection in LANforge has an ID known as an EID. These are an internal notation that expresses the heirarchy of the physical and virtual objects managed by LANforge realm.

Ports, Endpoints and Connections are Entities

Entity IDs (EIDs) are a dotted-decimal phrase. It expresses the Shelf, Resource Number, Port or Connection number, and if it is an endpoint, it gains an fourth decimal. An Example:

1.2.8.4  : EID
1        : shelf
  2      : resource
    8    : port
      4  : endpoint

You can assume the shelf number will always be 1 for now. The Resource number will refer to the LANforge machine ID as reported on the Status tab. The port id is only unique within a LANforge machine. The port ID also refers to hardware in a machine: radios get a third decimal. The fourth decimal refers to either endpoints or connections.

Only Some LANforge Entities Generate Connection Data

While some items with port numbers, notably radios and ports, do not generate traffic. Endpoints generate traffic, and typically endpoints are transmitting to an opposite endpoint. The exception to this are multicast endpoints.

EIDs Express Heirarchy

From the dotted-decimal perspective:

  • Physical or virtual ports reside below a resource, except:
  • ...for VLANs: A virtual port does not reside below it's physical port
  • ...for bridge ports:: A port of a bridge has to exist before the bridge is created
  • An endpoint resides below a physical or virtual port.

The formatting of the decimals might or might not be zero-padded. The picture below should convey how a connection (Layer 3) relates to two endpoints, and two ports:

The exception is connections. Connections are numbered outside of this heirarchy.

Do I use EIDs in Scripts?

Usually not, for these reasons:

  1. EIDs are generated at LANforge manager start time, and might depend on the detection order of ports when the PCI bus on the host is enumerated at boot time.
  2. New EIDs can be created by appending one database to another on non-conflicting devices
  3. New devices can be hot-added to a LANforge resource, like a programmable attenuator or a USB-Ethernet adapter, generating new Port IDs.

In scripts, it is legal to reference port numbers, but not advised to store them between sessions. If you reference an EID, it should be from within your present LANforge session. If your resources tend to disappear off the network and return (you had a machine reboot) those EIDs are not guaranteed to return.

For ports, only the first two decimals (shelf and resource id) are actually stable across machine reboots.

If you look into the saved scenarios (in /home/lanforge/DB/DFLT) you will notice that ports, endpoints, and connections are refered to by name. Event though in the CLI Users's guide, where it states port number, use names in your scripts:

CMD
|        SHELF
|        |  RESOURCE
|        |  |  PORT
|        |  |  |
set_port 1  1  eth1 10.26.1.2 255.255.255.0 10.26.1.1 ....

Querying the LANforge GUI for JSON Data

Goal: The LANforge GUI now has an embedded webserver and a headless mode of operation. Read on for how to configure and query the client for JSON formatted data.

Updated 2019-11-21:New features in 5.4.1.

  • Some of the CLI API parameter names have changed. Notably: nc_show_ports flags changed to probe_flags. Be aware that older scripts might break on upgrade.

Updated 2018-07-24:New features in 5.3.8.

The LANforge GUI (as of release 5.3.6) can be configured to start an embedded web server that can provide data about ports and layer-3 connections. This service can be queried with with any browser or AJAX connection. We're going to increasingly refer to it as the LANforge client. This feature provides these benefits:

  • More rapid polling: using CLI scripts to poll ports on the LANforge manager can add stress and contention to the LANforge manager; polling the GUI will not tax your test scenario.
  • Expanded array of data: the views found in the GUI, like Port Mgr and Layer-3 tabs, contain synthesized data columns not available through the CLI scripting API. Most of these columns can be returned in JSON format.
  • Reduced effort when integrating with third party test libraries: many other testing libraries expect JSON formatted input.
  • Web socket delivery of event data allows real-time reporting of interface changes and station scan results. This is also a channel for querying additional diagnostic data.
  • There is a /help web page that allows you to build POST commands.
  • A headless -daemon mode that will run the client without any GUI windows. This requires much less memory and has been queried for weeks at a time without crashing or memory leaks.

Present and potential drawbacks of the JSON feature:

  • Actively being developed: the JSON views/schema of the objects is at a demonstation state. URLs and JSON structures have changed in 5.3.8.
  • Now no longer possible to create Groovy plugins to add JSON features if you want to use the headless mode. JSON Features are compiled into the LANforge GUI from Java sources.
  • In 5.3.8 we have limited the view of ports, have added URLs to post direct CLI commands, and have applied HTML application/x-www-form-urlencoded form posting submissions in name/value pairs. There is no multipart/form-data JSON submission at this time.

Client Settings

The LANforge GUI is started using a script (lfclient.bash or lfclient.bat). From a terminal, we call that script with the -httpd switch. By default the GUI will listen on port 8080:

$ cd /home/lanforge
$ ./lfclient.bash -httpd

You can specify the port to listen on:

$ ./lfclient.bash -httpd 3210

You can run the client headless with the -daemon switch as well:

$ ./lfclient.bash -httpd -daemon

There is a setting in the 5.3.8 Control→Preferences menu for setting a minimized mode and the HTTP port number as well.

Making Queries

From the terminal we can query the port to find a basic message from the GUI:

$ curl -sq http://localhost:8080/

This first page (/) will give you a JSON list of the resource URLs available. Most URLs will provide JSON as their default content type. Notably, /help defaults to HTML.

By default, most URLs will treat a default Accept: */* header as text/html. Compare the two techniques below:

JSON Output

$ curl -sqv -H 'Accept: application/json' http://localhost:8080/resource/1/1
{"handler":"candela.lanforge.HttpResource$JsonResponse","uri":"resource","candela.lanforge.HttpResource":{"duration":"27"},"resources":[{"1.1":{"_links":"/resource/1/1","entity id":"NA","hostname":"idtest.candelatech.com"}},{"1.2":{"_links":"/resource/1/2","entity id":"NA","hostname":"hedtest"}},{"1.3":{"_links":"/resource/1/3","entity id":"NA","hostname":"ct524-debbie"}},{"1.4":{"_links":"/resource/1/4","entity id":"NA","hostname":"jed-apu2-a"}},{"1.5":{"_links":"/resource/1/5","entity id":"NA","hostname":"jed-apu2-b"}},{"1.6":{"_links":"/resource/1/6","entity id":"NA","hostname":"ct524-emily"}},{"1.7":{"_links":"/resource/1/7","entity id":"NA","hostname":"ct524-freya"}},{"1.8":{"_links":"/resource/1/8","entity id":"NA","hostname":"ct524-genia"}}]}

Clearly, the JSON output is difficult to read. We cover formatting output below.

HTML Output

Most of the queries to the client will return JSON by default. The notable exception is the /help URL. To get HTML output in the terminal, you have to specify Accept: text/html to curl:

$ curl -sqv -H 'Accept: text/html' http://localhost:8080/port/1/1/1
<!DOCTYPE html>
<html>
<head><title>/port</title>
</head>
<body>
<table border='1'><thead><tr><th>EID</th><th>AP</th><th>Activity</th><th>Channel</th><th>Device</th><th>Down</th><th>IP</th><th>Parent Dev</th><th>Phantom</th><th>Port</th><th>SSID</th></tr></thead>
<tbody>
<tr><td>1.1.1</td><td></td><td>0.0</td><td></td><td>eth1</td><td>false</td><td>0.0.0.0</td><td></td><td>false</td><td>1.1.01</td><td></td></tr>
</table><hr />
</body>
</html>

Formatting Results

JSON formatted text is pretty difficult to read, there are a few different utilities that can help you look at it: jq, json_pp, json_reformat, tidy, xmllint, yajl and jsonlint.

Example of installing formatters

On Fedora, install:

$ sudo dnf install -y jq perl-JSON-PP tidy libxml2 yajl

On Ubuntu, install:

$ sudo apt install -y jq libjson-pp-perl perltidy xmllint libxml2-utils yajl-tools

Now we can perform a query:

$ curl -sq /port/1/1/1
{
  "candela.lanforge.HttpPort" : {
     "duration" : "1"
  },
  "handler" : "candela.lanforge.HttpPort$JsonResponse",
  "interface" : {
     "stuff":...
  },
  "uri" : "port/:shelf_id/:resource_id/:port_id"
}

Notice that the URI object list paths with colon-tagged positions in them, e.g.: /cli-form/:cmd. These are interpreted as URL parameters and not query string parameters, they cannot be moved into the query string.

Making your shell friendly

To save you typing, you might want to add this function to your .bash_aliases file:

function Json() {
   curl -sqv -H 'Accept: application/json' "http://localhost:8080${@}" \
    | json_reformat | less
}

Then you can make your calls this way:

$ Json /port/1/1/1

Browsing results in table format

We can view a URL in a browser as well:

Viewing Alerts and Events

You can both view and stream event data. Querying events and alerts are both quite similar:

$ Json /events
{
"handler" : "candela.lanforge.HttpEvents$FixedJsonResponder",
"events" : [
   {
      "2249259" : {
         "event" : "Connect",
         "_links" : "/events/2249259",
         "entity id" : "NA"
      }
   },
   ....

A busy LANforge system will generate hundreds of thousands of events. Only the last few thousand can be recalled.

You can inspect a singular event:

$ Json /events/2249259
{
    "handler": "candela.lanforge.HttpEvents$FixedJsonResponder",
    "uri": "events/:event_id",
    "candela.lanforge.HttpEvents": {
        "duration": "0"
    },
    "event": {
        "eid": "1.3.21",
        "entity id": "NA",
        "event": "Connect",
        "event description": "sta3106 (phy #1): connected to 00:0e:8e:d5:fa:e6",
        "id": "2249259",
        "name": "sta3106",
        "priority": "  Info",
        "time-stamp": "2018-07-24 14:39:33.776",
        "type": "Port"
    }
}

We can view /alerts similarly.

$ Json /alerts/92
{
   "handler" : "candela.lanforge.HttpEvents$FixedJsonResponder",
   "uri" : "alerts/:event_id",
   "alert" : {
      "name" : "wlan0",
      "time-stamp" : "2018-07-02 16:23:30.880",
      "entity id" : "NA",
      "id" : "92",
      "eid" : "1.1.5",
      "event description" : "Port wlan0 has no WiFi SSID Configured.",
      "event" : "WiFi-Config",
      "priority" : "  Warning",
      "type" : "Port"
   },
   "candela.lanforge.HttpEvents" : {
      "duration" : "1"
   }
}

Streaming Events

Continually polling the /events URL is not as effective as streaming a websocket providing the same data. We need a web socket client. Websockets are built into modern browsers and there are python and perl utilities for the job as well. An easy to use python client is wsdump.

Installing wsdump

There is a useful python utility called wsdump (or wsdump.py). Try to install the python-websocket package to get it. There are many similar matches, but there is not one dedicated package that provides it. On Fedora:

root@fedora$ dnf whatprovides `which wsdump`
root@fedora$ dnf install -y python3-websocket-client
root@ubuntu$ ls -l /usr/bin/wsdump
  /usr/bin/wsdump → /etc/alternatives/wsdump
root@ubuntu$ ls -l /etc/alternatives/wsdump
 /etc/alternatives/wsdump → /usr/bin/python2-wsdump
root@ubuntu$ dpkg-query -S /usr/bin/python2-wsdump
python-websocket: /usr/bin/python2-wsdump

root@ubuntu$ sudo apt install python-websocket

You might need to install pip, and that might be in the python3-pip package. Then you can install via:

$ sudo apt install python-pip # or sudo dnf install python-pip
$ sudo pip install --upgrade pip
$ pip search websocket
$ sudo pip install websocket-client

Streaming Using wsdump

Here's an example of wsdump below. Don't forget you are now using h the ws:// schema and not the http:// schema!

$ /usr/bin/wsdump ws://localhost:8081/

It might take a few second to start showing results if your system is not very active. You should be able to prompt output by executing this message in the Messages tab: gossip hi ben!

Streaming Using javascript

You can also use a web page to follow events because websockets are built into modern browsers. This is a screenshot of the

Data Views

URLs

/shelf
The /shelf/1/ URL provides a list of resources in your realm:
$ Json /shelf/1
{
    "handler": "candela.lanforge.HttpResource$JsonResponse",
    "uri": "shelf/:shelf_id",
    "candela.lanforge.HttpResource": {
        "duration": "0"
    },
    "resources": [
        {
            "1.1": {
                "_links": "/resource/1/1",
                "hostname": "idtest.candelatech.com"
            }
        },
        {
            "1.2": {
                "_links": "/resource/1/2",
                "hostname": "hedtest"
            }
        }
   ]
}
/resource

The /resource URL provides a digest of ports available at the requested resource.

$ Json /resource/1/1
{
   "handler" : "candela.lanforge.HttpResource$JsonResponse",
   "resource" : {
      "free swap" : 526332,
      "free mem" : 4634228,
      "load" : 0.4,
      "bps-rx-3s" : 7850,
      "sw version" : "  5.3.8  64bit",
      "entity id" : "NA",
      "tx bytes" : 40533976395,
      "phantom" : false,
      "eid" : "1.1",
      "hostname" : "idtest.candelatech.com",
      "hw version" : "Linux/x86-64",
      "mem" : 8057280,
      "cpu" : "Intel(R) Core(TM) i7-3555LE CPU (2137Mhz)(x4)",
      "max staged" : 50,
      "ctrl-ip" : "192.168.100.41",
      "ports" : "0 1 2 3 4 5 6 7 8 9 10 11 12 ",
      "gps" : "0.0N 0.0E 0m",
      "max if-up" : 15,
      "bps-tx-3s" : 1753832,
      "cli-port" : "4003",
      "sta up" : 12,
      "shelf" : "1",
      "rx bytes" : 606510139,
      "ctrl-port" : "4004",
      "swap" : 526332
   },
   "uri" : "resource/:shelf_id/:resource_id",
   "candela.lanforge.HttpResource" : {
      "duration" : "1"
   }
}
/port
The /port URL provides a digest of ports and their state. You can request multiple ports by ID on this resource by appending the port IDs with commas. You can list ports on a resource:
$ Json /port/1/5/list
{
   "handler" : "candela.lanforge.HttpPort$JsonResponse",
   "uri" : "port/:shelf_id/:resource_id/:port_id",
   "interfaces" : [
      {
         "1.5.b5000" : {
            "entity id" : "NA",
            "_links" : "/port/1/5/7",
            "alias" : "b5000"
         }
      },
      {
         "1.5.eth0" : {
            "alias" : "eth0",
            "_links" : "/port/1/5/0",
            "entity id" : "NA"
         }
      },
...
   ],
   "candela.lanforge.HttpPort" : {
      "duration" : "2"
   }
}

We can query multiple ports at a time by their number or their name by placing a comma between the specifiers. Additionally, we can query for just the fields we desire. All field names are lower-case: ?fields=tx+crr,rx+fifo.

$ Json '/port/1/5/wiphy0,wiphy1?fields=device,phantom,tx+bytes,mode'
{
  "interfaces" : [
     {
        "1.5.wiphy0" : {
           "tx bytes" : 401236186,
           "mode" : "802.11abgn",
           "device" : "wiphy0",
           "phantom" : false
        }
     },
     {
        "1.5.wiphy1" : {
           "phantom" : false,
           "device" : "wiphy1",
           "mode" : "802.11abgn",
           "tx bytes" : 403975812
        }
     }
  ],
  "candela.lanforge.HttpPort" : {
     "duration" : "1"
  },
  "uri" : "port/:shelf_id/:resource_id/:port_id",
  "handler" : "candela.lanforge.HttpPort$JsonResponse"
}
/cx

The /cx URL allows us to query Layer-3 connection information.

$ Json /cx
{
   "uri" : "cx",
   "handler" : "candela.lanforge.GenericJsonResponder",
   "connections" : [
      "41.1" : {
         "entity id" : "NA",
         "name" : "udp:r3r2:3000",
         "_links" : "/cx/41"
      },
      "50.1" : {
         "name" : "udp:r3r2:3009",
         "entity id" : "NA",
         "_links" : "/cx/50"
      }
   ]
}

And individual connections:

$ Json /cx/udp:r3r2:3000$ Json 'cx/udp:r3r2:3000'
{
   "uri" : "cx/:cx_id",
   "41.1" : {
      "drop pkts b" : 0,
      "type" : "LF/UDP",
      "rx drop % a" : 0,
      "rpt timer" : "1000",
      "pkt rx a" : 0,
      "avg rtt" : 0,
      "rx drop % b" : 0,
      "name" : "udp:r3r2:3000",
      "endpoints (a ↔ b)" : "udp:r3r2:3000-A <=> udp:r3r2:3000-B",
      "drop pkts a" : 0,
      "entity id" : "NA",
      "bps rx a" : 0,
      "eid" : "1.41",
      "state" : "Stopped",
      "pkt rx b" : 0,
      "bps rx b" : 0
   },
   "handler" : "candela.lanforge.GenericJsonResponder"
}
Technically, colons in URLs need to be encoded as %3A, so the above URL should be /cx/udp%3Ar3r2%3A3000, but curl is pretty darned forgiving.
/endp

Endpoints may be listed and inspected:

$ Json /endp/
            {
   "uri" : "endp",
   "handler" : "candela.lanforge.HttpEndp$JsonResponse",
   "candela.lanforge.HttpEndp" : {
      "duration" : "4"
   },
   "endpoint" : [
      {
         "1.2.8.55.2" : {
            "_links" : "/endp/55",
            "entity id" : "NA",
            "name" : "sta3000-ep-B"
         }
      },
      {
         "1.2.8.57.1" : {
            "_links" : "/endp/57",
            "name" : "udp:r3r2:3000-B",
            "entity id" : "NA"
         }
      },
...
  ]
}
$ Json /endp/sta3000-ep-B
   {
      "candela.lanforge.HttpEndp" : {
         "duration" : "1"
      },
      "uri" : "endp/:endp_id",
      "endpoint" : {
         "rx rate ll" : 0,
         "pdu/s tx" : 0,
         "bursty" : false,
         "rx rate" : 0,
         "tx pkts ll" : 0,
         "rx bytes" : 0,
         "run" : false,
         "tcp rtx" : 0,
         "min pdu" : 1460,
         "pps rx ll" : 0,
         "ooo pkts" : 0,
         "cx to" : 0,
         "tx rate ll" : 0,
         "source addr" : "10.41.0.2 0",
         "name" : "sta3000-ep-B",
         "rx ber" : 0,
         "min rate" : 56000,
         "rx dup %" : 0,
         "max rate" : 56000,
         "tx rate (1 min)" : 0,
         "a/b" : "B",
         "destination addr" : "0.0.0.0 0",
         "dropped" : 0,
         "script" : "None",
         "jitter" : 0,
         "elapsed" : 0,
         "rx rate (1 min)" : 0,
         "tx rate" : 0,
         "1st rx" : -1,
         "tx bytes" : 0,
         "crc fail" : 0,
         "rx wrong dev" : 0,
         "tx pdus" : 0,
         "pattern" : "INCREASING",
         "rx drop %" : 0,
         "entity id" : "NA",
         "cwnd" : 0,
         "delay" : 0,
         "mng" : true,
         "cx estab" : 0,
         "rx pdus" : 0,
         "tcp mss" : "0/0",
         "dup pkts" : 0,
         "rcv buf" : "0/0",
         "pdu/s rx" : 0,
         "rx pkts ll" : 0,
         "max pdu" : 1460,
         "cx active" : 0,
         "eid" : "1.2.8.55",
         "rx ooo %" : 0,
         "replays" : 0,
         "cx estab/s" : 0,
         "pps tx ll" : 0,
         "tx rate (last)" : 0,
         "rx rate (last)" : 0,
         "send buf" : "0/0"
      },
      "handler" : "candela.lanforge.HttpEndp$JsonResponse"
   }

Creating Ports

It is possible to create ports and connections by using the CLI commands. Your LANforge test scenarios (located in the /home/lanforge/DB/ directory) contain all the CLI commands that create your ports and connections. You can submit those commands over HTTP in two ways:

  • /cli-json/$command An example of using the gossip command:
    curl -X POST -H 'Content-type: application/json' \
                   -d '{"message":"hello world"}' http://localhost:8080/cli-json/gossip
    Then check your LANforge GUI messages.
  • /cli-form/$command An example of using the gossip command:
    curl -X POST -d 'message=hello+world' http://localhost:8080/cli/gossip
    Then check your LANforge GUI messages.
  • /cli/: use this method to submit a raw URL-encoded command. This might be useful if you are copying commands directly out of a database:
    curl -X POST -d 'cmd=gossip hello' http://localhost:8080/cli/

Except for /cli-json, these methods accept application/x-www-form-urlencoded content type submissions. This is default for the NanoHttp library and default for curl.

These CLI commands do not return data, only a result code. All data that the Perl scripts would collect from command line queries is sent directly to the GUI. Some CLI commands send data over the websocket, like the diag command.

Command help

Commands are often complex and include a number of bitwise flags to set the state and features of ports. There is presently no tag-substitution for port flags, but there is a help utility that can help you compute them.

http://localhost:8080/help/

Select a command to see the field helper screen:

http://localhost:8080/help/set_port

Type values into the field inputs and the CLI command will be refreshed:

Click the Parse Command button and the values in the command box will be displayed in the curl command and the field inputs. (Notice this form is doing a GET request.)

You may find a list of flag fields that are organized by field names. The text area below the selection list is the sum of the selected fields. Copy the flag values into the input field above to incorporate it into your command.

Creating a WiFi Station

Please refer to the scripts lf_associate_ap.pl and lf_vue_mod.sh for examples of how to produce lists of CLI commands involved in creating stations. Please refer to:

  1. Learn CLI Commands used to operate WiFi stations
  2. and Changing Station WiFi SSID with the CLI API

These will provide ways of collecting the CLI commands in log files for you to place into the command /help/ page.

  • Use ssh to log into your LANforge manager. Use the lf_vue_mod.sh script to create a station:
  • $ cd scripts
    $ ./lf_vue_mod.sh --mgr localhost --resource 3 --create_sta --name sta3101 \
      --radio wiphy1 --ssid idtest-1000-open --passphrase '[BLANK]' \
      --log_cli /tmp/clilog.txt
    
    $ cat /tmp/clilog.txt
    set_wifi_radio 1 3 wiphy1 NA -1 NA NA NA NA NA NA NA NA 0x1 NA
    add_sta 1 3 wiphy1 sta3101 1024 idtest-1000-open NA [BLANK] AUTO NA 00:0e:8e:c1:df:45 8 NA NA NA NA NA 1024
    set_port 1 3 sta3101 0.0.0.0 255.255.0.0 0.0.0.0 NA 2147483648 00:0e:8e:c1:df:45 NA NA NA 8405038 1000 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NONE
  • Enter each command into the your browser toolbar by altering the command into a url:
    1. http://localhost:8080/help/set_wifi_radio?cli=1 3 wiphy1 NA -1 NA NA NA NA NA NA NA NA 0x1 NA
      Produces:
      $ echo 'shelf=1&resource=3&radio=wiphy1&channel=-1&flags=0x1' > /tmp/curl_data
      $ curl -sqv -H 'Accept: application/json' -X POST -d '@/tmp/curl_data' \
       http://localhost:8080/cli-form/set_wifi_radio
    2. http://localhost:8080/help/add_sta?cli=1 3 wiphy1 sta3101 1024 idtest-1000-open NA [BLANK] AUTO NA 00:0e:8e:c1:df:45 8 NA NA NA NA NA 1024
      Produces:
      $ echo 'shelf=1&resource=3&radio=wiphy1&sta_name=sta3101&flags=1024&ssid=idtest-1000-open&key=[BLANK]&ap=AUTO&mac=00:0e:8e:c1:df:45&mode=8&flags_mask=1024' > /tmp/curl_data
      $ curl -sqv -H 'Accept: application/json' -X POST -d '@/tmp/curl_data' \
       http://localhost:8080/cli-form/add_sta
    3. http://localhost:8080/help/set_port?cli=1 3 sta3101 0.0.0.0 255.255.0.0 0.0.0.0 NA 2147483648 00:0e:8e:c1:df:45 NA NA NA 8405038 1000 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NONE
      Produces:
      $ echo 'shelf=1&resource=3&port=sta3101&ip_addr=0.0.0.0&netmask=255.255.0.0&gateway=0.0.0.0&current_flags=2147483648&mac=00:0e:8e:c1:df:45&interest=8405038&report_timer=1000&current_flags_msk=NONE' > /tmp/curl_data
      $ curl -sqv -H 'Accept: application/json' -X POST -d '@/tmp/curl_data' \
       http://localhost:8080/cli-form/set_port
  • Verify with the LANforge GUI the changes you wish to make.

Creating Connections

Using the /cli-json/add_endp and /cli-json/add_cx URLs, it is possible to create Layer-3 connections. Create the Layer-3 endpoints first, of course.

Create L3 Endpoints

Construct your command using the /help/add_endp page. For an example, use these parameters:

alias
enter udp1000-A
shelf
1
resource
2
port
b2000
type
select type.lf_udp
min_rate
1000000 (1 Mbps)
max_rate
SAME
payload_pattern
select payload_pattern.increasing

Click Parse Command and copy the resulting curl command into a text editor:

And for the B endpoint, choose a station:

alias
enter udp1000-B
shelf
1
resource
7
port
sta7000
type
select type.lf_udp
min_rate
54000 (54 Kbps)
max_rate
SAME
payload_pattern
select payload_pattern.increasing

Click Parse Command and copy the resulting curl command into a text editor:

We'll save this file as a shell script: ~/create-endp.sh We can then run it from our terminal like so: bash -x create-endp.sh

We should see the endpoints we've created in the LANforge GUI Endps tab:

Create L3 Connection

With the creation of two endpoints, we can proceed with creating a Layer 3 cross-connect. This is much simpler, it really only takes the names of the two endpoints we created above. We'll choose default_tm for the test manager.

alias
udp1000
test_mgr
default_tm
tx_endp
udp1000-A
rx_endp
udp1000-B

Click the Parse Command button and copy the resulting curl command into your editor with the shell script. Run the script again. It doesn't hurt to re-create the endpoints.

Toggling the Connection

Cross connects have three good state: STOPPED, RUNNING, and QUIESCE. The command to change them is set_cx_state. You will have no trouble creating the command:

test_mgr
default_tm
cx_name
udp1000
cx_state
RUNNING

Click Parse Command and then you can paste the resulting command into your editor.

Advanced Techniques

You can make JSON submissions and you can also submit Base64 encoded values in both form an and JSON submission URLs.

Submitting Base64

Field names that end in -64 are interpreted as base64 encoded values. From a linux terminal, you can convert text to base64 encoded value using the base64 command:

$ echo "RUNNING" | base 64
UlVOTklORwo=

Below is a CLI command example. You typically would not care to spend the effort doing this unless the data you need to express is difficult to URL encode.

$ echo 'test_mgr-64=YW55Cg==&cx_name-64=dWRwMTAwMAo=&cx_state-64=UlVOTklORwo=' > /tmp/curl_data
$ curl -A 'Accept: application/json' -X POST -d @/tmp/curl_data http://host/cli-form?set_cx_state

Submitting JSON

Instead of posting to /cli-form, you can post to /cli-json and your submission will be parsed as a json object. The parameter names stay the same. The base64 name extensions are also available! You need to specify that your Content-type in the POST is application/json.

$ echo '{"test_mgr":"default_tm","cx_name":"udp1000","cx_state":"RUNNING"}' > /tmp/curl_data
$ curl -sq -H 'Content-type: application-json' -H 'Accept: application/json' \
  -X POST -d@/tmp/curl_data http://localhost:8080/cli-json/set_cx_state

Handling Mismatched Column Errors

(This should be fixed as of 2018/08/14) When the LANforge cliet is in GUI mode, the columns of data that are returned match the GUI table columns displayed. You can use the Right-click→Add/Remove Table Columns menu item to change this. We do not recommend doing this for querying JSON data though, because the table columns definitions will not match up to the data the webserver expects to return.

$ curl -sq http://localhost:8080/port | json_pp
{
   "error_list" : [
      "names_to_col_ids map is not going to work:\n[tx abort][25 > 4]\n[cx time (us)][48 > 4]\n[bytes rx ll][33 > 4]\n[bps tx][14 > 4]\n[channel][39 > 4]\n[no cx (us)][47 > 4]\n[rx frame][22 > 4]\n[login-fail][58 > 4]\n[tx hb][28 > 4]\n[mode][40 > 4]\n[anqp time (us)][49 > 4]\n[rx pkts][8 > 4]\n[bytes tx ll][31 > 4]\n[key/phrase][56 > 4]\n[signal][42 > 4]\n[connections][44 > 4]\n[ipv6 gateway][68 > 4]\n[time-stamp][69 > 4]\n[entity id][70 > 4]\n[bps rx ll][32 > 4]\n[rx errors][16 > 4]\n[tx errors][17 > 4]\n[pps tx][13 > 4]\n[rx over][20 > 4]\n[ap][38 > 4]\n[mtu][63 > 4]\n[qlen][62 > 4]\n[beacon][54 > 4]\n[rx drop][18 > 4]\n[tx wind][29 > 4]\n[reset][34 > 4]\n[device][61 > 4]\n[status][37 > 4]\n[activity][41 > 4]\n[cx ago][46 > 4]\n[crypt][51 > 4]\n[rx crc][21 > 4]\n[ipv6 address][67 > 4]\n[logout-ok][59 > 4]\n[parent dev][6 > 4]\n[ssid][55 > 4]\n[tx-rate][35 > 4]\n[mac][66 > 4]\n[login-ok][57 > 4]\n[4way time (us)][50 > 4]\n[logout-fail][60 > 4]\n[rx miss][24 > 4]\n[rx fifo][23 > 4]\n[noise][43 > 4]\n[alias][5 > 4]\n[tx pkts][12 > 4]\n[tx crr][26 > 4]\n[rx length][19 > 4]\n[dhcp (ms)][45 > 4]\n[retry][52 > 4]\n[misc][53 > 4]\n[mask][64 > 4]\n[tx bytes][11 > 4]\n[tx fifo][27 > 4]\n[collisions][15 > 4]\n[pps rx][9 > 4]\n[gateway ip][65 > 4]\n[bps tx ll][30 > 4]\n[rx bytes][7 > 4]\n[bps rx][10 > 4]\n[rx-rate][36 > 4]"
   ],
   "status" : "INTERNAL_ERROR"
}

The terminal you started the LANforge client on will also give a similar error:

1532480073953:  names_to_col_ids size:71
java.lang.IllegalArgumentException: names_to_col_ids map is not going to work:
1532480073953:  lfj_table columns:10

Reset the Table Layout

  1. Right-clicking the Port Mgr and selecting Add/Remove Table Columns will allow you to change this.
  2. Clicking the Select All/None button and then Apply will get all the columns displayed, and returned in your queries.
  3. Make sure to Right-Click → Save Table Layout so that your next session will show all the data.
  4. Restart the LANforge client

Learn CLI commands used to operate WiFi stations.

Goal: Compare and learn script and CLI commands used when creating and operating stations.

The LANforge perl scripts have always been able to print out the CLI commands used to communicate with the LANforger manager. These examples show recent modifications that allow you to collect the CLI commands more easily using the --log_cli switch. (Not all scripts have this feature yet). The --log_cli switch prints CLI commands to your console. You can collect those commands in a file using the switch with an argument of the file name:
 $ ./lf_vue_mod.sh --log_cli /tmp/clilog.txt 

It is possible to repeat these commands using the lf_firemod.pl script:

 $ ./lf_firemod.pl --mgr localhost --action do_cmd \
--cmd "set_port 1 2 sta200 NA NA NA NA 0 NA NA NA NA 8388610"

Requires a LANforge CT520 (or better) system and an access point.

Examples of CLI commands

  1. Creating Stations
  2. Using Open Authentication
  3. Using WPA2 Authentication
  4. Static IP Addresses
  5. Station DHCP IP Address
  6. Creating a Station with a MAC Address Pattern
  7. Admin Down
  8. Admin Up
  9. Deleting a Station
  10. Creating Connections and Running Traffic
  11. Starting and Stopping Traffic
  12. Create a Layer 3 TCP Connection
  13. Create a Layer 3 UDP Connection
  14. Create a Layer 4-7 Web Connection

Setting for Examples

This was done in a two-machine LANforge cluster, the manager named jedtest and the second resource named kedtest. The CLI output of these CLI commands has been discarded as well as any show_port commands.

The show_port commands are useful for inspecting the results of previous commands. Often there is useful wait before issuing the show_port command to allow processing time on the manager. Please inspect the scripts in the /home/lanforge/scripts directory for how and when they tend to sleep.

These commands are also found in the /home/lanforge/DB/DFLT directory files. You cannot run those DB files directly, because they are executed in certain order. However, you can grep for connection- and station-names in those files to find results of GUI commands.

Creating Stations

Using Open Authentication

This station is created with DHCP enabled. That is controlled via flags that are descibed in the add_sta command.

Shell script:
./lf_vue_mod.sh --mgr jedtest --resource 2 --create_sta --name sta100 --radio wiphy0 --security open --ssid jedtest
Perl script:
./lf_associate_ap.pl --mgr jedtest --resource 2 --quiet yes --action add --radio wiphy0 --security open --ssid jedtest --passphrase --first_sta sta100 --first_ip DHCP --num_stations 1
CLI command:
set_wifi_radio 1 2 wiphy0 NA -1 NA NA NA NA NA NA NA NA 0x1 NA
add_sta 1 2 wiphy0 sta100 0 jedtest NA [BLANK] AUTO NA 00:0e:8e:8d:8d:e9 8 NA NA NA NA NA 0
set_port 1 2 sta100 0.0.0.0 255.255.0.0 0.0.0.0 NA 2147483648 00:0e:8e:8d:8d:e9 NA NA NA 8405038 1000 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NONE

Using WPA2 Authentication

This station is created with DHCP enabled. That is controlled via flags that are descibed in the add_sta command.

Shell script:
 $ ./lf_vue_mod.sh --mgr jedtest --resource 2 --create_sta --name sta200 \
  --radio wiphy1 --security wpa2 --ssid jedtest --passphrase jedtest1 \
  --log_cli /tmp/clilog.txt
Perl script:
./lf_associate_ap.pl --mgr jedtest --resource 2 \
  --action add --radio wiphy1 --security wpa2 --ssid jedtest \
  --passphrase jedtest1 --first_sta sta200 --first_ip DHCP --num_stations 1
CLI command:
set_wifi_radio 1 2 wiphy1 NA -1 NA NA NA NA NA NA NA NA 0x1 NA
add_sta 1 2 wiphy1 sta200 1024 jedtest NA jedtest1 AUTO NA 00:0e:8e:6f:01:62 8 NA NA NA NA NA 1024
set_port 1 2 sta200 0.0.0.0 255.255.0.0 0.0.0.0 NA 2147483648 00:0e:8e:6f:01:62 NA NA NA 8405038 1000 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NONE

Static IP Addresses

Here is an example of creating a virtual station with a static address: 10.26.2.14/255.255.254.0

Shell Script:
--
Perl Script:
./lf_associate_ap.pl --mgr jedtest --resource 2 --action add --radio wiphy1 --first_sta sta203 --first_ip 10.26.2.4 --netmask 255.255.254.0 --ssid jedtest --security wpa2 --passphrase jedtest1 --num_stations 1 --wifi_mode abgnAC --log_cli /tmp/clilog.txt
CLI Command:
set_wifi_radio 1 2 wiphy1 NA -1 NA NA NA NA NA NA NA NA 0x1 NA
show_port 1 2 wiphy1
add_sta 1 2 wiphy1 sta203 1024 jedtest NA jedtest1 AUTO NA 00:0e:8e:63:50:62 8 NA NA NA NA NA 1024
set_port 1 2 sta100 10.26.2.4 255.255.254.0 0.0.0.0 NA 0 00:0e:8e:63:50:62 NA NA NA 8388654 1000 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NONE

Station DHCP IP Address

For the station to gain a DHCP IP address, you have to admin-up the station.

Creating a Station with a MAC Address Pattern

The lf_associate_ap script contains logic that parses a MAC address pattern and produces new MAC addresses. This is not a feature of the LANforge Manager. Your CLI calls to the LANforge manager will not parse the mask.

The pattern nomenclature of the LANforge GUI can also be used when specifying a MAC address for stations:

xx
keep parent radio octet
*
randomize this octet
00 - ff
assign this value to the octet
Shell script:
--
Perl script:
./lf_associate_ap.pl --mgr jedtest --resource 2 --action add --radio wiphy1 --first_sta sta205 --first_ip 10.26.2.4 --netmask 255.255.254.0 --ssid jedtest --security wpa2 --passphrase jedtest1 --num_stations 1 --mac-pattern '4e:xx:xx:xx:*:01' --log_cli /tmp/clilog.txt
CLI command:
set_wifi_radio 1 2 wiphy1 NA -1 NA NA NA NA NA NA NA NA 0x1 NA
show_port 1 2 wiphy1
add_sta 1 2 wiphy1 sta205 1024 jedtest NA jedtest1 AUTO NA 4e:0e:8e:43:f1:01 8 NA NA NA NA NA 1024
set_port 1 2 sta205 10.26.2.4 255.255.254.0 0.0.0.0 NA 0 4e:0e:8e:43:f1:01 NA NA NA 8388654 1000 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NONE

Admin Down

Shell script:
./lf_vue_mod.sh --mgr jedtest --resource 2 --down --name sta200 --log_cli /tmp/clilog.txt --quiet 1
Perl script:
./lf_portmod.pl --manager jedtest --card 2 --port_name sta200 --set_ifstate down
CLI command:
set_port 1 2 sta200 NA NA NA NA 1 NA NA NA NA 8388610

Admin Up

Shell script:
./lf_vue_mod.sh --mgr jedtest --resource 2 --up --name sta200 --log_cli /tmp/clilog.txt --quiet 1
Perl script:
./lf_portmod.pl --manager jedtest --card 2 --port_name sta200 --set_ifstate up
CLI command:
set_port 1 2 sta200 NA NA NA NA 0 NA NA NA NA 8388610

Delete Station

Shell script:
./lf_vue_mod.sh --mgr jedtest --resource 2 --delete_sta --name sta200 --log_cli /tmp/clilog.txt --quiet 1
Perl script:
./lf_associate_ap.pl --mgr jedtest --resource 2 --action del --port_del sta200
CLI command:
rm_vlan 1 2 sta100

Creating Connections and Running Traffic

LANforge can create Layer-3 and Layer 4-7 connections using the lf_vue_mod.sh script. When connections are created, they exist in a stopped state. Connections can then have their state changed to RUNNING to start traffic.

Starting and Stopping Traffic

Layer-3 and Layer 4-7 connections both subject to the states STOPPED, RUNNING, and QUIECSE.

Shell script:
./lf_vue_mod.sh --mgr jedtest --start_cx --name tcp200 --log_cli /tmp/clilog.txt --quiet 1
./lf_vue_mod.sh --mgr jedtest --stop_cx --name tcp200 --log_cli /tmp/clilog.txt --quiet 1
Perl script:
./lf_firemod.pl --mgr jedtest --action do_cmd --cmd "set_cx_state default_tm tcp200 RUNNING"
./lf_firemod.pl --mgr jedtest --action do_cmd --cmd "set_cx_state default_tm tcp200 STOPPED"
CLI commands:
set_cx_state default_tm tcp200 RUNNING
set_cx_state default_tm tcp200 STOPPED

Create a Layer 3 TCP Connection

Shell script:
./lf_vue_mod.sh --mgr jedtest --resource 2 --create_cx --name tcp200 --tcp --sta sta200 --port eth1 --bps 1000000 --log_cli /tmp/clilog.txt --quiet 1
Perl script:
./lf_firemod.pl --mgr jedtest --resource 2 --action create_endp --endp_name tcp200-A --speed 1000000 --endp_type lf_tcp --port_name sta200
./lf_firemod.pl --mgr jedtest --resource 2 --action create_endp --endp_name tcp200-B --speed 1000000 --endp_type lf_tcp --port_name eth1
./lf_firemod.pl --mgr jedtest --resource 2 --action create_cx --cx_name tcp200 --cx_endps tcp200-A,tcp200-B
CLI commands:
add_endp tcp200-A 1 2 sta200 lf_tcp -1 NA 1000000 1000000 NA -1 -1 increasing NO NA 0 0
set_endp_report_timer tcp200-A 5000
add_endp tcp200-B 1 2 eth1 lf_tcp -1 NA 1000000 1000000 NA -1 -1 increasing NO NA 0 0
set_endp_report_timer tcp200-B 5000
add_cx tcp200 default_tm tcp200-A tcp200-B
set_cx_report_timer default_tm tcp200 5000 NA 

Create a Layer 3 UDP Connection

Shell script:
./lf_vue_mod.sh --mgr jedtest --resource 2 --create_cx --name upd200 --udp --sta sta200 --port eth1 --bps 2000000 --log_cli /tmp/clilog.txt --quiet 1
Perl script:
./lf_firemod.pl --mgr jedtest --resource 2 --log_cli /tmp/clilog.txt --quiet 1 --action create_endp --endp_name udp200-A --speed 2000000 --endp_type lf_udp --port_name sta200
./lf_firemod.pl --mgr jedtest --resource 2 --log_cli /tmp/clilog.txt --quiet 1 --action create_endp --endp_name udp200-B --speed 2000000 --endp_type lf_udp --port_name eth1
./lf_firemod.pl --mgr jedtest --resource 2 --log_cli /tmp/clilog.txt --quiet 1 --action create_cx --cx_name udp200 --cx_endps udp200-A,udp200-B
CLI commands:
add_endp udp200-A 1 2 sta200 lf_udp -1 NA 2000000 2000000 NA -1 -1 increasing NO NA 0 0
set_endp_report_timer udp200-A 5000
add_endp udp200-B 1 2 eth1 lf_udp -1 NA 2000000 2000000 NA -1 -1 increasing NO NA 0 0
set_endp_report_timer udp200-B 5000
add_cx udp200 default_tm udp200-A udp200-B
set_cx_report_timer default_tm udp200 5000 NA

Create a Layer 4-7 Web Connection

Layer 4-7 connections are created with a one-sided technique, the curl command always operates on the A-side and the B-side is unmanaged. The endpoint and connection naming does not follow the Layer-3 convention.

Shell script:
./lf_vue_mod.sh --mgr jedtest --resource 2 --create_l4 --name yh200 --sta sta200 --url http://www.yahoo.com/ --utm 2400 --log_cli /tmp/clilog.txt --quiet 1
Perl script:
Commands are set using lf_firemod.pl --action do_cmd --cmd ...
CLI commands:
add_l4_endp yh200 1 2 sta200 l4_generic 0 10000 2400 'dl http://www.yahoo.com/ /dev/null' NA NA ca-bundle.crt NA 0 0 60 0 512   0.0.0.0
set_endp_tos yh200 DONT-SET 0
set_endp_flag yh200 L4Enable404 0
set_endp_report_timer yh200 5000
set_endp_flag yh200 ClearPortOnStart 0
set_endp_quiesce yh200 3
add_cx CX_yh200 default_tm yh200

Learn CLI commands used create Generic endpoints.

Goal: Compare and learn script and CLI commands used when creating and operating Generic endpoints.

Similar to the Layer3 perl script, lf_firemod.pl, the lf_generic_ping.pl script has been enhanced to use curl or other commands with parameter expansions. The lf_curl.sh script is a helper script that wraps curl commands and reports success or failure.

Introduced in LANforge 5.3.8.

Example Commands

  1. Creating ports and MAC VLANs
  2. Creating ping endpoints
  3. Creating curl endpoints
  4. Using parameters for endpoint options
  5. Using the lf_curl.shscript

Setting for Examples

Generic endpoints are effectively one-legged connections. You can ping an IP or use curl to download web content. Both of these types of connections can be pointed back at the LANforge itself. We can operate these connections from redirect interfaces. The same techniques can apply to WiFi stations, of course.

Create Redirects

  1. Create a bridge br0 including eth1
  2. In Netsmith, select br0→Modify and enable DHCP
  3. Create a redirect r1a, r1b
  4. Add r1a to br0
  5. Create 10 MAC VLANs based off r1b with DHCP enabled
  6. After the MAC VLAN ports have addresses, you can verify that you can ping and download pages from LANforge webserver:
    1. In a terminal, begin by sourcing lanforge.profile:
      /home/lanforge$ . lanforge.profile
    2. Ping the bridge from a MAC VLAN:
      /home/lanforge$ ping -I 10.41.1.141 10.41.0.1
    3. Grab the web page. (Apache is listening on all ports by default.)
      /home/lanforge$ curl -sq --interface 10.41.1.141 http://10.41.0.1/

Creating ping endpoints

In the /home/lanforge/scripts directory, the lf_generic_ping.pl script creates a wrapped ping command by default. There is another script, lfping, that reports ping results to LANforge. Here is an example of creating 1 ping endpoint:

/home/lanforge/scripts$ ./lf_generic_ping.pl --mgr localhost --resource 1 \
     --dest 10.41.0.1 --interface r1b#0 --name pingtest

Create a ping endpoint for every MAC VLAN parented by r1b:

 $ ./lf_generic_ping.pl --mgr localhost --resource 1 \
     --dest 10.41.0.1 --parent r1b

Create a ping endpoint for every virtual station parented by wiphy0:

 $ ./lf_generic_ping.pl --mgr localhost --resource 1 \
     --dest 10.41.0.1 --radio wiphy0

Create a ping endpoint for every MAC VLAN beginning with r1b#1 (r1b#1, r1b#10):

 $ ./lf_generic_ping.pl --mgr localhost --resource 1 \
     --dest 10.41.0.1 --match 'r1b#1'

Creating curl endpoints

To use other commands with the script, you can create a --cmd parameter. You can use curl directly if desired, but curl's output is not formatted well for LANforge to understand. By default, commands do not understand what port or IP they should be interacting as. We need to provide special parameters to help.

Parameter expansion

The lf_generic_ping.pl script will look for these tokens in the --cmd parameter:

  • %i Expands to the IPv4 address of the port.
  • %d Expands to the destination hostname or address
  • %p Expands to the port name

The curl wrapper script

The scripts/lf_curl.sh script is a wrapper for curl that detects success or failure, and an operate the request in a loop. Expandable parameters are expanded by lf_generic_ping.pl, not lf_curl.sh.

You can use lf_curl.sh from the command line to test it out:

 $ ./lf_curl.sh -i 10.41.1.141 -p r1b#1 -o /tmp/output -d http://example.com/

Executes:

curl -sqLk --interface 10.0.0.1 -o /tmp/output_r1b#1 http://example.com/

So it is best used from lf_generic_ping.pl to construct commands referencing this script:

./lf_generic_ping.pl --mgr localhost --resource 1 \
     --name curl_ex_ --match 'r1b#'  --dest http://10.41.0.1/ \
     --cmd 'lf_curl.sh -o /tmp/curl_%p.out -i %i -d %d -p %p'

Automate WiFi Capacity and other GUI tests.

Goal: Use a command-line script to have the LANforge-GUI run the WiFi Capacity test and generate a pdf automatically.

In this test scenario, a script is used to bring up the WiFi Capacity test with a pre-configured configuration. The capacity test is then started and a report is generated. All of this is automated, and other tests such as Dataplane are also supported. This feature requires LANforge version 5.4.1 or higher.

 
  1. Configure WiFi Capacity Test for automated run.
    1. For this to work, the LANforge GUI must be started with the -cli-socket 3990 argument. This causes it to open a socket to listen for text commands.
    2. Open Chamber View by clicking on the 'Chamber View' button in the LANforge-GUI. Create an appropriate scenario and DUT if you have not already done so. Other cookbook examples have more details of how to do this, please see those if you are unfamiliar with Chamber View. screenshot
    3. Select WiFi Capacity test, and click Run Test to configure it as desired. screenshot
    4. Enter a name in the 'Save' field, click save, and make sure it shows up as a loadable configuration. In this case, we are saving the configuration as 'udp-dl-120' screenshot
  2. Use the lf_gui_cmd.pl script to launch the WiFi Capacity Test.
    1. Open an ssh session or terminal window and log into the LANforge system, or some other system with the LANforge scripts/ repository. On a LANforge system, this will usually be /home/lanforge/scripts In this case, the directory name is called lf_scripts screenshot
    2. Run the lf_gui_cli_cmd.pl script with appropriate arguments. Use --help for details. Once you run this, the WiFi Capacity test should be automatically opened and the test will be started. The script will end when the capacity test has completed. You may copy the results to some easily found location, such as a web server directory. screenshot
    3. For details on what GUI-CLI commands are supported, please see the screen-shot below and look at the contents of the lf_gui_cmd.pl script. screenshot

Querying the LANforge JSON API using Python

Goal: Use Python scripts to query the LANforge Client JSON API. (See ) The provided Python scripts allow you the same API scope as the Perl scripts.

LANforge now provides Python scripts that query the REST API that the LANforge Client now exposes by default. This chapter steps through using each of the scripts. At the end we show an example of how to write a Python script. Scripts encourage Python 3. Requires LANforge 5.4.1 or later.

Client Settings

On your LANforge Server, the scripts directory is located at /home/lanforge/scripts. Under that directory, the py-json directory contains Python scripts.

ScriptPurpose
__init__.pyDefines the py-json module
show_ports.pySimplest example of querying all ports. This is typical of querying any of the APIs you browse from / or /help
create_sta.pyScript creates a virtual station
LANforge/__init__.pyDefines the py-json/LANforge module
LANforge/LFRequest.pyUse the LFRequest module to help make GET and POST requests to the LANforge Client
LANforge/LFUtils.pyUse the LFUtils module to help process JSON results

Getting Started

First, start the LANforge Client (LANforge GUI) and connect it to your LANforge Server. If you want to start the client in headless mode, open a terminal, and from the LANforgeGUI_5.4.1 directory, start the script with the -daemon argument:

$ ./lfclient -daemon -s localhost

Querying Ports

Running the script

In the /home/lanforge/scripts/py-json directory:

 $ python3 ./show_ports.py
{ '1.1.eth0': { '_links': '/port/1/1/0',
                'alias': 'eth0',
                'phantom': False,
                'port': '1.1.00'}}
{ '1.1.eth1': { '_links': '/port/1/1/1',
                'alias': 'eth1',
                'phantom': False,
                'port': '1.1.01'}}
{ '1.1.sta00500': { '_links': '/port/1/1/9',
                    'alias': 'sta00500',
                    'phantom': False,
                    'port': '1.1.09'}}
{ '1.1.sta00501': { '_links': '/port/1/1/10',
                    'alias': 'sta00501',
                    'phantom': False,
                    'port': '1.1.10'}}
{ '1.1.sta00502': { '_links': '/port/1/1/11',
                    'alias': 'sta00502',
                    'phantom': False,
                    'port': '1.1.11'}}

Looking inside the script

This script is a way of pretty-printing the results of GET http://localhost:8080/port/1/1/list

lf_r = LFRequest.LFRequest("http://localhost:8080/port/1/1/list")
json_response = lf_r.getAsJson()
j_printer = pprint.PrettyPrinter(indent=2)
for record in json_response['interfaces']:
     j_printer.pprint(record)

Other variations of this you can try are:

/port/list
This is an abbreviation
/port/1/2/list
If you have a second LANforge resource
/port/1/2/eth0
Show a specific port

Example of Creating a Station

Running the script

[lanforge@ct524-debbie py-json]$ python3 ./create_sta.py
Example 1: will create stations sta0200,sta0201,sta0202
Ex 1: Checking for station : http://localhost:8080/port/1/1/sta0200
...
Ex 1: Next we create stations...
Ex 1: Next we create station sta0200...
Ex 1: station up sta0200...

Example 2: using port list to find stations
Ex 2: checking for station : sta0220
Ex 2: create station sta0220
Ex 2: set port sta0220

Example 3: bring ports up and down
Ex 3: setting ports up...
Ex 3: setting ports down...
...ports are down
Example 4: Modify stations to mode /a
using add_sta to set sta0200 mode

Example 5: change station encryption from wpa2 to wpa3...
using add_sta to set sta0200 wpa3

Example 7: alter TX power on wiphy0...

Looking inside the script

Create a station

lf_r = LFRequest.LFRequest(base_url+"/cli-form/add_sta")

Flags are a decimal equivalent of a hexadecimal bitfield you can submit as either 0x(hex) or (dec) a helper page is available at http://localhost:8080/help/add_sta

You can watch console output of the LANforge GUI client when you get errors to this command, and you can also watch the websocket output for a response to this command at ws://localhost:8081. Use $ wsdump ws://localhost:8081/ to follow those messages.

Modes are listed at http://localhost/LANforgeDocs-5.4.1/lfcli_ug.html or at https://www.candelatech.com/lfcli_ug.html

The MAC address field is a pattern for creation: entirely random mac addresses do not take advantage of address mask matchin in Ath10k hardware, so we developed this pattern to randomize a section of octets:

XX
keep parent
*
randomize
chars [0-9a-f]
use this digit

If you get errors like "X is invalid hex character", this indicates a previous rm_vlan call has not removed your station yet: you cannot rewrite mac addresses with this call, just create new stations.

The staNewDownStaRequest() creates a station in the Admin-Down state. This is a good way to efficiently create batches of stations because it defers all the PHY layer activity which takes significant time when you do it in a loop.

lf_r.addPostData( LFUtils.staNewDownStaRequest(sta_name, resource_id=resource_id, radio=radio, ssid=ssid, passphrase=passphrase))
lf_r.formPost()
sleep(0.05)

Sleeping for 50ms is not sufficient to interact with the station, but is a functional minimum to allow the LANforge to start processing the command; this is a good value to use in a loop that creates stations. Follow with:

LFUtils.waitUntilPortsAppear(resource_id, desired_stations)

Set station up

The LANforge API separates STA creation and Ethernet port settings. We need to revisit the stations we create and amend flags to add things like DHCP or ip+gateway, admin-{up,down} for sta_name in desired_stations:

lf_r = LFRequest.LFRequest(base_url+"/cli-json/set_port")
data = LFUtils.portDhcpUpRequest(resource_id, sta_name)
lf_r.addPostData(data)
lf_r.jsonPost()
sleep(0.05)

Set station down

for sta_name in desired_stations:
   lf_r = LFRequest.LFRequest(base_url+"/cli-json/set_port")
   lf_r.addPostData(LFUtils.portDownRequest(resource_id, sta_name))
   lf_r.jsonPost()
LFUtils.waitUntilPortsAdminDown(resource_id, desired_stations)

Change station mode

There is not a set_sta command. Many LANforge CLI commands do a default modify if the entity already exists. This is how we can modify attributes of existing stations. For the mode values, see http://www.candelatech.com/lfcli_ug.php#add_sta

for sta_name in desired_stations:
  lf_r = LFRequest.LFRequest(base_url+"/cli-json/add_sta")
  lf_r.addPostData({
      "shelf":1,
      "resource": resource_id,
      "radio": radio,
      "sta_name": sta_name,
      "mode": 1, # 802.11a
  })
  lf_r.jsonPost()
  sleep(0.5)

Change station protocol

Flags for add_sta and set_port are actually 64-bit values. When the values in the command below are read by the /help/add_sta page, Javascript cannot deal with integers greater than 32-bits long.

lf_r = LFRequest.LFRequest(base_url+"/cli-json/add_sta")
lf_r.addPostData({
   "shelf":1,
   "resource": resource_id,
   "radio": radio,
   "sta_name": sta_name,
   "mode": 0, # mode AUTO

   # sets use-wpa3
   "flags": 1099511627776,

   # sets interest in use-wpa3, wpa2_enable (becomes zero)
   "flags_mask": 1099511628800
})
print("using add_sta to set %s wpa3"%sta_name)
lf_r.jsonPost()

Change radio power on radio wiphy0

Virtual stations do not have individual tx power states. You can set the radio transmit power. See http://www.candelatech.com/lfcli_ug.php#set_wifi_radio. The txpower is set through iwconfig, so see man 8 iwconfig. Power is in dBm, auto or off.

Not all flags in a JSON request are actually LANforge CLI parameters. The suppress_preexec_method parameter is a meta-flag tells the LANforge client to not check that the port exists before issuing the command. You would use this to expedite a script, because a check-port command is synchronous, not intended to be used in a loop.

lf_r = LFRequest.LFRequest(base_url+"/cli-json/set_wifi_radio")
lf_r.addPostData({
  "shelf":1,
  "resource":resource_id,
  "radio":radio,
  "mode":NA,
  "txpower": "auto",
  "suppress_preexec_method": "true"
})
lf_r.jsonPost()

Seeing Errors

Monitoring for Connection Errors

Use the wsdump utility on the LANforge to see the output of system errors and WiFi Events:

$ wsdump ws://localhost:8081/

The output will be mostly similar to what you see in the WiFi-Messages tab in the GUI:

< {"wifi-event":"1.1:  IFNAME=sta0200 <3>CTRL-EVENT-SCAN-STARTED","timestamp":"2019-11-21T16:00:50.095Z"}
< {"wifi-event":"1.1:  IFNAME=sta0200 <3>CTRL-EVENT-NETWORK-NOT-FOUND","timestamp":"2019-11-21T16:00:50.095Z"}
< {"wifi-event":"1.1:  sta0200 (phy #1): scan started","timestamp":"2019-11-21T16:00:50.095Z"}
< {"wifi-event":"1.1:  sta0200 (phy #1): scan finished: 5745, \"\"","timestamp":"2019-11-21T16:00:50.095Z"}
< {"wifi-event":"1.1:  IFNAME=sta0220 <3>CTRL-EVENT-SCAN-STARTED","timestamp":"2019-11-21T16:00:50.095Z"}
< {"wifi-event":"1.1:  IFNAME=sta0220 <3>CTRL-EVENT-NETWORK-NOT-FOUND","timestamp":"2019-11-21T16:00:50.095Z"}

The message CTRL-EVENT-NETWORK-NOT-FOUND indicates that the SSID we are attempting to connect to is unavailable.

Interpreting Python HTTP Error Output

It won't be uncommon to find errors similar to this:

Url: http://localhost:8080/cli-form/set_port
Error:  <class 'urllib.error.HTTPError'>
Request URL:
'http://localhost:8080/cli-form/set_port'
Request Content-type:
'application/x-www-form-urlencoded'
Request Accept:
'application/json'
Request Data:
(b'shelf=1&resource=1&port=sta0200&current_flags=2147483649&interest=75513858&r'
 b'eport_timer=8000')

The HTTPError exception is just some kind of 500 error and is often timing related. Perl scripts are subject to similar timing issues. When LANforge is busy creating and destroying stations, it is modifying the network stack during each modification...and this takes time.

You can decode this set_port request data by pasting the individual values into the /help/set_port page provided by your LANforge client: http://localhost:8080/help/set_port.

  • shelf 1
  • resource 1
  • port sta0200
  • current_flags 2147483649
  • interest 75513858
  • report_timer 8000
For numerical flag fields, you can use the button to try and decode the values of the flags.

Using the Scripts on Your Laptop

You can copy the py-json directory to your laptop or workstation. You may also use git and clone the LANforge-scripts repository: https://github.com/greearb/lanforge-scripts/.

If you make a script on a Windows laptop and copy it back to your LANforge, please run dos2unix on the script to change the line-ending characters: $ dos2unix myscript.py

Python Module Methods

LFRequest.py

Create a new LFRequest object to help create a request:

lf_r = LFRequest.LFRequest(base_url+"/port/1/1/wiphy0")
wiphy0_json = lf_r.getAsJson()

Your REST requests are discussed in the Querying LANforge GUI for JSON Data chapter.

formPost(show_error=true)
This method formats post data as application/x-www-form-urlencoded data. There should be no significant differience between this and the jsonPost() method.
jsonPost(show_error=true)
This method formats post data as application/json data. There should be no significant differience between this and the formPost() method.
get(show_error=true)
Use this method to do a GET request with 'Accept: application/json' headers. You get unformatted results.
getAsJson()
Formats the results of get() into Objects using json.loads()

LFUtils.py

def staNewDownStaRequest(sta_name, resource_id=1, radio="wiphy0", flags=ADD_STA_FLAGS_DOWN_WPA2, ssid="", passphrase="", debug_on=False):
For use with add_sta. If you don't want to generate mac addresses via patterns (xx:xx:xx:xx:81:*) you can generate octets using random_hex.pop(0)[2:] and gen_mac(parent_radio_mac, octet) See http://localhost:8080/help/add_sta
def portSetDhcpDownRequest(resource_id, port_name, debug_on=False):
Sets port admin down. See http://localhost:8080/help/set_port
def portDhcpUpRequest(resource_id, port_name, debug_on=False):
Sets port up and to use DHCP. See http://localhost:8080/help/set_port
def portUpRequest(resource_id, port_name, debug_on=False):
Sets port up. See http://localhost:8080/help/set_port
def portDownRequest(resource_id, port_name, debug_on=False):
Sets port down. Does not change the use_dhcp flag See http://localhost:8080/help/set_port
def generateMac(parent_mac, random_octet):
Helps generate a random mac address.
def portNameSeries(prefix="sta", start_id=0, end_id=1, padding_number=10000):
This produces a named series similar to "sta000, sta001, sta002...sta0(end_id)" The padding_number is added to the start and end numbers and the resulting sum has the first digit trimmed, so f(0, 1, 10000) => {0000, 0001}
def generateRandomHex():
Use in conjuction with generateMac()
def portAliasesInList(json_list):
Return reverse map of aliases to port records. Normally, you expect nested records, which is an artifact of some ORM that other customers expect:
[
   {
       "1.1.eth0": {
           "alias":"eth0"
       }
   },
   { ... }
]

Naturally, this is more difficult to digest. This method returns a more intuitive structure:

{
      "eth0" : {
         "1.1.eth0": {
              "alias":"eth0"
          },
       },
       "eth1": {},
       ...
}
def findPortEids(resource_id=1, port_names=(), base_url="http://localhost:8080"):
returns PortEID objects matching requested port_names. Use after set_port
def waitUntilPortsAdminDown(resource_id=1, port_list=()):
Sleep and query until all ports report admin down. Use after set_port
def waitUntilPortsAdminUp(resource_id=1, port_list=()):
Sleep and query until all ports report admin up. Use after set_port
def waitUntilPortsDisappear(resource_id=1, port_list=()):
Sleep and query until requested ports have entirely gone away. Use after rm_vlan
def waitUntilPortsAppear(resource_id=1, port_list=()):
Sleep and query until requested ports have appeared. Use after add_sta

Managing WAN Links Using LANforge JSON API

Goal: Create and modify WAN Links Using LANforge JSON API. This cookbook provides examples in Python. (See ) The provided Python scripts allow you the same API scope as the Perl scripts.

This chapter steps through using Python scripts to create and manage WAN Links on a LANforge. Scripts require Python 3. Requires LANforge 5.4.1 or later. Examples require CT910, CT521a, or better.

Creating a WAN Link

We will start by creating a WAN Link between ports eth2 and eth5 on our ct522. Two Ethernet ports will be involved in this example.

The create_wanlink.py Script

This script is located in /home/lanforge/scripts/py-json or on the lanforge-scripts github page. You can copy this script to a new name and edit it to fit your enviroment. Remember, these JSON scripts will be querying a LANforge Client (GUI or headless). The URL you will see being queried is going to be http://localhost:8080/ for these exaples, assuming you are running the LANforge client on the same machine you are running your script.

This script performs the basic tasks you might use to manage WANlink connections:

  • Listing existing WANlinks
  • Removing a WANlink if it exists.
  • Creating WANlink endpoints. You want to create the endpoints before creating the connection.
  • Joining WANlink endpoints into a WANlink connection (CX)
  • Starting the WANlink
  • Modifying the WANlink. You can set endpoint tx rates and lossiness parameters while the endpoints are running.
  • Stopping the WANlink
  • Listing WANlink endpoint stats

Script Sections Explained

  1. Listing Wanlinks

    Notice that when we get a listing response, we are looking for items in the response that are dictionarys with a _links key/value pair. There are other key/values used for diagnostics, such as uri, handler, warnings and errors.

    base_url = "http://localhost:8080"
    json_post = ""
    json_response = ""
    num_wanlinks = -1
    # see if there are old wanlinks to remove
    lf_r = LFRequest.LFRequest(base_url+"/wl/list")
    try:
       json_response = lf_r.getAsJson()
    
       # For debugging, this makes json response more legible:
       LFUtils.debug_printer.pprint(json_response)
       for key,value in json_response.items():
          if (isinstance(value, dict) and "_links" in value):
             num_wanlinks = 1
    except urllib.error.HTTPError as error:
       num_wanlinks = 0;

    JSON output

    {
      "wl_eg1" : {
          "_links" : "/wl/42.6",
          "name" : "wl_eg1",
          "entity id" : "Cross-Connect cx_id: 42, type: 6, idx: 0"
       },
       "uri" : "wl/:wl_id",
       "handler" : "candela.lanforge.GenericJsonResponder"
    }

    If there are no wanlinks, you will only see a warnings block telling you there are connections found that don't apply as WANlinks:

    {
    "warnings" : [
       "HttpWl::selectColumnsFromRow: eid not in table: Cross-Connect cx_id: 17, type: 1, idx: -1",
       "HttpWl::myEvaluateGet: EidCx type 1 (LANforge / UDP) unavailable in WL table: 17.1",
       "HttpWl::selectColumnsFromRow: eid not in table: Cross-Connect cx_id: 18, type: 1, idx: -1",
       "HttpWl::myEvaluateGet: EidCx type 1 (LANforge / UDP) unavailable in WL table: 18.1"
    ],
    "handler" : "candela.lanforge.GenericJsonResponder",
    "uri" : "wl/:wl_id"
    }
  2. Removing a WANlink

    If we found WANlinks, we can remove them by posting the data to the corresponding CLI command URIs: /cli-json/rm_cx and /cli-json/rm_endp.

    Remember the naming convention: Layer-3 and WANlink endpoints end with -A and -B. A WANlink named westin500 has endpoints named westin500-A and westin500-B.
    if (num_wanlinks > 0):
       lf_r = LFRequest.LFRequest(base_url+"/cli-json/rm_cx")
       lf_r.addPostData({
          'test_mgr': 'all', # could be 'default-tm', too
          'cx_name': 'wl_eg1'
       })
       lf_r.jsonPost()
       sleep(0.05)
    

    The parameters for each command can be found via the help page: http://localhost:8080/help/rm_cx.

    Notice that slight pause between commands: 50ms is a good idea between deletion commands.

       lf_r = LFRequest.LFRequest(base_url+"/cli-json/rm_endp")
       lf_r.addPostData({
          'endp_name': 'wl_eg1-A'
       })
       lf_r.jsonPost()
       sleep(0.05)
    
       lf_r = LFRequest.LFRequest(base_url+"/cli-json/rm_endp")
       lf_r.addPostData({
          'endp_name': 'wl_eg1-B'
       })
       lf_r.jsonPost()
       sleep(0.05)
  3. Creating WANLink Endpoints

    Create the two endpoints first. Each side of a WANlink has its own transmission rate, buffer size and corruption parameters. Each WANlink requires an ethernet port. Side A will be 128,000bps with 75ms latency:

    lf_r = LFRequest.LFRequest(base_url+"/cli-json/add_wl_endp")
    lf_r.addPostData({
       'alias': 'wl_eg1-A',
       'shelf': 1,
       'resource': '1',
       'port': 'eth3',
       'latency': '75',
       'max_rate': '128000',
       'description': 'cookbook-example'
    })
    lf_r.jsonPost()
    sleep(0.05)

    Side B will be 256,000bps with 95ms latency:

    lf_r = LFRequest.LFRequest(base_url+"/cli-json/add_wl_endp")
    lf_r.addPostData({
       'alias': 'wl_eg1-B',
       'shelf': 1,
       'resource': '1',
       'port': 'eth5',
       'latency': '95',
       'max_rate': '256000',
       'description': 'cookbook-example'
    })
    lf_r.jsonPost()
    sleep(0.05)
  4. Create the WANlink

    Creating the WANlink is simple, we will add it to the default test manager default-tm:

    lf_r = LFRequest.LFRequest(base_url+"/cli-json/add_cx")
    lf_r.addPostData({
       'alias': 'wl_eg1',
       'test_mgr': 'default_tm',
       'tx_endp': 'wl_eg1-A',
       'rx_endp': 'wl_eg1-B',
    })
    lf_r.jsonPost()
    sleep(0.05)
    
  5. Start the WANLink

    The LANforge server is very asynchronous. Before immediately changing the state on a connection or endpoint, test to see that it exists.

    Polling for the WANlink

    seen = 0
    while (seen < 1):
       sleep(1)
       lf_r = LFRequest.LFRequest(base_url+"/wl/wl_eg1?fields=name,state,_links")

    Note how we can request fields by name, in this case name, state, and _links.

    try:
          json_response = lf_r.getAsJson()
          if (json_response is None):
             continue

    If there is no response, or we get a 400 error, the wanlink has probably not finished creating. Our response will be None.

    In the reponse below, we're testing for dict entries that have the key _links in them. If the name value matches, our WANlink has been created:

          for key,value in json_response.items():
             if (isinstance(value, dict)):
                if ("_links" in value):
                   if (value["name"] == "wl_eg1"):
                      seen = 1

    It might be helpful to use these else clauses when getting started:

                   #else:
                   #   print(" name was not wl_eg1")
                #else:
                #   print("value lacks _links")
             #else:
             #   print("value not a dict")
    
       except urllib.error.HTTPError as error:
          print("Error code "+error.code)
          continue

    Change the WANLink State

    Starting and stopping connections is done by changing the state:

    lf_r = LFRequest.LFRequest(base_url+"/cli-json/set_cx_state")
    lf_r.addPostData({
       'test_mgr': 'all',
       'cx_name': 'wl_eg1',
       'cx_state': 'RUNNING'
    })
    lf_r.jsonPost()

    Polling the WANlink State

    The connection might take a second to start. You can poll it similar to to how we polled it above:

    running = 0
    while (running < 1):
       sleep(1)
       lf_r = LFRequest.LFRequest(base_url+"/wl/wl_eg1?fields=name,state,_links")
       try:
          json_response = lf_r.getAsJson()
          if (json_response is None):
             continue
          for key,value in json_response.items():
             if (isinstance(value, dict)):
                if ("_links" in value):
                   if (value["name"] == "wl_eg1"):
                      if (value["state"].startswith("Run")):
                         running = 1
    
       except urllib.error.HTTPError as error:
          print("Error code "+error.code)
          continue
  6. Modifying the WANlink

    The frequency fields below are in occurrance per million. Speeds are set in bits per second (bps). Latencies are in milliseconds.

    lf_r = LFRequest.LFRequest(base_url+"/cli-json/set_wanlink_info")
    lf_r.addPostData({
       'name': 'wl_eg1-A',
       'speed': 265333,        # bps
       'latency': 30,          # 30 ms
       'reorder_freq': 3200,   #  3200/1000000
       'drop_freq': 2000,      #  2000/1000000
       'dup_freq': 1325,       #  1325/1000000
       'jitter_freq': 25125,   # 25125/1000000
    })
    lf_r.jsonPost()
  7. Stopping the WANlink

    Choose your Stop State

    Stopping a WANlink is again, changing its state to either STOPPED or QUIESCE. The QUIESCE state stops transmission on both endpoints but does not close the connection so that in-flight packets can arrive. Choose QUIESCE if you want to make your accounting of packets the most accurate.

    lf_r = LFRequest.LFRequest(base_url+"/cli-json/set_cx_state")
    lf_r.addPostData({
       'test_mgr': 'all',
       'cx_name': 'wl_eg1',
       'cx_state': 'STOPPED'
    })
    lf_r.jsonPost()

    Poll Untill Stopped

    There might be a milliseconds to seconds of delay depending on how your connection is stopped. You might have to wait for slightly longer than QUIESCE-TIME before the connections are closed when using a QUIESCE stop. Polling the state of the connection is relatively simple:

    running = 1
    while (running > 0):
       sleep(1)
       lf_r = LFRequest.LFRequest(base_url+"/wl/wl_eg1?fields=name,state,_links")
       # LFUtils.debug_printer.pprint(json_response)
       

    You might want to watch that debug output at first.

       try:
          json_response = lf_r.getAsJson()
          if (json_response is None):
             continue
          for key,value in json_response.items():
             if (isinstance(value, dict)):
                if ("_links" in value):
                   if (value["name"] == "wl_eg1"):
                      if (value["state"].startswith("Stop")):
                         LFUtils.debug_printer.pprint(json_response)
                         running = 0
       except urllib.error.HTTPError as error:
          print("Error code "+error.code)
          continue

    JSON Output

    { 'handler': 'candela.lanforge.GenericJsonResponder',
      'uri': 'wl/:wl_id',
      'wl_eg1': { '_links': '/wl/wl_eg1',
                  'name': 'wl_eg1',
                  'state': 'Run'}}
    { 'handler': 'candela.lanforge.GenericJsonResponder',
      'uri': 'wl/:wl_id',
      'wl_eg1': { '_links': '/wl/wl_eg1',
                  'name': 'wl_eg1',
                  'state': 'Stopped'}}
  8. Listing WANlink Endpoint Stats

    Each of the endpoints will show the amount of packets transmitted:

       lf_r = LFRequest.LFRequest(base_url+"/wl_ep/wl_eg1-A")
       json_response = lf_r.getAsJson()
       LFUtils.debug_printer.pprint(json_response)
       

    JSON Output

    The key/value pairs are grouped for this example, but attribute order is not normally ordered.

    {
       "endpoint" : {
          "name" : "wl_eg1-A",
          "buffer"       : 19936,    # bytes
          "corrupt 1"    : 0,     # these corruptions are per-wanpath
          "corrupt 2"    : 0,
          "corrupt 3"    : 0,
          "corrupt 4"    : 0,
          "corrupt 5"    : 0,
          "corrupt 6"    : 0,
          "delay"        : 30000,
          "dropped"      : 0,
          "dropfreq %"   : 0.200000002980232,
          "dup pkts"     : 0,
          "dupfreq %"    : 0.132499992847443,
          "eid"          : "1.1.3.82",
          "elapsed"      : 7,
          "extrabuf"     : 17408,
          "failed-late"  : 0,
          "jitfreq %"    : 2.51250004768372,
          "maxjitter"    : 0,
          "maxlate"      : 606,
          "max rate"     : 265333,
          "ooo pkts"     : 0,
          "qdisc"        : "FIFO",
          "reordfrq %"   : 0.319999992847443,
          "run"          : false,
          "rx bytes"     : 0,
          "rx pkts"      : 0,
          "script"       : "None",      # applicable if 2544 script has be applied
          "serdelay"     : 45648.296875,
          "tx bytes"     : 0,
          "tx drop %"    : 0,
          "tx pkts"      : 0,
          "tx rate"      : 0,
          "tx-failed"    : 0,
          # below is a to-string debug value
          "wps" : "TblJButton, eid: Shelf: 1  Resource: 1  Port: 3  Endpoint: 82  Type: WanLink",
       },
       "uri" : "wl_ep/:wl_ep_id",
       "candela.lanforge.HttpWlEndp" : {
          "duration" : "0"
       },
       "handler" : "candela.lanforge.HttpWlEndp$JsonResponse"
    }

Control a Chamber with the lf_chamber.pl Script

Goal: Monitor and manipulate a CT480a chamber

The CT840a chamber with rotating platform contains an embedded controller that is operated by the modbus protocol. For manual control of the turntable, the LANforge GUI may be used. For automation, you will want to use the lf_chamber.pl script.The lf_chamber.pl script allows you to monitor the door sensor, table angle, light state and fan state. It also provides control over lights, fans, and table position. This script requires a LANforge server version 5.4.1 or higher to communicate with the chamber. A CT521a or a virtual machine instance is adequate for the task. These instructions apply to the CT840a chamber.
 
  1. Configuring the CT840a

    1. The CT840a requires a network connection. Plug an Ethernet cable into the Control LAN port at the bottom rear of the chamber.
      Depending on the date manufacture, these ports might be labeled differently. screenshot
      1. The chamber controller and lights are powered via AC cords at the outside bottom rear of the CT840a chamber.
      2. The Chamber Power or DC port is for 12v or other power required by devices inside the chamber. This runs below the turntable.
      3. The Turnable Power or Plate DC port is for a 12v or other power required by the DUT on the turntable. This is run up to the top of the turntable.
      4. Accessories or DUTs can be cabled to the Device USB port, or USB port.
      5. The USB camera has a dedicated USB port, Camera USB or Camera USB port.
      6. Below the turntable is an Ethernet jack for the DUT to use. That comes out at the Turnable Eth or Plate LAN port. It should be run up to the top of the turntable with the 12v power cord.
      7. The chamber controller is accessed on the network via the Chamber Eth or Control LAN port.
    2. Use the front touch screen to set an IP address screenshot
    3. Make sure you can ping the chamber from your laptop and/or the machine running LANforge server. The LANforge server will communicate over the network to the Chamber Eth port.
    4. The rear ports are all accessory ports for the chamber. screenshot
      1. 120v AC cord for internal power strip. screenshot
        1. This power plug provides power to the chamber modbus controller and the chamber lights.
        2. The turn table power cord plugs into the power strip.
      2. Pass-through DC barrel connectors. Use these for 12v (or other) power needed by devices in the chamber.
      3. SMA connectors. Seal these with terminators when not in use.
      4. Ethernet ports
      5. USB 3-A and USB C port
      6. Type F Coax port. Seal this with terminators when not in use.
      7. Fiber-optic pass-through. Seal this with screw-caps when not in use.
      8. HDMI ports
  2. Configuring the Chamber in LANforge

    1. In the Chamber View window, right-click on the main window and select New Chamber screenshot
    2. You will see the Create/Modify Chamber window. screenshot
    3. Select the chamber and turntable type: screenshot
      1. For Chamber Type, select 2D Large
      2. For Turntable Type, select CT840A
      3. For Turntable, put in the IP address of the chamber screenshot
      4. Select your LANforge server resource that manages the turntable screenshot
      5. Click OK
    4. You will see a new chamber, C0 in the Chamber View window. screenshot
    5. In the Chamber View window, right-click on the chamber C0 and select Modify
    6. Use the Speed and Position fields to adjust the turntable. screenshot
    7. Click Apply to send the configuration.
  3. Scripting Chamber Operations

    1. Connect to your LANforge system and open a terminal. An ssh connection is adequate.
    2. Become root:
        $ sudo -s
    3. The lf_chamber.pl script lives in /home/lanforge
        # cd /home/lanforge
    4. To use the script, you must setup your environment variables located in /home/lanforge/lanforge.profile:
        # source ./lanforge.profile
  4. Now you may operate the script. Just using the script provides you a summary of options:
    # ./lf_chamber.pl
    Usage:
    ./lf_chamber.pl --angle 45 --speed 3 --targ 192.168.100.122
    ./lf_chamber.pl --adjust 5 --targ 192.168.100.122
    ./lf_chamber.pl --fan 1 --targ 192.168.100.122
    ./lf_chamber.pl --lights 1 --targ 192.168.100.122
    ./lf_chamber.pl --status 1 [ --id foo --mgt_pipe /foo/bar ] --targ 192.168.100.122
  5. The following examples are going to use the example IP 10.0.0.9 for the chamber location on the network.
  6. Chamber Status

    1. Use the command ./lf_chamber.pl --targ 10.0.0.9 --status 1
      Current-Angle: 3598 Door-Open: 0 Table-Moving: 0 Lights: 0 Fan: 0 Jog-Speed: 3 Return-Speed: 3 Absolute-Speed: 3 Jog Angle: 449
    2. If you see a lot more output, debugging has been enabled. You will see the individual mbpoll commands: 
      Current-Angle: mbpoll -a 1 -r 4139 -t 4 10.0.0.9 -1 
          Door-Open: mbpoll -a 1 -r 2094 -t 1 10.0.0.9 -1 
          0 Table-Moving: mbpoll -a 1 -r 3046 -t 1 10.0.0.9 -1 
          0 Lights: mbpoll -a 1 -r 1283 -t 1 10.0.0.9 -1 
          0 Fan: mbpoll -a 1 -r 1284 -t 1 10.0.0.9 -1 
          0 Jog-Speed: mbpoll -a 1 -r 4507 -t 4 10.0.0.9 -1 
          3 Return-Speed: mbpoll -a 1 -r 4509 -t 4 10.0.0.9 -1 
          3 Absolute-Speed: mbpoll -a 1 -r 4511 -t 4 10.0.0.9 -1 
          3 Jog Angle: mbpoll -a 1 -r 4513 -t 4 10.0.0.9 -1 
          
    3. If a script is presently moving the table, you will see an error similar to:  
      Current-Angle: /home/lanforge/local/bin/mbpoll: Connection failed: Operation now in progress.
      COMM-FAIL
    4. If there is a LANforge service currently engaging the chamber, you might see this error because   the lanforge service polls the chamber frequently. If you want to stop the LANforge server, use the command:
      sudo service lanforge stop
  7. Controlling the Platform

    1. Use the command ./lf_chamber.pl --targ 10.0.0.9 --angle 45 --speed 3 to rotate the platform 45 degrees from zero.
    2. You will see the Current-Angle and Jog Angle reported in tenths of degrees, so 450 is 45.0 degrees.# ./lf_chamber.pl --targ 10.0.0.9 --status 1
      Current-Angle: 450 Door-Open: 0 Table-Moving: 0 Lights: 0 Fan: 0 Jog-Speed: 3 Return-Speed: 3 Absolute-Speed: 3 Jog Angle: 450
    3. Change argument --angle 45 to --adjust 5 to add five more degrees of rotation:
    4. # ./lf_chamber.pl --targ 10.0.0.9 --adjust 5
      Adjust 5
    5. # ./lf_chamber.pl --targ 10.0.0.9 --status 1
       Current-Angle: 500 Door-Open: 0 Table-Moving: 0 Lights: 0 Fan: 0 Jog-Speed: 3 Return-Speed: 3 Absolute-Speed: 3 Jog Angle: 500
    6. To return the plaform to zero rotation, use --angle 0 argument.
    7. The --speed argument modifies the rate of rotation. Speed 1 is very slow; use speed 3 to save time. Speed 6 might be too fast and your DUT might shift unexpectedly.
    8. If you see output that says mbpoll, you may ignore those lines.
  8. Controlling the Fans

    1. Use the command ./lf_chamber.pl --targ 10.0.0.9 --fan 1 to turn fan on. 
      Toggle fan  
          /home/lanforge/local/bin/mbpoll -a 1 -r 2074 -t 0 10.0.0.9 -1 0 > /dev/null  
          /home/lanforge/local/bin/mbpoll -a 1 -r 2074 -t 0 10.0.0.9 -1 1 > /dev/null 

        # ./lf_chamber.pl --targ 10.0.0.9 --status 1
      Current-Angle: 3598 Door-Open: 0 Table-Moving: 0 Lights: 0 Fan: 1 Jog-Speed: 3 Return-Speed: 3 Absolute-Speed: 3 Jog Angle: 449
    2. Change argument --fan 1 to --fan 0 to turn the fan off:
    3. # ./lf_chamber.pl --targ 10.0.0.9 --fan 0
      Toggle fan  
          /home/lanforge/local/bin/mbpoll -a 1 -r 2074 -t 0 10.0.0.9 -1 0 > /dev/null  
          /home/lanforge/local/bin/mbpoll -a 1 -r 2074 -t 0 10.0.0.9 -1 1 > /dev/null
    4. # ./lf_chamber.pl --targ 10.0.0.9 --status 1
      Current-Angle: 3598 Door-Open: 0 Table-Moving: 0 Lights: 0 Fan: 0 Jog-Speed: 3 Return-Speed: 3 Absolute-Speed: 3 Jog Angle: 449
    5. If you see output that says mbpoll, you may ignore those lines.
  9. Chamber Lights

    1. Use the command ./lf_chamber.pl --targ 10.0.0.9 --lights 1 to turn lights on.
    2. Use the command ./lf_chamber.pl --targ 10.0.0.9 --lights 0 to turn lights off.
    3. The chamber lights are useful when setting up equipment but also for   viewing the equipment with the USB camera.
  10. USB Camera

    1. The USB camera is directly controlled by the connected computer. In the video demonstrations the LANforge system has a USB A-to-USB A cable connected to the chamber to use the camera. The software to use the camera is installed on the LANforge system, it would be one of these: xawtv, cheese or camorama. There is nothing special about the camera, any laptop should be able to use it.

      For more information see USB Cable Types

    2. If you want to browse the camera from any machine on the network, the simplest way to do that is to  use vncviewer/rdesktop to browse the camera software running on the LANforge desktop.
    3. You might notice that the default frame rate of the camera takes a lot of the LANforge CPU time.   It should be possible to use v4l2-ctl to set the frame rate of the camera.
    4. Please note that recording movies using the camera can be done but they will be very large files.   We recommend doing timed frame captures every few seconds to save space.
    5. See also: Video for Linux documentation.

Emulate video streaming traffic with the l3_video_em.pl Script

Goal: Emulate video stream traffic patterns using Layer-3 connections.

Using the l3_video_em.pl and the l3_vid_group.pl, we assemble two test groups of connections, a group of Generic connections, and a group of Layer3 connections, that emulate the bursty buffer filling pattern of traffic that video streaming tends to resemble. Requires LANforge 5.4.2.
 
  1. Begin with stations

    1. Using a CT523c, we can create 16 stations, and for this script setup you probably do not want to create more than that. These scripts poll LANforge every 200ms and that loads the server quickly. If you are using a CT521a or CT522b, then consider starting with five or six stations.
      There needs to be a continuously named series of stations.
      screenshot

      For more information see Creating Stations

    2. In this example we will use eth1 as our upstream port. We will be referring to that using the EID format: 1.1.2

      For more information see LANforge Entity IDs

  2. Create Connections Using l3_vid_group.pl

    1. The script l3_vid_group.pl has help examples. You can do four tasks with the script. screenshot
      1. Create groups of video emulators
      2. Start groups
      3. Stop groups
      4. Destroy groups
    2. We will create a group of 16 connections on our stations. Use the command:
      ./l3_vid_group.pl --action create --endp_type tcp --first_sta sta000
      --num_cx 16 --test_grp sixteen --upstream 1.1.eth1
      screenshot
    3. You will see two test group created. The group named _L3_sixteen contains the Layer-3 tcp connections. The group named sixteen contains Generic connections that control the Layer-3 connections. screenshot
    4. The Generic tab will have 16 connections. screenshot
    5. The Layer-3 tab will have 16 connections. screenshot
    6. When we inspect one of the Generic connections, we can see the command it uses.
      /home/lanforge/scripts/l3_video_em.pl --mgr localhost --mgr_port 4001
      --cx_name _sixteen-0000 --max_tg 1G --buf_size 3145728 --stream yt-sdr-1080p30 --quiet yes
      You can paste this command into a shell prompt on your LANforge and use it. We discuss the options in the following section. screenshot
    7. You can highlight the command in the window and copy it with Ctrl-C screenshot
    8. You can paste the command into the shell with Ctrl-Shift-V screenshot
    9. When we inspect the Layer-3 connection, we see these aspects:
      • It is a TCP connection. This is optional, you can create UDP connections; the Android YouTube app uses TLS over UDP (QUIC protocol) connections.
      • Both endpoints are set at 0 bps transmit. The Generic script will control the throttle on the B-side of the connection.
      • The PDU size is auto. This doesn't have much bearing on TCP, but might have bearing on UDP connections.
      • The Report Timer is set to three seconds. This value is too long to graph with much detail in the Dynamic Report, but you can shorten it to 500ms if you desire to see more resolution in the Dynamic Report graph. This Report Timer value directly impacts processor load, so use it judiciously.
      • Auto-Helper is a new feature intended to reduce CPU load, it has little impact at the moment.
      • Multi-con is not desired for this style of connection.
      screenshot
  3. Exploring l3_video_em.pl

    1. The options for l3_video_em.pl are available with --help. The most important options for tuning video streaming emulation are:
      • tx_style: bufferfill is default and models present video playback
      • max_tx: this is the starting TX rate. The l3_vid_group script defaults this to 1Gbps, which is unrealistic for common WiFi connections. The script will regularly poll the station side for a TX-RATE value of the station to determine a more realistic upper bound for maximum rate. The more stations that share the same channel, the less realistic this rate becomes. We want to know this to some degree so that we can determine a realistic pause between buffer fills at a given bit rate.
      • buf_size: observation of packet captures indicate that a video plugin on a browser buffers three to four megabytes of video. Between this number and our max_tx rate, we can calculate when to transmit to fill the video buffer before it empties.
      • stream_res: This is a list with broadly agreed upon estimates of video bitrates. When people mention frame-rate, that is just part of the bitrate calculation; audio quality, color depth, and resolution are all part of the bitrate value.
      screenshot
    2. A table of stream resolutions are available when you use the --list option. By default, the l3_vid_group.pl script uses the yt-sdr-1080p30 stream size. That name can be decoded like so:
      yt: YouTube (but any popular stream, really)
      sdr: Standard Dynamic Range color, hdr: High Dynamic Range color
      1080: frame height
      p: progressive, i: interlaced
      30: 30 frames per second; smaller bitrates might be 29.9, 25, or 24 screenshot
    3. Running the command

    4. When we run the l3_video_em.pl command that we copied and pasted into our terminal above, we'll see regular output ever several seconds. Lets discuss whats going on: screenshot
      1. Filling yt-sdr-1080p30 3072KB buffer: tells us our video bitrate, and our buffer size (3MB)
      2. est 0.0503 sec: estimate of how long at 1Gbps filling the buffer will take
      3. empties in 3.0016 sec: playback rate before buffer is fully played.
      4. Random start delay: 3.304sec...: the script is waiting this long before starting. This is so that we avoid a load spike, false detections of constant transmit, and more realistic transmit pattern.
      5. Likely overfill detected This warning appears when you transmit longer than your buffer fill takes. Estimates are inaccurate at the start.
      6. drain_wait_seconds is the computed time between stopping and restarting the next transmission. This is our empty time minus our transmit time.
      7. Actual fill: describes how long transmitting a full buffer took.
      8. dev: the difference between estimated fill time and actual fill time.
      9. Setting max_tx to 360000000: indicates we have detected our RX-Rate for our station was detected, and estimates could be better in range. Estimates are only for an isolated station.
  4. Starting and Stopping Connections

    1. You can use the LANforge GUI Test Groups tab or the l3_vid_group.pl script to start and stop connections.
    2. First, make sure you stations are associated. The scripts will not admin-up your stations.
    3. Using the LANforge GUI

      1. Highlight the Test Group holding the Generic connections. In our example that is the group named sixteen
      2. Press the Start button.
      3. The Generic scripts will control the Layer-3 scripts in the _L3_sixteen group.
      4. Stopping the test group will also stop the Layer-3 connections.
    4. Using the l3_vid_group.pl script

      1. Starting the groups uses the --action start argument:
        ./l3_vid_group.pl --test_grp sixteen --action start
      2. Stopping the groups uses the --action stop argument:
        ./l3_vid_group.pl --test_grp sixteen --action stop
  5. Observing Performance

    screenshot
    1. You can observe the performance of the Layer-3 connections using the Dynamic Reports window.
    2. First, use the Rpt Timer combo box to apply a 500ms report timer to the connection. Press Go to apply
    3. Next, right click the connection and select Dynamic Report (or press D)
    4. Observe the bursts of transmission. screenshot
      1. Use the Adjust button to adjust your time window:
      2. Select 30 for max-time-ago
      3. Select 0 for min-time-ago
      4. Click Apply

Candela  Technologies, 2417 Main Street, Suite 201, Ferndale, WA 98248, USA
www.candelatech.com | sales@candelatech.com | +1.360.380.1618
Google+ | Facebook | LinkedIn | Blog