Add vBNG PPPoE test cases functionality 13/63213/17
authorSerhiy Pshyk <serhiyx.pshyk@intel.com>
Fri, 5 Oct 2018 16:50:38 +0000 (17:50 +0100)
committerOleksandr Naumets <oleksandrx.naumets@intel.com>
Fri, 7 Dec 2018 08:25:28 +0000 (08:25 +0000)
Added vBNG PPPoE test cases functionality which allows to:
- create and configure access network connections (PPPoE subscribers);
- create and configure core network connections;
- configure and run traffic between access and core network
  topologies.

JIRA: YARDSTICK-1508

Change-Id: I90975505fe7318227a837d97e8db4a06712de7eb
Signed-off-by: Serhiy Pshyk <serhiyx.pshyk@intel.com>
Signed-off-by: Oleksandr Naumets <oleksandrx.naumets@intel.com>
samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_4port_IMIX.yaml [new file with mode: 0644]
samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_IMIX.yaml [new file with mode: 0644]
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vbng-4.yaml [new file with mode: 0644]
yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
yardstick/network_services/vnf_generic/vnf/sample_vnf.py
yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py

diff --git a/samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_4port_IMIX.yaml b/samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_4port_IMIX.yaml
new file mode 100644 (file)
index 0000000..14aa97a
--- /dev/null
@@ -0,0 +1,62 @@
+# 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.
+
+---
+schema: yardstick:task:0.1
+scenarios:
+- type: NSPerf
+  traffic_profile: "../../traffic_profiles/ixia_ipv4_latency_vbng-4.yaml"
+  topology: "../agnostic/agnostic_vnf_topology_ixia_4ports.yaml"
+  ixia_config: IxiaPppoeClient
+  nodes:
+    tg__0: tg_0.yardstick
+    vnf__0: vnf_0.yardstick
+  options:
+    pppoe_client: # access network
+      sessions_per_port: 4000
+      sessions_per_svlan: 1000
+      pap_user: 'wfnos'
+      pap_password: ''
+      ip: [{'tg__0': 'xe0'}, {'tg__0': 'xe2'}]
+      s_vlan: 100  # s-vlan applies per device group
+      c_vlan: 1000  # c-vlan applies per subscriber
+    ipv4_client: # core network
+      sessions_per_port: 1
+      sessions_per_vlan: 1
+      ip: [{'tg__0': 'xe1'}, {'tg__0': 'xe3'}]
+      gateway_ip: [{'vnf__0': 'xe1'}, {'vnf__0': 'xe3'}]
+      vlan: 101
+      bgp:
+        bgp_type: external
+        dut_ip: 10.0.0.3
+        as_number: 65000
+    framesize:
+      uplink: {70B: 33, 940B: 33, 1470B: 34}
+      downlink: {68B: 3, 932B: 1, 1470B: 96}
+    flow:
+      src_ip: [{'tg__0': 'xe0'}, {'tg__0': 'xe2'}]
+      dst_ip: [{'tg__0': 'xe1'}, {'tg__0': 'xe3'}]
+      count: 1
+    traffic_type: 4
+    rfc2544:
+      allowed_drop_rate: 0.0001 - 0.0001
+  runner:
+    type: Iteration
+    iterations: 10
+    interval: 75
+context:
+  type: Node
+  name: yardstick
+  nfvi_type: baremetal
+  file: /etc/yardstick/nodes/pod_ixia_4port.yaml
diff --git a/samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_IMIX.yaml b/samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_IMIX.yaml
new file mode 100644 (file)
index 0000000..5fbe0c7
--- /dev/null
@@ -0,0 +1,63 @@
+# 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.
+
+---
+schema: yardstick:task:0.1
+scenarios:
+- type: NSPerf
+  traffic_profile: "../../traffic_profiles/ixia_ipv4_latency_vbng-4.yaml"
+  topology: "../agnostic/agnostic_vnf_topology_ixia_2ports.yaml"
+  ixia_config: IxiaPppoeClient
+  nodes:
+    tg__0: tg_0.yardstick
+    vnf__0: vnf_0.yardstick
+  options:
+    pppoe_client: # access network
+      sessions_per_port: 4000
+      sessions_per_svlan: 1000
+      pap_user: 'wfnos'
+      pap_password: ''
+      ip: [{'tg__0': 'xe0'}]
+      s_vlan: 100  # s-vlan applies per device group
+      c_vlan: 1000  # c-vlan applies per subscriber
+    ipv4_client: # core network
+      sessions_per_port: 1
+      sessions_per_vlan: 1
+      ip: [{'tg__0': 'xe1'}]
+      gateway_ip: [{'vnf__0': 'xe1'}]
+      prefix: '24'
+      vlan: 101
+      bgp:
+        bgp_type: external
+        dut_ip: 10.0.0.3
+        as_number: 65000
+    framesize:
+      uplink: {64B: 100}
+      downlink: {64B: 100}
+    flow:
+      src_ip: [{'tg__0': 'xe0'}]
+      dst_ip: [{'tg__0': 'xe1'}]
+      count: 1
+    traffic_type: 4
+    rfc2544:
+      allowed_drop_rate: 0.0001 - 0.0001
+  runner:
+    type: Iteration
+    iterations: 10
+    interval: 75
+context:
+  type: Node
+  name: yardstick
+  nfvi_type: baremetal
+  file: /etc/yardstick/nodes/pod_ixia.yaml
index f71c088..275509a 100644 (file)
@@ -19,7 +19,7 @@
 # the profile defines a public and private side to make limited traffic correlation
 # between private and public side same way as it is made by IXIA solution.
 #
-schema: "isb:traffic_profile:0.1"
+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
 
diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vbng-4.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vbng-4.yaml
new file mode 100644 (file)
index 0000000..e65876c
--- /dev/null
@@ -0,0 +1,139 @@
+# 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.
+
+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
+traffic_profile:
+  traffic_type : IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput
+  frame_rate : 25%  # pc of linerate
+  duration: {{ duration }}
+  enable_latency: True
+
+uplink_0:
+      ipv4:
+        id: 1
+        outer_l2:
+          framesize:
+            64B: "{{get(imix, 'imix.uplink.64B', '0') }}"
+            68B: "{{get(imix, 'imix.uplink.68B', '0') }}"
+            70B: "{{get(imix, 'imix.uplink.70B', '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') }}"
+            932B: "{{get(imix, 'imix.uplink.932B', '0') }}"
+            940B: "{{get(imix, 'imix.uplink.940B', '0') }}"
+            1024B: "{{get(imix, 'imix.uplink.1024B', '0') }}"
+            1280B: "{{get(imix, 'imix.uplink.1280B', '0') }}"
+            1400B: "{{get(imix, 'imix.uplink.1400B', '0') }}"
+            1470B: "{{get(imix, 'imix.uplink.1470B', '0') }}"
+            1500B: "{{get(imix, 'imix.uplink.1500B', '0') }}"
+            1518B: "{{get(imix, 'imix.uplink.1518B', '0') }}"
+
+        outer_l3v4:
+            priority:
+              tos:
+                # Precedence values:
+                # 0 - (000) Routine
+                # 1 - (001) Priority
+                # 2 - (010) Immediate
+                # 3 - (011) Flash
+                # 4 - (100) Flash Override
+                # 5 - (101) CRITIC/ECP
+                # 6 - (110) Internetwork Control
+                # 7 - (111) Network Control
+                precedence: [0, 4, 7]
+downlink_0:
+      ipv4:
+        id: 2
+        outer_l2:
+          framesize:
+            64B: "{{get(imix, 'imix.downlink.64B', '0') }}"
+            68B: "{{get(imix, 'imix.downlink.68B', '0') }}"
+            70B: "{{get(imix, 'imix.downlink.70B', '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') }}"
+            932B: "{{get(imix, 'imix.downlink.932B', '0') }}"
+            940B: "{{get(imix, 'imix.downlink.940B', '0') }}"
+            1024B: "{{get(imix, 'imix.downlink.1024B', '0') }}"
+            1280B: "{{get(imix, 'imix.downlink.1280B', '0') }}"
+            1400B: "{{get(imix, 'imix.downlink.1400B', '0') }}"
+            1470B: "{{get(imix, 'imix.downlink.1470B', '0') }}"
+            1500B: "{{get(imix, 'imix.downlink.1500B', '0') }}"
+            1518B: "{{get(imix, 'imix.downlink.1518B', '0') }}"
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: [0, 4, 7]
+uplink_1:
+      ipv4:
+        id: 3
+        outer_l2:
+          framesize:
+            64B: "{{get(imix, 'imix.uplink.64B', '0') }}"
+            68B: "{{get(imix, 'imix.uplink.68B', '0') }}"
+            70B: "{{get(imix, 'imix.uplink.70B', '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') }}"
+            932B: "{{get(imix, 'imix.uplink.932B', '0') }}"
+            940B: "{{get(imix, 'imix.uplink.940B', '0') }}"
+            1024B: "{{get(imix, 'imix.uplink.1024B', '0') }}"
+            1280B: "{{get(imix, 'imix.uplink.1280B', '0') }}"
+            1400B: "{{get(imix, 'imix.uplink.1400B', '0') }}"
+            1470B: "{{get(imix, 'imix.uplink.1470B', '0') }}"
+            1500B: "{{get(imix, 'imix.uplink.1500B', '0') }}"
+            1518B: "{{get(imix, 'imix.uplink.1518B', '0') }}"
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: [0, 4, 7]
+downlink_1:
+      ipv4:
+        id: 4
+        outer_l2:
+          framesize:
+            64B: "{{get(imix, 'imix.downlink.64B', '0') }}"
+            68B: "{{get(imix, 'imix.downlink.68B', '0') }}"
+            70B: "{{get(imix, 'imix.downlink.70B', '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') }}"
+            932B: "{{get(imix, 'imix.downlink.932B', '0') }}"
+            940B: "{{get(imix, 'imix.downlink.940B', '0') }}"
+            1024B: "{{get(imix, 'imix.downlink.1024B', '0') }}"
+            1280B: "{{get(imix, 'imix.downlink.1280B', '0') }}"
+            1400B: "{{get(imix, 'imix.downlink.1400B', '0') }}"
+            1470B: "{{get(imix, 'imix.downlink.1470B', '0') }}"
+            1500B: "{{get(imix, 'imix.downlink.1500B', '0') }}"
+            1518B: "{{get(imix, 'imix.downlink.1518B', '0') }}"
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: [0, 4, 7]
index 1f465bd..b5e4172 100644 (file)
@@ -49,6 +49,19 @@ PROTOCOL_STATUS_DOWN = ['down', 'notStarted']
 
 SUPPORTED_PROTO = [PROTO_UDP]
 
+SUPPORTED_DSCP_CLASSES = [
+    'defaultPHB',
+    'classSelectorPHB',
+    'assuredForwardingPHB',
+    'expeditedForwardingPHB']
+
+SUPPORTED_TOS_FIELDS = [
+    'precedence',
+    'delay',
+    'throughput',
+    'reliability'
+]
+
 
 class Vlan(object):
     def __init__(self,
@@ -198,9 +211,10 @@ class IxNextgen(object):  # pragma: no cover
 
         :param proto: IxNet protocol str representation, e.g.:
         '::ixNet::OBJ-/topology:2/deviceGroup:1/ethernet:1/ipv4:L14'
-        :return: (str) protocol status: 'up', 'down' or 'notStarted'
+        :return: (list) protocol status: list of sessions protocol
+        statuses which include states 'up', 'down' and 'notStarted'
         """
-        return self.ixnet.getAttribute(proto, '-sessionStatus')[0]
+        return self.ixnet.getAttribute(proto, '-sessionStatus')
 
     def is_traffic_running(self):
         """Returns true if traffic state == TRAFFIC_STATUS_STARTED"""
@@ -218,8 +232,8 @@ class IxNextgen(object):  # pragma: no cover
         :return: (bool) True if all protocols status is 'up', False if any
         protocol status is 'down' or 'notStarted'
         """
-        return all(self._get_protocol_status(proto) == PROTOCOL_STATUS_UP
-                   for proto in protocols)
+        return all(session_status is PROTOCOL_STATUS_UP for proto in protocols
+                   for session_status in self._get_protocol_status(proto))
 
     def is_protocols_stopped(self, protocols):
         """Returns true if all protocols statuses are in PROTOCOL_STATUS_DOWN
@@ -229,8 +243,8 @@ class IxNextgen(object):  # pragma: no cover
         :return: (bool) True if all protocols status is 'down' or 'notStarted',
         False if any protocol status is 'up'
         """
-        return all(self._get_protocol_status(proto) in PROTOCOL_STATUS_DOWN
-                   for proto in protocols)
+        return all(session_status in PROTOCOL_STATUS_DOWN for proto in protocols
+                   for session_status in self._get_protocol_status(proto))
 
     @staticmethod
     def _parse_framesize(framesize):
@@ -597,23 +611,25 @@ class IxNextgen(object):  # pragma: no cover
             'precedence': [1, 4, 7]
             }
          """
-        if 'raw' in priority:
+        if priority.get('raw'):
             priority_field = self._get_field_in_stack_item(ip_descriptor,
                                                            'priority.raw')
             self._set_priority_field(priority_field, priority['raw'])
 
-        elif 'dscp' in priority:
+        elif priority.get('dscp'):
             for field, value in priority['dscp'].items():
-                priority_field = self._get_field_in_stack_item(
-                    ip_descriptor,
-                    'priority.ds.phb.{field}.{field}'.format(field=field))
-                self._set_priority_field(priority_field, value)
+                if field in SUPPORTED_DSCP_CLASSES:
+                    priority_field = self._get_field_in_stack_item(
+                        ip_descriptor,
+                        'priority.ds.phb.{field}.{field}'.format(field=field))
+                    self._set_priority_field(priority_field, value)
 
-        elif 'tos' in priority:
+        elif priority.get('tos'):
             for field, value in priority['tos'].items():
-                priority_field = self._get_field_in_stack_item(
-                    ip_descriptor, 'priority.tos.' + field)
-                self._set_priority_field(priority_field, value)
+                if field in SUPPORTED_TOS_FIELDS:
+                    priority_field = self._get_field_in_stack_item(
+                        ip_descriptor, 'priority.tos.' + field)
+                    self._set_priority_field(priority_field, value)
 
     def _set_priority_field(self, field_descriptor, value):
         """Set the priority field described by field_descriptor
