--- /dev/null
+import string
+import robot
+
+class Switch:
+ dude = ''
+
+def jamo_was_here():
+ print 'yep yep, yo!'
--- /dev/null
+"""
+Base Switch Object Definition
+Authors: james.luhrsen@hp.com
+Created: 2014-09-20
+"""
+import string
+import robot
+import importlib
+from xml.etree.ElementTree import *
+
+class BaseSwitch(object):
+ '''
+ Switch Base Class
+ '''
+
+ make = ''
+ model = ''
+
+ mgmt_protocol = ''
+ ssh_key = ''
+ mgmt_ip = ''
+ mgmt_port = ''
+ mgmt_user = ''
+ mgmt_password = ''
+ mgmt_prompt = ''
+
+ connection_index = ''
+
+ initialization_type = ''
+
+ of_controller_ip = ''
+
+ connection_configs = []
+
+ initialization_cmds = []
+
+ base_openflow_config = []
+
+ openflow_enable_config = []
+
+ openflow_enable_validations = []
+
+ openflow_disable_config = []
+ openflow_disable_validations = []
+
+ dump_all_flows = []
+
+ src_mac = ''
+ dst_mac = ''
+ ip_src = ''
+ ip_dst = ''
+ table_id = ''
+ action = ''
+
+ datapath_id_output_string = ''
+ datapath_id_output_command = ''
+ datapath_id = ''
+
+ def set_connection_index(self, idx):
+ self.connection_index = idx
+
+ def set_controller_ip(self, ip):
+ self.of_controller_ip = ip
+
+ def set_mgmt_ip(self, ip):
+ self.mgmt_ip = ip
+
+ def set_mgmt_user(self, user):
+ self.mgmt_user = user
+
+ def set_ssh_key(self, key):
+ self.ssh_key = key
+
+ def update_datapath_id(self):
+ raise NotImplementedError("Please implement this method")
+
+ def create_flow_match_elements(self, flow_xml):
+ flow_tree = fromstring(flow_xml)
+
+ self.table_id = flow_tree.find('{urn:opendaylight:flow:inventory}table_id').text
+
+ instructions_element = flow_tree.find('{urn:opendaylight:flow:inventory}instructions')
+ instruction_element = instructions_element.find('{urn:opendaylight:flow:inventory}instruction')
+ apply_actions = instruction_element.find('{urn:opendaylight:flow:inventory}apply-actions')
+ action = apply_actions.find('{urn:opendaylight:flow:inventory}action')
+ output_action = action.find('{urn:opendaylight:flow:inventory}output-action')
+ output_node_connector = output_action.find('{urn:opendaylight:flow:inventory}output-node-connector')
+ self.action = output_node_connector.text
+
+ match_element = flow_tree.find('{urn:opendaylight:flow:inventory}match')
+ ethernet_match_element = match_element.find('{urn:opendaylight:flow:inventory}ethernet-match')
+
+ ethernet_source = ethernet_match_element.find('{urn:opendaylight:flow:inventory}ethernet-source')
+ ethernet_source_address = ethernet_source.find('{urn:opendaylight:flow:inventory}address')
+ self.src_mac = ethernet_source_address.text
+
+ ethernet_destination = ethernet_match_element.find('{urn:opendaylight:flow:inventory}ethernet-destination')
+ ethernet_destination_address = ethernet_destination.find('{urn:opendaylight:flow:inventory}address')
+ self.dst_mac = ethernet_destination_address.text
+
+ self.ip_src = match_element.find('{urn:opendaylight:flow:inventory}ipv4-source').text
+ self.ip_dst = match_element.find('{urn:opendaylight:flow:inventory}ipv4-destination').text
+
+ def convert_hex_to_decimal_as_string(self, hex_string):
+ ##TODO: need to add error checking in case the hex_string is
+ ##not fully hex
+ return str(int(hex_string, 16))
+
+ def get_switch(self, switch_type):
+ '''
+ Generic method that will allow Robot Code to pass a string
+ to this "keyword - Get Switch" and create an object of that
+ type. (EX: Get Switch OVS)
+ '''
+
+ ##TODO: what if the module "switch_type" does not exist. Need some
+ ##error checking for that.
+ module = importlib.import_module(switch_type)
+ return getattr(module, switch_type)()
--- /dev/null
+"""
+Provision 3800 Object Definition
+Authors: james.luhrsen@hp.com
+Created: 2014-10-02
+"""
+import string
+import robot
+import re
+from robot.libraries.BuiltIn import BuiltIn
+from BaseSwitch import *
+
+class H3C(BaseSwitch):
+ '''
+ H3C Super Class
+ '''
+
+ make = 'h3c'
+ model = ''
+
+ mgmt_protocol = 'telnet'
+ mgmt_ip = ''
+ mgmt_port = ''
+ mgmt_prompt = '(' + model + '.*>|' + model + '.*])'
+
+
+ initialization_type = 'reboot'
+
+ of_controller_ip = ''
+ of_instance_id = '21'
+
+ @property
+ def connection_configs(self):
+ return \
+ ['\r\r\r']
+
+ @property
+ def initialization_cmds(self):
+ return \
+ ['\rstartup saved-configuration odl_test_startup_config.cfg main\r', \
+ 'reboot\r', \
+ 'Y\r', \
+ '\r', \
+ 'N\r', \
+ 'Y\r']
+
+ @property
+ def cleanup_cmds(self):
+ return \
+ ['system-view', \
+ 'undo openflow instance ' + self.of_instance_id, \
+ 'return']
+
+ @property
+ def base_openflow_config(self):
+ return \
+ ['system-view', \
+ 'openflow instance ' + self.of_instance_id, \
+ 'classification vlan 1', \
+ 'controller ' + self.of_instance_id + ' address ip ' + self.of_controller_ip, \
+ 'active instance', \
+ 'return']
+
+ @property
+ def openflow_enable_config(self):
+ return \
+ ['system-view', \
+ 'openflow instance ' + self.of_instance_id, \
+ 'classification vlan 1', \
+ 'active instance', \
+ 'return']
+
+ @property
+ def openflow_validation_cmd(self):
+ return \
+ 'display openflow summary'
+
+ @property
+ def openflow_enable_validations(self):
+ return \
+ [self.of_instance_id + ' +Active', \
+ 'Connected 1 24 N']
+
+ @property
+ def openflow_disable_config(self):
+ return \
+ ['system-view', \
+ 'openflow instance ' + self.of_instance_id, \
+ 'undo classification', \
+ 'active instance', \
+ 'return']
+
+ @property
+ def openflow_disable_validations(self):
+ return \
+ [self.of_instance_id + ' +Inactive - +- +- +- +-']
+
+ @property
+ def dump_all_flows(self):
+ return \
+ ['']
+
+ @property
+ def datapath_id_output_command(self):
+ return \
+ 'display openflow summary | include 0x'
+
+ datapath_id_output_string = ''
+ datapath_id = ''
+
+ def update_datapath_id(self):
+ if not self.datapath_id_output_string:
+ self.datapath_id = 'unknown'
+ else:
+ #21 Active 0x0015cc3e5f42ad23 Connected 1 24 N
+ #|---------------------------------(0)---------------------------------|
+ #|------(1)-------||------(2)-----|
+ matches = re.search('(.*0x)(\w+) +Connected', self.datapath_id_output_string)
+ datapath_id_hex = matches.group(2)
+ self.datapath_id = self.convert_hex_to_decimal_as_string(datapath_id_hex)
--- /dev/null
+"""
+Provision 3800 Object Definition
+Authors: james.luhrsen@hp.com
+Created: 2014-10-02
+"""
+import string
+import robot
+import re
+from robot.libraries.BuiltIn import BuiltIn
+from H3C import *
+
+class H3C_5920(H3C):
+ '''
+ Comware 5920
+ '''
+
+ model = '5920'
--- /dev/null
+"""
+Provision 3800 Object Definition
+Authors: james.luhrsen@hp.com
+Created: 2014-10-02
+"""
+import string
+import robot
+import re
+from robot.libraries.BuiltIn import BuiltIn
+from BaseSwitch import *
+
+class Ovs(BaseSwitch):
+ '''
+ OpenVswitch Class
+ '''
+
+ make = 'OpenVswitch'
+ model = 'OVS'
+
+ mgmt_protocol = 'ssh'
+ mgmt_ip = ''
+ mgmt_port = ''
+ mgmt_user = 'mininet'
+ mgmt_password = 'mininet'
+
+ mgmt_prompt = '>'
+
+
+ initialization_type = 'cleanup'
+
+ @property
+ def connection_configs(self):
+ return \
+ ['pwd']
+
+ @property
+ def cleanup_cmds(self):
+ return \
+ ['/sbin/ifconfig | egrep \'^s\' | awk \'{print \"sudo ovs-vsctl del-br\",$1}\' | sh']
+
+ @property
+ def initialization_cmds(self):
+ return \
+ [self.cleanup_cmds]
+
+ @property
+ def base_openflow_config(self):
+ return \
+ ['sudo ovs-vsctl add-br s1', \
+ 'sudo ovs-vsctl set bridge s1 protocols=OpenFlow13', \
+ 'sudo ovs-vsctl set-controller s1 tcp:' + self.of_controller_ip]
+
+ @property
+ def openflow_validation_cmd(self):
+ return \
+ 'sudo ovs-vsctl show'
+
+ @property
+ def openflow_enable_config(self):
+ return \
+ ['sudo ovs-vsctl set-controller s1 tcp:' + self.of_controller_ip]
+
+ @property
+ def openflow_enable_validations(self):
+ return \
+ ['is_connected: true']
+
+ invalid_of_controller_ip = '1.1.1.1'
+ @property
+ def openflow_disable_config(self):
+ return \
+ ['sudo ovs-vsctl set-controller s1 tcp:' + self.invalid_of_controller_ip]
+
+ @property
+ def openflow_disable_validations(self):
+ return \
+ []
+
+ @property
+ def dump_all_flows(self):
+ return \
+ 'sudo /usr/bin/ovs-ofctl dump-flows s1 -O OpenFlow13'
+
+ @property
+ def flow_validations(self):
+ return \
+ ['dl_src=' + self.src_mac + \
+ ',dl_dst=' + self.dst_mac + \
+ ',nw_src=' + self.ip_src + \
+ ',nw_dst=' + self.ip_dst + \
+ ' actions=' + self.action, \
+ 'table=' + self.table_id]
+
+ def create_flow_match_elements(self, flow_xml):
+ super(Ovs, self).create_flow_match_elements(flow_xml)
+ if (self.action == 'INPORT'):
+ self.action = 'IN_PORT'
+
+ @property
+ def datapath_id_output_command(self):
+ return \
+ '/sbin/ifconfig | egrep \'^s1\' | awk \'{print $5}\''
+
+ datapath_id_output_string = ''
+ datapath_id = ''
+
+ def update_datapath_id(self):
+ if not self.datapath_id_output_string:
+ self.datapath_id = 'unknown'
+ else:
+ #32:cc:bf:34:ed:4c
+ datapath_id_hex = re.sub(':', '', self.datapath_id_output_string)
+ self.datapath_id = self.convert_hex_to_decimal_as_string(datapath_id_hex)
--- /dev/null
+"""
+Provision 3800 Object Definition
+Authors: james.luhrsen@hp.com
+Created: 2014-10-02
+"""
+import string
+import robot
+import re
+from robot.libraries.BuiltIn import BuiltIn
+from BaseSwitch import *
+
+class ProVision(BaseSwitch):
+ '''
+ ProVision Super Class
+ '''
+
+ make = 'provision'
+ model = ''
+
+ mgmt_protocol = 'telnet'
+ mgmt_ip = ''
+ mgmt_port = ''
+ mgmt_prompt = model + '.*#'
+
+ initialization_type = 'reboot'
+
+ of_instance_id = '21'
+
+ @property
+ def connection_configs(self):
+ return \
+ ['\rend \
+ \rconfig \
+ \rconsole local-terminal none \
+ \rno page \
+ \rend\r']
+
+ @property
+ def initialization_cmds(self):
+ return \
+ ['\rend\rboot system flash primary config odl_test_startup_config\r', \
+ 'y', \
+ 'n']
+
+ @property
+ def cleanup_cmds(self):
+ return \
+ ['end', \
+ 'config', \
+ 'no openflow\r \
+ y']
+
+ @property
+ def base_openflow_config(self):
+ return \
+ 'end', \
+ 'config', \
+ 'openflow', \
+ 'controller-id ' + self.of_instance_id + ' ip ' + self.of_controller_ip + \
+ ' controller-interface oobm', \
+ 'instance ' + self.of_instance_id, \
+ 'member vlan 10', \
+ 'controller-id ' + self.of_instance_id + ' ', \
+ 'version 1.3', \
+ 'enable', \
+ 'openflow enable', \
+ 'end'
+
+ @property
+ def openflow_enable_config(self):
+ return \
+ ['end', \
+ 'config', \
+ 'openflow enable', \
+ 'end']
+
+ @property
+ def openflow_validation_cmd(self):
+ return \
+ 'show openflow'
+
+ @property
+ def openflow_enable_validations(self):
+ return \
+ ['OpenFlow +: Enabled', \
+ self.of_instance_id + ' +Up +2 +1 +1.3']
+
+ @property
+ def openflow_disable_config(self):
+ return \
+ ['end', \
+ 'config', \
+ 'openflow disable', \
+ 'end']
+
+ @property
+ def openflow_disable_validations(self):
+ return \
+ ['OpenFlow +: Disabled', \
+ self.of_instance_id + ' +Down +0 +0 +1.3']
+
+ @property
+ def dump_all_flows(self):
+ return \
+ 'show openflow instance ' + self.of_instance_id + ' flows'
+
+ @property
+ def flow_validations(self):
+ return \
+ ['(?ms)Flow Table ID : 0.*Flow Table ID : 100.*' + \
+ 'Source Protocol Address : ' + self.ip_src + '.*' + \
+ 'Target Protocol Address : ' + self.ip_dst + '.*' + \
+ 'Flow Table ID : ' + self.table_id + '.*' + self.action, \
+ 'Source MAC : ' + self.src_mac, \
+ 'Destination MAC : ' + self.dst_mac]
+
+ def create_flow_match_elements(self, flow_xml):
+ super(ProVision, self).create_flow_match_elements(flow_xml)
+ self.src_mac = self.format_mac_with_no_hyphens_and_one_colon(self.src_mac)
+ self.dst_mac = self.format_mac_with_no_hyphens_and_one_colon(self.dst_mac)
+ self.action = self.convert_action_to_provision_format(self.action)
+
+ def format_mac_with_no_hyphens_and_one_colon(self, mac):
+ mac_no_colons = re.sub(':', '', mac)
+ mac_with_hyphen = mac_no_colons[:6] + '-' + mac_no_colons[6:]
+ return mac_with_hyphen
+
+ def convert_action_to_provision_format(self, action):
+ if (action == 'INPORT'):
+ return 'Ingress Port'
+ if (action == 'TABLE'):
+ return 'Table'
+ if (action == 'NORMAL'):
+ return 'Normal'
+ if (action == 'FLOOD'):
+ return 'Flood'
+ if (action == 'ALL'):
+ return 'All'
+ if (action == 'CONTROLLER'):
+ return 'Controller Port'
+ if (action == 'LOCAL'):
+ return 'Local'
+
+ @property
+ def datapath_id_output_command(self):
+ return \
+ 'show openflow instance ' + self.of_instance_id + ' | include Datapath'
+
+ connection_index = ''
+
+ def set_connection_index(self, idx):
+ self.connection_index = idx
+
+ datapath_id_output_string = ''
+ datapath_id = ''
+
+ def update_datapath_id(self):
+ if not self.datapath_id_output_string:
+ self.datapath_id = 'unknown'
+ else:
+ #Datapath ID : 000af0921c22bac0
+ #|-----------------(0)---------------------|
+ #|-----------(1)----------| |------(2)-----|
+ matches = re.search('(.*: )(\w+)', self.datapath_id_output_string)
+ datapath_id_hex = matches.group(2)
+ self.datapath_id = self.convert_hex_to_decimal_as_string(datapath_id_hex)
--- /dev/null
+"""
+Provision 3800 Object Definition
+Authors: james.luhrsen@hp.com
+Created: 2014-10-02
+"""
+import string
+import robot
+import re
+from robot.libraries.BuiltIn import BuiltIn
+from ProVision import *
+
+class ProVision_3800(ProVision):
+ '''
+ ProVision 3800
+ '''
+
+ model = '3800'
--- /dev/null
+*** Settings ***
+Library SSHLibrary
+Library Telnet
+
+*** Variables ***
+
+*** Keywords ***
+Get Switch Datapath ID
+ [Arguments] ${switch}
+ [Documentation] Using the connection index for the given switch, will execute the command string
+ ... "datapath_id_output_command" which will store the output in switch.datapath_id_output_string.
+ ... The switch object method "update_datapath_id" is called which is assumed to place the ODL
+ ... friendly (decimal) version of the datapath id in to switch.datapath_id and the value is also
+ ... returned from this keyword.
+ Configure Connection Index And Prompt Wrapper ${switch}
+ Read Wrapper ${switch}
+ ${switch.datapath_id_output_string}= Execute Command Wrapper ${switch} ${switch.datapath_id_output_command}
+ Log ${switch.datapath_id_output_string}
+ Call Method ${switch} update_datapath_id
+ [Return] ${switch.datapath_id}
+
+Verify Switch In Operational Data Store
+ [Arguments] ${switch}
+ [Documentation] Verifies the existence of the switch.datapath_id in the operational datastore.
+ ${resp} Get session ${REST_CONTEXT}
+ Log ${resp.content}
+ Should Match Regexp ${resp.content} openflow:${switch.datapath_id}
+
+Verify Switch Not In Operational Data Store
+ [Arguments] ${switch}
+ [Documentation] Verifies that the given switch.datapath_id is not in the operational datastore.
+ ${resp} Get session ${REST_CONTEXT}
+ Log ${resp.content}
+ Should Not Match Regexp ${resp.content} openflow:${switch.datapath_id}
+
+Iterate Switch Commands From List
+ [Arguments] ${switch} ${cmd_list}
+ [Documentation] Each string in the @{cmd_list} argument is executed on the switch.connection_index.
+ Configure Connection Index And Prompt Wrapper ${switch}
+ : FOR ${cmd} IN @{cmd_list}
+ \ Log ${cmd}
+ \ Read Wrapper ${switch}
+ \ Execute Command Wrapper ${switch} ${cmd}
+
+Configure OpenFlow
+ [Arguments] ${switch}
+ [Documentation] The commands neccessary to configure openflow on the given switch object should exist in the switch.base_openflow_config attribute. \ Also, the commands/logic to verify that openflow is working are checked in this keyword and come
+ ... from switch.openflow_validation_cmd output where the validation strings are
+ ... stored in switch.openflow_enable_validations
+ Log Applying configs to configure openflow on the given switch.
+ Configure Connection Index And Prompt Wrapper ${switch}
+ Iterate Switch Commands From List ${switch} ${switch.base_openflow_config}
+ Read Wrapper ${switch}
+ Wait Until Keyword Succeeds 10s 1s Validate Switch Output ${switch} ${switch.openflow_validation_cmd} ${switch.openflow_enable_validations}
+ Read Wrapper ${switch}
+
+Validate Switch Output
+ [Arguments] ${switch} ${cmd} ${validations} ${should_exist}=true
+ [Documentation] A generic keyword that will execute one command on the switch, and check for each string in the @{validations} argument. \ There is a boolean flag ${should_exist} that can be used to check that the validations are or are NOT in the output of the command executed.
+ Configure Connection Index And Prompt Wrapper ${switch}
+ Read Wrapper ${switch}
+ ${tmp}= Execute Command Wrapper ${switch} /sbin/ifconfig
+ Log ${tmp}
+ ${output}= Execute Command Wrapper ${switch} ${cmd}
+ Log ${output}
+ : FOR ${str} IN @{validations}
+ \ Run Keyword If "${should_exist}" == "true" Should Match Regexp ${output} ${str}
+ \ Run Keyword If "${should_exist}" == "false" Should Not Match Regexp ${output} ${str}
+
+Enable OpenFlow
+ [Arguments] ${switch}
+ [Documentation] executes the switch.openflow_enable_config on the given switch and validates that openflow is operational with the switch.openflow_validation_command against all the strings in the switch.openflow_enable_validations list.
+ Log Will toggle openflow to be ON
+ Iterate Switch Commands From List ${switch} ${switch.openflow_enable_config}
+ Read Wrapper ${switch}
+ Wait Until Keyword Succeeds 10s 1s Validate Switch Output ${switch} ${switch.openflow_validation_cmd} ${switch.openflow_enable_validations}
+
+Disable OpenFlow
+ [Arguments] ${switch}
+ [Documentation] executes the switch.openflow_disable_config on the given switch and validates that openflow is NOT operational with the switch.openflow_validation_command against all the strings in the switch.openflow_disable_validations list.
+ Log Will toggle openflow to be OFF
+ Iterate Switch Commands From List ${switch} ${switch.openflow_disable_config}
+ Read Wrapper ${switch}
+ Wait Until Keyword Succeeds 10s 1s Validate Switch Output ${switch} ${switch.openflow_validation_cmd} ${switch.openflow_disable_validations}
+
+Open Connection Wrapper
+ [Arguments] ${switch}
+ [Documentation] Some switches require telnet access and others require ssh access. \ Based on the
+ ... switch.mgmt_protocol, the connection open will be handled by the right robot
+ ... library (Telnet or SSHLibrary). \ The connection_index is returned.
+ Run Keyword If "${switch.mgmt_protocol}" == "ssh" Call Method ${switch} set_ssh_key ${USER_HOME}/.ssh/id_rsa
+ Run Keyword If "${switch.mgmt_protocol}" == "ssh" Call Method ${switch} set_mgmt_user ${MININET_USER}
+ ${connection_index}= Run Keyword If "${switch.mgmt_protocol}" == "ssh" SSHLibrary.Open Connection ${switch.mgmt_ip} prompt=${switch.mgmt_prompt}
+ Run Keyword If "${switch.mgmt_protocol}" == "ssh" Login With Public Key ${switch.mgmt_user} ${switch.ssh_key} any
+ ${connection_index}= Run Keyword If "${switch.mgmt_protocol}" == "telnet" Telnet.Open Connection ${switch.mgmt_ip} ELSE Set Variable
+ ... ${connection_index}
+ [Return] ${connection_index}
+
+Configure Connection Index And Prompt Wrapper
+ [Arguments] ${switch}
+ [Documentation] when using multiple switch connections (e.g. more than one switch device) this keyword will switch the current connection index and prompt so that the following
+ ... Read or Write actions happen on the correct device.
+ Run Keyword If "${switch.mgmt_protocol}" == "ssh" SSHLibrary.Switch Connection ${switch.connection_index}
+ Run Keyword If "${switch.mgmt_protocol}" == "ssh" SSHLibrary.Set Client Configuration prompt=${switch.mgmt_prompt} timeout=5s
+ Run Keyword If "${switch.mgmt_protocol}" == "telnet" Telnet.Switch Connection ${switch.connection_index}
+ Run Keyword If "${switch.mgmt_protocol}" == "telnet" Telnet.Set Prompt ${switch.mgmt_prompt} True
+
+Read Wrapper
+ [Arguments] ${switch}
+ [Documentation] Wraps the Read command so that depending on the switch.mgmt_protocol the right
+ ... library (Telnet or SSHLibrary) is used.
+ Run Keyword If "${switch.mgmt_protocol}" == "ssh" SSHLibrary.Read
+ Run Keyword If "${switch.mgmt_protocol}" == "telnet" Telnet.Read
+
+Write Bare Wrapper
+ [Arguments] ${switch} ${cmd}
+ [Documentation] Wraps the Write Bare command so that depending on the switch.mgmt_protocol the right
+ ... library (Telnet or SSHLibrary) is used.
+ Run Keyword If "${switch.mgmt_protocol}" == "ssh" SSHLibrary.Write Bare ${cmd}
+ Run Keyword If "${switch.mgmt_protocol}" == "telnet" Telnet.Write Bare ${cmd}
+
+Execute Command Wrapper
+ [Arguments] ${switch} ${cmd}
+ [Documentation] Wraps the Execute Command keyword so that depending on the switch.mgmt_protocol the right
+ ... library (Telnet or SSHLibrary) is used.
+ ${output}= Run Keyword If "${switch.mgmt_protocol}" == "ssh" SSHLibrary.Execute Command ${cmd}
+ ${output}= Run Keyword If "${switch.mgmt_protocol}" == "telnet" Telnet.Execute Command ${cmd} ELSE Set Variable
+ ... ${output}
+ [Return] ${output}
+
+Connect To Switch
+ [Arguments] ${switch}
+ [Documentation] Will Open a connection to the switch, which will set the switch.connection_index.
+ ... For each switch.connection_configs string, a write bare will be executed on the
+ ... switch connection. \ The write bare is done becuase some switch consoles require
+ ... extra input (CR/LF, etc.) that are needed. \ The connection_configs strings should
+ ... be sufficient to put the switch console in to a usuable state so that further
+ ... interactions with the switch can be used with the robot keyword "Execute
+ ... Command"
+ ${connection_index}= Open Connection Wrapper ${switch}
+ Call Method ${switch} set_connection_index ${connection_index}
+ Configure Connection Index And Prompt Wrapper ${switch}
+ : FOR ${cmd} IN @{switch.connection_configs}
+ \ Write Bare Wrapper ${switch} ${cmd}
+ \ Sleep 1
+ \ Read Wrapper ${switch}
+
+Cleanup Switch
+ [Arguments] ${switch}
+ [Documentation] will execute and command strings stored in switch.cleanup_cmds
+ Iterate Switch Commands From List ${switch} ${switch.cleanup_cmds}
+
+Initialize Switch
+ [Arguments] ${switch}
+ [Documentation] Will connect and execute all switch.initialization_cmds on the given switch.
+ ... In some cases, this may be a reboot. \ If so, the switch.initialization_type can
+ ... be set to "reboot" and further logic is invoked to wait for the reboot to complete
+ ... and a reconnect to the switch is made.
+ Connect To Switch ${switch}
+ Configure Connection Index And Prompt Wrapper ${switch}
+ : FOR ${cmd} IN @{switch.initialization_cmds}
+ \ Write Bare Wrapper ${switch} ${cmd}
+ \ Sleep 1
+ \ Run Keyword And Ignore Error Read Wrapper ${switch}
+ Run Keyword If "${switch.initialization_type}" == "reboot" Wait For Switch Reboot ${switch}
+ Run Keyword If "${switch.initialization_type}" == "reboot" Connect To Switch ${switch}
+
+Wait For Switch Reboot
+ [Arguments] ${switch}
+ [Documentation] If a switch has been set to reboot, it may take some time. \ This keyword will first
+ ... make sure the switch has gone down (10 pings over 10 seconds should not see
+ ... a 100% success, although it may respond for a short time after the reload is
+ ... issued). \ Then a poll is done with a single ping request every 5s until a success
+ ... is found, at which point it is assumed the switch is up and ready.
+ ${output}= Run ping ${switch.mgmt_ip} -c 10 -W 1
+ Should Not Contain ${output} 10 packets transmitted, 10 received, 0% packet loss Does not appear that switch has rebooted
+ Wait Until Keyword Succeeds 240s 5s Ping ${switch.mgmt_ip}
+
+Ping
+ [Arguments] ${ip}
+ ${output}= Run ping ${ip} -c 1 -W 1
+ Should Contain ${output} 1 packets transmitted, 1 received
--- /dev/null
+*** Settings ***
+Documentation TODO
+Suite Setup Switch Qualification Suite Setup
+Suite Teardown Switch Qualification Suite Teardown
+Test Timeout 5m
+Library Collections
+Library OperatingSystem
+Resource ../../../libraries/SwitchUtils.txt
+Resource ../../../libraries/Utils.txt
+Library ../../../libraries/RequestsLibrary.py
+Library ../../../libraries/Common.py
+Library ../../../libraries/SwitchClasses/${SWITCH_CLASS}.py
+Variables ../../../variables/Variables.py
+
+*** Variables ***
+${SWITCH_CLASS} Ovs
+${SWITCH_IP} ${MININET}
+${CONTROLLER} null
+${REST_CONTEXT} /restconf/operational/opendaylight-inventory:nodes
+
+*** Test Cases ***
+OF1.3 Connection Between Switch and Controller
+ [Tags] switch_qualification
+ Configure OpenFlow ${test_switch}
+ Enable OpenFlow ${test_switch}
+ ${datapath_id_from_switch}= Get Switch Datapath ID ${test_switch}
+ Verify Switch In Operational Data Store ${test_switch}
+ Disable OpenFlow ${test_switch}
+ Verify Switch Not In Operational Data Store ${test_switch}
+ ##MORE CHECKS TO ADD ON SWITCH AND OPERATIONAL DATA STORE
+ ##- proper OF version
+ ##- proper default flow rules
+ ##- ???
+
+*** Keywords ***
+Switch Qualification Suite Setup
+ ${test_switch}= Get Switch ${SWITCH_CLASS}
+ Set Suite Variable ${test_switch}
+ Call Method ${test_switch} set_mgmt_ip ${SWITCH_IP}
+ Call Method ${test_switch} set_controller_ip ${CONTROLLER}
+ Log MAKE: ${test_switch.make}\n MODEL: ${test_switch.model}\n IP: ${test_switch.mgmt_ip}\n PROMPT: ${test_switch.mgmt_prompt}\n CONTROLLER_IP: ${test_switch.of_controller_ip}\n MGMT_PROTOCOL: ${test_switch.mgmt_protocol}
+ Ping ${test_switch.mgmt_ip}
+ Initialize Switch ${test_switch}
+ Create Session session http://${CONTROLLER}:${RESTCONFPORT} auth=${AUTH} headers=${HEADERS_XML}
+
+Switch Qualification Suite Teardown
+ Cleanup Switch ${test_switch}
+ SSHLibrary.Close All Connections
+ Telnet.Close All Connections
... - output ANY
...
... NOTE: for OVS, INPORT does not appear to be supported
-Suite Setup Create Session session http://${CONTROLLER}:${RESTCONFPORT} auth=${AUTH} headers=${HEADERS_XML}
-Suite Teardown Delete All Sessions
+Suite Setup OpenFlow Actions Suite Setup
+Suite Teardown OpenFlow Actions Suite Teardown
Test Template Create And Remove Flow
-Library SSHLibrary
Library Collections
Library OperatingSystem
Library String
Library XML
Resource ../../../libraries/FlowLib.txt
+Resource ../../../libraries/SwitchUtils.txt
Library ../../../libraries/RequestsLibrary.py
Library ../../../libraries/Common.py
Variables ../../../variables/Variables.py
+Library ../../../libraries/SwitchClasses/${SWITCH_CLASS}.py
*** Variables ***
+${SWITCH_CLASS} Ovs
+${SWITCH_IP} ${MININET}
+${CONTROLLER} null
${REST_CON} /restconf/config/opendaylight-inventory:nodes
${REST_OPR} /restconf/operational/opendaylight-inventory:nodes
${ipv4_src} 11.3.0.0/16
${eth_type} 0x800
${eth_src} 00:ab:cd:ef:01:23
${eth_dst} ff:ff:ff:ff:ff:ff
-${node_id} openflow:1
##documentation strings
${INPORT_doc} OF1.3: OFPP_INPORT = 0xfffffff8, /* Send the packet out the input port. This\nreserved port must be explicitly used\nin order to send back out of the input\nport. */\n
${TABLE_doc} OF1.3: OFPP_TABLE = 0xfffffff9, /* Submit the packet to the first flow table NB: This destination port can only be used in packet-out messages. */
${LOCAL_doc} OF1.3 OFPP_LOCAL = 0xfffffffe, /* Local openflow "port". */
${ANY_doc} OF1.3 OFPP_ANY = 0xffffffff /* Wildcard port used only for flow mod (delete) and flow stats requests. Selects all flows regardless of output port (including flows with no output port). */
-*** Test Cases *** output port tableID flowID verify OVS? OVS specific strings
+*** Test Cases *** output port tableID flowID
INPORT [Documentation] ${INPORT_doc}
[Tags] inport
- ${TEST_NAME} 22 161 yes actions=IN_PORT
+ ${TEST_NAME} 200 161
TABLE [Documentation] ${TABLE_doc}
[Tags] table
- ${TEST_NAME} 29 261 yes actions=${TEST_NAME}
+ ${TEST_NAME} 200 261
NORMAL [Documentation] ${NORMAL_doc}
[Tags] normal
- ${TEST_NAME} 13 361 yes actions=${TEST_NAME}
+ ${TEST_NAME} 200 361
FLOOD [Documentation] ${FLOOD_doc}
[Tags] flood
- ${TEST_NAME} 47 81 yes actions=${TEST_NAME}
+ ${TEST_NAME} 200 81
ALL [Documentation] ${ALL_doc}
[Tags] all
- ${TEST_NAME} 42 88 yes actions=${TEST_NAME}
+ ${TEST_NAME} 200 88
CONTROLLER [Documentation] ${CONTROLLER_doc}
[Tags] controller
- ${TEST_NAME} 81 21 yes actions=${TEST_NAME}
+ ${TEST_NAME} 200 21
LOCAL [Documentation] ${LOCAL_doc}
[Tags] local
- ${TEST_NAME} 122 32 yes actions=${TEST_NAME}
+ ${TEST_NAME} 200 32
ANY [Documentation] ${ANY_doc}
[Tags] any
- ${TEST_NAME} 222 111 yes actions=${TEST_NAME}
+ ${TEST_NAME} 200 111
*** Keywords ***
Create And Remove Flow
- [Arguments] ${output_port} ${table_id} ${flow_id} ${verify_switch_flag} ${additional_ovs_flowelements}
- Remove Default Flows ${node_id}
- @{OVS_FLOWELEMENTS} Create List dl_dst=${eth_dst} table=${table_id} dl_src=${eth_src} nw_src=${ipv4_src} nw_dst=${ipv4_dst}
- ... ${additional_ovs_flowelements}
+ [Arguments] ${output_port} ${table_id} ${flow_id}
##The dictionaries here will be used to populate the match and action elements of the flow mod
${ethernet_match_dict}= Create Dictionary type=${eth_type} destination=${eth_dst} source=${eth_src}
${ipv4_match_dict}= Create Dictionary source=${ipv4_src} destination=${ipv4_dst}
Set Flow Ethernet Match ${flow} ${ethernet_match_dict}
Set Flow IPv4 Match ${flow} ${ipv4_match_dict}
Log Flow XML is ${flow.xml}
- Add Flow To Controller And Verify ${flow.xml} ${node_id} ${flow.table_id} ${flow.id}
- Run Keyword If "${verify_switch_flag}" == "yes" Verify Flow On Mininet Switch ${OVS_FLOWELEMENTS}
- Remove Flow From Controller And Verify ${flow.xml} ${node_id} ${flow.table_id} ${flow.id}
- Run Keyword If "${verify_switch_flag}" == "yes" Verify Flow Does Not Exist On Mininet Switch ${OVS_FLOWELEMENTS}
+ Call Method ${test_switch} create_flow_match_elements ${flow.xml}
+ Log ${test_switch.flow_validations}
+ ${dpid_id}= Get Switch Datapath ID ${test_switch}
+ Add Flow To Controller And Verify ${flow.xml} openflow:${dpid_id} ${flow.table_id} ${flow.id}
+ Validate Switch Output ${test_switch} ${test_switch.dump_all_flows} ${test_switch.flow_validations}
+ Remove Flow From Controller And Verify ${flow.xml} openflow:${dpid_id} ${flow.table_id} ${flow.id}
+ Validate Switch Output ${test_switch} ${test_switch.dump_all_flows} ${test_switch.flow_validations} false
+
+OpenFlow Actions Suite Setup
+ ${test_switch}= Get Switch ${SWITCH_CLASS}
+ Set Suite Variable ${test_switch}
+ Call Method ${test_switch} set_mgmt_ip ${SWITCH_IP}
+ Call Method ${test_switch} set_controller_ip ${CONTROLLER}
+ Log MAKE: ${test_switch.make}\n MODEL: ${test_switch.model}\n IP: ${test_switch.mgmt_ip}\n PROMPT: ${test_switch.mgmt_prompt}\n CONTROLLER_IP: ${test_switch.of_controller_ip}\n MGMT_PROTOCOL: ${test_switch.mgmt_protocol}
+ Ping ${test_switch.mgmt_ip}
+ Initialize Switch ${test_switch}
+ Configure OpenFlow ${test_switch}
+ Create Session session http://${CONTROLLER}:${RESTCONFPORT} auth=${AUTH} headers=${HEADERS_XML}
+
+OpenFlow Actions Suite Teardown
+ Cleanup Switch ${test_switch}
+ SSHLibrary.Close All Connections
+ Telnet.Close All Connections
CONTROLLER = '127.0.0.1'
PORT = '8080'
RESTPORT = '8080'
-RESTCONFPORT = '8080'
+RESTCONFPORT = '8181'
PREFIX = 'http://' + CONTROLLER + ':' + PORT
CONTAINER = 'default'
USER = 'admin'