[SDFAB-506] Add QoS test for on edge ports with GTP encapped traffic

Also, create library to attach, detach UEs via UP4 and to generate Traffic via TRex.

Change-Id: I9cd7bedbc0f799813dd033220fcdffb5baf20eda
diff --git a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
index a7f9804..0dcbbd8 100644
--- a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
+++ b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
@@ -13,191 +13,39 @@
         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.up4 import UP4
             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()
+        up4 = UP4()
+        # Get the P4RT client connected to UP4 in the first available ONOS instance
+        up4.setup(main.Cluster.active(0).p4rtUp4)
 
-        # 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)
+        up4.attachUes()
 
-        # ----------------- Test Upstream traffic (enb->pdn)
+        # ------- 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)
+        up4.testUpstreamTraffic()
 
-        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)
+        # ------- 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)
+        up4.testDownstreamTraffic()
 
-        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)
+        up4.detachUes()
 
-        # Teardown
         main.step("Stop scapy and p4rt client")
-        enodeb_host.stopScapy()
-        pdn_host.stopScapy()
-        up4Client.stopP4RtClient()
+        up4.teardown()
         run.cleanup(main)