@@ -938,7 +954,7 @@ class IxNextgen(object):  # pragma: no cover
         self.ixnet.commit()
         return obj
 
-    def add_pppox_client(self, xproto, auth, user, pwd):
+    def add_pppox_client(self, xproto, auth, user, pwd, enable_redial=True):
         log.debug(
             "add_pppox_client: xproto='%s', auth='%s', user='%s', pwd='%s'",
             xproto, auth, user, pwd)
@@ -958,6 +974,10 @@ class IxNextgen(object):  # pragma: no cover
         else:
             raise NotImplementedError()
 
+        if enable_redial:
+            redial = self.ixnet.getAttribute(obj, '-enableRedial')
+            self.ixnet.setAttribute(redial + '/singleValue', '-value', 'true')
+
         self.ixnet.commit()
         return obj
 
index 673344f..ebe3ff7 100644 (file)
@@ -898,6 +898,8 @@ class SampleVNFTrafficGen(GenericTrafficGen):
             self.scenario_helper.nodes[self.name]
         )
 
+        self.resource_helper.context_cfg = context_cfg
+
         self.resource_helper.setup()
         # must generate_cfg after DPDK bind because we need port number
         self.resource_helper.generate_cfg()
index 89f8194..4c13112 100644 (file)
@@ -12,7 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import ipaddress
 import logging
+import six
 
 from yardstick.common import utils
 from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api
@@ -25,6 +27,183 @@ LOG = logging.getLogger(__name__)
 
 WAIT_AFTER_CFG_LOAD = 10
 WAIT_FOR_TRAFFIC = 30
