[SDFAB-504] Add UP4 encap, decap test
Change-Id: Ic1cc30fd9c87d7c20e03f02171b62e92b7ff6e94
diff --git a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
new file mode 100644
index 0000000..a7f9804
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
@@ -0,0 +1,203 @@
+class UP4:
+
+ def __init__(self):
+ self.default = ''
+
+ # TODO: add test case that checks entries are being inserted and deleted from ONOS correclty
+ def CASE1(self, main):
+ """
+ Attach UE
+ Generate traffic from UE to PDN
+ Verify traffic received from PDN
+ Generate traffic from PDN to UE
+ Verify traffic received from UE
+ Detach UE
+ """
+ UE_PORT = 400
+ PDN_PORT = 800
+ GPDU_PORT = 2152
+ try:
+ from tests.USECASE.SegmentRouting.dependencies.up4libcli import \
+ Up4LibCli
+ from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+ Testcaselib as run
+ from distutils.util import strtobool
+ except ImportError as e:
+ main.log.error("Import not found. Exiting the test")
+ main.log.error(e)
+ main.cleanAndExit()
+
+ # TODO: Move to a setup script
+ run.initTest(main)
+ main.log.info(main.Cluster.numCtrls)
+ main.Cluster.setRunningNode(3)
+ run.installOnos(main, skipPackage=True, cliSleep=5)
+
+ # Get the P4RT client connected to UP4 in the first available ONOS instance
+ up4Client = main.Cluster.active(0).p4rtUp4
+
+ s1u_address = main.params["UP4"]["s1u_address"]
+ enb_address = main.params["UP4"]["enb_address"]
+ router_mac = main.params["UP4"]["router_mac"]
+
+ pdn_host = getattr(main, main.params["UP4"]["pdn_host"])
+ pdn_interface = pdn_host.interfaces[0]
+
+ enodeb_host = getattr(main, main.params["UP4"]["enodeb_host"])
+ enodeb_interface = enodeb_host.interfaces[0]
+
+ emulated_ues = main.params["UP4"]['ues']
+ n_ues = len(emulated_ues)
+
+ main.step("Start scapy and p4rt client")
+ pdn_host.startScapy(ifaceName=pdn_interface["name"])
+ enodeb_host.startScapy(ifaceName=enodeb_interface["name"],
+ enableGtp=True)
+ up4Client.startP4RtClient()
+
+ # TODO: move to library in dependencies
+ main.step("Attach UEs")
+ for ue in emulated_ues.values():
+ # Sanitize values coming from the params file
+ if "five_g" in ue:
+ ue["five_g"] = bool(strtobool(ue["five_g"]))
+ if "qfi" in ue and ue["qfi"] == "":
+ ue["qfi"] = None
+ Up4LibCli.attachUe(up4Client, s1u_address=s1u_address,
+ enb_address=enb_address,
+ **ue)
+
+ # ----------------- Test Upstream traffic (enb->pdn)
+ main.step("Test upstream traffic")
+ # Scapy filter needs to start before sending traffic
+ pkt_filter_upstream = ""
+ for ue in emulated_ues.values():
+ if "ue_address" in ue:
+ if len(pkt_filter_upstream) != 0:
+ pkt_filter_upstream += " or "
+ pkt_filter_upstream += "src host " + ue["ue_address"]
+ pkt_filter_upstream = "ip and udp dst port %s and (%s) and dst host %s" % \
+ (PDN_PORT, pkt_filter_upstream,
+ pdn_interface["ips"][0])
+ main.log.info("Start listening on %s intf %s" %
+ (main.params["UP4"]["pdn_host"], pdn_interface["name"]))
+ main.log.debug("BPF Filter Upstream: \n %s" % pkt_filter_upstream)
+ pdn_host.startFilter(ifaceName=pdn_interface["name"],
+ sniffCount=n_ues,
+ pktFilter=pkt_filter_upstream)
+
+ main.log.info("Sending %d packets from eNodeB host" % len(emulated_ues))
+ for ue in emulated_ues.values():
+ enodeb_host.buildEther()
+ enodeb_host.buildIP(src=enb_address, dst=s1u_address)
+ enodeb_host.buildUDP(ipVersion=4, dport=GPDU_PORT)
+ # FIXME: With newer scapy TEID becomes teid (required for Scapy 2.4.5)
+ enodeb_host.buildGTP(gtp_type=0xFF, TEID=int(ue["teid"]))
+ enodeb_host.buildIP(overGtp=True, src=ue["ue_address"],
+ dst=pdn_interface["ips"][0])
+ enodeb_host.buildUDP(ipVersion=4, overGtp=True, sport=UE_PORT,
+ dport=PDN_PORT)
+
+ enodeb_host.sendPacket(iface=enodeb_interface["name"])
+
+ finished = pdn_host.checkFilter()
+ packets = ""
+ if finished:
+ packets = pdn_host.readPackets(detailed=True)
+ for p in packets.splitlines():
+ main.log.debug(p)
+ # We care only of the last line from readPackets
+ packets = packets.splitlines()[-1]
+ else:
+ kill = pdn_host.killFilter()
+ main.log.debug(kill)
+
+ fail = False
+ if len(emulated_ues) != packets.count('Ether'):
+ fail = True
+ msg = "Failed to capture packets in PDN. "
+ else:
+ msg = "Correctly captured packet in PDN. "
+ # We expect exactly 1 packet per UE
+ pktsFiltered = [packets.count("src=" + ue["ue_address"])
+ for ue in emulated_ues.values()]
+ if pktsFiltered.count(1) != len(pktsFiltered):
+ fail = True
+ msg += "More than one packet per UE in downstream. "
+ else:
+ msg += "One packet per UE in upstream. "
+
+ utilities.assert_equal(
+ expect=False, actual=fail, onpass=msg, onfail=msg)
+
+ # --------------- Test Downstream traffic (pdn->enb)
+ main.step("Test downstream traffic")
+ pkt_filter_downstream = "ip and udp src port %d and udp dst port %d and dst host %s and src host %s" % (
+ GPDU_PORT, GPDU_PORT, enb_address, s1u_address)
+ main.log.info("Start listening on %s intf %s" % (
+ main.params["UP4"]["enodeb_host"], enodeb_interface["name"]))
+ main.log.debug("BPF Filter Downstream: \n %s" % pkt_filter_downstream)
+ enodeb_host.startFilter(ifaceName=enodeb_interface["name"],
+ sniffCount=len(emulated_ues),
+ pktFilter=pkt_filter_downstream)
+
+ main.log.info("Sending %d packets from PDN host" % len(emulated_ues))
+ for ue in emulated_ues.values():
+ # From PDN we have to set dest MAC, otherwise scapy will do ARP
+ # request for the UE IP address.
+ pdn_host.buildEther(dst=router_mac)
+ pdn_host.buildIP(src=pdn_interface["ips"][0],
+ dst=ue["ue_address"])
+ pdn_host.buildUDP(ipVersion=4, sport=PDN_PORT, dport=UE_PORT)
+ pdn_host.sendPacket(iface=pdn_interface["name"])
+
+ finished = enodeb_host.checkFilter()
+ packets = ""
+ if finished:
+ packets = enodeb_host.readPackets(detailed=True)
+ for p in packets.splitlines():
+ main.log.debug(p)
+ # We care only of the last line from readPackets
+ packets = packets.splitlines()[-1]
+ else:
+ kill = enodeb_host.killFilter()
+ main.log.debug(kill)
+
+ # The BPF filter might capture non-GTP packets because we can't filter
+ # GTP header in BPF. For this reason, check that the captured packets
+ # are from the expected tunnels.
+ # TODO: check inner UDP and IP fields as well
+ # FIXME: with newer scapy TEID becomes teid (required for Scapy 2.4.5)
+ pktsFiltered = [packets.count("TEID=" + hex(int(ue["teid"])) + "L ")
+ for ue in emulated_ues.values()]
+
+ fail = False
+ if len(emulated_ues) != sum(pktsFiltered):
+ fail = True
+ msg = "Failed to capture packets in eNodeB. "
+ else:
+ msg = "Correctly captured packets in eNodeB. "
+ # We expect exactly 1 packet per UE
+ if pktsFiltered.count(1) != len(pktsFiltered):
+ fail = True
+ msg += "More than one packet per GTP TEID in downstream. "
+ else:
+ msg += "One packet per GTP TEID in downstream. "
+
+ utilities.assert_equal(
+ expect=False, actual=fail, onpass=msg, onfail=msg)
+
+ # Detach UEs
+ main.step("Detach UEs")
+ for ue in emulated_ues.values():
+ # No need to sanitize values, already sanitized during attachment
+ Up4LibCli.detachUe(up4Client, s1u_address=s1u_address,
+ enb_address=enb_address,
+ **ue)
+
+ # Teardown
+ main.step("Stop scapy and p4rt client")
+ enodeb_host.stopScapy()
+ pdn_host.stopScapy()
+ up4Client.stopP4RtClient()
+ run.cleanup(main)