blob: f9aba6c3b09d41d764aba8eff2eafd5027ec595f [file] [log] [blame]
Daniele Moro80889562021-09-08 10:09:26 +02001from distutils.util import strtobool
Daniele Moro522023c2021-10-15 17:30:33 +02002import copy
Daniele Moro80889562021-09-08 10:09:26 +02003
4FALSE = '0'
5TRUE = '1'
6DIR_UPLINK = '1'
7DIR_DOWNLINK = '2'
8IFACE_ACCESS = '1'
9IFACE_CORE = '2'
10TUNNEL_SPORT = '2152'
11TUNNEL_TYPE_GPDU = '3'
12
13UE_PORT = 400
Daniele Morobef0c7e2022-02-16 17:47:13 -080014DEFAULT_PDN_PORT = 800
Daniele Moro80889562021-09-08 10:09:26 +020015GPDU_PORT = 2152
16
Daniele Moroa1975192022-01-21 18:01:19 +010017DEFAULT_APP_ID = 0
Daniele Moro4650ffb2022-02-15 22:44:18 +010018DEFAULT_SESSION_METER_IDX = 0
19DEFAULT_APP_METER_IDX = 0
20
Daniele Moro80889562021-09-08 10:09:26 +020021
22class UP4:
23 """
24 Utility that manages interaction with UP4 via a P4RuntimeCliDriver available
25 in the cluster. Additionally, can verify connectivity by crafting GTP packets
Daniele Moro522023c2021-10-15 17:30:33 +020026 via Scapy with an HostDriver component, specified via <enodebs>, <pdn_host>,
Daniele Moro80889562021-09-08 10:09:26 +020027 and <router_mac> parameters.
28
29 Example params file:
30 <UP4>
31 <pdn_host>Compute1</pdn_host> # Needed to verify connectivity with scapy
Daniele Moro522023c2021-10-15 17:30:33 +020032 <enodebs> # List of emulated eNodeBs
33 <enode_1>
34 <host>Compute1</host> # Host that emulates this eNodeB
35 <interface>eno3</interface> # Name of the linux interface to use on the host, if not specified take the default
36 <enb_address>10.32.11.122</enb_address> # IP address of the eNodeB
37 <ues>ue3</ues> # Emulated ues connected to this eNB
38 </enode_1>
39 <enodeb_2>
40 <host>Compute3</host>
41 <enb_address>10.32.11.194</enb_address>
42 <ues>ue1,ue2</ues>
43 </enodeb_2>
44 </enodebs>
45 <enodeb_host>Compute3</enodeb_host>
Daniele Moro80889562021-09-08 10:09:26 +020046 <router_mac>00:00:0A:4C:1C:46</router_mac> # Needed to verify connectivity with scapy
47 <s1u_address>10.32.11.126</s1u_address>
Daniele Moro80889562021-09-08 10:09:26 +020048 <ues>
49 <ue2>
Daniele Moro80889562021-09-08 10:09:26 +020050 <ue_address>10.240.0.2</ue_address>
51 <teid>200</teid>
52 <up_id>20</up_id>
53 <down_id>21</down_id>
Carmelo Cascone848d1f52022-01-27 18:15:58 -080054 <!-- TC 0 means BEST EFFORT -->
55 <tc>2</tc>
Daniele Moro80889562021-09-08 10:09:26 +020056 <five_g>False</five_g>
57 </ue2>
58 </ues>
Daniele Moro522023c2021-10-15 17:30:33 +020059 <switch_to_kill>Leaf2</switch_to_kill> # Component name of the switch to kill in CASE 5
60 <enodebs_fail>enodeb_1</enodebs_fail> # List of eNodeBs that should fail traffic forwarding in CASE 5
Daniele Moro80889562021-09-08 10:09:26 +020061 </UP4>
62 """
63
64 def __init__(self):
65 self.s1u_address = None
Daniele Moro522023c2021-10-15 17:30:33 +020066 self.enodebs = None
Daniele Moro80889562021-09-08 10:09:26 +020067 self.pdn_host = None
68 self.pdn_interface = None
69 self.router_mac = None
Daniele Moro522023c2021-10-15 17:30:33 +020070 self.emulated_ues = {}
Daniele Morobef0c7e2022-02-16 17:47:13 -080071 self.app_filters = {}
Daniele Moro80889562021-09-08 10:09:26 +020072 self.up4_client = None
Daniele Moro522023c2021-10-15 17:30:33 +020073 self.no_host = False
Daniele Moro80889562021-09-08 10:09:26 +020074
Daniele Moro954e2282021-09-22 17:32:03 +020075 def setup(self, p4rt_client, no_host=False):
76 """
77 Set up P4RT and scapy on eNB and PDN hosts
78 :param p4rt_client: a P4RuntimeCliDriver component
79 :param no_host: True if you don't want to start scapy on the hosts
80 :return:
81 """
Daniele Moro80889562021-09-08 10:09:26 +020082 self.s1u_address = main.params["UP4"]["s1u_address"]
Daniele Moro80889562021-09-08 10:09:26 +020083 self.emulated_ues = main.params["UP4"]['ues']
Daniele Morobef0c7e2022-02-16 17:47:13 -080084 self.app_filters = main.params["UP4"]['app_filters']
Daniele Moro80889562021-09-08 10:09:26 +020085 self.up4_client = p4rt_client
Daniele Moro522023c2021-10-15 17:30:33 +020086 self.no_host = no_host
Daniele Moro80889562021-09-08 10:09:26 +020087
88 # Optional Parameters
Daniele Moro522023c2021-10-15 17:30:33 +020089
90 self.enodebs = copy.deepcopy((main.params["UP4"]["enodebs"]))
91 for enb in self.enodebs.values():
92 enb["ues"] = enb["ues"].split(",")
93 enb["host"] = getattr(main, enb["host"])
94 # If interface not provided by the params, use the default in the host
95 if "interface" not in enb.keys():
96 enb["interface"] = enb["host"].interfaces[0]["name"]
97 if "pdn_host" in main.params["UP4"]:
98 self.pdn_host = getattr(main, main.params["UP4"]["pdn_host"])
99 self.pdn_interface = self.pdn_host.interfaces[0]
100 self.router_mac = main.params["UP4"].get("router_mac", None)
Daniele Moro80889562021-09-08 10:09:26 +0200101
102 # Start components
103 self.up4_client.startP4RtClient()
Daniele Moro522023c2021-10-15 17:30:33 +0200104 if not self.no_host:
105 if self.enodebs is not None:
106 for enb in self.enodebs.values():
107 enb["host"].startScapy(ifaceName=enb["interface"],
Daniele Moro49a843c2022-01-05 14:36:32 +0100108 enableGtp=True)
Daniele Moro522023c2021-10-15 17:30:33 +0200109 if self.pdn_host is not None:
110 self.pdn_host.startScapy(ifaceName=self.pdn_interface["name"])
Daniele Moro80889562021-09-08 10:09:26 +0200111
112 def teardown(self):
113 self.up4_client.stopP4RtClient()
Daniele Moro522023c2021-10-15 17:30:33 +0200114 if not self.no_host:
115 if self.enodebs is not None:
116 for enb in self.enodebs.values():
117 enb["host"].stopScapy()
118 if self.pdn_host is not None:
119 self.pdn_host.stopScapy()
Daniele Moro80889562021-09-08 10:09:26 +0200120
121 def attachUes(self):
Daniele Morobef0c7e2022-02-16 17:47:13 -0800122 for app_filter in self.app_filters.values():
123 self.insertAppFilter(**app_filter)
Daniele Moro522023c2021-10-15 17:30:33 +0200124 for (name, ue) in self.emulated_ues.items():
Daniele Moro80889562021-09-08 10:09:26 +0200125 ue = UP4.__sanitizeUeData(ue)
Daniele Moro522023c2021-10-15 17:30:33 +0200126 self.attachUe(name, **ue)
Daniele Moro80889562021-09-08 10:09:26 +0200127
128 def detachUes(self):
Daniele Morobef0c7e2022-02-16 17:47:13 -0800129 for app_filter in self.app_filters.values():
130 self.removeAppFilter(**app_filter)
Daniele Moro522023c2021-10-15 17:30:33 +0200131 for (name, ue) in self.emulated_ues.items():
Daniele Moro249d6e72021-09-20 10:32:54 +0200132 ue = UP4.__sanitizeUeData(ue)
Daniele Moro522023c2021-10-15 17:30:33 +0200133 self.detachUe(name, **ue)
Daniele Moro80889562021-09-08 10:09:26 +0200134
Daniele Morobef0c7e2022-02-16 17:47:13 -0800135 def __pickPortFromRange(self, range):
136 if range is None or len(range) == 0:
137 return DEFAULT_PDN_PORT
138 # First port in range
139 return int(range.split('..')[0])
140
141 def testUpstreamTraffic(self, enb_names=None, app_filter_name=None, shouldFail=False):
Daniele Moro522023c2021-10-15 17:30:33 +0200142 if self.enodebs is None or self.pdn_host is None:
Daniele Moro80889562021-09-08 10:09:26 +0200143 main.log.error(
144 "Need eNodeB and PDN host params to generate scapy traffic")
145 return
Daniele Moro522023c2021-10-15 17:30:33 +0200146 if enb_names is None or enb_names == []:
147 enodebs = self.enodebs.values()
148 else:
149 enodebs = [self.enodebs[enb] for enb in enb_names]
Daniele Morobef0c7e2022-02-16 17:47:13 -0800150
151 app_filter = self.app_filters[app_filter_name]
152 pdn_port = self.__pickPortFromRange(app_filter.get("port_range", None))
153 app_filter_should_drop = app_filter["action"] != "allow"
154
Daniele Moro80889562021-09-08 10:09:26 +0200155 pkt_filter_upstream = ""
Daniele Moro522023c2021-10-15 17:30:33 +0200156 ues = []
157 for enb in enodebs:
158 for ue_name in enb["ues"]:
159 ue = self.emulated_ues[ue_name]
160 if "ue_address" in ue:
161 ues.append(ue)
162 if len(pkt_filter_upstream) != 0:
163 pkt_filter_upstream += " or "
164 pkt_filter_upstream += "src host " + ue["ue_address"]
Daniele Moro80889562021-09-08 10:09:26 +0200165 pkt_filter_upstream = "ip and udp dst port %s and (%s) and dst host %s" % \
Daniele Morobef0c7e2022-02-16 17:47:13 -0800166 (pdn_port, pkt_filter_upstream,
Daniele Moro80889562021-09-08 10:09:26 +0200167 self.pdn_interface["ips"][0])
168 main.log.info("Start listening on %s intf %s" %
169 (self.pdn_host.name, self.pdn_interface["name"]))
170 main.log.debug("BPF Filter Upstream: \n %s" % pkt_filter_upstream)
171 self.pdn_host.startFilter(ifaceName=self.pdn_interface["name"],
Daniele Moro522023c2021-10-15 17:30:33 +0200172 sniffCount=len(ues),
Daniele Moro80889562021-09-08 10:09:26 +0200173 pktFilter=pkt_filter_upstream)
174
175 main.log.info(
Daniele Moro522023c2021-10-15 17:30:33 +0200176 "Sending %d packets from eNodeB host" % len(ues))
177 for enb in enodebs:
178 for ue_name in enb["ues"]:
179 main.log.info(ue_name)
180 ue = self.emulated_ues[ue_name]
181 main.log.info(str(ue))
182 UP4.buildGtpPacket(enb["host"],
183 src_ip_outer=enb["enb_address"],
184 dst_ip_outer=self.s1u_address,
185 src_ip_inner=ue["ue_address"],
186 dst_ip_inner=self.pdn_interface["ips"][0],
187 src_udp_inner=UE_PORT,
Daniele Morobef0c7e2022-02-16 17:47:13 -0800188 dst_udp_inner=pdn_port,
Daniele Moro522023c2021-10-15 17:30:33 +0200189 teid=int(ue["teid"]))
190 enb["host"].sendPacket(iface=enb["interface"])
Daniele Moro80889562021-09-08 10:09:26 +0200191
Daniele Morobf53dec2021-09-13 18:11:56 +0200192 packets = UP4.checkFilterAndGetPackets(self.pdn_host)
Daniele Morobef0c7e2022-02-16 17:47:13 -0800193 if app_filter_should_drop:
194 expected_pkt_count = 0
195 else:
196 # We expect exactly 1 packet per UE.
197 expected_pkt_count = len(ues)
198 actual_pkt_count = packets.count('Ether')
Daniele Moro80889562021-09-08 10:09:26 +0200199 fail = False
Daniele Morobef0c7e2022-02-16 17:47:13 -0800200 if expected_pkt_count != actual_pkt_count:
Daniele Moro80889562021-09-08 10:09:26 +0200201 fail = True
Daniele Morobef0c7e2022-02-16 17:47:13 -0800202 msg = "Received %d packets (expected %d)\n%s\n" % (
203 actual_pkt_count, expected_pkt_count, str(packets)
204 )
Daniele Moro80889562021-09-08 10:09:26 +0200205 else:
Daniele Morobef0c7e2022-02-16 17:47:13 -0800206 msg = "Received %d packets (expected %d)\n" % (
207 actual_pkt_count, expected_pkt_count
208 )
Daniele Moro80889562021-09-08 10:09:26 +0200209
Daniele Morobef0c7e2022-02-16 17:47:13 -0800210 if expected_pkt_count > 0:
211 # Make sure the captured packets are from the expected UE addresses.
212 for ue in ues:
213 ue_pkt_count = packets.count("src=" + ue["ue_address"])
214 if ue_pkt_count != 1:
215 fail = True
216 msg += "Received %d packet(s) from UE %s (expected 1)\n" % (
217 ue_pkt_count, ue["ue_address"]
218 )
Daniele Moro80889562021-09-08 10:09:26 +0200219 utilities.assert_equal(
Daniele Morobef0c7e2022-02-16 17:47:13 -0800220 expect=shouldFail, actual=fail, onpass=msg, onfail=msg
221 )
Daniele Moro80889562021-09-08 10:09:26 +0200222
Daniele Morobef0c7e2022-02-16 17:47:13 -0800223 def testDownstreamTraffic(self, enb_names=None, app_filter_name=None, shouldFail=False):
Daniele Moro522023c2021-10-15 17:30:33 +0200224 if self.enodebs is None or self.pdn_host is None:
Daniele Moro80889562021-09-08 10:09:26 +0200225 main.log.error(
226 "Need eNodeB and PDN host params to generate scapy traffic")
227 return
Daniele Moro522023c2021-10-15 17:30:33 +0200228 if enb_names is None or enb_names == []:
229 enodebs = self.enodebs.values()
230 else:
231 enodebs = [self.enodebs[enb] for enb in enb_names]
Daniele Morobef0c7e2022-02-16 17:47:13 -0800232
233 app_filter = self.app_filters[app_filter_name]
234 pdn_port = self.__pickPortFromRange(app_filter.get("port_range", None))
235 app_filter_should_drop = app_filter["action"] != "allow"
236
Daniele Moro522023c2021-10-15 17:30:33 +0200237 pkt_filter_downstream = "ip and udp src port %d and udp dst port %d and src host %s" % (
238 GPDU_PORT, GPDU_PORT, self.s1u_address)
239 ues = []
240 for enb in enodebs:
Daniele Moro49a843c2022-01-05 14:36:32 +0100241 filter_down = pkt_filter_downstream + " and dst host %s" % enb[
242 "enb_address"]
Daniele Moro522023c2021-10-15 17:30:33 +0200243 main.log.info("Start listening on %s intf %s" % (
244 enb["host"], enb["interface"]))
245 main.log.debug("BPF Filter Downstream: \n %s" % filter_down)
246 enb["host"].startFilter(ifaceName=enb["interface"],
247 sniffCount=len(enb["ues"]),
248 pktFilter=filter_down)
249 ues.extend([self.emulated_ues[ue_name] for ue_name in enb["ues"]])
Daniele Moro80889562021-09-08 10:09:26 +0200250
251 main.log.info(
Daniele Moro522023c2021-10-15 17:30:33 +0200252 "Sending %d packets from PDN host" % len(ues))
253 for ue in ues:
Daniele Moro80889562021-09-08 10:09:26 +0200254 # From PDN we have to set dest MAC, otherwise scapy will do ARP
255 # request for the UE IP address.
Daniele Morobf53dec2021-09-13 18:11:56 +0200256 UP4.buildUdpPacket(self.pdn_host,
257 dst_eth=self.router_mac,
258 src_ip=self.pdn_interface["ips"][0],
259 dst_ip=ue["ue_address"],
Daniele Morobef0c7e2022-02-16 17:47:13 -0800260 src_udp=pdn_port,
Daniele Morobf53dec2021-09-13 18:11:56 +0200261 dst_udp=UE_PORT)
Daniele Moro80889562021-09-08 10:09:26 +0200262 self.pdn_host.sendPacket(iface=self.pdn_interface["name"])
Daniele Moro522023c2021-10-15 17:30:33 +0200263 packets = ""
264 for enb in enodebs:
265 pkt = UP4.checkFilterAndGetPackets(enb["host"])
266 packets += pkt
Daniele Moro80889562021-09-08 10:09:26 +0200267 # The BPF filter might capture non-GTP packets because we can't filter
268 # GTP header in BPF. For this reason, check that the captured packets
269 # are from the expected tunnels.
Daniele Morobef0c7e2022-02-16 17:47:13 -0800270 # TODO: check inner IP fields as well
Daniele Moro80889562021-09-08 10:09:26 +0200271 # FIXME: with newer scapy TEID becomes teid (required for Scapy 2.4.5)
Daniele Morobef0c7e2022-02-16 17:47:13 -0800272 downlink_teids = [int(ue["teid"]) + 1 for ue in ues]
273 # Number of GTP packets from expected TEID per UEs
274 gtp_pkts = [
275 packets.count("TEID=" + hex(teid) + "L ") for teid in downlink_teids
276 ]
277 # Number of packets from the expected PDN port
278 app_pkts = packets.count("UDP sport=" + str(pdn_port))
279 if app_filter_should_drop:
280 expected_pkt_count = 0
281 else:
282 # We expect exactly 1 packet per UE.
283 expected_pkt_count = len(ues)
284
Daniele Moro80889562021-09-08 10:09:26 +0200285 fail = False
Daniele Morobef0c7e2022-02-16 17:47:13 -0800286 if expected_pkt_count != sum(gtp_pkts):
Daniele Moro80889562021-09-08 10:09:26 +0200287 fail = True
Daniele Morobef0c7e2022-02-16 17:47:13 -0800288 msg = "Received %d packets (expected %d) from TEIDs %s\n%s\n" % (
289 sum(gtp_pkts), expected_pkt_count, downlink_teids, str(packets)
290 )
Daniele Moro80889562021-09-08 10:09:26 +0200291 else:
Daniele Morobef0c7e2022-02-16 17:47:13 -0800292 msg = "Received %d packets (expected %d) from TEIDs %s\n" % (
293 sum(gtp_pkts), expected_pkt_count, downlink_teids
294 )
295 if expected_pkt_count != app_pkts:
Daniele Moro80889562021-09-08 10:09:26 +0200296 fail = True
Daniele Morobef0c7e2022-02-16 17:47:13 -0800297 msg += "Received %d packets (expected %d) from PDN port %s\n%s\n" % (
298 sum(gtp_pkts), expected_pkt_count, pdn_port, str(packets)
299 )
Daniele Moro80889562021-09-08 10:09:26 +0200300 else:
Daniele Morobef0c7e2022-02-16 17:47:13 -0800301 msg += "Received %d packets (expected %d) from PDN port %s\n" % (
302 sum(gtp_pkts), expected_pkt_count, pdn_port
303 )
304 if expected_pkt_count > 0:
305 if gtp_pkts.count(1) != len(gtp_pkts):
306 fail = True
307 msg += "Received %s packet(s) per UE (expected %s)\n%s\n" % (
308 gtp_pkts, [1] * len(gtp_pkts), packets
309 )
310 else:
311 msg += "Received %s packet(s) per UE (expected %s)\n" % (
312 gtp_pkts, [1] * len(gtp_pkts)
313 )
Daniele Moro80889562021-09-08 10:09:26 +0200314
315 utilities.assert_equal(
Daniele Morobef0c7e2022-02-16 17:47:13 -0800316 expect=shouldFail, actual=fail, onpass=msg, onfail=msg
317 )
Daniele Moro80889562021-09-08 10:09:26 +0200318
Daniele Moro49a843c2022-01-05 14:36:32 +0100319 def readUeSessionsNumber(self):
Daniele Moro954e2282021-09-22 17:32:03 +0200320 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100321 Read the UE session tables and return the number of entries
Daniele Moro954e2282021-09-22 17:32:03 +0200322
Daniele Moro49a843c2022-01-05 14:36:32 +0100323 :return: Number of entries in the UE session tables
Daniele Moro954e2282021-09-22 17:32:03 +0200324 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100325 tableName = 'PreQosPipe.sessions_uplink'
326 nUeSess = self.up4_client.readNumberTableEntries(tableName)
327 tableName = 'PreQosPipe.sessions_downlink'
328 nUeSess += self.up4_client.readNumberTableEntries(tableName)
329 return nUeSess
Daniele Moro954e2282021-09-22 17:32:03 +0200330
Daniele Moro49a843c2022-01-05 14:36:32 +0100331 def readTerminationsNumber(self):
Daniele Moro954e2282021-09-22 17:32:03 +0200332 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100333 Read the terminations and return the number of entities
Daniele Moro954e2282021-09-22 17:32:03 +0200334
Daniele Moro49a843c2022-01-05 14:36:32 +0100335 :return: Number of terminations entities
Daniele Moro954e2282021-09-22 17:32:03 +0200336 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100337 tableName = 'PreQosPipe.terminations_uplink'
338 nTerm = self.up4_client.readNumberTableEntries(tableName)
339 tableName = 'PreQosPipe.terminations_downlink'
340 nTerm += self.up4_client.readNumberTableEntries(tableName)
341 return nTerm
Daniele Moro954e2282021-09-22 17:32:03 +0200342
343 def verifyUesFlowNumberP4rt(self):
344 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100345 Verify via P4RT CLI that the number of UE sessions and terminations
346 is the expected one
Daniele Moro954e2282021-09-22 17:32:03 +0200347
Daniele Moro49a843c2022-01-05 14:36:32 +0100348 :return: True if the number of UE sessions and terminations is expected,
349 False otherwise
Daniele Moro954e2282021-09-22 17:32:03 +0200350 """
Daniele Morobef0c7e2022-02-16 17:47:13 -0800351 return self.readUeSessionsNumber() == len(self.emulated_ues) * 2 and \
352 self.readTerminationsNumber() == len(self.emulated_ues) * 2 * len(self.app_filters)
Daniele Moro954e2282021-09-22 17:32:03 +0200353
354 def verifyNoUesFlowNumberP4rt(self, preInstalledUes=0):
355 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100356 Verify via P4RT CLI that there is no UE sessions and terminations installed.
Daniele Moro954e2282021-09-22 17:32:03 +0200357
Daniele Moro49a843c2022-01-05 14:36:32 +0100358 :param preInstalledUes: Number of UEs whose UE sessions and terminations
359 are still programmed
Daniele Moro954e2282021-09-22 17:32:03 +0200360 :return:
361 """
Daniele Morobef0c7e2022-02-16 17:47:13 -0800362 return self.readUeSessionsNumber() == preInstalledUes * 2 and \
363 self.readTerminationsNumber() == preInstalledUes * 2 * len(self.app_filters)
Daniele Moro954e2282021-09-22 17:32:03 +0200364
Daniele Moro6dfbfef2021-09-28 22:44:19 +0200365 def verifyNoUesFlow(self, onosCli, retries=10):
Daniele Morobf53dec2021-09-13 18:11:56 +0200366 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100367 Verify that no UE session, terminations are installed in ONOS.
Daniele Morobf53dec2021-09-13 18:11:56 +0200368
369 :param onosCli: An instance of a OnosCliDriver
370 :param retries: number of retries
371 :return:
372 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100373 retValue = utilities.retry(f=UP4.__verifyNoUeSessionAndTerminationOnos,
Daniele Morobf53dec2021-09-13 18:11:56 +0200374 retValue=False,
375 args=[onosCli],
Daniele Moro6dfbfef2021-09-28 22:44:19 +0200376 sleep=5,
Daniele Morobf53dec2021-09-13 18:11:56 +0200377 attempts=retries)
378 utilities.assert_equal(expect=True,
379 actual=retValue,
Daniele Moro49a843c2022-01-05 14:36:32 +0100380 onpass="No UE session and terminations in ONOS",
381 onfail="Stale UE session or terminations")
Daniele Morobf53dec2021-09-13 18:11:56 +0200382
383 @staticmethod
Daniele Moro49a843c2022-01-05 14:36:32 +0100384 def __verifyNoUeSessionAndTerminationOnos(onosCli):
Daniele Morobf53dec2021-09-13 18:11:56 +0200385 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100386 Verify that no UE session, terminations are installed in ONOS
Daniele Morobf53dec2021-09-13 18:11:56 +0200387
388 :param onosCli: An instance of a OnosCliDriver
389 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100390 sessions = onosCli.sendline(cmdStr="up4:read-entities -s",
391 showResponse=True,
392 noExit=True, expectJson=False)
393 terminations = onosCli.sendline(cmdStr="up4:read-entities -t",
394 showResponse=True,
395 noExit=True, expectJson=False)
396 return sessions == "" and terminations == ""
Daniele Morobf53dec2021-09-13 18:11:56 +0200397
Daniele Moroc6811a82021-10-12 11:29:41 +0200398 def verifyUp4Flow(self, onosCli, retries=10):
Daniele Morobf53dec2021-09-13 18:11:56 +0200399 """
Daniele Moro49a843c2022-01-05 14:36:32 +0100400 Verify UE session, terminations and GTP tunnel peers installed via UP4
401 using the ONOS CLI.
Daniele Morobf53dec2021-09-13 18:11:56 +0200402
403 :param onosCli: An instance of a OnosCliDriver
Daniele Moroc6811a82021-10-12 11:29:41 +0200404 :param retries: Number of retries
Daniele Morobf53dec2021-09-13 18:11:56 +0200405 """
Daniele Morobef0c7e2022-02-16 17:47:13 -0800406 failString = []
Daniele Moroc6811a82021-10-12 11:29:41 +0200407 retValue = utilities.retry(f=self.__internalVerifyUp4Flow,
408 retValue=False,
409 args=[onosCli, failString],
410 sleep=5,
411 attempts=retries)
412 utilities.assert_equal(
413 expect=True,
414 actual=retValue,
Daniele Moro49a843c2022-01-05 14:36:32 +0100415 onpass="Correct UE session, terminations and GTP tunnel peers in ONOS",
416 onfail="Wrong UE session, terminations and GTP tunnel peers in ONOS. " +
Daniele Morobef0c7e2022-02-16 17:47:13 -0800417 "Missing:\n" + '\n'.join(failString)
Daniele Moroc6811a82021-10-12 11:29:41 +0200418 )
419
Daniele Morobef0c7e2022-02-16 17:47:13 -0800420 def __internalVerifyUp4Flow(self, onosCli, failMsg=[]):
421 # Need to pass a list, so it's an object and we can use failMsg to
422 # return a string values from this method.
423
424 # Cleanup failMsg if any remaining from previous runs
425 del failMsg[:]
426 applications = onosCli.sendline(cmdStr="up4:read-entities -f",
427 showResponse=True,
428 noExit=True, expectJson=False)
Daniele Moro49a843c2022-01-05 14:36:32 +0100429 sessions = onosCli.sendline(cmdStr="up4:read-entities -s",
430 showResponse=True,
431 noExit=True, expectJson=False)
432 terminations = onosCli.sendline(cmdStr="up4:read-entities -t",
433 showResponse=True,
434 noExit=True, expectJson=False)
435 tunn_peer = onosCli.sendline(cmdStr="up4:read-entities -g",
436 showResponse=True,
437 noExit=True, expectJson=False)
Daniele Morobf53dec2021-09-13 18:11:56 +0200438 fail = False
Daniele Morobef0c7e2022-02-16 17:47:13 -0800439 for app_filter in self.app_filters.values():
440 if not UP4.__defaultApp(**app_filter):
441 if applications.count(self.appFilterOnosString(**app_filter)) != 1:
442 failMsg.append(self.appFilterOnosString(**app_filter))
443 fail = True
Daniele Moro522023c2021-10-15 17:30:33 +0200444 for (ue_name, ue) in self.emulated_ues.items():
Daniele Moro49a843c2022-01-05 14:36:32 +0100445 if sessions.count(self.upUeSessionOnosString(**ue)) != 1:
Daniele Morobef0c7e2022-02-16 17:47:13 -0800446 failMsg.append(self.upUeSessionOnosString(**ue))
Daniele Morobf53dec2021-09-13 18:11:56 +0200447 fail = True
Daniele Moro49a843c2022-01-05 14:36:32 +0100448 if sessions.count(self.downUeSessionOnosString(**ue)) != 1:
Daniele Morobef0c7e2022-02-16 17:47:13 -0800449 failMsg.append(self.downUeSessionOnosString(**ue))
Daniele Morobf53dec2021-09-13 18:11:56 +0200450 fail = True
Daniele Morobef0c7e2022-02-16 17:47:13 -0800451 for app_filter in self.app_filters.values():
452 if terminations.count(self.upTerminationOnosString(app_filter=app_filter, **ue)) != 1:
453 failMsg.append(self.upTerminationOnosString(app_filter=app_filter, **ue))
454 fail = True
455 if terminations.count(self.downTerminationOnosString(app_filter=app_filter, **ue)) != 1:
456 failMsg.append(self.downTerminationOnosString(app_filter=app_filter, **ue))
457 fail = True
Daniele Moro49a843c2022-01-05 14:36:32 +0100458 if tunn_peer.count(self.gtpTunnelPeerOnosString(ue_name, **ue)) != 1:
Daniele Morobef0c7e2022-02-16 17:47:13 -0800459 failMsg.append(self.gtpTunnelPeerOnosString(ue_name, **ue))
Daniele Morobf53dec2021-09-13 18:11:56 +0200460 fail = True
Daniele Moroc6811a82021-10-12 11:29:41 +0200461 return not fail
Daniele Morobf53dec2021-09-13 18:11:56 +0200462
Daniele Morobef0c7e2022-02-16 17:47:13 -0800463 def appFilterOnosString(self, app_id, priority, ip_proto, ip_prefix, port_range, **kwargs):
464 return "UpfApplication(priority=%s, Match(%s%s%s%s) -> Action(app_id=%s))" % (
465 priority,
466 ("ip_prefix=%s, " % ip_prefix) if ip_prefix else "",
467 ("l4_port_range=[%s], " % port_range) if port_range else "",
468 ("ip_proto=%s, " % ip_proto) if ip_proto else "",
469 "slice_id=0",
470 app_id
471 )
472
Daniele Moro4650ffb2022-02-15 22:44:18 +0100473 def upUeSessionOnosString(self, teid=None, teid_up=None, sess_meter_idx=DEFAULT_SESSION_METER_IDX, **kwargs):
Daniele Morobf53dec2021-09-13 18:11:56 +0200474 if teid is not None:
475 teid_up = teid
Daniele Moro4650ffb2022-02-15 22:44:18 +0100476 return "UpfSessionUL(Match(tun_dst_addr={}, teid={}) -> Action(FWD, session_meter_idx={}))".format(
477 self.s1u_address, teid_up, sess_meter_idx)
Daniele Morobf53dec2021-09-13 18:11:56 +0200478
Daniele Moro49a843c2022-01-05 14:36:32 +0100479 def downUeSessionOnosString(self, ue_address, down_id=None,
Daniele Morobef0c7e2022-02-16 17:47:13 -0800480 tunn_peer_id=None, sess_meter_idx=DEFAULT_SESSION_METER_IDX,
Daniele Moro49a843c2022-01-05 14:36:32 +0100481 **kwargs):
Daniele Morobf53dec2021-09-13 18:11:56 +0200482 if down_id is not None:
Daniele Moro49a843c2022-01-05 14:36:32 +0100483 tunn_peer_id = down_id
Daniele Moro4650ffb2022-02-15 22:44:18 +0100484 return "UpfSessionDL(Match(ue_addr={}) -> Action(FWD, tun_peer={}, session_meter_idx={}))".format(
485 ue_address, tunn_peer_id, sess_meter_idx)
Daniele Moro49a843c2022-01-05 14:36:32 +0100486
Daniele Morobef0c7e2022-02-16 17:47:13 -0800487 def upTerminationOnosString(self, ue_address, app_filter, up_id=None,
Daniele Moro4650ffb2022-02-15 22:44:18 +0100488 ctr_id_up=None, tc=None, app_meter_idx=DEFAULT_APP_METER_IDX, **kwargs):
Daniele Moro49a843c2022-01-05 14:36:32 +0100489 if up_id is not None:
490 ctr_id_up = up_id
Daniele Morobef0c7e2022-02-16 17:47:13 -0800491 if app_filter["action"] == "allow":
492 return "UpfTerminationUL(Match(ue_addr={}, app_id={}) -> Action(FWD, ctr_id={}, tc={}, app_meter_idx={}))".format(
493 ue_address, app_filter["app_id"], ctr_id_up, tc, app_meter_idx)
494 else:
495 return "UpfTerminationUL(Match(ue_addr={}, app_id={}) -> Action(DROP, ctr_id={}, tc=null, app_meter_idx=0))".format(
496 ue_address, app_filter["app_id"], ctr_id_up)
Daniele Moro49a843c2022-01-05 14:36:32 +0100497
Daniele Morobef0c7e2022-02-16 17:47:13 -0800498 def downTerminationOnosString(self, ue_address, app_filter, teid=None,
Daniele Moro1f7ca6f2022-01-27 11:58:50 +0100499 down_id=None, ctr_id_down=None, teid_down=None,
Daniele Moro4650ffb2022-02-15 22:44:18 +0100500 tc=None, app_meter_idx=DEFAULT_APP_METER_IDX,
501 **kwargs):
Daniele Moro49a843c2022-01-05 14:36:32 +0100502 if down_id is not None:
Daniele Morobf53dec2021-09-13 18:11:56 +0200503 ctr_id_down = down_id
Daniele Morobf53dec2021-09-13 18:11:56 +0200504 if teid is not None:
Daniele Morobef0c7e2022-02-16 17:47:13 -0800505 teid_down = int(teid) + 1
506 if tc is None:
507 tc="null"
508 if app_filter["action"] == "allow":
509 return "UpfTerminationDL(Match(ue_addr={}, app_id={}) -> Action(FWD, teid={}, ctr_id={}, qfi={}, tc={}, app_meter_idx={}))".format(
510 ue_address, app_filter["app_id"], teid_down, ctr_id_down, tc, tc, app_meter_idx)
511 else:
512 return "UpfTerminationDL(Match(ue_addr={}, app_id={}) -> Action(DROP, teid=null, ctr_id={}, qfi=null, tc=null, app_meter_idx=0))".format(
513 ue_address, app_filter["app_id"], ctr_id_down)
Daniele Morobf53dec2021-09-13 18:11:56 +0200514
Daniele Moro49a843c2022-01-05 14:36:32 +0100515 def gtpTunnelPeerOnosString(self, ue_name, down_id=None, tunn_peer_id=None,
516 **kwargs):
517 if down_id is not None:
518 tunn_peer_id = down_id
519 enb_address = self.__getEnbAddress(ue_name)
Daniele Moro1f7ca6f2022-01-27 11:58:50 +0100520 return "UpfGtpTunnelPeer(tunn_peer_id={} -> src={}, dst={} src_port={})".format(
Daniele Moro49a843c2022-01-05 14:36:32 +0100521 tunn_peer_id, self.s1u_address, enb_address, GPDU_PORT)
Daniele Morobf53dec2021-09-13 18:11:56 +0200522
Daniele Moro80889562021-09-08 10:09:26 +0200523 @staticmethod
524 def __sanitizeUeData(ue):
Daniele Moro249d6e72021-09-20 10:32:54 +0200525 if "five_g" in ue and type(ue["five_g"]) != bool:
Daniele Moro80889562021-09-08 10:09:26 +0200526 ue["five_g"] = bool(strtobool(ue["five_g"]))
Carmelo Cascone848d1f52022-01-27 18:15:58 -0800527 if "tc" in ue and ue["tc"] == "":
528 ue["tc"] = 0
Daniele Moro80889562021-09-08 10:09:26 +0200529 return ue
530
Daniele Morobef0c7e2022-02-16 17:47:13 -0800531 def insertAppFilter(self, **kwargs):
532 if not UP4.__defaultApp(**kwargs):
533 self.__programAppFilter(op="program", **kwargs)
534
535 def removeAppFilter(self, **kwargs):
536 if not UP4.__defaultApp(**kwargs):
537 self.__programAppFilter(op="clear", **kwargs)
538
Daniele Moro49a843c2022-01-05 14:36:32 +0100539 def attachUe(self, ue_name, ue_address,
Daniele Moro80889562021-09-08 10:09:26 +0200540 teid=None, up_id=None, down_id=None,
541 teid_up=None, teid_down=None,
Daniele Moro49a843c2022-01-05 14:36:32 +0100542 ctr_id_up=None, ctr_id_down=None,
543 tunn_peer_id=None,
Carmelo Cascone848d1f52022-01-27 18:15:58 -0800544 tc=None, five_g=False):
Daniele Morobef0c7e2022-02-16 17:47:13 -0800545 self.__programUeRules(ue_name,
546 ue_address,
547 teid, up_id, down_id,
548 teid_up, teid_down,
549 ctr_id_up, ctr_id_down,
550 tunn_peer_id,
551 tc, five_g, op="program")
Daniele Moro80889562021-09-08 10:09:26 +0200552
Daniele Moro49a843c2022-01-05 14:36:32 +0100553 def detachUe(self, ue_name, ue_address,
Daniele Moro80889562021-09-08 10:09:26 +0200554 teid=None, up_id=None, down_id=None,
555 teid_up=None, teid_down=None,
Daniele Moro49a843c2022-01-05 14:36:32 +0100556 ctr_id_up=None, ctr_id_down=None,
557 tunn_peer_id=None,
Carmelo Cascone848d1f52022-01-27 18:15:58 -0800558 tc=None, five_g=False):
Daniele Morobef0c7e2022-02-16 17:47:13 -0800559 self.__programUeRules(ue_name,
560 ue_address,
561 teid, up_id, down_id,
562 teid_up, teid_down,
563 ctr_id_up, ctr_id_down,
564 tunn_peer_id,
565 tc, five_g, op="clear")
Daniele Moro80889562021-09-08 10:09:26 +0200566
Daniele Morobef0c7e2022-02-16 17:47:13 -0800567 def __programAppFilter(self, app_id, ip_prefix=None, ip_proto=None,
568 port_range=None, priority=0, op="program", **kwargs):
569
570 entries = []
571
572 tableName = 'PreQosPipe.applications'
573 actionName = 'PreQosPipe.set_app_id'
574 actionParams = {'app_id': str(app_id)}
575 matchFields = {}
576 if ip_prefix:
577 matchFields['app_ip_addr'] = str(ip_prefix)
578 if ip_proto:
579 matchFields['app_ip_proto'] = str(ip_proto)
580 if port_range:
581 matchFields['app_l4_port'] = str(port_range)
582
583 if not self.__add_entry(tableName, actionName, matchFields,
584 actionParams, entries, op, priority):
585 return False
586
587 if op == "program":
588 main.log.info("Application entry added successfully.")
589 elif op == "clear":
590 self.__clear_entries(entries)
591
592 def __programUeRules(self, ue_name, ue_address,
593 teid=None, up_id=None, down_id=None,
594 teid_up=None, teid_down=None, ctr_id_up=None,
595 ctr_id_down=None, tunn_peer_id=None,
596 tc=0, five_g=False,
597 op="program"):
Daniele Moro80889562021-09-08 10:09:26 +0200598 if up_id is not None:
Daniele Moro80889562021-09-08 10:09:26 +0200599 ctr_id_up = up_id
600 if down_id is not None:
Daniele Moro49a843c2022-01-05 14:36:32 +0100601 tunn_peer_id = down_id
Daniele Moro80889562021-09-08 10:09:26 +0200602 ctr_id_down = down_id
603 if teid is not None:
604 teid_up = teid
Daniele Morobef0c7e2022-02-16 17:47:13 -0800605 teid_down = int(teid) + 1
Daniele Moro80889562021-09-08 10:09:26 +0200606
607 entries = []
608
Daniele Moro522023c2021-10-15 17:30:33 +0200609 # Retrieve eNobeB address from eNodeB list
610 enb_address = self.__getEnbAddress(ue_name)
611
Daniele Moro80889562021-09-08 10:09:26 +0200612 # ========================#
Daniele Moro49a843c2022-01-05 14:36:32 +0100613 # UE Session Entries
Daniele Moro80889562021-09-08 10:09:26 +0200614 # ========================#
615
616 # Uplink
Daniele Moro49a843c2022-01-05 14:36:32 +0100617 tableName = 'PreQosPipe.sessions_uplink'
618 actionName = 'PreQosPipe.set_session_uplink'
Daniele Moro80889562021-09-08 10:09:26 +0200619 matchFields = {}
Daniele Morobef0c7e2022-02-16 17:47:13 -0800620 actionParams = {}
Daniele Moro80889562021-09-08 10:09:26 +0200621 # Match fields
Daniele Moro49a843c2022-01-05 14:36:32 +0100622 matchFields['n3_address'] = str(self.s1u_address)
Daniele Moro80889562021-09-08 10:09:26 +0200623 matchFields['teid'] = str(teid_up)
Daniele Moro4650ffb2022-02-15 22:44:18 +0100624 # Action params
625 actionParams["session_meter_idx"] = str(DEFAULT_SESSION_METER_IDX)
Daniele Moro49a843c2022-01-05 14:36:32 +0100626 if five_g:
627 # TODO: currently QFI match is unsupported in TNA
628 main.log.warn("Matching on QFI is currently unsupported in TNA")
Daniele Moro80889562021-09-08 10:09:26 +0200629 if not self.__add_entry(tableName, actionName, matchFields,
Daniele Morobef0c7e2022-02-16 17:47:13 -0800630 actionParams, entries, op):
Daniele Moro80889562021-09-08 10:09:26 +0200631 return False
632
633 # Downlink
Daniele Moro49a843c2022-01-05 14:36:32 +0100634 tableName = 'PreQosPipe.sessions_downlink'
635 actionName = 'PreQosPipe.set_session_downlink'
Daniele Moro80889562021-09-08 10:09:26 +0200636 matchFields = {}
637 actionParams = {}
Daniele Moro80889562021-09-08 10:09:26 +0200638 # Match fields
Daniele Moro49a843c2022-01-05 14:36:32 +0100639 matchFields['ue_address'] = str(ue_address)
Daniele Moro80889562021-09-08 10:09:26 +0200640 # Action params
Daniele Moro49a843c2022-01-05 14:36:32 +0100641 actionParams['tunnel_peer_id'] = str(tunn_peer_id)
Daniele Moro4650ffb2022-02-15 22:44:18 +0100642 actionParams["session_meter_idx"] = str(DEFAULT_SESSION_METER_IDX)
Daniele Moro80889562021-09-08 10:09:26 +0200643 if not self.__add_entry(tableName, actionName, matchFields,
Daniele Morobef0c7e2022-02-16 17:47:13 -0800644 actionParams, entries, op):
Daniele Moro80889562021-09-08 10:09:26 +0200645 return False
646
647 # ========================#
Daniele Moro49a843c2022-01-05 14:36:32 +0100648 # Terminations Entries
Daniele Moro80889562021-09-08 10:09:26 +0200649 # ========================#
650
Daniele Morobef0c7e2022-02-16 17:47:13 -0800651 # Insert one termination entry per app filtering rule,
Daniele Moro80889562021-09-08 10:09:26 +0200652
Daniele Morobef0c7e2022-02-16 17:47:13 -0800653 # Uplink
654 for f in self.app_filters.values():
655 tableName = 'PreQosPipe.terminations_uplink'
656 matchFields = {}
657 actionParams = {}
658
659 # Match fields
660 matchFields['ue_address'] = str(ue_address)
661 matchFields['app_id'] = str(f["app_id"])
662
663 # Action params
664 if f['action'] == 'allow':
665 actionName = 'PreQosPipe.uplink_term_fwd'
666 actionParams['app_meter_idx'] = str(DEFAULT_APP_METER_IDX)
667 actionParams['tc'] = str(tc)
668 else:
669 actionName = 'PreQosPipe.uplink_term_drop'
670 actionParams['ctr_idx'] = str(ctr_id_up)
671 if not self.__add_entry(
672 tableName, actionName, matchFields, actionParams, entries, op
673 ):
674 return False
Daniele Moro80889562021-09-08 10:09:26 +0200675
676 # Downlink
Daniele Morobef0c7e2022-02-16 17:47:13 -0800677 for f in self.app_filters.values():
678 tableName = 'PreQosPipe.terminations_downlink'
679 matchFields = {}
680 actionParams = {}
Daniele Moro80889562021-09-08 10:09:26 +0200681
Daniele Morobef0c7e2022-02-16 17:47:13 -0800682 # Match fields
683 matchFields['ue_address'] = str(ue_address)
684 matchFields['app_id'] = str(f["app_id"])
685
686 # Action params
687 if f['action'] == 'allow':
688 actionName = 'PreQosPipe.downlink_term_fwd'
689 actionParams['teid'] = str(teid_down)
690 # 1-1 mapping between QFI and TC
691 actionParams['tc'] = str(tc)
692 actionParams['qfi'] = str(tc)
693 actionParams['app_meter_idx'] = str(DEFAULT_APP_METER_IDX)
694 else:
695 actionName = 'PreQosPipe.downlink_term_drop'
696 actionParams['ctr_idx'] = str(ctr_id_down)
697
698 if not self.__add_entry(tableName, actionName, matchFields,
699 actionParams, entries, op):
700 return False
Daniele Moro49a843c2022-01-05 14:36:32 +0100701
702 # ========================#
703 # Tunnel Peer Entry
704 # ========================#
705 tableName = 'PreQosPipe.tunnel_peers'
706 actionName = 'PreQosPipe.load_tunnel_param'
707 matchFields = {}
708 actionParams = {}
709 # Match fields
710 matchFields['tunnel_peer_id'] = str(tunn_peer_id)
711 # Action params
Daniele Moro80889562021-09-08 10:09:26 +0200712 actionParams['src_addr'] = str(self.s1u_address)
Daniele Moro522023c2021-10-15 17:30:33 +0200713 actionParams['dst_addr'] = str(enb_address)
Daniele Moro80889562021-09-08 10:09:26 +0200714 actionParams['sport'] = TUNNEL_SPORT
715 if not self.__add_entry(tableName, actionName, matchFields,
Daniele Morobef0c7e2022-02-16 17:47:13 -0800716 actionParams, entries, op):
Daniele Moro80889562021-09-08 10:09:26 +0200717 return False
Daniele Morobef0c7e2022-02-16 17:47:13 -0800718 if op == "program":
Daniele Moro80889562021-09-08 10:09:26 +0200719 main.log.info("All entries added successfully.")
Daniele Morobef0c7e2022-02-16 17:47:13 -0800720 elif op == "clear":
Daniele Moro80889562021-09-08 10:09:26 +0200721 self.__clear_entries(entries)
722
723 def __add_entry(self, tableName, actionName, matchFields, actionParams,
Daniele Morobef0c7e2022-02-16 17:47:13 -0800724 entries, op, priority=0):
725 if op == "program":
Daniele Moro80889562021-09-08 10:09:26 +0200726 self.up4_client.buildP4RtTableEntry(
727 tableName=tableName, actionName=actionName,
Daniele Morobef0c7e2022-02-16 17:47:13 -0800728 actionParams=actionParams, matchFields=matchFields, priority=priority)
Daniele Moro80889562021-09-08 10:09:26 +0200729 if self.up4_client.pushTableEntry(debug=True) == main.TRUE:
730 main.log.info("*** Entry added.")
731 else:
732 main.log.error("Error during table insertion")
733 self.__clear_entries(entries)
734 return False
Daniele Morobef0c7e2022-02-16 17:47:13 -0800735 entries.append({
736 "tableName": tableName, "actionName": actionName,
737 "matchFields": matchFields,
738 "actionParams": actionParams,
739 "priority": priority
740 })
Daniele Moro80889562021-09-08 10:09:26 +0200741 return True
742
743 def __clear_entries(self, entries):
744 for i, entry in enumerate(entries):
745 self.up4_client.buildP4RtTableEntry(**entry)
746 if self.up4_client.deleteTableEntry(debug=True) == main.TRUE:
747 main.log.info(
748 "*** Entry %d of %d deleted." % (i + 1, len(entries)))
749 else:
750 main.log.error("Error during table delete")
Daniele Morobf53dec2021-09-13 18:11:56 +0200751
Daniele Moro522023c2021-10-15 17:30:33 +0200752 def __getEnbAddress(self, ue_name):
753 for enb in self.enodebs.values():
754 if ue_name in enb["ues"]:
755 return enb["enb_address"]
756 main.log.error("Missing eNodeB address!")
757 return ""
758
Daniele Morobf53dec2021-09-13 18:11:56 +0200759 @staticmethod
760 def buildGtpPacket(host, src_ip_outer, dst_ip_outer, src_ip_inner,
761 dst_ip_inner, src_udp_inner, dst_udp_inner, teid):
762 host.buildEther()
763 host.buildIP(src=src_ip_outer, dst=dst_ip_outer)
764 host.buildUDP(ipVersion=4, dport=GPDU_PORT)
765 # FIXME: With newer scapy TEID becomes teid (required for Scapy 2.4.5)
766 host.buildGTP(gtp_type=0xFF, TEID=teid)
767 host.buildIP(overGtp=True, src=src_ip_inner, dst=dst_ip_inner)
768 host.buildUDP(ipVersion=4, overGtp=True, sport=src_udp_inner,
769 dport=dst_udp_inner)
770
771 @staticmethod
772 def buildUdpPacket(host, src_ip, dst_ip, src_udp, dst_udp, src_eth=None,
773 dst_eth=None):
774 host.buildEther(src=src_eth, dst=dst_eth)
775 host.buildIP(src=src_ip, dst=dst_ip)
776 host.buildUDP(ipVersion=4, sport=src_udp, dport=dst_udp)
777
778 @staticmethod
779 def checkFilterAndGetPackets(host):
780 finished = host.checkFilter()
781 if finished:
782 packets = host.readPackets(detailed=True)
783 for p in packets.splitlines():
784 main.log.debug(p)
785 # We care only of the last line from readPackets
786 return packets.splitlines()[-1]
787 else:
788 kill = host.killFilter()
789 main.log.debug(kill)
790 return ""
Daniele Morobef0c7e2022-02-16 17:47:13 -0800791
792 @staticmethod
793 def __defaultApp(ip_prefix=None, ip_proto=None, port_range=None, **kwargs):
794 if ip_prefix is None and ip_proto is None and port_range is None:
795 return True
796 return False
797