+WAIT_PROTOCOLS_STARTED = 360
+
+
+class IxiaBasicScenario(object):
+    def __init__(self, client, context_cfg, ixia_cfg):
+
+        self.client = client
+        self.context_cfg = context_cfg
+        self.ixia_cfg = ixia_cfg
+
+        self._uplink_vports = None
+        self._downlink_vports = None
+
+    def apply_config(self):
+        pass
+
+    def create_traffic_model(self):
+        vports = self.client.get_vports()
+        self._uplink_vports = vports[::2]
+        self._downlink_vports = vports[1::2]
+        self.client.create_traffic_model(self._uplink_vports,
+                                         self._downlink_vports)
+
+    def run_protocols(self):
+        pass
+
+    def stop_protocols(self):
+        pass
+
+
+class IxiaPppoeClientScenario(object):
+    def __init__(self, client, context_cfg, ixia_cfg):
+
+        self.client = client
+
+        self._uplink_vports = None
+        self._downlink_vports = None
+
+        self._access_topologies = []
+        self._core_topologies = []
+
+        self._context_cfg = context_cfg
+        self._ixia_cfg = ixia_cfg
+        self.protocols = []
+
+    def apply_config(self):
+        vports = self.client.get_vports()
+        self._uplink_vports = vports[::2]
+        self._downlink_vports = vports[1::2]
+        self._fill_ixia_config()
+        self._apply_access_network_config()
+        self._apply_core_network_config()
+
+    def create_traffic_model(self):
+        self.client.create_ipv4_traffic_model(self._access_topologies,
+                                              self._core_topologies)
+
+    def run_protocols(self):
+        LOG.info('PPPoE Scenario - Start Protocols')
+        self.client.start_protocols()
+        utils.wait_until_true(
+            lambda: self.client.is_protocols_running(self.protocols),
+            timeout=WAIT_PROTOCOLS_STARTED, sleep=2)
+
+    def stop_protocols(self):
+        LOG.info('PPPoE Scenario - Stop Protocols')
+        self.client.stop_protocols()
+
+    def _get_intf_addr(self, intf):
+        """Retrieve interface IP address and mask
+
+        :param intf: could be the string which represents IP address
+        with mask (e.g 192.168.10.2/24) or a dictionary with the host
+        name and the port (e.g. {'tg__0': 'xe1'})
+        :return: (tuple) pair of ip address and mask
+        """
+        if isinstance(intf, six.string_types):
+            ip, mask = tuple(intf.split('/'))
+            return ip, int(mask)
+
+        node_name, intf_name = next(iter(intf.items()))
+        node = self._context_cfg["nodes"].get(node_name, {})
+        interface = node.get("interfaces", {})[intf_name]
+        ip = interface["local_ip"]
+        mask = interface["netmask"]
+        ipaddr = ipaddress.ip_network(six.text_type('{}/{}'.format(ip, mask)),
+                                      strict=False)
+        return ip, ipaddr.prefixlen
+
+    def _fill_ixia_config(self):
+        pppoe = self._ixia_cfg["pppoe_client"]
+        ipv4 = self._ixia_cfg["ipv4_client"]
+
+        _ip = [self._get_intf_addr(intf)[0] for intf in pppoe["ip"]]
+        self._ixia_cfg["pppoe_client"]["ip"] = _ip
+
+        _ip = [self._get_intf_addr(intf)[0] for intf in ipv4["gateway_ip"]]
+        self._ixia_cfg["ipv4_client"]["gateway_ip"] = _ip
+
+        addrs = [self._get_intf_addr(intf) for intf in ipv4["ip"]]
+        _ip = [addr[0] for addr in addrs]
+        _prefix = [addr[1] for addr in addrs]
+
+        self._ixia_cfg["ipv4_client"]["ip"] = _ip
+        self._ixia_cfg["ipv4_client"]["prefix"] = _prefix
+
+    def _apply_access_network_config(self):
+        pppoe = self._ixia_cfg["pppoe_client"]
+        sessions_per_port = pppoe['sessions_per_port']
+        sessions_per_svlan = pppoe['sessions_per_svlan']
+        svlan_count = int(sessions_per_port / sessions_per_svlan)
+
+        # add topology per uplink port (access network)
+        for access_tp_id, vport in enumerate(self._uplink_vports):
+            name = 'Topology access {}'.format(access_tp_id)
+            tp = self.client.add_topology(name, vport)
+            self._access_topologies.append(tp)
+            # add device group per svlan
+            for dg_id in range(svlan_count):
+                s_vlan_id = int(pppoe['s_vlan']) + dg_id + access_tp_id * svlan_count
+                s_vlan = ixnet_api.Vlan(vlan_id=s_vlan_id)
+                c_vlan = ixnet_api.Vlan(vlan_id=pppoe['c_vlan'], vlan_id_step=1)
+                name = 'SVLAN {}'.format(s_vlan_id)
+                dg = self.client.add_device_group(tp, name, sessions_per_svlan)
+                # add ethernet layer to device group
+                ethernet = self.client.add_ethernet(dg, 'Ethernet')
+                self.protocols.append(ethernet)
+                self.client.add_vlans(ethernet, [s_vlan, c_vlan])
+                # add ppp over ethernet
+                if 'pap_user' in pppoe:
+                    ppp = self.client.add_pppox_client(ethernet, 'pap',
+                                                       pppoe['pap_user'],
+                                                       pppoe['pap_password'])
+                else:
+                    ppp = self.client.add_pppox_client(ethernet, 'chap',
+                                                       pppoe['chap_user'],
+                                                       pppoe['chap_password'])
+                self.protocols.append(ppp)
+
+    def _apply_core_network_config(self):
+        ipv4 = self._ixia_cfg["ipv4_client"]
+        sessions_per_port = ipv4['sessions_per_port']
+        sessions_per_vlan = ipv4['sessions_per_vlan']
+        vlan_count = int(sessions_per_port / sessions_per_vlan)
+
+        # add topology per downlink port (core network)
+        for core_tp_id, vport in enumerate(self._downlink_vports):
+            name = 'Topology core {}'.format(core_tp_id)
+            tp = self.client.add_topology(name, vport)
+            self._core_topologies.append(tp)
+            # add device group per vlan
+            for dg_id in range(vlan_count):
+                name = 'Core port {}'.format(core_tp_id)
+                dg = self.client.add_device_group(tp, name, sessions_per_vlan)
+                # add ethernet layer to device group
+                ethernet = self.client.add_ethernet(dg, 'Ethernet')
+                self.protocols.append(ethernet)
+                if 'vlan' in ipv4:
+                    vlan_id = int(ipv4['vlan']) + dg_id + core_tp_id * vlan_count
+                    vlan = ixnet_api.Vlan(vlan_id=vlan_id)
+                    self.client.add_vlans(ethernet, [vlan])
+                # add ipv4 layer
+                gw_ip = ipv4['gateway_ip'][core_tp_id]
+                # use gw addr to generate ip addr from the same network
+                ip_addr = ipaddress.IPv4Address(gw_ip) + 1
+                ipv4_obj = self.client.add_ipv4(ethernet, name='ipv4',
+                                                addr=ip_addr,
+                                                addr_step='0.0.0.1',
+                                                prefix=ipv4['prefix'][core_tp_id],
+                                                gateway=gw_ip)
+                self.protocols.append(ipv4_obj)
+                if ipv4.get("bgp"):
+                    bgp_peer_obj = self.client.add_bgp(ipv4_obj,
+                                                       dut_ip=ipv4["bgp"]["dut_ip"],
+                                                       local_as=ipv4["bgp"]["as_number"],
+                                                       bgp_type=ipv4["bgp"].get("bgp_type"))
+                    self.protocols.append(bgp_peer_obj)
 
 
 class IxiaRfc2544Helper(Rfc2544ResourceHelper):
@@ -41,6 +220,11 @@ class IxiaResourceHelper(ClientResourceHelper):
         super(IxiaResourceHelper, self).__init__(setup_helper)
         self.scenario_helper = setup_helper.scenario_helper
 
+        self._ixia_scenarios = {
+            "IxiaBasic": IxiaBasicScenario,
+            "IxiaPppoeClient": IxiaPppoeClientScenario,
+        }
+
         self.client = ixnet_api.IxNextgen()
 
         if rfc_helper_type is None:
@@ -49,6 +233,8 @@ class IxiaResourceHelper(ClientResourceHelper):
         self.rfc_helper = rfc_helper_type(self.scenario_helper)
         self.uplink_ports = None
         self.downlink_ports = None
+        self.context_cfg = None
+        self._ix_scenario = None
         self._connect()
 
     def _connect(self, client=None):
@@ -57,7 +243,12 @@ class IxiaResourceHelper(ClientResourceHelper):
     def get_stats(self, *args, **kwargs):
         return self.client.get_statistics()
 
+    def setup(self):
+        super(IxiaResourceHelper, self).setup()
+        self._init_ix_scenario()
+
     def stop_collect(self):
+        self._ix_scenario.stop_protocols()
         self._terminated.value = 1
 
     def generate_samples(self, ports, duration):
@@ -92,14 +283,24 @@ class IxiaResourceHelper(ClientResourceHelper):
 
         return samples
 
