Add IxNetwork L3 scenario implementation 11/65811/15
authorMyron Sosyak <myronx.sosyak@intel.com>
Thu, 13 Dec 2018 17:53:07 +0000 (17:53 +0000)
committerMyron Sosyak <myronx.sosyak@intel.com>
Thu, 27 Dec 2018 14:04:20 +0000 (14:04 +0000)
Protocol interfaces are creating with config from pod file
Static IP configuration are creating from testcase flow options

JIRA: YARDSTICK-1570

Change-Id: I74cde67b5084d5b65d09934fe8fce7760b5ea461
Signed-off-by: Myron Sosyak <myronx.sosyak@intel.com>
samples/vnf_samples/nsut/agnostic/tc_baremetal_rfc2544_latency_ipv4_64B_ixia_L3.yaml [new file with mode: 0644]
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_L3.yaml [new file with mode: 0644]
yardstick/common/exceptions.py
yardstick/common/utils.py
yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
yardstick/tests/unit/common/test_utils.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py

diff --git a/samples/vnf_samples/nsut/agnostic/tc_baremetal_rfc2544_latency_ipv4_64B_ixia_L3.yaml b/samples/vnf_samples/nsut/agnostic/tc_baremetal_rfc2544_latency_ipv4_64B_ixia_L3.yaml
new file mode 100644 (file)
index 0000000..1610193
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright (c) 2018 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+{% set vports = vports or 2 %}
+---
+schema: yardstick:task:0.1
+scenarios:
+- type: NSPerf
+  traffic_profile: ../../traffic_profiles/ixia_ipv4_latency_L3.yaml
+  topology: agnostic_vnf_topology_ixia_{{ vports }}ports.yaml
+  ixia_config: IxiaL3
+  extra_args:
+    vports: {{ vports }}
+  nodes:
+    tg__0: tg_0.yardstick
+    vnf__0: vnf_0.yardstick
+  options:
+    framesize:
+      uplink: {64B: 100}
+      downlink: {64B: 100}
+    flow:
+      src_ip:
+{% for vport in range(0,vports,2|int) %}
+        - '152.{{ vport }}.0.1-152.{{ vport }}.0.50'
+{% endfor %}
+      dst_ip:
+{% for vport in range(1,vports,2|int) %}
+        - '152.{{ vport }}.1.1-152.{{ vport }}.1.150'
+{% endfor %}
+      count: 1
+    traffic_type: 4
+    rfc2544:
+      allowed_drop_rate: 0.0001 - 0.0001
+    vnf__0:
+      []
+  runner:
+    type: Iteration
+    iterations: 10
+    interval: 35
+context:
+  type: Node
+  name: yardstick
+  nfvi_type: baremetal
+  file: /etc/yardstick/nodes/pod_ixia.yaml
diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_L3.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_L3.yaml
new file mode 100644 (file)
index 0000000..e7221b1
--- /dev/null
@@ -0,0 +1,64 @@
+# Copyright (c) 2018 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+{% set vports = get(extra_args, 'vports', '2') %}
+---
+schema: "nsb:traffic_profile:0.1"
+
+# This file is a template, it will be filled with values from tc.yaml before passing to the traffic generator
+
+name:            rfc2544
+description:     Traffic profile to run RFC2544 latency with L3 support
+traffic_profile:
+  traffic_type : IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput
+  frame_rate : 100  # pc of linerate
+  duration: {{ duration }}
+  enable_latency: True
+
+{% for vport in range(vports|int) %}
+uplink_{{ vport }}:
+  ipv4:
+    id: {{ (vport * 2) + 1 }}
+    outer_l2:
+      framesize:
+        64B: "{{get(imix, 'imix.uplink.64B', '0') }}"
+        128B: "{{get(imix, 'imix.uplink.128B', '0') }}"
+        256B: "{{get(imix, 'imix.uplink.256B', '0') }}"
+        373b: "{{get(imix, 'imix.uplink.373B', '0') }}"
+        512B: "{{get(imix, 'imix.uplink.512B', '0') }}"
+        570B: "{{get(imix, 'imix.uplink.570B', '0') }}"
+        1024B: "{{get(imix, 'imix.uplink.1024B', '0') }}"
+        1280B: "{{get(imix, 'imix.uplink.1280B', '0') }}"
+        1400B: "{{get(imix, 'imix.uplink.1400B', '0') }}"
+        1500B: "{{get(imix, 'imix.uplink.1500B', '0') }}"
+        1518B: "{{get(imix, 'imix.uplink.1518B', '0') }}"
+
+downlink_{{vport}}:
+  ipv4:
+    id: {{ (vport * 2) + 2 }}
+    outer_l2:
+      framesize:
+        64B: "{{get(imix, 'imix.downlink.64B', '0') }}"
+        128B: "{{get(imix, 'imix.downlink.128B', '0') }}"
+        256B: "{{get(imix, 'imix.downlink.256B', '0') }}"
+        373b: "{{get(imix, 'imix.downlink.373B', '0') }}"
+        512B: "{{get(imix, 'imix.downlink.512B', '0') }}"
+        570B: "{{get(imix, 'imix.downlink.570B', '0') }}"
+        1024B: "{{get(imix, 'imix.downlink.1024B', '0') }}"
+        1280B: "{{get(imix, 'imix.downlink.1280B', '0') }}"
+        1400B: "{{get(imix, 'imix.downlink.1400B', '0') }}"
+        1500B: "{{get(imix, 'imix.downlink.1500B', '0') }}"
+        1518B: "{{get(imix, 'imix.downlink.1518B', '0') }}"
+{% endfor %}
index 5e0df97..f62f02f 100644 (file)
@@ -405,6 +405,10 @@ class IxNetworkFieldNotPresentInStackItem(YardstickException):
     message = 'Field "%(field_name)s" not present in stack item %(stack_item)s'
 
 
