[SDFAB-493] UP4 data plane failure test
Change-Id: I25a7c728d1a6d068ac5f9bb02319e6c32623a6b0
diff --git a/TestON/tests/USECASE/SegmentRouting/QOS/QOS.params b/TestON/tests/USECASE/SegmentRouting/QOS/QOS.params
index e23f4ae..ceb29b6 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOS/QOS.params
+++ b/TestON/tests/USECASE/SegmentRouting/QOS/QOS.params
@@ -17,7 +17,14 @@
<UP4>
<s1u_address>10.32.11.126</s1u_address>
- <enb_address>10.32.11.124</enb_address>
+ <enodebs>
+ <enodeb_1>
+ <host>TRexClient</host>
+ <enb_address>10.32.11.124</enb_address>
+ <interface>pairbond</interface> <!-- useless for this test, we use TRex to generate traffic -->
+ <ues>ue1,ue2</ues>
+ </enodeb_1>
+ </enodebs>
<ues>
<ue1>
<pfcp_session_id>100</pfcp_session_id>
diff --git a/TestON/tests/USECASE/SegmentRouting/QOS/QOS.py b/TestON/tests/USECASE/SegmentRouting/QOS/QOS.py
index 37629da..2a851c4 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOS/QOS.py
+++ b/TestON/tests/USECASE/SegmentRouting/QOS/QOS.py
@@ -34,7 +34,7 @@
up4 = UP4()
trex = Trex()
# Get the P4RT client connected to UP4 in the first available ONOS instance
- up4.setup(main.Cluster.active(0).p4rtUp4)
+ up4.setup(main.Cluster.active(0).p4rtUp4, no_host=True)
trex.setup(main.TRexClient)
main.step("Program PDRs and FARs via UP4")
diff --git a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.params b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.params
index 5d1cf1d..7662f82 100644
--- a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.params
+++ b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.params
@@ -1,5 +1,5 @@
<PARAMS>
- <testcases>1,2,3,4</testcases>
+ <testcases>1,2,3,4,5</testcases>
<GRAPH>
<nodeCluster>pairedleaves</nodeCluster>
@@ -16,10 +16,21 @@
</kubernetes>
<UP4>
- <pdn_host>Compute1</pdn_host>
- <enodeb_host>Compute3</enodeb_host>
+ <pdn_host>MgmtServer</pdn_host>
+ <enodebs>
+ <enodeb_1>
+ <host>Compute3</host>
+ <enb_address>10.32.11.194</enb_address>
+ <ues>ue1,ue2</ues>
+ </enodeb_1>
+ <enodeb_2>
+ <host>Compute1</host>
+ <interface>eno3</interface>
+ <enb_address>10.32.11.122</enb_address>
+ <ues>ue3</ues>
+ </enodeb_2>
+ </enodebs>
<s1u_address>10.32.11.126</s1u_address>
- <enb_address>10.32.11.194</enb_address>
<router_mac>00:00:0A:4C:1C:46</router_mac>
<ues>
<ue1>
@@ -40,9 +51,28 @@
<qfi></qfi>
<five_g>False</five_g>
</ue2>
+ <ue3>
+ <pfcp_session_id>100</pfcp_session_id>
+ <ue_address>10.240.0.3</ue_address>
+ <teid>201</teid>
+ <up_id>30</up_id>
+ <down_id>31</down_id>
+ <qfi></qfi>
+ <five_g>False</five_g>
+ </ue3>
</ues>
+ <switch_to_kill>Leaf2</switch_to_kill> <!-- Component name of the switch to kill in CASE 5 -->
+ <enodebs_fail>enodeb_1</enodebs_fail> <!-- list of eNodeBs that should fail traffic forwarding in CASE 5-->
</UP4>
+ <!-- Parameters for UP4 CASE2 related to Emulated BESS UPF -->
+ <BESS_UPF>
+ <enodeb_host>Compute3</enodeb_host>
+ <enb_address>10.32.11.194</enb_address>
+ <ue_address>10.241.0.1</ue_address> <!-- different subnet than the one used for UP4 UEs -->
+ <bess_host>Compute2</bess_host>
+ </BESS_UPF>
+
<UP4_delete_pod>onos-tost-onos-classic-0</UP4_delete_pod>
<TOPO>
diff --git a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
index 99fbf4c..ef659fc 100644
--- a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
+++ b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
@@ -82,7 +82,6 @@
Verify removed PDRs and FARs
"""
BESS_TEID = 300
- BESS_UE_ADDR = "10.241.0.1"
GPDU_PORT = 2152
UE_PORT = 400
PDN_PORT = 800
@@ -111,12 +110,14 @@
up4.setup(main.Cluster.active(0).p4rtUp4)
# Setup the emulated BESS host and required parameters
- bess_host = main.Compute2 # FIXME: Parametrize?
+ bess_host = getattr(main, main.params["BESS_UPF"]["bess_host"])
bess_interface = bess_host.interfaces[0]
bess_s1u_address = bess_interface["ips"][0]
bess_host.startScapy(ifaceName=bess_interface["name"], enableGtp=True)
- enodeb_host = up4.enodeb_host
- enodeb_interface = up4.enodeb_interface
+ bess_ue_address = main.params["BESS_UPF"]["ue_address"]
+ enodeb_host = getattr(main, main.params["BESS_UPF"]["enodeb_host"])
+ enodeb_address = main.params["BESS_UPF"]["enb_address"]
+ enodeb_interface = enodeb_host.interfaces[0]["name"]
pdn_host = up4.pdn_host
pdn_interface = up4.pdn_interface
@@ -136,7 +137,7 @@
# Start filter before sending packets, BESS should receive GTP encapped
# packets
pkt_filter_upstream = "ip and udp src port %d and udp dst port %d and src host %s and dst host %s" % (
- GPDU_PORT, GPDU_PORT, up4.enb_address, bess_s1u_address)
+ GPDU_PORT, GPDU_PORT, enodeb_address, bess_s1u_address)
main.log.info("Start listening on %s intf %s" % (
bess_host.name, bess_interface["name"]))
main.log.debug("BPF Filter BESS Upstream: \n %s" % pkt_filter_upstream)
@@ -145,9 +146,9 @@
pktFilter=pkt_filter_upstream)
# Send GTP Packet
UP4.buildGtpPacket(enodeb_host,
- src_ip_outer=up4.enb_address,
+ src_ip_outer=enodeb_address,
dst_ip_outer=bess_s1u_address,
- src_ip_inner=BESS_UE_ADDR,
+ src_ip_inner=bess_ue_address,
dst_ip_inner=pdn_interface["ips"][0],
src_udp_inner=UE_PORT,
dst_udp_inner=PDN_PORT,
@@ -168,7 +169,7 @@
main.step("Test upstream BESS -> fabric -> PDN")
# Start filter before sending packets, PDN should receive non-GTP packet
pkt_filter_upstream = "ip and udp src port %d and udp dst port %d and src host %s and dst host %s" % (
- UE_PORT, PDN_PORT, BESS_UE_ADDR, pdn_interface["ips"][0])
+ UE_PORT, PDN_PORT, bess_ue_address, pdn_interface["ips"][0])
main.log.info("Start listening on %s intf %s" % (
pdn_host.name, pdn_interface["name"]))
main.log.debug("BPF Filter PDN Upstream: \n %s" % pkt_filter_upstream)
@@ -177,7 +178,7 @@
pktFilter=pkt_filter_upstream)
# Send UDP Packet
UP4.buildUdpPacket(bess_host,
- src_ip=BESS_UE_ADDR,
+ src_ip=bess_ue_address,
dst_ip=pdn_interface["ips"][0],
src_udp=UE_PORT,
dst_udp=PDN_PORT)
@@ -196,7 +197,7 @@
# ------- PDN -> fabric -> BESS (not-encapped)
main.step("Test downstream PDN -> fabric -> BESS")
pkt_filter_downstream = "ip and udp src port %d and udp dst port %d and src host %s and dst host %s" % (
- PDN_PORT, UE_PORT, pdn_interface["ips"][0], BESS_UE_ADDR)
+ PDN_PORT, UE_PORT, pdn_interface["ips"][0], bess_ue_address)
main.log.info("Start listening on %s intf %s" % (
bess_host.name, bess_interface["name"]))
main.log.debug(
@@ -207,7 +208,7 @@
UP4.buildUdpPacket(pdn_host,
dst_eth=up4.router_mac,
src_ip=pdn_interface["ips"][0],
- dst_ip=BESS_UE_ADDR,
+ dst_ip=bess_ue_address,
src_udp=PDN_PORT,
dst_udp=UE_PORT)
pdn_host.sendPacket()
@@ -224,20 +225,20 @@
# ------- BESS -> fabric -> eNB (encapped)
main.step("Test downstream BESS -> fabric -> eNB")
pkt_filter_downstream = "ip and udp src port %d and udp dst port %d and src host %s and dst host %s" % (
- GPDU_PORT, GPDU_PORT, bess_s1u_address, up4.enb_address)
+ GPDU_PORT, GPDU_PORT, bess_s1u_address, enodeb_address)
main.log.info("Start listening on %s intf %s" % (
- enodeb_host.name, enodeb_interface["name"]))
+ enodeb_host.name, enodeb_interface))
main.log.debug(
"BPF Filter BESS Downstream: \n %s" % pkt_filter_downstream)
- enodeb_host.startFilter(ifaceName=enodeb_interface["name"],
+ enodeb_host.startFilter(ifaceName=enodeb_interface,
sniffCount=1,
pktFilter=pkt_filter_downstream)
# Build GTP packet from BESS host
UP4.buildGtpPacket(bess_host,
src_ip_outer=bess_s1u_address,
- dst_ip_outer=up4.enb_address,
+ dst_ip_outer=enodeb_address,
src_ip_inner=pdn_interface["ips"][0],
- dst_ip_inner=BESS_UE_ADDR,
+ dst_ip_inner=bess_ue_address,
src_udp_inner=PDN_PORT,
dst_udp_inner=UE_PORT,
teid=BESS_TEID)
@@ -605,3 +606,123 @@
run.saveOnosDiagsIfFailure(main)
run.cleanup(main)
+
+ def CASE5(self, main):
+ main.case("UP4 Data Plane Failure Test")
+ """
+ Program PDRs/FARs
+ Kill one switch
+ Verify that traffic from eNodebs that are connected to that switch fails
+ Verify that traffic from other eNodeBs is being forwarded
+ Wait for the switch to be up again
+ Check flows
+ Remove PDRs/FARs (cleanup)
+ """
+ try:
+ from tests.USECASE.SegmentRouting.dependencies.up4 import UP4, \
+ N_FLOWS_PER_UE
+ from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+ Testcaselib as run
+ from tests.USECASE.SegmentRouting.SRStaging.dependencies.SRStagingTest import \
+ SRStagingTest
+ import time
+ import itertools
+ except ImportError as e:
+ main.log.error("Import not found. Exiting the test")
+ main.log.error(e)
+ main.cleanAndExit()
+ n_switches = int(main.params["TOPO"]["switchNum"])
+ switch_to_kill = main.params["UP4"]["switch_to_kill"]
+
+ run.initTest(main)
+ main.log.info(main.Cluster.numCtrls)
+ main.Cluster.setRunningNode(3)
+ run.installOnos(main, skipPackage=True, cliSleep=5)
+
+ onos_cli = main.Cluster.active(0).CLI
+
+ up4 = UP4()
+
+ initial_flow_count = onos_cli.checkFlowCount()
+
+ main.step("Program and Verify PDRs and FARs via UP4")
+ up4.setup(main.Cluster.active(0).p4rtUp4)
+ up4.attachUes()
+ up4.verifyUp4Flow(onos_cli)
+
+ run.checkFlows(
+ main,
+ minFlowCount=initial_flow_count+(len(up4.emulated_ues)*4*n_switches)
+ )
+
+ main.step("Kill switch")
+ switch_component = getattr(main, switch_to_kill)
+ switch_component.handle.sendline("sudo reboot")
+
+ sleepTime = 20
+ main.log.info("Sleeping %s seconds for Fabric to react" % sleepTime)
+ time.sleep(sleepTime)
+
+ available = utilities.retry(SRStagingTest.switchIsConnected,
+ True,
+ args=[switch_component],
+ attempts=300,
+ getRetryingTime=True)
+ main.log.info("Switch %s is available in ONOS? %s" % (
+ switch_to_kill, available))
+ utilities.assert_equal(
+ expect=False,
+ actual=available,
+ onpass="Switch was rebooted (ONL reboot) successfully",
+ onfail="Switch was not rebooted (ONL reboot) successfully"
+ )
+
+ enodebs_fail = main.params["UP4"]["enodebs_fail"].split(",")
+ enodebs_no_fail = list(set(up4.enodebs.keys()) - set(enodebs_fail))
+
+ # ------- Test Upstream traffic (enbs->pdn)
+ main.step("Test upstream traffic FAIL")
+ up4.testUpstreamTraffic(enb_names=enodebs_fail, shouldFail=True)
+ main.step("Test upstream traffic NO FAIL")
+ up4.testUpstreamTraffic(enb_names=enodebs_no_fail, shouldFail=False)
+
+ # ------- Test Downstream traffic (pdn->enbs)
+ main.step("Test downstream traffic FAIL")
+ up4.testDownstreamTraffic(enb_names=enodebs_fail, shouldFail=True)
+ main.step("Test downstream traffic NO FAIL")
+ up4.testDownstreamTraffic(enb_names=enodebs_no_fail, shouldFail=False)
+
+ # Reconnect to the switch
+ connect = utilities.retry(switch_component.connect,
+ main.FALSE,
+ attempts=30,
+ getRetryingTime=True)
+ main.log.info("Connected to the switch %s? %s" % (
+ switch_to_kill, connect))
+ # Wait switch to be back in ONOS
+ available = utilities.retry(SRStagingTest.switchIsConnected,
+ False,
+ args=[switch_component],
+ attempts=300,
+ getRetryingTime=True)
+ main.log.info("Switch %s is available in ONOS? %s" % (
+ switch_to_kill, available))
+ utilities.assert_equal(
+ expect=True,
+ actual=available and connect == main.TRUE,
+ onpass="Switch is back available in ONOS",
+ onfail="Switch is not available in ONOS, may influence subsequent tests!"
+ )
+
+ main.step("Test upstream traffic AFTER switch reboot")
+ up4.testUpstreamTraffic()
+
+ main.step("Cleanup PDRs and FARs via UP4")
+ up4.detachUes()
+ up4.verifyNoUesFlow(onos_cli)
+ up4.teardown()
+
+ run.checkFlows(main, minFlowCount=initial_flow_count)
+
+ # Teardown
+ run.cleanup(main)
diff --git a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.topo b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.topo
index 8605cad..731c259 100644
--- a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.topo
+++ b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.topo
@@ -27,6 +27,35 @@
</COMPONENTS>
</ONOScell>
+ <MgmtServer>
+ <host>10.76.28.66</host>
+ <user>jenkins</user>
+ <password></password>
+ <type>HostDriver</type>
+ <connect_order>6</connect_order>
+ <jump_host></jump_host>
+ <COMPONENTS>
+ <mac></mac>
+ <inband>false</inband>
+ <dhcp>True</dhcp>
+ <ip>10.32.11.1</ip>
+ <shortName>mgmt</shortName>
+ <port1></port1>
+ <link1></link1>
+ <ifaceName>pairbond</ifaceName>
+ <scapy_path>/usr/bin/scapy</scapy_path>
+ <routes>
+ <route1>
+ <network></network>
+ <netmask></netmask>
+ <gw></gw>
+ <interface></interface>
+ </route1>
+ </routes>
+ <sudo_required>true</sudo_required>
+ </COMPONENTS>
+ </MgmtServer>
+
<Compute1>
<host>10.76.28.74</host>
<user>jenkins</user>
@@ -114,6 +143,21 @@
</COMPONENTS>
</Compute3>
+ <Leaf2>
+ <host>10.76.28.71</host>
+ <user>root</user>
+ <password>onl</password>
+ <type>StratumOSSwitchDriver</type>
+ <connect_order>10</connect_order>
+ <COMPONENTS>
+ <shortName>leaf2</shortName>
+ <port1>2</port1>
+ <link1>Host2</link1>
+ <onosConfigPath></onosConfigPath>
+ <onosConfigFile></onosConfigFile>
+ </COMPONENTS>
+ </Leaf2>
+
<!-- This component is not needed, but required to use the Testcaselib -->
<NetworkBench>
<host>10.76.28.66</host>
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/up4.py b/TestON/tests/USECASE/SegmentRouting/dependencies/up4.py
index bc6a49a..0f6c8a8 100644
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/up4.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/up4.py
@@ -1,4 +1,5 @@
from distutils.util import strtobool
+import copy
FALSE = '0'
TRUE = '1'
@@ -20,16 +21,28 @@
"""
Utility that manages interaction with UP4 via a P4RuntimeCliDriver available
in the cluster. Additionally, can verify connectivity by crafting GTP packets
- via Scapy with an HostDriver component, specified via <enodeb_host>, <pdn_host>,
+ via Scapy with an HostDriver component, specified via <enodebs>, <pdn_host>,
and <router_mac> parameters.
Example params file:
<UP4>
<pdn_host>Compute1</pdn_host> # Needed to verify connectivity with scapy
- <enodeb_host>Compute3</enodeb_host> # Needed to verify connectivity with scapy
+ <enodebs> # List of emulated eNodeBs
+ <enode_1>
+ <host>Compute1</host> # Host that emulates this eNodeB
+ <interface>eno3</interface> # Name of the linux interface to use on the host, if not specified take the default
+ <enb_address>10.32.11.122</enb_address> # IP address of the eNodeB
+ <ues>ue3</ues> # Emulated ues connected to this eNB
+ </enode_1>
+ <enodeb_2>
+ <host>Compute3</host>
+ <enb_address>10.32.11.194</enb_address>
+ <ues>ue1,ue2</ues>
+ </enodeb_2>
+ </enodebs>
+ <enodeb_host>Compute3</enodeb_host>
<router_mac>00:00:0A:4C:1C:46</router_mac> # Needed to verify connectivity with scapy
<s1u_address>10.32.11.126</s1u_address>
- <enb_address>10.32.11.100</enb_address>
<ues>
<ue2>
<pfcp_session_id>100</pfcp_session_id>
@@ -41,19 +54,20 @@
<five_g>False</five_g>
</ue2>
</ues>
+ <switch_to_kill>Leaf2</switch_to_kill> # Component name of the switch to kill in CASE 5
+ <enodebs_fail>enodeb_1</enodebs_fail> # List of eNodeBs that should fail traffic forwarding in CASE 5
</UP4>
"""
def __init__(self):
self.s1u_address = None
- self.enb_address = None
- self.enodeb_host = None
- self.enodeb_interface = None
+ self.enodebs = None
self.pdn_host = None
self.pdn_interface = None
self.router_mac = None
- self.emulated_ues = []
+ self.emulated_ues = {}
self.up4_client = None
+ self.no_host = False
def setup(self, p4rt_client, no_host=False):
"""
@@ -63,58 +77,73 @@
:return:
"""
self.s1u_address = main.params["UP4"]["s1u_address"]
- self.enb_address = main.params["UP4"]["enb_address"]
self.emulated_ues = main.params["UP4"]['ues']
self.up4_client = p4rt_client
+ self.no_host = no_host
# Optional Parameters
- if not no_host:
- if "enodeb_host" in main.params["UP4"]:
- self.enodeb_host = getattr(main,
- main.params["UP4"]["enodeb_host"])
- self.enodeb_interface = self.enodeb_host.interfaces[0]
- if "pdn_host" in main.params["UP4"]:
- self.pdn_host = getattr(main, main.params["UP4"]["pdn_host"])
- self.pdn_interface = self.pdn_host.interfaces[0]
- self.router_mac = main.params["UP4"].get("router_mac", None)
+
+ self.enodebs = copy.deepcopy((main.params["UP4"]["enodebs"]))
+ for enb in self.enodebs.values():
+ enb["ues"] = enb["ues"].split(",")
+ enb["host"] = getattr(main, enb["host"])
+ # If interface not provided by the params, use the default in the host
+ if "interface" not in enb.keys():
+ enb["interface"] = enb["host"].interfaces[0]["name"]
+ if "pdn_host" in main.params["UP4"]:
+ self.pdn_host = getattr(main, main.params["UP4"]["pdn_host"])
+ self.pdn_interface = self.pdn_host.interfaces[0]
+ self.router_mac = main.params["UP4"].get("router_mac", None)
# Start components
self.up4_client.startP4RtClient()
- if self.enodeb_host is not None:
- self.enodeb_host.startScapy(ifaceName=self.enodeb_interface["name"],
- enableGtp=True)
- if self.pdn_host is not None:
- self.pdn_host.startScapy(ifaceName=self.pdn_interface["name"])
+ if not self.no_host:
+ if self.enodebs is not None:
+ for enb in self.enodebs.values():
+ enb["host"].startScapy(ifaceName=enb["interface"],
+ enableGtp=True)
+ if self.pdn_host is not None:
+ self.pdn_host.startScapy(ifaceName=self.pdn_interface["name"])
def teardown(self):
self.up4_client.stopP4RtClient()
- if self.enodeb_host is not None:
- self.enodeb_host.stopScapy()
- if self.pdn_host is not None:
- self.pdn_host.stopScapy()
+ if not self.no_host:
+ if self.enodebs is not None:
+ for enb in self.enodebs.values():
+ enb["host"].stopScapy()
+ if self.pdn_host is not None:
+ self.pdn_host.stopScapy()
def attachUes(self):
- for ue in self.emulated_ues.values():
+ for (name, ue) in self.emulated_ues.items():
ue = UP4.__sanitizeUeData(ue)
- self.attachUe(**ue)
+ self.attachUe(name, **ue)
def detachUes(self):
- for ue in self.emulated_ues.values():
+ for (name, ue) in self.emulated_ues.items():
ue = UP4.__sanitizeUeData(ue)
- self.detachUe(**ue)
+ self.detachUe(name, **ue)
- def testUpstreamTraffic(self):
- if self.enodeb_host is None or self.pdn_host is None:
+ def testUpstreamTraffic(self, enb_names=None, shouldFail=False):
+ if self.enodebs is None or self.pdn_host is None:
main.log.error(
"Need eNodeB and PDN host params to generate scapy traffic")
return
# Scapy filter needs to start before sending traffic
+ if enb_names is None or enb_names == []:
+ enodebs = self.enodebs.values()
+ else:
+ enodebs = [self.enodebs[enb] for enb in enb_names]
pkt_filter_upstream = ""
- for ue in self.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"]
+ ues = []
+ for enb in enodebs:
+ for ue_name in enb["ues"]:
+ ue = self.emulated_ues[ue_name]
+ if "ue_address" in ue:
+ ues.append(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,
self.pdn_interface["ips"][0])
@@ -122,33 +151,35 @@
(self.pdn_host.name, self.pdn_interface["name"]))
main.log.debug("BPF Filter Upstream: \n %s" % pkt_filter_upstream)
self.pdn_host.startFilter(ifaceName=self.pdn_interface["name"],
- sniffCount=len(self.emulated_ues),
+ sniffCount=len(ues),
pktFilter=pkt_filter_upstream)
main.log.info(
- "Sending %d packets from eNodeB host" % len(self.emulated_ues))
- for ue in self.emulated_ues.values():
- UP4.buildGtpPacket(self.enodeb_host,
- src_ip_outer=self.enb_address,
- dst_ip_outer=self.s1u_address,
- src_ip_inner=ue["ue_address"],
- dst_ip_inner=self.pdn_interface["ips"][0],
- src_udp_inner=UE_PORT,
- dst_udp_inner=PDN_PORT,
- teid=int(ue["teid"]))
-
- self.enodeb_host.sendPacket(iface=self.enodeb_interface["name"])
+ "Sending %d packets from eNodeB host" % len(ues))
+ for enb in enodebs:
+ for ue_name in enb["ues"]:
+ main.log.info(ue_name)
+ ue = self.emulated_ues[ue_name]
+ main.log.info(str(ue))
+ UP4.buildGtpPacket(enb["host"],
+ src_ip_outer=enb["enb_address"],
+ dst_ip_outer=self.s1u_address,
+ src_ip_inner=ue["ue_address"],
+ dst_ip_inner=self.pdn_interface["ips"][0],
+ src_udp_inner=UE_PORT,
+ dst_udp_inner=PDN_PORT,
+ teid=int(ue["teid"]))
+ enb["host"].sendPacket(iface=enb["interface"])
packets = UP4.checkFilterAndGetPackets(self.pdn_host)
fail = False
- if len(self.emulated_ues) != packets.count('Ether'):
+ if len(ues) != packets.count('Ether'):
fail = True
msg = "Failed to capture packets in PDN.\n" + str(packets)
else:
msg = "Correctly captured packet in PDN. "
# We expect exactly 1 packet per UE
- pktsFiltered = [packets.count("src=" + ue["ue_address"])
- for ue in self.emulated_ues.values()]
+ pktsFiltered = [packets.count("src=" + ue["ue_address"]) for ue in ues]
if pktsFiltered.count(1) != len(pktsFiltered):
fail = True
msg += "\nError on the number of packets per UE in downstream.\n" + str(packets)
@@ -156,25 +187,33 @@
msg += "\nOne packet per UE in upstream. "
utilities.assert_equal(
- expect=False, actual=fail, onpass=msg, onfail=msg)
+ expect=shouldFail, actual=fail, onpass=msg, onfail=msg)
- def testDownstreamTraffic(self):
- if self.enodeb_host is None or self.pdn_host is None:
+ def testDownstreamTraffic(self, enb_names=None, shouldFail=False):
+ if self.enodebs is None or self.pdn_host is None:
main.log.error(
"Need eNodeB and PDN host params to generate scapy traffic")
return
- 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, self.enb_address, self.s1u_address)
- main.log.info("Start listening on %s intf %s" % (
- self.enodeb_host.name, self.enodeb_interface["name"]))
- main.log.debug("BPF Filter Downstream: \n %s" % pkt_filter_downstream)
- self.enodeb_host.startFilter(ifaceName=self.enodeb_interface["name"],
- sniffCount=len(self.emulated_ues),
- pktFilter=pkt_filter_downstream)
+ if enb_names is None or enb_names == []:
+ enodebs = self.enodebs.values()
+ else:
+ enodebs = [self.enodebs[enb] for enb in enb_names]
+ pkt_filter_downstream = "ip and udp src port %d and udp dst port %d and src host %s" % (
+ GPDU_PORT, GPDU_PORT, self.s1u_address)
+ ues = []
+ for enb in enodebs:
+ filter_down = pkt_filter_downstream + " and dst host %s" % enb["enb_address"]
+ main.log.info("Start listening on %s intf %s" % (
+ enb["host"], enb["interface"]))
+ main.log.debug("BPF Filter Downstream: \n %s" % filter_down)
+ enb["host"].startFilter(ifaceName=enb["interface"],
+ sniffCount=len(enb["ues"]),
+ pktFilter=filter_down)
+ ues.extend([self.emulated_ues[ue_name] for ue_name in enb["ues"]])
main.log.info(
- "Sending %d packets from PDN host" % len(self.emulated_ues))
- for ue in self.emulated_ues.values():
+ "Sending %d packets from PDN host" % len(ues))
+ for ue in ues:
# From PDN we have to set dest MAC, otherwise scapy will do ARP
# request for the UE IP address.
UP4.buildUdpPacket(self.pdn_host,
@@ -184,19 +223,21 @@
src_udp=PDN_PORT,
dst_udp=UE_PORT)
self.pdn_host.sendPacket(iface=self.pdn_interface["name"])
-
- packets = UP4.checkFilterAndGetPackets(self.enodeb_host)
-
+ packets = ""
+ for enb in enodebs:
+ pkt = UP4.checkFilterAndGetPackets(enb["host"])
+ packets += pkt
# 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 self.emulated_ues.values()]
-
+ pktsFiltered= [packets.count("TEID=" + hex(int(ue["teid"])) + "L ")
+ for ue in ues]
+ main.log.info("PACKETS: " + str(packets))
+ main.log.info("PKTs Filtered: " + str(pktsFiltered))
fail = False
- if len(self.emulated_ues) != sum(pktsFiltered):
+ if len(ues) != sum(pktsFiltered):
fail = True
msg = "Failed to capture packets in eNodeB.\n" + str(packets)
else:
@@ -209,7 +250,7 @@
msg += "\nOne packet per GTP TEID in downstream. "
utilities.assert_equal(
- expect=False, actual=fail, onpass=msg, onfail=msg)
+ expect=shouldFail, actual=fail, onpass=msg, onfail=msg)
def readPdrsNumber(self):
"""
@@ -305,7 +346,7 @@
fars = onosCli.sendline(cmdStr="up4:read-fars", showResponse=True,
noExit=True, expectJson=False)
fail = False
- for ue in self.emulated_ues.values():
+ for (ue_name, ue) in self.emulated_ues.items():
if pdrs.count(self.upPdrOnosString(**ue)) != 1:
failMsg += self.upPdrOnosString(**ue) + "\n"
fail = True
@@ -315,8 +356,8 @@
if fars.count(self.upFarOnosString(**ue)) != 1:
failMsg += self.upFarOnosString(**ue) + "\n"
fail = True
- if fars.count(self.downFarOnosString(**ue)) != 1:
- failMsg += self.downFarOnosString(**ue) + "\n"
+ if fars.count(self.downFarOnosString(ue_name, **ue)) != 1:
+ failMsg += self.downFarOnosString(ue_name, **ue) + "\n"
fail = True
return not fail
@@ -351,16 +392,16 @@
return "PDR{{Match(Dst={}, !GTP) -> LoadParams(SEID={}, FAR={}, CtrIdx={})}}".format(
ue_address, hex(int(pfcp_session_id)), far_id_down, ctr_id_down)
- def downFarOnosString(self, pfcp_session_id, teid=None, down_id=None,
+ def downFarOnosString(self, ue_name, pfcp_session_id, teid=None, down_id=None,
teid_down=None, far_id_down=None, **kwargs):
if down_id is not None:
far_id_down = down_id
if teid is not None:
teid_down = teid
+ enb_address = self.__getEnbAddress(ue_name)
return "FAR{{Match(ID={}, SEID={}) -> Encap(Src={}, SPort={}, TEID={}, Dst={})}}".format(
far_id_down, hex(int(pfcp_session_id)), self.s1u_address, GPDU_PORT,
- hex(int(teid_down)),
- self.enb_address)
+ hex(int(teid_down)), enb_address)
def upFarOnosString(self, pfcp_session_id, up_id=None, far_id_up=None,
**kwargs):
@@ -377,13 +418,14 @@
ue["qfi"] = None
return ue
- def attachUe(self, pfcp_session_id, ue_address,
+ def attachUe(self, ue_name, pfcp_session_id, ue_address,
teid=None, up_id=None, down_id=None,
teid_up=None, teid_down=None,
pdr_id_up=None, far_id_up=None, ctr_id_up=None,
pdr_id_down=None, far_id_down=None, ctr_id_down=None,
qfi=None, five_g=False):
- self.__programUp4Rules(pfcp_session_id,
+ self.__programUp4Rules(ue_name,
+ pfcp_session_id,
ue_address,
teid, up_id, down_id,
teid_up, teid_down,
@@ -391,13 +433,14 @@
pdr_id_down, far_id_down, ctr_id_down,
qfi, five_g, action="program")
- def detachUe(self, pfcp_session_id, ue_address,
+ def detachUe(self, ue_name, pfcp_session_id, ue_address,
teid=None, up_id=None, down_id=None,
teid_up=None, teid_down=None,
pdr_id_up=None, far_id_up=None, ctr_id_up=None,
pdr_id_down=None, far_id_down=None, ctr_id_down=None,
qfi=None, five_g=False):
- self.__programUp4Rules(pfcp_session_id,
+ self.__programUp4Rules(ue_name,
+ pfcp_session_id,
ue_address,
teid, up_id, down_id,
teid_up, teid_down,
@@ -405,7 +448,7 @@
pdr_id_down, far_id_down, ctr_id_down,
qfi, five_g, action="clear")
- def __programUp4Rules(self, pfcp_session_id, ue_address,
+ def __programUp4Rules(self, ue_name, pfcp_session_id, ue_address,
teid=None, up_id=None, down_id=None,
teid_up=None, teid_down=None,
pdr_id_up=None, far_id_up=None, ctr_id_up=None,
@@ -425,6 +468,9 @@
entries = []
+ # Retrieve eNobeB address from eNodeB list
+ enb_address = self.__getEnbAddress(ue_name)
+
# ========================#
# PDR Entries
# ========================#
@@ -518,7 +564,7 @@
actionParams['needs_buffering'] = FALSE
actionParams['tunnel_type'] = TUNNEL_TYPE_GPDU
actionParams['src_addr'] = str(self.s1u_address)
- actionParams['dst_addr'] = str(self.enb_address)
+ actionParams['dst_addr'] = str(enb_address)
actionParams['teid'] = str(teid_down)
actionParams['sport'] = TUNNEL_SPORT
if not self.__add_entry(tableName, actionName, matchFields,
@@ -555,6 +601,13 @@
else:
main.log.error("Error during table delete")
+ def __getEnbAddress(self, ue_name):
+ for enb in self.enodebs.values():
+ if ue_name in enb["ues"]:
+ return enb["enb_address"]
+ main.log.error("Missing eNodeB address!")
+ return ""
+
@staticmethod
def buildGtpPacket(host, src_ip_outer, dst_ip_outer, src_ip_inner,
dst_ip_inner, src_udp_inner, dst_udp_inner, teid):