Extend vBNG PPPoE test cases functionality 65/65065/12
authorOleksandr Naumets <oleksandrx.naumets@intel.com>
Tue, 13 Nov 2018 12:42:08 +0000 (12:42 +0000)
committerOleksandr Naumets <oleksandrx.naumets@intel.com>
Tue, 11 Dec 2018 17:32:16 +0000 (17:32 +0000)
Extended Ixia traffic generator with functionality to
create traffic flows between device groups.

JIRA: YARDSTICK-1521

Change-Id: Iaaa822f2f3da876629576d4101be29c9a65296d0
Signed-off-by: Oleksandr Naumets <oleksandrx.naumets@intel.com>
samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_8ports_1port_congested_IMIX.yaml [moved from samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_4port_IMIX.yaml with 57% similarity]
samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_IMIX_scale_up.yaml [moved from samples/vnf_samples/nsut/bng/tc_bng_pppoe_rfc2544_ixia_IMIX.yaml with 51% similarity]
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vbng_1port_congested-8.yaml [new file with mode: 0644]
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vbng_scale_up.yaml [moved from samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vbng-4.yaml with 50% similarity]
yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
yardstick/network_services/traffic_profile/ixia_rfc2544.py
yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py

 # limitations under the License.
 
 ---
+{% set sessions_per_port = sessions_per_port or 4000 %}
+{% set sessions_per_svlan = sessions_per_svlan or 1000 %}
 schema: yardstick:task:0.1
+description: >
+  vBNG RFC2544 test case with QoS base line with link congestion.
+  Test case creates PPPoE sessions, runs traffic from two core ports
+  to one access port causing congestion of that port (traffic from
+  other access ports are splitting between remaining core ports)
+  and measures packets drop rate on all ports for each priority flow.
 scenarios:
 - type: NSPerf
-  traffic_profile: "../../traffic_profiles/ixia_ipv4_latency_vbng-4.yaml"
-  topology: "../agnostic/agnostic_vnf_topology_ixia_4ports.yaml"
+  traffic_profile: "../../traffic_profiles/ixia_ipv4_latency_vbng_1port_congested-8.yaml"
+  topology: "../agnostic/agnostic_vnf_topology_ixia_8ports.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
+      sessions_per_port: {{ sessions_per_port }}
+      sessions_per_svlan: {{ sessions_per_svlan }}
       pap_user: 'wfnos'
       pap_password: ''
-      ip: [{'tg__0': 'xe0'}, {'tg__0': 'xe2'}]
+      ip: [{'tg__0': 'xe0'}, {'tg__0': 'xe2'}, {'tg__0': 'xe4'}, {'tg__0': 'xe6'}]
       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'}]
+      ip: [{'tg__0': 'xe1'}, {'tg__0': 'xe3'}, {'tg__0': 'xe5'}, {'tg__0': 'xe7'}]
+      gateway_ip: [{'vnf__0': 'xe1'}, {'vnf__0': 'xe3'}, {'vnf__0': 'xe5'}, {'vnf__0': 'xe7'}]
       vlan: 101
       bgp:
         bgp_type: external
@@ -45,8 +53,8 @@ scenarios:
       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'}]
+      src_ip: [{'tg__0': 'xe0'}, {'tg__0': 'xe2'}, {'tg__0': 'xe4'}, {'tg__0': 'xe6'}]
+      dst_ip: [{'tg__0': 'xe1'}, {'tg__0': 'xe3'}, {'tg__0': 'xe5'}, {'tg__0': 'xe7'}]
       count: 1
     traffic_type: 4
     rfc2544:
@@ -59,4 +67,4 @@ context:
   type: Node
   name: yardstick
   nfvi_type: baremetal
-  file: /etc/yardstick/nodes/pod_ixia_4port.yaml
+  file: /etc/yardstick/nodes/pod_ixia.yaml
 # limitations under the License.
 
 ---
+{% set sessions_per_port = sessions_per_port or 4000 %}
+{% set sessions_per_svlan = sessions_per_svlan or 1000 %}
+{% set vports = vports or 2 %}
+{% set svlans_per_port = sessions_per_port / sessions_per_svlan %}
 schema: yardstick:task:0.1
