+
+ def _add_flows(self):
+ """Add flows to the vswitch
+ """
+ vswitch = self._vswitch_ctl.get_vswitch()
+ # NOTE BOM 15-08-07 the frame mod code assumes that the
+ # physical ports are ports 1 & 2. The actual numbers
+ # need to be retrived from the vSwitch and the metadata value
+ # updated accordingly.
+ bridge = S.getValue('VSWITCH_BRIDGE_NAME')
+ if self._frame_mod == "vlan":
+ # 0x8100 => VLAN ethertype
+ self._logger.debug(" **** VLAN ***** ")
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'actions': ['push_vlan:0x8100', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'actions': ['push_vlan:0x8100', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "mpls":
+ # 0x8847 => MPLS unicast ethertype
+ self._logger.debug(" **** MPLS ***** ")
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'actions': ['push_mpls:0x8847', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'actions': ['push_mpls:0x8847', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "mac":
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'actions': ['mod_dl_src:22:22:22:22:22:22',
+ 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'actions': ['mod_dl_src:11:11:11:11:11:11',
+ 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "dscp":
+ # DSCP 184d == 0x4E<<2 => 'Expedited Forwarding'
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_tos:184', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_tos:184', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "ttl":
+ # 251 and 241 are the highest prime numbers < 255
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_ttl:251', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_ttl:241', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "ip_addr":
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_src:10.10.10.10',
+ 'mod_nw_dst:20.20.20.20',
+ 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_src:20.20.20.20',
+ 'mod_nw_dst:10.10.10.10',
+ 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "ip_port":
+ # NOTE BOM 15-08-27 The traffic generated is assumed
+ # to be UDP (nw_proto 17d) which is the default case but
+ # we will need to pick up the actual traffic params in use.
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'dl_type':'0x0800', 'nw_proto':'17',
+ 'actions': ['mod_tp_src:44444',
+ 'mod_tp_dst:44444', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'dl_type':'0x0800', 'nw_proto':'17',
+ 'actions': ['mod_tp_src:44444',
+ 'mod_tp_dst:44444', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ else:
+ pass
+
+
+ #
+ # TestSteps realted methods
+ #
+ def step_report_status(self, label, status):
+ """ Log status of test step
+ """
+ self._logger.info("%s ... %s", label, 'OK' if status else 'FAILED')
+
+ def step_stop_vnfs(self):
+ """ Stop all VNFs started by TestSteps
+ """
+ for vnf in self._step_vnf_list:
+ if self._step_vnf_list[vnf]:
+ self._step_vnf_list[vnf].stop()
+
+ def step_eval_param(self, param, STEP):
+ # pylint: disable=invalid-name
+ """ Helper function for #STEP macro evaluation
+ """
+ if isinstance(param, str):
+ # evaluate every #STEP reference inside parameter itself
+ macros = re.findall(r'#STEP\[[\w\[\]\-\'\"]+\]', param)
+ if macros:
+ for macro in macros:
+ # pylint: disable=eval-used
+ tmp_val = str(eval(macro[1:]))
+ param = param.replace(macro, tmp_val)
+
+ # evaluate references to vsperf configuration options
+ macros = re.findall(r'\$(([\w\-]+)(\[[\w\[\]\-\'\"]+\])*)', param)
+ if macros:
+ for macro in macros:
+ # pylint: disable=eval-used
+ try:
+ tmp_val = str(eval("S.getValue('{}'){}".format(macro[1], macro[2])))
+ param = param.replace('${}'.format(macro[0]), tmp_val)
+ # ignore that required option can't be evaluated
+ except (IndexError, KeyError, AttributeError):
+ self._logger.debug("Skipping %s as it isn't a configuration "
+ "parameter.", '${}'.format(macro[0]))
+ return param
+ elif isinstance(param, list) or isinstance(param, tuple):
+ tmp_list = []
+ for item in param:
+ tmp_list.append(self.step_eval_param(item, STEP))
+ return tmp_list
+ elif isinstance(param, dict):
+ tmp_dict = {}
+ for (key, value) in param.items():
+ tmp_dict[key] = self.step_eval_param(value, STEP)
+ return tmp_dict
+ else:
+ return param
+
+ def step_eval_params(self, params, step_result):
+ """ Evaluates referrences to results from previous steps
+ """
+ eval_params = []
+ # evaluate all parameters if needed
+ for param in params:
+ eval_params.append(self.step_eval_param(param, step_result))
+ return eval_params
+
+ def step_run(self):
+ """ Execute actions specified by TestSteps list
+
+ :return: False if any error was detected
+ True otherwise
+ """
+ # anything to do?
+ if not self.test:
+ return True
+
+ # required for VNFs initialization
+ loader = Loader()
+ # initialize list with results
+ self._step_result = [None] * len(self.test)
+
+ # We have to suppress pylint report, because test_object has to be set according
+ # to the test step definition
+ # pylint: disable=redefined-variable-type
+ # run test step by step...
+ for i, step in enumerate(self.test):
+ step_ok = not self._step_check
+ if step[0] == 'vswitch':
+ test_object = self._vswitch_ctl.get_vswitch()
+ elif step[0] == 'namespace':
+ test_object = namespace
+ elif step[0] == 'veth':
+ test_object = veth
+ elif step[0] == 'settings':
+ test_object = S
+ elif step[0] == 'tools':
+ test_object = TestStepsTools()
+ step[1] = step[1].title()
+ elif step[0] == 'trafficgen':
+ test_object = self._traffic_ctl
+ # in case of send_traffic or send_traffic_async methods, ensure
+ # that specified traffic values are merged with existing self._traffic
+ if step[1].startswith('send_traffic'):
+ tmp_traffic = copy.deepcopy(self._traffic)
+ tmp_traffic.update(step[2])
+ step[2] = tmp_traffic
+ elif step[0].startswith('vnf'):
+ if not self._step_vnf_list[step[0]]:
+ # initialize new VM
+ self._step_vnf_list[step[0]] = loader.get_vnf_class()()
+ test_object = self._step_vnf_list[step[0]]
+ elif step[0] == 'wait':
+ input(os.linesep + "Step {}: Press Enter to continue with "
+ "the next step...".format(i) + os.linesep + os.linesep)
+ continue
+ elif step[0] == 'sleep':
+ self._logger.debug("Sleep %s seconds", step[1])
+ time.sleep(int(step[1]))
+ continue
+ else:
+ self._logger.error("Unsupported test object %s", step[0])
+ self._step_status = {'status' : False, 'details' : ' '.join(step)}
+ self.step_report_status("Step '{}'".format(' '.join(step)),
+ self._step_status['status'])
+ return False
+
+ test_method = getattr(test_object, step[1])
+ if self._step_check:
+ test_method_check = getattr(test_object, CHECK_PREFIX + step[1])
+ else:
+ test_method_check = None
+
+ step_params = []
+ try:
+ # eval parameters, but use only valid step_results
+ # to support negative indexes
+ step_params = self.step_eval_params(step[2:], self._step_result[:i])
+ step_log = '{} {}'.format(' '.join(step[:2]), step_params)
+ self._logger.debug("Step %s '%s' start", i, step_log)
+ self._step_result[i] = test_method(*step_params)
+ self._logger.debug("Step %s '%s' results '%s'", i,
+ step_log, self._step_result[i])
+ time.sleep(S.getValue('TEST_STEP_DELAY'))
+ if self._step_check:
+ step_ok = test_method_check(self._step_result[i], *step_params)
+ except (AssertionError, AttributeError, IndexError) as ex:
+ step_ok = False
+ self._logger.error("Step %s raised %s", i, type(ex).__name__)
+
+ if self._step_check:
+ self.step_report_status("Step {} - '{}'".format(i, step_log), step_ok)
+
+ if not step_ok:
+ self._step_status = {'status' : False, 'details' : step_log}
+ # Stop all VNFs started by TestSteps
+ self.step_stop_vnfs()
+ return False
+
+ # all steps processed without any issue
+ return True
+
+ #
+ # get methods for TestCase members, which needs to be publicly available
+ #
+ def get_output_file(self):
+ """Return content of self._output_file member
+ """
+ return self._output_file
+
+ def get_desc(self):
+ """Return content of self.desc member
+ """
+ return self.desc
+
+ def get_versions(self):
+ """Return content of self.versions member
+ """
+ return self._versions
+
+ def get_traffic(self):
+ """Return content of self._traffic member
+ """
+ return self._traffic
+
+ def get_tc_results(self):
+ """Return content of self._tc_results member
+ """
+ return self._tc_results
+
+ def get_collector(self):
+ """Return content of self._collector member
+ """
+ return self._collector