+    def _init_ix_scenario(self):
+        ixia_config = self.scenario_helper.scenario_cfg.get('ixia_config', 'IxiaBasic')
+
+        if ixia_config in self._ixia_scenarios:
+            scenario_type = self._ixia_scenarios[ixia_config]
+
+            self._ix_scenario = scenario_type(self.client, self.context_cfg,
+                                              self.scenario_helper.scenario_cfg['options'])
+        else:
+            raise RuntimeError(
+                "IXIA config type '{}' not supported".format(ixia_config))
+
     def _initialize_client(self):
         """Initialize the IXIA IxNetwork client and configure the server"""
         self.client.clear_config()
         self.client.assign_ports()
-        vports = self.client.get_vports()
-        uplink_vports = vports[::2]
-        downlink_vports = vports[1::2]
-        self.client.create_traffic_model(uplink_vports, downlink_vports)
+        self._ix_scenario.apply_config()
+        self._ix_scenario.create_traffic_model()
 
     def run_traffic(self, traffic_profile, *args):
         if self._terminated.value:
@@ -123,6 +324,8 @@ class IxiaResourceHelper(ClientResourceHelper):
             mac["src_mac_{}".format(port_num)] = virt_intf.get("local_mac", default)
             mac["dst_mac_{}".format(port_num)] = virt_intf.get("dst_mac", default)
 
+        self._ix_scenario.run_protocols()
+
         try:
             while not self._terminated.value:
                 first_run = traffic_profile.execute_traffic(
@@ -144,6 +347,7 @@ class IxiaResourceHelper(ClientResourceHelper):
         except Exception:  # pylint: disable=broad-except
             LOG.exception('Run Traffic terminated')
 
+        self._ix_scenario.stop_protocols()
         self._terminated.value = 1
 
     def collect_kpi(self):
index 5e2578b..bf613ca 100644 (file)
@@ -673,7 +673,23 @@ class TestIxNextgen(unittest.TestCase):
                                return_value='field_desc'):
             self.ixnet_gen._update_ipv4_priority('field_desc', priority)
 
-        self.assertEqual(self.ixnet_gen._set_priority_field.call_count, 0)
+        self.ixnet_gen._set_priority_field.assert_not_called()
+
+    def test__update_ipv4_priority_not_supported_dscp_class(self):
+        priority = {'dscp': {'testPHB': [0, 4, 7]}}
+        self.ixnet_gen._set_priority_field = mock.Mock()
+        self.ixnet_gen._get_field_in_stack_item = mock.Mock()
+        self.ixnet_gen._update_ipv4_priority('field_desc', priority)
+        self.ixnet_gen._set_priority_field.assert_not_called()
+        self.ixnet_gen._get_field_in_stack_item.assert_not_called()
+
+    def test__update_ipv4_priority_not_supported_tos_field(self):
+        priority = {'tos': {'test': [0, 4, 7]}}
+        self.ixnet_gen._set_priority_field = mock.Mock()
+        self.ixnet_gen._get_field_in_stack_item = mock.Mock()
+        self.ixnet_gen._update_ipv4_priority('field_desc', priority)
+        self.ixnet_gen._set_priority_field.assert_not_called()
+        self.ixnet_gen._get_field_in_stack_item.assert_not_called()
 
     def test__set_priority_field_list_value(self):
         value = [1, 4, 7]
@@ -818,13 +834,13 @@ class TestIxNextgen(unittest.TestCase):
 
     @mock.patch.object(ixnet_api.IxNextgen, '_get_protocol_status')
     def test_is_protocols_running(self, mock_ixnextgen_get_protocol_status):
-        mock_ixnextgen_get_protocol_status.return_value = 'up'
+        mock_ixnextgen_get_protocol_status.return_value = ['up', 'up']
         result = self.ixnet_gen.is_protocols_running(['ethernet', 'ipv4'])
         self.assertTrue(result)
 
     @mock.patch.object(ixnet_api.IxNextgen, '_get_protocol_status')
     def test_is_protocols_stopped(self, mock_ixnextgen_get_protocol_status):
-        mock_ixnextgen_get_protocol_status.return_value = 'down'
+        mock_ixnextgen_get_protocol_status.return_value = ['down', 'down']
         result = self.ixnet_gen.is_protocols_running(['ethernet', 'ipv4'])
         self.assertFalse(result)
 
index 741201f..e223988 100644 (file)
@@ -17,8 +17,10 @@ import os
 import mock
 import six
 import unittest
+import ipaddress
 
 from yardstick.common import utils
+from yardstick.common import exceptions
 from yardstick.benchmark import contexts
 from yardstick.benchmark.contexts import base as ctx_base
 from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api
@@ -49,12 +51,43 @@ class TestIxiaResourceHelper(unittest.TestCase):
             mock.Mock(), MyRfcHelper)
         self.assertIsInstance(ixia_resource_helper.rfc_helper, MyRfcHelper)
 
+    def test__init_ix_scenario(self):
+        mock_scenario = mock.Mock()
+        mock_scenario_helper = mock.Mock()
+        mock_scenario_helper.scenario_cfg = {'ixia_config': 'TestScenario',
+                                             'options': 'scenario_options'}
+        mock_setup_helper = mock.Mock(scenario_helper=mock_scenario_helper)
+        ixia_resource_helper = tg_rfc2544_ixia.IxiaResourceHelper(mock_setup_helper)
+        ixia_resource_helper._ixia_scenarios = {'TestScenario': mock_scenario}
+        ixia_resource_helper.client = 'client'
+        ixia_resource_helper.context_cfg = 'context'
+        ixia_resource_helper._init_ix_scenario()
+        mock_scenario.assert_called_once_with('client', 'context', 'scenario_options')
+
+    def test__init_ix_scenario_not_supported_cfg_type(self):
+        mock_scenario_helper = mock.Mock()
+        mock_scenario_helper.scenario_cfg = {'ixia_config': 'FakeScenario',
+                                             'options': 'scenario_options'}
+        mock_setup_helper = mock.Mock(scenario_helper=mock_scenario_helper)
+        ixia_resource_helper = tg_rfc2544_ixia.IxiaResourceHelper(mock_setup_helper)
+        ixia_resource_helper._ixia_scenarios = {'TestScenario': mock.Mock()}
+        with self.assertRaises(RuntimeError):
+            ixia_resource_helper._init_ix_scenario()
+
+    @mock.patch.object(tg_rfc2544_ixia.IxiaResourceHelper, '_init_ix_scenario')
+    def test_setup(self, mock__init_ix_scenario):
+        ixia_resource_helper = tg_rfc2544_ixia.IxiaResourceHelper(mock.Mock())
+        ixia_resource_helper.setup()
+        mock__init_ix_scenario.assert_called_once()
+
     def test_stop_collect_with_client(self):
         mock_client = mock.Mock()
         ixia_resource_helper = tg_rfc2544_ixia.IxiaResourceHelper(mock.Mock())
         ixia_resource_helper.client = mock_client
