blob: d710d07f9367d018278b68f3d735767040fe534f [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
Yi Tsengdda7e322021-09-20 14:21:20 -070070 def resetFlows(self):
71 self.packets = {}
72
Daniele Moro80889562021-09-08 10:09:26 +020073 def sendAndReceiveTraffic(self, duration):
74 """
75 Connect the client, create the flows in trex (with packets created with
76 createFlow, send and receive the traffic, and disconnect the client.
77 :param duration: traffic duration
78 :return:
79 """
80 self.trex_client.connectTrexClient()
81 for flow_name, packet in self.packets.items():
82 flow_config = self.traffic_flows[flow_name]
83 Trex.__sanitizeFlowConfig(flow_config)
84 self.trex_client.addStream(pkt=packet,
85 trex_port=flow_config["trex_port"],
86 l1_bps=flow_config["l1_bps"],
87 percentage=flow_config["percentage"],
88 delay=flow_config["delay"],
89 flow_id=flow_config["flow_id"],
90 flow_stats=flow_config["latency_stats"])
91 self.trex_client.startAndWaitTraffic(duration=duration)
92 self.trex_client.disconnectTrexClient()
93
94 def assertRxPackets(self, flow_name):
95 if not self.isFlowStats(flow_name):
96 main.log.info("No flow stats for flow {}".format(flow_name))
97 expected_min_received = int(
98 self.traffic_flows[flow_name].get("expected_min_received", "1"))
99 flow_id = self.traffic_flows[flow_name]["flow_id"]
100 flow_stats = self.trex_client.getFlowStats(flow_id)
101 utilities.assert_equals(
102 expect=True,
103 actual=flow_stats.rx_packets >= expected_min_received,
104 onpass="Traffic Flow {}: Received traffic".format(flow_name),
105 onfail="Traffic Flow {}: No traffic received".format(flow_name))
106
107 def assertDroppedPacket(self, flow_name):
108 if not self.isFlowStats(flow_name):
109 main.log.info("No flow stats for flow {}".format(flow_name))
110 expected_max_dropped = int(
111 self.traffic_flows[flow_name].get("expected_max_dropped", "0"))
112 latency_stats = self.__getLatencyStats(flow_name)
113 utilities.assert_equals(
114 expect=True,
115 actual=latency_stats.dropped <= expected_max_dropped,
116 onpass="Traffic Flow {}: {} packets dropped, below threshold ({})".format(
117 flow_name, latency_stats.dropped,
118 expected_max_dropped),
119 onfail="Traffic Flow {}: {} packets dropped, above threshold ({})".format(
120 flow_name, latency_stats.dropped,
121 expected_max_dropped))
122
123 def assertMaxLatency(self, flow_name):
124 if not self.isFlowStats(flow_name):
125 main.log.info("No flow stats for flow {}".format(flow_name))
126 expected_max_latency = int(
127 self.traffic_flows[flow_name].get("expected_max_latency", "0"))
128 latency_stats = self.__getLatencyStats(flow_name)
129 utilities.assert_equals(
130 expect=True,
131 actual=latency_stats.total_max <= expected_max_latency,
132 onpass="Traffic Flow {}: Maximum latency below threshold".format(
133 flow_name),
134 onfail="Traffic Flow {}: Maximum latency is too high {}".format(
135 flow_name, latency_stats.total_max))
136
137 def assert99_9PercentileLatency(self, flow_name):
138 if not self.isFlowStats(flow_name):
139 main.log.info("No flow stats for flow {}".format(flow_name))
140 expected_99_9_percentile_latency = int(
141 self.traffic_flows[flow_name].get(
142 "expected_99_9_percentile_latency", "0"))
143 latency_stats = self.__getLatencyStats(flow_name)
144 utilities.assert_equals(
145 expect=True,
146 actual=latency_stats.percentile_99_9 <= expected_99_9_percentile_latency,
147 onpass="Traffic Flow {}: 99.9th percentile latency below threshold".format(
148 flow_name),
149 onfail="Traffic Flow {}: 99.9th percentile latency is too high {}".format(
150 flow_name, latency_stats.percentile_99_9))
151
152 def logPortStats(self):
153 main.log.debug(self.port_stats)
154 for port in self.port_stats:
155 self.trex_client.logPortStats(port)
156
157 def logFlowStats(self, flow_name):
158 if self.isFlowStats(flow_name):
159 flow_id = self.traffic_flows[flow_name]["flow_id"]
160 self.trex_client.logFlowStats(flow_id)
161 self.trex_client.logLatencyStats(flow_id)
162
163 def isFlowStats(self, flow_name):
164 return self.traffic_flows[flow_name]["latency_stats"]
165
166 def __getLatencyStats(self, flow_name):
167 flow_id = self.traffic_flows[flow_name]["flow_id"]
168 return self.trex_client.getLatencyStats(flow_id)
169
170 @staticmethod
171 def __sanitizePacketConfig(packet):
172 if "gtp_teid" in packet.keys():
173 packet["gtp_teid"] = int(packet["gtp_teid"])
174 if "pktlen" in packet.keys():
175 packet["pktlen"] = int(packet["pktlen"])
Daniele Moro04a62d12021-10-06 17:37:36 +0200176 if "udp_dport" in packet.keys():
177 packet["udp_dport"] = int(packet["udp_dport"])
178 if "udp_sport" in packet.keys():
179 packet["udp_sport"] = int(packet["udp_sport"])
Daniele Moro80889562021-09-08 10:09:26 +0200180 return packet
181
182 @staticmethod
183 def __sanitizeFlowConfig(flow_config):
184 flow_config["trex_port"] = int(flow_config["trex_port"])
185 flow_config["percentage"] = float(
186 flow_config["percentage"]) if "percentage" in flow_config else None
187 flow_config["l1_bps"] = float(
188 flow_config["l1_bps"]) if "l1_bps" in flow_config else None
189 flow_config["delay"] = int(flow_config.get("delay", 0))
190 flow_config["flow_id"] = int(
191 flow_config["flow_id"]) if "flow_id" in flow_config else None
192 flow_config["latency_stats"] = bool(
193 strtobool(flow_config.get("latency_stats", "False")))