+description: >
+  vBNG RFC2544 test case with QoS base line without link congestion.
+  Test case creates PPPoE sessions, runs traffic on maximum throughput
+  and measures packets drop rate on all ports for each priority flow.
 scenarios:
 - type: NSPerf
-  traffic_profile: "../../traffic_profiles/ixia_ipv4_latency_vbng-4.yaml"
-  topology: "../agnostic/agnostic_vnf_topology_ixia_2ports.yaml"
+  traffic_profile: "../../traffic_profiles/ixia_ipv4_latency_vbng_scale_up.yaml"
+  topology: "../agnostic/agnostic_vnf_topology_ixia_{{ vports }}ports.yaml"
   ixia_config: IxiaPppoeClient
+  extra_args:
+    svlans_per_port: {{ svlans_per_port|int }}
+    access_vports_num: {{ vports|int / 2 }}
   nodes:
     tg__0: tg_0.yardstick
     vnf__0: vnf_0.yardstick
   options:
     pppoe_client: # access network
-      sessions_per_port: 4000
-      sessions_per_svlan: 1000
+      sessions_per_port: {{ sessions_per_port }}
+      sessions_per_svlan: {{ sessions_per_svlan }}
       pap_user: 'wfnos'
       pap_password: ''
-      ip: [{'tg__0': 'xe0'}]
+      ip:
+{% for vnf_num in range(0, vports|int, 2) %}
+        - {'tg__0': 'xe{{ vnf_num }}'}
+{% endfor %}
       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'
+      ip:
+{% for vnf_num in range(1, vports|int, 2) %}
+        - {'tg__0': 'xe{{ vnf_num }}'}
+{% endfor %}
+      gateway_ip:
+{% for vnf_num in range(1, vports|int, 2) %}
+        - {'vnf__0': 'xe{{ vnf_num }}'}
+{% endfor %}
       vlan: 101
       bgp:
         bgp_type: external
         dut_ip: 10.0.0.3
         as_number: 65000
     framesize:
-      uplink: {64B: 100}
-      downlink: {64B: 100}
+      uplink: {70B: 33, 940B: 33, 1470B: 34}
+      downlink: {68B: 3, 932B: 1, 1470B: 96}
     flow:
-      src_ip: [{'tg__0': 'xe0'}]
-      dst_ip: [{'tg__0': 'xe1'}]
+      src_ip:
+{% for vnf_num in range(0, vports|int, 2) %}
+        - {'tg__0': 'xe{{ vnf_num }}'}
+{% endfor %}
+      dst_ip:
+{% for vnf_num in range(1, vports|int, 2) %}
+        - {'tg__0': 'xe{{ vnf_num }}'}
+{% endfor %}
       count: 1
     traffic_type: 4
     rfc2544:
diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vbng_1port_congested-8.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vbng_1port_congested-8.yaml
new file mode 100644 (file)
index 0000000..a317004
--- /dev/null
@@ -0,0 +1,412 @@
+# 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 : IXIARFC2544PppoeScenarioProfile # defines traffic behavior - constant or look for highest possible throughput
+  frame_rate : 12.5%  # pc of linerate
+  duration: {{ duration }}
+  enable_latency: True
+
+uplink_0:
+      ipv4:
+        id: 1
+        port: xe0
+        outer_l2:
+          framesize: &uplink_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: &uplink_precedence [0, 4, 7]
+downlink_0:
+      ipv4:
+        id: 2
+        port: xe1
+        outer_l2:
+          framesize: &downlink_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: &downlink_precedence [0, 4, 7]
+uplink_1:
+      ipv4:
+        id: 3
+        port: xe0
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_1:
+      ipv4:
+        id: 4
+        port: xe1
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_2:
+      ipv4:
+        id: 5
+        port: xe0
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_2:
+      ipv4:
+        id: 6
+        port: xe3
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_3:
+      ipv4:
+        id: 7
+        port: xe0
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_3:
+      ipv4:
+        id: 8
+        port: xe3
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_4:
+      ipv4:
+        id: 9
+        port: xe2
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_4:
+      ipv4:
+        id: 10
+        port: xe5
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_5:
+      ipv4:
+        id: 11
+        port: xe2
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_5:
+      ipv4:
+        id: 12
+        port: xe5
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_6:
+      ipv4:
+        id: 13
+        port: xe2
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_6:
+      ipv4:
+        id: 14
+        port: xe5
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_7:
+      ipv4:
+        id: 15
+        port: xe2
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_7:
+      ipv4:
+        id: 16
+        port: xe5
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_8:
+      ipv4:
+        id: 17
+        port: xe4
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_8:
+      ipv4:
+        id: 18
+        port: xe5
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_9:
+      ipv4:
+        id: 19
+        port: xe4
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_9:
+      ipv4:
+        id: 20
+        port: xe5
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_10:
+      ipv4:
+        id: 21
+        port: xe4
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_10:
+      ipv4:
+        id: 22
+        port: xe7
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_11:
+      ipv4:
+        id: 23
+        port: xe4
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_11:
+      ipv4:
+        id: 24
+        port: xe7
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+
+uplink_12:
+      ipv4:
+        id: 25
+        port: xe6
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_12:
+      ipv4:
+        id: 26
+        port: xe7
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_13:
+      ipv4:
+        id: 27
+        port: xe6
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_13:
+      ipv4:
+        id: 28
+        port: xe7
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_14:
+      ipv4:
+        id: 29
+        port: xe6
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_14:
+      ipv4:
+        id: 30
+        port: xe7
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
+uplink_15:
+      ipv4:
+        id: 31
+        port: xe6
+        outer_l2:
+          framesize: *uplink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *uplink_precedence
+downlink_15:
+      ipv4:
+        id: 32
+        port: xe7
+        outer_l2:
+          framesize: *downlink_framesize
+
+        outer_l3v4:
+            priority:
+              tos:
+                precedence: *downlink_precedence
@@ -12,6 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+---
+{% set svlan_per_port = get(extra_args, 'svlans_per_port') %}
+{% set ports = get(extra_args, 'access_vports_num')|int %}
 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
@@ -19,14 +22,15 @@ schema: "nsb:traffic_profile:0.1"
 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
+  traffic_type : IXIARFC2544PppoeScenarioProfile # defines traffic behavior - constant or look for highest possible throughput
+  frame_rate : 12.5%  # pc of linerate
   duration: {{ duration }}
   enable_latency: True
 
-uplink_0:
+{% for i in range(svlan_per_port|int * ports|int) %}
+uplink_{{ i }}:
       ipv4:
-        id: 1
+        id: {{ (i * 2) + 1 }}
         outer_l2:
           framesize:
             64B: "{{get(imix, 'imix.uplink.64B', '0') }}"
@@ -34,7 +38,7 @@ uplink_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') }}"
+            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') }}"
@@ -49,19 +53,10 @@ uplink_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:
+downlink_{{ i }}:
       ipv4:
-        id: 2
+        id: {{ (i * 2) + 2 }}
         outer_l2:
           framesize:
             64B: "{{get(imix, 'imix.downlink.64B', '0') }}"
@@ -69,59 +64,7 @@ downlink_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') }}"
+            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') }}"
@@ -137,3 +80,4 @@ downlink_1:
             priority:
               tos:
                 precedence: [0, 4, 7]
+{% endfor %}
index b5e4172..4e7434c 100644 (file)
@@ -216,6 +216,14 @@ class IxNextgen(object):  # pragma: no cover
         """
         return self.ixnet.getAttribute(proto, '-sessionStatus')
 
+    def get_topology_device_groups(self, topology):
+        """Get list of device groups in topology
+
+        :param topology: (str) topology descriptor
+        :return: (list) list of device groups descriptors
+        """
+        return self.ixnet.getList(topology, 'deviceGroup')
+
     def is_traffic_running(self):
         """Returns true if traffic state == TRAFFIC_STATUS_STARTED"""
         return self._get_traffic_state() == TRAFFIC_STATUS_STARTED
@@ -406,7 +414,7 @@ class IxNextgen(object):  # pragma: no cover
         self._create_flow_groups(uplink_endpoints, downlink_endpoints)
         self._setup_config_elements()
 
-    def create_ipv4_traffic_model(self, uplink_topologies, downlink_topologies):
+    def create_ipv4_traffic_model(self, uplink_endpoints, downlink_endpoints):
         """Create a traffic item and the needed flow groups
 
         Each flow group inside the traffic item (only one is present)
