| # |
| # Copyright 2020 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. |
| |
| from __future__ import absolute_import |
| |
| import random |
| import structlog |
| from twisted.internet import reactor |
| |
| |
| class TpState: |
| ALLOC_ID = "alloc_id" |
| GEM_ID = "gem_id" |
| |
| def __init__(self, handler, uni_id, tp_path): |
| self.log = structlog.get_logger(device_id=handler.device_id, uni_id=uni_id, tp_path=tp_path) |
| self._handler = handler |
| self._uni_id = uni_id |
| self._tp_path = tp_path |
| self._tp_task_ref = None |
| self._tp_setup_done = False |
| # When the vlan filter is being removed for a given TP ID on a given UNI, |
| # mark that we are expecting a tp delete to happen for this UNI. |
| # Unless the TP delete is complete to not allow new vlan add tasks to this TP ID |
| self._is_tp_delete_pending = False |
| # Map maintains details of PON resources (alloc_id and gem_port_id(s) to be deleted) for a given TP |
| self._pending_delete_pon_res_map = dict() |
| |
| @property |
| def tp_task_ref(self): |
| return self._tp_task_ref |
| |
| @tp_task_ref.setter |
| def tp_task_ref(self, tp_task_ref): |
| self._tp_task_ref = tp_task_ref |
| |
| @property |
| def tp_setup_done(self): |
| return self._tp_setup_done |
| |
| @tp_setup_done.setter |
| def tp_setup_done(self, tp_setup_done): |
| self._tp_setup_done = tp_setup_done |
| |
| @property |
| def is_tp_delete_pending(self): |
| return self._is_tp_delete_pending |
| |
| @is_tp_delete_pending.setter |
| def is_tp_delete_pending(self, is_tp_delete_pending): |
| self._is_tp_delete_pending = is_tp_delete_pending |
| |
| @property |
| def pending_delete_pon_res_map(self): |
| return self._pending_delete_pon_res_map |
| |
| def queue_pending_delete_pon_resource(self, res_type, res): |
| if res_type not in self._pending_delete_pon_res_map: |
| if res_type == TpState.ALLOC_ID: |
| # There is only one alloc-id for a TP |
| self._pending_delete_pon_res_map[TpState.ALLOC_ID] = res |
| elif res_type == TpState.GEM_ID: |
| # There can be more than one gem-port-id for a TP |
| self._pending_delete_pon_res_map[TpState.GEM_ID] = list() |
| self._pending_delete_pon_res_map[TpState.GEM_ID].append(res) |
| else: |
| self.log.error("unknown-res-type", res_type=res_type) |
| else: |
| if res_type == TpState.ALLOC_ID: |
| self.log.warn("alloc-id-already-pending-for-deletion", alloc_id=res.alloc_id) |
| elif res_type == TpState.GEM_ID: |
| # Make sure that we are not adding duplicate gem-port-id to the list |
| for v in self._pending_delete_pon_res_map[TpState.GEM_ID]: |
| if v.gem_id == res.gem_id: |
| self.log.warn("gem-id-already-pending-for-deletion", gem_id=res.gem_id) |
| return |
| self._pending_delete_pon_res_map[TpState.GEM_ID].append(res) |
| else: |
| self.log.error("unknown-res-type", res_type=res_type) |
| |
| def pon_resource_delete_complete(self, res_type, res_id): |
| if res_type not in self._pending_delete_pon_res_map: |
| self.log.error("resource-was-not-queued-for-delete", res_type=res_type, res_id=res_id) |
| return |
| if res_type == TpState.ALLOC_ID: |
| # After removing the TCONT, remove the ALLOC_ID key |
| del self._pending_delete_pon_res_map[res_type] |
| else: |
| for v in self._pending_delete_pon_res_map[TpState.GEM_ID]: |
| if v.gem_id == res_id: |
| self._pending_delete_pon_res_map[TpState.GEM_ID].remove(v) |
| if len(self._pending_delete_pon_res_map[TpState.GEM_ID]) == 0: |
| del self._pending_delete_pon_res_map[TpState.GEM_ID] |
| return |
| self.log.warn("gem-id-was-not-queued-for-delete", gem_id=res_id) |
| |
| def get_queued_resource_for_delete(self, res_type, res_id): |
| if res_type not in self._pending_delete_pon_res_map: |
| self.log.warn("resource-was-not-queued-for-delete", res_type=res_type, res_id=res_id) |
| return None |
| if res_type == TpState.ALLOC_ID: |
| # After removing the TCONT, remove the ALLOC_ID key |
| return self._pending_delete_pon_res_map[res_type] |
| elif res_type == TpState.GEM_ID: |
| for i, v in enumerate(self._pending_delete_pon_res_map[res_type]): |
| if v.gem_id == res_id: |
| return self._pending_delete_pon_res_map[res_type][i] |
| return None |
| |
| def is_all_pon_resource_delete_complete(self): |
| return len(self._pending_delete_pon_res_map) == 0 |
| |
| def reset_tp_state(self): |
| self._tp_task_ref = None |
| self._tp_setup_done = False |
| self._is_tp_delete_pending = False |
| self._pending_delete_pon_res_map.clear() |
| self.log.info("reset-tp-success") |