+        ixia_resource_helper._ix_scenario = mock.Mock()
         ixia_resource_helper.stop_collect()
         self.assertEqual(1, ixia_resource_helper._terminated.value)
+        ixia_resource_helper._ix_scenario.stop_protocols.assert_called_once()
 
     def test_run_traffic(self):
         mock_tprofile = mock.Mock()
@@ -63,6 +96,7 @@ class TestIxiaResourceHelper(unittest.TestCase):
         ixia_rhelper = tg_rfc2544_ixia.IxiaResourceHelper(mock.Mock())
         ixia_rhelper.rfc_helper = mock.Mock()
         ixia_rhelper.vnfd_helper = mock.Mock()
+        ixia_rhelper._ix_scenario = mock.Mock()
         ixia_rhelper.vnfd_helper.port_pairs.all_ports = []
         with mock.patch.object(ixia_rhelper, 'generate_samples'), \
                 mock.patch.object(ixia_rhelper, '_build_ports'), \
@@ -261,8 +295,8 @@ class TestIXIATrafficGen(unittest.TestCase):
             ssh_mock.execute = \
                 mock.Mock(return_value=(0, "", ""))
             ssh.from_node.return_value = ssh_mock
-            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
-                                                               'task_id')
+            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(
+                NAME, vnfd, 'task_id', resource_helper_type=mock.Mock())
             ixnet_traffic_gen._terminated = mock.MagicMock()
             ixnet_traffic_gen._terminated.value = 0
             ixnet_traffic_gen._ixia_traffic_gen = mock.MagicMock()
@@ -360,6 +394,7 @@ class TestIXIATrafficGen(unittest.TestCase):
         sut.resource_helper.client_started = mock.MagicMock()
         sut.resource_helper.client_started.value = 1
         sut.resource_helper.rfc_helper.iteration.value = 11
