From b89f122cdbe24fed8328da34b0aa0cb02b83bb58 Mon Sep 17 00:00:00 2001 From: "Georgios P. Katsikas" Date: Fri, 27 Feb 2026 16:04:24 +0200 Subject: [PATCH] feat: UPF test script and minor fixes --- .../automation/test_functional_automation.py | 2 +- .../descriptors/sbi-rules-insert-int-b1.json | 2 +- .../descriptors/sbi-rules-insert-int-b2.json | 36 ++--- .../descriptors/sbi-rules-insert-int-b3.json | 8 +- .../sbi-rules-insert-routing-east.json | 8 +- .../sbi-rules-insert-routing-west.json | 8 +- .../descriptors/sbi-rules-remove.json | 62 ++++---- .../test-scripts/p4-upf/README.md | 25 +++ .../test-scripts/p4-upf/packet-gen-5g-ue.py | 149 ++++++++++++++++++ 9 files changed, 237 insertions(+), 63 deletions(-) create mode 100644 src/tests/p4-topologies/test-scripts/p4-upf/README.md create mode 100644 src/tests/p4-topologies/test-scripts/p4-upf/packet-gen-5g-ue.py diff --git a/src/tests/automation/test_functional_automation.py b/src/tests/automation/test_functional_automation.py index a29307765..b4505931c 100644 --- a/src/tests/automation/test_functional_automation.py +++ b/src/tests/automation/test_functional_automation.py @@ -14,6 +14,7 @@ import json import logging +import os import uuid from common.proto.analytics_frontend_pb2 import AnalyzerId, AnalyzerOperationMode from common.proto.automation_pb2 import ZSMCreateRequest @@ -81,7 +82,6 @@ def test_service_zsm_create( # Add important information in the request loaded_request = _zsm_create_request(loaded_request, kpi_manager_client) - # loaded_request = _static_zsm_create_request() # Invoke Automation automation_client.ZSMCreate(loaded_request) diff --git a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b1.json b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b1.json index b260c5a4c..22aa84205 100644 --- a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b1.json +++ b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b1.json @@ -120,7 +120,7 @@ }, { "match-field": "ipv4_dst", - "match-value": "10.10.10.41&&&0xFFFFFFFF" + "match-value": "192.168.5.137&&&0xFFFFFFFF" } ], "action-name": "FabricIngress.int_watchlist.no_report_collector", diff --git a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b2.json b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b2.json index 1ddf941cb..8650d18ec 100644 --- a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b2.json +++ b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b2.json @@ -34,15 +34,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -76,15 +76,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -118,15 +118,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -160,15 +160,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -202,15 +202,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -244,15 +244,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", diff --git a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b3.json b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b3.json index d4d8a92fd..66bdbbdd1 100644 --- a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b3.json +++ b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-int-b3.json @@ -102,7 +102,7 @@ }, { "match-field": "eth_dst", - "match-value": "fa:16:3e:fb:cf:96" + "match-value": "46:e4:58:c6:74:53" } ], "action-name": "FabricIngress.forwarding.set_next_id_bridging", @@ -147,7 +147,7 @@ "match-fields": [ { "match-field": "ipv4_dst", - "match-value": "10.10.10.41/32" + "match-value": "192.168.5.137/32" } ], "action-name": "FabricIngress.forwarding.set_next_id_routing_v4", @@ -180,11 +180,11 @@ }, { "action-param": "smac", - "action-value": "fa:16:3e:93:8c:c0" + "action-value": "ee:ee:8c:6c:f3:2c" }, { "action-param": "dmac", - "action-value": "fa:16:3e:fb:cf:96" + "action-value": "46:e4:58:c6:74:53" } ] } diff --git a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-routing-east.json b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-routing-east.json index f0c438568..2a54108f0 100644 --- a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-routing-east.json +++ b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-routing-east.json @@ -102,7 +102,7 @@ }, { "match-field": "eth_dst", - "match-value": "fa:16:3e:e2:af:28" + "match-value": "00:00:00:00:00:02" } ], "action-name": "FabricIngress.forwarding.set_next_id_bridging", @@ -147,7 +147,7 @@ "match-fields": [ { "match-field": "ipv4_dst", - "match-value": "172.16.10.9/32" + "match-value": "10.0.0.2/32" } ], "action-name": "FabricIngress.forwarding.set_next_id_routing_v4", @@ -180,11 +180,11 @@ }, { "action-param": "smac", - "action-value": "fa:16:3e:9b:cb:a1" + "action-value": "00:00:00:00:00:01" }, { "action-param": "dmac", - "action-value": "fa:16:3e:e2:af:28" + "action-value": "00:00:00:00:00:02" } ] } diff --git a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-routing-west.json b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-routing-west.json index 2d5b9e080..6e30d8b3a 100644 --- a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-routing-west.json +++ b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-insert-routing-west.json @@ -102,7 +102,7 @@ }, { "match-field": "eth_dst", - "match-value": "fa:16:3e:58:92:ba" + "match-value": "00:00:00:00:00:01" } ], "action-name": "FabricIngress.forwarding.set_next_id_bridging", @@ -147,7 +147,7 @@ "match-fields": [ { "match-field": "ipv4_dst", - "match-value": "10.158.72.25/32" + "match-value": "10.0.0.1/32" } ], "action-name": "FabricIngress.forwarding.set_next_id_routing_v4", @@ -180,11 +180,11 @@ }, { "action-param": "smac", - "action-value": "fa:16:3e:e2:af:28" + "action-value": "00:00:00:00:00:02" }, { "action-param": "dmac", - "action-value": "fa:16:3e:58:92:ba" + "action-value": "00:00:00:00:00:01" } ] } diff --git a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-remove.json b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-remove.json index b2b3b429f..f82b25f89 100644 --- a/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-remove.json +++ b/src/tests/p4-sd-fabric-sbi-connectivity/descriptors/sbi-rules-remove.json @@ -131,15 +131,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -173,15 +173,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -215,15 +215,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -257,15 +257,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -299,15 +299,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -341,15 +341,15 @@ "action-params": [ { "action-param": "src_ip", - "action-value": "10.10.10.120" + "action-value": "192.168.5.139" }, { "action-param": "mon_ip", - "action-value": "10.10.10.41" + "action-value": "192.168.5.137" }, { "action-param": "mon_port", - "action-value": "32766" + "action-value": "12345" }, { "action-param": "switch_id", @@ -372,7 +372,7 @@ }, { "match-field": "ipv4_dst", - "match-value": "10.10.10.41&&&0xFFFFFFFF" + "match-value": "192.168.5.137&&&0xFFFFFFFF" } ], "action-name": "FabricIngress.int_watchlist.no_report_collector", @@ -473,7 +473,7 @@ }, { "match-field": "eth_dst", - "match-value": "fa:16:3e:fb:cf:96" + "match-value": "46:e4:58:c6:74:53" } ], "action-name": "FabricIngress.forwarding.set_next_id_bridging", @@ -518,7 +518,7 @@ "match-fields": [ { "match-field": "ipv4_dst", - "match-value": "10.10.10.41/32" + "match-value": "192.168.5.137/32" } ], "action-name": "FabricIngress.forwarding.set_next_id_routing_v4", @@ -551,11 +551,11 @@ }, { "action-param": "smac", - "action-value": "fa:16:3e:93:8c:c0" + "action-value": "ee:ee:8c:6c:f3:2c" }, { "action-param": "dmac", - "action-value": "fa:16:3e:fb:cf:96" + "action-value": "46:e4:58:c6:74:53" } ] } @@ -668,7 +668,7 @@ }, { "match-field": "eth_dst", - "match-value": "fa:16:3e:58:92:ba" + "match-value": "00:00:00:00:00:01" } ], "action-name": "FabricIngress.forwarding.set_next_id_bridging", @@ -713,7 +713,7 @@ "match-fields": [ { "match-field": "ipv4_dst", - "match-value": "10.158.72.25/32" + "match-value": "10.0.0.1/32" } ], "action-name": "FabricIngress.forwarding.set_next_id_routing_v4", @@ -746,11 +746,11 @@ }, { "action-param": "smac", - "action-value": "fa:16:3e:e2:af:28" + "action-value": "00:00:00:00:00:02" }, { "action-param": "dmac", - "action-value": "fa:16:3e:58:92:ba" + "action-value": "00:00:00:00:00:01" } ] } @@ -848,7 +848,7 @@ }, { "match-field": "eth_dst", - "match-value": "fa:16:3e:e2:af:28" + "match-value": "00:00:00:00:00:02" } ], "action-name": "FabricIngress.forwarding.set_next_id_bridging", @@ -893,7 +893,7 @@ "match-fields": [ { "match-field": "ipv4_dst", - "match-value": "172.16.10.9/32" + "match-value": "10.0.0.2/32" } ], "action-name": "FabricIngress.forwarding.set_next_id_routing_v4", @@ -926,11 +926,11 @@ }, { "action-param": "smac", - "action-value": "fa:16:3e:9b:cb:a1" + "action-value": "00:00:00:00:00:01" }, { "action-param": "dmac", - "action-value": "fa:16:3e:e2:af:28" + "action-value": "00:00:00:00:00:02" } ] } diff --git a/src/tests/p4-topologies/test-scripts/p4-upf/README.md b/src/tests/p4-topologies/test-scripts/p4-upf/README.md new file mode 100644 index 000000000..577e5dc29 --- /dev/null +++ b/src/tests/p4-topologies/test-scripts/p4-upf/README.md @@ -0,0 +1,25 @@ +# UPF Test + +If you have already deployed your UPF following the instructions provided in `src/tests/p4-sd-fabric-svc-upf/` and you want to perform a quick test without deploying a fully-fledged 5G system, you may execute the script in this folder. +All you need is to tweak the script's initial variables to fit your setup. + +## Where to deploy the script + +On the network interface that connects the 5G gNB node with the UPF. +Mark this network interface and add its name as a value in variable `GNB_IFACE`. + +## What to configure in the script + +Apart from the `GNB_IFACE` variable, you need to provide: +- `GNB_IP` and `GNB_MAC` addresses that correspond to the interface `GNB_IFACE` +- `DNN_IP` and `DNN_IP` addresses that correspond to the destination of the packet after traversing the UPF. +- `UPF_IP_LEFT` and `UPF_MAC_LEFT` addresses that correspond to the interface of the UPF that talks to te gNB +- a `UE_IP` of your choice if the default value in the script is not what you want. The UE is emulated by this script so you may leave the default IP. + + +## How the script works + +The script employs a traffic sniffer on the `GNB_IFACE` with a timeout. +After the sniffer is employed, the script transmits a GTP-U packet towards the DNN, which encapsulates an ICMP echo request from the UE to the DNN host. +This packet has to pass through your UPF and get back once the kernel of the DNN host responds with an ICMP echo reply. +This reply is captured by the script and printed. diff --git a/src/tests/p4-topologies/test-scripts/p4-upf/packet-gen-5g-ue.py b/src/tests/p4-topologies/test-scripts/p4-upf/packet-gen-5g-ue.py new file mode 100644 index 000000000..94bb6e48b --- /dev/null +++ b/src/tests/p4-topologies/test-scripts/p4-upf/packet-gen-5g-ue.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +import time +from scapy.all import * +from scapy.contrib.gtp import * + +# 5G gNB network interface towards the 5G UPF +GNB_IFACE = "dp-2" +GNB_IP = "10.10.1.2" +GNB_MAC = "50:3e:aa:85:89:09" + +DNN_IP = "10.10.2.2" # DNN IP address +DNN_MAC = "50:3e:aa:96:ba:dd" + +UPF_IP_LEFT = "10.10.1.1" +UPF_MAC_LEFT = "50:3e:aa:52:3e:38" + +UE_IP = "12.1.1.51" # 5G UE IP address +GTPU_PORT = 2152 + +def send_echo_request(): + # Outer IP + outer_ip = IP( + src=GNB_IP, # IP address of the GNB_IFACE above + dst=UPF_IP_LEFT, + ttl=63, + flags="DF", + id=0x2bae + ) + + # UDP + udp = UDP(sport=GTPU_PORT, dport=GTPU_PORT) + + # GTP PDU Session Container (UL, QFI=9) + pdu_sess = GTPPDUSessionContainer( + type=1, # UL PDU SESSION INFORMATION + QFI=9 + ) + + gtp = GTP_U_Header( + version=1, + PT=1, + E=1, + S=0, + PN=0, + teid=1 + ) / pdu_sess + + # Inner ICMP payload (exact bytes) + icmp_payload = bytes.fromhex( + "7c370600000000001011121314151617" + "18191a1b1c1d1e1f2021222324252627" + "28292a2b2c2d2e2f" + ) + + # ICMP + icmp = ICMP( + type=8, + code=0, + id=0x0035, + seq=1 + ) / Raw(load=icmp_payload) + + # Inner IP + inner_ip = IP( + src=UE_IP, + dst=DNN_IP, + ttl=64, + flags="DF", + id=0xa538 + ) + + # Full packet + pkt = ( + Ether(src=GNB_MAC, dst=DNN_MAC) / + outer_ip / + udp / + gtp / + inner_ip / + icmp + ) + + # Freeze computed fields + pkt = pkt.__class__(raw(pkt)) + + # pkt.show2() + sendp(pkt, iface=GNB_IFACE, verbose=True) + print("Packet sent...\n") + +def interface_capture(pkt): + if pkt[IP].src == GNB_IP: + print("\n=== Tx Packet ===") + print("Packet transmitted by the UE\n") + print(f"{pkt}") + return + + print("\n=== Rx Packet ===") + print(f"{pkt}") + if not pkt.haslayer(GTP_U_Header): + print("Packet received by the UPF is not GTP-U encapsulated\n") + return + + if pkt[IP].src != UPF_IP_LEFT: + print("Packet received by the UPF has incorrect source IP\n") + return + + gtp = pkt[GTP_U_Header] + inner = gtp.payload + + if not inner.haslayer(ICMP): + print("Packet received by the UPF is not ICMP\n") + return + + icmp = inner[ICMP] + + if icmp.type != 0: + return + + # print("\n=== Received Echo Reply ===") + # print("DL TEID:", gtp.teid) + # print(" From:", inner.src) + # print(" To:", inner.dst) + # print("ICMP ID:", icmp.id) + # print(" Seq:", icmp.seq) + # print("===========================\n") + + print("--------------> Your UPF works!") + +print("================================================") + +sniffer = AsyncSniffer( + iface=GNB_IFACE, + filter="udp port 2152", + prn=interface_capture +) + +sniffer.start() +print("Sniffer started") +time.sleep(1) + +# Send packet +send_echo_request() + +# Listen for reply +print("Waiting for reply...\n") + +time.sleep(10) +sniffer.stop() +print("Sniffer is torn down") +print("================================================") -- GitLab