diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py
index ccf821b2feb4fe615babdc72c8b505e6c0a6b4b2..bddc8ee6e3d9114754b4076d483ce8c9c62ee875 100644
--- a/src/service/service/service_handlers/__init__.py
+++ b/src/service/service/service_handlers/__init__.py
@@ -25,7 +25,7 @@ from .l3nm_ietf_actn.L3NMIetfActnServiceHandler import L3NMIetfActnServiceHandle
 from .l3nm_nce.L3NMNCEServiceHandler import L3NMNCEServiceHandler
 from .l3slice_ietfslice.L3SliceIETFSliceServiceHandler import L3NMSliceIETFSliceServiceHandler
 from .microwave.MicrowaveServiceHandler import MicrowaveServiceHandler
-from .p4_l1.p4_l1_service_handler import P4L1ServiceHandler
+from .p4_dummy_l1.p4_dummy_l1_service_handler import P4DummyL1ServiceHandler
 from .tapi_tapi.TapiServiceHandler import TapiServiceHandler
 from .tapi_xr.TapiXrServiceHandler import TapiXrServiceHandler
 from .e2e_orch.E2EOrchestratorServiceHandler import E2EOrchestratorServiceHandler
@@ -105,7 +105,7 @@ SERVICE_HANDLERS = [
             FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY, DeviceDriverEnum.DEVICEDRIVER_ONF_TR_532],
         }
     ]),
