e63b8bc5a3053986c288a7d12d51856c8aace2ba
[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
22 __all__ = ['TrafficGenerator']
23
24 class TrafficGenerator(object):
25     """Traffic Generator"""
26
27     def __init__(self):
28         self._result = None
29         self._loss = None
30         self._sent = None
31         self._received = None
32
33     @staticmethod
34     def initialize_traffic_generator(node, interface1, interface2):
35         """TG initialization
36         :param node: Traffic generator node
37         :param interface1: interface name of first interface
38         :param interface2: interface name of second interface
39         :type node: dict
40         :type interface1: str
41         :type interface2: str
42         :return: nothing
43         """
44
45         trex_path = "/opt/trex-core-1.91"
46
47         if node['type'] != NodeType.TG:
48             raise Exception('Node type is not a TG')
49         if node['subtype'] == NodeSubTypeTG.TREX:
50             ssh = SSH()
51             ssh.connect(node)
52
53             (ret, stdout, stderr) = ssh.exec_command(
54                 "sh -c 'cd {0}/scripts/ && "
55                 "sudo ./trex-cfg'"\
56                 .format(trex_path))
57             if int(ret) != 0:
58                 logger.error('trex-cfg failed: {0}'.format(stdout + stderr))
59                 raise RuntimeError('trex-cfg failed')
60
61             (ret, _, _) = ssh.exec_command(
62                 "sh -c 'cd {0}/scripts/ && "
63                 "sudo nohup ./t-rex-64 -i -c 4 --iom 0 > /dev/null 2>&1 &'"
64                 "> /dev/null"\
65                 .format(trex_path))
66             if int(ret) != 0:
67                 raise RuntimeError('t-rex-64 startup failed')
68
69     @staticmethod
70     def teardown_traffic_generator(node):
71         """TG teardown
72         :param node: Traffic generator node
73         :type node: dict
74         :return: nothing
75         """
76
77         if node['type'] != NodeType.TG:
78             raise Exception('Node type is not a TG')
79         if node['subtype'] == NodeSubTypeTG.TREX:
80             ssh = SSH()
81             ssh.connect(node)
82             (ret, stdout, stderr) = ssh.exec_command(
83                 "sh -c 'sudo pkill t-rex'")
84
85     def send_traffic_on(self, nodes_info, duration, rate,
86                         framesize, traffic_type):
87         """Send traffic from all configured interfaces on TG
88         :param nodes_info: Dictionary containing information on all nodes
89         in topology.
90         :param duration: Duration of test traffic generation in seconds
91         :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...)
92         :param framesize: Frame size (L2) in Bytes
93         :param traffic_type: Traffic profile
94         :type nodes_info: dict
95         :type duration: str
96         :type rate: str
97         :type framesize: str
98         :type traffic_type: str
99         :return: TG output
100         :rtype: str
101         """
102
103         node = nodes_info["TG"]
104
105         if node['type'] != NodeType.TG:
106             raise Exception('Node type is not a TG')
107
108         if node['subtype'] is None:
109             raise Exception('TG subtype not defined')
110
111         ssh = SSH()
112         ssh.connect(node)
113
114         if node['subtype'] == NodeSubTypeTG.TREX:
115             if traffic_type in ["3-node-xconnect", "3-node-bridge"]:
116                 (ret, stdout, stderr) = ssh.exec_command(
117                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex-stateless.py "
118                     "-d {0} -r {1} -s {2} "
119                     "--p1_src_start_ip 10.10.10.1 "
120                     "--p1_src_end_ip 10.10.10.254 "
121                     "--p1_dst_start_ip 20.20.20.1 "
122                     "--p2_src_start_ip 20.20.20.1 "
123                     "--p2_src_end_ip 20.20.20.254 "
124                     "--p2_dst_start_ip 10.10.10.1'".\
125                     format(duration, rate, framesize), timeout=int(duration)+60)
126             elif traffic_type in ["3-node-IPv4"]:
127                 (ret, stdout, stderr) = ssh.exec_command(
128                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex-stateless.py "
129                     "-d {0} -r {1} -s {2} "
130                     "--p1_src_start_ip 10.10.10.2 "
131                     "--p1_src_end_ip 10.10.10.254 "
132                     "--p1_dst_start_ip 20.20.20.2 "
133                     "--p2_src_start_ip 20.20.20.2 "
134                     "--p2_src_end_ip 20.20.20.254 "
135                     "--p2_dst_start_ip 10.10.10.2'".\
136                     format(duration, rate, framesize),\
137                     timeout=int(duration)+60)
138             else:
139                 raise NotImplementedError('Unsupported traffic type')
140
141         else:
142             raise NotImplementedError("TG subtype not supported")
143
144         logger.trace(ret)
145         logger.trace(stdout)
146         logger.trace(stderr)
147
148         for line in stdout.splitlines():
149             pass
150
151         self._result = line
152         logger.info('TrafficGen result: {0}'.format(self._result))
153
154         self._loss = self._result.split(', ')[3].split('=')[1]
155
156         return self._result
157
158     def no_traffic_loss_occured(self):
159         """Fail is loss occured in traffic run
160         :return: nothing
161         """
162
163         if self._loss is None:
164             raise Exception('The traffic generation has not been issued')
165         if self._loss != '0':
166             raise Exception('Traffic loss occured: {0}'.format(self._loss))