Add UDP ports configuration to IXIA traffic profile 45/60445/6
authorMyron Sosyak <myronx.sosyak@intel.com>
Thu, 2 Aug 2018 13:34:03 +0000 (14:34 +0100)
committerMyron Sosyak <myronx.sosyak@intel.com>
Thu, 2 Aug 2018 13:34:53 +0000 (14:34 +0100)
- 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 <myronx.sosyak@intel.com>
Signed-off-by: Pshyk Serhiy <serhiyx.pshyk@intel.com>
Signed-off-by: Mytnyk, Volodymyr <volodymyrx.mytnyk@intel.com>
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml
yardstick/benchmark/scenarios/networking/vnf_generic.py
yardstick/common/exceptions.py
yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
yardstick/network_services/traffic_profile/ixia_rfc2544.py
yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py
yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py

index b346729..dcf66e0 100644 (file)
@@ -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') }}"
index 513aefb..4c08858 100644 (file)
@@ -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') }}"
index aad7515..7c13e51 100644 (file)
@@ -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') }}"
index a755773..10f10d4 100644 (file)
@@ -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}
index 48f15c0..9fbe199 100644 (file)
@@ -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')
index ba27d4d..2729cf6 100644 (file)
@@ -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)
index 4345533..056f32a 100644 (file)
@@ -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):
index 42ca7f7..4d5276a 100644 (file)
@@ -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]
index 1a33304..6f76eb7 100644 (file)
@@ -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)