diff options
Diffstat (limited to 'vicn/resource/icn/central.py')
-rw-r--r-- | vicn/resource/icn/central.py | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/vicn/resource/icn/central.py b/vicn/resource/icn/central.py new file mode 100644 index 00000000..aa8ea357 --- /dev/null +++ b/vicn/resource/icn/central.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import logging +import networkx as nx + +from netmodel.model.type import String +from vicn.core.attribute import Attribute, Reference +from vicn.core.exception import ResourceNotFound +from vicn.core.resource import Resource +from vicn.core.task import inline_task +from vicn.resource.central import _get_l2_graph, MAP_ROUTING_STRATEGY +from vicn.resource.icn.face import Face +from vicn.resource.icn.route import Route + +log = logging.getLogger(__name__) + + +def _get_icn_graph(manager, groups): + G = nx.Graph() + for group in groups: + # It's safer to iterate on node which we know are in the right groups, + # while it might not be the case for the forwarders... + for node in group.iter_by_type_str('node'): + G.add_node(node._state.uuid) + try: + forwarder = node.forwarder + except ResourceNotFound: + continue + for face in forwarder.faces: + other_face = manager.by_uuid(face._internal_data['sibling_face']) + other_node = other_face.node + if G.has_edge(node._state.uuid, other_node._state.uuid): + continue + map_node_face = { node._state.uuid: face._state.uuid, + other_node._state.uuid: other_face._state.uuid } + G.add_edge(node._state.uuid, other_node._state.uuid, + map_node_face = map_node_face) + + return G + +#------------------------------------------------------------------------------- + +class ICNFaces(Resource): + """ + Resource: ICNFaces + + Centralized ICN face creation. + """ + protocol_name = Attribute(String) + + #-------------------------------------------------------------------------- + # Resource lifecycle + #-------------------------------------------------------------------------- + + @inline_task + def __get__(self): + raise ResourceNotFound # always create faces + + @inline_task + def __create__(self): + icn_faces = self._get_faces() + for face in icn_faces: + face.node.forwarder.faces << face + + def __delete__(self): + raise NotImplementedError + + #-------------------------------------------------------------------------- + # Internal methods + #-------------------------------------------------------------------------- + + def _get_faces(self): + """ + Face creation (heuristic: facemgr) + + Requires: at least direct IP links + """ + faces = list() + G = _get_l2_graph(self.groups) + for src_node_uuid, dst_node_uuid, data in G.edges_iter(data = True): + src_node = self._state.manager.by_uuid(src_node_uuid) + dst_node = self._state.manager.by_uuid(dst_node_uuid) + + if not src_node.managed or not dst_node.managed: + continue + + map_ = data['map_node_interface'] + src = self._state.manager.by_uuid(map_[src_node_uuid]) + dst = self._state.manager.by_uuid(map_[dst_node_uuid]) + + log.debug('{} -> {} ({} -> {})'.format(src_node_uuid, + dst_node_uuid, src.device_name, dst.device_name)) + + face_cls = Face.from_protocol(self.protocol_name) + if face_cls is None: + raise NotImplementedError + + src_face = face_cls(protocol = self.protocol_name, + owner = self, + node = src_node, + src = src, + dst = dst) + dst_face = face_cls(protocol = self.protocol_name, + owner = self, + node = dst_node, + src = dst, + dst = src) + + + # We key the sibling face for easier building of the ICN graph + src_face._internal_data['sibling_face'] = dst_face._state.uuid + dst_face._internal_data['sibling_face'] = src_face._state.uuid + + faces.append(src_face) + faces.append(dst_face) + + return faces + +#------------------------------------------------------------------------------ + +class ICNRoutes(Resource): + """ + Resource: Routes + + Centralized ICN route computation. + """ + + routing_strategy = Attribute(String) + + #-------------------------------------------------------------------------- + # Resource lifecycle + #-------------------------------------------------------------------------- + + @inline_task + def __get__(self): + raise ResourceNotFound # always create routes + + @inline_task + def __create__(self): + icn_routes = self._get_icn_routes() + for route in icn_routes: + route.node.forwarder.routes << route + + def __delete__(self): + raise NotImplementedError + + #-------------------------------------------------------------------------- + # Internal methods + #-------------------------------------------------------------------------- + + def _get_prefix_origins(self): + origins = dict() + for group in self.groups: + for node in group.iter_by_type_str('node'): + node_uuid = node._state.uuid + if not node_uuid in origins: + origins[node_uuid] = list() + for producer in node.producers: + origins[node_uuid].extend(producer.prefixes) + return origins + + def _get_icn_routes(self): + strategy = MAP_ROUTING_STRATEGY.get(self.routing_strategy) + + G = _get_icn_graph(self._state.manager, self.groups) + origins = self._get_prefix_origins() + + routes = list() + for src, prefix, dst in strategy(G, origins): + src_node = self._state.manager.by_uuid(src) + if not src_node.managed: + continue + data = G.get_edge_data(src, dst) + + map_ = data['map_node_face'] + next_hop_face = map_[src] + + route = Route(node = src, + owner = self, + prefix = prefix, + face = next_hop_face) + routes.append(route) + + return routes + +#------------------------------------------------------------------------------ + +class CentralICN(Resource): + """ + Resource: CentralICN + + Central ICN management (main resource) + """ + + # Choices: spt, max_flow + icn_routing_strategy = Attribute(String, + description = 'ICN routing strategy', + default = 'spt') + face_protocol = Attribute(String, + description = 'Protocol used to create faces', + default = 'ether') + + #-------------------------------------------------------------------------- + # Resource lifecycle + #-------------------------------------------------------------------------- + + def __after__(self): + """ + We need to wait for IP configuration in order to be able to build + overload ICN faces, and producers for prefix origins. + """ + return ('CentralIP',) + + def __subresources__(self): + icn_faces = ICNFaces(owner = self, protocol_name = self.face_protocol, + groups = Reference(self, 'groups')) + icn_routes = ICNRoutes(owner = self, + routing_strategy = self.icn_routing_strategy, + groups = Reference(self, 'groups')) + return icn_faces > icn_routes |