From da33d374ef656da0648059439f2e28a0bfe2f13a Mon Sep 17 00:00:00 2001 From: Myron Sosyak Date: Thu, 2 Aug 2018 14:34:03 +0100 Subject: Add UDP ports configuration to IXIA traffic profile - Implemented handling of UDP source and destination ports from IXIA traffic profile. - UDP ports can be defined as a single value or as a random range. Ports range is configured with two parameters 'fixed_bits' and 'mask_bits'. - For example '8-48' range definition will create a repeatable pattern of four values that fall within the range of 8 and 56. JIRA: YARDSTICK-1363 Change-Id: I0ace722f6be843ea79c3d3f4de22cb8fa5669d4f Signed-off-by: Myron Sosyak Signed-off-by: Pshyk Serhiy Signed-off-by: Mytnyk, Volodymyr --- .../traffic_profiles/ixia_ipv4_latency.yaml | 4 ++ .../traffic_profiles/ixia_ipv4_latency_cgnapt.yaml | 4 ++ .../traffic_profiles/ixia_ipv4_latency_vpe.yaml | 5 ++ .../benchmark/scenarios/networking/vnf_generic.py | 1 + yardstick/common/exceptions.py | 4 ++ .../libs/ixia_libs/ixnet/ixnet_api.py | 61 +++++++++++++++++++++ .../traffic_profile/ixia_rfc2544.py | 21 +++++++- .../libs/ixia_libs/test_ixnet_api.py | 63 ++++++++++++++++++++-- .../traffic_profile/test_ixia_rfc2544.py | 16 ++++++ 9 files changed, 174 insertions(+), 5 deletions(-) diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml index b34672907..dcf66e044 100644 --- a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml +++ b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml @@ -58,6 +58,7 @@ uplink_0: srcport: "{{get(flow, 'flow.src_port_0', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_0', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_0: ipv4: id: 2 @@ -89,6 +90,7 @@ downlink_0: srcport: "{{get(flow, 'flow.src_port_0', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_0', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" uplink_1: ipv4: id: 3 @@ -117,6 +119,7 @@ uplink_1: srcport: "{{get(flow, 'flow.src_port_1', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_1', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_1: ipv4: id: 4 @@ -148,3 +151,4 @@ downlink_1: srcport: "{{get(flow, 'flow.dst_port_1', '1234') }}" dstport: "{{get(flow, 'flow.src_port_1', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml index 513aefb40..4c08858cc 100644 --- a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml +++ b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml @@ -56,6 +56,7 @@ uplink_0: srcport: "{{get(flow, 'flow.src_port_0', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_0', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_0: ipv4: id: 2 @@ -82,6 +83,7 @@ downlink_0: srcport: "{{get(flow, 'flow.src_port_0', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_0', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" uplink_1: ipv4: id: 3 @@ -108,6 +110,7 @@ uplink_1: srcport: "{{get(flow, 'flow.src_port_1', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_1', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_1: ipv4: id: 4 @@ -134,3 +137,4 @@ downlink_1: srcport: "{{get(flow, 'flow.dst_port_1', '1234') }}" dstport: "{{get(flow, 'flow.src_port_1', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml index aad751549..7c13e514c 100644 --- a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml +++ b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml @@ -79,6 +79,7 @@ uplink_0: srcport: "{{get(flow, 'flow.src_port_0', '0') }}" dstport: "{{get(flow, 'flow.dst_port_0', '0') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_0: id: 2 ipv4: @@ -104,6 +105,7 @@ downlink_0: srcport: "{{get(flow, 'flow.dst_port_0', '0') }}" dstport: "{{get(flow, 'flow.src_port_0', '0') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" uplink_1: id: 3 ipv4: @@ -131,6 +133,7 @@ uplink_1: proto: "tcp" srcip4: "{{get(flow, 'flow.srcip_1', '192.168.0.0-192.168.255.255') }}" dstip4: "{{get(flow, 'flow.dstip_1', '192.16.0.0-192.16.0.31') }}" + count: "{{get(flow, 'flow.count', '1') }}" ttl: 32 dscp: 32 @@ -138,6 +141,7 @@ uplink_1: srcport: "{{get(flow, 'flow.src_port_1', '0') }}" dstport: "{{get(flow, 'flow.dst_port_1', '0') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_1: id: 4 ipv4: @@ -163,3 +167,4 @@ downlink_1: srcport: "{{get(flow, 'flow.dst_port_1', '0') }}" dstport: "{{get(flow, 'flow.src_port_1', '0') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py index a7557733b..10f10d4e6 100644 --- a/yardstick/benchmark/scenarios/networking/vnf_generic.py +++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py @@ -118,6 +118,7 @@ class NetworkServiceTestCase(scenario_base.Scenario): flow["dst_port_{}".format(index)] = dst_port flow["count"] = fflow["count"] + flow["seed"] = fflow["seed"] except KeyError: flow = {} return {"flow": flow} diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index 48f15c059..9fbe19949 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -88,6 +88,10 @@ class YardstickBannedModuleImported(YardstickException): message = 'Module "%(module)s" cannnot be imported. Reason: "%(reason)s"' +class IXIAUnsupportedProtocol(YardstickException): + message = 'Protocol "%(protocol)" is not supported in IXIA' + + class PayloadMissingAttributes(YardstickException): message = ('Error instantiating a Payload class, missing attributes: ' '%(missing_attributes)s') diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py index ba27d4d05..2729cf6ea 100644 --- a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py +++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py @@ -40,6 +40,8 @@ IP_VERSION_6_MASK = 64 TRAFFIC_STATUS_STARTED = 'started' TRAFFIC_STATUS_STOPPED = 'stopped' +SUPPORTED_PROTO = [PROTO_UDP] + # NOTE(ralonsoh): this pragma will be removed in the last patch of this series class IxNextgen(object): # pragma: no cover @@ -440,6 +442,65 @@ class IxNextgen(object): # pragma: no cover self._get_stack_item(fg_id, PROTO_IPV4)[0], 'dstIp', dstip, 1, dstmask, count) + def update_l4(self, traffic): + """Update the L4 headers + + NOTE: Only UDP is currently supported + :param traffic: list of traffic elements; each traffic element contains + the injection parameter for each flow group + """ + for traffic_param in traffic.values(): + fg_id = str(traffic_param['id']) + if not self._get_config_element_by_flow_group_name(fg_id): + raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) + + proto = traffic_param['outer_l3']['proto'] + if proto not in SUPPORTED_PROTO: + raise exceptions.IXIAUnsupportedProtocol(protocol=proto) + + count = traffic_param['outer_l4']['count'] + seed = traffic_param['outer_l4']['seed'] + + srcport = traffic_param['outer_l4']['srcport'] + srcmask = traffic_param['outer_l4']['srcportmask'] + + dstport = traffic_param['outer_l4']['dstport'] + dstmask = traffic_param['outer_l4']['dstportmask'] + + if proto in SUPPORTED_PROTO: + self._update_udp_port(self._get_stack_item(fg_id, proto)[0], + 'srcPort', srcport, seed, srcmask, count) + + self._update_udp_port(self._get_stack_item(fg_id, proto)[0], + 'dstPort', dstport, seed, dstmask, count) + + def _update_udp_port(self, descriptor, field, value, + seed=1, mask=0, count=1): + """Set the UDP port in a config element stack UDP field + + :param udp_descriptor: (str) UDP descriptor, e.g.: + /traffic/trafficItem:1/configElement:1/stack:"udp-3" + :param field: (str) field name, e.g.: scrPort, dstPort + :param value: (int) UDP port fixed bits + :param seed: (int) seed length + :param mask: (int) UDP port mask + :param count: (int) number of random ports to generate + """ + field_descriptor = self._get_field_in_stack_item(descriptor, field) + + if mask == 0: + seed = count = 1 + + self.ixnet.setMultiAttribute(field_descriptor, + '-auto', 'false', + '-seed', seed, + '-fixedBits', value, + '-randomMask', mask, + '-valueType', 'random', + '-countValue', count) + + self.ixnet.commit() + def _build_stats_map(self, view_obj, name_map): return {data_yardstick: self.ixnet.execute( 'getColumnValues', view_obj, data_ixia) diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py index 43455330f..056f32a57 100644 --- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py +++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py @@ -42,6 +42,13 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): mask = utils.get_mask_from_ip_range(_ip_range[0], _ip_range[1]) return _ip_range[0], mask + def _get_fixed_and_mask(self, port_range): + _port_range = str(port_range).split('-') + if len(_port_range) == 1: + return int(_port_range[0]), 0 + + return int(_port_range[0]), int(_port_range[1]) + def _get_ixia_traffic_profile(self, profile_data, mac=None): mac = {} if mac is None else mac result = {} @@ -70,6 +77,9 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): srcip, srcmask = self._get_ip_and_mask(ip[src_key]) dstip, dstmask = self._get_ip_and_mask(ip[dst_key]) + outer_l4 = value.get('outer_l4') + src_port, src_port_mask = self._get_fixed_and_mask(outer_l4['srcport']) + dst_port, dst_port_mask = self._get_fixed_and_mask(outer_l4['dstport']) result[traffickey] = { 'bidir': False, 'id': port_id, @@ -92,7 +102,15 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): 'type': key, 'proto': ip['proto'], }, - 'outer_l4': value['outer_l4'], + 'outer_l4': { + 'srcport': src_port, + 'dstport': dst_port, + 'srcportmask': src_port_mask, + 'dstportmask': dst_port_mask, + 'count': outer_l4['count'], + 'seed': outer_l4['seed'], + } + } except KeyError: continue @@ -102,6 +120,7 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): def _ixia_traffic_generate(self, traffic, ixia_obj): ixia_obj.update_frame(traffic, self.config.duration) ixia_obj.update_ip_packet(traffic) + ixia_obj.update_l4(traffic) ixia_obj.start_traffic() def update_traffic_profile(self, traffic_generator): diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py index 42ca7f769..4d5276ab8 100644 --- a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py +++ b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py @@ -44,8 +44,12 @@ TRAFFIC_PARAMETERS = { 'srcmask': 24 }, 'outer_l4': { - 'dstport': '2001', - 'srcport': '1234' + 'seed': 1, + 'count': 1, + 'dstport': 2001, + 'srcport': 1234, + 'srcportmask': 0, + 'dstportmask': 0 }, 'traffic_type': 'continuous' }, @@ -69,8 +73,12 @@ TRAFFIC_PARAMETERS = { 'srcmask': 64 }, 'outer_l4': { - 'dstport': '1234', - 'srcport': '2001' + 'seed': 1, + 'count': 1, + 'dstport': 1234, + 'srcport': 2001, + 'srcportmask': 0, + 'dstportmask': 0 }, 'traffic_type': 'continuous' } @@ -357,6 +365,21 @@ class TestIxNextgen(unittest.TestCase): '-randomMask', '0.0.0.63', '-valueType', 'random', '-countValue', 25) + def test__update_udp_port(self): + with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item', + return_value='field_desc'): + self.ixnet_gen._update_udp_port(mock.ANY, mock.ANY, 1234, + 2, 0, 2) + + self.ixnet_gen.ixnet.setMultiAttribute.assert_called_once_with( + 'field_desc', + '-auto', 'false', + '-seed', 1, + '-fixedBits', 1234, + '-randomMask', 0, + '-valueType', 'random', + '-countValue', 1) + def test_update_ip_packet(self): with mock.patch.object(self.ixnet_gen, '_update_ipv4_address') as \ mock_update_add, \ @@ -374,6 +397,38 @@ class TestIxNextgen(unittest.TestCase): with self.assertRaises(exceptions.IxNetworkFlowNotPresent): self.ixnet_gen.update_ip_packet(TRAFFIC_PARAMETERS) + def test_update_l4(self): + with mock.patch.object(self.ixnet_gen, '_update_udp_port') as \ + mock_update_udp, \ + mock.patch.object(self.ixnet_gen, '_get_stack_item'), \ + mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', return_value='celm'): + self.ixnet_gen.update_l4(TRAFFIC_PARAMETERS) + + self.assertEqual(4, len(mock_update_udp.mock_calls)) + + def test_update_l4_exception_no_config_element(self): + with mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', + return_value=None): + with self.assertRaises(exceptions.IxNetworkFlowNotPresent): + self.ixnet_gen.update_l4(TRAFFIC_PARAMETERS) + + def test_update_l4_exception_no_supported_proto(self): + traffic_parameters = { + UPLINK: { + 'id': 1, + 'outer_l3': { + 'proto': 'unsupported', + }, + }, + } + with mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', + return_value='celm'): + with self.assertRaises(exceptions.IXIAUnsupportedProtocol): + self.ixnet_gen.update_l4(traffic_parameters) + @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state') def test_start_traffic(self, mock_ixnextgen_get_traffic_state): self.ixnet_gen._ixnet.getList.return_value = [0] diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py index 1a33304a5..6f76eb77c 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py @@ -462,6 +462,22 @@ class TestIXIARFC2544Profile(unittest.TestCase): self.assertEqual('192.168.1.10', ip) self.assertIsNone(mask) + def test__get_fixed_and_mask_range(self): + fixed_mask = '8-48' + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) + fixed, mask = r_f_c2544_profile._get_fixed_and_mask(fixed_mask) + self.assertEqual(8, fixed) + self.assertEqual(48, mask) + + def test__get_fixed_and_mask_single(self): + fixed_mask = 1234 + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) + fixed, mask = r_f_c2544_profile._get_fixed_and_mask(fixed_mask) + self.assertEqual(1234, fixed) + self.assertEqual(0, mask) + def test__get_ixia_traffic_profile_default_args(self): r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( self.TRAFFIC_PROFILE) -- cgit 1.2.3-korg