From df5542d36092851b4961b8513c5e035252a6056f Mon Sep 17 00:00:00 2001 From: "Georgios P. Katsikas" Date: Tue, 13 May 2025 09:14:23 +0300 Subject: [PATCH 1/4] fix: naming and logging in fabric-tna test --- src/common/tools/descriptor/Tools.py | 2 +- .../p4_fabric_tna_acl_service_handler.py | 12 +++--- .../p4_fabric_tna_int_service_handler.py | 10 +++-- ...p4_fabric_tna_l2_simple_service_handler.py | 12 +++--- .../p4_fabric_tna_l3_service_handler.py | 12 +++--- ...son => sbi-rules-insert-routing-east.json} | 0 ...son => sbi-rules-insert-routing-west.json} | 0 ...ce-create-acl.json => service-p4-acl.json} | 0 ...ce-create-int.json => service-p4-int.json} | 6 +-- ...-simple.json => service-p4-l2-simple.json} | 0 ...vice-create-l3.json => service-p4-l3.json} | 0 .../p4-fabric-tna/descriptors/topology.json | 31 +++++++------ .../test_functional_sbi_rules_deprovision.py | 20 +++++++-- .../test_functional_sbi_rules_provision.py | 43 +++++++++++++------ ...test_functional_service_deprovision_acl.py | 11 ++++- ...test_functional_service_deprovision_int.py | 11 ++++- .../test_functional_service_deprovision_l2.py | 11 ++++- .../test_functional_service_deprovision_l3.py | 11 ++++- .../test_functional_service_provision_acl.py | 13 +++++- .../test_functional_service_provision_int.py | 13 +++++- .../test_functional_service_provision_l2.py | 13 +++++- .../test_functional_service_provision_l3.py | 13 +++++- .../tests-setup/test_functional_bootstrap.py | 2 +- .../tests-setup/test_functional_cleanup.py | 2 +- .../tests-setup/test_functional_purge.py | 9 ++-- src/tests/tools/test_tools_p4.py | 32 +++++++------- 26 files changed, 202 insertions(+), 87 deletions(-) rename src/tests/p4-fabric-tna/descriptors/{sbi-rules-insert-routing-corp.json => sbi-rules-insert-routing-east.json} (100%) rename src/tests/p4-fabric-tna/descriptors/{sbi-rules-insert-routing-edge.json => sbi-rules-insert-routing-west.json} (100%) rename src/tests/p4-fabric-tna/descriptors/{service-create-acl.json => service-p4-acl.json} (100%) rename src/tests/p4-fabric-tna/descriptors/{service-create-int.json => service-p4-int.json} (91%) rename src/tests/p4-fabric-tna/descriptors/{service-create-l2-simple.json => service-p4-l2-simple.json} (100%) rename src/tests/p4-fabric-tna/descriptors/{service-create-l3.json => service-p4-l3.json} (100%) diff --git a/src/common/tools/descriptor/Tools.py b/src/common/tools/descriptor/Tools.py index 07bc18d31..361ddbc9f 100644 --- a/src/common/tools/descriptor/Tools.py +++ b/src/common/tools/descriptor/Tools.py @@ -148,7 +148,7 @@ def split_links_by_type(links : List[Dict]) -> Dict[str, List[Dict]]: raise Exception(MSG.format(str(link))) link_type = LinkTypeEnum.Value(str_link_type) - if link_type in {LinkTypeEnum.LINKTYPE_UNKNOWN, LinkTypeEnum.LINKTYPE_COPPER, LinkTypeEnum.LINKTYPE_RADIO}: + if link_type in {LinkTypeEnum.LINKTYPE_UNKNOWN, LinkTypeEnum.LINKTYPE_COPPER, LinkTypeEnum.LINKTYPE_RADIO, LinkTypeEnum.LINKTYPE_MANAGEMENT}: typed_links['normal'].append(link) elif link_type in {LinkTypeEnum.LINKTYPE_FIBER}: typed_links['optical'].append(link) diff --git a/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py index b57086a29..510b59ebb 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py @@ -140,8 +140,9 @@ class P4FabricACLServiceHandler(_ServiceHandler): # You should no longer visit this device port again visited.add(dev_port_key) - LOGGER.info("Installed {}/{} ACL rules on device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) + if applied_rules > 0: + LOGGER.info("Installed {}/{} ACL rules on device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) return results @@ -214,7 +215,7 @@ class P4FabricACLServiceHandler(_ServiceHandler): json_config_rules=rules ) except Exception as ex: - LOGGER.error("Failed to insert ACL rules on device {} due to {}".format(device.name, ex)) + LOGGER.error("Failed to delete ACL rules from device {} due to {}".format(device.name, ex)) finally: rules.clear() @@ -225,8 +226,9 @@ class P4FabricACLServiceHandler(_ServiceHandler): # You should no longer visit this device port again visited.add(dev_port_key) - LOGGER.info("Deleted {}/{} ACL rules from device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) + if applied_rules > 0: + LOGGER.info("Deleted {}/{} ACL rules from device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) return results diff --git a/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py index dd19c4f89..c5ecdd682 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py @@ -126,8 +126,9 @@ class P4FabricINTServiceHandler(_ServiceHandler): # You should no longer visit this device again visited.add(device.name) - LOGGER.info("Installed {}/{} INT rules on device {}".format( - applied_rules, actual_rules, device.name)) + if applied_rules > 0: + LOGGER.info("Installed {}/{} INT rules on device {}".format( + applied_rules, actual_rules, device.name)) return results @@ -191,8 +192,9 @@ class P4FabricINTServiceHandler(_ServiceHandler): # You should no longer visit this device again visited.add(device.name) - LOGGER.info("Deleted {}/{} INT rules from device {}".format( - applied_rules, actual_rules, device.name)) + if applied_rules > 0: + LOGGER.info("Deleted {}/{} INT rules from device {}".format( + applied_rules, actual_rules, device.name)) return results diff --git a/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py index 8d4aaf081..c24bdc880 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py @@ -131,8 +131,9 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): # You should no longer visit this device port again visited.add(dev_port_key) - LOGGER.info("Installed {}/{} L2 rules on device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) + if applied_rules > 0: + LOGGER.info("Installed {}/{} L2 rules on device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) return results @@ -197,7 +198,7 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): json_config_rules=rules ) except Exception as ex: - LOGGER.error("Failed to insert L2 rules on device {} due to {}".format(device.name, ex)) + LOGGER.error("Failed to delete L2 rules from device {} due to {}".format(device.name, ex)) finally: rules.clear() @@ -208,8 +209,9 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): # You should no longer visit this device port again visited.add(dev_port_key) - LOGGER.info("Deleted {}/{} L2 rules from device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) + if applied_rules > 0: + LOGGER.info("Deleted {}/{} L2 rules from device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) return results diff --git a/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py index 4b013328e..c97d38829 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py @@ -129,8 +129,9 @@ class P4FabricL3ServiceHandler(_ServiceHandler): # You should no longer visit this device port again visited.add(dev_port_key) - LOGGER.info("Installed {}/{} L3 rules on device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) + if applied_rules > 0: + LOGGER.info("Installed {}/{} L3 rules on device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) return results @@ -195,7 +196,7 @@ class P4FabricL3ServiceHandler(_ServiceHandler): json_config_rules=rules ) except Exception as ex: - LOGGER.error("Failed to insert L3 rules on device {} due to {}".format(device.name, ex)) + LOGGER.error("Failed to delete L3 rules from device {} due to {}".format(device.name, ex)) finally: rules.clear() @@ -206,8 +207,9 @@ class P4FabricL3ServiceHandler(_ServiceHandler): # You should no longer visit this device port again visited.add(dev_port_key) - LOGGER.info("Deleted {}/{} L3 rules from device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) + if applied_rules > 0: + LOGGER.info("Deleted {}/{} L3 rules from device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) return results diff --git a/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-corp.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-east.json similarity index 100% rename from src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-corp.json rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-east.json diff --git a/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-edge.json b/src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-west.json similarity index 100% rename from src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-edge.json rename to src/tests/p4-fabric-tna/descriptors/sbi-rules-insert-routing-west.json diff --git a/src/tests/p4-fabric-tna/descriptors/service-create-acl.json b/src/tests/p4-fabric-tna/descriptors/service-p4-acl.json similarity index 100% rename from src/tests/p4-fabric-tna/descriptors/service-create-acl.json rename to src/tests/p4-fabric-tna/descriptors/service-p4-acl.json diff --git a/src/tests/p4-fabric-tna/descriptors/service-create-int.json b/src/tests/p4-fabric-tna/descriptors/service-p4-int.json similarity index 91% rename from src/tests/p4-fabric-tna/descriptors/service-create-int.json rename to src/tests/p4-fabric-tna/descriptors/service-p4-int.json index 785468f68..7bffd72f1 100644 --- a/src/tests/p4-fabric-tna/descriptors/service-create-int.json +++ b/src/tests/p4-fabric-tna/descriptors/service-p4-int.json @@ -37,9 +37,9 @@ } }, "int_collector_info": { - "mac": "46:e4:58:c6:74:53", - "ip": "192.168.5.137", - "port": 32766, + "mac": "3e:87:de:3d:6d:33", + "ip": "192.168.5.131", + "port": 12345, "vlan_id": 4094 } } diff --git a/src/tests/p4-fabric-tna/descriptors/service-create-l2-simple.json b/src/tests/p4-fabric-tna/descriptors/service-p4-l2-simple.json similarity index 100% rename from src/tests/p4-fabric-tna/descriptors/service-create-l2-simple.json rename to src/tests/p4-fabric-tna/descriptors/service-p4-l2-simple.json diff --git a/src/tests/p4-fabric-tna/descriptors/service-create-l3.json b/src/tests/p4-fabric-tna/descriptors/service-p4-l3.json similarity index 100% rename from src/tests/p4-fabric-tna/descriptors/service-create-l3.json rename to src/tests/p4-fabric-tna/descriptors/service-p4-l3.json diff --git a/src/tests/p4-fabric-tna/descriptors/topology.json b/src/tests/p4-fabric-tna/descriptors/topology.json index 908faaa7d..619060e9e 100644 --- a/src/tests/p4-fabric-tna/descriptors/topology.json +++ b/src/tests/p4-fabric-tna/descriptors/topology.json @@ -10,20 +10,19 @@ { "device_id": {"device_uuid": {"uuid": "tfs-sdn-controller"}}, "name": "tfs-sdn-controller", - "device_type": "teraflowsdn", - "device_drivers": ["DEVICEDRIVER_IETF_L2VPN"], + "device_type": "ietf-slice", + "device_drivers": ["DEVICEDRIVER_IETF_SLICE"], "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_config": {"config_rules": [ - {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "192.168.5.137"}}, - {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "8003"}}, + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": { - "endpoints": [{"uuid": "mgmt", "name": "mgmt", "type": "mgmt-int"}], - "scheme": "http", "username": "admin", "password": "admin", "import_topology": "topology" + "endpoints": [{"uuid": "mgmt", "name": "mgmt", "type": "mgmt-int"}] }}} ]} }, { - "device_id": {"device_uuid": {"uuid": "edge-net"}}, + "device_id": {"device_uuid": {"uuid": "west-net"}}, "device_type": "network", "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_config": { @@ -37,7 +36,7 @@ } }, { - "device_id": {"device_uuid": {"uuid": "corporate-net"}}, + "device_id": {"device_uuid": {"uuid": "east-net"}}, "device_type": "network", "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_config": { @@ -81,26 +80,26 @@ ], "links": [ { - "link_id": {"link_uuid": {"uuid": "sw1/1==edge-net/eth1"}}, "link_type": "LINKTYPE_VIRTUAL", "link_endpoint_ids": [ + "link_id": {"link_uuid": {"uuid": "sw1/1==west-net/eth1"}}, "link_type": "LINKTYPE_COPPER", "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "sw1"}}, "endpoint_uuid": {"uuid": "1"}}, - {"device_id": {"device_uuid": {"uuid": "edge-net"}}, "endpoint_uuid": {"uuid": "eth1"}} + {"device_id": {"device_uuid": {"uuid": "west-net"}}, "endpoint_uuid": {"uuid": "eth1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "edge-net/eth1==sw1/1"}}, "link_type": "LINKTYPE_VIRTUAL", "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "edge-net"}}, "endpoint_uuid": {"uuid": "eth1"}}, + "link_id": {"link_uuid": {"uuid": "west-net/eth1==sw1/1"}}, "link_type": "LINKTYPE_COPPER", "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "west-net"}}, "endpoint_uuid": {"uuid": "eth1"}}, {"device_id": {"device_uuid": {"uuid": "sw1"}}, "endpoint_uuid": {"uuid": "1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "sw1/2==corporate-net/eth1"}}, "link_type": "LINKTYPE_VIRTUAL", "link_endpoint_ids": [ + "link_id": {"link_uuid": {"uuid": "sw1/2==east-net/eth1"}}, "link_type": "LINKTYPE_COPPER", "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "sw1"}}, "endpoint_uuid": {"uuid": "2"}}, - {"device_id": {"device_uuid": {"uuid": "corporate-net"}}, "endpoint_uuid": {"uuid": "eth1"}} + {"device_id": {"device_uuid": {"uuid": "east-net"}}, "endpoint_uuid": {"uuid": "eth1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "corporate-net/eth1==sw1/2"}}, "link_type": "LINKTYPE_VIRTUAL", "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "corporate-net"}}, "endpoint_uuid": {"uuid": "eth1"}}, + "link_id": {"link_uuid": {"uuid": "east-net/eth1==sw1/2"}}, "link_type": "LINKTYPE_COPPER", "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "east-net"}}, "endpoint_uuid": {"uuid": "eth1"}}, {"device_id": {"device_uuid": {"uuid": "sw1"}}, "endpoint_uuid": {"uuid": "2"}} ] }, diff --git a/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_deprovision.py b/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_deprovision.py index 6d5f7dfd2..f9b09ebd6 100644 --- a/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_deprovision.py +++ b/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_deprovision.py @@ -18,7 +18,21 @@ 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 tests.tools.test_tools_p4 import * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DESC_FILE_RULES_DELETE_ALL, + DEV_NB, + CONNECTION_RULES, + ENDPOINT_RULES, + DATAPLANE_RULES_NB_INT_B1, + DATAPLANE_RULES_NB_INT_B2, + DATAPLANE_RULES_NB_INT_B3, + DATAPLANE_RULES_NB_RT_WEST, + DATAPLANE_RULES_NB_RT_EAST, + DATAPLANE_RULES_NB_ACL, + DATAPLANE_RULES_NB_TOT, + verify_number_of_rules +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) @@ -60,8 +74,8 @@ def test_rules_before_removal( 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_RT_WEST + \ + DATAPLANE_RULES_NB_RT_EAST + \ DATAPLANE_RULES_NB_ACL assert desired_rules_nb == CONNECTION_RULES + ENDPOINT_RULES + DATAPLANE_RULES_NB_TOT verify_number_of_rules(response.devices, desired_rules_nb) diff --git a/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_provision.py b/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_provision.py index 49d9aba4d..afb7a6df3 100644 --- a/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_provision.py +++ b/src/tests/p4-fabric-tna/tests-sbi/test_functional_sbi_rules_provision.py @@ -18,7 +18,26 @@ 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 tests.tools.test_tools_p4 import * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DESC_FILE_RULES_INSERT_INT_B1, + DESC_FILE_RULES_INSERT_INT_B2, + DESC_FILE_RULES_INSERT_INT_B3, + DESC_FILE_RULES_INSERT_ROUTING_WEST, + DESC_FILE_RULES_INSERT_ROUTING_EAST, + DESC_FILE_RULES_INSERT_ACL, + DEV_NB, + CONNECTION_RULES, + ENDPOINT_RULES, + DATAPLANE_RULES_NB_INT_B1, + DATAPLANE_RULES_NB_INT_B2, + DATAPLANE_RULES_NB_INT_B3, + DATAPLANE_RULES_NB_RT_WEST, + DATAPLANE_RULES_NB_RT_EAST, + DATAPLANE_RULES_NB_ACL, + DATAPLANE_RULES_NB_TOT, + verify_number_of_rules +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) @@ -143,18 +162,18 @@ def test_rules_after_insertion_int_batch_3( DATAPLANE_RULES_NB_INT_B3 verify_number_of_rules(response.devices, desired_rules_nb) -def test_rules_insertion_routing_edge_batch_4( +def test_rules_insertion_routing_west_batch_4( context_client : ContextClient, # pylint: disable=redefined-outer-name device_client : DeviceClient # pylint: disable=redefined-outer-name ) -> None: # Load routing edge batch 4 rules for insertion descriptor_loader = DescriptorLoader( - descriptors_file=DESC_FILE_RULES_INSERT_ROUTING_EDGE, context_client=context_client, device_client=device_client + descriptors_file=DESC_FILE_RULES_INSERT_ROUTING_WEST, context_client=context_client, device_client=device_client ) results = descriptor_loader.process() check_descriptor_load_results(results, descriptor_loader) -def test_rules_after_insertion_routing_edge_batch_4( +def test_rules_after_insertion_routing_west_batch_4( context_client : ContextClient # pylint: disable=redefined-outer-name ) -> None: # State **after** inserting batch 4 of routing edge rules @@ -170,21 +189,21 @@ def test_rules_after_insertion_routing_edge_batch_4( DATAPLANE_RULES_NB_INT_B1 + \ DATAPLANE_RULES_NB_INT_B2 + \ DATAPLANE_RULES_NB_INT_B3 + \ - DATAPLANE_RULES_NB_RT_EDGE + DATAPLANE_RULES_NB_RT_WEST verify_number_of_rules(response.devices, desired_rules_nb) -def test_rules_insertion_routing_corp_batch_5( +def test_rules_insertion_routing_east_batch_5( context_client : ContextClient, # pylint: disable=redefined-outer-name device_client : DeviceClient # pylint: disable=redefined-outer-name ) -> None: # Load routing corp batch 5 rules for insertion descriptor_loader = DescriptorLoader( - descriptors_file=DESC_FILE_RULES_INSERT_ROUTING_CORP, context_client=context_client, device_client=device_client + descriptors_file=DESC_FILE_RULES_INSERT_ROUTING_EAST, context_client=context_client, device_client=device_client ) results = descriptor_loader.process() check_descriptor_load_results(results, descriptor_loader) -def test_rules_after_insertion_routing_corp_batch_5( +def test_rules_after_insertion_routing_east_batch_5( context_client : ContextClient # pylint: disable=redefined-outer-name ) -> None: # State **after** inserting batch 5 of routing corp rules @@ -200,8 +219,8 @@ def test_rules_after_insertion_routing_corp_batch_5( 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_RT_WEST + \ + DATAPLANE_RULES_NB_RT_EAST verify_number_of_rules(response.devices, desired_rules_nb) def test_rules_insertion_acl_batch_6( @@ -231,8 +250,8 @@ def test_rules_after_insertion_acl_batch_6( 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_RT_WEST + \ + DATAPLANE_RULES_NB_RT_EAST + \ DATAPLANE_RULES_NB_ACL assert desired_rules_nb == CONNECTION_RULES + ENDPOINT_RULES + DATAPLANE_RULES_NB_TOT verify_number_of_rules(response.devices, desired_rules_nb) diff --git a/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_acl.py b/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_acl.py index fcecbd2c7..a93691c46 100644 --- a/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_acl.py +++ b/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_acl.py @@ -15,11 +15,20 @@ import logging from common.proto.context_pb2 import ServiceId, ServiceStatusEnum, ServiceTypeEnum from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Service import json_service_id from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient from tests.Fixtures import context_client, service_client # pylint: disable=unused-import -from tests.tools.test_tools_p4 import * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DEV_NB, + P4_DEV_NB, + ACL_RULES, + identify_number_of_p4_devices, + get_number_of_rules, + verify_active_service_type +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) diff --git a/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_int.py b/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_int.py index f29f6b17c..cee498c8f 100644 --- a/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_int.py +++ b/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_int.py @@ -15,11 +15,20 @@ import logging from common.proto.context_pb2 import ServiceId, ServiceStatusEnum, ServiceTypeEnum from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Service import json_service_id from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient from tests.Fixtures import context_client, service_client # pylint: disable=unused-import -from tests.tools.test_tools_p4 import * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DEV_NB, + P4_DEV_NB, + INT_RULES, + identify_number_of_p4_devices, + get_number_of_rules, + verify_active_service_type +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) diff --git a/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_l2.py b/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_l2.py index 87ef21285..dfbd57865 100644 --- a/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_l2.py +++ b/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_l2.py @@ -15,11 +15,20 @@ import logging from common.proto.context_pb2 import ServiceId, ServiceStatusEnum, ServiceTypeEnum from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Service import json_service_id from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient from tests.Fixtures import context_client, service_client # pylint: disable=unused-import -from tests.tools.test_tools_p4 import * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DEV_NB, + P4_DEV_NB, + L2_RULES, + identify_number_of_p4_devices, + get_number_of_rules, + verify_active_service_type +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) diff --git a/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_l3.py b/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_l3.py index d349a0874..e5f804ce0 100644 --- a/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_l3.py +++ b/src/tests/p4-fabric-tna/tests-service/test_functional_service_deprovision_l3.py @@ -15,11 +15,20 @@ import logging from common.proto.context_pb2 import ServiceId, ServiceStatusEnum, ServiceTypeEnum from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Service import json_service_id from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient from tests.Fixtures import context_client, service_client # pylint: disable=unused-import -from tests.tools.test_tools_p4 import * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DEV_NB, + P4_DEV_NB, + L3_RULES, + identify_number_of_p4_devices, + get_number_of_rules, + verify_active_service_type +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) diff --git a/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_acl.py b/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_acl.py index 58de046b4..5593e093c 100644 --- a/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_acl.py +++ b/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_acl.py @@ -20,7 +20,16 @@ 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 * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DESC_FILE_SERVICE_P4_ACL, + DEV_NB, + P4_DEV_NB, + ACL_RULES, + identify_number_of_p4_devices, + get_number_of_rules, + verify_active_service_type +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) @@ -51,7 +60,7 @@ def test_service_creation_acl( # Load service descriptor_loader = DescriptorLoader( - descriptors_file=DESC_FILE_SERVICE_CREATE_ACL, + descriptors_file=DESC_FILE_SERVICE_P4_ACL, context_client=context_client, device_client=device_client, service_client=service_client ) results = descriptor_loader.process() diff --git a/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_int.py b/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_int.py index 7a875c66a..7f1453dd9 100644 --- a/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_int.py +++ b/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_int.py @@ -20,7 +20,16 @@ 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 * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DESC_FILE_SERVICE_P4_INT, + DEV_NB, + P4_DEV_NB, + INT_RULES, + identify_number_of_p4_devices, + get_number_of_rules, + verify_active_service_type +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) @@ -51,7 +60,7 @@ def test_service_creation_int( # Load service descriptor_loader = DescriptorLoader( - descriptors_file=DESC_FILE_SERVICE_CREATE_INT, + descriptors_file=DESC_FILE_SERVICE_P4_INT, context_client=context_client, device_client=device_client, service_client=service_client ) results = descriptor_loader.process() diff --git a/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_l2.py b/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_l2.py index a42c05546..4786cb324 100644 --- a/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_l2.py +++ b/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_l2.py @@ -20,7 +20,16 @@ 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 * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DESC_FILE_SERVICE_P4_L2_SIMPLE, + DEV_NB, + P4_DEV_NB, + L2_RULES, + identify_number_of_p4_devices, + get_number_of_rules, + verify_active_service_type +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) @@ -51,7 +60,7 @@ def test_service_creation_l2( # Load service descriptor_loader = DescriptorLoader( - descriptors_file=DESC_FILE_SERVICE_CREATE_L2_SIMPLE, + descriptors_file=DESC_FILE_SERVICE_P4_L2_SIMPLE, context_client=context_client, device_client=device_client, service_client=service_client ) results = descriptor_loader.process() diff --git a/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_l3.py b/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_l3.py index 9c0009b14..8c480ce83 100644 --- a/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_l3.py +++ b/src/tests/p4-fabric-tna/tests-service/test_functional_service_provision_l3.py @@ -20,7 +20,16 @@ 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 * +from tests.tools.test_tools_p4 import ( + ADMIN_CONTEXT_ID, + DESC_FILE_SERVICE_P4_L3, + DEV_NB, + P4_DEV_NB, + L3_RULES, + identify_number_of_p4_devices, + get_number_of_rules, + verify_active_service_type +) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) @@ -51,7 +60,7 @@ def test_service_creation_l3( # Load service descriptor_loader = DescriptorLoader( - descriptors_file=DESC_FILE_SERVICE_CREATE_L3, + descriptors_file=DESC_FILE_SERVICE_P4_L3, context_client=context_client, device_client=device_client, service_client=service_client ) results = descriptor_loader.process() diff --git a/src/tests/p4-fabric-tna/tests-setup/test_functional_bootstrap.py b/src/tests/p4-fabric-tna/tests-setup/test_functional_bootstrap.py index 2f9130ad0..fb06a659e 100644 --- a/src/tests/p4-fabric-tna/tests-setup/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 tests.tools.test_tools_p4 import * +from tests.tools.test_tools_p4 import ADMIN_CONTEXT_ID, DESC_TOPO LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) diff --git a/src/tests/p4-fabric-tna/tests-setup/test_functional_cleanup.py b/src/tests/p4-fabric-tna/tests-setup/test_functional_cleanup.py index 4d98c9e05..eff11b3c2 100644 --- a/src/tests/p4-fabric-tna/tests-setup/test_functional_cleanup.py +++ b/src/tests/p4-fabric-tna/tests-setup/test_functional_cleanup.py @@ -17,7 +17,7 @@ from common.tools.descriptor.Loader import DescriptorLoader, validate_empty_scen 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 tests.tools.test_tools_p4 import * +from tests.tools.test_tools_p4 import ADMIN_CONTEXT_ID, DESC_TOPO 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 index ba37fbd89..f9baeaf97 100644 --- a/src/tests/p4-fabric-tna/tests-setup/test_functional_purge.py +++ b/src/tests/p4-fabric-tna/tests-setup/test_functional_purge.py @@ -15,12 +15,14 @@ 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.Context import json_context_id +from common.tools.object_factory.Device import json_device_id 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 * +from tests.tools.test_tools_p4 import ADMIN_CONTEXT_ID LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) @@ -63,10 +65,11 @@ def test_clean_devices( 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 + device_uuid = device.device_id.device_uuid.uuid + device_json = json_device_id(device_uuid) # Delete device - device_client.DeleteDevice(DeviceId(**device_id)) + device_client.DeleteDevice(DeviceId(**device_json)) def test_clean_context( context_client : ContextClient # pylint: disable=redefined-outer-name diff --git a/src/tests/tools/test_tools_p4.py b/src/tests/tools/test_tools_p4.py index c68f35183..4e9c63734 100644 --- a/src/tests/tools/test_tools_p4.py +++ b/src/tests/tools/test_tools_p4.py @@ -35,15 +35,15 @@ 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_RT_WEST = 7 +DATAPLANE_RULES_NB_RT_EAST = 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_RT_WEST +\ + DATAPLANE_RULES_NB_RT_EAST +\ DATAPLANE_RULES_NB_ACL # Service-related variables @@ -75,12 +75,12 @@ DESC_FILE_RULES_INSERT_INT_B3 = os.path.join(TEST_PATH, 'sbi-rules-insert-int-b3 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),\ +DESC_FILE_RULES_INSERT_ROUTING_WEST = os.path.join(TEST_PATH, 'sbi-rules-insert-routing-west.json') +assert os.path.exists(DESC_FILE_RULES_INSERT_ROUTING_WEST),\ "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),\ +DESC_FILE_RULES_INSERT_ROUTING_EAST = os.path.join(TEST_PATH, 'sbi-rules-insert-routing-east.json') +assert os.path.exists(DESC_FILE_RULES_INSERT_ROUTING_EAST),\ "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') @@ -92,20 +92,20 @@ 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),\ +DESC_FILE_SERVICE_P4_INT = os.path.join(TEST_PATH, 'service-p4-int.json') +assert os.path.exists(DESC_FILE_SERVICE_P4_INT),\ "Invalid path to the SD-Fabric INT service descriptor" -DESC_FILE_SERVICE_CREATE_L2_SIMPLE = os.path.join(TEST_PATH, 'service-create-l2-simple.json') -assert os.path.exists(DESC_FILE_SERVICE_CREATE_L2_SIMPLE),\ +DESC_FILE_SERVICE_P4_L2_SIMPLE = os.path.join(TEST_PATH, 'service-p4-l2-simple.json') +assert os.path.exists(DESC_FILE_SERVICE_P4_L2_SIMPLE),\ "Invalid path to the SD-Fabric L2 simple 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),\ +DESC_FILE_SERVICE_P4_L3 = os.path.join(TEST_PATH, 'service-p4-l3.json') +assert os.path.exists(DESC_FILE_SERVICE_P4_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),\ +DESC_FILE_SERVICE_P4_ACL = os.path.join(TEST_PATH, 'service-p4-acl.json') +assert os.path.exists(DESC_FILE_SERVICE_P4_ACL),\ "Invalid path to the SD-Fabric ACL service descriptor" def identify_number_of_p4_devices(devices) -> int: -- GitLab From 18d2709e1b0ac317a0030c31fb3645827caaff7f Mon Sep 17 00:00:00 2001 From: "Georgios P. Katsikas" Date: Wed, 14 May 2025 07:16:23 +0300 Subject: [PATCH 2/4] fix: P4 service handlers support multi-device config --- .../p4_fabric_tna_acl_service_handler.py | 150 +++++++++--------- .../p4_fabric_tna_int_service_handler.py | 65 ++++---- ...p4_fabric_tna_l2_simple_service_handler.py | 108 ++++++------- .../p4_fabric_tna_l3_service_handler.py | 126 +++++++-------- 4 files changed, 229 insertions(+), 220 deletions(-) diff --git a/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py index 510b59ebb..00eccfb4a 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py @@ -346,83 +346,85 @@ class P4FabricACLServiceHandler(_ServiceHandler): except Exception as ex: LOGGER.error("Failed to parse service settings: {}".format(ex)) raise Exception(ex) - assert isinstance(self.__switch_info, dict), "Switch info object must be a map with switch names as keys" - - for switch_name, switch_info in self.__switch_info.items(): - assert switch_name, "Invalid P4 switch name" - assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" - assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ - "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) - switch_dpid = switch_info[DPID] - assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) - - # Access Control list - acl = switch_info[ACL] - assert isinstance(acl, list), "Switch {} access control list must be a list with port_id, [ipv4_dst/src, trn_post_dst/src], and action items)" - for acl_entry in acl: - LOGGER.info("ACL entry: {}".format(acl_entry)) - port_id = acl_entry[PORT_ID] - assert port_id >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) - - # Prepare the port map - if switch_name not in self.__port_map: - self.__port_map[switch_name] = {} - port_key = PORT_PREFIX + str(port_id) - if port_key not in self.__port_map[switch_name]: - self.__port_map[switch_name][port_key] = {} - self.__port_map[switch_name][port_key][PORT_ID] = port_id - if ACL not in self.__port_map[switch_name][port_key]: - self.__port_map[switch_name][port_key][ACL] = [] - - map_entry = {} - - ipv4_src = "" - if IPV4_SRC in acl_entry: - ipv4_src = acl_entry[IPV4_SRC] - assert chk_address_ipv4(ipv4_src), "Invalid source IPv4 address {}".format(ipv4_dst) - map_entry[IPV4_SRC] = ipv4_src - - ipv4_dst = "" - if IPV4_DST in acl_entry: - ipv4_dst = acl_entry[IPV4_DST] - assert chk_address_ipv4(ipv4_dst), "Invalid destination IPv4 address {}".format(ipv4_dst) - map_entry[IPV4_DST] = ipv4_dst - - ipv4_prefix_len = -1 - if ipv4_src or ipv4_dst: - ipv4_prefix_len = acl_entry[IPV4_PREFIX_LEN] - assert chk_prefix_len_ipv4(ipv4_prefix_len), "Invalid IPv4 address prefix length {}".format(ipv4_prefix_len) - map_entry[IPV4_PREFIX_LEN] = ipv4_prefix_len - - trn_port_src = -1 - if TRN_PORT_SRC in acl_entry: - trn_port_src = acl_entry[TRN_PORT_SRC] - assert chk_transport_port(trn_port_src), "Invalid source transport port" - map_entry[TRN_PORT_SRC] = trn_port_src - - trn_port_dst = -1 - if TRN_PORT_DST in acl_entry: - trn_port_dst = acl_entry[TRN_PORT_DST] - assert chk_transport_port(trn_port_dst), "Invalid destination transport port" - map_entry[TRN_PORT_DST] = trn_port_dst - - action = acl_entry[ACTION] - assert is_valid_acl_action(action), "Valid actions are: {}".format(','.join(ACTION_LIST)) - - # Retrieve entry from the port map - switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id) - - # Add routing entry - switch_port_entry[ACL].append(map_entry) + assert isinstance(self.__switch_info, list), "Switch info object must be a list" + + for switch in self.__switch_info: + for switch_name, switch_info in switch.items(): + assert switch_name, "Invalid P4 switch name" + assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" + assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ + "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) + switch_dpid = switch_info[DPID] + assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) + + # Access Control list + acl = switch_info[ACL] + assert isinstance(acl, list), "Switch {} access control list must be a list with port_id, [ipv4_dst/src, trn_post_dst/src], and action items)" + for acl_entry in acl: + LOGGER.info("ACL entry: {}".format(acl_entry)) + port_id = acl_entry[PORT_ID] + assert port_id >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) + + # Prepare the port map + if switch_name not in self.__port_map: + self.__port_map[switch_name] = {} + port_key = PORT_PREFIX + str(port_id) + if port_key not in self.__port_map[switch_name]: + self.__port_map[switch_name][port_key] = {} + self.__port_map[switch_name][port_key][PORT_ID] = port_id + if ACL not in self.__port_map[switch_name][port_key]: + self.__port_map[switch_name][port_key][ACL] = [] + + map_entry = {} + + ipv4_src = "" + if IPV4_SRC in acl_entry: + ipv4_src = acl_entry[IPV4_SRC] + assert chk_address_ipv4(ipv4_src), "Invalid source IPv4 address {}".format(ipv4_dst) + map_entry[IPV4_SRC] = ipv4_src + + ipv4_dst = "" + if IPV4_DST in acl_entry: + ipv4_dst = acl_entry[IPV4_DST] + assert chk_address_ipv4(ipv4_dst), "Invalid destination IPv4 address {}".format(ipv4_dst) + map_entry[IPV4_DST] = ipv4_dst + + ipv4_prefix_len = -1 + if ipv4_src or ipv4_dst: + ipv4_prefix_len = acl_entry[IPV4_PREFIX_LEN] + assert chk_prefix_len_ipv4(ipv4_prefix_len), "Invalid IPv4 address prefix length {}".format(ipv4_prefix_len) + map_entry[IPV4_PREFIX_LEN] = ipv4_prefix_len + + trn_port_src = -1 + if TRN_PORT_SRC in acl_entry: + trn_port_src = acl_entry[TRN_PORT_SRC] + assert chk_transport_port(trn_port_src), "Invalid source transport port" + map_entry[TRN_PORT_SRC] = trn_port_src + + trn_port_dst = -1 + if TRN_PORT_DST in acl_entry: + trn_port_dst = acl_entry[TRN_PORT_DST] + assert chk_transport_port(trn_port_dst), "Invalid destination transport port" + map_entry[TRN_PORT_DST] = trn_port_dst + + action = acl_entry[ACTION] + assert is_valid_acl_action(action), "Valid actions are: {}".format(','.join(ACTION_LIST)) + + # Retrieve entry from the port map + switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id) + + # Add routing entry + switch_port_entry[ACL].append(map_entry) def _print_settings(self): LOGGER.info("--------------- {} settings ---------------".format(self.__service.name)) LOGGER.info("--- Topology info") - for switch_name, switch_info in self.__switch_info.items(): - LOGGER.info("\t Device {}".format(switch_name)) - LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) - LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) - LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) + for switch in self.__switch_info: + for switch_name, switch_info in switch.items(): + LOGGER.info("\t Device {}".format(switch_name)) + LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) + LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) + LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) LOGGER.info("-------------------------------------------------------") def _get_switch_port_in_port_map(self, switch_name : str, port_id : int) -> Dict: @@ -434,7 +436,7 @@ class P4FabricACLServiceHandler(_ServiceHandler): assert switch_entry[port_key], "Port with ID {} does not exist in the switch map".format(port_id) return switch_entry[port_key] - + def _get_acl_of_switch_port(self, switch_name : str, port_id : int) -> List [Tuple]: switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id) return switch_port_entry[ACL] diff --git a/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py index c5ecdd682..73d555a0b 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py @@ -316,27 +316,29 @@ class P4FabricINTServiceHandler(_ServiceHandler): except Exception as ex: LOGGER.error("Failed to parse service settings: {}".format(ex)) raise Exception(ex) - assert isinstance(self.__switch_info, dict), "Switch info object must be a map with switch names as keys" - - for switch_name, switch_info in self.__switch_info.items(): - assert switch_name, "Invalid P4 switch name" - assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, mac, ip, and int_port items)" - assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ - "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) - assert switch_info[DPID] > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) - assert chk_address_mac(switch_info[MAC]), "Switch {} - Invalid source Ethernet address".format(switch_name) - assert chk_address_ipv4(switch_info[IP]), "Switch {} - Invalid source IP address".format(switch_name) - assert isinstance(switch_info[PORT_INT], dict), "Switch {} - INT port object must be a map with port_id and port_type items".format(switch_name) - assert switch_info[PORT_INT][PORT_ID] >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) - assert switch_info[PORT_INT][PORT_TYPE] in PORT_TYPES_STR_VALID, "Switch {} - Valid P4 switch port types are: {}".format( - switch_name, ','.join(PORT_TYPES_STR_VALID)) - if arch_tna(switch_info[ARCH]): - switch_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_TNA - switch_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_TNA - else: - switch_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_V1MODEL - switch_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_V1MODEL - assert isinstance(switch_info[RECIRCULATION_PORT_LIST], list), "Switch {} - Recirculation ports must be described as a list".format(switch_name) + assert isinstance(self.__switch_info, list), "Switch info object must be a list" + + # for switch_name, switch_info in self.__switch_info.items(): + for switch in self.__switch_info: + for switch_name, switch_info in switch.items(): + assert switch_name, "Invalid P4 switch name" + assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, mac, ip, and int_port items)" + assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ + "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) + assert switch_info[DPID] > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) + assert chk_address_mac(switch_info[MAC]), "Switch {} - Invalid source Ethernet address".format(switch_name) + assert chk_address_ipv4(switch_info[IP]), "Switch {} - Invalid source IP address".format(switch_name) + assert isinstance(switch_info[PORT_INT], dict), "Switch {} - INT port object must be a map with port_id and port_type items".format(switch_name) + assert switch_info[PORT_INT][PORT_ID] >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) + assert switch_info[PORT_INT][PORT_TYPE] in PORT_TYPES_STR_VALID, "Switch {} - Valid P4 switch port types are: {}".format( + switch_name, ','.join(PORT_TYPES_STR_VALID)) + if arch_tna(switch_info[ARCH]): + switch_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_TNA + switch_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_TNA + else: + switch_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_V1MODEL + switch_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_V1MODEL + assert isinstance(switch_info[RECIRCULATION_PORT_LIST], list), "Switch {} - Recirculation ports must be described as a list".format(switch_name) self.__int_collector_info = self.__settings.value[INT_COLLECTOR_INFO] assert isinstance(self.__int_collector_info, dict), "INT collector info object must be a map with mac, ip, port, and vlan_id keys)" @@ -356,16 +358,17 @@ class P4FabricINTServiceHandler(_ServiceHandler): def _print_settings(self): LOGGER.info("-------------------- {} settings --------------------".format(self.__service.name)) LOGGER.info("--- Topology info") - for switch_name, switch_info in self.__switch_info.items(): - LOGGER.info("\t Device {}".format(switch_name)) - LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) - LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) - LOGGER.info("\t\t| Source MAC address: {}".format(switch_info[MAC])) - LOGGER.info("\t\t| Source IP address: {}".format(switch_info[IP])) - LOGGER.info("\t\t| INT port ID: {}".format(switch_info[PORT_INT][PORT_ID])) - LOGGER.info("\t\t| INT port type: {}".format(switch_info[PORT_INT][PORT_TYPE])) - LOGGER.info("\t\t| Recirculation port list: {}".format(switch_info[RECIRCULATION_PORT_LIST])) - LOGGER.info("\t\t| Report mirror ID list: {}".format(switch_info[INT_REPORT_MIRROR_ID_LIST])) + for switch in self.__switch_info: + for switch_name, switch_info in switch.items(): + LOGGER.info("\t Device {}".format(switch_name)) + LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) + LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) + LOGGER.info("\t\t| Source MAC address: {}".format(switch_info[MAC])) + LOGGER.info("\t\t| Source IP address: {}".format(switch_info[IP])) + LOGGER.info("\t\t| INT port ID: {}".format(switch_info[PORT_INT][PORT_ID])) + LOGGER.info("\t\t| INT port type: {}".format(switch_info[PORT_INT][PORT_TYPE])) + LOGGER.info("\t\t| Recirculation port list: {}".format(switch_info[RECIRCULATION_PORT_LIST])) + LOGGER.info("\t\t| Report mirror ID list: {}".format(switch_info[INT_REPORT_MIRROR_ID_LIST])) LOGGER.info("--- INT collector MAC: {}".format(self.__int_collector_mac)) LOGGER.info("--- INT collector IP: {}".format(self.__int_collector_ip)) LOGGER.info("--- INT collector port: {}".format(self.__int_collector_port)) diff --git a/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py index c24bdc880..d58a183ef 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py @@ -329,62 +329,64 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): except Exception as ex: LOGGER.error("Failed to parse service settings: {}".format(ex)) raise Exception(ex) - assert isinstance(self.__switch_info, dict), "Switch info object must be a map with switch names as keys" - - for switch_name, switch_info in self.__switch_info.items(): - assert switch_name, "Invalid P4 switch name" - assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" - assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ - "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) - switch_dpid = switch_info[DPID] - assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) - - # Port list - port_list = switch_info[PORT_LIST] - assert isinstance(port_list, list), "Switch {} port list must be a list with port_id, port_type, and vlan_id items)" - for port in port_list: - port_id = port[PORT_ID] - assert port_id >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) - port_type = port[PORT_TYPE] - assert port_type in PORT_TYPES_STR_VALID, "Switch {} - Valid P4 switch port types are: {}".format( - switch_name, ','.join(PORT_TYPES_STR_VALID)) - vlan_id = port[VLAN_ID] - assert chk_vlan_id(vlan_id), "Switch {} - Invalid VLAN ID for port {}".format(switch_name, port_id) - - if switch_name not in self.__port_map: - self.__port_map[switch_name] = {} - port_key = PORT_PREFIX + str(port_id) - if port_key not in self.__port_map[switch_name]: - self.__port_map[switch_name][port_key] = {} - self.__port_map[switch_name][port_key][PORT_ID] = port_id - self.__port_map[switch_name][port_key][PORT_TYPE] = port_type - self.__port_map[switch_name][port_key][VLAN_ID] = vlan_id - self.__port_map[switch_name][port_key][FORWARDING_LIST] = [] - - # Forwarding list - fwd_list = switch_info[FORWARDING_LIST] - assert isinstance(fwd_list, list), "Switch {} forwarding list be a list)" - for fwd_entry in fwd_list: - port_id = fwd_entry[PORT_ID] - assert port_id >= 0, "Invalid port ID: {}".format(port_id) - host_mac = fwd_entry[HOST_MAC] - assert chk_address_mac(host_mac), "Invalid host MAC address {}".format(host_mac) - - # Retrieve entry from the port map - switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id) - - host_facing_port = self._is_host_facing_port(switch_name, port_id) - LOGGER.info("Switch {} - Port {}: Is host facing: {}".format(switch_name, port_id, "True" if host_facing_port else "False")) - switch_port_entry[FORWARDING_LIST].append(host_mac) + assert isinstance(self.__switch_info, list), "Switch info object must be a list" + + for switch in self.__switch_info: + for switch_name, switch_info in switch.items(): + assert switch_name, "Invalid P4 switch name" + assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" + assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ + "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) + switch_dpid = switch_info[DPID] + assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) + + # Port list + port_list = switch_info[PORT_LIST] + assert isinstance(port_list, list), "Switch {} port list must be a list with port_id, port_type, and vlan_id items)" + for port in port_list: + port_id = port[PORT_ID] + assert port_id >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) + port_type = port[PORT_TYPE] + assert port_type in PORT_TYPES_STR_VALID, "Switch {} - Valid P4 switch port types are: {}".format( + switch_name, ','.join(PORT_TYPES_STR_VALID)) + vlan_id = port[VLAN_ID] + assert chk_vlan_id(vlan_id), "Switch {} - Invalid VLAN ID for port {}".format(switch_name, port_id) + + if switch_name not in self.__port_map: + self.__port_map[switch_name] = {} + port_key = PORT_PREFIX + str(port_id) + if port_key not in self.__port_map[switch_name]: + self.__port_map[switch_name][port_key] = {} + self.__port_map[switch_name][port_key][PORT_ID] = port_id + self.__port_map[switch_name][port_key][PORT_TYPE] = port_type + self.__port_map[switch_name][port_key][VLAN_ID] = vlan_id + self.__port_map[switch_name][port_key][FORWARDING_LIST] = [] + + # Forwarding list + fwd_list = switch_info[FORWARDING_LIST] + assert isinstance(fwd_list, list), "Switch {} forwarding list be a list)" + for fwd_entry in fwd_list: + port_id = fwd_entry[PORT_ID] + assert port_id >= 0, "Invalid port ID: {}".format(port_id) + host_mac = fwd_entry[HOST_MAC] + assert chk_address_mac(host_mac), "Invalid host MAC address {}".format(host_mac) + + # Retrieve entry from the port map + switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id) + + host_facing_port = self._is_host_facing_port(switch_name, port_id) + LOGGER.info("Switch {} - Port {}: Is host facing: {}".format(switch_name, port_id, "True" if host_facing_port else "False")) + switch_port_entry[FORWARDING_LIST].append(host_mac) def _print_settings(self): LOGGER.info("--------------- {} settings ---------------".format(self.__service.name)) LOGGER.info("--- Topology info") - for switch_name, switch_info in self.__switch_info.items(): - LOGGER.info("\t Device {}".format(switch_name)) - LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) - LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) - LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) + for switch in self.__switch_info: + for switch_name, switch_info in switch.items(): + LOGGER.info("\t Device {}".format(switch_name)) + LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) + LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) + LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) LOGGER.info("-------------------------------------------------------") def _get_switch_port_in_port_map(self, switch_name : str, port_id : int) -> Dict: @@ -452,7 +454,7 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): except Exception as ex: LOGGER.error("Error while creating bridging rules") raise Exception(ex) - + try: ### Next output rule rules += rules_set_up_next_output_simple( diff --git a/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py index c97d38829..cc7a8dbd5 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py @@ -327,72 +327,74 @@ class P4FabricL3ServiceHandler(_ServiceHandler): except Exception as ex: LOGGER.error("Failed to parse service settings: {}".format(ex)) raise Exception(ex) - assert isinstance(self.__switch_info, dict), "Switch info object must be a map with switch names as keys" - - for switch_name, switch_info in self.__switch_info.items(): - assert switch_name, "Invalid P4 switch name" - assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" - assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ - "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) - switch_dpid = switch_info[DPID] - assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) - - # Port list - port_list = switch_info[PORT_LIST] - assert isinstance(port_list, list), "Switch {} port list must be a list with port_id and port_type items)" - for port in port_list: - port_id = port[PORT_ID] - assert port_id >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) - port_type = port[PORT_TYPE] - assert port_type in PORT_TYPES_STR_VALID, "Switch {} - Valid P4 switch port types are: {}".format( - switch_name, ','.join(PORT_TYPES_STR_VALID)) - - if switch_name not in self.__port_map: - self.__port_map[switch_name] = {} - port_key = PORT_PREFIX + str(port_id) - if port_key not in self.__port_map[switch_name]: - self.__port_map[switch_name][port_key] = {} - self.__port_map[switch_name][port_key][PORT_ID] = port_id - self.__port_map[switch_name][port_key][PORT_TYPE] = port_type - self.__port_map[switch_name][port_key][ROUTING_LIST] = [] - - # Routing list - routing_list = switch_info[ROUTING_LIST] - assert isinstance(routing_list, list), "Switch {} routing list be a list)" - for rt_entry in routing_list: - port_id = rt_entry[PORT_ID] - assert port_id >= 0, "Invalid port ID: {}".format(port_id) - ipv4_dst = rt_entry[IPV4_DST] - assert chk_address_ipv4(ipv4_dst), "Invalid destination IPv4 address {}".format(ipv4_dst) - ipv4_prefix_len = rt_entry[IPV4_PREFIX_LEN] - assert chk_prefix_len_ipv4(ipv4_prefix_len), "Invalid IPv4 address prefix length {}".format(ipv4_prefix_len) - mac_src = rt_entry[MAC_SRC] - assert chk_address_mac(mac_src), "Invalid source MAC address {}".format(mac_src) - mac_dst = rt_entry[MAC_DST] - assert chk_address_mac(mac_dst), "Invalid destination MAC address {}".format(mac_dst) - - # Retrieve entry from the port map - switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id) - - # Add routing entry - switch_port_entry[ROUTING_LIST].append( - { - PORT_ID: port_id, - IPV4_DST: ipv4_dst, - IPV4_PREFIX_LEN: ipv4_prefix_len, - MAC_SRC: mac_src, - MAC_DST: mac_dst - } - ) + assert isinstance(self.__switch_info, list), "Switch info object must be a list" + + for switch in self.__switch_info: + for switch_name, switch_info in switch.items(): + assert switch_name, "Invalid P4 switch name" + assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" + assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ + "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) + switch_dpid = switch_info[DPID] + assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) + + # Port list + port_list = switch_info[PORT_LIST] + assert isinstance(port_list, list), "Switch {} port list must be a list with port_id and port_type items)" + for port in port_list: + port_id = port[PORT_ID] + assert port_id >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) + port_type = port[PORT_TYPE] + assert port_type in PORT_TYPES_STR_VALID, "Switch {} - Valid P4 switch port types are: {}".format( + switch_name, ','.join(PORT_TYPES_STR_VALID)) + + if switch_name not in self.__port_map: + self.__port_map[switch_name] = {} + port_key = PORT_PREFIX + str(port_id) + if port_key not in self.__port_map[switch_name]: + self.__port_map[switch_name][port_key] = {} + self.__port_map[switch_name][port_key][PORT_ID] = port_id + self.__port_map[switch_name][port_key][PORT_TYPE] = port_type + self.__port_map[switch_name][port_key][ROUTING_LIST] = [] + + # Routing list + routing_list = switch_info[ROUTING_LIST] + assert isinstance(routing_list, list), "Switch {} routing list be a list)" + for rt_entry in routing_list: + port_id = rt_entry[PORT_ID] + assert port_id >= 0, "Invalid port ID: {}".format(port_id) + ipv4_dst = rt_entry[IPV4_DST] + assert chk_address_ipv4(ipv4_dst), "Invalid destination IPv4 address {}".format(ipv4_dst) + ipv4_prefix_len = rt_entry[IPV4_PREFIX_LEN] + assert chk_prefix_len_ipv4(ipv4_prefix_len), "Invalid IPv4 address prefix length {}".format(ipv4_prefix_len) + mac_src = rt_entry[MAC_SRC] + assert chk_address_mac(mac_src), "Invalid source MAC address {}".format(mac_src) + mac_dst = rt_entry[MAC_DST] + assert chk_address_mac(mac_dst), "Invalid destination MAC address {}".format(mac_dst) + + # Retrieve entry from the port map + switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id) + + # Add routing entry + switch_port_entry[ROUTING_LIST].append( + { + PORT_ID: port_id, + IPV4_DST: ipv4_dst, + IPV4_PREFIX_LEN: ipv4_prefix_len, + MAC_SRC: mac_src, + MAC_DST: mac_dst + } + ) def _print_settings(self): LOGGER.info("--------------- {} settings ---------------".format(self.__service.name)) LOGGER.info("--- Topology info") - for switch_name, switch_info in self.__switch_info.items(): - LOGGER.info("\t Device {}".format(switch_name)) - LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) - LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) - LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) + for switch in self.__switch_info: + for switch_name, switch_info in switch.items(): + LOGGER.info("\t Device {}".format(switch_name)) + LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) + LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) + LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) LOGGER.info("-------------------------------------------------------") def _get_switch_port_in_port_map(self, switch_name : str, port_id : int) -> Dict: -- GitLab From 6bd4562df02125a4a08fa296d6a2877c10c1da77 Mon Sep 17 00:00:00 2001 From: "Georgios P. Katsikas" Date: Wed, 14 May 2025 12:16:19 +0300 Subject: [PATCH 3/4] fix: better exception handling in P4 service handlers --- .../p4_fabric_tna_acl_service_handler.py | 134 ++++++++++-------- .../p4_fabric_tna_int_service_handler.py | 126 ++++++++++------ ...p4_fabric_tna_l2_simple_service_handler.py | 59 ++++---- .../p4_fabric_tna_l3_service_handler.py | 59 ++++---- 4 files changed, 214 insertions(+), 164 deletions(-) diff --git a/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py index 00eccfb4a..84fd768cc 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_acl/p4_fabric_tna_acl_service_handler.py @@ -130,20 +130,19 @@ class P4FabricACLServiceHandler(_ServiceHandler): ) except Exception as ex: LOGGER.error("Failed to insert ACL rules on device {} due to {}".format(device.name, ex)) + results.append(ex) finally: rules.clear() # Ensure correct status - results.append(True) if (failed_rules == 0) and (applied_rules == actual_rules) \ - else results.append(False) + if (failed_rules == 0) and (applied_rules == actual_rules): + LOGGER.info("Installed {}/{} ACL rules on device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) + results.append(True) # You should no longer visit this device port again visited.add(dev_port_key) - if applied_rules > 0: - LOGGER.info("Installed {}/{} ACL rules on device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) - return results @metered_subclass_method(METRICS_POOL) @@ -189,7 +188,7 @@ class P4FabricACLServiceHandler(_ServiceHandler): try: # Check if this port is part of the ACL configuration _ = self._get_switch_port_in_port_map(device_name, port_id) - except Exception: + except Exception as ex: LOGGER.warning("Switch {} endpoint {} is not part of the ACL configuration".format(device_name, port_id)) results.append(False) continue @@ -216,20 +215,19 @@ class P4FabricACLServiceHandler(_ServiceHandler): ) except Exception as ex: LOGGER.error("Failed to delete ACL rules from device {} due to {}".format(device.name, ex)) + results.append(ex) finally: rules.clear() # Ensure correct status - results.append(True) if (failed_rules == 0) and (applied_rules == actual_rules) \ - else results.append(False) + if (failed_rules == 0) and (applied_rules == actual_rules): + LOGGER.info("Deleted {}/{} ACL rules from device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) + results.append(True) # You should no longer visit this device port again visited.add(dev_port_key) - if applied_rules > 0: - LOGGER.info("Deleted {}/{} ACL rules from device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) - return results @metered_subclass_method(METRICS_POOL) @@ -342,24 +340,26 @@ class P4FabricACLServiceHandler(_ServiceHandler): def _parse_settings(self): try: - self.__switch_info = self.__settings.value[SWITCH_INFO] + switch_info = self.__settings.value[SWITCH_INFO] except Exception as ex: LOGGER.error("Failed to parse service settings: {}".format(ex)) raise Exception(ex) - assert isinstance(self.__switch_info, list), "Switch info object must be a list" + assert isinstance(switch_info, list), "Switch info object must be a list" - for switch in self.__switch_info: - for switch_name, switch_info in switch.items(): + for switch in switch_info: + for switch_name, sw_info in switch.items(): assert switch_name, "Invalid P4 switch name" - assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" - assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ + assert isinstance(sw_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" + assert sw_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) - switch_dpid = switch_info[DPID] - assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) + switch_dpid = sw_info[DPID] + assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, sw_info[DPID]) # Access Control list - acl = switch_info[ACL] - assert isinstance(acl, list), "Switch {} access control list must be a list with port_id, [ipv4_dst/src, trn_post_dst/src], and action items)" + acl = sw_info[ACL] + assert isinstance(acl, list),\ + "Switch {} access control list must be a list with port_id, [ipv4_dst/src, trn_post_dst/src], and action items)".\ + format(switch_name) for acl_entry in acl: LOGGER.info("ACL entry: {}".format(acl_entry)) port_id = acl_entry[PORT_ID] @@ -398,13 +398,13 @@ class P4FabricACLServiceHandler(_ServiceHandler): trn_port_src = -1 if TRN_PORT_SRC in acl_entry: trn_port_src = acl_entry[TRN_PORT_SRC] - assert chk_transport_port(trn_port_src), "Invalid source transport port" + assert chk_transport_port(trn_port_src), "Invalid source transport port {}".format(trn_port_src) map_entry[TRN_PORT_SRC] = trn_port_src trn_port_dst = -1 if TRN_PORT_DST in acl_entry: trn_port_dst = acl_entry[TRN_PORT_DST] - assert chk_transport_port(trn_port_dst), "Invalid destination transport port" + assert chk_transport_port(trn_port_dst), "Invalid destination transport port {}".format(trn_port_dst) map_entry[TRN_PORT_DST] = trn_port_dst action = acl_entry[ACTION] @@ -416,15 +416,16 @@ class P4FabricACLServiceHandler(_ServiceHandler): # Add routing entry switch_port_entry[ACL].append(map_entry) + self.__switch_info[switch_name] = sw_info + def _print_settings(self): LOGGER.info("--------------- {} settings ---------------".format(self.__service.name)) LOGGER.info("--- Topology info") - for switch in self.__switch_info: - for switch_name, switch_info in switch.items(): - LOGGER.info("\t Device {}".format(switch_name)) - LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) - LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) - LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) + for switch_name, switch_info in self.__switch_info.items(): + LOGGER.info("\t Device {}".format(switch_name)) + LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) + LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) + LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) LOGGER.info("-------------------------------------------------------") def _get_switch_port_in_port_map(self, switch_name : str, port_id : int) -> Dict: @@ -450,34 +451,53 @@ class P4FabricACLServiceHandler(_ServiceHandler): acl = self._get_acl_of_switch_port(switch_name=dev_name, port_id=port_id) for acl_entry in acl: if IPV4_SRC in acl_entry: - rules += rules_set_up_acl_filter_host( - ingress_port=port_id, - ip_address=acl_entry[IPV4_SRC], - prefix_len=acl_entry[IPV4_PREFIX_LEN], - ip_direction="src", - action=action - ) + try: + rules += rules_set_up_acl_filter_host( + ingress_port=port_id, + ip_address=acl_entry[IPV4_SRC], + prefix_len=acl_entry[IPV4_PREFIX_LEN], + ip_direction="src", + action=action + ) + except Exception as ex: + LOGGER.error("Error while creating ACL source host filter rules") + raise Exception(ex) + if IPV4_DST in acl_entry: - rules += rules_set_up_acl_filter_host( - ingress_port=port_id, - ip_address=acl_entry[IPV4_DST], - prefix_len=acl_entry[IPV4_PREFIX_LEN], - ip_direction="dst", - action=action - ) + try: + rules += rules_set_up_acl_filter_host( + ingress_port=port_id, + ip_address=acl_entry[IPV4_DST], + prefix_len=acl_entry[IPV4_PREFIX_LEN], + ip_direction="dst", + action=action + ) + except Exception as ex: + LOGGER.error("Error while creating ACL destination host filter rules") + raise Exception(ex) + if TRN_PORT_SRC in acl_entry: - rules += rules_set_up_acl_filter_port( - ingress_port=port_id, - transport_port=acl_entry[TRN_PORT_SRC], - transport_direction="src", - action=action - ) + try: + rules += rules_set_up_acl_filter_port( + ingress_port=port_id, + transport_port=acl_entry[TRN_PORT_SRC], + transport_direction="src", + action=action + ) + except Exception as ex: + LOGGER.error("Error while creating ACL source port filter rules") + raise Exception(ex) + if TRN_PORT_DST in acl_entry: - rules += rules_set_up_acl_filter_port( - ingress_port=port_id, - transport_port=acl_entry[TRN_PORT_DST], - transport_direction="dst", - action=action - ) + try: + rules += rules_set_up_acl_filter_port( + ingress_port=port_id, + transport_port=acl_entry[TRN_PORT_DST], + transport_direction="dst", + action=action + ) + except Exception as ex: + LOGGER.error("Error while creating ACL destination port filter rules") + raise Exception(ex) return rules diff --git a/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py index 73d555a0b..3212887b8 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_int/p4_fabric_tna_int_service_handler.py @@ -116,20 +116,19 @@ class P4FabricINTServiceHandler(_ServiceHandler): ) except Exception as ex: LOGGER.error("Failed to insert INT rules on device {} due to {}".format(device.name, ex)) + results.append(ex) finally: rules.clear() # Ensure correct status - results.append(True) if (failed_rules == 0) and (applied_rules == actual_rules) \ - else results.append(False) + if (failed_rules == 0) and (applied_rules == actual_rules): + LOGGER.info("Installed {}/{} INT rules on device {}".format( + applied_rules, actual_rules, device.name)) + results.append(True) # You should no longer visit this device again visited.add(device.name) - if applied_rules > 0: - LOGGER.info("Installed {}/{} INT rules on device {}".format( - applied_rules, actual_rules, device.name)) - return results @metered_subclass_method(METRICS_POOL) @@ -182,20 +181,19 @@ class P4FabricINTServiceHandler(_ServiceHandler): task_executor=self.__task_executor, device_obj=device, json_config_rules=rules) except Exception as ex: LOGGER.error("Failed to delete INT rules from device {} due to {}".format(device.name, ex)) + results.append(ex) finally: rules.clear() # Ensure correct status - results.append(True) if (failed_rules == 0) and (applied_rules == actual_rules) \ - else results.append(False) + if (failed_rules == 0) and (applied_rules == actual_rules): + LOGGER.info("Deleted {}/{} INT rules from device {}".format( + applied_rules, actual_rules, device.name)) + results.append(True) # You should no longer visit this device again visited.add(device.name) - if applied_rules > 0: - LOGGER.info("Deleted {}/{} INT rules from device {}".format( - applied_rules, actual_rules, device.name)) - return results @metered_subclass_method(METRICS_POOL) @@ -312,33 +310,33 @@ class P4FabricINTServiceHandler(_ServiceHandler): def _parse_settings(self): try: - self.__switch_info = self.__settings.value[SWITCH_INFO] + switch_info = self.__settings.value[SWITCH_INFO] except Exception as ex: LOGGER.error("Failed to parse service settings: {}".format(ex)) raise Exception(ex) - assert isinstance(self.__switch_info, list), "Switch info object must be a list" + assert isinstance(switch_info, list), "Switch info object must be a list" - # for switch_name, switch_info in self.__switch_info.items(): - for switch in self.__switch_info: - for switch_name, switch_info in switch.items(): + for switch in switch_info: + for switch_name, sw_info in switch.items(): assert switch_name, "Invalid P4 switch name" - assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, mac, ip, and int_port items)" - assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ + assert isinstance(sw_info, dict), "Switch {} info must be a map with arch, dpid, mac, ip, and int_port items)" + assert sw_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) - assert switch_info[DPID] > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) - assert chk_address_mac(switch_info[MAC]), "Switch {} - Invalid source Ethernet address".format(switch_name) - assert chk_address_ipv4(switch_info[IP]), "Switch {} - Invalid source IP address".format(switch_name) - assert isinstance(switch_info[PORT_INT], dict), "Switch {} - INT port object must be a map with port_id and port_type items".format(switch_name) - assert switch_info[PORT_INT][PORT_ID] >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) - assert switch_info[PORT_INT][PORT_TYPE] in PORT_TYPES_STR_VALID, "Switch {} - Valid P4 switch port types are: {}".format( + assert sw_info[DPID] > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, sw_info[DPID]) + assert chk_address_mac(sw_info[MAC]), "Switch {} - Invalid source Ethernet address".format(switch_name) + assert chk_address_ipv4(sw_info[IP]), "Switch {} - Invalid source IP address".format(switch_name) + assert isinstance(sw_info[PORT_INT], dict), "Switch {} - INT port object must be a map with port_id and port_type items".format(switch_name) + assert sw_info[PORT_INT][PORT_ID] >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) + assert sw_info[PORT_INT][PORT_TYPE] in PORT_TYPES_STR_VALID, "Switch {} - Valid P4 switch port types are: {}".format( switch_name, ','.join(PORT_TYPES_STR_VALID)) - if arch_tna(switch_info[ARCH]): - switch_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_TNA - switch_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_TNA + if arch_tna(sw_info[ARCH]): + sw_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_TNA + sw_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_TNA else: - switch_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_V1MODEL - switch_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_V1MODEL - assert isinstance(switch_info[RECIRCULATION_PORT_LIST], list), "Switch {} - Recirculation ports must be described as a list".format(switch_name) + sw_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_V1MODEL + sw_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_V1MODEL + assert isinstance(sw_info[RECIRCULATION_PORT_LIST], list), "Switch {} - Recirculation ports must be described as a list".format(switch_name) + self.__switch_info[switch_name] = sw_info self.__int_collector_info = self.__settings.value[INT_COLLECTOR_INFO] assert isinstance(self.__int_collector_info, dict), "INT collector info object must be a map with mac, ip, port, and vlan_id keys)" @@ -358,17 +356,16 @@ class P4FabricINTServiceHandler(_ServiceHandler): def _print_settings(self): LOGGER.info("-------------------- {} settings --------------------".format(self.__service.name)) LOGGER.info("--- Topology info") - for switch in self.__switch_info: - for switch_name, switch_info in switch.items(): - LOGGER.info("\t Device {}".format(switch_name)) - LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) - LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) - LOGGER.info("\t\t| Source MAC address: {}".format(switch_info[MAC])) - LOGGER.info("\t\t| Source IP address: {}".format(switch_info[IP])) - LOGGER.info("\t\t| INT port ID: {}".format(switch_info[PORT_INT][PORT_ID])) - LOGGER.info("\t\t| INT port type: {}".format(switch_info[PORT_INT][PORT_TYPE])) - LOGGER.info("\t\t| Recirculation port list: {}".format(switch_info[RECIRCULATION_PORT_LIST])) - LOGGER.info("\t\t| Report mirror ID list: {}".format(switch_info[INT_REPORT_MIRROR_ID_LIST])) + for switch_name, switch_info in self.__switch_info.items(): + LOGGER.info("\t Device {}".format(switch_name)) + LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) + LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) + LOGGER.info("\t\t| Source MAC address: {}".format(switch_info[MAC])) + LOGGER.info("\t\t| Source IP address: {}".format(switch_info[IP])) + LOGGER.info("\t\t| INT port ID: {}".format(switch_info[PORT_INT][PORT_ID])) + LOGGER.info("\t\t| INT port type: {}".format(switch_info[PORT_INT][PORT_TYPE])) + LOGGER.info("\t\t| Recirculation port list: {}".format(switch_info[RECIRCULATION_PORT_LIST])) + LOGGER.info("\t\t| Report mirror ID list: {}".format(switch_info[INT_REPORT_MIRROR_ID_LIST])) LOGGER.info("--- INT collector MAC: {}".format(self.__int_collector_mac)) LOGGER.info("--- INT collector IP: {}".format(self.__int_collector_ip)) LOGGER.info("--- INT collector port: {}".format(self.__int_collector_port)) @@ -379,9 +376,14 @@ class P4FabricINTServiceHandler(_ServiceHandler): dev_name = device_obj.name rules = [] + ### INT reporting rules try: - ### INT reporting rules rules += rules_set_up_int_watchlist(action=action) + except Exception as ex: + LOGGER.error("Error while creating INT watchlist rules") + raise Exception(ex) + + try: rules += rules_set_up_int_recirculation_ports( recirculation_port_list=self.__switch_info[dev_name][RECIRCULATION_PORT_LIST], port_type=PORT_TYPE_INT, @@ -389,10 +391,20 @@ class P4FabricINTServiceHandler(_ServiceHandler): vlan_id=self.__int_vlan_id, action=action ) + except Exception as ex: + LOGGER.error("Error while creating INT recirculation rules") + raise Exception(ex) + + try: rules += rules_set_up_int_report_collector( int_collector_ip=self.__int_collector_ip, action=action ) + except Exception as ex: + LOGGER.error("Error while creating INT report collector rules") + raise Exception(ex) + + try: rules += rules_set_up_int_report_flow( switch_id=self.__switch_info[dev_name][DPID], src_ip=self.__switch_info[dev_name][IP], @@ -400,12 +412,22 @@ class P4FabricINTServiceHandler(_ServiceHandler): int_collector_port=self.__int_collector_port, action=action ) + except Exception as ex: + LOGGER.error("Error while creating INT report flow rules") + raise Exception(ex) + + try: rules += rules_set_up_report_mirror_flow( recirculation_port_list=self.__switch_info[dev_name][RECIRCULATION_PORT_LIST], report_mirror_id_list=self.__switch_info[dev_name][INT_REPORT_MIRROR_ID_LIST], action=action ) - ### INT port setup rules + except Exception as ex: + LOGGER.error("Error while creating report mirror flow rules") + raise Exception(ex) + + ### INT port setup rules + try: rules += rules_set_up_port( port=self.__switch_info[dev_name][PORT_INT][PORT_ID], port_type=PORT_TYPE_HOST, @@ -413,7 +435,12 @@ class P4FabricINTServiceHandler(_ServiceHandler): vlan_id=self.__int_vlan_id, action=action ) - ### INT port forwarding rules + except Exception as ex: + LOGGER.error("Error while creating INT port rules") + raise Exception(ex) + + ### INT port forwarding rules + try: rules += rules_set_up_fwd_bridging( vlan_id=self.__int_vlan_id, eth_dst=self.__int_collector_mac, @@ -424,7 +451,12 @@ class P4FabricINTServiceHandler(_ServiceHandler): egress_port=self.__switch_info[dev_name][PORT_INT][PORT_ID], action=action ) - ### INT packet routing rules + except Exception as ex: + LOGGER.error("Error while creating INT bridging rules") + raise Exception(ex) + + ### INT packet routing rules + try: rules += rules_set_up_next_routing_simple( egress_port=self.__switch_info[dev_name][PORT_INT][PORT_ID], eth_src=self.__switch_info[dev_name][MAC], @@ -438,7 +470,7 @@ class P4FabricINTServiceHandler(_ServiceHandler): action=action ) except Exception as ex: - LOGGER.error("Error while creating rules") + LOGGER.error("Error while creating INT routing rules") raise Exception(ex) return rules diff --git a/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py index d58a183ef..7dff44ce8 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_l2_simple/p4_fabric_tna_l2_simple_service_handler.py @@ -121,20 +121,19 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): ) except Exception as ex: LOGGER.error("Failed to insert L2 rules on device {} due to {}".format(device.name, ex)) + results.append(ex) finally: rules.clear() # Ensure correct status - results.append(True) if (failed_rules == 0) and (applied_rules == actual_rules) \ - else results.append(False) + if (failed_rules == 0) and (applied_rules == actual_rules): + LOGGER.info("Installed {}/{} L2 rules on device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) + results.append(True) # You should no longer visit this device port again visited.add(dev_port_key) - if applied_rules > 0: - LOGGER.info("Installed {}/{} L2 rules on device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) - return results @metered_subclass_method(METRICS_POOL) @@ -199,20 +198,19 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): ) except Exception as ex: LOGGER.error("Failed to delete L2 rules from device {} due to {}".format(device.name, ex)) + results.append(ex) finally: rules.clear() # Ensure correct status - results.append(True) if (failed_rules == 0) and (applied_rules == actual_rules) \ - else results.append(False) + if (failed_rules == 0) and (applied_rules == actual_rules): + LOGGER.info("Deleted {}/{} L2 rules from device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) + results.append(True) # You should no longer visit this device port again visited.add(dev_port_key) - if applied_rules > 0: - LOGGER.info("Deleted {}/{} L2 rules from device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) - return results @metered_subclass_method(METRICS_POOL) @@ -325,24 +323,25 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): def _parse_settings(self): try: - self.__switch_info = self.__settings.value[SWITCH_INFO] + switch_info = self.__settings.value[SWITCH_INFO] except Exception as ex: LOGGER.error("Failed to parse service settings: {}".format(ex)) raise Exception(ex) - assert isinstance(self.__switch_info, list), "Switch info object must be a list" + assert isinstance(switch_info, list), "Switch info object must be a list" - for switch in self.__switch_info: - for switch_name, switch_info in switch.items(): + for switch in switch_info: + for switch_name, sw_info in switch.items(): assert switch_name, "Invalid P4 switch name" - assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" - assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ + assert isinstance(sw_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" + assert sw_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) - switch_dpid = switch_info[DPID] - assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) + switch_dpid = sw_info[DPID] + assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, sw_info[DPID]) # Port list - port_list = switch_info[PORT_LIST] - assert isinstance(port_list, list), "Switch {} port list must be a list with port_id, port_type, and vlan_id items)" + port_list = sw_info[PORT_LIST] + assert isinstance(port_list, list), \ + "Switch {} port list must be a list with port_id, port_type, and vlan_id items".format(switch_name) for port in port_list: port_id = port[PORT_ID] assert port_id >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) @@ -363,8 +362,8 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): self.__port_map[switch_name][port_key][FORWARDING_LIST] = [] # Forwarding list - fwd_list = switch_info[FORWARDING_LIST] - assert isinstance(fwd_list, list), "Switch {} forwarding list be a list)" + fwd_list = sw_info[FORWARDING_LIST] + assert isinstance(fwd_list, list), "Switch {} forwarding list must be a list".format(switch_name) for fwd_entry in fwd_list: port_id = fwd_entry[PORT_ID] assert port_id >= 0, "Invalid port ID: {}".format(port_id) @@ -377,16 +376,16 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler): host_facing_port = self._is_host_facing_port(switch_name, port_id) LOGGER.info("Switch {} - Port {}: Is host facing: {}".format(switch_name, port_id, "True" if host_facing_port else "False")) switch_port_entry[FORWARDING_LIST].append(host_mac) + self.__switch_info[switch_name] = sw_info def _print_settings(self): LOGGER.info("--------------- {} settings ---------------".format(self.__service.name)) LOGGER.info("--- Topology info") - for switch in self.__switch_info: - for switch_name, switch_info in switch.items(): - LOGGER.info("\t Device {}".format(switch_name)) - LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) - LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) - LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) + for switch_name, switch_info in self.__switch_info.items(): + LOGGER.info("\t Device {}".format(switch_name)) + LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) + LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) + LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) LOGGER.info("-------------------------------------------------------") def _get_switch_port_in_port_map(self, switch_name : str, port_id : int) -> Dict: diff --git a/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py b/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py index cc7a8dbd5..e1b73b374 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py +++ b/src/service/service/service_handlers/p4_fabric_tna_l3/p4_fabric_tna_l3_service_handler.py @@ -119,20 +119,19 @@ class P4FabricL3ServiceHandler(_ServiceHandler): ) except Exception as ex: LOGGER.error("Failed to insert L3 rules on device {} due to {}".format(device.name, ex)) + results.append(ex) finally: rules.clear() # Ensure correct status - results.append(True) if (failed_rules == 0) and (applied_rules == actual_rules) \ - else results.append(False) + if (failed_rules == 0) and (applied_rules == actual_rules): + LOGGER.info("Installed {}/{} ACL rules on device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) + results.append(True) # You should no longer visit this device port again visited.add(dev_port_key) - if applied_rules > 0: - LOGGER.info("Installed {}/{} L3 rules on device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) - return results @metered_subclass_method(METRICS_POOL) @@ -197,20 +196,19 @@ class P4FabricL3ServiceHandler(_ServiceHandler): ) except Exception as ex: LOGGER.error("Failed to delete L3 rules from device {} due to {}".format(device.name, ex)) + results.append(ex) finally: rules.clear() # Ensure correct status - results.append(True) if (failed_rules == 0) and (applied_rules == actual_rules) \ - else results.append(False) + if (failed_rules == 0) and (applied_rules == actual_rules): + LOGGER.info("Deleted {}/{} L3 rules from device {} and port {}".format( + applied_rules, actual_rules, device_name, port_id)) + results.append(True) # You should no longer visit this device port again visited.add(dev_port_key) - if applied_rules > 0: - LOGGER.info("Deleted {}/{} L3 rules from device {} and port {}".format( - applied_rules, actual_rules, device_name, port_id)) - return results @metered_subclass_method(METRICS_POOL) @@ -323,24 +321,25 @@ class P4FabricL3ServiceHandler(_ServiceHandler): def _parse_settings(self): try: - self.__switch_info = self.__settings.value[SWITCH_INFO] + switch_info = self.__settings.value[SWITCH_INFO] except Exception as ex: LOGGER.error("Failed to parse service settings: {}".format(ex)) raise Exception(ex) - assert isinstance(self.__switch_info, list), "Switch info object must be a list" + assert isinstance(switch_info, list), "Switch info object must be a list" - for switch in self.__switch_info: - for switch_name, switch_info in switch.items(): + for switch in switch_info: + for switch_name, sw_info in switch.items(): assert switch_name, "Invalid P4 switch name" - assert isinstance(switch_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" - assert switch_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ + assert isinstance(sw_info, dict), "Switch {} info must be a map with arch, dpid, and fwd_list items)" + assert sw_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \ "Switch {} - Supported P4 architectures are: {}".format(switch_name, ','.join(SUPPORTED_TARGET_ARCH_LIST)) - switch_dpid = switch_info[DPID] - assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, switch_info[DPID]) + switch_dpid = sw_info[DPID] + assert switch_dpid > 0, "Switch {} - P4 switch dataplane ID must be a positive integer".format(switch_name, sw_info[DPID]) # Port list - port_list = switch_info[PORT_LIST] - assert isinstance(port_list, list), "Switch {} port list must be a list with port_id and port_type items)" + port_list = sw_info[PORT_LIST] + assert isinstance(port_list, list),\ + "Switch {} port list must be a list with port_id and port_type items".format(switch_name) for port in port_list: port_id = port[PORT_ID] assert port_id >= 0, "Switch {} - Invalid P4 switch port ID".format(switch_name) @@ -358,8 +357,8 @@ class P4FabricL3ServiceHandler(_ServiceHandler): self.__port_map[switch_name][port_key][ROUTING_LIST] = [] # Routing list - routing_list = switch_info[ROUTING_LIST] - assert isinstance(routing_list, list), "Switch {} routing list be a list)" + routing_list = sw_info[ROUTING_LIST] + assert isinstance(routing_list, list), "Switch {} routing list must be a list".format(switch_name) for rt_entry in routing_list: port_id = rt_entry[PORT_ID] assert port_id >= 0, "Invalid port ID: {}".format(port_id) @@ -385,16 +384,16 @@ class P4FabricL3ServiceHandler(_ServiceHandler): MAC_DST: mac_dst } ) + self.__switch_info[switch_name] = sw_info def _print_settings(self): LOGGER.info("--------------- {} settings ---------------".format(self.__service.name)) LOGGER.info("--- Topology info") - for switch in self.__switch_info: - for switch_name, switch_info in switch.items(): - LOGGER.info("\t Device {}".format(switch_name)) - LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) - LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) - LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) + for switch_name, switch_info in self.__switch_info.items(): + LOGGER.info("\t Device {}".format(switch_name)) + LOGGER.info("\t\t| Target P4 architecture: {}".format(switch_info[ARCH])) + LOGGER.info("\t\t| Data plane ID: {}".format(switch_info[DPID])) + LOGGER.info("\t\t| Port map: {}".format(self.__port_map[switch_name])) LOGGER.info("-------------------------------------------------------") def _get_switch_port_in_port_map(self, switch_name : str, port_id : int) -> Dict: -- GitLab From 058937d8b6615c0f22a3a08b1bbc2bbcda0a1edf Mon Sep 17 00:00:00 2001 From: "Georgios P. Katsikas" Date: Wed, 14 May 2025 16:04:05 +0300 Subject: [PATCH 4/4] fix: update json data model of P4 service handlers --- .../descriptors/service-p4-acl.json | 26 ++++---- .../descriptors/service-p4-int.json | 22 ++++--- .../descriptors/service-p4-l2-simple.json | 56 ++++++++-------- .../descriptors/service-p4-l3.json | 64 ++++++++++--------- 4 files changed, 88 insertions(+), 80 deletions(-) diff --git a/src/tests/p4-fabric-tna/descriptors/service-p4-acl.json b/src/tests/p4-fabric-tna/descriptors/service-p4-acl.json index 2ec9c6674..b2cf2946a 100644 --- a/src/tests/p4-fabric-tna/descriptors/service-p4-acl.json +++ b/src/tests/p4-fabric-tna/descriptors/service-p4-acl.json @@ -24,19 +24,21 @@ "custom": { "resource_key": "/settings", "resource_value": { - "switch_info": { - "sw1": { - "arch": "v1model", - "dpid": 1, - "acl": [ - { - "port_id": 1, - "trn_port_dst": 8080, - "action": "drop" - } - ] + "switch_info": [ + { + "sw1": { + "arch": "v1model", + "dpid": 1, + "acl": [ + { + "port_id": 1, + "trn_port_dst": 8080, + "action": "drop" + } + ] + } } - } + ] } } } diff --git a/src/tests/p4-fabric-tna/descriptors/service-p4-int.json b/src/tests/p4-fabric-tna/descriptors/service-p4-int.json index 7bffd72f1..9d70bca5b 100644 --- a/src/tests/p4-fabric-tna/descriptors/service-p4-int.json +++ b/src/tests/p4-fabric-tna/descriptors/service-p4-int.json @@ -24,18 +24,20 @@ "custom": { "resource_key": "/settings", "resource_value": { - "switch_info": { - "sw1": { - "arch": "v1model", - "dpid": 1, - "mac": "ee:ee:8c:6c:f3:2c", - "ip": "192.168.5.139", - "int_port": { - "port_id": 3, - "port_type": "host" + "switch_info": [ + { + "sw1": { + "arch": "v1model", + "dpid": 1, + "mac": "ee:ee:8c:6c:f3:2c", + "ip": "192.168.5.139", + "int_port": { + "port_id": 3, + "port_type": "host" + } } } - }, + ], "int_collector_info": { "mac": "3e:87:de:3d:6d:33", "ip": "192.168.5.131", diff --git a/src/tests/p4-fabric-tna/descriptors/service-p4-l2-simple.json b/src/tests/p4-fabric-tna/descriptors/service-p4-l2-simple.json index 05f53d7a6..8ecc2df96 100644 --- a/src/tests/p4-fabric-tna/descriptors/service-p4-l2-simple.json +++ b/src/tests/p4-fabric-tna/descriptors/service-p4-l2-simple.json @@ -24,34 +24,36 @@ "custom": { "resource_key": "/settings", "resource_value": { - "switch_info": { - "sw1": { - "arch": "v1model", - "dpid": 1, - "port_list": [ - { - "port_id": 1, - "port_type": "host", - "vlan_id": 4094 - }, - { - "port_id": 2, - "port_type": "host", - "vlan_id": 4094 - } - ], - "fwd_list": [ - { - "port_id": 1, - "host_mac": "00:00:00:00:00:01" - }, - { - "port_id": 2, - "host_mac": "00:00:00:00:00:02" - } - ] + "switch_info": [ + { + "sw1": { + "arch": "v1model", + "dpid": 1, + "port_list": [ + { + "port_id": 1, + "port_type": "host", + "vlan_id": 4094 + }, + { + "port_id": 2, + "port_type": "host", + "vlan_id": 4094 + } + ], + "fwd_list": [ + { + "port_id": 1, + "host_mac": "00:00:00:00:00:01" + }, + { + "port_id": 2, + "host_mac": "00:00:00:00:00:02" + } + ] + } } - } + ] } } } diff --git a/src/tests/p4-fabric-tna/descriptors/service-p4-l3.json b/src/tests/p4-fabric-tna/descriptors/service-p4-l3.json index 4a016f255..6fda23e80 100644 --- a/src/tests/p4-fabric-tna/descriptors/service-p4-l3.json +++ b/src/tests/p4-fabric-tna/descriptors/service-p4-l3.json @@ -24,38 +24,40 @@ "custom": { "resource_key": "/settings", "resource_value": { - "switch_info": { - "sw1": { - "arch": "v1model", - "dpid": 1, - "port_list": [ - { - "port_id": 1, - "port_type": "host" - }, - { - "port_id": 2, - "port_type": "host" - } - ], - "routing_list": [ - { - "port_id": 1, - "ipv4_dst": "10.0.0.1", - "ipv4_prefix_len": 32, - "mac_src": "00:00:00:00:00:02", - "mac_dst": "00:00:00:00:00:01" - }, - { - "port_id": 2, - "ipv4_dst": "10.0.0.2", - "ipv4_prefix_len": 32, - "mac_src": "00:00:00:00:00:01", - "mac_dst": "00:00:00:00:00:02" - } - ] + "switch_info": [ + { + "sw1": { + "arch": "v1model", + "dpid": 1, + "port_list": [ + { + "port_id": 1, + "port_type": "host" + }, + { + "port_id": 2, + "port_type": "host" + } + ], + "routing_list": [ + { + "port_id": 1, + "ipv4_dst": "10.0.0.1", + "ipv4_prefix_len": 32, + "mac_src": "00:00:00:00:00:02", + "mac_dst": "00:00:00:00:00:01" + }, + { + "port_id": 2, + "ipv4_dst": "10.0.0.2", + "ipv4_prefix_len": 32, + "mac_src": "00:00:00:00:00:01", + "mac_dst": "00:00:00:00:00:02" + } + ] + } } - } + ] } } } -- GitLab