-    (P4L1ServiceHandler, [
+    (P4DummyL1ServiceHandler, [
         {
             FilterFieldEnum.SERVICE_TYPE: ServiceTypeEnum.SERVICETYPE_L1NM,
             FilterFieldEnum.DEVICE_DRIVER: DeviceDriverEnum.DEVICEDRIVER_P4,
diff --git a/src/service/service/service_handlers/p4_l1/__init__.py b/src/service/service/service_handlers/p4_dummy_l1/__init__.py
similarity index 100%
rename from src/service/service/service_handlers/p4_l1/__init__.py
rename to src/service/service/service_handlers/p4_dummy_l1/__init__.py
diff --git a/src/service/service/service_handlers/p4_l1/p4_l1_service_handler.py b/src/service/service/service_handlers/p4_dummy_l1/p4_dummy_l1_service_handler.py
similarity index 99%
rename from src/service/service/service_handlers/p4_l1/p4_l1_service_handler.py
rename to src/service/service/service_handlers/p4_dummy_l1/p4_dummy_l1_service_handler.py
index b1ff9c600bf995bab250144c288d45d6a7945474..6e9141cafc4146e9a942f4b22d88700886c3e584 100644
--- a/src/service/service/service_handlers/p4_l1/p4_l1_service_handler.py
+++ b/src/service/service/service_handlers/p4_dummy_l1/p4_dummy_l1_service_handler.py
@@ -29,7 +29,7 @@ from service.service.task_scheduler.TaskExecutor import TaskExecutor
 
 LOGGER = logging.getLogger(__name__)
 
-METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'p4_l1'})
+METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'p4_dummy_l1'})
 
 def create_rule_set(endpoint_a, endpoint_b):
     return json_config_rule_set(
@@ -83,7 +83,7 @@ def find_names(uuid_a, uuid_b, device_endpoints):
 
     return (endpoint_a, endpoint_b)
 
-class P4L1ServiceHandler(_ServiceHandler):
+class P4DummyL1ServiceHandler(_ServiceHandler):
     def __init__(   # pylint: disable=super-init-not-called
         self, service : Service, task_executor : TaskExecutor, **settings
     ) -> None:
diff --git a/src/tests/p4-int-routing-acl/README.md b/src/tests/p4-fabric-tna/README.md
similarity index 73%
rename from src/tests/p4-int-routing-acl/README.md
rename to src/tests/p4-fabric-tna/README.md
index fa935e1b2eae2decb0e852ebd72b752c3d67ca28..fc49276a990694f3de9cbaef1c7d4272e92d6004 100644
--- a/src/tests/p4-int-routing-acl/README.md
+++ b/src/tests/p4-fabric-tna/README.md
@@ -1,6 +1,7 @@
 # Tests for P4 routing, ACL, and In-Band Network Telemetry functions
 
-This directory contains the necessary scripts and configurations to run tests atop a Stratum-based P4 whitebox that performs a set of network functions, including routing, access control list (ACL), and In-Band Network Telemetry (INT).
+This directory contains the necessary scripts and configurations to run tests atop a Stratum-based P4 whitebox that performs a set of network functions, including forwarding (L2), routing (L3), L3/L4 access control list (ACL), and In-Band Network Telemetry (INT).
+The P4 data plane is based on ONF's SD-Fabric implementation, titled [fabric-tna](https://github.com/stratum/fabric-tna)
 
 ## Prerequisites
 
@@ -16,6 +17,7 @@ pip3 install grpcio-tools
 ```
 
 The versions used for this test are:
+
 - `protobuf` 3.20.3
 - `grpclib` 0.4.4
 - `grpcio` 1.47.5
@@ -29,11 +31,11 @@ First we copy it to /usr/local/bin/:
 ```
 
 Then, we include this path to the PYTHONPATH:
+
 ```shell
 export PYTHONPATH="${PYTHONPATH}:/usr/local/bin/protoc-gen-grpclib_python"
 ```
 
-
 You need to build and deploy a software-based Stratum switch, before being able to use TFS to control it.
 To do so, follow the instructions in the `./topology` folder.
 
@@ -41,7 +43,7 @@ To do so, follow the instructions in the `./topology` folder.
 
 To conduct this test, follow the steps below.
 
-### TFS re-deploy
+### Deploy TFS
 
 ```shell
 cd ~/tfs-ctrl/
@@ -67,7 +69,7 @@ The `./setup.sh` script copies from this directory. If you need to change the P4
 
 ## Tests
 
-The following tests are implemented.
+A set of tests is implemented, each focusing on different aspects of TFS.
 For each of these tests, an auxiliary bash script allows to run it with less typing.
 
 |                 Test                 |              Bash Runner           |                Purpose             |
@@ -80,7 +82,7 @@ For each of these tests, an auxiliary bash script allows to run it with less typ
 
 Each of the tests above is described in detail below.
 
-### Step 1: Copy the necessary P4 artifacts into the TFS SBI service pod
+### Step 0: Copy the necessary P4 artifacts into the TFS SBI service pod
 
 The setup script copies the necessary artifacts to the SBI service pod.
 It should be run just once, after a fresh install of TFS.
@@ -89,34 +91,33 @@ If you `deploy/all.sh` again, you need to repeat this step.
 ```shell
 cd ~/tfs-ctrl/
 source my_deploy.sh && source tfs_runtime_env_vars.sh
-bash src/tests/p4-int-routing-acl/setup.sh
+bash src/tests/p4-fabric-tna/setup.sh
 ```
 
-### Step 2: Bootstrap topology
+### Step 1: Bootstrap topology
 
 The bootstrap script registers the context, topology, links, and devices to TFS.
 
 ```shell
 cd ~/tfs-ctrl/
-bash src/tests/p4-int-routing-acl/run_test_01_bootstrap.sh
+bash src/tests/p4-fabric-tna/run_test_01_bootstrap.sh
 ```
 
-### Step 3: Provision rules via the SBI API
+### Step 2: Manage L2, L3, ACL, and INT via the SBI API (rules)
 
-Implement routing, ACL, and INT functions by installing P4 rules to the Stratum switch via the TFS SBI API.
+Implement forwarding, routing, ACL, and INT network functions by installing P4 rules to the Stratum switch via the TFS SBI API.
+In this test, these rules are installed in batches, as the switch cannot digest all these rules at once.
 
 ```shell
 cd ~/tfs-ctrl/
-bash src/tests/p4-int-routing-acl/run_test_02_rules_provision.sh
+bash src/tests/p4-fabric-tna/run_test_02a_sbi_provision_int_l2_l3_acl.sh
 ```
 
-### Step 4: Deprovision rules via the SBI API
-
-Deprovision the routing, ACL, and INT network functions by removing the previously installed P4 rules (via the TFS SBI API) from the Stratum switch.
+Deprovision forwarding, routing, ACL, and INT network functions by removing the previously installed P4 rules (via the TFS SBI API) from the Stratum switch.
 
 ```shell
 cd ~/tfs-ctrl/
-bash src/tests/p4-int-routing-acl/run_test_03_rules_deprovision.sh
+bash src/tests/p4-fabric-tna/run_test_02b_sbi_deprovision_int_l2_l3_acl.sh
 ```
 
 ### Step 4: Deprovision topology
@@ -125,5 +126,12 @@ Delete all the objects (context, topology, links, devices) from TFS:
 
 ```shell
 cd ~/tfs-ctrl/
-bash src/tests/p4-int-routing-acl/run_test_04_cleanup.sh
+bash src/tests/p4-fabric-tna/run_test_07_cleanup.sh
+```
+
+Alternatively, a purge test is implemented; this test removes services, links, devices, topology, and context in this order.
+
+```shell
+cd ~/tfs-ctrl/
+bash src/tests/p4-fabric-tna/run_test_08_purge.sh
 ```
diff --git a/src/tests/p4-int-routing-acl/__init__.py b/src/tests/p4-fabric-tna/__init__.py
similarity index 100%
rename from src/tests/p4-int-routing-acl/__init__.py
rename to src/tests/p4-fabric-tna/__init__.py
diff --git a/src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-acl.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-acl.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-acl.json
rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-acl.json
diff --git a/src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-int-b1.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-int-b1.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-int-b1.json
rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-int-b1.json
diff --git a/src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-int-b2.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-int-b2.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-int-b2.json
rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-int-b2.json
diff --git a/src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-int-b3.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-int-b3.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-int-b3.json
rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-int-b3.json
diff --git a/src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-routing-corp.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-corp.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-routing-corp.json
rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-corp.json
diff --git a/src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-routing-edge.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-edge.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/descriptors/sbi-rules-insert-routing-edge.json
rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-edge.json
diff --git a/src/tests/p4-int-routing-acl/descriptors/sbi-rules-remove.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-remove.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/descriptors/sbi-rules-remove.json
rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-remove.json
diff --git a/src/tests/p4-int-routing-acl/descriptors/topology.json b/src/tests/p4-fabric-tna/descriptors/topology.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/descriptors/topology.json
rename to src/tests/p4-fabric-tna/descriptors/topology.json
diff --git a/src/tests/p4-int-routing-acl/p4src/README.md b/src/tests/p4-fabric-tna/p4src/README.md
similarity index 100%
rename from src/tests/p4-int-routing-acl/p4src/README.md
rename to src/tests/p4-fabric-tna/p4src/README.md
diff --git a/src/tests/p4-int-routing-acl/p4src/_pp.p4 b/src/tests/p4-fabric-tna/p4src/_pp.p4
similarity index 100%
rename from src/tests/p4-int-routing-acl/p4src/_pp.p4
rename to src/tests/p4-fabric-tna/p4src/_pp.p4
diff --git a/src/tests/p4-int-routing-acl/p4src/bmv2.json b/src/tests/p4-fabric-tna/p4src/bmv2.json
similarity index 100%
rename from src/tests/p4-int-routing-acl/p4src/bmv2.json
rename to src/tests/p4-fabric-tna/p4src/bmv2.json
diff --git a/src/tests/p4-int-routing-acl/p4src/p4info.txt b/src/tests/p4-fabric-tna/p4src/p4info.txt
similarity index 100%
rename from src/tests/p4-int-routing-acl/p4src/p4info.txt
rename to src/tests/p4-fabric-tna/p4src/p4info.txt
diff --git a/src/tests/p4-int-routing-acl/run_test_01_bootstrap.sh b/src/tests/p4-fabric-tna/run_test_01_bootstrap.sh
similarity index 89%
rename from src/tests/p4-int-routing-acl/run_test_01_bootstrap.sh
rename to src/tests/p4-fabric-tna/run_test_01_bootstrap.sh
index 76469ca55455aec65569a7c104f87e8d6673dec9..81d87476e396130cc90e3f75dc0873874005c3b0 100755
--- a/src/tests/p4-int-routing-acl/run_test_01_bootstrap.sh
+++ b/src/tests/p4-fabric-tna/run_test_01_bootstrap.sh
@@ -18,4 +18,4 @@
 # - tfs_runtime_env_vars.sh
 
 source tfs_runtime_env_vars.sh
-python3 -m pytest --verbose src/tests/p4-int-routing-acl/test_functional_bootstrap.py
+python3 -m pytest --verbose src/tests/p4-fabric-tna/tests-setup/test_functional_bootstrap.py
diff --git a/src/tests/p4-int-routing-acl/run_test_03_sbi_rules_deprovision.sh b/src/tests/p4-fabric-tna/run_test_02a_sbi_provision_int_l2_l3_acl.sh
similarity index 86%
rename from src/tests/p4-int-routing-acl/run_test_03_sbi_rules_deprovision.sh
rename to src/tests/p4-fabric-tna/run_test_02a_sbi_provision_int_l2_l3_acl.sh
index 4032c01dfbfe5666c1f825b8f778461f88a62026..a3ab51c2247a39005cb1502e386e835d7b076157 100755
--- a/src/tests/p4-int-routing-acl/run_test_03_sbi_rules_deprovision.sh
+++ b/src/tests/p4-fabric-tna/run_test_02a_sbi_provision_int_l2_l3_acl.sh
@@ -14,4 +14,4 @@
 # limitations under the License.
 
 source tfs_runtime_env_vars.sh
-python3 -m pytest --verbose src/tests/p4-int-routing-acl/test_functional_sbi_rules_deprovision.py
+python3 -m pytest --verbose src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_provision.py
diff --git a/src/tests/p4-fabric-tna/run_test_02b_sbi_deprovision_int_l2_l3_acl.sh b/src/tests/p4-fabric-tna/run_test_02b_sbi_deprovision_int_l2_l3_acl.sh
new file mode 100755
index 0000000000000000000000000000000000000000..49a686638775ee261636f9600c11164e6838d105
--- /dev/null
+++ b/src/tests/p4-fabric-tna/run_test_02b_sbi_deprovision_int_l2_l3_acl.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source tfs_runtime_env_vars.sh
+python3 -m pytest --verbose src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_deprovision.py
diff --git a/src/tests/p4-int-routing-acl/run_test_02_sbi_rules_provision.sh b/src/tests/p4-fabric-tna/run_test_07_cleanup.sh
similarity index 87%
rename from src/tests/p4-int-routing-acl/run_test_02_sbi_rules_provision.sh
rename to src/tests/p4-fabric-tna/run_test_07_cleanup.sh
index 7c485d4019f45286ffc3909fcdd72278842afa3c..c7b829168e956b2bcc0c2ee1a65cfdda66f20180 100755
--- a/src/tests/p4-int-routing-acl/run_test_02_sbi_rules_provision.sh
+++ b/src/tests/p4-fabric-tna/run_test_07_cleanup.sh
@@ -14,4 +14,4 @@
 # limitations under the License.
 
 source tfs_runtime_env_vars.sh
-python3 -m pytest --verbose src/tests/p4-int-routing-acl/test_functional_sbi_rules_provision.py
+python3 -m pytest --verbose src/tests/p4-fabric-tna/tests-setup/test_functional_cleanup.py
diff --git a/src/tests/p4-int-routing-acl/run_test_06_cleanup.sh b/src/tests/p4-fabric-tna/run_test_08_purge.sh
similarity index 88%
rename from src/tests/p4-int-routing-acl/run_test_06_cleanup.sh
rename to src/tests/p4-fabric-tna/run_test_08_purge.sh
index 917a2af2dab0ab1b9d0d05ad272c6494486d9580..9aef079f1919a8131e016f19a0b3064d6836e7c6 100755
--- a/src/tests/p4-int-routing-acl/run_test_06_cleanup.sh
+++ b/src/tests/p4-fabric-tna/run_test_08_purge.sh
@@ -14,4 +14,4 @@
 # limitations under the License.
 
 source tfs_runtime_env_vars.sh
-python3 -m pytest --verbose src/tests/p4-int-routing-acl/test_functional_cleanup.py
+python3 -m pytest --verbose src/tests/p4-fabric-tna/tests-setup/test_functional_purge.py
diff --git a/src/tests/p4-int-routing-acl/setup.sh b/src/tests/p4-fabric-tna/setup.sh
similarity index 80%
rename from src/tests/p4-int-routing-acl/setup.sh
rename to src/tests/p4-fabric-tna/setup.sh
index c771642769fe528fe1179909ab0b8edb768f7264..9418ac3d7132eca5d08db44d73441922aa2be228 100755
--- a/src/tests/p4-int-routing-acl/setup.sh
+++ b/src/tests/p4-fabric-tna/setup.sh
@@ -18,5 +18,5 @@ export POD_NAME=$(kubectl get pods -n=tfs | grep device | awk '{print $1}')
 
 kubectl exec ${POD_NAME} -n=tfs -c=server -- mkdir -p /root/p4
 
-kubectl cp src/tests/p4-int-routing-acl/p4src/p4info.txt tfs/${POD_NAME}:/root/p4 -c=server
-kubectl cp src/tests/p4-int-routing-acl/p4src/bmv2.json tfs/${POD_NAME}:/root/p4 -c=server
+kubectl cp src/tests/p4-fabric-tna/p4src/p4info.txt tfs/${POD_NAME}:/root/p4 -c=server
+kubectl cp src/tests/p4-fabric-tna/p4src/bmv2.json tfs/${POD_NAME}:/root/p4 -c=server
diff --git a/src/tests/p4-int-routing-acl/test_functional_sbi_rules_deprovision.py b/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_deprovision.py
similarity index 99%
rename from src/tests/p4-int-routing-acl/test_functional_sbi_rules_deprovision.py
rename to src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_deprovision.py
index 2d54ae9088600381a000722608bd39eb49483a03..6d5f7dfd2b2207b1a98bcc516259f841285fdb9d 100644
--- a/src/tests/p4-int-routing-acl/test_functional_sbi_rules_deprovision.py
+++ b/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_deprovision.py
@@ -18,7 +18,7 @@ from common.tools.grpc.Tools import grpc_message_to_json_string
 from context.client.ContextClient import ContextClient
 from device.client.DeviceClient import DeviceClient
 from tests.Fixtures import context_client, device_client   # pylint: disable=unused-import
-from test_common import *
+from tests.tools.test_tools_p4 import *
 
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
diff --git a/src/tests/p4-int-routing-acl/test_functional_sbi_rules_provision.py b/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_provision.py
similarity index 99%
rename from src/tests/p4-int-routing-acl/test_functional_sbi_rules_provision.py
rename to src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_provision.py
index 86a82d2129e495f3c3be9f9ea7b67b24d27a8db7..49d9aba4d504477d1079aa55cefc607368ee79b8 100644
--- a/src/tests/p4-int-routing-acl/test_functional_sbi_rules_provision.py
+++ b/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_provision.py
@@ -18,7 +18,7 @@ from common.tools.grpc.Tools import grpc_message_to_json_string
 from context.client.ContextClient import ContextClient
 from device.client.DeviceClient import DeviceClient
 from tests.Fixtures import context_client, device_client # pylint: disable=unused-import
-from test_common import *
+from tests.tools.test_tools_p4 import *
 
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
diff --git a/src/tests/p4-int-routing-acl/test_functional_bootstrap.py b/src/tests/p4-fabric-tna/tests-setup/test_functional_bootstrap.py
similarity index 98%
rename from src/tests/p4-int-routing-acl/test_functional_bootstrap.py
rename to src/tests/p4-fabric-tna/tests-setup/test_functional_bootstrap.py
index b5b72cc331ea1c7bf6e57aefc484532d66cb8504..2f9130ad000f406c7dab6de828c314670ffaa173 100644
--- a/src/tests/p4-int-routing-acl/test_functional_bootstrap.py
+++ b/src/tests/p4-fabric-tna/tests-setup/test_functional_bootstrap.py
@@ -19,7 +19,7 @@ from common.tools.descriptor.Loader import DescriptorLoader, \
 from context.client.ContextClient import ContextClient
 from device.client.DeviceClient import DeviceClient
 from tests.Fixtures import context_client, device_client # pylint: disable=unused-import
-from test_common import *
+from tests.tools.test_tools_p4 import *
 
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
diff --git a/src/tests/p4-int-routing-acl/test_functional_cleanup.py b/src/tests/p4-fabric-tna/tests-setup/test_functional_cleanup.py
similarity index 94%
rename from src/tests/p4-int-routing-acl/test_functional_cleanup.py
rename to src/tests/p4-fabric-tna/tests-setup/test_functional_cleanup.py
index fc29be24d5bdc643cb15f09eb69fe288c965687e..4d98c9e0500281c4e8dfd6f43de833c4ad3411fd 100644
--- a/src/tests/p4-int-routing-acl/test_functional_cleanup.py
+++ b/src/tests/p4-fabric-tna/tests-setup/test_functional_cleanup.py
@@ -12,13 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import logging, os
-from common.Constants import DEFAULT_CONTEXT_NAME
+import logging
 from common.tools.descriptor.Loader import DescriptorLoader, validate_empty_scenario
 from context.client.ContextClient import ContextClient
 from device.client.DeviceClient import DeviceClient
 from tests.Fixtures import context_client, device_client # pylint: disable=unused-import
-from test_common import *
+from tests.tools.test_tools_p4 import *
 
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
diff --git a/src/tests/p4-fabric-tna/tests-setup/test_functional_purge.py b/src/tests/p4-fabric-tna/tests-setup/test_functional_purge.py
new file mode 100644
index 0000000000000000000000000000000000000000..ba37fbd89c2eea9ab6e3bae84fcfb8669f9a4e78
--- /dev/null
+++ b/src/tests/p4-fabric-tna/tests-setup/test_functional_purge.py
@@ -0,0 +1,81 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+from common.proto.context_pb2 import ServiceId, DeviceId, LinkId, ServiceStatusEnum, ServiceTypeEnum
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.object_factory.Service import json_service_id
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from service.client.ServiceClient import ServiceClient
+from tests.Fixtures import context_client, device_client, service_client # pylint: disable=unused-import
+from tests.tools.test_tools_p4 import *
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+def test_clean_services(
+    context_client : ContextClient,  # pylint: disable=redefined-outer-name
+    service_client : ServiceClient  # pylint: disable=redefined-outer-name
+) -> None:
+    response = context_client.ListServices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response)))
+    
+    for service in response.services:
+        service_id = service.service_id
+        assert service_id
+
+        service_uuid = service_id.service_uuid.uuid
+        context_uuid = service_id.context_id.context_uuid.uuid
+        assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        assert service.service_type == ServiceTypeEnum.SERVICETYPE_INT
+
+        # Delete service
+        service_client.DeleteService(ServiceId(**json_service_id(service_uuid, json_context_id(context_uuid))))
+
+def test_clean_links(
+    context_client : ContextClient,  # pylint: disable=redefined-outer-name
+) -> None:
+    response = context_client.ListLinks(ADMIN_CONTEXT_ID)
+    
+    for link in response.links:
+        link_id = link.link_id
+
+        # Delete link
+        context_client.RemoveLink(LinkId(**link_id))
+
+def test_clean_devices(
+    context_client : ContextClient,  # pylint: disable=redefined-outer-name
+    device_client : DeviceClient   # pylint: disable=redefined-outer-name
+) -> None:
+    response = context_client.ListDevices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Devices[{:d}] = {:s}'.format(len(response.devices), grpc_message_to_json_string(response)))
+    
+    for device in response.devices:
+        device_id = device.device_id
+
+        # Delete device
+        device_client.DeleteDevice(DeviceId(**device_id))
+
+def test_clean_context(
+    context_client : ContextClient  # pylint: disable=redefined-outer-name
+) -> None:
+    # Verify the scenario has no services/slices
+    response = context_client.ListTopologies(ADMIN_CONTEXT_ID)
+
+    for topology in response.topologies:
+        topology_id = topology.topology_id
+        response = context_client.RemoveTopology(topology_id)
+
+    response = context_client.RemoveContext(ADMIN_CONTEXT_ID)
diff --git a/src/tests/p4-int-routing-acl/topology/README.md b/src/tests/p4-fabric-tna/topology/README.md
similarity index 100%
rename from src/tests/p4-int-routing-acl/topology/README.md
rename to src/tests/p4-fabric-tna/topology/README.md
diff --git a/src/tests/p4-int-routing-acl/topology/p4-switch-conf-common.sh b/src/tests/p4-fabric-tna/topology/p4-switch-conf-common.sh
similarity index 100%
rename from src/tests/p4-int-routing-acl/topology/p4-switch-conf-common.sh
rename to src/tests/p4-fabric-tna/topology/p4-switch-conf-common.sh
diff --git a/src/tests/p4-int-routing-acl/topology/p4-switch-setup.sh b/src/tests/p4-fabric-tna/topology/p4-switch-setup.sh
similarity index 100%
rename from src/tests/p4-int-routing-acl/topology/p4-switch-setup.sh
rename to src/tests/p4-fabric-tna/topology/p4-switch-setup.sh
diff --git a/src/tests/p4-int-routing-acl/topology/p4-switch-tear-down.sh b/src/tests/p4-fabric-tna/topology/p4-switch-tear-down.sh
similarity index 100%
rename from src/tests/p4-int-routing-acl/topology/p4-switch-tear-down.sh
rename to src/tests/p4-fabric-tna/topology/p4-switch-tear-down.sh
diff --git a/src/tests/p4-int-routing-acl/topology/p4-switch-three-port-chassis-config-phy.pb.txt b/src/tests/p4-fabric-tna/topology/p4-switch-three-port-chassis-config-phy.pb.txt
similarity index 100%
rename from src/tests/p4-int-routing-acl/topology/p4-switch-three-port-chassis-config-phy.pb.txt
rename to src/tests/p4-fabric-tna/topology/p4-switch-three-port-chassis-config-phy.pb.txt
diff --git a/src/tests/p4-int-routing-acl/topology/run-stratum.sh b/src/tests/p4-fabric-tna/topology/run-stratum.sh
similarity index 100%
rename from src/tests/p4-int-routing-acl/topology/run-stratum.sh
rename to src/tests/p4-fabric-tna/topology/run-stratum.sh
diff --git a/src/tests/p4-int-routing-acl/test_common.py b/src/tests/p4-int-routing-acl/test_common.py
deleted file mode 100644
index f2d00f1dc01815d3567fd371f65f35f1bf078209..0000000000000000000000000000000000000000
--- a/src/tests/p4-int-routing-acl/test_common.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-from common.Constants import DEFAULT_CONTEXT_NAME
-from common.proto.context_pb2 import ContextId, DeviceOperationalStatusEnum
-from common.tools.object_factory.Context import json_context_id
-
-# Context info
-CONTEXT_NAME_P4 = DEFAULT_CONTEXT_NAME
-ADMIN_CONTEXT_ID = ContextId(**json_context_id(CONTEXT_NAME_P4))
-
-# Device and rule cardinality variables
-DEV_NB = 4
-CONNECTION_RULES = 3
-ENDPOINT_RULES = 3
-DATAPLANE_RULES_NB_INT_B1 = 5
-DATAPLANE_RULES_NB_INT_B2 = 6
-DATAPLANE_RULES_NB_INT_B3 = 8
-DATAPLANE_RULES_NB_RT_EDGE = 7
-DATAPLANE_RULES_NB_RT_CORP = 7
-DATAPLANE_RULES_NB_ACL = 1
-DATAPLANE_RULES_NB_TOT = \
-    DATAPLANE_RULES_NB_INT_B1 +\
-    DATAPLANE_RULES_NB_INT_B2 +\
-    DATAPLANE_RULES_NB_INT_B3 +\
-    DATAPLANE_RULES_NB_RT_EDGE +\
-    DATAPLANE_RULES_NB_RT_CORP +\
-    DATAPLANE_RULES_NB_ACL
-
-# Service-related variables
-SVC_NB = 1
-NO_SERVICES = 0
-NO_SLICES = 0
-
-# Topology descriptor
-DESC_TOPO = os.path.join(
-    os.path.dirname(
-        os.path.abspath(__file__)
-    ),
-    'descriptors', 'topology.json'
-)
-
-# SBI rule insertion descriptors
-# The switch cannot digest all rules at once, hence we insert in batches
-DESC_FILE_RULES_INSERT_INT_B1 = os.path.join(
-    os.path.dirname(
-        os.path.abspath(__file__)
-    ),
-    'descriptors', 'sbi-rules-insert-int-b1.json'
-)
-DESC_FILE_RULES_INSERT_INT_B2 = os.path.join(
-    os.path.dirname(
-        os.path.abspath(__file__)
-    ),
-    'descriptors', 'sbi-rules-insert-int-b2.json'
-)
-DESC_FILE_RULES_INSERT_INT_B3 = os.path.join(
-    os.path.dirname(
-        os.path.abspath(__file__)
-    ),
-    'descriptors', 'sbi-rules-insert-int-b3.json'
-)
-DESC_FILE_RULES_INSERT_ROUTING_EDGE = os.path.join(
-    os.path.dirname(
-        os.path.abspath(__file__)
-    ),
-    'descriptors', 'sbi-rules-insert-routing-edge.json'
-)
-DESC_FILE_RULES_INSERT_ROUTING_CORP = os.path.join(
-    os.path.dirname(
-        os.path.abspath(__file__)
-    ),
-    'descriptors', 'sbi-rules-insert-routing-corp.json'
-)
-DESC_FILE_RULES_INSERT_ACL = os.path.join(
-    os.path.dirname(
-        os.path.abspath(__file__)
-    ),
-    'descriptors', 'sbi-rules-insert-acl.json'
-)
-
-# SBI rule deletion descriptor
-DESC_FILE_RULES_DELETE_ALL = os.path.join(
-    os.path.dirname(
-        os.path.abspath(__file__)
-    ),
-    'descriptors', 'sbi-rules-remove.json'
-)
-
-def verify_number_of_rules(devices, desired_rules_nb):
-    # Iterate all devices
-    for device in devices:
-        # Skip non-P4 devices
-        if device.device_type != "p4-switch": continue
-
-        # We want the device to be active
-        assert \
-            device.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
-
-        # Get the configuration rules of this device
-        config_rules = device.device_config.config_rules
-
-        # Expected rule cardinality
-        assert len(config_rules) == desired_rules_nb
diff --git a/src/tests/tools/test_tools_p4.py b/src/tests/tools/test_tools_p4.py
new file mode 100644
index 0000000000000000000000000000000000000000..4557fef61e1f495706a28a5b5646ff97edcfaa54
--- /dev/null
+++ b/src/tests/tools/test_tools_p4.py
@@ -0,0 +1,172 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, DeviceOperationalStatusEnum,\
+    DeviceDriverEnum, ServiceTypeEnum, ServiceStatusEnum
+from common.tools.object_factory.Context import json_context_id
+
+# Context info
+CONTEXT_NAME_P4 = DEFAULT_CONTEXT_NAME
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(CONTEXT_NAME_P4))
+
+# Device and rule cardinality variables
+DEV_NB = 4
+P4_DEV_NB = 1
+CONNECTION_RULES = 3
+ENDPOINT_RULES = 3
+INT_RULES = 19
+L2_RULES = 8
+L3_RULES = 8
+ACL_RULES = 1
+
+DATAPLANE_RULES_NB_INT_B1 = 5
+DATAPLANE_RULES_NB_INT_B2 = 6
+DATAPLANE_RULES_NB_INT_B3 = 8
+DATAPLANE_RULES_NB_RT_EDGE = 7
+DATAPLANE_RULES_NB_RT_CORP = 7
+DATAPLANE_RULES_NB_ACL = 1
+DATAPLANE_RULES_NB_TOT = \
+    DATAPLANE_RULES_NB_INT_B1 +\
+    DATAPLANE_RULES_NB_INT_B2 +\
+    DATAPLANE_RULES_NB_INT_B3 +\
+    DATAPLANE_RULES_NB_RT_EDGE +\
+    DATAPLANE_RULES_NB_RT_CORP +\
+    DATAPLANE_RULES_NB_ACL
+
+# Service-related variables
+SVC_NB = 1
+NO_SERVICES = 0
+NO_SLICES = 0
+
+TEST_PATH = os.path.join(
+    os.path.dirname(os.path.dirname(
+        os.path.abspath(__file__)
+    )) + '/p4-fabric-tna/descriptors')
+assert os.path.exists(TEST_PATH), "Invalid path to P4 SD-Fabric tests"
+
+# Topology descriptor
+DESC_TOPO = os.path.join(TEST_PATH, 'topology.json')
+assert os.path.exists(DESC_TOPO), "Invalid path to the SD-Fabric topology descriptor"
+
+# SBI descriptors
+# The switch cannot digest all rules at once, hence we insert in batches
+DESC_FILE_RULES_INSERT_INT_B1 = os.path.join(TEST_PATH, 'sbi-rules-insert-int-b1.json')
+assert os.path.exists(DESC_FILE_RULES_INSERT_INT_B1),\
+    "Invalid path to the SD-Fabric INT SBI descriptor (batch #1)"
+
+DESC_FILE_RULES_INSERT_INT_B2 = os.path.join(TEST_PATH, 'sbi-rules-insert-int-b2.json')
+assert os.path.exists(DESC_FILE_RULES_INSERT_INT_B2),\
+    "Invalid path to the SD-Fabric INT SBI descriptor (batch #2)"
+
+DESC_FILE_RULES_INSERT_INT_B3 = os.path.join(TEST_PATH, 'sbi-rules-insert-int-b3.json')
+assert os.path.exists(DESC_FILE_RULES_INSERT_INT_B3),\
+    "Invalid path to the SD-Fabric INT SBI descriptor (batch #3)"
+
+DESC_FILE_RULES_INSERT_ROUTING_EDGE = os.path.join(TEST_PATH, 'sbi-rules-insert-routing-edge.json')
+assert os.path.exists(DESC_FILE_RULES_INSERT_ROUTING_EDGE),\
+    "Invalid path to the SD-Fabric routing SBI descriptor (domain1-side)"
+
+DESC_FILE_RULES_INSERT_ROUTING_CORP = os.path.join(TEST_PATH, 'sbi-rules-insert-routing-corp.json')
+assert os.path.exists(DESC_FILE_RULES_INSERT_ROUTING_CORP),\
+    "Invalid path to the SD-Fabric routing SBI descriptor (domain2-side)"
+
+DESC_FILE_RULES_INSERT_ACL = os.path.join(TEST_PATH, 'sbi-rules-insert-acl.json')
+assert os.path.exists(DESC_FILE_RULES_INSERT_ACL),\
+    "Invalid path to the SD-Fabric ACL SBI descriptor"
+
+DESC_FILE_RULES_DELETE_ALL = os.path.join(TEST_PATH, 'sbi-rules-remove.json')
+assert os.path.exists(DESC_FILE_RULES_DELETE_ALL),\
+    "Invalid path to the SD-Fabric rule removal SBI descriptor"
+
+# Service descriptors
+DESC_FILE_SERVICE_CREATE_INT = os.path.join(TEST_PATH, 'service-create-int.json')
+assert os.path.exists(DESC_FILE_SERVICE_CREATE_INT),\
+    "Invalid path to the SD-Fabric INT service descriptor"
+
+DESC_FILE_SERVICE_CREATE_L2 = os.path.join(TEST_PATH, 'service-create-l2.json')
+assert os.path.exists(DESC_FILE_SERVICE_CREATE_L2),\
+    "Invalid path to the SD-Fabric L2 service descriptor"
+
+DESC_FILE_SERVICE_CREATE_L3 = os.path.join(TEST_PATH, 'service-create-l3.json')
+assert os.path.exists(DESC_FILE_SERVICE_CREATE_L3),\
+    "Invalid path to the SD-Fabric L3 service descriptor"
+
+DESC_FILE_SERVICE_CREATE_ACL = os.path.join(TEST_PATH, 'service-create-acl.json')
+assert os.path.exists(DESC_FILE_SERVICE_CREATE_ACL),\
+    "Invalid path to the SD-Fabric ACL service descriptor"
+
+def identify_number_of_p4_devices(devices) -> int:
+    p4_dev_no = 0
+
+    # Iterate all devices
+    for device in devices:
+        # Skip non-P4 devices
+        if not DeviceDriverEnum.DEVICEDRIVER_P4 in device.device_drivers: continue
+
+        p4_dev_no += 1
+    
+    return p4_dev_no
+
+def get_number_of_rules(devices) -> int:
+    total_rules_no = 0
+
+    # Iterate all devices
+    for device in devices:
+        # Skip non-P4 devices
+        if not DeviceDriverEnum.DEVICEDRIVER_P4 in device.device_drivers: continue
+
+        # We want the device to be active
+        assert device.device_operational_status == \
+            DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+
+        # Get the configuration rules of this device
+        config_rules = device.device_config.config_rules
+
+        # Expected rule cardinality
+        total_rules_no += len(config_rules)
+    
+    return total_rules_no
+
+def verify_number_of_rules(devices, desired_rules_nb : int) -> None:
+    # Iterate all devices
+    for device in devices:
+        # Skip non-P4 devices
+        if not DeviceDriverEnum.DEVICEDRIVER_P4 in device.device_drivers: continue
+
+        # We want the device to be active
+        assert device.device_operational_status == \
+            DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+
+        # Get the configuration rules of this device
+        config_rules = device.device_config.config_rules
+
+        # Expected rule cardinality
+        assert len(config_rules) == desired_rules_nb
+
+def verify_active_service_type(services, target_service_type : ServiceTypeEnum) -> bool: # type: ignore
+    # Iterate all services
+    for service in services:
+        # Ignore services of other types
+        if service.service_type != target_service_type:
+            continue
+
+        service_id = service.service_id
+        assert service_id
+        assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        assert service.service_config
+        return True
+    
+    return False