Candela Technologies Logo
Network Testing and Emulation Solutions

Create Python Scripts Utilizing the Realm Library

Goal: Create a python script to create stations and Layer-3 cross connects

Using the realm.py library we will write a script that will allow us to automate the creation of stations and Layer-3 cross connects. We will also be able to start and stop traffic over the cross connects using the script. We will be referencing the script, test_ipv4_variable_time.py, as an example throughout this cookbook. Requires LANforge 5.4.2.
 
  1. Starting the script

    1. Setting up inheritance for our object
      1. In order for our script to be platform independent we will need to import sys. Then use
        if 'py-json' not in sys.path:
            sys.path.append(os.path.join(os.path.abspath('..'), 'py-json'))
      2. When creating our object we will need to import the LFCliBase module from the LANforge module using from LANforge.lfcli_base import LFCliBase
      3. After importing LFCliBase we can create our Class and inherit from LFCliBase
    2. Setting up the main method
      1. The main method will typically follow a pattern:
        1. First, the creation of a list of stations. This can be done in many ways.
          Example:
          station_list = LFUtils.port_name_series(prefix_="sta",
              start_id_=0,
              end_id_=4,
              padding_number_=10000)
        2. Following the station list, we can initialize our object:
           ip_var_test = IPV4VariableTime(lfjson_host, lfjson_port, 
              number_template="00",
              sta_list=station_list,
              name_prefix="var_time",
              ssid="testNet",
              password="testPass",
              resource=1,
              security="wpa2",
              test_duration="5m",
              side_a_min_rate=256,
              side_b_min_rate=256)
        3. After our object has been initialized we can begin the testing process. The preferred order for running our tests is to:
          1. Call cleanup() to prevent stations, cross-connects, and endpoints within our list from having creation issues if anything exists with the same name.
          2. Call the build() method in our class to setup the basic versions of the stations, cross-connects, and endpoints.
          3. Call the start() method that will start the test itself, as well as any bring up any stations and start traffic on cross-connects that need it.
          4. Call the stop() method to stop the traffic and bring down any stations that are up.
          5. Verify that the tests passed using our inherited passes() method.
          6. After verifying a pass we can then call our cleanup function again to clean up everything we worked with.
    3. Example Main Method
      def main():
          lfjson_host = "localhost"
          lfjson_port = 8080
          station_list = LFUtils.portNameSeries(prefix_="sta", start_id_=0, end_id_=4, padding_number_=10000)
          ip_var_test = IPV4VariableTime(lfjson_host, lfjson_port, number_template="00", sta_list=station_list,
              name_prefix="var_time",
              ssid="testNet",
              password="testPass",
              resource=1,
              security="wpa2", test_duration="5m",
              side_a_min_rate=256, side_b_min_rate=256),
          ip_var_test.cleanup(station_list)
          ip_var_test.build()
          if not ip_var_test.passes():
              print(ip_var_test.get_fail_message())
              exit(1)
          ip_var_test.start(False, False)
          ip_var_test.stop()
          if not ip_var_test.passes():
              print(ip_var_test.get_fail_message())
              exit(1)
          time.sleep(30)
          ip_var_test.cleanup(station_list)
          if ip_var_test.passes():
              print("Full test passed, all connections increased rx bytes")
  2. Test Methods Available With Realm

    1. Using lfcli_base._pass() and lfcli_base._fail()
      1. Since our class is inheriting lfcli_base.py, we have access to methods that will help us keep track of passes and fails during our tests. We can access them using self._pass() or self._fail(). They will take two parameters, a string message and an optional boolean print_pass and print_fail for _pass() and _fail() respectively. If print_pass or print_fail are set to True, they will write the message to stdout whenever the functions are called.
      2. lfcli_base will add a "PASSED: message" or "FAILED: message" to a list when the tests pass or fail. This list can be accessed using the methods
        get_result_list()
        get_failed_result_list()
        get_fail_message()
        get_all_message()
    2. Using lfcli_base to check test success
      1. passes() will return a boolean depending on whether or not there were any fails in the test. If it finds a fail message it will return False, if none are found it will return True.
        get_result_list() will return all logged pass/fail messages as a list.
        get_failed_result_list() will return a list of only fail messages.
        get_fail_message() will return a list of string of fail messages separated by newlines
        get_message() will return a list of string of all messages separated by newlines
  3. Building a Station

    1. Build Method
      1. We will need to do a number of things to setup our build method.
        1. To begin we will set the security type of our stations using station_profile.use_security()
        2. We will then use station_profile.set_number_template() to name our stations
        3. After this we can set our command flags and parameters using
          self.station_profile.set_command_flag("add_sta","create_admin_down",1)
          self.station_profile.set_command_param("set_port","report_timer",1500)
          self.station_profile.set_command_flag("set_port","rpt_timer", 1)
        4. Once our parameters and flags are set, we can pass a list of stations to station_profile.create() and cx_profile.create(). Our build function could look like this:
          for station in range(len(self.sta_list)):
              temp_sta_list.append(str(self.resource)+"."+self.sta_list[station])
          self.station_profile.create(resource=1, radio="wiphy0", sta_names_=self.sta_list, debug=False)
          self.cx_profile.create(endp_type="lf_udp", side_a=temp_sta_list, side_b="1.eth1", sleep_time=.5)
          self._pass("PASS: Station build finished")
          The naming convention for the sides will look like foo-A for side_a and foo-B for side_b. foo will be set based on the names in the list of stations given.
    2. StationProfile
      1. The preferred method for creating a station_profile is to use the factory method new_station_profile() found in realm
        1. We will need to assign some variables for the creation of our stations before we can call create().
          1. self.station_profile.use_security(security_type, ssid, passwd) is the preferred method to use when setting the security type, ssid, and password variables
            Example:
            self.station_profile.use_security("wpa2", "testNet", "testPass") 
          2. self.station_profile.number_template_ is the numerical prefix for stations. Using a number_template of "00" will have stations look like sta01, sta02...sta10
            Example:
            self.station_profile.number_template_="00"
          3. self.station_profile.mode determines the wifi mode used by the stations. See here for available modes
            Example:
            self.station_profile.mode=0
  4. Cross Connects

    1. Starting and Stopping Traffic
      1. In order for us to be able to start traffic, our stations will need to be admined up, associated, and with an IP. We can bring them up using station_profile.admin_up(). We can then use realm.wait_for_ip(resource, sta_list) to wait for our stations, as well as eth1, to get an IP address.
      2. Once we are sure all of our stations have ip addresses, we can use cx_profile.start_cx() to start the traffic for our cross-connects. When we decide to stop the traffic we can just as easily use cx_profile.stop_cx() to stop traffic.
    2. L3CXProfile
      1. self.local_realm.create_new_l3_cx_profile() is the preferred method for creating a new Layer 3 CX Profile.
        1. We will need to assign some variables for the creation of our stations before we can call create().
          1. self.cx_profile.name_prefix will be used to specify the name prefix for the cx. Assigning self.cx_profile.name_prefix to "test_" would produce cross-connects named test_sta00 with the numbers being dependent on station_profile's number_template.
            Example:
            self.cx_profile.name_prefix="test_"
          2. Set the _min_bps to the desired amount. _max_bps can be set but typically defaults to 0 which sets it to the same as the minimum bps.
            Example:
            self.cx_profile.side_a_min_bps=56000
            self.cx_profile.side_b_min_bps=56000
  5. Using TTLS

    1. TTLS setup requires a few pieces of information to work correctly. StationProfile has a set_wifi_extra() method for setting the relevant variables. See here for the available options
    2. We will need a key management type (key_mgmt), an EAP method (eap), an EAP identity string (identity), an EAP password string (passwd), an 802.11u realm (realm), an 802.11u domain (domain), and an 802.11u HESSID (hessid)
      Example:
      key_mgmt="WPA-EAP"
      eap="TTLS"
      identity="testuser"
      passwd="testpasswd"
      realm="localhost.localdomain"
      domain="localhost.localdomain"
      hessid="00:00:00:00:00:01"
      We can then use these variables to call the set_wifi_extra() method
      Example:
      station_profile.set_wifi_extra(key_mgmt, eap, identity, passwd, realm, domain, hessid)
  6. Cleaning Up

    1. Cleanup stations and cross connects
      1. We have two options for cleaning up everything once we finish:
        1. The preferred method to cleanup is to use the individual cleanup methods found in StationProfile and L3CXProfile. These are station_profile.cleanup(resource, desired_station_list) and cx_profile.cleanup(). These methods are preferred because they will only delete stations, cross-connects, and endpoints created during the test while leaving others untouched.This is useful if you are running other scripts in the background.
        2. The other method for cleanup is to use Realm's remove_all_stations(), remove_all_endps(), and remove_all_cxs() methods. These will remove all stations, cxs, and endpoints that exist. These are good for doing a full cleanup, and it is recommended to use them in the order of cx, endpoint, station to prevent potential issues or missed deletions.
  7. Debugging Stations

    1. Debug information for station creation can be output by setting _debug_on=True in StationProfile.create()
      1. There are a few important debug outputs to pay attention to:
        1. This is the debug output that appears when using the add_sta command. This is used frequently in StationProfile.create(). This debug output will allow you to troubleshoot any flags or other information that is being set when creating your stations. It will output the name at the top and the raw JSON data will follow.

          - 381 - sta0000- - - - - - - - - - - - - - - - - -
          {'flags': 132096,
          'flags_mask': 68719608832,
          'key': 'testPass',
          'mac': 'xx:xx:xx:xx:*:xx',
          'mode': 0,'
          radio': 'wiphy0',
          'resource': 1,
          'shelf': 1,
          'ssid': 'testNet,
          'sta_name': 'sta0000'}
        2. The next bit of debugging output comes from using the set_port command. We are able to see all of the JSON data that is posted, and can use this to check our flags and other info.

          {'current_flags': 2147483649,
          'interest': 8437762,
          'port': 'sta0000',
          'report_timer': 1500,
          'resource': 1,
          'shelf': 1}
          <LANforge.LFRequest.LFRequest object at 0x7f13dbc56850>
          -~381 - - - - - - - - - - - - - - - - - - -
    2. There are a few steps we can take to make validating the information we get through debugging easier.
      1. We can use the help page available on the address of the machine LANforge is running on. http://127.0.0.1/help/ will take us to a page containing all of the commands we can get help with.Default Help Page
      2. Using http://127.0.0.1/help/add_sta will bring us to a page specific to the add_sta command. add_sta Help Page
      3. Here we can enter all of the data we got from our debugging output into the correct areas. Flag Entry Fields
      4. Flag fields have a button next to them that will calculate and highlight relevant flags in the right hand column of the page. This can be useful for checking that the correct flags are being set. Flags Highlighted
      5. After we have done this, we can click the parse command button towards the top of the data inputs. We can then enter this command into LANforge's messages tab in the input box.Parsed Command After Entering Fields

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