+class IncorrectFlowOption(YardstickException):
+    message = 'Flow option {option} for {link} is incorrect'
+
+
 class SLAValidationError(YardstickException):
     message = '%(case_name)s SLA validation failed. Error: %(error_msg)s'
 
index 51313ef..9eba896 100644 (file)
@@ -293,6 +293,17 @@ def make_ipv4_address(ip_addr):
     return ipaddress.IPv4Address(six.text_type(ip_addr))
 
 
+def get_ip_range_count(iprange):
+    start_range, end_range = iprange.split("-")
+    start = int(make_ipv4_address(start_range))
+    end = int(make_ipv4_address(end_range))
+    return end - start
+
+
+def get_ip_range_start(iprange):
+    return str(make_ipv4_address(iprange.split("-")[0]))
+
+
 def safe_ip_address(ip_addr):
     """ get ip address version v6 or v4 """
     try:
index 6645d45..ede03a8 100644 (file)
@@ -152,6 +152,9 @@ class IxNextgen(object):  # pragma: no cover
         vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport')
         return vports
 
+    def get_static_interface(self, vport):
+        return self.ixnet.getList(vport, 'interface')
+
     def _get_config_element_by_flow_group_name(self, flow_group_name):
         """Get a config element using the flow group name
 
index 1d37f8f..4d6bd42 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2016-2017 Intel Corporation
+# Copyright (c) 2016-2018 Intel Corporation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ import logging
 import six
 
 from yardstick.common import utils
+from yardstick.common import exceptions
 from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api
 from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen
 from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper
@@ -31,6 +32,8 @@ WAIT_PROTOCOLS_STARTED = 360
 
 
 class IxiaBasicScenario(object):
+    """Ixia Basic scenario for flow from port to port"""
+
     def __init__(self, client, context_cfg, ixia_cfg):
 
         self.client = client
@@ -43,6 +46,12 @@ class IxiaBasicScenario(object):
     def apply_config(self):
         pass
 
+    def run_protocols(self):
+        pass
+
+    def stop_protocols(self):
+        pass
+
     def create_traffic_model(self, traffic_profile=None):
         # pylint: disable=unused-argument
         vports = self.client.get_vports()
@@ -51,11 +60,81 @@ class IxiaBasicScenario(object):
         self.client.create_traffic_model(self._uplink_vports,
                                          self._downlink_vports)
 
-    def run_protocols(self):
-        pass
 
-    def stop_protocols(self):
-        pass
+class IxiaL3Scenario(IxiaBasicScenario):
+    """Ixia scenario for L3 flow between static ip's"""
+
+    def _add_static_ips(self):
+        vports = self.client.get_vports()
+        uplink_intf_vport = [(self.client.get_static_interface(vport), vport)
+                             for vport in vports[::2]]
+        downlink_intf_vport = [(self.client.get_static_interface(vport), vport)
+                               for vport in vports[1::2]]
+
+        for index in range(len(uplink_intf_vport)):
+            intf, vport = uplink_intf_vport[index]
+            try:
+                iprange = self.ixia_cfg['flow'].get('src_ip')[index]
+                start_ip = utils.get_ip_range_start(iprange)
+                count = utils.get_ip_range_count(iprange)
+                self.client.add_static_ipv4(intf, vport, start_ip, count)
+            except IndexError:
+                raise exceptions.IncorrectFlowOption(
+                    option="src_ip", link="uplink_{}".format(index))
+
+            intf, vport = downlink_intf_vport[index]
+            try:
+                iprange = self.ixia_cfg['flow'].get('dst_ip')[index]
+                start_ip = utils.get_ip_range_start(iprange)
+                count = utils.get_ip_range_count(iprange)
+                self.client.add_static_ipv4(intf, vport, start_ip, count)
+            except IndexError:
+                raise exceptions.IncorrectFlowOption(
+                    option="dst_ip", link="downlink_{}".format(index))
+
+    def _add_interfaces(self):
+        vports = self.client.get_vports()
+        uplink_vports = (vport for vport in vports[::2])
+        downlink_vports = (vport for vport in vports[1::2])
+
+        ix_node = next(node for _, node in self.context_cfg['nodes'].items()
+                       if node['role'] == 'IxNet')
+
+        for intf in ix_node['interfaces'].values():
+            ip = intf.get('local_ip')
+            mac = intf.get('local_mac')
+            gateway = None
+            try:
+                gateway = next(route.get('gateway')
+                               for route in ix_node.get('routing_table')
+                               if route.get('if') == intf.get('ifname'))
+            except StopIteration:
+                LOG.debug("Gateway not provided")
+
+            if 'uplink' in intf.get('vld_id'):
+                self.client.add_interface(next(uplink_vports),
+                                          ip, mac, gateway)
+            else:
+                self.client.add_interface(next(downlink_vports),
+                                          ip, mac, gateway)
+
+    def apply_config(self):
+        self._add_interfaces()
+        self._add_static_ips()
+
+    def create_traffic_model(self, traffic_profile=None):
+        # pylint: disable=unused-argument
+        vports = self.client.get_vports()
+        self._uplink_vports = vports[::2]
+        self._downlink_vports = vports[1::2]
+
+        uplink_endpoints = [port + '/protocols/static'
+                            for port in self._uplink_vports]
+        downlink_endpoints = [port + '/protocols/static'
+                              for port in self._downlink_vports]
+
+        self.client.create_ipv4_traffic_model(uplink_endpoints,
+                                              downlink_endpoints)
 
 
 class IxiaPppoeClientScenario(object):
