blob: 8cce46cce2abdecbcb5fcb10fa1157fdf84b0daf [file] [log] [blame]
#
# 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)