From eaaec384b49ee39012e3327e7662033ee8acfe98 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Mon, 3 Jun 2024 12:23:19 -0400 Subject: [PATCH 1/7] ero changes --- fim/graph/abc_property_graph.py | 14 ++++++- fim/graph/neo4j_property_graph.py | 39 +++++++++++++++++++ fim/slivers/network_service.py | 6 +-- test/networkxx_pg_disjoint_test.py | 23 +++++++++++ test/networkxx_pg_test.py | 20 +++++++++- test/zz_neo4j_pg_test.py | 61 +++++++++++++++++++++++++++++- 6 files changed, 157 insertions(+), 6 deletions(-) diff --git a/fim/graph/abc_property_graph.py b/fim/graph/abc_property_graph.py index 00cf1a2..b7c1efe 100644 --- a/fim/graph/abc_property_graph.py +++ b/fim/graph/abc_property_graph.py @@ -335,6 +335,18 @@ def get_nodes_on_shortest_path(self, *, node_a: str, node_z: str, rel: str = Non :return: """ + def get_nodes_on_path_with_hops(self, *, node_a: str, node_z: str, hops: List[str], cut_off: int = 100) -> List: + """ + Get a list of node ids that lie on a path between two nodes with the specified hops. Return empty + list if no path can be found. Optionally specify the type of relationship that path + should consist of. + :param node_a: Starting node ID. + :param node_z: Ending node ID. + :param hops: List of relationship hops that must be present in the path. + :param cut_off: Optional Depth to stop the search. Only paths of length <= cutoff are returned. + :return: Path with specified hops and no loops exists, empty list otherwise. + """ + @abstractmethod def get_first_neighbor(self, *, node_id: str, rel: str, node_label: str) -> List: """ @@ -665,7 +677,7 @@ def sliver_to_dict(sliver) -> Dict[str, Any]: if sliver.network_service_info is not None: nss = list() - for ns in sliver.network_service_info.list_network_services(): + for ns in sliver.network_service_info.list_services(): nss.append(ABCPropertyGraph.sliver_to_dict(ns)) d['network_services'] = nss diff --git a/fim/graph/neo4j_property_graph.py b/fim/graph/neo4j_property_graph.py index 0edf28e..12eb33e 100644 --- a/fim/graph/neo4j_property_graph.py +++ b/fim/graph/neo4j_property_graph.py @@ -26,6 +26,7 @@ """ Neo4j-specific implementation of property graph abstraction """ +from collections import deque from typing import Dict, Any, Tuple, List, Set import logging @@ -416,6 +417,44 @@ def get_nodes_on_shortest_path(self, *, node_a: str, node_z: str, rel: str = Non return list() return val.data()['nodeids'] + def get_nodes_on_path_with_hops(self, *, node_a: str, node_z: str, hops: List[str], cut_off: int = 100) -> List: + """ + Get a list of node ids that lie on a path between two nodes with the specified hops. Return empty + list if no path can be found. Optionally specify the type of relationship that path + should consist of. + :param node_a: Starting node ID. + :param node_z: Ending node ID. + :param hops: List of relationship hops that must be present in the path. + :param cut_off: Optional Depth to stop the search. Only paths of length <= cutoff are returned. + :return: Path with specified hops and no loops exists, empty list otherwise. + """ + assert node_a is not None + assert node_z is not None + + query = "MATCH (a:GraphNode {GraphID: $graphId, NodeID: $nodeA}), " \ + "(z:GraphNode {GraphID: $graphId, NodeID: $nodeZ}) " \ + "CALL apoc.algo.allSimplePaths(a, z, 'connects|has', $cut_off) " \ + "YIELD path AS path WITH path, relationships(path) AS rels " \ + "WHERE size(rels) = size(apoc.coll.toSet(rels)) " \ + "RETURN [node in nodes(path) | node.NodeID] AS nodeids" + + path_nodes = [] + with self.driver.session() as session: + result = session.run(query, graphId=self.graph_id, nodeA=node_a, nodeZ=node_z, cut_off=cut_off) + for record in result: + path_nodes.append(record["nodeids"]) + + if not len(path_nodes): + return [] + + result = [] + for path in path_nodes: + if all(hop in path for hop in hops): + if not len(result) or len(result) > len(path): + result = path + + return result + def get_first_neighbor(self, *, node_id: str, rel: str, node_label: str) -> List[str]: """ Return a list of ids of nodes of this label related via relationship. List may be empty. diff --git a/fim/slivers/network_service.py b/fim/slivers/network_service.py index 77bba5e..d2ebf20 100644 --- a/fim/slivers/network_service.py +++ b/fim/slivers/network_service.py @@ -172,10 +172,10 @@ class NetworkServiceSliver(BaseSliver): num_instances=NO_LIMIT, desc='A Site-to-Site service in FABRIC.', required_properties=[], - forbidden_properties=['ero', - 'mirror_port', + forbidden_properties=['mirror_port', 'mirror_direction', - 'controller_url'], + 'controller_url', + "ero"], required_interface_types=[]), ServiceType.L2PTP: ServiceConstraintRecord(layer=NSLayer.L2, min_interfaces=2, num_interfaces=2, num_sites=2, diff --git a/test/networkxx_pg_disjoint_test.py b/test/networkxx_pg_disjoint_test.py index 51245f0..364a165 100644 --- a/test/networkxx_pg_disjoint_test.py +++ b/test/networkxx_pg_disjoint_test.py @@ -11,6 +11,7 @@ class NetworkXPropertyGraphDisjointTests(unittest.TestCase): GRAPH_FILE = "test/models/site-2-am-1broker-ad.graphml" + NET_FILE_DEV = "test/models/Network-dev.graphml" NET_FILE = "test/models/network-am-ad.graphml" FAVORITE_NODES = ['Worker1', 'SwitchFabric1', 'GPU1', 'NIC1', 'NICSwitchFabric1'] # this one set in file, should not be overwritten @@ -197,6 +198,28 @@ def test_shortest_path(self): edge_kind, edge_props = self.g.get_link_properties(node_a=e[0], node_b=e[1]) assert(edge_kind == e[2]) + def test_path_exists_with_hops(self): + graph_string = self.imp.enumerate_graph_nodes_to_string(graph_file=self.NET_FILE_DEV) + net_graph = self.imp.import_graph_from_string(graph_string=graph_string) + + renc_sw_node_id = "node+renc-data-sw:ip+192.168.11.3" + lbnl_sw_node_id = "node+lbnl-data-sw:ip+192.168.13.3" + hops = ["node+uky-data-sw:ip+192.168.12.3-ns"] + path = net_graph.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) + + assert(len(path) == 11) + + def test_path_not_exists_with_hops(self): + graph_string = self.imp.enumerate_graph_nodes_to_string(graph_file=self.NET_FILE_DEV) + net_graph = self.imp.import_graph_from_string(graph_string=graph_string) + + renc_sw_node_id = "node+renc-data-sw:ip+192.168.11.3" + lbnl_sw_node_id = "node+lbnl-data-sw:ip+192.168.13.3" + hops = ["node+max-data-sw:ip+192.168.12.3-ns"] + path = net_graph.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) + + assert (len(path) == 0) + def test_first_neighbor(self): favs = self._find_favorite_nodes() assert((favs.get('Worker1'), None) is not None) diff --git a/test/networkxx_pg_test.py b/test/networkxx_pg_test.py index b383619..5d52ecc 100644 --- a/test/networkxx_pg_test.py +++ b/test/networkxx_pg_test.py @@ -4,6 +4,8 @@ import uuid import json +import networkx as nx + import fim.graph.networkx_property_graph as nx_graph from fim.graph.abc_property_graph import ABCPropertyGraphConstants, ABCPropertyGraph, GraphFormat @@ -11,6 +13,7 @@ class NetworkXPropertyGraphTests(unittest.TestCase): GRAPH_FILE = "test/models/site-2-am-1broker-ad.graphml" + NET_FILE_DEV = "test/models/Network-dev.graphml" NET_FILE = "test/models/network-am-ad.graphml" FAVORITE_NODES = ['Worker1', 'SwitchFabric1', 'GPU1', 'NIC1', 'NICSwitchFabric1'] # this one set in file, should not be overwritten @@ -117,7 +120,6 @@ def test_node_properties(self): _, worker1_props = self.g.get_node_properties(node_id=worker1) assert(worker1_props.get('RandomProp', None) is None) - def test_edge_properties(self): favs = self._find_favorite_nodes() assert((favs.get('Worker1'), None) is not None) @@ -200,6 +202,22 @@ def test_shortest_path(self): edge_kind, edge_props = self.g.get_link_properties(node_a=e[0], node_b=e[1]) assert(edge_kind == e[2]) + def test_path_exists_with_hops(self): + graph_string = self.imp.enumerate_graph_nodes_to_string(graph_file=self.NET_FILE_DEV) + net_graph = self.imp.import_graph_from_string(graph_string=graph_string) + + renc_sw_node_id = "node+renc-data-sw:ip+192.168.11.3" + lbnl_sw_node_id = "node+lbnl-data-sw:ip+192.168.13.3" + hops = ["node+uky-data-sw:ip+192.168.12.3-ns"] + path = net_graph.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) + + assert(len(path) == 11) + + hops = ["node+max-data-sw:ip+192.168.12.3-ns"] + path = net_graph.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) + + assert (len(path) == 0) + def test_first_neighbor(self): favs = self._find_favorite_nodes() assert((favs.get('Worker1'), None) is not None) diff --git a/test/zz_neo4j_pg_test.py b/test/zz_neo4j_pg_test.py index ab71aa4..dada34f 100644 --- a/test/zz_neo4j_pg_test.py +++ b/test/zz_neo4j_pg_test.py @@ -1,12 +1,13 @@ import unittest +import yaml + import fim.user as fu from fim.graph.abc_property_graph import ABCPropertyGraphConstants, ABCPropertyGraph from fim.graph.neo4j_property_graph import Neo4jGraphImporter, Neo4jPropertyGraph from fim.graph.resources.neo4j_cbm import Neo4jCBMGraph from fim.graph.slices.neo4j_asm import Neo4jASM, Neo4jASMFactory from fim.graph.resources.neo4j_arm import Neo4jARMGraph -from fim.slivers.delegations import Delegation from fim.slivers.attached_components import AttachedComponentsInfo, ComponentSliver, ComponentType @@ -23,6 +24,16 @@ class Neo4jTests(unittest.TestCase): "import_host_dir": "neo4j/imports/", "import_dir": "/imports"} + FIM_CONFIG_YAML = "./fim_config.yml" + + try: + with open(FIM_CONFIG_YAML, 'r') as config_file: + yaml_config = yaml.safe_load(config_file) + neo4j = yaml_config.get("neo4j") + print(neo4j) + except IOError: + print(f"Unable to open config file {FIM_CONFIG_YAML}, Using the Default Config") + def setUp(self) -> None: self.n4j_imp = Neo4jGraphImporter(url=self.neo4j["url"], user=self.neo4j["user"], pswd=self.neo4j["pass"], @@ -373,5 +384,53 @@ def test_3_site_load(self): self.n4j_imp.delete_all_graphs() + def test_path_with_hops(self): + self.n4j_imp.delete_all_graphs() + + # these are produced by substrate tests + site_ads = ['models/RENC.graphml', 'models/UKY.graphml', 'models/LBNL.graphml', 'models/Network-dev.graphml'] + + cbm = Neo4jCBMGraph(importer=self.n4j_imp) + + adm_ids = dict() + site_arms = dict() + + for ad in site_ads: + plain_neo4j = self.n4j_imp.import_graph_from_file_direct(graph_file=ad) + print(f"Validating ARM graph {ad} with id {plain_neo4j.graph_id}") + plain_neo4j.validate_graph() + + site_arms[ad] = Neo4jARMGraph(graph=Neo4jPropertyGraph(graph_id=plain_neo4j.graph_id, + importer=self.n4j_imp)) + # generate a dict of ADMs from site graph ARM + site_adms = site_arms[ad].generate_adms() + print('ADMS ' + str(site_adms.keys())) + for adm_id in site_adms.keys(): + print(f' ADM id {site_adms[adm_id].graph_id}') + + # desired ADM is under 'primary' + site_adm = site_adms['primary'] + cbm.merge_adm(adm=site_adm) + + print('Deleting ADM and ARM graphs') + for adm in site_adms.values(): + adm_ids[ad] = adm.graph_id + adm.delete_graph() + #site_arms[ad].delete_graph() + + cbm.validate_graph() + print('CBM ID is ' + cbm.graph_id) + + renc_sw_node_id = "node+renc-data-sw:ip+192.168.11.3" + lbnl_sw_node_id = "node+lbnl-data-sw:ip+192.168.13.3" + hops = ["node+uky-data-sw:ip+192.168.12.3-ns"] + path = cbm.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) + + assert (len(path) == 11) + + hops = ["node+max-data-sw:ip+192.168.12.3-ns"] + path = cbm.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) + assert (len(path) == 0) + cbm.delete_graph() From 7e5b4281e9a886be9db95b241f7e94675bafa9f2 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Mon, 3 Jun 2024 12:24:06 -0400 Subject: [PATCH 2/7] up the version --- fim/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fim/__init__.py b/fim/__init__.py index 7e5f261..92681a7 100644 --- a/fim/__init__.py +++ b/fim/__init__.py @@ -1,5 +1,5 @@ """ FABRIC Information Model library and utilities """ -__VERSION__ = "1.7.0b4" +__VERSION__ = "1.7.0b5" __version__ = __VERSION__ From a436982b6288dfc35c4f2075451048ebb2ad6822 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Mon, 3 Jun 2024 12:24:45 -0400 Subject: [PATCH 3/7] add dev net model for tests --- test/models/Network-dev.graphml | 1069 +++++++++++++++++++++++++++++++ 1 file changed, 1069 insertions(+) create mode 100644 test/models/Network-dev.graphml diff --git a/test/models/Network-dev.graphml b/test/models/Network-dev.graphml new file mode 100644 index 0000000..b3b38ce --- /dev/null +++ b/test/models/Network-dev.graphml @@ -0,0 +1,1069 @@ + + + + + + + + + + + + + + + + + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkNode + node+AL2S + AL2S + Switch + {"unit": 1} + true + AL2S + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+AL2S-ns + AL2S-ns + MPLS + true + L2 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkNode + node+lbnl-data-sw:ip+192.168.13.3 + lbnl-data-sw + Switch + NCS 55A1-36H + {"unit": 1} + {"ipv4": "192.168.13.3", "local_name": "lbnl-data-sw"} + false + LBNL + {"primary": {"pool_id": "_", "capacities": {"unit": 1}}} + {"primary": {"pool_id": "_", "labels": {"ipv4": "192.168.13.3", "local_name": "lbnl-data-sw"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+lbnl-data-sw:ip+192.168.13.3-ipv4-ns + lbnl-data-sw-ipv4-ns + FABNetv4 + {"ipv4": "10.129.0.1", "ipv4_subnet": "10.129.0.0/17"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv4": "10.129.0.1", "ipv4_subnet": "10.129.0.0/17"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+lbnl-data-sw:ip+192.168.13.3-ipv4ext-ns + lbnl-data-sw-ipv4ext-ns + FABNetv4Ext + {"ipv4_subnet": "23.134.232.32/28"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv4_subnet": "23.134.232.32/28"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+lbnl-data-sw:ip+192.168.13.3-ipv6-ns + lbnl-data-sw-ipv6-ns + FABNetv6 + {"ipv6": "2602:fcfb:2::1", "ipv6_subnet": "2602:fcfb:2::/48"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv6": "2602:fcfb:2::1", "ipv6_subnet": "2602:fcfb:2::/48"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+lbnl-data-sw:ip+192.168.13.3-ipv6ext-ns + lbnl-data-sw-ipv6ext-ns + FABNetv6Ext + {"ipv6_subnet": "2602:fcfb:2::/48"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv6_subnet": "2602:fcfb:2::/48"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+lbnl-data-sw:ip+192.168.13.3-l3vpn-ns + lbnl-data-sw-l3vpn-ns + L3VPN + {"asn": "398900"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"asn": "398900"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+lbnl-data-sw:ip+192.168.13.3-ns + lbnl-data-sw-ns + MPLS + + false + L2 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/0 + HundredGigE0/0/0/0 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/0", "mac": "94:ae:f0:dc:a8:00"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:00", "local_name": "HundredGigE0/0/0/0"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/0.2400 + HundredGigE0/0/0/0.2400 + TrunkPort + {"bw": 100} + {"ipv4": "10.128.0.134", "ipv6": "2602:fcfb:0:1024::6", "local_name": "HundredGigE0/0/0/0.2400", "mac": "94:ae:f0:dc:a8:00"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:00", "ipv4": "10.128.0.134", "ipv6": "2602:fcfb:0:1024::6", "local_name": "HundredGigE0/0/0/0.2400"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/0.2401 + HundredGigE0/0/0/0.2401 + TrunkPort + {"bw": 100} + {"ipv4": "10.128.128.130", "ipv6": "2602:fcfb:1:1024::2", "local_name": "HundredGigE0/0/0/0.2401", "mac": "94:ae:f0:dc:a8:00"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:00", "ipv4": "10.128.128.130", "ipv6": "2602:fcfb:1:1024::2", "local_name": "HundredGigE0/0/0/0.2401"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/1 + HundredGigE0/0/0/1 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/1", "mac": "94:ae:f0:dc:a8:04"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:04", "local_name": "HundredGigE0/0/0/1"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/13 + HundredGigE0/0/0/13 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/13", "mac": "94:ae:f0:dc:a8:34"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:34", "local_name": "HundredGigE0/0/0/13"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/15 + HundredGigE0/0/0/15 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/15", "mac": "94:ae:f0:dc:a8:3c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:3c", "local_name": "HundredGigE0/0/0/15"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/17 + HundredGigE0/0/0/17 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/17", "mac": "94:ae:f0:dc:a8:44"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:44", "local_name": "HundredGigE0/0/0/17"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/19 + HundredGigE0/0/0/19 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/19", "mac": "94:ae:f0:dc:a8:4c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:4c", "local_name": "HundredGigE0/0/0/19"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/21 + HundredGigE0/0/0/21 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/21", "mac": "94:ae:f0:dc:a8:54"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:54", "local_name": "HundredGigE0/0/0/21"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/5 + HundredGigE0/0/0/5 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/5", "mac": "94:ae:f0:dc:a8:14"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:14", "local_name": "HundredGigE0/0/0/5"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:HundredGigE0/0/0/9 + HundredGigE0/0/0/9 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/9", "mac": "94:ae:f0:dc:a8:24"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:24", "local_name": "HundredGigE0/0/0/9"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:TwentyFiveGigE0/0/0/23/0 + TwentyFiveGigE0/0/0/23/0 + TrunkPort + {"bw": 25} + {"local_name": "TwentyFiveGigE0/0/0/23/0", "mac": "94:ae:f0:dc:a8:5c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 25}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:5c", "local_name": "TwentyFiveGigE0/0/0/23/0"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:TwentyFiveGigE0/0/0/23/1 + TwentyFiveGigE0/0/0/23/1 + TrunkPort + {"bw": 25} + {"local_name": "TwentyFiveGigE0/0/0/23/1", "mac": "94:ae:f0:dc:a8:5d"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 25}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:5d", "local_name": "TwentyFiveGigE0/0/0/23/1"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:TwentyFiveGigE0/0/0/23/2 + TwentyFiveGigE0/0/0/23/2 + TrunkPort + {"bw": 25} + {"local_name": "TwentyFiveGigE0/0/0/23/2", "mac": "94:ae:f0:dc:a8:5e"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 25}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:5e", "local_name": "TwentyFiveGigE0/0/0/23/2"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+lbnl-data-sw:TwentyFiveGigE0/0/0/23/3 + TwentyFiveGigE0/0/0/23/3 + TrunkPort + {"bw": 25} + {"local_name": "TwentyFiveGigE0/0/0/23/3", "mac": "94:ae:f0:dc:a8:5f"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 25}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:dc:a8:5f", "local_name": "TwentyFiveGigE0/0/0/23/3"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkNode + node+renc-data-sw:ip+192.168.11.3 + renc-data-sw + Switch + NCS 55A1-36H + {"unit": 1} + {"ipv4": "192.168.11.3", "local_name": "renc-data-sw"} + false + RENC + {"primary": {"pool_id": "_", "capacities": {"unit": 1}}} + {"primary": {"pool_id": "_", "labels": {"ipv4": "192.168.11.3", "local_name": "renc-data-sw"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+renc-data-sw:ip+192.168.11.3-ipv4-ns + renc-data-sw-ipv4-ns + FABNetv4 + {"ipv4": "10.128.0.1", "ipv4_subnet": "10.128.0.0/17"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv4": "10.128.0.1", "ipv4_subnet": "10.128.0.0/17"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+renc-data-sw:ip+192.168.11.3-ipv4ext-ns + renc-data-sw-ipv4ext-ns + FABNetv4Ext + {"ipv4_subnet": "23.134.232.0/28"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv4_subnet": "23.134.232.0/28"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+renc-data-sw:ip+192.168.11.3-ipv6-ns + renc-data-sw-ipv6-ns + FABNetv6 + {"ipv6": "2602:fcfb::1", "ipv6_subnet": "2602:fcfb::/48"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv6": "2602:fcfb::1", "ipv6_subnet": "2602:fcfb::/48"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+renc-data-sw:ip+192.168.11.3-ipv6ext-ns + renc-data-sw-ipv6ext-ns + FABNetv6Ext + {"ipv6_subnet": "2602:fcfb::/48"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv6_subnet": "2602:fcfb::/48"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+renc-data-sw:ip+192.168.11.3-l3vpn-ns + renc-data-sw-l3vpn-ns + L3VPN + {"asn": "398900"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"asn": "398900"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+renc-data-sw:ip+192.168.11.3-ns + renc-data-sw-ns + MPLS + + false + L2 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:FortyGigE0/0/0/18 + FortyGigE0/0/0/18 + TrunkPort + {"bw": 40} + {"local_name": "FortyGigE0/0/0/18", "mac": "bc:2c:e6:9a:94:4c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 40}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:4c", "local_name": "FortyGigE0/0/0/18"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:HundredGigE0/0/0/0 + HundredGigE0/0/0/0 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/0", "mac": "bc:2c:e6:9a:94:04"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:04", "local_name": "HundredGigE0/0/0/0"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:HundredGigE0/0/0/13 + HundredGigE0/0/0/13 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/13", "mac": "bc:2c:e6:9a:94:38"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:38", "local_name": "HundredGigE0/0/0/13"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:HundredGigE0/0/0/2 + HundredGigE0/0/0/2 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/2", "mac": "bc:2c:e6:9a:94:0c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:0c", "local_name": "HundredGigE0/0/0/2"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:HundredGigE0/0/0/4 + HundredGigE0/0/0/4 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/4", "mac": "bc:2c:e6:9a:94:14"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:14", "local_name": "HundredGigE0/0/0/4"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:HundredGigE0/0/0/5 + HundredGigE0/0/0/5 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/5", "mac": "bc:2c:e6:9a:94:18"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:18", "local_name": "HundredGigE0/0/0/5"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:HundredGigE0/0/0/6 + HundredGigE0/0/0/6 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/6", "mac": "bc:2c:e6:9a:94:1c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:1c", "local_name": "HundredGigE0/0/0/6"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:HundredGigE0/0/0/9 + HundredGigE0/0/0/9 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/9", "mac": "bc:2c:e6:9a:94:28"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:28", "local_name": "HundredGigE0/0/0/9"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:TenGigE0/0/0/22 + TenGigE0/0/0/22 + TrunkPort + {"bw": 10} + {"local_name": "TenGigE0/0/0/22", "mac": "bc:2c:e6:9a:94:5c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 10}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:5c", "local_name": "TenGigE0/0/0/22"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:TenGigE0/0/0/22.3981 + TenGigE0/0/0/22.3981 + TrunkPort + {"bw": 10} + {"ipv4": "10.128.0.133", "ipv6": "2602:fcfb:0:1024::5", "local_name": "TenGigE0/0/0/22.3981", "mac": "bc:2c:e6:9a:94:5c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 10}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:5c", "ipv4": "10.128.0.133", "ipv6": "2602:fcfb:0:1024::5", "local_name": "TenGigE0/0/0/22.3981"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:TenGigE0/0/0/22.3999 + TenGigE0/0/0/22.3999 + TrunkPort + {"bw": 10} + {"ipv4": "10.128.0.129", "ipv6": "2602:fcfb:0:1024::1", "local_name": "TenGigE0/0/0/22.3999", "mac": "bc:2c:e6:9a:94:5c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 10}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:5c", "ipv4": "10.128.0.129", "ipv6": "2602:fcfb:0:1024::1", "local_name": "TenGigE0/0/0/22.3999"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:TwentyFiveGigE0/0/0/10/0 + TwentyFiveGigE0/0/0/10/0 + TrunkPort + {"bw": 25} + {"local_name": "TwentyFiveGigE0/0/0/10/0", "mac": "bc:2c:e6:9a:94:2c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 25}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:2c", "local_name": "TwentyFiveGigE0/0/0/10/0"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:TwentyFiveGigE0/0/0/10/1 + TwentyFiveGigE0/0/0/10/1 + TrunkPort + {"bw": 25} + {"local_name": "TwentyFiveGigE0/0/0/10/1", "mac": "bc:2c:e6:9a:94:2d"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 25}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:2d", "local_name": "TwentyFiveGigE0/0/0/10/1"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:TwentyFiveGigE0/0/0/10/2 + TwentyFiveGigE0/0/0/10/2 + TrunkPort + {"bw": 25} + {"local_name": "TwentyFiveGigE0/0/0/10/2", "mac": "bc:2c:e6:9a:94:2e"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 25}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:2e", "local_name": "TwentyFiveGigE0/0/0/10/2"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+renc-data-sw:TwentyFiveGigE0/0/0/10/3 + TwentyFiveGigE0/0/0/10/3 + TrunkPort + {"bw": 25} + {"local_name": "TwentyFiveGigE0/0/0/10/3", "mac": "bc:2c:e6:9a:94:2f"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 25}}} + {"primary": {"pool_id": "_", "labels": {"mac": "bc:2c:e6:9a:94:2f", "local_name": "TwentyFiveGigE0/0/0/10/3"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkNode + node+uky-data-sw:ip+192.168.12.3 + uky-data-sw + Switch + NCS 55A1-36H + {"unit": 1} + {"ipv4": "192.168.12.3", "local_name": "uky-data-sw"} + false + UKY + {"primary": {"pool_id": "_", "capacities": {"unit": 1}}} + {"primary": {"pool_id": "_", "labels": {"ipv4": "192.168.12.3", "local_name": "uky-data-sw"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+uky-data-sw:ip+192.168.12.3-ipv4-ns + uky-data-sw-ipv4-ns + FABNetv4 + {"ipv4": "10.128.128.1", "ipv4_subnet": "10.128.128.0/17"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv4": "10.128.128.1", "ipv4_subnet": "10.128.128.0/17"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+uky-data-sw:ip+192.168.12.3-ipv4ext-ns + uky-data-sw-ipv4ext-ns + FABNetv4Ext + {"ipv4_subnet": "23.134.232.16/28"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv4_subnet": "23.134.232.16/28"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+uky-data-sw:ip+192.168.12.3-ipv6-ns + uky-data-sw-ipv6-ns + FABNetv6 + {"ipv6": "2602:fcfb:1::1", "ipv6_subnet": "2602:fcfb:1::/48"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv6": "2602:fcfb:1::1", "ipv6_subnet": "2602:fcfb:1::/48"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+uky-data-sw:ip+192.168.12.3-ipv6ext-ns + uky-data-sw-ipv6ext-ns + FABNetv6Ext + {"ipv6_subnet": "2602:fcfb:1::/48"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"ipv6_subnet": "2602:fcfb:1::/48"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+uky-data-sw:ip+192.168.12.3-l3vpn-ns + uky-data-sw-l3vpn-ns + L3VPN + {"asn": "398900"} + false + L3 + {"primary": {"pool_id": "_", "labels": {"asn": "398900"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + node+uky-data-sw:ip+192.168.12.3-ns + uky-data-sw-ns + MPLS + + false + L2 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/0 + HundredGigE0/0/0/0 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/0", "mac": "94:ae:f0:e3:58:00"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:00", "local_name": "HundredGigE0/0/0/0"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkNode + port+uky-data-sw:HundredGigE0/0/0/0:facility+UKY-AL2S + UKY-AL2S + Facility + false + UKY + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + NetworkService + port+uky-data-sw:HundredGigE0/0/0/0:facility+UKY-AL2S-ns + UKY-AL2S-ns + VLAN + false + L2 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/0:facility+UKY-AL2S-int + UKY-AL2S-int + FacilityPort + + {"device_name": "core1.loui", "local_name": "HundredGigE0/0/0/24", "vlan_range": ["852-855"]} + false + Intenet2 AL2S at LOUI to UKY + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + Link + port+uky-data-sw:HundredGigE0/0/0/0:facility+UKY-AL2S+link + UKY-AL2S-link + L2Path + false + L2 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+al2s:core1.loui:HundredGigE0/0/0/24 + core1.loui:HundredGigE0/0/0/24 + TrunkPort + {"vlan_range": ["852-855"]} + true + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + Link + port+uky-data-sw:HundredGigE0/0/0/0:core1.loui:HundredGigE0/0/0/24+link + core1.loui:HundredGigE0/0/0/24-link + L2Path + false + L2 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/0.850 + HundredGigE0/0/0/0.850 + TrunkPort + {"bw": 100} + {"ipv4": "10.128.128.137", "ipv6": "2602:fcfb:1:1024::9", "local_name": "HundredGigE0/0/0/0.850", "mac": "94:ae:f0:e3:58:00"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:00", "ipv4": "10.128.128.137", "ipv6": "2602:fcfb:1:1024::9", "local_name": "HundredGigE0/0/0/0.850"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/0.851 + HundredGigE0/0/0/0.851 + TrunkPort + {"bw": 100} + {"ipv4": "10.128.128.129", "ipv6": "2602:fcfb:1:1024::1", "local_name": "HundredGigE0/0/0/0.851", "mac": "94:ae:f0:e3:58:00"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:00", "ipv4": "10.128.128.129", "ipv6": "2602:fcfb:1:1024::1", "local_name": "HundredGigE0/0/0/0.851"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/0.859 + HundredGigE0/0/0/0.859 + TrunkPort + {"bw": 100} + {"ipv4": "10.128.0.130", "ipv6": "2602:fcfb:0:1024::2", "local_name": "HundredGigE0/0/0/0.859", "mac": "94:ae:f0:e3:58:00"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:00", "ipv4": "10.128.0.130", "ipv6": "2602:fcfb:0:1024::2", "local_name": "HundredGigE0/0/0/0.859"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/13 + HundredGigE0/0/0/13 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/13", "mac": "94:ae:f0:e3:58:34"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:34", "local_name": "HundredGigE0/0/0/13"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/15 + HundredGigE0/0/0/15 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/15", "mac": "94:ae:f0:e3:58:3c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:3c", "local_name": "HundredGigE0/0/0/15"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/17 + HundredGigE0/0/0/17 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/17", "mac": "94:ae:f0:e3:58:44"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:44", "local_name": "HundredGigE0/0/0/17"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/19 + HundredGigE0/0/0/19 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/19", "mac": "94:ae:f0:e3:58:4c"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:4c", "local_name": "HundredGigE0/0/0/19"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/21 + HundredGigE0/0/0/21 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/21", "mac": "94:ae:f0:e3:58:54"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:54", "local_name": "HundredGigE0/0/0/21"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/5 + HundredGigE0/0/0/5 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/5", "mac": "94:ae:f0:e3:58:14"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:14", "local_name": "HundredGigE0/0/0/5"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + ConnectionPoint + port+uky-data-sw:HundredGigE0/0/0/9 + HundredGigE0/0/0/9 + TrunkPort + {"bw": 100} + {"local_name": "HundredGigE0/0/0/9", "mac": "94:ae:f0:e3:58:24"} + false + {"primary": {"pool_id": "_", "capacities": {"bw": 100}}} + {"primary": {"pool_id": "_", "labels": {"mac": "94:ae:f0:e3:58:24", "local_name": "HundredGigE0/0/0/9"}}} + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + Link + link:local-port+lbnl-data-sw:HundredGigE0/0/0/0.2400:remote-port+renc-data-sw:TenGigE0/0/0/22.3981 + port+lbnl-data-sw:HundredGigE0/0/0/0.2400 to port+renc-data-sw:TenGigE0/0/0/22.3981 + L1Path + false + L1 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + Link + link:local-port+lbnl-data-sw:HundredGigE0/0/0/0.2401:remote-port+uky-data-sw:HundredGigE0/0/0/0.851 + port+lbnl-data-sw:HundredGigE0/0/0/0.2401 to port+uky-data-sw:HundredGigE0/0/0/0.851 + L1Path + false + L1 + + + de8bdc67-fcfb-4558-8f10-17b0832c4ff6 + Link + link:local-port+renc-data-sw:TenGigE0/0/0/22.3999:remote-port+uky-data-sw:HundredGigE0/0/0/0.859 + port+renc-data-sw:TenGigE0/0/0/22.3999 to port+uky-data-sw:HundredGigE0/0/0/0.859 + L1Path + false + L1 + + + has + + + connects + + + has + + + has + + + has + + + has + + + has + + + has + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + has + + + has + + + has + + + has + + + has + + + has + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + has + + + has + + + has + + + has + + + has + + + has + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + connects + + + has + + + connects + + + connects + + + connects + + + connects + + + connects + + + From 5d2335a785f42357e18c1d684e25becdbce521ee Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Mon, 3 Jun 2024 13:27:41 -0400 Subject: [PATCH 4/7] remove temp changes --- test/zz_neo4j_pg_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/zz_neo4j_pg_test.py b/test/zz_neo4j_pg_test.py index dada34f..801e52d 100644 --- a/test/zz_neo4j_pg_test.py +++ b/test/zz_neo4j_pg_test.py @@ -10,6 +10,7 @@ from fim.graph.resources.neo4j_arm import Neo4jARMGraph from fim.slivers.attached_components import AttachedComponentsInfo, ComponentSliver, ComponentType +from fim.slivers.network_node import NodeType class Neo4jTests(unittest.TestCase): From 108775b78f0d7ecc3457dd13a28acb6f753491c2 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Mon, 3 Jun 2024 17:23:01 -0400 Subject: [PATCH 5/7] add comments and networkx implementation --- fim/graph/abc_property_graph.py | 2 +- fim/graph/neo4j_property_graph.py | 4 ++- fim/graph/networkx_property_graph.py | 40 ++++++++++++++++++++++++++++ test/networkxx_pg_test.py | 6 +++-- test/zz_neo4j_pg_test.py | 6 +++-- 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/fim/graph/abc_property_graph.py b/fim/graph/abc_property_graph.py index b7c1efe..49f6475 100644 --- a/fim/graph/abc_property_graph.py +++ b/fim/graph/abc_property_graph.py @@ -342,7 +342,7 @@ def get_nodes_on_path_with_hops(self, *, node_a: str, node_z: str, hops: List[st should consist of. :param node_a: Starting node ID. :param node_z: Ending node ID. - :param hops: List of relationship hops that must be present in the path. + :param hops: List of hops that must be present in the path. :param cut_off: Optional Depth to stop the search. Only paths of length <= cutoff are returned. :return: Path with specified hops and no loops exists, empty list otherwise. """ diff --git a/fim/graph/neo4j_property_graph.py b/fim/graph/neo4j_property_graph.py index 12eb33e..d026df4 100644 --- a/fim/graph/neo4j_property_graph.py +++ b/fim/graph/neo4j_property_graph.py @@ -424,7 +424,7 @@ def get_nodes_on_path_with_hops(self, *, node_a: str, node_z: str, hops: List[st should consist of. :param node_a: Starting node ID. :param node_z: Ending node ID. - :param hops: List of relationship hops that must be present in the path. + :param hops: List of hops that must be present in the path. :param cut_off: Optional Depth to stop the search. Only paths of length <= cutoff are returned. :return: Path with specified hops and no loops exists, empty list otherwise. """ @@ -449,7 +449,9 @@ def get_nodes_on_path_with_hops(self, *, node_a: str, node_z: str, hops: List[st result = [] for path in path_nodes: + # Check all hops are in path if all(hop in path for hop in hops): + # Update shortest path if not len(result) or len(result) > len(path): result = path diff --git a/fim/graph/networkx_property_graph.py b/fim/graph/networkx_property_graph.py index 6633cbb..d676dde 100644 --- a/fim/graph/networkx_property_graph.py +++ b/fim/graph/networkx_property_graph.py @@ -420,6 +420,46 @@ def get_nodes_on_shortest_path(self, *, node_a: str, node_z: str, rel: str = Non return list() return self._get_node_ids_for_list(graph, sp) + def get_nodes_on_path_with_hops(self, *, node_a: str, node_z: str, hops: List[str], cut_off: int = 100) -> List: + """ + Get a list of node ids that lie on a path between two nodes with the specified hops. Return empty + list if no path can be found. Optionally specify the type of relationship that path + should consist of. + :param node_a: Starting node ID. + :param node_z: Ending node ID. + :param hops: List of hops that must be present in the path. + :param cut_off: Optional Depth to stop the search. Only paths of length <= cutoff are returned. + :return: Path with specified hops and no loops exists, empty list otherwise. + """ + # extract a graph + graph = self.storage.extract_graph(self.graph_id) + if graph is None: + raise PropertyGraphQueryException(graph_id=self.graph_id, + msg="Unable to find graph") + real_node_a = self._find_node(node_id=node_a) + real_node_z = self._find_node(node_id=node_z) + + try: + all_paths = nx.all_simple_paths(graph, real_node_a, real_node_z, cutoff=cut_off) + except nx.exception.NetworkXNoPath: + return list() + + result = [] + for path in all_paths: + subgraph = graph.subgraph(path) + # check no cycles + cycles = nx.cycle_basis(subgraph) + if len(cycles): + continue + # Extract Node Id for all nodes in Path + path_node_ids = self._get_node_ids_for_list(graph, path) + # Check all hops are in path + if all(hop in path_node_ids for hop in hops): + # Update the result if this path is shortest + if not len(result) or len(result) > len(path_node_ids): + result = path_node_ids + return result + def get_first_neighbor(self, *, node_id: str, rel: str, node_label: str) -> List: """ Return a list of ids of nodes of this label related via relationship. List may be empty. diff --git a/test/networkxx_pg_test.py b/test/networkxx_pg_test.py index 5d52ecc..b978397 100644 --- a/test/networkxx_pg_test.py +++ b/test/networkxx_pg_test.py @@ -12,8 +12,8 @@ class NetworkXPropertyGraphTests(unittest.TestCase): - GRAPH_FILE = "test/models/site-2-am-1broker-ad.graphml" - NET_FILE_DEV = "test/models/Network-dev.graphml" + GRAPH_FILE = "models/site-2-am-1broker-ad.graphml" + NET_FILE_DEV = "models/Network-dev.graphml" NET_FILE = "test/models/network-am-ad.graphml" FAVORITE_NODES = ['Worker1', 'SwitchFabric1', 'GPU1', 'NIC1', 'NICSwitchFabric1'] # this one set in file, should not be overwritten @@ -211,6 +211,8 @@ def test_path_exists_with_hops(self): hops = ["node+uky-data-sw:ip+192.168.12.3-ns"] path = net_graph.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) + print(path) + assert(len(path) == 11) hops = ["node+max-data-sw:ip+192.168.12.3-ns"] diff --git a/test/zz_neo4j_pg_test.py b/test/zz_neo4j_pg_test.py index 801e52d..8daae2b 100644 --- a/test/zz_neo4j_pg_test.py +++ b/test/zz_neo4j_pg_test.py @@ -424,8 +424,10 @@ def test_path_with_hops(self): renc_sw_node_id = "node+renc-data-sw:ip+192.168.11.3" lbnl_sw_node_id = "node+lbnl-data-sw:ip+192.168.13.3" - hops = ["node+uky-data-sw:ip+192.168.12.3-ns"] - path = cbm.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) + uky_sw_node_id = "node+uky-data-sw:ip+192.168.12.3" + hops = [f"{renc_sw_node_id}-ns"] + path = cbm.get_nodes_on_path_with_hops(node_a=lbnl_sw_node_id, node_z=uky_sw_node_id, hops=hops, cut_off=200) + print(f"Source: {lbnl_sw_node_id} End: {uky_sw_node_id} Hops: {hops} Path: {path}") assert (len(path) == 11) From f74b75c231da62371752ff8d4d5b9deba23f76d1 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Mon, 3 Jun 2024 17:23:39 -0400 Subject: [PATCH 6/7] up the version --- fim/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fim/__init__.py b/fim/__init__.py index 92681a7..b886e7c 100644 --- a/fim/__init__.py +++ b/fim/__init__.py @@ -1,5 +1,5 @@ """ FABRIC Information Model library and utilities """ -__VERSION__ = "1.7.0b5" +__VERSION__ = "1.7.0b6" __version__ = __VERSION__ From 20c8cfae45433e3ccb70d0b67e947ec0261245e5 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Mon, 3 Jun 2024 17:25:05 -0400 Subject: [PATCH 7/7] fix path in tests --- test/networkxx_pg_test.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/networkxx_pg_test.py b/test/networkxx_pg_test.py index b978397..5d52ecc 100644 --- a/test/networkxx_pg_test.py +++ b/test/networkxx_pg_test.py @@ -12,8 +12,8 @@ class NetworkXPropertyGraphTests(unittest.TestCase): - GRAPH_FILE = "models/site-2-am-1broker-ad.graphml" - NET_FILE_DEV = "models/Network-dev.graphml" + GRAPH_FILE = "test/models/site-2-am-1broker-ad.graphml" + NET_FILE_DEV = "test/models/Network-dev.graphml" NET_FILE = "test/models/network-am-ad.graphml" FAVORITE_NODES = ['Worker1', 'SwitchFabric1', 'GPU1', 'NIC1', 'NICSwitchFabric1'] # this one set in file, should not be overwritten @@ -211,8 +211,6 @@ def test_path_exists_with_hops(self): hops = ["node+uky-data-sw:ip+192.168.12.3-ns"] path = net_graph.get_nodes_on_path_with_hops(node_a=renc_sw_node_id, node_z=lbnl_sw_node_id, hops=hops) - print(path) - assert(len(path) == 11) hops = ["node+max-data-sw:ip+192.168.12.3-ns"]