@@ -370,6 +449,7 @@ class IxiaResourceHelper(ClientResourceHelper):
 
         self._ixia_scenarios = {
             "IxiaBasic": IxiaBasicScenario,
+            "IxiaL3": IxiaL3Scenario,
             "IxiaPppoeClient": IxiaPppoeClientScenario,
         }
 
index c0c9289..6b8d819 100644 (file)
@@ -1135,6 +1135,15 @@ class TestUtilsIpAddrMethods(ut_base.BaseUnitTestCase):
         for addr in addr_list:
             self.assertRaises(Exception, utils.make_ipv4_address, addr)
 
+    def test_get_ip_range_count(self):
+        iprange = "192.168.0.1-192.168.0.25"
+        count = utils.get_ip_range_count(iprange)
+        self.assertEqual(count, 24)
+
+    def test_get_ip_range_start(self):
+        iprange = "192.168.0.1-192.168.0.25"
+        start = utils.get_ip_range_start(iprange)
+        self.assertEqual(start, "192.168.0.1")
 
     def test_safe_ip_address(self):
         addr_list = self.GOOD_IP_V4_ADDRESS_STR_LIST
index 65bf56f..7247ee8 100644 (file)
@@ -432,7 +432,6 @@ class TestIXIATrafficGen(unittest.TestCase):
 
 
 class TestIxiaBasicScenario(unittest.TestCase):
-
     def setUp(self):
         self._mock_IxNextgen = mock.patch.object(ixnet_api, 'IxNextgen')
         self.mock_IxNextgen = self._mock_IxNextgen.start()
@@ -450,15 +449,15 @@ class TestIxiaBasicScenario(unittest.TestCase):
         self.assertIsInstance(self.scenario, tg_rfc2544_ixia.IxiaBasicScenario)
         self.assertEqual(self.scenario.client, self.mock_IxNextgen)
 