+        sut.resource_helper._ix_scenario = mock.Mock()
 
         sut.scenario_helper.scenario_cfg = {
             'options': {
@@ -392,3 +427,342 @@ class TestIXIATrafficGen(unittest.TestCase):
             self.assertIsNone(result)
 
         _traffic_runner()
+
+
+class TestIxiaBasicScenario(unittest.TestCase):
+
+    def setUp(self):
+        self._mock_IxNextgen = mock.patch.object(ixnet_api, 'IxNextgen')
+        self.mock_IxNextgen = self._mock_IxNextgen.start()
+        self.context_cfg = mock.Mock()
+        self.ixia_cfg = mock.Mock()
+        self.scenario = tg_rfc2544_ixia.IxiaBasicScenario(self.mock_IxNextgen,
+                                                          self.context_cfg,
+                                                          self.ixia_cfg)
+        self.addCleanup(self._stop_mocks)
+
+    def _stop_mocks(self):
+        self._mock_IxNextgen.stop()
+
+    def test___init___(self):
+        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_run_protocols(self):
+        self.assertIsNone(self.scenario.run_protocols())
+
+    def test_stop_protocols(self):
+        self.assertIsNone(self.scenario.stop_protocols())
+
+
+class TestIxiaPppoeClientScenario(unittest.TestCase):
+
+    IXIA_CFG = {
+        'pppoe_client': {
+            'sessions_per_port': 4,
+            'sessions_per_svlan': 1,
+            's_vlan': 10,
+            'c_vlan': 20,
+            'ip': ['10.3.3.1', '10.4.4.1']
+        },
+        'ipv4_client': {
+            'sessions_per_port': 1,
+            'sessions_per_vlan': 1,
+            'vlan': 101,
+            'gateway_ip': ['10.1.1.1', '10.2.2.1'],
+            'ip': ['10.1.1.1', '10.2.2.1'],
+            'prefix': ['24', '24']
+        }
+    }
+
+    CONTEXT_CFG = {
+        'nodes': {'tg__0': {
+            'interfaces': {'xe0': {
+                'local_ip': '10.1.1.1',
+                'netmask': '255.255.255.0'
+                }}}}}
+
+    def setUp(self):
+        self._mock_IxNextgen = mock.patch.object(ixnet_api, 'IxNextgen')
+        self.mock_IxNextgen = self._mock_IxNextgen.start()
+        self.scenario = tg_rfc2544_ixia.IxiaPppoeClientScenario(
+            self.mock_IxNextgen, self.CONTEXT_CFG, self.IXIA_CFG)
+        tg_rfc2544_ixia.WAIT_PROTOCOLS_STARTED = 2
+        self.addCleanup(self._stop_mocks)
+
+    def _stop_mocks(self):
+        self._mock_IxNextgen.stop()
+
+    def test___init___(self):
+        self.assertIsInstance(self.scenario, tg_rfc2544_ixia.IxiaPppoeClientScenario)
+        self.assertEqual(self.scenario.client, self.mock_IxNextgen)
+
+    @mock.patch.object(tg_rfc2544_ixia.IxiaPppoeClientScenario,
+                       '_fill_ixia_config')
+    @mock.patch.object(tg_rfc2544_ixia.IxiaPppoeClientScenario,
+                       '_apply_access_network_config')
+    @mock.patch.object(tg_rfc2544_ixia.IxiaPppoeClientScenario,
+                       '_apply_core_network_config')
+    def test_apply_config(self, mock_apply_core_net_cfg,
+                          mock_apply_access_net_cfg,
+                          mock_fill_ixia_config):
+        self.mock_IxNextgen.get_vports.return_value = [1, 2, 3, 4]
+        self.scenario.apply_config()
+        self.scenario.client.get_vports.assert_called_once()
+        self.assertEqual(self.scenario._uplink_vports, [1, 3])
+        self.assertEqual(self.scenario._downlink_vports, [2, 4])
+        mock_fill_ixia_config.assert_called_once()
+        mock_apply_core_net_cfg.assert_called_once()
+        mock_apply_access_net_cfg.assert_called_once()
+
+    def test_create_traffic_model(self):
+        self.scenario._access_topologies = 'access'
+        self.scenario._core_topologies = 'core'
+        self.scenario.create_traffic_model()
+        self.scenario.client.create_ipv4_traffic_model.assert_called_once_with(
+            'access', 'core')
+
+    def test_run_protocols(self):
+        self.scenario.client.is_protocols_running.return_value = True
+        self.scenario.run_protocols()
+        self.scenario.client.start_protocols.assert_called_once()
+
+    def test_run_protocols_timeout_exception(self):
+        self.scenario.client.is_protocols_running.return_value = False
+        with self.assertRaises(exceptions.WaitTimeout):
+            self.scenario.run_protocols()
+        self.scenario.client.start_protocols.assert_called_once()
+
+    def test_stop_protocols(self):
+        self.scenario.stop_protocols()
+        self.scenario.client.stop_protocols.assert_called_once()
+
+    def test__get_intf_addr_str_type_input(self):
+        intf = '192.168.10.2/24'
+        ip, mask = self.scenario._get_intf_addr(intf)
+        self.assertEqual(ip, '192.168.10.2')
+        self.assertEqual(mask, 24)
+
+    def test__get_intf_addr_dict_type_input(self):
+        intf = {'tg__0': 'xe0'}
+        ip, mask = self.scenario._get_intf_addr(intf)
+        self.assertEqual(ip, '10.1.1.1')
+        self.assertEqual(mask, 24)
+
+    @mock.patch.object(tg_rfc2544_ixia.IxiaPppoeClientScenario, '_get_intf_addr')
+    def test__fill_ixia_config(self, mock_get_intf_addr):
+
+        ixia_cfg = {
+            'pppoe_client': {
+                'sessions_per_port': 4,
+                'sessions_per_svlan': 1,
+                's_vlan': 10,
+                'c_vlan': 20,
+                'ip': ['10.3.3.1/24', '10.4.4.1/24']
+            },
+            'ipv4_client': {
+                'sessions_per_port': 1,
+                'sessions_per_vlan': 1,
+                'vlan': 101,
+                'gateway_ip': ['10.1.1.1/24', '10.2.2.1/24'],
+                'ip': ['10.1.1.1/24', '10.2.2.1/24']
+            }
+        }
+
+        mock_get_intf_addr.side_effect = [
+            ('10.3.3.1', '24'),
+            ('10.4.4.1', '24'),
+            ('10.1.1.1', '24'),
+            ('10.2.2.1', '24'),
+            ('10.1.1.1', '24'),
+            ('10.2.2.1', '24')
+        ]
+        self.scenario._ixia_cfg = ixia_cfg
+        self.scenario._fill_ixia_config()
+        self.assertEqual(mock_get_intf_addr.call_count, 6)
+        self.assertEqual(self.scenario._ixia_cfg['pppoe_client']['ip'],
+                         ['10.3.3.1', '10.4.4.1'])
+        self.assertEqual(self.scenario._ixia_cfg['ipv4_client']['ip'],
+                         ['10.1.1.1', '10.2.2.1'])
+        self.assertEqual(self.scenario._ixia_cfg['ipv4_client']['prefix'],
+                         ['24', '24'])
+
+    @mock.patch('yardstick.network_services.libs.ixia_libs.ixnet.ixnet_api.Vlan')
+    def test__apply_access_network_config_pap_auth(self, mock_vlan):
+        _ixia_cfg = {
+            'pppoe_client': {
+                'sessions_per_port': 4,
+                'sessions_per_svlan': 1,
+                's_vlan': 10,
+                'c_vlan': 20,
+                'pap_user': 'test_pap',
+                'pap_password': 'pap'
+                }}
+        pap_user = _ixia_cfg['pppoe_client']['pap_user']
+        pap_passwd = _ixia_cfg['pppoe_client']['pap_password']
+        self.scenario._ixia_cfg = _ixia_cfg
+        self.scenario._uplink_vports = [0, 2]
+        self.scenario.client.add_topology.side_effect = ['Topology 1', 'Topology 2']
+        self.scenario.client.add_device_group.side_effect = ['Dg1', 'Dg2', 'Dg3',
+                                                             'Dg4', 'Dg5', 'Dg6',
+                                                             'Dg7', 'Dg8']
+        self.scenario.client.add_ethernet.side_effect = ['Eth1', 'Eth2', 'Eth3',
+                                                         'Eth4', 'Eth5', 'Eth6',
+                                                         'Eth7', 'Eth8']
+        self.scenario._apply_access_network_config()
+        self.assertEqual(self.scenario.client.add_topology.call_count, 2)
+        self.assertEqual(self.scenario.client.add_device_group.call_count, 8)
+        self.assertEqual(self.scenario.client.add_ethernet.call_count, 8)
+        self.assertEqual(mock_vlan.call_count, 16)
+        self.assertEqual(self.scenario.client.add_vlans.call_count, 8)
+        self.assertEqual(self.scenario.client.add_pppox_client.call_count, 8)
+        self.scenario.client.add_topology.assert_has_calls([
+            mock.call('Topology access 0', 0),
+            mock.call('Topology access 1', 2)
+        ])
+        self.scenario.client.add_device_group.assert_has_calls([
+            mock.call('Topology 1', 'SVLAN 10', 1),
+            mock.call('Topology 1', 'SVLAN 11', 1),
+            mock.call('Topology 1', 'SVLAN 12', 1),
+            mock.call('Topology 1', 'SVLAN 13', 1),
+            mock.call('Topology 2', 'SVLAN 14', 1),
+            mock.call('Topology 2', 'SVLAN 15', 1),
+            mock.call('Topology 2', 'SVLAN 16', 1),
+            mock.call('Topology 2', 'SVLAN 17', 1)
+        ])
+        self.scenario.client.add_ethernet.assert_has_calls([
+            mock.call('Dg1', 'Ethernet'),
+            mock.call('Dg2', 'Ethernet'),
+            mock.call('Dg3', 'Ethernet'),
+            mock.call('Dg4', 'Ethernet'),
+            mock.call('Dg5', 'Ethernet'),
+            mock.call('Dg6', 'Ethernet'),
+            mock.call('Dg7', 'Ethernet'),
+            mock.call('Dg8', 'Ethernet')
+        ])
+        mock_vlan.assert_has_calls([
+            mock.call(vlan_id=10),
+            mock.call(vlan_id=20, vlan_id_step=1),
+            mock.call(vlan_id=11),
+            mock.call(vlan_id=20, vlan_id_step=1),
+            mock.call(vlan_id=12),
+            mock.call(vlan_id=20, vlan_id_step=1),
+            mock.call(vlan_id=13),
+            mock.call(vlan_id=20, vlan_id_step=1),
+            mock.call(vlan_id=14),
+            mock.call(vlan_id=20, vlan_id_step=1),
+            mock.call(vlan_id=15),
+            mock.call(vlan_id=20, vlan_id_step=1),
+            mock.call(vlan_id=16),
+            mock.call(vlan_id=20, vlan_id_step=1),
+            mock.call(vlan_id=17),
+            mock.call(vlan_id=20, vlan_id_step=1)
+        ])
+        self.scenario.client.add_pppox_client.assert_has_calls([
+            mock.call('Eth1', 'pap', pap_user, pap_passwd),
+            mock.call('Eth2', 'pap', pap_user, pap_passwd),
+            mock.call('Eth3', 'pap', pap_user, pap_passwd),
+            mock.call('Eth4', 'pap', pap_user, pap_passwd),
+            mock.call('Eth5', 'pap', pap_user, pap_passwd),
+            mock.call('Eth6', 'pap', pap_user, pap_passwd),
+            mock.call('Eth7', 'pap', pap_user, pap_passwd),
+            mock.call('Eth8', 'pap', pap_user, pap_passwd)
+        ])
+
+    def test__apply_access_network_config_chap_auth(self):
+        _ixia_cfg = {
+            'pppoe_client': {
+                'sessions_per_port': 4,
+                'sessions_per_svlan': 1,
+                's_vlan': 10,
+                'c_vlan': 20,
+                'chap_user': 'test_chap',
+                'chap_password': 'chap'
+            }}
+        chap_user = _ixia_cfg['pppoe_client']['chap_user']
+        chap_passwd = _ixia_cfg['pppoe_client']['chap_password']
+        self.scenario._ixia_cfg = _ixia_cfg
+        self.scenario._uplink_vports = [0, 2]
+        self.scenario.client.add_ethernet.side_effect = ['Eth1', 'Eth2', 'Eth3',
+                                                         'Eth4', 'Eth5', 'Eth6',
+                                                         'Eth7', 'Eth8']
+        self.scenario._apply_access_network_config()
+        self.assertEqual(self.scenario.client.add_pppox_client.call_count, 8)
+        self.scenario.client.add_pppox_client.assert_has_calls([
+            mock.call('Eth1', 'chap', chap_user, chap_passwd),
+            mock.call('Eth2', 'chap', chap_user, chap_passwd),
+            mock.call('Eth3', 'chap', chap_user, chap_passwd),
+            mock.call('Eth4', 'chap', chap_user, chap_passwd),
+            mock.call('Eth5', 'chap', chap_user, chap_passwd),
+            mock.call('Eth6', 'chap', chap_user, chap_passwd),
+            mock.call('Eth7', 'chap', chap_user, chap_passwd),
+            mock.call('Eth8', 'chap', chap_user, chap_passwd)
+        ])
+
+    @mock.patch('yardstick.network_services.libs.ixia_libs.ixnet.ixnet_api.Vlan')
+    def test__apply_core_network_config_no_bgp_proto(self, mock_vlan):
+        self.scenario._downlink_vports = [1, 3]
+        self.scenario.client.add_topology.side_effect = ['Topology 1', 'Topology 2']
+        self.scenario.client.add_device_group.side_effect = ['Dg1', 'Dg2']
+        self.scenario.client.add_ethernet.side_effect = ['Eth1', 'Eth2']
+        self.scenario._apply_core_network_config()
+        self.assertEqual(self.scenario.client.add_topology.call_count, 2)
+        self.assertEqual(self.scenario.client.add_device_group.call_count, 2)
+        self.assertEqual(self.scenario.client.add_ethernet.call_count, 2)
+        self.assertEqual(mock_vlan.call_count, 2)
+        self.assertEqual(self.scenario.client.add_vlans.call_count, 2)
+        self.assertEqual(self.scenario.client.add_ipv4.call_count, 2)
+        self.scenario.client.add_topology.assert_has_calls([
+            mock.call('Topology core 0', 1),
+            mock.call('Topology core 1', 3)
+        ])
+        self.scenario.client.add_device_group.assert_has_calls([
+            mock.call('Topology 1', 'Core port 0', 1),
+            mock.call('Topology 2', 'Core port 1', 1)
+        ])
+        self.scenario.client.add_ethernet.assert_has_calls([
+            mock.call('Dg1', 'Ethernet'),
+            mock.call('Dg2', 'Ethernet')
+        ])
+        mock_vlan.assert_has_calls([
+            mock.call(vlan_id=101),
+            mock.call(vlan_id=102)
+        ])
+        self.scenario.client.add_ipv4.assert_has_calls([
+            mock.call('Eth1', name='ipv4', addr=ipaddress.IPv4Address('10.1.1.2'),
+                      addr_step='0.0.0.1', prefix='24', gateway='10.1.1.1'),
+            mock.call('Eth2', name='ipv4', addr=ipaddress.IPv4Address('10.2.2.2'),
+                      addr_step='0.0.0.1', prefix='24', gateway='10.2.2.1')
+        ])
+        self.scenario.client.add_bgp.assert_not_called()
+
+    def test__apply_core_network_config_with_bgp_proto(self):
+        bgp_params = {
+            'bgp': {
+                'bgp_type': 'external',
+                'dut_ip': '10.0.0.1',
+                'as_number': 65000
+            }
+        }
+        self.scenario._ixia_cfg['ipv4_client'].update(bgp_params)
+        self.scenario._downlink_vports = [1, 3]
+        self.scenario.client.add_ipv4.side_effect = ['ipv4_1', 'ipv4_2']
+        self.scenario._apply_core_network_config()
+        self.assertEqual(self.scenario.client.add_bgp.call_count, 2)
+        self.scenario.client.add_bgp.assert_has_calls([
+            mock.call('ipv4_1', dut_ip=bgp_params["bgp"]["dut_ip"],
+                      local_as=bgp_params["bgp"]["as_number"],
+                      bgp_type=bgp_params["bgp"]["bgp_type"]),
+            mock.call('ipv4_2', dut_ip=bgp_params["bgp"]["dut_ip"],
+                      local_as=bgp_params["bgp"]["as_number"],
+                      bgp_type=bgp_params["bgp"]["bgp_type"])
+        ])