diff options
Diffstat (limited to 'vicn/core/address_mgr.py')
-rw-r--r-- | vicn/core/address_mgr.py | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/vicn/core/address_mgr.py b/vicn/core/address_mgr.py new file mode 100644 index 00000000..7df5e4ac --- /dev/null +++ b/vicn/core/address_mgr.py @@ -0,0 +1,181 @@ +#!/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 ipaddress +import logging +import random +import struct +import socket + +from netmodel.util.deprecated import deprecated +from netmodel.util.singleton import Singleton +from netmodel.util.toposort import toposort, toposort_flatten + +log = logging.getLogger(__name__) + +#------------------------------------------------------------------------------ +# SharedResource +#------------------------------------------------------------------------------ + +class SharedResource: + """ + Base class for allocating shared resource + """ + def __init__(self): + self._counter = 0 + self._values = dict() + + def __next__(self): + ret = self._counter + self._counter += 1 + return ret + + def get(self, requestor, tag = None): + if requestor not in self._values: + self._values[requestor] = dict() + if tag not in self._values[requestor]: + self._values[requestor][tag] = next(self) + return self._values[requestor][tag] + +#------------------------------------------------------------------------------ + +class Vlan(SharedResource): + """ + SharedResource: Vlan + + Manages VLAN allocation + """ + + def get(self, requestor, tag = None): + if requestor not in self._values: + self._values[requestor] = dict() + if tag not in self._values[requestor]: + self._values[requestor][tag] = (next(self)+1) + return self._values[requestor][tag] + +#------------------------------------------------------------------------------ + +MAX_DEVICE_NAME_SIZE = 15 + +class DeviceName(SharedResource): + + def get(self, *args, prefix = None, **kwargs): + count = super().get(*args, **kwargs) + device_name = '{}{}'.format(prefix, count) + if len(device_name) > MAX_DEVICE_NAME_SIZE: + overflow = len(device_name) - MAX_DEVICE_NAME_SIZE + max_prefix_len = len(prefix) - overflow + device_name = '{}{}'.format(prefix[:max_prefix_len], count) + return device_name + +#------------------------------------------------------------------------------ + +class IpAddress(SharedResource): + pass + +class Ipv4Address(IpAddress): + pass + +class Ipv6Address(IpAddress): + pass + +#------------------------------------------------------------------------------ +# AddressManager +#------------------------------------------------------------------------------ + +class AddressManager(metaclass = Singleton): + """ + The purpose of this class is to generate sequential deterministic MAC/IP + addresses in order to assign them to the node in the network. + """ + + MAP_TYPE = { + 'vlan': Vlan, + 'device_name': DeviceName, + } + + def __init__(self): + self._ips = dict() + self._macs = dict() + + self._pools = dict() + + from vicn.core.resource_mgr import ResourceManager + + network = ResourceManager().get('network') + network = ipaddress.ip_network(network, strict=False) + self._next_ip = network[1] + + mac_address_base = ResourceManager().get('mac_address_base') + self._next_mac = int(mac_address_base, 0) + 1 + + def get(self, resource_type, requestor, *args, tag=None, scope=None, + **kwargs): + """ + Params: + type : the type of shared resource to be requested + requestor: name of the resource that requests the shared resource, in + order to reattribute the same if requested multiple times. + tag: use when a single resource request multiple times the same + resource. + scope: None = global scope by default. Ensure uniqueness of resource + at global scope + """ + if not scope in self._pools: + self._pools[scope] = dict() + if not resource_type in self._pools[scope]: + self._pools[scope][resource_type] = self.MAP_TYPE[resource_type]() + return self._pools[scope][resource_type].get(requestor, tag, + *args, **kwargs) + + #-------------------------------------------------------------------------- + # Attributes + #-------------------------------------------------------------------------- + + def get_mac(self, resource_name): + """ + Generate a new mac address to assign to the containers created. + + :return: The MAC address + """ + + if resource_name in self._macs: + return self._macs[resource_name] + + mac = ':'.join(map(''.join, + zip(*[iter(hex(self._next_mac)[2:].zfill(12))]*2))) + self._next_mac += 1 + + self._macs[resource_name] = mac + return mac + + def get_ip(self, resource): + """ + Generate a new ip address to assign to the containers created. + + :return: The IP address + """ + + if resource in self._ips: + return self._ips[resource] + + ip = str(self._next_ip) + self._next_ip += 1 + + self._ips[resource] = ip + return ip |