-    def test_apply_config(self):
-        self.assertIsNone(self.scenario.apply_config())
-
     def test_create_traffic_model(self):
         self.mock_IxNextgen.get_vports.return_value = [1, 2, 3, 4]
         self.scenario.create_traffic_model()
         self.scenario.client.get_vports.assert_called_once()
         self.scenario.client.create_traffic_model.assert_called_once_with([1, 3], [2, 4])
 
+    def test_apply_config(self):
+        self.assertIsNone(self.scenario.apply_config())
+
     def test_run_protocols(self):
         self.assertIsNone(self.scenario.run_protocols())
 
@@ -466,6 +465,97 @@ class TestIxiaBasicScenario(unittest.TestCase):
         self.assertIsNone(self.scenario.stop_protocols())
 
 
+class TestIxiaL3Scenario(TestIxiaBasicScenario):
+    IXIA_CFG = {
+        'flow': {
+            'src_ip': ['192.168.0.1-192.168.0.50'],
+            'dst_ip': ['192.168.1.1-192.168.1.150']
+        }
+    }
+
+    CONTEXT_CFG = {
+        'nodes': {
+            'tg__0': {
+                'role': 'IxNet',
+                'interfaces': {
+                    'xe0': {
+                        'vld_id': 'uplink_0',
+                        'local_ip': '10.1.1.1',
+                        'local_mac': 'aa:bb:cc:dd:ee:ff',
+                        'ifname': 'xe0'
+                    },
+                    'xe1': {
+                        'vld_id': 'downlink_0',
+                        'local_ip': '20.2.2.2',
+                        'local_mac': 'bb:bb:cc:dd:ee:ee',
+                        'ifname': 'xe1'
+                    }
+                },
+                'routing_table': [{
+                    'network': "152.16.100.20",
+                    'netmask': '255.255.0.0',
+                    'gateway': '152.16.100.21',
+                    'if': 'xe0'
+                }]
+            }
+        }
+    }
+
+    def setUp(self):
+        super(TestIxiaL3Scenario, self).setUp()
+        self.ixia_cfg = self.IXIA_CFG
+        self.context_cfg = self.CONTEXT_CFG
+        self.scenario = tg_rfc2544_ixia.IxiaL3Scenario(self.mock_IxNextgen,
+                                                       self.context_cfg,
+                                                       self.ixia_cfg)
+
+    def test___init___(self):
+        self.assertIsInstance(self.scenario, tg_rfc2544_ixia.IxiaL3Scenario)
+        self.assertEqual(self.scenario.client, self.mock_IxNextgen)
+
+    def test_create_traffic_model(self):
+        self.mock_IxNextgen.get_vports.return_value = ['1', '2']
+        self.scenario.create_traffic_model()
+        self.scenario.client.get_vports.assert_called_once()
+        self.scenario.client.create_ipv4_traffic_model.\
+            assert_called_once_with(['1/protocols/static'],
+                                    ['2/protocols/static'])
+
+    def test_apply_config(self):
+        self.scenario._add_interfaces = mock.Mock()
+        self.scenario._add_static_ips = mock.Mock()
+        self.assertIsNone(self.scenario.apply_config())
+
+    def test__add_static(self):
+        self.mock_IxNextgen.get_vports.return_value = ['1', '2']
+        self.mock_IxNextgen.get_static_interface.side_effect = ['intf1',
+                                                                'intf2']
+
+        self.scenario._add_static_ips()
+
+        self.mock_IxNextgen.get_static_interface.assert_any_call('1')
+        self.mock_IxNextgen.get_static_interface.assert_any_call('2')
+
+        self.scenario.client.add_static_ipv4.assert_any_call(
+            'intf1', '1', '192.168.0.1', 49)
+        self.scenario.client.add_static_ipv4.assert_any_call(
+            'intf2', '2', '192.168.1.1', 149)
+
+    def test__add_interfaces(self):
+        self.mock_IxNextgen.get_vports.return_value = ['1', '2']
+
+        self.scenario._add_interfaces()
+
+        self.mock_IxNextgen.add_interface.assert_any_call('1',
+                                                          '10.1.1.1',
+                                                          'aa:bb:cc:dd:ee:ff',
+                                                          '152.16.100.21')
+        self.mock_IxNextgen.add_interface.assert_any_call('2',
+                                                          '20.2.2.2',
+                                                          'bb:bb:cc:dd:ee:ee',
+                                                          None)
+
+
 class TestIxiaPppoeClientScenario(unittest.TestCase):
 
     IXIA_CFG = {