blob: 9245f160919928c9e3bfc77ca6c61a214749aa12 [file] [log] [blame]
Daniele Moro80889562021-09-08 10:09:26 +02001from distutils.util import strtobool
2from tests.USECASE.SegmentRouting.dependencies import scapy_helper
3
4
5class Trex:
6 """
7 Utility that manages interaction with TRex server via TRexDriver component
8 Example params:
9 <TREX>
10 <port_stats>0,1</port_stats>
11 <flows>
12 <RT_FROM_UE>
13 <name>Real Time</name>
14 <l1_bps>40000000</l1_bps>
15 <trex_port>0</trex_port>
16 <packet>
17 <pktlen>1400</pktlen>
18 <ip_src>10.240.0.2</ip_src>
19 <ip_dst>10.32.11.101</ip_dst>
20 <eth_src>3C:EC:EF:3E:0B:A0</eth_src>
21 <eth_dst>00:00:0A:4C:1C:46</eth_dst>
22 <gtp_teid>200</gtp_teid>
23 <s1u_addr>10.32.11.126</s1u_addr>
24 <enb_addr>10.32.11.100</enb_addr>
25 </packet>
26 <latency_stats>true</latency_stats>
27 <flow_id>10</flow_id> <!-- Mandatory when latency_stats=true -->
28 <delay>50000</delay> <!-- wait 50 ms till start to let queues fill up -->
29 <expected_min_received>1</expected_min_received>
30 <expected_max_dropped>0</expected_max_dropped>
31 <expected_max_latency>1500</expected_max_latency>
32 <expected_99_9_percentile_latency>100</expected_99_9_percentile_latency>
33 </RT_FROM_UE>
34 </flows>
35 <TREX>
36 """
37
38 def __init__(self):
39 self.trex_client = None
40 self.traffic_flows = {}
41 self.port_stats = []
42 self.packets = {} # Per-flow dictionary of packets
43
44 def setup(self, trex_client):
45 self.trex_client = trex_client
46 self.traffic_flows = main.params["TREX"]["flows"]
47 if "port_stats" in main.params["TREX"] and \
48 main.params["TREX"].get("port_stats") is not '':
49 self.port_stats = [int(p) for p in
50 main.params["TREX"].get("port_stats").split(",")]
51 self.trex_client.setupTrex(main.configPath)
52
53 def teardown(self):
54 self.trex_client.stopTrexServer()
55
56 def createFlow(self, flow_name):
57 if flow_name not in self.traffic_flows:
58 main.log.error("CFG flow not present in params")
59 return False
60 self.traffic_flows[flow_name]["packet"] = Trex.__sanitizePacketConfig(
61 self.traffic_flows[flow_name]["packet"])
62 if "gtp_teid" in self.traffic_flows[flow_name]["packet"]:
63 # packets must be GTP encapped
64 self.packets[flow_name] = scapy_helper.simple_gtp_udp_packet(
65 **self.traffic_flows[flow_name]["packet"])
66 else:
67 self.packets[flow_name] = scapy_helper.simple_udp_packet(
68 **self.traffic_flows[flow_name]["packet"])
69
70 def sendAndReceiveTraffic(self, duration):
71 """
72 Connect the client, create the flows in trex (with packets created with
73 createFlow, send and receive the traffic, and disconnect the client.
74 :param duration: traffic duration
75 :return:
76 """
77 self.trex_client.connectTrexClient()
78 for flow_name, packet in self.packets.items():
79 flow_config = self.traffic_flows[flow_name]
80 Trex.__sanitizeFlowConfig(flow_config)
81 self.trex_client.addStream(pkt=packet,
82 trex_port=flow_config["trex_port"],
83 l1_bps=flow_config["l1_bps"],
84 percentage=flow_config["percentage"],
85 delay=flow_config["delay"],
86 flow_id=flow_config["flow_id"],
87 flow_stats=flow_config["latency_stats"])
88 self.trex_client.startAndWaitTraffic(duration=duration)
89 self.trex_client.disconnectTrexClient()
90
91 def assertRxPackets(self, flow_name):
92 if not self.isFlowStats(flow_name):
93 main.log.info("No flow stats for flow {}".format(flow_name))
94 expected_min_received = int(
95 self.traffic_flows[flow_name].get("expected_min_received", "1"))
96 flow_id = self.traffic_flows[flow_name]["flow_id"]
97 flow_stats = self.trex_client.getFlowStats(flow_id)
98 utilities.assert_equals(
99 expect=True,
100 actual=flow_stats.rx_packets >= expected_min_received,
101 onpass="Traffic Flow {}: Received traffic".format(flow_name),
102 onfail="Traffic Flow {}: No traffic received".format(flow_name))
103
104 def assertDroppedPacket(self, flow_name):
105 if not self.isFlowStats(flow_name):
106 main.log.info("No flow stats for flow {}".format(flow_name))
107 expected_max_dropped = int(
108 self.traffic_flows[flow_name].get("expected_max_dropped", "0"))
109 latency_stats = self.__getLatencyStats(flow_name)
110 utilities.assert_equals(
111 expect=True,
112 actual=latency_stats.dropped <= expected_max_dropped,
113 onpass="Traffic Flow {}: {} packets dropped, below threshold ({})".format(
114 flow_name, latency_stats.dropped,
115 expected_max_dropped),
116 onfail="Traffic Flow {}: {} packets dropped, above threshold ({})".format(
117 flow_name, latency_stats.dropped,
118 expected_max_dropped))
119
120 def assertMaxLatency(self, flow_name):
121 if not self.isFlowStats(flow_name):
122 main.log.info("No flow stats for flow {}".format(flow_name))
123 expected_max_latency = int(
124 self.traffic_flows[flow_name].get("expected_max_latency", "0"))
125 latency_stats = self.__getLatencyStats(flow_name)
126 utilities.assert_equals(
127 expect=True,
128 actual=latency_stats.total_max <= expected_max_latency,
129 onpass="Traffic Flow {}: Maximum latency below threshold".format(
130 flow_name),
131 onfail="Traffic Flow {}: Maximum latency is too high {}".format(
132 flow_name, latency_stats.total_max))
133
134 def assert99_9PercentileLatency(self, flow_name):
135 if not self.isFlowStats(flow_name):
136 main.log.info("No flow stats for flow {}".format(flow_name))
137 expected_99_9_percentile_latency = int(
138 self.traffic_flows[flow_name].get(
139 "expected_99_9_percentile_latency", "0"))
140 latency_stats = self.__getLatencyStats(flow_name)
141 utilities.assert_equals(
142 expect=True,
143 actual=latency_stats.percentile_99_9 <= expected_99_9_percentile_latency,
144 onpass="Traffic Flow {}: 99.9th percentile latency below threshold".format(
145 flow_name),
146 onfail="Traffic Flow {}: 99.9th percentile latency is too high {}".format(
147 flow_name, latency_stats.percentile_99_9))
148
149 def logPortStats(self):
150 main.log.debug(self.port_stats)
151 for port in self.port_stats:
152 self.trex_client.logPortStats(port)
153
154 def logFlowStats(self, flow_name):
155 if self.isFlowStats(flow_name):
156 flow_id = self.traffic_flows[flow_name]["flow_id"]
157 self.trex_client.logFlowStats(flow_id)
158 self.trex_client.logLatencyStats(flow_id)
159
160 def isFlowStats(self, flow_name):
161 return self.traffic_flows[flow_name]["latency_stats"]
162
163 def __getLatencyStats(self, flow_name):
164 flow_id = self.traffic_flows[flow_name]["flow_id"]
165 return self.trex_client.getLatencyStats(flow_id)
166
167 @staticmethod
168 def __sanitizePacketConfig(packet):
169 if "gtp_teid" in packet.keys():
170 packet["gtp_teid"] = int(packet["gtp_teid"])
171 if "pktlen" in packet.keys():
172 packet["pktlen"] = int(packet["pktlen"])
173 return packet
174
175 @staticmethod
176 def __sanitizeFlowConfig(flow_config):
177 flow_config["trex_port"] = int(flow_config["trex_port"])
178 flow_config["percentage"] = float(
179 flow_config["percentage"]) if "percentage" in flow_config else None
180 flow_config["l1_bps"] = float(
181 flow_config["l1_bps"]) if "l1_bps" in flow_config else None
182 flow_config["delay"] = int(flow_config.get("delay", 0))
183 flow_config["flow_id"] = int(
184 flow_config["flow_id"]) if "flow_id" in flow_config else None
185 flow_config["latency_stats"] = bool(
186 strtobool(flow_config.get("latency_stats", "False")))