9c66982bb2c9bd0c7f484b3b2ca29fcc2835284a
[csit.git] / resources / libraries / python / TrafficGenerator.py
1 # Copyright (c) 2016 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Performance testing traffic generator library."""
15
16 from robot.api import logger
17
18 from resources.libraries.python.ssh import SSH
19 from resources.libraries.python.topology import NodeType
20 from resources.libraries.python.topology import NodeSubTypeTG
21 from resources.libraries.python.topology import Topology
22
23 __all__ = ['TrafficGenerator']
24
25 class TrafficGenerator(object):
26     """Traffic Generator"""
27
28     def __init__(self):
29         self._result = None
30         self._loss = None
31         self._sent = None
32         self._received = None
33         #T-REX interface order mapping
34         self._ifaces_reordered = 0
35
36     def initialize_traffic_generator(self, node, interface1, interface2, test_type):
37         """TG initialization
38         :param node: Traffic generator node
39         :param interface1: interface name of first interface
40         :param interface2: interface name of second interface
41         :test_type: 'L2' or 'L3' - src/dst MAC address
42         :type node: dict
43         :type interface1: str
44         :type interface2: str
45         :type test_type: str
46         :return: nothing
47         """
48
49         trex_path = "/opt/trex-core-1.91"
50
51         topo = Topology()
52
53         if node['type'] != NodeType.TG:
54             raise Exception('Node type is not a TG')
55         if node['subtype'] == NodeSubTypeTG.TREX:
56             ssh = SSH()
57             ssh.connect(node)
58
59             iface1_pci = topo.get_interface_pci_addr(node, interface1)
60             iface2_pci = topo.get_interface_pci_addr(node, interface2)
61             iface1_mac = topo.get_interface_mac(node, interface1)
62             iface2_mac = topo.get_interface_mac(node, interface2)
63             if min(iface1_pci, iface2_pci) != iface1_pci:
64                 iface1_mac, iface2_mac = iface2_mac, iface1_mac
65                 iface1_pci, iface2_pci = iface2_pci, iface1_pci
66                 self._ifaces_reordered = 1
67
68             iface1_mac_hex = "0x"+iface1_mac.replace(":", ",0x")
69             iface2_mac_hex = "0x"+iface2_mac.replace(":", ",0x")
70
71             if test_type == 'L2':
72                 (ret, stdout, stderr) = ssh.exec_command(
73                     "sudo sh -c 'cat << EOF > /etc/trex_cfg.yaml\n"
74                     "- port_limit      : 2\n"
75                     "  version         : 2\n"
76                     "  interfaces      : [\"{}\",\"{}\"]\n"
77                     "  port_info       :\n"
78                     "          - dest_mac        :   [{}]\n"
79                     "            src_mac         :   [{}]\n"
80                     "          - dest_mac        :   [{}]\n"
81                     "            src_mac         :   [{}]\n"
82                     "EOF'"\
83                     .format(iface1_pci, iface2_pci,
84                             iface2_mac_hex, iface1_mac_hex,
85                             iface1_mac_hex, iface2_mac_hex))
86                 if int(ret) != 0:
87                     logger.error("failed to create t-rex config: {}"\
88                     .format(stdout + stderr))
89                     raise RuntimeError('trex config generation error')
90             elif test_type == 'L3':
91                 raise NotImplementedError("L3 test_type not supported")
92             else:
93                 raise Exception("test_type unknown")
94
95
96             (ret, stdout, stderr) = ssh.exec_command(
97                 "sh -c 'cd {0}/scripts/ && "
98                 "sudo ./trex-cfg'"\
99                 .format(trex_path))
100             if int(ret) != 0:
101                 logger.error('trex-cfg failed: {0}'.format(stdout + stderr))
102                 raise RuntimeError('trex-cfg failed')
103
104             (ret, _, _) = ssh.exec_command(
105                 "sh -c 'cd {0}/scripts/ && "
106                 "sudo nohup ./t-rex-64 -i -c 4 --iom 0 > /dev/null 2>&1 &'"
107                 "> /dev/null"\
108                 .format(trex_path))
109             if int(ret) != 0:
110                 raise RuntimeError('t-rex-64 startup failed')
111
112     @staticmethod
113     def teardown_traffic_generator(node):
114         """TG teardown
115         :param node: Traffic generator node
116         :type node: dict
117         :return: nothing
118         """
119
120         if node['type'] != NodeType.TG:
121             raise Exception('Node type is not a TG')
122         if node['subtype'] == NodeSubTypeTG.TREX:
123             ssh = SSH()
124             ssh.connect(node)
125             (ret, stdout, stderr) = ssh.exec_command(
126                 "sh -c 'sudo pkill t-rex'")
127
128     def send_traffic_on(self, nodes_info, duration, rate,
129                         framesize, traffic_type):
130         """Send traffic from all configured interfaces on TG
131         :param nodes_info: Dictionary containing information on all nodes
132         in topology.
133         :param duration: Duration of test traffic generation in seconds
134         :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...)
135         :param framesize: Frame size (L2) in Bytes
136         :param traffic_type: Traffic profile
137         :type nodes_info: dict
138         :type duration: str
139         :type rate: str
140         :type framesize: str
141         :type traffic_type: str
142         :return: TG output
143         :rtype: str
144         """
145
146         node = nodes_info["TG"]
147
148         if node['type'] != NodeType.TG:
149             raise Exception('Node type is not a TG')
150
151         if node['subtype'] is None:
152             raise Exception('TG subtype not defined')
153
154         ssh = SSH()
155         ssh.connect(node)
156
157         if node['subtype'] == NodeSubTypeTG.TREX:
158             if traffic_type in ["3-node-xconnect", "3-node-bridge"]:
159                 (ret, stdout, stderr) = ssh.exec_command(
160                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/t-rex-stateless.py "
161                     "-d {0} -r {1} -s {2} "
162                     "--p1_src_start_ip 10.10.10.1 "
163                     "--p1_src_end_ip 10.10.10.254 "
164                     "--p1_dst_start_ip 20.20.20.1 "
165                     "--p2_src_start_ip 20.20.20.1 "
166                     "--p2_src_end_ip 20.20.20.254 "
167                     "--p2_dst_start_ip 10.10.10.1'".\
168                     format(duration, rate, framesize), timeout=int(duration)+60)
169             elif traffic_type in ["3-node-IPv4"]:
170                 (ret, stdout, stderr) = ssh.exec_command(
171                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/t-rex-stateless.py "
172                     "-d {0} -r {1} -s {2} "
173                     "--p1_src_start_ip 10.10.10.2 "
174                     "--p1_src_end_ip 10.10.10.254 "
175                     "--p1_dst_start_ip 20.20.20.2 "
176                     "--p2_src_start_ip 20.20.20.2 "
177                     "--p2_src_end_ip 20.20.20.254 "
178                     "--p2_dst_start_ip 10.10.10.2'".\
179                     format(duration, rate, framesize),\
180                     timeout=int(duration)+60)
181             else:
182                 raise NotImplementedError('Unsupported traffic type')
183
184         else:
185             raise NotImplementedError("TG subtype not supported")
186
187         logger.trace(ret)
188         logger.trace(stdout)
189         logger.trace(stderr)
190
191         for line in stdout.splitlines():
192             pass
193
194         self._result = line
195         logger.info('TrafficGen result: {0}'.format(self._result))
196
197         self._loss = self._result.split(', ')[3].split('=')[1]
198
199         return self._result
200
201     def no_traffic_loss_occured(self):
202         """Fail is loss occured in traffic run
203         :return: nothing
204         """
205
206         if self._loss is None:
207             raise Exception('The traffic generation has not been issued')
208         if self._loss != '0':
209             raise Exception('Traffic loss occured: {0}'.format(self._loss))