@@ -418,7 +426,7 @@ class IxNextgen(object):  # pragma: no cover
             FlowGroup4: uplink2    <- downlink2
         """
         self._create_traffic_item('ipv4')
-        self._create_flow_groups(uplink_topologies, downlink_topologies)
+        self._create_flow_groups(uplink_endpoints, downlink_endpoints)
         self._setup_config_elements(False)
 
     def _update_frame_mac(self, ethernet_descriptor, field, mac_address):
index 83d24a4..9328953 100644 (file)
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import logging
+import collections
 
 from yardstick.common import utils
 from yardstick.network_services.traffic_profile import base as tp_base
@@ -35,6 +36,7 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile):
         super(IXIARFC2544Profile, self).__init__(yaml_data)
         self.rate = self.config.frame_rate
         self.rate_unit = self.config.rate_unit
+        self.full_profile = {}
 
     def _get_ip_and_mask(self, ip_range):
         _ip_range = ip_range.split('-')
@@ -164,9 +166,7 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile):
         first_run = self.first_run
         if self.first_run:
             self.first_run = False
-            self.full_profile = {}
             self.pg_id = 0
-            self.update_traffic_profile(traffic_generator)
             self.max_rate = self.rate
             self.min_rate = 0.0
         else:
@@ -237,3 +237,33 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile):
         samples['latency_ns_max'] = latency_ns_max
 
         return completed, samples
+
+
+class IXIARFC2544PppoeScenarioProfile(IXIARFC2544Profile):
+    """Class handles BNG PPPoE scenario tests traffic profile"""
+
+    def __init__(self, yaml_data):
+        super(IXIARFC2544PppoeScenarioProfile, self).__init__(yaml_data)
+        self.full_profile = collections.OrderedDict()
+
+    def _get_flow_groups_params(self):
+        flows_data = [key for key in self.params.keys()
+                      if key.split('_')[0] in [self.UPLINK, self.DOWNLINK]]
+        for i in range(len(flows_data)):
+            uplink = '_'.join([self.UPLINK, str(i)])
+            downlink = '_'.join([self.DOWNLINK, str(i)])
+            if uplink in flows_data:
+                self.full_profile.update({uplink: self.params[uplink]})
+            if downlink in flows_data:
+                self.full_profile.update({downlink: self.params[downlink]})
+
+    def update_traffic_profile(self, traffic_generator):
+        def port_generator():
+            for vld_id, intfs in sorted(traffic_generator.networks.items()):
+                if not vld_id.startswith((self.UPLINK, self.DOWNLINK)):
+                    continue
+                for intf in intfs:
+                    yield traffic_generator.vnfd_helper.port_num(intf)
+
+        self._get_flow_groups_params()
+        self.ports = [port for port in port_generator()]
index 4c13112..1d37f8f 100644 (file)
@@ -43,7 +43,8 @@ class IxiaBasicScenario(object):
     def apply_config(self):
         pass
 
-    def create_traffic_model(self):
+    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]
@@ -71,6 +72,7 @@ class IxiaPppoeClientScenario(object):
         self._context_cfg = context_cfg
         self._ixia_cfg = ixia_cfg
         self.protocols = []
+        self.device_groups = []
 
     def apply_config(self):
         vports = self.client.get_vports()
@@ -80,9 +82,15 @@ class IxiaPppoeClientScenario(object):
         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 create_traffic_model(self, traffic_profile):
+        endpoints_id_pairs = self._get_endpoints_src_dst_id_pairs(
+            traffic_profile.full_profile)
+        endpoints_obj_pairs = \
+            self._get_endpoints_src_dst_obj_pairs(endpoints_id_pairs)
+        uplink_endpoints = endpoints_obj_pairs[::2]
+        downlink_endpoints = endpoints_obj_pairs[1::2]
+        self.client.create_ipv4_traffic_model(uplink_endpoints,
+                                              downlink_endpoints)
 
     def run_protocols(self):
         LOG.info('PPPoE Scenario - Start Protocols')
@@ -116,6 +124,144 @@ class IxiaPppoeClientScenario(object):
                                       strict=False)
         return ip, ipaddr.prefixlen
 
+    @staticmethod
+    def _get_endpoints_src_dst_id_pairs(flows_params):
+        """Get list of flows src/dst port pairs
+
+        Create list of flows src/dst port pairs based on traffic profile
+        flows data. Each uplink/downlink pair in traffic profile represents
+        specific flows between the pair of ports.
+
+        Example ('port' key represents port on which flow will be created):
+
+        Input flows data:
+        uplink_0:
+          ipv4:
+            id: 1
+            port: xe0
+        downlink_0:
+          ipv4:
+            id: 2
+            port: xe1
+        uplink_1:
+          ipv4:
+            id: 3
+            port: xe2
+        downlink_1:
+          ipv4:
+            id: 4
+            port: xe3
+
+        Result list: ['xe0', 'xe1', 'xe2', 'xe3']
+
+        Result list means that the following flows pairs will be created:
+        - uplink 0: port xe0 <-> port xe1
+        - downlink 0: port xe1 <-> port xe0
+        - uplink 1: port xe2 <-> port xe3
+        - downlink 1: port xe3 <-> port xe2
+
+        :param flows_params: ordered dict of traffic profile flows params
+        :return: (list) list of flows src/dst ports
+        """
+        if len(flows_params) % 2:
+            raise RuntimeError('Number of uplink/downlink pairs'
+                               ' in traffic profile is not equal')
+        endpoint_pairs = []
+        for flow in flows_params:
+            port = flows_params[flow]['ipv4'].get('port')
+            if port is None:
+                continue
+            endpoint_pairs.append(port)
+        return endpoint_pairs
+
+    def _get_endpoints_src_dst_obj_pairs(self, endpoints_id_pairs):
+        """Create list of uplink/downlink device groups pairs
+
+        Based on traffic profile options, create list of uplink/downlink
+        device groups pairs between which flow groups will be created:
+
+        1. In case uplink/downlink flows in traffic profile doesn't have
+           specified 'port' key, flows will be created between each device
+           group on access port and device group on corresponding core port.
+           E.g.:
+           Device groups created on access port xe0: dg1, dg2, dg3
+           Device groups created on core port xe1: dg4
+           Flows will be created between:
+           dg1 -> dg4
+           dg4 -> dg1
+           dg2 -> dg4
+           dg4 -> dg2
+           dg3 -> dg4
+           dg4 -> dg3
+
+        2. In case uplink/downlink flows in traffic profile have specified
+           'port' key, flows will be created between device groups on this
+           port.
+           E.g., for the following traffic profile
+           uplink_0:
+             port: xe0
+           downlink_0:
+             port: xe1
+           uplink_1:
+             port: xe0
+           downlink_0:
+             port: xe3
+           Flows will be created between:
+           Port xe0 (dg1) -> Port xe1 (dg1)
+           Port xe1 (dg1) -> Port xe0 (dg1)
+           Port xe0 (dg2) -> Port xe3 (dg1)
+           Port xe3 (dg3) -> Port xe0 (dg1)
+
+        :param endpoints_id_pairs: (list) List of uplink/downlink flows ports
+         pairs
+        :return: (list) list of uplink/downlink device groups descriptors pairs
+        """
+        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)
+
+        uplink_ports = [p['tg__0'] for p in self._ixia_cfg['flow']['src_ip']]
+        downlink_ports = [p['tg__0'] for p in self._ixia_cfg['flow']['dst_ip']]
+        uplink_port_topology_map = zip(uplink_ports, self._access_topologies)
+        downlink_port_topology_map = zip(downlink_ports, self._core_topologies)
+
+        port_to_dev_group_mapping = {}
+        for port, topology in uplink_port_topology_map:
+            topology_dgs = self.client.get_topology_device_groups(topology)
+            port_to_dev_group_mapping[port] = topology_dgs
+        for port, topology in downlink_port_topology_map:
+            topology_dgs = self.client.get_topology_device_groups(topology)
+            port_to_dev_group_mapping[port] = topology_dgs
+
+        uplink_endpoints = endpoints_id_pairs[::2]
+        downlink_endpoints = endpoints_id_pairs[1::2]
+
+        uplink_dev_groups = []
+        group_up = [uplink_endpoints[i:i + svlan_count]
+                    for i in range(0, len(uplink_endpoints), svlan_count)]
+
+        for group in group_up:
+            for i, port in enumerate(group):
+                uplink_dev_groups.append(port_to_dev_group_mapping[port][i])
+
+        downlink_dev_groups = []
+        for port in downlink_endpoints:
+            downlink_dev_groups.append(port_to_dev_group_mapping[port][0])
+
+        endpoint_obj_pairs = []
+        [endpoint_obj_pairs.extend([up, down])
+         for up, down in zip(uplink_dev_groups, downlink_dev_groups)]
+
+        if not endpoint_obj_pairs:
+            for up, down in zip(uplink_ports, downlink_ports):
+                uplink_dev_groups = port_to_dev_group_mapping[up]
+                downlink_dev_groups = \
+                    port_to_dev_group_mapping[down] * len(uplink_dev_groups)
+                [endpoint_obj_pairs.extend(list(i))
+                 for i in zip(uplink_dev_groups, downlink_dev_groups)]
+        return endpoint_obj_pairs
+
     def _fill_ixia_config(self):
         pppoe = self._ixia_cfg["pppoe_client"]
         ipv4 = self._ixia_cfg["ipv4_client"]
@@ -151,6 +297,7 @@ class IxiaPppoeClientScenario(object):
                 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)
+                self.device_groups.append(dg)
                 # add ethernet layer to device group
                 ethernet = self.client.add_ethernet(dg, 'Ethernet')
                 self.protocols.append(ethernet)
@@ -181,6 +328,7 @@ class IxiaPppoeClientScenario(object):
             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)
+                self.device_groups.append(dg)
                 # add ethernet layer to device group
                 ethernet = self.client.add_ethernet(dg, 'Ethernet')
                 self.protocols.append(ethernet)
@@ -295,12 +443,12 @@ class IxiaResourceHelper(ClientResourceHelper):
             raise RuntimeError(
                 "IXIA config type '{}' not supported".format(ixia_config))
 
-    def _initialize_client(self):
+    def _initialize_client(self, traffic_profile):
         """Initialize the IXIA IxNetwork client and configure the server"""
         self.client.clear_config()
         self.client.assign_ports()
         self._ix_scenario.apply_config()
-        self._ix_scenario.create_traffic_model()
+        self._ix_scenario.create_traffic_model(traffic_profile)
 
     def run_traffic(self, traffic_profile, *args):
         if self._terminated.value:
@@ -312,7 +460,8 @@ class IxiaResourceHelper(ClientResourceHelper):
         default = "00:00:00:00:00:00"
 
         self._build_ports()
-        self._initialize_client()
+        traffic_profile.update_traffic_profile(self)
+        self._initialize_client(traffic_profile)
 
         mac = {}
         for port_name in self.vnfd_helper.port_pairs.all_ports:
index 5b39b6c..ef16676 100644 (file)
@@ -16,6 +16,7 @@ import copy
 
 import mock
 import unittest
+import collections
 
 from yardstick.network_services.traffic_profile import ixia_rfc2544
 from yardstick.network_services.traffic_profile import trex_traffic_profile
@@ -511,9 +512,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
         with mock.patch.object(rfc2544_profile, '_get_ixia_traffic_profile') \
                 as mock_get_tp, \
                 mock.patch.object(rfc2544_profile, '_ixia_traffic_generate') \
-                as mock_tgenerate, \
-                mock.patch.object(rfc2544_profile, 'update_traffic_profile') \
-                as mock_update_tp:
+                as mock_tgenerate:
             mock_get_tp.return_value = 'fake_tprofile'
             output = rfc2544_profile.execute_traffic(mock.ANY,
                                                      ixia_obj=mock.ANY)
@@ -524,7 +523,6 @@ class TestIXIARFC2544Profile(unittest.TestCase):
         self.assertEqual(0, rfc2544_profile.min_rate)
         mock_get_tp.assert_called_once()
         mock_tgenerate.assert_called_once()
-        mock_update_tp.assert_called_once()
 
     def test_execute_traffic_not_first_run(self):
         rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE)
@@ -683,3 +681,37 @@ class TestIXIARFC2544Profile(unittest.TestCase):
         self.assertEqual(66.833, samples['RxThroughput'])
         self.assertEqual(0.099651, samples['DropPercentage'])
         self.assertEqual(33.45, rfc2544_profile.rate)
+
+
+class TestIXIARFC2544PppoeScenarioProfile(unittest.TestCase):
+
+    TRAFFIC_PROFILE = {
+        "schema": "nsb:traffic_profile:0.1",
+        "name": "fixed",
+        "description": "Fixed traffic profile to run UDP traffic",
+        "traffic_profile": {
+            "traffic_type": "FixedTraffic",
+            "frame_rate": 100},
+        'uplink_0': {'ipv4': {'port': 'xe0', 'id': 1}},
+        'downlink_0': {'ipv4': {'port': 'xe2', 'id': 2}},
+        'uplink_1': {'ipv4': {'port': 'xe1', 'id': 3}},
+        'downlink_1': {'ipv4': {'port': 'xe2', 'id': 4}}
+    }
+
+    def setUp(self):
+        self.ixia_tp = ixia_rfc2544.IXIARFC2544PppoeScenarioProfile(
+            self.TRAFFIC_PROFILE)
+
+    def test___init__(self):
+        self.assertIsInstance(self.ixia_tp.full_profile,
+                              collections.OrderedDict)
+
+    def test__get_flow_groups_params(self):
+        expected_tp = collections.OrderedDict([
+            ('uplink_0', {'ipv4': {'id': 1, 'port': 'xe0'}}),
+            ('downlink_0', {'ipv4': {'id': 2, 'port': 'xe2'}}),
+            ('uplink_1', {'ipv4': {'id': 3, 'port': 'xe1'}}),
+            ('downlink_1', {'ipv4': {'id': 4, 'port': 'xe2'}})])
+
+        self.ixia_tp._get_flow_groups_params()
+        self.assertDictEqual(self.ixia_tp.full_profile, expected_tp)
index e223988..65bf56f 100644 (file)
@@ -18,6 +18,7 @@ import mock
 import six
 import unittest
 import ipaddress
+from collections import OrderedDict
 
 from yardstick.common import utils
 from yardstick.common import exceptions
@@ -105,6 +106,7 @@ class TestIxiaResourceHelper(unittest.TestCase):
             ixia_rhelper.run_traffic(mock_tprofile)
 
         self.assertEqual('fake_samples', ixia_rhelper._queue.get())
+        mock_tprofile.update_traffic_profile.assert_called_once()
 
 
 @mock.patch.object(tg_rfc2544_ixia, 'ixnet_api')
@@ -524,12 +526,112 @@ class TestIxiaPppoeClientScenario(unittest.TestCase):
         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()
+    @mock.patch.object(tg_rfc2544_ixia.IxiaPppoeClientScenario,
+                       '_get_endpoints_src_dst_id_pairs')
+    @mock.patch.object(tg_rfc2544_ixia.IxiaPppoeClientScenario,
+                       '_get_endpoints_src_dst_obj_pairs')
+    def test_create_traffic_model(self, mock_obj_pairs, mock_id_pairs):
+        uplink_endpoints = ['group1', 'group2']
+        downlink_endpoints = ['group3', 'group3']
+        mock_id_pairs.return_value = ['xe0', 'xe1', 'xe0', 'xe1']
+        mock_obj_pairs.return_value = ['group1', 'group3', 'group2', 'group3']
+        mock_tp = mock.Mock()
+        mock_tp.full_profile = {'uplink_0': 'data',
+                                'downlink_0': 'data',
+                                'uplink_1': 'data',
+                                'downlink_1': 'data'
+                                }
+        self.scenario.create_traffic_model(mock_tp)
+        mock_id_pairs.assert_called_once_with(mock_tp.full_profile)
+        mock_obj_pairs.assert_called_once_with(['xe0', 'xe1', 'xe0', 'xe1'])
         self.scenario.client.create_ipv4_traffic_model.assert_called_once_with(
-            'access', 'core')
+            uplink_endpoints, downlink_endpoints)
+
+    def test__get_endpoints_src_dst_id_pairs(self):
+        full_tp = OrderedDict([
+            ('uplink_0', {'ipv4': {'port': 'xe0'}}),
+            ('downlink_0', {'ipv4': {'port': 'xe1'}}),
+            ('uplink_1', {'ipv4': {'port': 'xe0'}}),
+            ('downlink_1', {'ipv4': {'port': 'xe3'}})])
+        endpoints_src_dst_pairs = ['xe0', 'xe1', 'xe0', 'xe3']
+        res = self.scenario._get_endpoints_src_dst_id_pairs(full_tp)
+        self.assertEqual(res, endpoints_src_dst_pairs)
+
+    def test__get_endpoints_src_dst_id_pairs_wrong_flows_number(self):
+        full_tp = OrderedDict([
+            ('uplink_0', {'ipv4': {'port': 'xe0'}}),
+            ('downlink_0', {'ipv4': {'port': 'xe1'}}),
+            ('uplink_1', {'ipv4': {'port': 'xe0'}})])
+        with self.assertRaises(RuntimeError):
+            self.scenario._get_endpoints_src_dst_id_pairs(full_tp)
+
+    def test__get_endpoints_src_dst_id_pairs_no_port_key(self):
+        full_tp = OrderedDict([
+            ('uplink_0', {'ipv4': {'id': 1}}),
+            ('downlink_0', {'ipv4': {'id': 2}})])
+        self.assertEqual(
+            self.scenario._get_endpoints_src_dst_id_pairs(full_tp), [])
+
+    def test__get_endpoints_src_dst_obj_pairs_tp_with_port_key(self):
+        endpoints_id_pairs = ['xe0', 'xe1',
+                              'xe0', 'xe1',
+                              'xe0', 'xe3',
+                              'xe0', 'xe3']
+        ixia_cfg = {
+            'pppoe_client': {
+                'sessions_per_port': 4,
+                'sessions_per_svlan': 1
+            },
+            'flow': {
+                'src_ip': [{'tg__0': 'xe0'}, {'tg__0': 'xe2'}],
+                'dst_ip': [{'tg__0': 'xe1'}, {'tg__0': 'xe3'}]
+            }
+        }
+
+        expected_result = ['tp1_dg1', 'tp3_dg1', 'tp1_dg2', 'tp3_dg1',
+                           'tp1_dg3', 'tp4_dg1', 'tp1_dg4', 'tp4_dg1']
+
+        self.scenario._ixia_cfg = ixia_cfg
+        self.scenario._access_topologies = ['topology1', 'topology2']
+        self.scenario._core_topologies = ['topology3', 'topology4']
+        self.mock_IxNextgen.get_topology_device_groups.side_effect = \
+            [['tp1_dg1', 'tp1_dg2', 'tp1_dg3', 'tp1_dg4'],
+             ['tp2_dg1', 'tp2_dg2', 'tp2_dg3', 'tp2_dg4'],
+             ['tp3_dg1'],
+             ['tp4_dg1']]
+        res = self.scenario._get_endpoints_src_dst_obj_pairs(
+            endpoints_id_pairs)
+        self.assertEqual(res, expected_result)
+
+    def test__get_endpoints_src_dst_obj_pairs_default_flows_mapping(self):
+        endpoints_id_pairs = []
+        ixia_cfg = {
+            'pppoe_client': {
+                'sessions_per_port': 4,
+                'sessions_per_svlan': 1
+            },
+            'flow': {
+                'src_ip': [{'tg__0': 'xe0'}, {'tg__0': 'xe2'}],
+                'dst_ip': [{'tg__0': 'xe1'}, {'tg__0': 'xe3'}]
+            }
+        }
+
+        expected_result = ['tp1_dg1', 'tp3_dg1', 'tp1_dg2', 'tp3_dg1',
+                           'tp1_dg3', 'tp3_dg1', 'tp1_dg4', 'tp3_dg1',
+                           'tp2_dg1', 'tp4_dg1', 'tp2_dg2', 'tp4_dg1',
+                           'tp2_dg3', 'tp4_dg1', 'tp2_dg4', 'tp4_dg1']
+
+        self.scenario._ixia_cfg = ixia_cfg
+        self.scenario._access_topologies = ['topology1', 'topology2']
+        self.scenario._core_topologies = ['topology3', 'topology4']
+        self.mock_IxNextgen.get_topology_device_groups.side_effect = \
+            [['tp1_dg1', 'tp1_dg2', 'tp1_dg3', 'tp1_dg4'],
+             ['tp2_dg1', 'tp2_dg2', 'tp2_dg3', 'tp2_dg4'],
+             ['tp3_dg1'],
+             ['tp4_dg1']]
+        res = self.scenario._get_endpoints_src_dst_obj_pairs(
+            endpoints_id_pairs)
+        self.assertEqual(res, expected_result)
 
     def test_run_protocols(self):
         self.scenario.client.is_protocols_running.return_value = True