| # |
| # Copyright 2018 the original author or authors. |
| # |
| # 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 structlog |
| |
| from pyvoltha.adapters.common.pon_resource_manager.resource_manager import PONResourceManager |
| from pyvoltha.common.utils.registry import registry |
| # from voltha.core.config.config_backend import ConsulStore |
| # from voltha.core.config.config_backend import EtcdStore |
| from pyvoltha.adapters.common.kvstore.kvstore import create_kv_client |
| from adtran_resource_manager import AdtranPONResourceManager |
| |
| |
| class AdtranOltResourceMgr(object): |
| |
| GEMPORT_IDS = "gemport_ids" |
| ALLOC_IDS = "alloc_ids" |
| BASE_PATH_KV_STORE = "adtran_olt/{}" # adtran_olt/<device_id> |
| |
| def __init__(self, device_id, host_and_port, extra_args, device_info): |
| self.log = structlog.get_logger(id=device_id, |
| ip=host_and_port) |
| self.device_id = device_id |
| self.host_and_port = host_and_port |
| self.extra_args = extra_args |
| self.device_info = device_info |
| self.args = registry('main').get_args() |
| self._path_prefix = AdtranOltResourceMgr.BASE_PATH_KV_STORE.format(device_id) |
| |
| # KV store's IP Address and PORT |
| # host, port = '127.0.0.1', 8500 |
| if self.args.backend == 'etcd': |
| host, port = self.args.etcd.split(':', 1) |
| self.kv_store = create_kv_client('etcd', host, port) |
| # self.kv_store = EtcdStore(host, port, |
| # AdtranOltResourceMgr.BASE_PATH_KV_STORE.format(device_id)) |
| elif self.args.backend == 'consul': |
| host, port = self.args.consul.split(':', 1) |
| self.kv_store = create_kv_client('consul', host, port) |
| # self.kv_store = ConsulStore(host, port, |
| # AdtranOltResourceMgr.BASE_PATH_KV_STORE.format(device_id)) |
| else: |
| self.log.error('Invalid-backend') |
| raise Exception("Invalid-backend-for-kv-store") |
| |
| self.resource_mgr = AdtranPONResourceManager( |
| self.device_info.technology, |
| self.extra_args, |
| self.device_id, self.args.backend, |
| host, port |
| ) |
| # Tech profiles uses this resource manager to retrieve information on a per-interface |
| # basis |
| self.resource_managers = {intf_id: self.resource_mgr for intf_id in device_info.intf_ids} |
| |
| # Flag to indicate whether information fetched from device should |
| # be used to initialize PON Resource Ranges |
| self.use_device_info = False |
| |
| self.initialize_device_resource_range_and_pool() |
| |
| def __del__(self): |
| self.log.info("clearing-device-resource-pool") |
| for key, resource_mgr in self.resource_mgrs.iteritems(): |
| resource_mgr.clear_device_resource_pool() |
| |
| def get_onu_id(self, pon_intf_id): |
| onu_id = self.resource_mgr.get_resource_id(pon_intf_id, |
| PONResourceManager.ONU_ID, |
| onu_id=None, |
| num_of_id=1) |
| if onu_id is not None: |
| pon_intf_onu_id = (pon_intf_id, onu_id) |
| self.resource_mgr.init_resource_map(pon_intf_onu_id) |
| |
| return onu_id |
| |
| def free_onu_id(self, pon_intf_id, onu_id): |
| self.resource_mgr.free_resource_id(pon_intf_id, |
| PONResourceManager.ONU_ID, |
| onu_id) |
| pon_intf_onu_id = (pon_intf_id, onu_id) |
| self.resource_mgr.remove_resource_map(pon_intf_onu_id) |
| |
| def get_alloc_id(self, pon_intf_onu_id): |
| # Derive the pon_intf from the pon_intf_onu_id tuple |
| pon_intf = pon_intf_onu_id[0] |
| onu_id = pon_intf_onu_id[1] |
| alloc_id_list = self.resource_mgr.get_current_alloc_ids_for_onu(pon_intf_onu_id) |
| |
| if alloc_id_list and len(alloc_id_list) > 0: |
| # Since we support only one alloc_id for the ONU at the moment, |
| # return the first alloc_id in the list, if available, for that |
| # ONU. |
| return alloc_id_list[0] |
| |
| alloc_id_list = self.resource_mgr.get_resource_id(pon_intf, |
| PONResourceManager.ALLOC_ID, |
| onu_id=onu_id, |
| num_of_id=1) |
| if alloc_id_list and len(alloc_id_list) == 0: |
| self.log.error("no-alloc-id-available") |
| return None |
| |
| # update the resource map on KV store with the list of alloc_id |
| # allocated for the pon_intf_onu_id tuple |
| self.resource_mgr.update_alloc_ids_for_onu(pon_intf_onu_id, |
| alloc_id_list) |
| |
| # Since we request only one alloc id, we refer the 0th |
| # index |
| alloc_id = alloc_id_list[0] |
| |
| return alloc_id |
| |
| def get_gemport_id(self, pon_intf_onu_id, num_of_id=1): |
| # TODO: Remove this if never used |
| # Derive the pon_intf and onu_id from the pon_intf_onu_id tuple |
| pon_intf = pon_intf_onu_id[0] |
| onu_id = pon_intf_onu_id[1] |
| uni_id = pon_intf_onu_id[2] |
| assert False, 'unused function' |
| |
| # gemport_id_list = self.resource_managers[pon_intf].get_current_gemport_ids_for_onu( |
| # pon_intf_onu_id) |
| # if gemport_id_list and len(gemport_id_list) > 0: |
| # return gemport_id_list |
| # |
| # gemport_id_list = self.resource_mgrs[pon_intf].get_resource_id( |
| # pon_intf_id=pon_intf, |
| # resource_type=PONResourceManager.GEMPORT_ID, |
| # num_of_id=num_of_id |
| # ) |
| # |
| # if gemport_id_list and len(gemport_id_list) == 0: |
| # self.log.error("no-gemport-id-available") |
| # return None |
| # |
| # # update the resource map on KV store with the list of gemport_id |
| # # allocated for the pon_intf_onu_id tuple |
| # self.resource_managers[pon_intf].update_gemport_ids_for_onu(pon_intf_onu_id, |
| # gemport_id_list) |
| # |
| # self.update_gemports_ponport_to_onu_map_on_kv_store(gemport_id_list, |
| # pon_intf, onu_id, uni_id) |
| # return gemport_id_list |
| |
| def free_pon_resources_for_onu(self, pon_intf_id_onu_id): |
| """ Typically called on ONU delete """ |
| |
| pon_intf_id = pon_intf_id_onu_id[0] |
| onu_id = pon_intf_id_onu_id[1] |
| try: |
| alloc_ids = self.resource_mgr.get_current_alloc_ids_for_onu(pon_intf_id_onu_id) |
| if alloc_ids is not None: |
| self.resource_mgr.free_resource_id(pon_intf_id, |
| PONResourceManager.ALLOC_ID, |
| alloc_ids, onu_id=onu_id) |
| except: |
| pass |
| |
| try: |
| gemport_ids = self.resource_mgr.get_current_gemport_ids_for_onu(pon_intf_id_onu_id) |
| if gemport_ids is not None: |
| self.resource_mgr.free_resource_id(pon_intf_id, |
| PONResourceManager.GEMPORT_ID, |
| gemport_ids) |
| except: |
| pass |
| |
| try: |
| self.resource_mgr.free_resource_id(pon_intf_id, |
| PONResourceManager.ONU_ID, |
| onu_id) |
| except: |
| pass |
| |
| # Clear resource map associated with (pon_intf_id, gemport_id) tuple. |
| self.resource_mgr.remove_resource_map(pon_intf_id_onu_id) |
| |
| # Clear the ONU Id associated with the (pon_intf_id, gemport_id) tuple. |
| if gemport_ids is not None: |
| for gemport_id in gemport_ids: |
| try: |
| self.kv_store.delete(self._make_path(str((pon_intf_id, gemport_id)))) |
| # del self.kv_store[str((pon_intf_id, gemport_id))] |
| except: |
| pass |
| |
| def initialize_device_resource_range_and_pool(self): |
| if not self.use_device_info: |
| status = self.resource_mgr.init_resource_ranges_from_kv_store() |
| if not status: |
| self.log.error("failed-to-load-resource-range-from-kv-store") |
| # When we have failed to read the PON Resource ranges from KV |
| # store, use the information selected as the default. |
| self.use_device_info = True |
| |
| if self.use_device_info: |
| self.log.info("using-device-info-to-init-pon-resource-ranges") |
| self.resource_mgr.init_default_pon_resource_ranges( |
| onu_id_start_idx=self.device_info.onu_id_start, |
| onu_id_end_idx=self.device_info.onu_id_end, |
| alloc_id_start_idx=self.device_info.alloc_id_start, |
| alloc_id_end_idx=self.device_info.alloc_id_end, |
| gemport_id_start_idx=self.device_info.gemport_id_start, |
| gemport_id_end_idx=self.device_info.gemport_id_end, |
| num_of_pon_ports=self.device_info.pon_ports, |
| intf_ids=self.device_info.intf_ids |
| ) |
| |
| # After we have initialized resource ranges, initialize the |
| # resource pools accordingly. |
| self.resource_mgr.init_device_resource_pool() |
| |
| def get_current_gemport_ids_for_onu(self, pon_intf_onu_id): |
| pon_intf_id = pon_intf_onu_id[0] |
| return self.resource_managers[pon_intf_id].get_current_gemport_ids_for_onu(pon_intf_onu_id) |
| |
| def get_current_alloc_ids_for_onu(self, pon_intf_onu_id): |
| pon_intf_id = pon_intf_onu_id[0] |
| alloc_ids = self.resource_managers[pon_intf_id].get_current_alloc_ids_for_onu(pon_intf_onu_id) |
| if alloc_ids is None: |
| return None |
| # We support only one tcont at the moment |
| return alloc_ids[0] |
| |
| def update_gemports_ponport_to_onu_map_on_kv_store(self, gemport_list, pon_port, onu_id, uni_id): |
| for gemport in gemport_list: |
| pon_intf_gemport = (pon_port, gemport) |
| # This information is used when packet_indication is received and |
| # we need to derive the ONU Id for which the packet arrived based |
| # on the pon_intf and gemport available in the packet_indication |
| # self.kv_store[str(pon_intf_gemport)] = ' '.join(map(str, (onu_id, uni_id))) |
| self.kv_store.put(self._make_path(str(pon_intf_gemport)), ' '.join(map(str, (onu_id, uni_id)))) |
| |
| def get_onu_uni_from_ponport_gemport(self, pon_port, gemport): |
| pon_intf_gemport = (pon_port, gemport) |
| #return tuple(map(int, self.kv_store[str(pon_intf_gemport)].split(' '))) |
| return tuple(map(int, self.kv_store.get(self._make_path(str(pon_intf_gemport))).split(' '))) |
| |
| def get_flow_id(self, pon_intf_id, onu_id, uni_id, flow_store_cookie, flow_category=None): |
| pon_intf_onu_id = (pon_intf_id, onu_id, uni_id) |
| try: |
| flow_ids = self.resource_managers[pon_intf_id]. \ |
| get_current_flow_ids_for_onu(pon_intf_onu_id) |
| if flow_ids is not None: |
| for flow_id in flow_ids: |
| flows = self.get_flow_id_info(pon_intf_id, onu_id, uni_id, flow_id) |
| assert (isinstance(flows, list)) |
| for flow in flows: |
| |
| if flow_category is not None and \ |
| 'flow_category' in flow and \ |
| flow['flow_category'] == flow_category: |
| return flow_id |
| if flow['flow_store_cookie'] == flow_store_cookie: |
| return flow_id |
| except Exception as e: |
| self.log.error("error-retrieving-flow-info", e=e) |
| |
| flow_id = self.resource_managers[pon_intf_id].get_resource_id( |
| pon_intf_onu_id[0], PONResourceManager.FLOW_ID) |
| if flow_id is not None: |
| self.resource_managers[pon_intf_id].update_flow_id_for_onu( |
| pon_intf_onu_id, flow_id |
| ) |
| |
| return flow_id |
| |
| def get_flow_id_info(self, pon_intf_id, onu_id, uni_id, flow_id): |
| pon_intf_onu_id = (pon_intf_id, onu_id, uni_id) |
| return self.resource_managers[pon_intf_id].get_flow_id_info(pon_intf_onu_id, flow_id) |
| |
| def get_current_flow_ids_for_uni(self, pon_intf_id, onu_id, uni_id): |
| pon_intf_onu_id = (pon_intf_id, onu_id, uni_id) |
| return self.resource_managers[pon_intf_id].get_current_flow_ids_for_onu(pon_intf_onu_id) |
| |
| def update_flow_id_info_for_uni(self, pon_intf_id, onu_id, uni_id, flow_id, flow_data): |
| pon_intf_onu_id = (pon_intf_id, onu_id, uni_id) |
| return self.resource_managers[pon_intf_id].update_flow_id_info_for_onu( |
| pon_intf_onu_id, flow_id, flow_data) |