blob: 426da70dae90f53ad72154fbe1474999634242ac [file] [log] [blame]
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001#
2# Copyright 2017 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17"""
18Broadcom OpenOMCI OLT/ONU adapter handler.
19"""
20
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -050021from __future__ import absolute_import
Girish Gowdra5b499342020-06-16 14:45:51 -070022
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -050023import json
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -050024import random
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050025from collections import OrderedDict
26
Girish Gowdra5b499342020-06-16 14:45:51 -070027import arrow
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050028import pyvoltha.common.openflow.utils as fd
Girish Gowdra5b499342020-06-16 14:45:51 -070029import six
30import structlog
31from heartbeat import HeartBeat
32from omci.brcm_mcast_task import BrcmMcastTask
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050033from omci.brcm_mib_download_task import BrcmMibDownloadTask
Girish Gowdrae933cd32019-11-21 21:04:41 +053034from omci.brcm_tp_delete_task import BrcmTpDeleteTask
Girish Gowdra5b499342020-06-16 14:45:51 -070035from omci.brcm_tp_setup_task import BrcmTpSetupTask
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050036from omci.brcm_uni_lock_task import BrcmUniLockTask
37from omci.brcm_vlan_filter_task import BrcmVlanFilterTask
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -050038from onu_gem_port import OnuGemPort
39from onu_tcont import OnuTCont
40from pon_port import PonPort
Girish Gowdrac5117452020-08-03 11:20:53 -070041from tp_state import TpState
Girish Gowdra5b499342020-06-16 14:45:51 -070042from pyvoltha.adapters.common.frameio.frameio import hexify
43from pyvoltha.adapters.common.kvstore.twisted_etcd_store import TwistedEtcdStore
44from pyvoltha.adapters.extensions.events.adapter_events import AdapterEvents
45from pyvoltha.adapters.extensions.events.device_events.onu.onu_active_event import OnuActiveEvent
46from pyvoltha.adapters.extensions.events.device_events.onu.onu_deleted_event import OnuDeletedEvent
47from pyvoltha.adapters.extensions.events.device_events.onu.onu_disabled_event import OnuDisabledEvent
48from pyvoltha.adapters.extensions.events.kpi.onu.onu_omci_pm import OnuOmciPmMetrics
49from pyvoltha.adapters.extensions.events.kpi.onu.onu_pm_metrics import OnuPmMetrics
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -050050from pyvoltha.adapters.extensions.omci.omci_defs import EntityOperations, ReasonCodes
Girish Gowdra5b499342020-06-16 14:45:51 -070051from pyvoltha.adapters.extensions.omci.omci_entities import AniG, Tcont, MacBridgeServiceProfile
52from pyvoltha.adapters.extensions.omci.onu_device_entry import OnuDeviceEvents, \
53 OnuDeviceEntry, IN_SYNC_KEY
54from pyvoltha.adapters.extensions.omci.tasks.omci_test_request import OmciTestRequest
55from pyvoltha.common.tech_profile.tech_profile import TechProfile
56from pyvoltha.common.utils.registry import registry
57from twisted.internet import reactor
58from twisted.internet.defer import inlineCallbacks, returnValue
59from uni_port import RESERVED_TRANSPARENT_VLAN
60from uni_port import UniPort, UniType
61from voltha_protos.common_pb2 import OperStatus, ConnectStatus, AdminState
62from voltha_protos.device_pb2 import Port
63from voltha_protos.inter_container_pb2 import InterAdapterMessageType, \
64 InterAdapterOmciMessage, InterAdapterTechProfileDownloadMessage, InterAdapterDeleteGemPortMessage, \
65 InterAdapterDeleteTcontMessage
66from voltha_protos.openflow_13_pb2 import OFPXMC_OPENFLOW_BASIC
67from voltha_protos.openolt_pb2 import OnuIndication
onkarkundargia1e2af22020-01-27 11:51:43 +053068from voltha_protos.voltha_pb2 import TestResponse
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050069
70OP = EntityOperations
71RC = ReasonCodes
72
Girish Gowdradc98d812020-03-20 13:04:58 -070073IS_MULTICAST = 'is_multicast'
Mahir Gunyel5de33fe2020-03-03 22:38:44 -080074GEM_PORT_ID = 'gemport_id'
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -050075_STARTUP_RETRY_WAIT = 10
Mahir Gunyele9110a32020-02-20 14:56:50 -080076_PATH_SEPERATOR = "/"
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050077
78
79class BrcmOpenomciOnuHandler(object):
80
81 def __init__(self, adapter, device_id):
82 self.log = structlog.get_logger(device_id=device_id)
Matt Jeanneret08a8e862019-12-20 14:02:32 -050083 self.log.debug('starting-handler')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050084 self.adapter = adapter
Matt Jeannereta32441c2019-03-07 05:16:37 -050085 self.core_proxy = adapter.core_proxy
86 self.adapter_proxy = adapter.adapter_proxy
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050087 self.parent_id = None
88 self.device_id = device_id
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050089 self.proxy_address = None
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050090 self._enabled = False
Girish Gowdra322cca12020-08-09 15:55:54 -070091 self._is_device_active_and_reachable = False
Devmalya Paulffc89df2019-07-31 17:43:13 -040092 self.events = None
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -050093 self._pm_metrics = None
94 self._pm_metrics_started = False
95 self._test_request = None
96 self._test_request_started = False
Girish Gowdradc98d812020-03-20 13:04:58 -070097 self._tp = dict() # tp_id -> technology profile definition in KV Store.
Matt Jeanneret5e331892019-12-07 21:31:45 -050098 self._reconciling = False
99
100 # Persisted onu configuration needed in case of reconciliation.
101 self._onu_persisted_state = {
102 'onu_id': None,
103 'intf_id': None,
104 'serial_number': None,
105 'admin_state': None,
106 'oper_state': None,
107 'uni_config': list()
108 }
109
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500110 self._unis = dict() # Port # -> UniPort
111
112 self._pon = None
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500113 self._pon_port_number = 100
114 self.logical_device_id = None
115
116 self._heartbeat = HeartBeat.create(self, device_id)
117
118 # Set up OpenOMCI environment
119 self._onu_omci_device = None
120 self._dev_info_loaded = False
121 self._deferred = None
122
123 self._in_sync_subscription = None
Matt Jeanneretf4113222019-08-14 19:44:34 -0400124 self._port_state_subscription = None
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500125 self._connectivity_subscription = None
126 self._capabilities_subscription = None
127
128 self.mac_bridge_service_profile_entity_id = 0x201
129 self.gal_enet_profile_entity_id = 0x1
130
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400131 # Stores information related to queued vlan filter tasks
132 # Dictionary with key being uni_id and value being device,uni port ,uni id and vlan id
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400133 self._queued_vlan_filter_task = dict()
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500134
Girish Gowdra6dd965a2020-08-13 19:13:33 -0700135 self._multicast_task = None
136
Girish Gowdradc98d812020-03-20 13:04:58 -0700137 self._set_vlan = dict() # uni_id, tp_id -> set_vlan_id
Girish Gowdrac5117452020-08-03 11:20:53 -0700138 self._tp_state_map_per_uni = dict() # uni_id -> {dictionary tp_id->TpState}
Matt Jeanneret5e331892019-12-07 21:31:45 -0500139
140 # Paths from kv store
141 ONU_PATH = 'service/voltha/openonu'
142
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500143 # Initialize KV store client
144 self.args = registry('main').get_args()
Matt Jeanneret5e331892019-12-07 21:31:45 -0500145 host, port = self.args.etcd.split(':', 1)
146 self.tp_kv_client = TwistedEtcdStore(host, port, TechProfile.KV_STORE_TECH_PROFILE_PATH_PREFIX)
147 self.onu_kv_client = TwistedEtcdStore(host, port, ONU_PATH)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500148
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500149 @property
150 def enabled(self):
151 return self._enabled
152
153 @enabled.setter
154 def enabled(self, value):
155 if self._enabled != value:
156 self._enabled = value
157
158 @property
159 def omci_agent(self):
160 return self.adapter.omci_agent
161
162 @property
163 def omci_cc(self):
164 return self._onu_omci_device.omci_cc if self._onu_omci_device is not None else None
165
166 @property
167 def heartbeat(self):
168 return self._heartbeat
169
170 @property
171 def uni_ports(self):
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -0500172 return list(self._unis.values())
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500173
Girish Gowdra322cca12020-08-09 15:55:54 -0700174 @property
175 def is_device_active_and_reachable(self):
176 return self._is_device_active_and_reachable
177
178 @is_device_active_and_reachable.setter
179 def is_device_active_and_reachable(self, value):
180 self._is_device_active_and_reachable = value
181
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500182 def uni_port(self, port_no_or_name):
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -0500183 if isinstance(port_no_or_name, six.string_types):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500184 return next((uni for uni in self.uni_ports
185 if uni.name == port_no_or_name), None)
186
187 assert isinstance(port_no_or_name, int), 'Invalid parameter type'
188 return next((uni for uni in self.uni_ports
Girish Gowdrae933cd32019-11-21 21:04:41 +0530189 if uni.port_number == port_no_or_name), None)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500190
191 @property
192 def pon_port(self):
193 return self._pon
194
Girish Gowdraa73ee452019-12-20 18:52:17 +0530195 @property
196 def onu_omci_device(self):
197 return self._onu_omci_device
198
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500199 def receive_message(self, msg):
200 if self.omci_cc is not None:
201 self.omci_cc.receive_message(msg)
202
203 # Called once when the adapter creates the device/onu instance
Matt Jeanneret84e56f62019-02-26 10:48:09 -0500204 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500205 def activate(self, device):
Matteo Scandolod8d73172019-11-26 12:15:15 -0700206 self.log.debug('activate-device', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500207
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500208 assert device.parent_id
Matt Jeanneret0c287892019-02-28 11:48:00 -0500209 assert device.parent_port_no
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500210 assert device.proxy_address.device_id
211
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500212 self.proxy_address = device.proxy_address
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500213 self.parent_id = device.parent_id
Matt Jeanneret0c287892019-02-28 11:48:00 -0500214 self._pon_port_number = device.parent_port_no
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500215 if self.enabled is not True:
Matteo Scandolod8d73172019-11-26 12:15:15 -0700216 self.log.info('activating-new-onu', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500217 # populate what we know. rest comes later after mib sync
Matt Jeanneret0c287892019-02-28 11:48:00 -0500218 device.root = False
Matt Jeannereta32441c2019-03-07 05:16:37 -0500219 device.vendor = 'OpenONU'
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500220 device.reason = 'activating-onu'
221
Matt Jeanneret84e56f62019-02-26 10:48:09 -0500222 # TODO NEW CORE: Need to either get logical device id from core or use regular device id
Matt Jeanneret3b7db442019-04-22 16:29:48 -0400223 # pm_metrics requires a logical device id. For now set to just device_id
224 self.logical_device_id = self.device_id
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500225
Matt Jeanneret5e331892019-12-07 21:31:45 -0500226 self._onu_persisted_state['serial_number'] = device.serial_number
227 try:
228 self.log.debug('updating-onu-state', device_id=self.device_id,
229 onu_persisted_state=self._onu_persisted_state)
230 yield self.onu_kv_client.set(self.device_id, json.dumps(self._onu_persisted_state))
231 except Exception as e:
232 self.log.error('could-not-store-onu-state', device_id=self.device_id,
233 onu_persisted_state=self._onu_persisted_state, e=e)
234 # if we cannot write to storage we can proceed, for now.
235 # later onu indications from the olt will have another chance
236
Matt Jeannereta32441c2019-03-07 05:16:37 -0500237 yield self.core_proxy.device_update(device)
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500238 self.log.debug('device-updated', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500239
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700240 yield self._init_pon_state()
Matteo Scandolod8d73172019-11-26 12:15:15 -0700241 self.log.debug('pon state initialized', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500242
Matt Jeanneret5e331892019-12-07 21:31:45 -0500243 yield self._init_metrics()
244 self.log.debug('metrics initialized', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -0500245
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500246 self.enabled = True
247 else:
248 self.log.info('onu-already-activated')
249
250 # Called once when the adapter needs to re-create device. usually on vcore restart
William Kurkian3a206332019-04-29 11:05:47 -0400251 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500252 def reconcile(self, device):
Matteo Scandolod8d73172019-11-26 12:15:15 -0700253 self.log.debug('reconcile-device', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500254
Matt Jeanneret5e331892019-12-07 21:31:45 -0500255 if self._reconciling:
256 self.log.debug('already-running-reconcile-device', device_id=device.id, serial_number=device.serial_number)
257 return
258
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500259 # first we verify that we got parent reference and proxy info
260 assert device.parent_id
261 assert device.proxy_address.device_id
262
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700263 self.proxy_address = device.proxy_address
264 self.parent_id = device.parent_id
265 self._pon_port_number = device.parent_port_no
266
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500267 if self.enabled is not True:
Matt Jeanneret5e331892019-12-07 21:31:45 -0500268 self._reconciling = True
269 self.log.info('reconciling-openonu-device')
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700270 self.logical_device_id = self.device_id
Matt Jeanneret5e331892019-12-07 21:31:45 -0500271
272 try:
273 query_data = yield self.onu_kv_client.get(device.id)
274 self._onu_persisted_state = json.loads(query_data)
275 self.log.debug('restored-onu-state', device_id=self.device_id,
276 onu_persisted_state=self._onu_persisted_state)
277 except Exception as e:
278 self.log.error('no-stored-onu-state', device_id=device.id, e=e)
279 # there is nothing we can do without data. flag the device as UNKNOWN and cannot reconcile
280 # likely it will take manual steps to delete/re-add this onu
281 yield self.core_proxy.device_reason_update(self.device_id, "cannot-reconcile")
282 yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.UNKNOWN)
283 return
284
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700285 self._init_pon_state()
Matt Jeanneret5e331892019-12-07 21:31:45 -0500286 self.log.debug('pon state initialized', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500287
Matt Jeanneret5e331892019-12-07 21:31:45 -0500288 self._init_metrics()
289 self.log.debug('metrics initialized', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500290
Matt Jeanneret5e331892019-12-07 21:31:45 -0500291 self._subscribe_to_events()
292 # need to restart omci start machines and reload mib database. once db is loaded we can finish reconcile
293 self._onu_omci_device.start(device)
294 self._heartbeat.enabled = True
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500295
296 self.enabled = True
297 else:
298 self.log.info('onu-already-activated')
299
300 @inlineCallbacks
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700301 def _init_pon_state(self):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500302 self.log.debug('init-pon-state', device_id=self.device_id, device_logical_id=self.logical_device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500303
304 self._pon = PonPort.create(self, self._pon_port_number)
Matt Jeanneret0c287892019-02-28 11:48:00 -0500305 self._pon.add_peer(self.parent_id, self._pon_port_number)
Matteo Scandolod8d73172019-11-26 12:15:15 -0700306 self.log.debug('adding-pon-port-to-agent',
307 type=self._pon.get_port().type,
308 admin_state=self._pon.get_port().admin_state,
309 oper_status=self._pon.get_port().oper_status,
310 )
Matt Jeanneret0c287892019-02-28 11:48:00 -0500311
Matt Jeanneret5e331892019-12-07 21:31:45 -0500312 if not self._reconciling:
313 yield self.core_proxy.port_created(self.device_id, self._pon.get_port())
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500314
Matteo Scandolod8d73172019-11-26 12:15:15 -0700315 self.log.debug('added-pon-port-to-agent',
316 type=self._pon.get_port().type,
317 admin_state=self._pon.get_port().admin_state,
318 oper_status=self._pon.get_port().oper_status,
319 )
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500320
321 # Create and start the OpenOMCI ONU Device Entry for this ONU
322 self._onu_omci_device = self.omci_agent.add_device(self.device_id,
Matt Jeannereta32441c2019-03-07 05:16:37 -0500323 self.core_proxy,
324 self.adapter_proxy,
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500325 support_classes=self.adapter.broadcom_omci,
326 custom_me_map=self.adapter.custom_me_entities())
327 # Port startup
328 if self._pon is not None:
329 self._pon.enabled = True
330
Matt Jeanneret5e331892019-12-07 21:31:45 -0500331 @inlineCallbacks
332 def _init_metrics(self):
333 self.log.debug('init-metrics', device_id=self.device_id, device_logical_id=self.logical_device_id)
334
335 serial_number = self._onu_persisted_state.get('serial_number')
336
337 ############################################################################
338 # Setup Alarm handler
339 self.events = AdapterEvents(self.core_proxy, self.device_id, self.logical_device_id,
340 serial_number)
341 ############################################################################
342 # Setup PM configuration for this device
343 # Pass in ONU specific options
344 kwargs = {
345 OnuPmMetrics.DEFAULT_FREQUENCY_KEY: OnuPmMetrics.DEFAULT_ONU_COLLECTION_FREQUENCY,
346 'heartbeat': self.heartbeat,
347 OnuOmciPmMetrics.OMCI_DEV_KEY: self._onu_omci_device
348 }
349 self.log.debug('create-pm-metrics', device_id=self.device_id, serial_number=serial_number)
350 self._pm_metrics = OnuPmMetrics(self.events, self.core_proxy, self.device_id,
351 self.logical_device_id, serial_number,
352 grouped=True, freq_override=False, **kwargs)
353 pm_config = self._pm_metrics.make_proto()
354 self._onu_omci_device.set_pm_config(self._pm_metrics.omci_pm.openomci_interval_pm)
355 self.log.debug("initial-pm-config", device_id=self.device_id, serial_number=serial_number)
356
357 if not self._reconciling:
358 yield self.core_proxy.device_pm_config_update(pm_config, init=True)
359
360 # Note, ONU ID and UNI intf set in add_uni_port method
361 self._onu_omci_device.alarm_synchronizer.set_alarm_params(mgr=self.events,
362 ani_ports=[self._pon])
363
364 # Code to Run OMCI Test Action
365 kwargs_omci_test_action = {
366 OmciTestRequest.DEFAULT_FREQUENCY_KEY:
367 OmciTestRequest.DEFAULT_COLLECTION_FREQUENCY
368 }
369 self._test_request = OmciTestRequest(self.core_proxy,
370 self.omci_agent, self.device_id,
371 AniG, serial_number,
372 self.logical_device_id,
373 exclusive=False,
374 **kwargs_omci_test_action)
375
376 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500377 def delete(self, device):
Matteo Scandolod8d73172019-11-26 12:15:15 -0700378 self.log.info('delete-onu', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneret5e331892019-12-07 21:31:45 -0500379 try:
380 yield self.onu_kv_client.delete(device.id)
381 except Exception as e:
382 self.log.error('could-not-delete-onu-state', device_id=device.id, e=e)
383
Devmalya Paul1e1b1722020-05-07 02:51:15 -0400384 try:
385 self._deferred.cancel()
386 self._test_request.stop_collector()
387 self._pm_metrics.stop_collector()
388 self.log.debug('removing-openomci-statemachine')
389 self.omci_agent.remove_device(device.id, cleanup=True)
390 yield self.onu_deleted_event()
391 except Exception as e:
392 self.log.error('could-not-delete-onu', device_id=device.id, e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500393
394 def _create_tconts(self, uni_id, us_scheduler):
395 alloc_id = us_scheduler['alloc_id']
396 q_sched_policy = us_scheduler['q_sched_policy']
397 self.log.debug('create-tcont', us_scheduler=us_scheduler)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800398 # TODO: revisit for multi tconts support
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800399 new_tconts = []
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500400 tcontdict = dict()
401 tcontdict['alloc-id'] = alloc_id
402 tcontdict['q_sched_policy'] = q_sched_policy
403 tcontdict['uni_id'] = uni_id
404
Matt Jeanneret3789d0d2020-01-19 09:03:42 -0500405 tcont = OnuTCont.create(self, tcont=tcontdict)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500406
Girish Gowdra7c1240c2020-07-15 15:06:42 -0700407 success = self._pon.add_tcont(tcont, True)
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500408 if success:
409 new_tconts.append(tcont)
410 self.log.debug('pon-add-tcont', tcont=tcont)
411
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800412 return new_tconts
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500413
414 # Called when there is an olt up indication, providing the gem port id chosen by the olt handler
415 def _create_gemports(self, uni_id, gem_ports, alloc_id_ref, direction):
416 self.log.debug('create-gemport',
417 gem_ports=gem_ports, direction=direction)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530418 new_gem_ports = []
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500419 for gem_port in gem_ports:
420 gemdict = dict()
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800421 if gem_port[IS_MULTICAST] == 'True':
422 gemdict[GEM_PORT_ID] = gem_port['multicast_gem_id']
423 gemdict[IS_MULTICAST] = True
424 else:
425 gemdict[GEM_PORT_ID] = gem_port[GEM_PORT_ID]
426 gemdict[IS_MULTICAST] = False
427
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500428 gemdict['direction'] = direction
429 gemdict['alloc_id_ref'] = alloc_id_ref
430 gemdict['encryption'] = gem_port['aes_encryption']
431 gemdict['discard_config'] = dict()
432 gemdict['discard_config']['max_probability'] = \
433 gem_port['discard_config']['max_probability']
434 gemdict['discard_config']['max_threshold'] = \
435 gem_port['discard_config']['max_threshold']
436 gemdict['discard_config']['min_threshold'] = \
437 gem_port['discard_config']['min_threshold']
438 gemdict['discard_policy'] = gem_port['discard_policy']
439 gemdict['max_q_size'] = gem_port['max_q_size']
440 gemdict['pbit_map'] = gem_port['pbit_map']
441 gemdict['priority_q'] = gem_port['priority_q']
442 gemdict['scheduling_policy'] = gem_port['scheduling_policy']
443 gemdict['weight'] = gem_port['weight']
444 gemdict['uni_id'] = uni_id
445
446 gem_port = OnuGemPort.create(self, gem_port=gemdict)
447
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500448 success = self._pon.add_gem_port(gem_port, True)
449 if success:
450 new_gem_ports.append(gem_port)
451 self.log.debug('pon-add-gemport', gem_port=gem_port)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500452
Girish Gowdrae933cd32019-11-21 21:04:41 +0530453 return new_gem_ports
454
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800455 def _execute_queued_vlan_filter_tasks(self, uni_id, tp_id):
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400456 # During OLT Reboots, ONU Reboots, ONU Disable/Enable, it is seen that vlan_filter
457 # task is scheduled even before tp task. So we queue vlan-filter task if tp_task
458 # or initial-mib-download is not done. Once the tp_task is completed, we execute
459 # such queued vlan-filter tasks
460 try:
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800461 if uni_id in self._queued_vlan_filter_task and tp_id in self._queued_vlan_filter_task[uni_id]:
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400462 self.log.info("executing-queued-vlan-filter-task",
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800463 uni_id=uni_id, tp_id=tp_id)
Mahir Gunyela982ec32020-02-25 12:30:37 -0800464 for filter_info in self._queued_vlan_filter_task[uni_id][tp_id]:
465 reactor.callLater(0, self._add_vlan_filter_task, filter_info.get("device"),
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800466 uni_id=uni_id, uni_port=filter_info.get("uni_port"),
467 match_vlan=filter_info.get("match_vlan"),
468 _set_vlan_vid=filter_info.get("set_vlan_vid"),
469 _set_vlan_pcp=filter_info.get("set_vlan_pcp"),
470 tp_id=filter_info.get("tp_id"))
Girish Gowdraaf98a082020-03-05 16:40:51 -0800471 # Now remove the entry from the dictionary
Girish Gowdraaf98a082020-03-05 16:40:51 -0800472 self.log.debug("executed-queued-vlan-filter-task",
473 uni_id=uni_id, tp_id=tp_id)
Girish Gowdraa63eda82020-05-12 13:40:04 -0700474
475 # Now delete the key entry for the tp_id once we have handled the
476 # queued vlan filter tasks for that tp_id
477 del self._queued_vlan_filter_task[uni_id][tp_id]
478 # If the queued vlan filter tasks for all the tp_ids on a given
479 # uni_id is handled, then delete the uni_id key
480 if len(self._queued_vlan_filter_task[uni_id]) == 0:
481 del self._queued_vlan_filter_task[uni_id]
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400482 except Exception as e:
483 self.log.error("vlan-filter-configuration-failed", uni_id=uni_id, error=e)
484
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500485 def _do_tech_profile_configuration(self, uni_id, tp):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500486 us_scheduler = tp['us_scheduler']
487 alloc_id = us_scheduler['alloc_id']
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800488 new_tconts = self._create_tconts(uni_id, us_scheduler)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500489 upstream_gem_port_attribute_list = tp['upstream_gem_port_attribute_list']
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800490 new_upstream_gems = self._create_gemports(uni_id, upstream_gem_port_attribute_list, alloc_id, "UPSTREAM")
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500491 downstream_gem_port_attribute_list = tp['downstream_gem_port_attribute_list']
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800492 new_downstream_gems = self._create_gemports(uni_id, downstream_gem_port_attribute_list, alloc_id, "DOWNSTREAM")
493
494 new_gems = []
495 new_gems.extend(new_upstream_gems)
496 new_gems.extend(new_downstream_gems)
497
498 return new_tconts, new_gems
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500499
Matt Jeanneret5e331892019-12-07 21:31:45 -0500500 @inlineCallbacks
Girish Gowdrab3895a02020-06-12 15:34:20 -0700501 def _get_tp_instance_from_kv_store(self, tp_path):
502 _max_tp_load_retry_count = 5
503 _curr_retry_cnt = 0
504 _tp_instance = None
505 while _curr_retry_cnt < _max_tp_load_retry_count:
506 _curr_retry_cnt += 1
507 try:
508 _tp_instance = yield self.tp_kv_client.get(tp_path)
509 except Exception as e:
510 pass
511 if _tp_instance is None:
512 self.log.error("failed-to-load-tp--retrying", retry_cnt=_curr_retry_cnt)
513 continue
514 # if we have got a valid tp instance, break from loop
515 break
516
517 returnValue(_tp_instance)
518
519 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500520 def load_and_configure_tech_profile(self, uni_id, tp_path):
521 self.log.debug("loading-tech-profile-configuration", uni_id=uni_id, tp_path=tp_path)
Mahir Gunyele9110a32020-02-20 14:56:50 -0800522 tp_id = self.extract_tp_id_from_path(tp_path)
Girish Gowdrac5117452020-08-03 11:20:53 -0700523 if tp_id not in self._tp_state_map_per_uni[uni_id]:
524 self._tp_state_map_per_uni[uni_id][tp_id] = TpState(self, uni_id, tp_path)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500525
Girish Gowdrac5117452020-08-03 11:20:53 -0700526 if not self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500527 try:
Girish Gowdrac5117452020-08-03 11:20:53 -0700528 if self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref is not None:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500529 self.log.info("tech-profile-config-already-in-progress",
Girish Gowdrae933cd32019-11-21 21:04:41 +0530530 tp_path=tp_path)
Matt Jeanneret5e331892019-12-07 21:31:45 -0500531 returnValue(None)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500532
Girish Gowdrab3895a02020-06-12 15:34:20 -0700533 if tp_path in self._tp:
534 tp = self._tp[tp_path]
535 else:
536 tpstored = yield self._get_tp_instance_from_kv_store(tp_path)
537 if tpstored is None:
538 self.log.error("failed-to-load-tp-instance", tp_path=tp_path)
539 returnValue(None)
540 tpstring = tpstored.decode('ascii')
541 tp = json.loads(tpstring)
542 self._tp[tp_id] = tp
543
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500544 self.log.debug("tp-instance", tp=tp)
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800545 tconts, gem_ports = self._do_tech_profile_configuration(uni_id, tp)
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700546
William Kurkian3a206332019-04-29 11:05:47 -0400547 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500548 def success(_results):
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800549 self.log.info("tech-profile-config-done-successfully", uni_id=uni_id, tp_id=tp_id)
Girish Gowdrac5117452020-08-03 11:20:53 -0700550 if tp_id in self._tp_state_map_per_uni[uni_id]:
551 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = None
552 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done = True
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400553 # Now execute any vlan filter tasks that were queued for later
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800554 reactor.callInThread(self._execute_queued_vlan_filter_tasks, uni_id, tp_id)
Matt Jeanneretd84c9072020-01-31 06:33:27 -0500555 yield self.core_proxy.device_reason_update(self.device_id, 'tech-profile-config-download-success')
Girish Gowdrae933cd32019-11-21 21:04:41 +0530556
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800557 # Execute mcast task
558 for gem in gem_ports:
Girish Gowdradc98d812020-03-20 13:04:58 -0700559 self.log.debug("checking-multicast-service-for-gem ", gem=gem)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800560 if gem.mcast is True:
Girish Gowdradc98d812020-03-20 13:04:58 -0700561 self.log.info("found-multicast-service-for-gem ", gem=gem, uni_id=uni_id, tp_id=tp_id)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800562 reactor.callInThread(self.start_multicast_service, uni_id, tp_path)
563 self.log.debug("started_multicast_service-successfully", tconts=tconts, gems=gem_ports)
564 break
565
William Kurkian3a206332019-04-29 11:05:47 -0400566 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500567 def failure(_reason):
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800568 self.log.warn('tech-profile-config-failure-retrying', uni_id=uni_id, tp_id=tp_id,
Girish Gowdrae933cd32019-11-21 21:04:41 +0530569 _reason=_reason)
Girish Gowdrac5117452020-08-03 11:20:53 -0700570 if tp_id in self._tp_state_map_per_uni[uni_id]:
571 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = None
572 retry = random.randint(1, 5)
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -0500573 reactor.callLater(retry, self.load_and_configure_tech_profile,
574 uni_id, tp_path)
Matt Jeanneretd84c9072020-01-31 06:33:27 -0500575 yield self.core_proxy.device_reason_update(self.device_id,
576 'tech-profile-config-download-failure-retrying')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500577
Mahir Gunyela982ec32020-02-25 12:30:37 -0800578 self.log.info('downloading-tech-profile-configuration', uni_id=uni_id, tp_id=tp_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530579 self.log.debug("tconts-gems-to-install", tconts=tconts, gem_ports=gem_ports)
580
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500581 self.log.debug("current-cached-tconts", tconts=list(self.pon_port.tconts.values()))
582 self.log.debug("current-cached-gem-ports", gem_ports=list(self.pon_port.gem_ports.values()))
583
Girish Gowdrac5117452020-08-03 11:20:53 -0700584 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = \
Mahir Gunyele9110a32020-02-20 14:56:50 -0800585 BrcmTpSetupTask(self.omci_agent, self, uni_id, tconts, gem_ports, tp_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500586 self._deferred = \
Girish Gowdrac5117452020-08-03 11:20:53 -0700587 self._onu_omci_device.task_runner.queue_task(self._tp_state_map_per_uni[uni_id][tp_id].
588 tp_task_ref)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500589 self._deferred.addCallbacks(success, failure)
590
591 except Exception as e:
592 self.log.exception("error-loading-tech-profile", e=e)
593 else:
Girish Gowdradc98d812020-03-20 13:04:58 -0700594 # There is an active tech-profile task ongoing on this UNI port. So, reschedule this task
595 # after a short interval
Girish Gowdrac5117452020-08-03 11:20:53 -0700596 for tpid in self._tp_state_map_per_uni[uni_id]:
597 if self._tp_state_map_per_uni[uni_id][tpid].tp_task_ref is not None:
598 self.log.debug("active-tp-tasks-in-progress-for-uni--scheduling-this-task-for-later",
599 uni_id=uni_id, tp_id=tpid)
600 retry = random.randint(1, 5)
601 reactor.callLater(retry, self.load_and_configure_tech_profile,
602 uni_id, tp_path)
603 return
Girish Gowdradc98d812020-03-20 13:04:58 -0700604
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500605 self.log.info("tech-profile-config-already-done")
Girish Gowdradc98d812020-03-20 13:04:58 -0700606
Girish Gowdrae933cd32019-11-21 21:04:41 +0530607 # Could be a case where TP exists but new gem-ports are getting added dynamically
Matt Jeanneret5e331892019-12-07 21:31:45 -0500608 tpstored = yield self.tp_kv_client.get(tp_path)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530609 tpstring = tpstored.decode('ascii')
610 tp = json.loads(tpstring)
611 upstream_gems = []
612 downstream_gems = []
613 # Find out the new Gem ports that are getting added afresh.
614 for gp in tp['upstream_gem_port_attribute_list']:
615 if self.pon_port.gem_port(gp['gemport_id'], "upstream"):
616 # gem port already exists
617 continue
618 upstream_gems.append(gp)
619 for gp in tp['downstream_gem_port_attribute_list']:
620 if self.pon_port.gem_port(gp['gemport_id'], "downstream"):
621 # gem port already exists
622 continue
623 downstream_gems.append(gp)
624
625 us_scheduler = tp['us_scheduler']
626 alloc_id = us_scheduler['alloc_id']
627
628 if len(upstream_gems) > 0 or len(downstream_gems) > 0:
629 self.log.info("installing-new-gem-ports", upstream_gems=upstream_gems, downstream_gems=downstream_gems)
630 new_upstream_gems = self._create_gemports(uni_id, upstream_gems, alloc_id, "UPSTREAM")
631 new_downstream_gems = self._create_gemports(uni_id, downstream_gems, alloc_id, "DOWNSTREAM")
632 new_gems = []
633 new_gems.extend(new_upstream_gems)
634 new_gems.extend(new_downstream_gems)
635
636 def success(_results):
637 self.log.info("new-gem-ports-successfully-installed", result=_results)
Girish Gowdra865776d2020-08-12 14:59:03 -0700638 if tp_id in self._tp_state_map_per_uni[uni_id]:
639 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = None
Girish Gowdra6dd965a2020-08-13 19:13:33 -0700640 # Execute mcast task
641 for gem in downstream_gems:
642 self.log.debug("checking-multicast-service-for-gem ", gem=gem)
643 if gem.mcast:
644 self.log.info("found-multicast-service-for-gem ", gem=gem, uni_id=uni_id, tp_id=tp_id)
645 reactor.callInThread(self.start_multicast_service, uni_id, tp_path)
646 self.log.debug("started_multicast_service-successfully", gem=gem)
647 break
Girish Gowdrae933cd32019-11-21 21:04:41 +0530648
649 def failure(_reason):
650 self.log.warn('new-gem-port-install-failed--retrying',
651 _reason=_reason)
Girish Gowdra865776d2020-08-12 14:59:03 -0700652 if tp_id in self._tp_state_map_per_uni[uni_id]:
653 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = None
Girish Gowdrae933cd32019-11-21 21:04:41 +0530654 # Remove gem ports from cache. We will re-add them during the retry
655 for gp in new_gems:
656 self.pon_port.remove_gem_id(gp.gem_id, gp.direction, False)
657
Girish Gowdrac5117452020-08-03 11:20:53 -0700658 retry = random.randint(1, 5)
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -0500659 reactor.callLater(retry, self.load_and_configure_tech_profile,
660 uni_id, tp_path)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530661
Girish Gowdra8777c852020-07-23 12:00:23 -0700662 if self._pon.get_tcont(alloc_id) is None:
663 self.log.error("no-valid-tcont-reference-for-tp-id--not-installing-gem", alloc_id=alloc_id, tp_id=tp_id)
664 return
665
Girish Gowdrac5117452020-08-03 11:20:53 -0700666 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = \
Girish Gowdra8777c852020-07-23 12:00:23 -0700667 BrcmTpSetupTask(self.omci_agent, self, uni_id, [self._pon.get_tcont(alloc_id)], new_gems, tp_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530668 self._deferred = \
Girish Gowdrac5117452020-08-03 11:20:53 -0700669 self._onu_omci_device.task_runner.queue_task(self._tp_state_map_per_uni[uni_id][tp_id].
670 tp_task_ref)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530671 self._deferred.addCallbacks(success, failure)
Girish Gowdradc98d812020-03-20 13:04:58 -0700672
Matt Jeanneret5e331892019-12-07 21:31:45 -0500673 @inlineCallbacks
Girish Gowdradc98d812020-03-20 13:04:58 -0700674 def start_multicast_service(self, uni_id, tp_path, retry_count=0):
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800675 self.log.debug("starting-multicast-service", uni_id=uni_id, tp_path=tp_path)
676 tp_id = self.extract_tp_id_from_path(tp_path)
677 if uni_id in self._set_vlan and tp_id in self._set_vlan[uni_id]:
678 try:
679 tp = self._tp[tp_id]
680 if tp is None:
Matt Jeanneret5e331892019-12-07 21:31:45 -0500681 tpstored = yield self.tp_kv_client.get(tp_path)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800682 tpstring = tpstored.decode('ascii')
683 tp = json.loads(tpstring)
684 if tp is None:
685 self.log.error("cannot-find-tp-to-start-multicast-service", uni_id=uni_id, tp_path=tp_path)
686 return
687 else:
688 self._tp[tp_id] = tp
689
690 self.log.debug("mcast-vlan-learned-before", self._set_vlan[uni_id][tp_id], uni_id=uni_id, tp_id=tp_id)
Girish Gowdradc98d812020-03-20 13:04:58 -0700691
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800692 def success(_results):
693 self.log.debug('multicast-success', uni_id=uni_id)
694 self._multicast_task = None
695
696 def failure(_reason):
697 self.log.warn('multicast-failure', _reason=_reason)
Girish Gowdrac5117452020-08-03 11:20:53 -0700698 retry = random.randint(1, 5)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800699 reactor.callLater(retry, self.start_multicast_service,
Girish Gowdradc98d812020-03-20 13:04:58 -0700700 uni_id, tp_path)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800701
702 self.log.debug('starting-multicast-task', mcast_vlan_id=self._set_vlan[uni_id][tp_id])
703 downstream_gem_port_attribute_list = tp['downstream_gem_port_attribute_list']
704 for i in range(len(downstream_gem_port_attribute_list)):
705 if IS_MULTICAST in downstream_gem_port_attribute_list[i] and \
706 downstream_gem_port_attribute_list[i][IS_MULTICAST] == 'True':
Girish Gowdradc98d812020-03-20 13:04:58 -0700707 dynamic_access_control_list_table = downstream_gem_port_attribute_list[i][
708 'dynamic_access_control_list'].split("-")
709 static_access_control_list_table = downstream_gem_port_attribute_list[i][
710 'static_access_control_list'].split("-")
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800711 multicast_gem_id = downstream_gem_port_attribute_list[i]['multicast_gem_id']
Girish Gowdra6dd965a2020-08-13 19:13:33 -0700712 self._multicast_task = BrcmMcastTask(self.omci_agent, self, self.device_id, uni_id, tp_id,
713 self._set_vlan[uni_id][tp_id],
714 dynamic_access_control_list_table,
715 static_access_control_list_table, multicast_gem_id)
716 self._deferred = self._onu_omci_device.task_runner.queue_task(self._multicast_task)
717 self._deferred.addCallbacks(success, failure)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800718 break
719
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800720 except Exception as e:
721 self.log.exception("error-loading-multicast", e=e)
722 else:
Girish Gowdradc98d812020-03-20 13:04:58 -0700723 if retry_count < 30:
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800724 retry_count = +1
Girish Gowdradc98d812020-03-20 13:04:58 -0700725 self.log.debug("going-to-wait-for-flow-to-learn-mcast-vlan", uni_id=uni_id, tp_id=tp_id,
726 retry=retry_count)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800727 reactor.callLater(0.5, self.start_multicast_service, uni_id, tp_path, retry_count)
728 else:
Girish Gowdradc98d812020-03-20 13:04:58 -0700729 self.log.error("mcast-vlan-not-configured-yet-failing-mcast-service-conf", uni_id=uni_id, tp_id=tp_id,
730 retry=retry_count)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530731
Girish Gowdraba4b1812020-07-17 12:21:26 -0700732 def _clear_alloc_id_gem_port_from_internal_cache(self, alloc_id=None, gem_port_id=None):
733 tcont = None
734 gem_port = None
735 if alloc_id is not None:
736 self.log.debug("current-cached-tconts", tconts=list(self.pon_port.tconts.values()))
737 for tc in list(self.pon_port.tconts.values()):
738 if tc.alloc_id == alloc_id:
739 self.log.info("removing-tcont-from-internal-cache",
740 alloc_id=alloc_id)
741 tcont = tc
742 self.pon_port.remove_tcont(tc.alloc_id, False)
743
744 if gem_port_id is not None:
745 self.log.debug("current-cached-gem-ports", gem_ports=list(self.pon_port.gem_ports.values()))
746 for gp in list(self.pon_port.gem_ports.values()):
747 if gp.gem_id == gem_port_id:
748 self.log.info("removing-gem-from-internal-cache",
749 gem_port_id=gem_port_id, direction=gp.direction)
750 gem_port = gp
751 self.pon_port.remove_gem_id(gp.gem_id, gp.direction, False)
752
753 return tcont, gem_port
754
Girish Gowdrac5117452020-08-03 11:20:53 -0700755 def _tcont_delete_complete(self, uni_id, tp_id):
756 if not self._tp_state_map_per_uni[uni_id][tp_id].is_all_pon_resource_delete_complete():
757 self.log.info("waiting-for-gem-port-delete-to-complete-before-clearing-tp-states")
758 retry = random.randint(1, 5)
759 reactor.callLater(retry, self._tcont_delete_complete, uni_id, tp_id)
760 return
761 self.log.info("tp-delete-complete")
762 # Clear TP states
763 self._tp_state_map_per_uni[uni_id][tp_id].reset_tp_state()
764 del self._tp_state_map_per_uni[uni_id][tp_id]
765
766 def delete_tech_profile(self, uni_id, tp_path, tcont=None, gem_port=None):
767 alloc_id = None
768 gem_port_id = None
Girish Gowdrae933cd32019-11-21 21:04:41 +0530769 try:
Mahir Gunyele9110a32020-02-20 14:56:50 -0800770 tp_table_id = self.extract_tp_id_from_path(tp_path)
Girish Gowdraba4b1812020-07-17 12:21:26 -0700771 # Extract the current set of TCONT and GEM Ports from the Handler's pon_port that are
772 # relevant to this task's UNI. It won't change. But, the underlying pon_port may change
773 # due to additional tasks on different UNIs. So, it we cannot use the pon_port affter
774 # this initializer
Girish Gowdrac5117452020-08-03 11:20:53 -0700775 alloc_id = tcont.alloc_id if tcont is not None else None
776 gem_port_id = gem_port.gem_id if gem_port is not None else None
777 self._clear_alloc_id_gem_port_from_internal_cache(alloc_id, gem_port_id)
Girish Gowdraba4b1812020-07-17 12:21:26 -0700778
Girish Gowdrac5117452020-08-03 11:20:53 -0700779 if tp_table_id not in self._tp_state_map_per_uni[uni_id]:
Mahir Gunyele9110a32020-02-20 14:56:50 -0800780 self.log.warn("tp-id-is-not-present", uni_id=uni_id, tp_id=tp_table_id)
Naga Manjunathe433c712020-01-02 17:27:20 +0530781 return
782
Girish Gowdrac5117452020-08-03 11:20:53 -0700783 if self._tp_state_map_per_uni[uni_id][tp_table_id].tp_setup_done is not True:
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800784 self.log.error("tp-download-is-not-done-in-order-to-process-tp-delete", uni_id=uni_id,
785 tp_id=tp_table_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530786 return
787
788 if alloc_id is None and gem_port_id is None:
Mahir Gunyele9110a32020-02-20 14:56:50 -0800789 self.log.error("alloc-id-and-gem-port-id-are-none", uni_id=uni_id, tp_id=tp_table_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530790 return
791
Girish Gowdrae933cd32019-11-21 21:04:41 +0530792 @inlineCallbacks
793 def success(_results):
794 if gem_port_id:
795 self.log.info("gem-port-delete-done-successfully")
Girish Gowdrac5117452020-08-03 11:20:53 -0700796 self._tp_state_map_per_uni[uni_id][tp_table_id].pon_resource_delete_complete(TpState.GEM_ID,
797 gem_port_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530798 if alloc_id:
799 self.log.info("tcont-delete-done-successfully")
800 # The deletion of TCONT marks the complete deletion of tech-profile
Girish Gowdrac5117452020-08-03 11:20:53 -0700801 self._tp_state_map_per_uni[uni_id][tp_table_id].pon_resource_delete_complete(TpState.ALLOC_ID,
802 alloc_id)
803 self._tcont_delete_complete(uni_id, tp_table_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530804
805 # TODO: There could be multiple TP on the UNI, and also the ONU.
806 # TODO: But the below reason updates for the whole device.
807 yield self.core_proxy.device_reason_update(self.device_id, 'tech-profile-config-delete-success')
808
809 @inlineCallbacks
Girish Gowdraa73ee452019-12-20 18:52:17 +0530810 def failure(_reason):
Girish Gowdrae933cd32019-11-21 21:04:41 +0530811 self.log.warn('tech-profile-delete-failure-retrying',
812 _reason=_reason)
Girish Gowdrac5117452020-08-03 11:20:53 -0700813 retry = random.randint(1, 5)
814 _tcont = self._tp_state_map_per_uni[uni_id][tp_table_id].get_queued_resource_for_delete(TpState.ALLOC_ID, alloc_id)
815 _gem_port = self._tp_state_map_per_uni[uni_id][tp_table_id].get_queued_resource_for_delete(TpState.GEM_ID, gem_port_id)
816 reactor.callLater(retry, self.delete_tech_profile, uni_id, tp_path, _tcont, _gem_port)
Matt Jeanneretd84c9072020-01-31 06:33:27 -0500817 yield self.core_proxy.device_reason_update(self.device_id,
818 'tech-profile-config-delete-failure-retrying')
Girish Gowdrae933cd32019-11-21 21:04:41 +0530819
820 self.log.info('deleting-tech-profile-configuration')
821
Girish Gowdraa73ee452019-12-20 18:52:17 +0530822 if tcont is None and gem_port is None:
823 if alloc_id is not None:
824 self.log.error("tcont-info-corresponding-to-alloc-id-not-found", alloc_id=alloc_id)
825 if gem_port_id is not None:
826 self.log.error("gem-port-info-corresponding-to-gem-port-id-not-found", gem_port_id=gem_port_id)
827 return
828
Girish Gowdrac5117452020-08-03 11:20:53 -0700829 self._tp_state_map_per_uni[uni_id][tp_table_id].tp_task_ref = \
Girish Gowdrae933cd32019-11-21 21:04:41 +0530830 BrcmTpDeleteTask(self.omci_agent, self, uni_id, tp_table_id,
831 tcont=tcont, gem_port=gem_port)
832 self._deferred = \
Girish Gowdrac5117452020-08-03 11:20:53 -0700833 self._onu_omci_device.task_runner.queue_task(self._tp_state_map_per_uni[uni_id][tp_table_id].
834 tp_task_ref)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530835 self._deferred.addCallbacks(success, failure)
836 except Exception as e:
837 self.log.exception("failed-to-delete-tp",
838 e=e, uni_id=uni_id, tp_path=tp_path,
839 alloc_id=alloc_id, gem_port_id=gem_port_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500840
Rohan Agrawalf0f8c292020-06-01 09:30:55 +0000841 def update_pm_config(self, device, pm_configs):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500842 # TODO: This has not been tested
Rohan Agrawalf0f8c292020-06-01 09:30:55 +0000843 self.log.info('update_pm_config', pm_configs=pm_configs)
844 self._pm_metrics.update(pm_configs)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500845
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800846 def remove_onu_flows(self, device, flows):
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500847 self.log.debug('remove-onu-flows')
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800848
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800849 # no point in removing omci flows if the device isnt reachable
850 if device.connect_status != ConnectStatus.REACHABLE or \
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800851 device.admin_state != AdminState.ENABLED:
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800852 self.log.warn("device-disabled-or-offline-skipping-remove-flow",
853 admin=device.admin_state, connect=device.connect_status)
854 return
855
856 for flow in flows:
857 # if incoming flow contains cookie, then remove from ONU
858 if flow.cookie:
859 self.log.debug("remove-flow", device_id=device.id, flow=flow)
860
861 def is_downstream(port):
862 return port == self._pon_port_number
863
864 def is_upstream(port):
865 return not is_downstream(port)
866
867 try:
868 _in_port = fd.get_in_port(flow)
869 assert _in_port is not None
870
871 _out_port = fd.get_out_port(flow) # may be None
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800872
873 if is_downstream(_in_port):
874 self.log.debug('downstream-flow-no-need-to-remove', in_port=_in_port, out_port=_out_port,
875 device_id=device.id)
876 # extended vlan tagging operation will handle it
877 continue
878 elif is_upstream(_in_port):
879 self.log.debug('upstream-flow', in_port=_in_port, out_port=_out_port)
880 if fd.is_dhcp_flow(flow):
881 self.log.debug('The dhcp trap-to-host flow will be discarded', device_id=device.id)
882 return
883
Mahir Gunyel45610b42020-03-16 17:29:01 -0700884 _match_vlan_vid = None
885 for field in fd.get_ofb_fields(flow):
886 if field.type == fd.VLAN_VID:
887 if field.vlan_vid == RESERVED_TRANSPARENT_VLAN and field.vlan_vid_mask == RESERVED_TRANSPARENT_VLAN:
888 _match_vlan_vid = RESERVED_TRANSPARENT_VLAN
889 else:
890 _match_vlan_vid = field.vlan_vid & 0xfff
891 self.log.debug('field-type-vlan-vid',
892 vlan=_match_vlan_vid)
893
894 _set_vlan_vid = None
895 _set_vlan_pcp = None
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800896 # Retrieve the VLAN_VID that needs to be removed from the EVTO rule on the ONU.
897 for action in fd.get_actions(flow):
898 if action.type == fd.SET_FIELD:
899 _field = action.set_field.field.ofb_field
900 assert (action.set_field.field.oxm_class ==
901 OFPXMC_OPENFLOW_BASIC)
902 if _field.type == fd.VLAN_VID:
Mahir Gunyel45610b42020-03-16 17:29:01 -0700903 _set_vlan_vid = _field.vlan_vid & 0xfff
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800904 self.log.debug('vlan-vid-to-remove',
Mahir Gunyel45610b42020-03-16 17:29:01 -0700905 _vlan_vid=_set_vlan_vid, in_port=_in_port)
906 elif _field.type == fd.VLAN_PCP:
907 _set_vlan_pcp = _field.vlan_pcp
908 self.log.debug('set-field-type-vlan-pcp',
909 vlan_pcp=_set_vlan_pcp)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800910
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800911 uni_port = self.uni_port(_in_port)
912 uni_id = _in_port & 0xF
913 else:
914 raise Exception('port should be 1 or 2 by our convention')
915
916 self.log.debug('flow-ports', in_port=_in_port, out_port=_out_port, uni_port=str(uni_port))
917
918 tp_id = self.get_tp_id_in_flow(flow)
Girish Gowdradc98d812020-03-20 13:04:58 -0700919 # The vlan filter remove should be followed by a TP deleted for that TP ID.
920 # Use this information to re-schedule any vlan filter add tasks for the same TP ID again.
921 # First check if the TP download was done, before we access that TP delete is necessary
Girish Gowdrac5117452020-08-03 11:20:53 -0700922 if tp_id in self._tp_state_map_per_uni[uni_id] and \
923 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done is True:
924 self._tp_state_map_per_uni[uni_id][tp_id].is_tp_delete_pending = True
925
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800926 # Deleting flow from ONU.
Mahir Gunyel45610b42020-03-16 17:29:01 -0700927 self._remove_vlan_filter_task(device, uni_id, uni_port=uni_port,
928 _set_vlan_pcp=_set_vlan_pcp,
929 _set_vlan_vid=_set_vlan_vid,
930 match_vlan=_match_vlan_vid,
931 tp_id=tp_id)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800932 # TODO:Delete TD task.
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800933 except Exception as e:
934 self.log.exception('failed-to-remove-flow', e=e)
935
936 def add_onu_flows(self, device, flows):
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500937 self.log.debug('add-onu-flows')
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800938
939 # no point in pushing omci flows if the device isnt reachable
940 if device.connect_status != ConnectStatus.REACHABLE or \
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800941 device.admin_state != AdminState.ENABLED:
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800942 self.log.warn("device-disabled-or-offline-skipping-flow-update",
943 admin=device.admin_state, connect=device.connect_status)
944 return
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800945
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800946 def is_downstream(port):
947 return port == self._pon_port_number
948
949 def is_upstream(port):
950 return not is_downstream(port)
951
952 for flow in flows:
953 # if incoming flow contains cookie, then add to ONU
954 if flow.cookie:
955 _type = None
956 _port = None
957 _vlan_vid = None
958 _udp_dst = None
959 _udp_src = None
960 _ipv4_dst = None
961 _ipv4_src = None
962 _metadata = None
963 _output = None
964 _push_tpid = None
965 _field = None
966 _set_vlan_vid = None
Mahir Gunyel45610b42020-03-16 17:29:01 -0700967 _set_vlan_pcp = None
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800968 _tunnel_id = None
Girish Gowdra6a73ad62020-06-11 13:40:16 -0700969 _proto = -1
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800970 self.log.debug("add-flow", device_id=device.id, flow=flow)
971
972 try:
973 _in_port = fd.get_in_port(flow)
974 assert _in_port is not None
975
976 _out_port = fd.get_out_port(flow) # may be None
977 tp_id = self.get_tp_id_in_flow(flow)
978 if is_downstream(_in_port):
979 self.log.debug('downstream-flow', in_port=_in_port, out_port=_out_port)
980 # NOTE: We don't care downstream flow because we will copy vlan_id to upstream flow
981 # uni_port = self.uni_port(_out_port)
982 # uni_id = _out_port & 0xF
983 continue
984 elif is_upstream(_in_port):
985 self.log.debug('upstream-flow', in_port=_in_port, out_port=_out_port)
986 uni_port = self.uni_port(_in_port)
987 uni_id = _in_port & 0xF
988 else:
989 raise Exception('port should be 1 or 2 by our convention')
990
991 self.log.debug('flow-ports', in_port=_in_port, out_port=_out_port, uni_port=str(uni_port))
992
993 for field in fd.get_ofb_fields(flow):
994 if field.type == fd.ETH_TYPE:
995 _type = field.eth_type
996 self.log.debug('field-type-eth-type',
997 eth_type=_type)
998
999 elif field.type == fd.IP_PROTO:
1000 _proto = field.ip_proto
Girish Gowdra6a73ad62020-06-11 13:40:16 -07001001 if _proto == 2:
1002 # Workaround for TT workflow - avoids installing invalid EVTO rule
1003 self.log.debug("igmp-trap-flow")
1004 break
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001005 self.log.debug('field-type-ip-proto',
1006 ip_proto=_proto)
1007
1008 elif field.type == fd.IN_PORT:
1009 _port = field.port
1010 self.log.debug('field-type-in-port',
1011 in_port=_port)
1012 elif field.type == fd.TUNNEL_ID:
1013 self.log.debug('field-type-tunnel-id')
1014
1015 elif field.type == fd.VLAN_VID:
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001016 if field.vlan_vid == RESERVED_TRANSPARENT_VLAN and field.vlan_vid_mask == RESERVED_TRANSPARENT_VLAN:
1017 _vlan_vid = RESERVED_TRANSPARENT_VLAN
1018 else:
1019 _vlan_vid = field.vlan_vid & 0xfff
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001020 self.log.debug('field-type-vlan-vid',
1021 vlan=_vlan_vid)
1022
1023 elif field.type == fd.VLAN_PCP:
1024 _vlan_pcp = field.vlan_pcp
1025 self.log.debug('field-type-vlan-pcp',
1026 pcp=_vlan_pcp)
1027
1028 elif field.type == fd.UDP_DST:
1029 _udp_dst = field.udp_dst
1030 self.log.debug('field-type-udp-dst',
1031 udp_dst=_udp_dst)
1032
1033 elif field.type == fd.UDP_SRC:
1034 _udp_src = field.udp_src
1035 self.log.debug('field-type-udp-src',
1036 udp_src=_udp_src)
1037
1038 elif field.type == fd.IPV4_DST:
1039 _ipv4_dst = field.ipv4_dst
1040 self.log.debug('field-type-ipv4-dst',
1041 ipv4_dst=_ipv4_dst)
1042
1043 elif field.type == fd.IPV4_SRC:
1044 _ipv4_src = field.ipv4_src
1045 self.log.debug('field-type-ipv4-src',
1046 ipv4_dst=_ipv4_src)
1047
1048 elif field.type == fd.METADATA:
1049 _metadata = field.table_metadata
1050 self.log.debug('field-type-metadata',
1051 metadata=_metadata)
1052
1053 else:
1054 raise NotImplementedError('field.type={}'.format(
1055 field.type))
1056
Girish Gowdra6a73ad62020-06-11 13:40:16 -07001057 if _proto == 2:
1058 # Workaround for TT workflow - avoids installing invalid EVTO rule
1059 self.log.warn("skipping-igmp-trap-flow")
1060 continue
1061
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001062 for action in fd.get_actions(flow):
1063
1064 if action.type == fd.OUTPUT:
1065 _output = action.output.port
1066 self.log.debug('action-type-output',
1067 output=_output, in_port=_in_port)
1068
1069 elif action.type == fd.POP_VLAN:
1070 self.log.debug('action-type-pop-vlan',
1071 in_port=_in_port)
1072
1073 elif action.type == fd.PUSH_VLAN:
1074 _push_tpid = action.push.ethertype
1075 self.log.debug('action-type-push-vlan',
1076 push_tpid=_push_tpid, in_port=_in_port)
1077 if action.push.ethertype != 0x8100:
1078 self.log.error('unhandled-tpid',
1079 ethertype=action.push.ethertype)
1080
1081 elif action.type == fd.SET_FIELD:
1082 _field = action.set_field.field.ofb_field
1083 assert (action.set_field.field.oxm_class ==
1084 OFPXMC_OPENFLOW_BASIC)
1085 self.log.debug('action-type-set-field',
1086 field=_field, in_port=_in_port)
1087 if _field.type == fd.VLAN_VID:
1088 _set_vlan_vid = _field.vlan_vid & 0xfff
1089 self.log.debug('set-field-type-vlan-vid',
1090 vlan_vid=_set_vlan_vid)
1091 elif _field.type == fd.VLAN_PCP:
1092 _set_vlan_pcp = _field.vlan_pcp
1093 self.log.debug('set-field-type-vlan-pcp',
1094 vlan_pcp=_set_vlan_pcp)
1095 else:
1096 self.log.error('unsupported-action-set-field-type',
1097 field_type=_field.type)
1098 else:
1099 self.log.error('unsupported-action-type',
1100 action_type=action.type, in_port=_in_port)
1101
Mahir Gunyel5de33fe2020-03-03 22:38:44 -08001102 if self._set_vlan is not None:
1103 if uni_id not in self._set_vlan:
1104 self._set_vlan[uni_id] = dict()
1105 self._set_vlan[uni_id][tp_id] = _set_vlan_vid
1106 self.log.debug("set_vlan_id-for-tp", _set_vlan_vid=_set_vlan_vid, tp_id=tp_id)
1107
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001108 # OMCI set vlan task can only filter and set on vlan header attributes. Any other openflow
1109 # supported match and action criteria cannot be handled by omci and must be ignored.
1110 if (_set_vlan_vid is None or _set_vlan_vid == 0) and _vlan_vid != RESERVED_TRANSPARENT_VLAN:
1111 self.log.warn('ignoring-flow-that-does-not-set-vlanid', set_vlan_vid=_set_vlan_vid)
1112 elif (_set_vlan_vid is None or _set_vlan_vid == 0) and _vlan_vid == RESERVED_TRANSPARENT_VLAN:
1113 self.log.info('set-vlanid-any', uni_id=uni_id, uni_port=uni_port,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001114 _set_vlan_vid=_vlan_vid,
1115 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1116 tp_id=tp_id)
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001117 self._add_vlan_filter_task(device, uni_id=uni_id, uni_port=uni_port,
1118 _set_vlan_vid=_vlan_vid,
1119 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1120 tp_id=tp_id)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001121 else:
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001122 self.log.info('set-vlanid', uni_id=uni_id, uni_port=uni_port, match_vlan=_vlan_vid,
1123 set_vlan_vid=_set_vlan_vid, _set_vlan_pcp=_set_vlan_pcp, ethType=_type)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001124 self._add_vlan_filter_task(device, uni_id=uni_id, uni_port=uni_port,
1125 _set_vlan_vid=_set_vlan_vid,
1126 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1127 tp_id=tp_id)
1128
1129 except Exception as e:
1130 self.log.exception('failed-to-install-flow', e=e, flow=flow)
1131
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001132 # Calling this assumes the onu is active/ready and had at least an initial mib downloaded. This gets called from
1133 # flow decomposition that ultimately comes from onos
1134 def update_flow_table(self, device, flows):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001135 self.log.debug('update-flow-table', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001136
1137 #
1138 # We need to proxy through the OLT to get to the ONU
1139 # Configuration from here should be using OMCI
1140 #
1141 # self.log.info('bulk-flow-update', device_id=device.id, flows=flows)
1142
1143 # no point in pushing omci flows if the device isnt reachable
1144 if device.connect_status != ConnectStatus.REACHABLE or \
Girish Gowdrae933cd32019-11-21 21:04:41 +05301145 device.admin_state != AdminState.ENABLED:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001146 self.log.warn("device-disabled-or-offline-skipping-flow-update",
1147 admin=device.admin_state, connect=device.connect_status)
1148 return
1149
1150 def is_downstream(port):
1151 return port == self._pon_port_number
1152
1153 def is_upstream(port):
1154 return not is_downstream(port)
1155
1156 for flow in flows:
1157 _type = None
1158 _port = None
1159 _vlan_vid = None
1160 _udp_dst = None
1161 _udp_src = None
1162 _ipv4_dst = None
1163 _ipv4_src = None
1164 _metadata = None
1165 _output = None
1166 _push_tpid = None
1167 _field = None
1168 _set_vlan_vid = None
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001169 _set_vlan_pcp = None
Matt Jeanneretef06d0d2019-04-27 17:36:53 -04001170 _tunnel_id = None
1171
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001172 try:
Girish Gowdraa73ee452019-12-20 18:52:17 +05301173 write_metadata = fd.get_write_metadata(flow)
1174 if write_metadata is None:
1175 self.log.error("do-not-process-flow-without-write-metadata")
1176 return
1177
1178 # extract tp id from flow
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001179 tp_id = self.get_tp_id_in_flow(flow)
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001180 self.log.debug("tp-id-in-flow", tp_id=tp_id)
Girish Gowdraa73ee452019-12-20 18:52:17 +05301181
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001182 _in_port = fd.get_in_port(flow)
1183 assert _in_port is not None
1184
1185 _out_port = fd.get_out_port(flow) # may be None
1186
1187 if is_downstream(_in_port):
1188 self.log.debug('downstream-flow', in_port=_in_port, out_port=_out_port)
1189 uni_port = self.uni_port(_out_port)
Girish Gowdrae933cd32019-11-21 21:04:41 +05301190 uni_id = _out_port & 0xF
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001191 elif is_upstream(_in_port):
1192 self.log.debug('upstream-flow', in_port=_in_port, out_port=_out_port)
1193 uni_port = self.uni_port(_in_port)
Chaitrashree G S8fb96782019-08-19 00:10:49 -04001194 uni_id = _in_port & 0xF
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001195 else:
1196 raise Exception('port should be 1 or 2 by our convention')
1197
1198 self.log.debug('flow-ports', in_port=_in_port, out_port=_out_port, uni_port=str(uni_port))
1199
1200 for field in fd.get_ofb_fields(flow):
1201 if field.type == fd.ETH_TYPE:
1202 _type = field.eth_type
1203 self.log.debug('field-type-eth-type',
1204 eth_type=_type)
1205
1206 elif field.type == fd.IP_PROTO:
1207 _proto = field.ip_proto
1208 self.log.debug('field-type-ip-proto',
1209 ip_proto=_proto)
1210
1211 elif field.type == fd.IN_PORT:
1212 _port = field.port
1213 self.log.debug('field-type-in-port',
1214 in_port=_port)
1215
1216 elif field.type == fd.VLAN_VID:
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001217 if field.vlan_vid == RESERVED_TRANSPARENT_VLAN and field.vlan_vid_mask == RESERVED_TRANSPARENT_VLAN:
1218 _vlan_vid = RESERVED_TRANSPARENT_VLAN
1219 else:
1220 _vlan_vid = field.vlan_vid & 0xfff
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001221 self.log.debug('field-type-vlan-vid',
1222 vlan=_vlan_vid)
1223
1224 elif field.type == fd.VLAN_PCP:
1225 _vlan_pcp = field.vlan_pcp
1226 self.log.debug('field-type-vlan-pcp',
1227 pcp=_vlan_pcp)
1228
1229 elif field.type == fd.UDP_DST:
1230 _udp_dst = field.udp_dst
1231 self.log.debug('field-type-udp-dst',
1232 udp_dst=_udp_dst)
1233
1234 elif field.type == fd.UDP_SRC:
1235 _udp_src = field.udp_src
1236 self.log.debug('field-type-udp-src',
1237 udp_src=_udp_src)
1238
1239 elif field.type == fd.IPV4_DST:
1240 _ipv4_dst = field.ipv4_dst
1241 self.log.debug('field-type-ipv4-dst',
1242 ipv4_dst=_ipv4_dst)
1243
1244 elif field.type == fd.IPV4_SRC:
1245 _ipv4_src = field.ipv4_src
1246 self.log.debug('field-type-ipv4-src',
1247 ipv4_dst=_ipv4_src)
1248
1249 elif field.type == fd.METADATA:
1250 _metadata = field.table_metadata
1251 self.log.debug('field-type-metadata',
1252 metadata=_metadata)
1253
Matt Jeanneretef06d0d2019-04-27 17:36:53 -04001254 elif field.type == fd.TUNNEL_ID:
1255 _tunnel_id = field.tunnel_id
1256 self.log.debug('field-type-tunnel-id',
1257 tunnel_id=_tunnel_id)
1258
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001259
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001260 else:
1261 raise NotImplementedError('field.type={}'.format(
1262 field.type))
1263
1264 for action in fd.get_actions(flow):
1265
1266 if action.type == fd.OUTPUT:
1267 _output = action.output.port
1268 self.log.debug('action-type-output',
1269 output=_output, in_port=_in_port)
1270
1271 elif action.type == fd.POP_VLAN:
1272 self.log.debug('action-type-pop-vlan',
1273 in_port=_in_port)
1274
1275 elif action.type == fd.PUSH_VLAN:
1276 _push_tpid = action.push.ethertype
1277 self.log.debug('action-type-push-vlan',
1278 push_tpid=_push_tpid, in_port=_in_port)
1279 if action.push.ethertype != 0x8100:
1280 self.log.error('unhandled-tpid',
1281 ethertype=action.push.ethertype)
1282
1283 elif action.type == fd.SET_FIELD:
1284 _field = action.set_field.field.ofb_field
1285 assert (action.set_field.field.oxm_class ==
1286 OFPXMC_OPENFLOW_BASIC)
1287 self.log.debug('action-type-set-field',
1288 field=_field, in_port=_in_port)
1289 if _field.type == fd.VLAN_VID:
1290 _set_vlan_vid = _field.vlan_vid & 0xfff
1291 self.log.debug('set-field-type-vlan-vid',
1292 vlan_vid=_set_vlan_vid)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001293 elif _field.type == fd.VLAN_PCP:
1294 _set_vlan_pcp = _field.vlan_pcp
1295 self.log.debug('set-field-type-vlan-pcp',
1296 vlan_pcp=_set_vlan_pcp)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001297 else:
1298 self.log.error('unsupported-action-set-field-type',
1299 field_type=_field.type)
1300 else:
1301 self.log.error('unsupported-action-type',
1302 action_type=action.type, in_port=_in_port)
1303
Mahir Gunyel5de33fe2020-03-03 22:38:44 -08001304 if self._set_vlan is not None:
1305 if uni_id not in self._set_vlan:
1306 self._set_vlan[uni_id] = dict()
1307 self._set_vlan[uni_id][tp_id] = _set_vlan_vid
1308 self.log.debug("set_vlan_id-for-tp", _set_vlan_vid=_set_vlan_vid, tp_id=tp_id)
Matt Jeanneret810148b2019-09-29 12:44:01 -04001309 # OMCI set vlan task can only filter and set on vlan header attributes. Any other openflow
1310 # supported match and action criteria cannot be handled by omci and must be ignored.
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001311 if (_set_vlan_vid is None or _set_vlan_vid == 0) and _vlan_vid != RESERVED_TRANSPARENT_VLAN:
1312 self.log.warn('ignoring-flow-that-does-not-set-vlanid', set_vlan_vid=_set_vlan_vid)
1313 elif (_set_vlan_vid is None or _set_vlan_vid == 0) and _vlan_vid == RESERVED_TRANSPARENT_VLAN:
1314 self.log.info('set-vlanid-any', uni_id=uni_id, uni_port=uni_port,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001315 _set_vlan_vid=_vlan_vid,
1316 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1317 tp_id=tp_id)
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001318 self._add_vlan_filter_task(device, uni_id=uni_id, uni_port=uni_port,
1319 _set_vlan_vid=_vlan_vid,
1320 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1321 tp_id=tp_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001322 else:
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001323 self.log.info('set-vlanid', uni_id=uni_id, uni_port=uni_port, match_vlan=_vlan_vid,
1324 set_vlan_vid=_set_vlan_vid, _set_vlan_pcp=_set_vlan_pcp, ethType=_type)
1325 self._add_vlan_filter_task(device, uni_id=uni_id, uni_port=uni_port,
1326 _set_vlan_vid=_set_vlan_vid,
1327 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1328 tp_id=tp_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001329 except Exception as e:
1330 self.log.exception('failed-to-install-flow', e=e, flow=flow)
1331
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001332 def _add_vlan_filter_task(self, device, uni_id, uni_port=None, match_vlan=0,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001333 _set_vlan_vid=None, _set_vlan_pcp=8, tp_id=0):
Girish Gowdrac5117452020-08-03 11:20:53 -07001334 if tp_id in self._tp_state_map_per_uni[uni_id] and \
1335 self._tp_state_map_per_uni[uni_id][tp_id].is_tp_delete_pending is True:
Girish Gowdradc98d812020-03-20 13:04:58 -07001336 self.log.debug("pending-del-tp--scheduling-add-vlan-filter-task-for-later")
Girish Gowdrac5117452020-08-03 11:20:53 -07001337 retry = random.randint(1, 5)
1338 reactor.callLater(retry, self._add_vlan_filter_task, device, uni_id, uni_port, match_vlan,
Girish Gowdradc98d812020-03-20 13:04:58 -07001339 _set_vlan_vid, _set_vlan_pcp, tp_id)
1340 return
1341
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001342 self.log.info('_adding_vlan_filter_task', uni_port=uni_port, uni_id=uni_id, tp_id=tp_id, match_vlan=match_vlan,
1343 vlan=_set_vlan_vid, vlan_pcp=_set_vlan_pcp)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001344 assert uni_port is not None
Girish Gowdrac5117452020-08-03 11:20:53 -07001345 if tp_id in self._tp_state_map_per_uni[uni_id] and \
1346 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done is True:
Chaitrashree G S8fb96782019-08-19 00:10:49 -04001347 @inlineCallbacks
1348 def success(_results):
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001349 self.log.info('vlan-tagging-success', uni_port=uni_port, vlan=_set_vlan_vid, tp_id=tp_id,
1350 set_vlan_pcp=_set_vlan_pcp)
Matt Jeanneretd84c9072020-01-31 06:33:27 -05001351 yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-pushed')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001352
Chaitrashree G S8fb96782019-08-19 00:10:49 -04001353 @inlineCallbacks
1354 def failure(_reason):
Girish Gowdraa73ee452019-12-20 18:52:17 +05301355 self.log.warn('vlan-tagging-failure', uni_port=uni_port, vlan=_set_vlan_vid, tp_id=tp_id)
Girish Gowdrac5117452020-08-03 11:20:53 -07001356 retry = random.randint(1, 5)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001357 reactor.callLater(retry,
1358 self._add_vlan_filter_task, device, uni_id, uni_port=uni_port,
1359 match_vlan=match_vlan, _set_vlan_vid=_set_vlan_vid,
1360 _set_vlan_pcp=_set_vlan_pcp, tp_id=tp_id)
Matt Jeanneretd84c9072020-01-31 06:33:27 -05001361 yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-failed-retrying')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001362
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001363 self.log.info('setting-vlan-tag', uni_port=uni_port, uni_id=uni_id, tp_id=tp_id, match_vlan=match_vlan,
1364 vlan=_set_vlan_vid, vlan_pcp=_set_vlan_pcp)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001365 vlan_filter_add_task = BrcmVlanFilterTask(self.omci_agent, self, uni_port, _set_vlan_vid,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001366 match_vlan, _set_vlan_pcp, add_tag=True,
1367 tp_id=tp_id)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001368 self._deferred = self._onu_omci_device.task_runner.queue_task(vlan_filter_add_task)
Chaitrashree G S8fb96782019-08-19 00:10:49 -04001369 self._deferred.addCallbacks(success, failure)
1370 else:
1371 self.log.info('tp-service-specific-task-not-done-adding-request-to-local-cache',
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001372 uni_id=uni_id, tp_id=tp_id)
1373 if uni_id not in self._queued_vlan_filter_task:
1374 self._queued_vlan_filter_task[uni_id] = dict()
Mahir Gunyela982ec32020-02-25 12:30:37 -08001375 if tp_id not in self._queued_vlan_filter_task[uni_id]:
1376 self._queued_vlan_filter_task[uni_id][tp_id] = []
1377 self._queued_vlan_filter_task[uni_id][tp_id].append({"device": device,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001378 "uni_id": uni_id,
1379 "uni_port": uni_port,
1380 "match_vlan": match_vlan,
1381 "set_vlan_vid": _set_vlan_vid,
1382 "set_vlan_pcp": _set_vlan_pcp,
1383 "tp_id": tp_id})
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001384
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001385 def get_tp_id_in_flow(self, flow):
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001386 flow_metadata = fd.get_metadata_from_write_metadata(flow)
1387 tp_id = fd.get_tp_id_from_metadata(flow_metadata)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001388 return tp_id
1389
1390 def _remove_vlan_filter_task(self, device, uni_id, uni_port=None, match_vlan=0,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001391 _set_vlan_vid=None, _set_vlan_pcp=8, tp_id=0):
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001392 assert uni_port is not None
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001393
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001394 @inlineCallbacks
1395 def success(_results):
1396 self.log.info('vlan-untagging-success', _results=_results)
1397 yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-deleted')
1398
1399 @inlineCallbacks
1400 def failure(_reason):
1401 self.log.warn('vlan-untagging-failure', _reason=_reason)
1402 yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-deletion-failed-retrying')
Girish Gowdrac5117452020-08-03 11:20:53 -07001403 retry = random.randint(1, 5)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001404 reactor.callLater(retry,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001405 self._remove_vlan_filter_task, device, uni_id,
ozgecanetsiace4e37f2020-07-20 10:16:00 +03001406 uni_port=uni_port, match_vlan=match_vlan, _set_vlan_vid=_set_vlan_vid,
1407 _set_vlan_pcp=_set_vlan_pcp, tp_id=tp_id)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001408
1409 self.log.info("remove_vlan_filter_task", tp_id=tp_id)
1410 vlan_remove_task = BrcmVlanFilterTask(self.omci_agent, self, uni_port, _set_vlan_vid,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001411 match_vlan, _set_vlan_pcp, add_tag=False,
1412 tp_id=tp_id)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001413 self._deferred = self._onu_omci_device.task_runner.queue_task(vlan_remove_task)
1414 self._deferred.addCallbacks(success, failure)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001415
Matt Jeanneret5e331892019-12-07 21:31:45 -05001416 @inlineCallbacks
Matt Jeannereta32441c2019-03-07 05:16:37 -05001417 def process_inter_adapter_message(self, request):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001418 self.log.debug('process-inter-adapter-message', type=request.header.type, from_topic=request.header.from_topic,
1419 to_topic=request.header.to_topic, to_device_id=request.header.to_device_id)
Matt Jeanneret2101f3d2020-03-12 10:13:06 -04001420
1421 if not self.enabled:
1422 self.log.warn('device-not-activated')
1423 reactor.callLater(0.5, self.process_inter_adapter_message, request)
1424 return
1425
Matt Jeannereta32441c2019-03-07 05:16:37 -05001426 try:
Matt Jeanneret5e331892019-12-07 21:31:45 -05001427
1428 update_onu_state = False
1429
Matt Jeannereta32441c2019-03-07 05:16:37 -05001430 if request.header.type == InterAdapterMessageType.OMCI_REQUEST:
1431 omci_msg = InterAdapterOmciMessage()
1432 request.body.Unpack(omci_msg)
Matteo Scandolod8d73172019-11-26 12:15:15 -07001433 self.log.debug('inter-adapter-recv-omci', omci_msg=hexify(omci_msg.message))
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001434
Matt Jeannereta32441c2019-03-07 05:16:37 -05001435 self.receive_message(omci_msg.message)
1436
1437 elif request.header.type == InterAdapterMessageType.ONU_IND_REQUEST:
1438 onu_indication = OnuIndication()
1439 request.body.Unpack(onu_indication)
Matteo Scandolod8d73172019-11-26 12:15:15 -07001440 self.log.debug('inter-adapter-recv-onu-ind', onu_id=onu_indication.onu_id,
1441 oper_state=onu_indication.oper_state, admin_state=onu_indication.admin_state,
1442 serial_number=onu_indication.serial_number)
Matt Jeannereta32441c2019-03-07 05:16:37 -05001443
Matt Jeanneret5e331892019-12-07 21:31:45 -05001444 update_onu_state = True
1445 self._onu_persisted_state['onu_id'] = onu_indication.onu_id
1446 self._onu_persisted_state['intf_id'] = onu_indication.intf_id
1447 self._onu_persisted_state['admin_state'] = onu_indication.admin_state
Mahir Gunyel45610b42020-03-16 17:29:01 -07001448 self._onu_persisted_state['oper_state'] = onu_indication.oper_state
Matt Jeanneret5e331892019-12-07 21:31:45 -05001449
Matt Jeannereta32441c2019-03-07 05:16:37 -05001450 if onu_indication.oper_state == "up":
Matt Jeanneret5e331892019-12-07 21:31:45 -05001451 yield self.create_interface(onu_indication)
Girish Gowdrae933cd32019-11-21 21:04:41 +05301452 elif onu_indication.oper_state == "down" or onu_indication.oper_state == "unreachable":
Matt Jeanneret5e331892019-12-07 21:31:45 -05001453 yield self.update_interface(onu_indication)
Matt Jeannereta32441c2019-03-07 05:16:37 -05001454 else:
Matteo Scandolod8d73172019-11-26 12:15:15 -07001455 self.log.error("unknown-onu-indication", onu_id=onu_indication.onu_id,
1456 serial_number=onu_indication.serial_number)
Matt Jeannereta32441c2019-03-07 05:16:37 -05001457
Matt Jeanneret3bfebff2019-04-12 18:25:03 -04001458 elif request.header.type == InterAdapterMessageType.TECH_PROFILE_DOWNLOAD_REQUEST:
1459 tech_msg = InterAdapterTechProfileDownloadMessage()
1460 request.body.Unpack(tech_msg)
1461 self.log.debug('inter-adapter-recv-tech-profile', tech_msg=tech_msg)
1462
Matt Jeanneret5e331892019-12-07 21:31:45 -05001463 update_onu_state = self._update_onu_persisted_state(tech_msg.uni_id, tp_path=tech_msg.path)
1464 yield self.load_and_configure_tech_profile(tech_msg.uni_id, tech_msg.path)
Matt Jeanneret3bfebff2019-04-12 18:25:03 -04001465
Girish Gowdrae933cd32019-11-21 21:04:41 +05301466 elif request.header.type == InterAdapterMessageType.DELETE_GEM_PORT_REQUEST:
1467 del_gem_msg = InterAdapterDeleteGemPortMessage()
1468 request.body.Unpack(del_gem_msg)
1469 self.log.debug('inter-adapter-recv-del-gem', gem_del_msg=del_gem_msg)
Girish Gowdrac5117452020-08-03 11:20:53 -07001470 tp_id = self.extract_tp_id_from_path(del_gem_msg.tp_path)
1471 uni_id = del_gem_msg.uni_id
1472 gem_port = self._pon.get_gem_port(del_gem_msg.gem_port_id)
1473 self._tp_state_map_per_uni[uni_id][tp_id].queue_pending_delete_pon_resource(TpState.GEM_ID,
1474 gem_port)
Girish Gowdra322cca12020-08-09 15:55:54 -07001475 if self.is_device_active_and_reachable:
1476 self.delete_tech_profile(uni_id=del_gem_msg.uni_id,
1477 gem_port=gem_port,
1478 tp_path=del_gem_msg.tp_path)
1479 else:
1480 self.log.debug("device-unreachable--clearing-gem-id-from-local-cache")
1481 if tp_id in self._tp_state_map_per_uni[uni_id]:
1482 self._tp_state_map_per_uni[uni_id][tp_id].pon_resource_delete_complete(TpState.GEM_ID,
1483 gem_port.gem_id)
1484 self._clear_alloc_id_gem_port_from_internal_cache(None, gem_port.gem_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +05301485
1486 elif request.header.type == InterAdapterMessageType.DELETE_TCONT_REQUEST:
1487 del_tcont_msg = InterAdapterDeleteTcontMessage()
1488 request.body.Unpack(del_tcont_msg)
1489 self.log.debug('inter-adapter-recv-del-tcont', del_tcont_msg=del_tcont_msg)
1490
Matt Jeanneret5e331892019-12-07 21:31:45 -05001491 # Removal of the tcont/alloc id mapping represents the removal of the tech profile
1492 update_onu_state = self._update_onu_persisted_state(del_tcont_msg.uni_id, tp_path=None)
Girish Gowdrac5117452020-08-03 11:20:53 -07001493 tp_id = self.extract_tp_id_from_path(del_tcont_msg.tp_path)
1494 uni_id = del_tcont_msg.uni_id
1495 tcont = self._pon.get_tcont(del_tcont_msg.alloc_id)
1496 self._tp_state_map_per_uni[uni_id][tp_id].queue_pending_delete_pon_resource(TpState.ALLOC_ID,
1497 tcont)
Girish Gowdra322cca12020-08-09 15:55:54 -07001498 if self.is_device_active_and_reachable:
1499 self.delete_tech_profile(uni_id=del_tcont_msg.uni_id,
1500 tcont=tcont,
1501 tp_path=del_tcont_msg.tp_path)
1502 else:
1503 self.log.debug("device-unreachable--clearing-tcont-from-local-cache")
1504 if tp_id in self._tp_state_map_per_uni[uni_id]:
1505 self._tp_state_map_per_uni[uni_id][tp_id].pon_resource_delete_complete(TpState.ALLOC_ID,
1506 tcont.alloc_id)
1507 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done = False
1508 self._clear_alloc_id_gem_port_from_internal_cache(tcont.alloc_id, None)
1509
Matt Jeannereta32441c2019-03-07 05:16:37 -05001510 else:
1511 self.log.error("inter-adapter-unhandled-type", request=request)
1512
Matt Jeanneret5e331892019-12-07 21:31:45 -05001513 if update_onu_state:
1514 try:
1515 self.log.debug('updating-onu-state', device_id=self.device_id,
1516 onu_persisted_state=self._onu_persisted_state)
1517 yield self.onu_kv_client.set(self.device_id, json.dumps(self._onu_persisted_state))
1518 except Exception as e:
1519 self.log.error('could-not-store-onu-state', device_id=self.device_id,
1520 onu_persisted_state=self._onu_persisted_state, e=e)
1521 # at this point omci is started and/or indications being processed
1522 # later indications may have a chance to write this state out again
1523
Matt Jeannereta32441c2019-03-07 05:16:37 -05001524 except Exception as e:
1525 self.log.exception("error-processing-inter-adapter-message", e=e)
1526
Matt Jeanneret5e331892019-12-07 21:31:45 -05001527 def _update_onu_persisted_state(self, uni_id, tp_path):
1528 # persist the uni and tech profile path for later reconciliation. update only if changed
1529 update_onu_state = False
1530 found = False
1531 for entry in self._onu_persisted_state.get('uni_config', list()):
1532 if entry.get('uni_id') == uni_id:
1533 found = True
1534 if entry.get('tp_path') != tp_path:
1535 update_onu_state = True
1536 entry['tp_path'] = tp_path
1537
1538 if not found:
1539 update_onu_state = True
1540 uni_tp = {
1541 'uni_id': uni_id,
1542 'tp_path': tp_path
1543 }
1544 self._onu_persisted_state['uni_config'].append(uni_tp)
1545
1546 return update_onu_state
1547
Matt Jeannereta32441c2019-03-07 05:16:37 -05001548 # Called each time there is an onu "up" indication from the olt handler
1549 @inlineCallbacks
1550 def create_interface(self, onu_indication):
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001551 self.log.info('create-interface', onu_id=onu_indication.onu_id,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001552 serial_number=onu_indication.serial_number)
Amit Ghosh028eb202020-02-17 13:34:00 +00001553
1554 # Ignore if onu_indication is received for an already running ONU
1555 if self._onu_omci_device is not None and self._onu_omci_device.active:
1556 self.log.warn('received-onu-indication-for-active-onu', onu_indication=onu_indication)
1557 return
1558
Matt Jeanneretc083f462019-03-11 15:02:01 -04001559 yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.ACTIVATING,
1560 connect_status=ConnectStatus.REACHABLE)
1561
Matt Jeannereta32441c2019-03-07 05:16:37 -05001562 onu_device = yield self.core_proxy.get_device(self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001563
1564 self.log.debug('starting-openomci-statemachine')
1565 self._subscribe_to_events()
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001566 onu_device.reason = "starting-openomci"
Girish Gowdrae933cd32019-11-21 21:04:41 +05301567 reactor.callLater(1, self._onu_omci_device.start, onu_device)
Mahir Gunyel0e6882a2019-10-16 17:02:39 -07001568 yield self.core_proxy.device_reason_update(self.device_id, onu_device.reason)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001569 self._heartbeat.enabled = True
1570
Matt Jeanneret42dad792020-02-01 09:28:27 -05001571 # Called each time there is an onu "down" indication from the olt handler
Matt Jeannereta32441c2019-03-07 05:16:37 -05001572 @inlineCallbacks
1573 def update_interface(self, onu_indication):
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001574 self.log.info('update-interface', onu_id=onu_indication.onu_id,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001575 serial_number=onu_indication.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001576
Chaitrashree G Sd73fb9b2019-09-09 20:27:30 -04001577 if onu_indication.oper_state == 'down' or onu_indication.oper_state == "unreachable":
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001578 self.log.debug('stopping-openomci-statemachine', device_id=self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001579 reactor.callLater(0, self._onu_omci_device.stop)
1580
Mahir Gunyel5de33fe2020-03-03 22:38:44 -08001581 self._tp = dict()
1582
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001583 # Let TP download happen again
Girish Gowdrac5117452020-08-03 11:20:53 -07001584 for uni_id in self._tp_state_map_per_uni:
Girish Gowdra322cca12020-08-09 15:55:54 -07001585 for tp_id in self._tp_state_map_per_uni[uni_id]:
1586 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done = False
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001587
Matt Jeanneretf4113222019-08-14 19:44:34 -04001588 yield self.disable_ports(lock_ports=False)
Mahir Gunyel0e6882a2019-10-16 17:02:39 -07001589 yield self.core_proxy.device_reason_update(self.device_id, "stopping-openomci")
1590 yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.DISCOVERED,
1591 connect_status=ConnectStatus.UNREACHABLE)
Girish Gowdra322cca12020-08-09 15:55:54 -07001592 self.is_device_active_and_reachable = False
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001593 else:
1594 self.log.debug('not-changing-openomci-statemachine')
1595
Matt Jeanneretf4113222019-08-14 19:44:34 -04001596 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001597 def disable(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001598 self.log.info('disable', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001599 try:
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001600 yield self.disable_ports(lock_ports=True, device_disabled=True)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001601 yield self.core_proxy.device_reason_update(self.device_id, "omci-admin-lock")
1602 yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.UNKNOWN)
Girish Gowdra322cca12020-08-09 15:55:54 -07001603 self.is_device_active_and_reachable = False
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001604 except Exception as e:
Matteo Scandolod8d73172019-11-26 12:15:15 -07001605 self.log.exception('exception-in-onu-disable', exception=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001606
William Kurkian3a206332019-04-29 11:05:47 -04001607 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001608 def reenable(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001609 self.log.info('reenable', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001610 try:
Matt Jeanneretf4113222019-08-14 19:44:34 -04001611 yield self.core_proxy.device_state_update(device.id,
1612 oper_status=OperStatus.ACTIVE,
1613 connect_status=ConnectStatus.REACHABLE)
Girish Gowdra322cca12020-08-09 15:55:54 -07001614 self.is_device_active_and_reachable = True
Matt Jeanneretf4113222019-08-14 19:44:34 -04001615 yield self.core_proxy.device_reason_update(self.device_id, 'onu-reenabled')
1616 yield self.enable_ports()
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001617 except Exception as e:
Matteo Scandolod8d73172019-11-26 12:15:15 -07001618 self.log.exception('exception-in-onu-reenable', exception=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001619
William Kurkian3a206332019-04-29 11:05:47 -04001620 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001621 def reboot(self):
1622 self.log.info('reboot-device')
William Kurkian3a206332019-04-29 11:05:47 -04001623 device = yield self.core_proxy.get_device(self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001624 if device.connect_status != ConnectStatus.REACHABLE:
1625 self.log.error("device-unreachable")
1626 return
1627
William Kurkian3a206332019-04-29 11:05:47 -04001628 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001629 def success(_results):
1630 self.log.info('reboot-success', _results=_results)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001631 yield self.core_proxy.device_reason_update(self.device_id, 'rebooting')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001632
1633 def failure(_reason):
1634 self.log.info('reboot-failure', _reason=_reason)
1635
1636 self._deferred = self._onu_omci_device.reboot()
1637 self._deferred.addCallbacks(success, failure)
1638
William Kurkian3a206332019-04-29 11:05:47 -04001639 @inlineCallbacks
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001640 def disable_ports(self, lock_ports=True, device_disabled=False):
Mahir Gunyel0e6882a2019-10-16 17:02:39 -07001641 self.log.info('disable-ports', device_id=self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001642
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001643 # TODO: for now only support the first UNI given no requirement for multiple uni yet. Also needed to reduce flow
1644 # load on the core
Matt Jeanneretf4113222019-08-14 19:44:34 -04001645 for port in self.uni_ports:
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001646 if port.mac_bridge_port_num == 1:
1647 port.operstatus = OperStatus.UNKNOWN
1648 self.log.info('disable-port', device_id=self.device_id, port=port)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001649 yield self.core_proxy.port_state_update(self.device_id, Port.ETHERNET_UNI, port.port_number,
1650 port.operstatus)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001651
1652 if lock_ports is True:
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001653 self.lock_ports(lock=True, device_disabled=device_disabled)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001654
William Kurkian3a206332019-04-29 11:05:47 -04001655 @inlineCallbacks
Mahir Gunyel0e6882a2019-10-16 17:02:39 -07001656 def enable_ports(self):
1657 self.log.info('enable-ports', device_id=self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001658
Matt Jeanneretf4113222019-08-14 19:44:34 -04001659 self.lock_ports(lock=False)
1660
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001661 # TODO: for now only support the first UNI given no requirement for multiple uni yet. Also needed to reduce flow
1662 # load on the core
1663 # Given by default all unis are initially active according to omci alarming, we must mimic this.
Matt Jeanneretf4113222019-08-14 19:44:34 -04001664 for port in self.uni_ports:
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001665 if port.mac_bridge_port_num == 1:
Matt Jeanneretf4113222019-08-14 19:44:34 -04001666 port.operstatus = OperStatus.ACTIVE
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001667 self.log.info('enable-port', device_id=self.device_id, port=port)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001668 yield self.core_proxy.port_state_update(self.device_id, Port.ETHERNET_UNI, port.port_number,
1669 port.operstatus)
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001670
1671 # TODO: Normally we would want any uni ethernet link down or uni ethernet link up alarms to register in the core,
1672 # but practically olt provisioning cannot handle the churn of links up, down, then up again typical on startup.
1673 #
1674 # Basically the link state sequence:
1675 # 1) per omci default alarm state, all unis are initially up (no link down alarms received yet)
1676 # 2) a link state down alarm is received for all uni, given the lock command, and also because most unis have nothing plugged in
1677 # 3) a link state up alarm is received for the uni plugged in.
1678 #
1679 # Given the olt (BAL) has to provision all uni, de-provision all uni, and re-provision one uni in quick succession
1680 # and cannot (bug?), we have to skip this and leave uni ports as assumed active. Also all the link state activity
1681 # would have a ripple effect through the core to the controller as well. And is it really worth it?
1682 '''
Matt Jeanneretf4113222019-08-14 19:44:34 -04001683 @inlineCallbacks
1684 def port_state_handler(self, _topic, msg):
1685 self.log.info("port-state-change", _topic=_topic, msg=msg)
1686
1687 onu_id = msg['onu_id']
1688 port_no = msg['port_number']
1689 serial_number = msg['serial_number']
1690 port_status = msg['port_status']
1691 uni_port = self.uni_port(int(port_no))
1692
1693 self.log.debug("port-state-parsed-message", onu_id=onu_id, port_no=port_no, serial_number=serial_number,
1694 port_status=port_status)
1695
1696 if port_status is True:
1697 uni_port.operstatus = OperStatus.ACTIVE
1698 self.log.info('link-up', device_id=self.device_id, port=uni_port)
1699 else:
1700 uni_port.operstatus = OperStatus.UNKNOWN
1701 self.log.info('link-down', device_id=self.device_id, port=uni_port)
1702
1703 yield self.core_proxy.port_state_update(self.device_id, Port.ETHERNET_UNI, uni_port.port_number, uni_port.operstatus)
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001704 '''
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001705
1706 # Called just before openomci state machine is started. These listen for events from selected state machines,
1707 # most importantly, mib in sync. Which ultimately leads to downloading the mib
1708 def _subscribe_to_events(self):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001709 self.log.debug('subscribe-to-events')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001710
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001711 bus = self._onu_omci_device.event_bus
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001712
1713 # OMCI MIB Database sync status
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001714 topic = OnuDeviceEntry.event_bus_topic(self.device_id,
1715 OnuDeviceEvents.MibDatabaseSyncEvent)
1716 self._in_sync_subscription = bus.subscribe(topic, self.in_sync_handler)
1717
1718 # OMCI Capabilities
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001719 topic = OnuDeviceEntry.event_bus_topic(self.device_id,
1720 OnuDeviceEvents.OmciCapabilitiesEvent)
1721 self._capabilities_subscription = bus.subscribe(topic, self.capabilties_handler)
1722
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001723 # TODO: these alarms seem to be unreliable depending on the environment
1724 # Listen for UNI link state alarms and set the oper_state based on that rather than assuming all UNI are up
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001725 # topic = OnuDeviceEntry.event_bus_topic(self.device_id,
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001726 # OnuDeviceEvents.PortEvent)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001727 # self._port_state_subscription = bus.subscribe(topic, self.port_state_handler)
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001728
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001729 # Called when the mib is in sync
1730 def in_sync_handler(self, _topic, msg):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001731 self.log.debug('in-sync-handler', _topic=_topic, msg=msg)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001732 if self._in_sync_subscription is not None:
1733 try:
1734 in_sync = msg[IN_SYNC_KEY]
1735
1736 if in_sync:
1737 # Only call this once
1738 bus = self._onu_omci_device.event_bus
1739 bus.unsubscribe(self._in_sync_subscription)
1740 self._in_sync_subscription = None
1741
1742 # Start up device_info load
1743 self.log.debug('running-mib-sync')
1744 reactor.callLater(0, self._mib_in_sync)
1745
1746 except Exception as e:
1747 self.log.exception('in-sync', e=e)
1748
1749 def capabilties_handler(self, _topic, _msg):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001750 self.log.debug('capabilities-handler', _topic=_topic, msg=_msg)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001751 if self._capabilities_subscription is not None:
1752 self.log.debug('capabilities-handler-done')
1753
1754 # Mib is in sync, we can now query what we learned and actually start pushing ME (download) to the ONU.
Matt Jeanneretc083f462019-03-11 15:02:01 -04001755 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001756 def _mib_in_sync(self):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001757 self.log.debug('mib-in-sync')
Matt Jeanneretc083f462019-03-11 15:02:01 -04001758 device = yield self.core_proxy.get_device(self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001759
Matt Jeanneret5e331892019-12-07 21:31:45 -05001760 # only notify core if this is a new device. otherwise do not have reconcile generating
1761 # a lot of needless message churn
1762 if not self._reconciling:
1763 yield self.core_proxy.device_reason_update(self.device_id, 'discovery-mibsync-complete')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001764
1765 if self._dev_info_loaded:
Matt Jeanneret5e331892019-12-07 21:31:45 -05001766 self.log.debug('device-info-already-loaded')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001767 else:
Matt Jeanneret5e331892019-12-07 21:31:45 -05001768 # new onu or adapter was restarted. fill up our local data
1769 yield self._load_device_data(device)
1770
1771 if self._check_mib_downloaded():
1772 self.log.debug('mib-already-downloaded')
1773 if not self._reconciling:
1774 yield self.core_proxy.device_state_update(device.id,
1775 oper_status=OperStatus.ACTIVE,
1776 connect_status=ConnectStatus.REACHABLE)
Girish Gowdra322cca12020-08-09 15:55:54 -07001777 self.is_device_active_and_reachable = True
Matt Jeanneret5e331892019-12-07 21:31:45 -05001778 yield self.enable_ports()
1779 else:
1780 self._download_mib(device)
1781
1782 if self._reconciling:
1783 yield self._restore_tech_profile()
1784 self._start_monitoring()
1785 self._reconciling = False
1786 self.log.debug('reconcile-finished')
1787
1788 def _download_mib(self, device):
1789 self.log.debug('downloading-initial-mib-configuration')
1790
1791 @inlineCallbacks
1792 def success(_results):
1793 self.log.debug('mib-download-success', _results=_results)
1794 yield self.core_proxy.device_state_update(device.id,
1795 oper_status=OperStatus.ACTIVE,
1796 connect_status=ConnectStatus.REACHABLE)
Girish Gowdra322cca12020-08-09 15:55:54 -07001797 self.is_device_active_and_reachable = True
Matt Jeanneret5e331892019-12-07 21:31:45 -05001798 yield self.core_proxy.device_reason_update(self.device_id, 'initial-mib-downloaded')
1799 self._mib_download_task = None
1800 yield self.enable_ports()
1801 yield self.onu_active_event()
1802 self._start_monitoring()
1803
1804 @inlineCallbacks
1805 def failure(_reason):
1806 self.log.warn('mib-download-failure-retrying', _reason=_reason)
1807 retry = _STARTUP_RETRY_WAIT * (random.randint(1, 5))
1808 reactor.callLater(retry, self._mib_in_sync)
1809 yield self.core_proxy.device_reason_update(self.device_id, 'initial-mib-download-failure-retrying')
1810
1811 # start by locking all the unis till mib sync and initial mib is downloaded
1812 # this way we can capture the port down/up events when we are ready
1813 self.lock_ports(lock=True)
1814
1815 # Download an initial mib that creates simple bridge that can pass EAP. On success (above) finally set
1816 # the device to active/reachable. This then opens up the handler to openflow pushes from outside
1817 self._mib_download_task = BrcmMibDownloadTask(self.omci_agent, self)
1818 self._deferred = self._onu_omci_device.task_runner.queue_task(self._mib_download_task)
1819 self._deferred.addCallbacks(success, failure)
1820
1821 def _start_monitoring(self):
1822 self.log.debug('starting-monitoring')
1823
1824 # Start collecting stats from the device after a brief pause
1825 if not self._pm_metrics_started:
1826 self._pm_metrics_started = True
Rohan Agrawal36a4e442020-06-29 11:10:32 +00001827 pmstart = _STARTUP_RETRY_WAIT * (random.randint(1, self._pm_metrics.max_skew))
Matt Jeanneret5e331892019-12-07 21:31:45 -05001828 reactor.callLater(pmstart, self._pm_metrics.start_collector)
1829
1830 # Start test requests after a brief pause
1831 if not self._test_request_started:
1832 self._test_request_started = True
1833 tststart = _STARTUP_RETRY_WAIT * (random.randint(1, 5))
1834 reactor.callLater(tststart, self._test_request.start_collector)
1835
1836 def _check_mib_downloaded(self):
1837 self.log.debug('checking-mib-downloaded')
1838 results = False
1839
1840 mac_bridges = self.onu_omci_device.query_mib(MacBridgeServiceProfile.class_id)
1841 self.log.debug('mac-bridges', mac_bridges=mac_bridges)
1842
1843 for k, v in mac_bridges.items():
1844 if not isinstance(v, dict):
1845 continue
1846 # found at least one mac bridge, good enough to say its done, break out
1847 self.log.debug('found-mac-bridge-mib-download-has-been-done', omci_key=k, omci_value=v)
1848 results = True
1849 break
1850
1851 return results
1852
1853 @inlineCallbacks
1854 def _load_device_data(self, device):
1855 self.log.debug('loading-device-data-from-mib', device_id=device.id)
1856
1857 omci_dev = self._onu_omci_device
1858 config = omci_dev.configuration
1859
1860 try:
1861 # sort the lists so we get consistent port ordering.
1862 ani_list = sorted(config.ani_g_entities) if config.ani_g_entities else []
1863 uni_list = sorted(config.uni_g_entities) if config.uni_g_entities else []
1864 pptp_list = sorted(config.pptp_entities) if config.pptp_entities else []
1865 veip_list = sorted(config.veip_entities) if config.veip_entities else []
1866
1867 if ani_list is None or (pptp_list is None and veip_list is None):
1868 yield self.core_proxy.device_reason_update(self.device_id, 'onu-missing-required-elements')
1869 raise Exception("onu-missing-required-elements")
1870
1871 # Currently logging the ani, pptp, veip, and uni for information purposes.
1872 # Actually act on the veip/pptp as its ME is the most correct one to use in later tasks.
1873 # And in some ONU the UNI-G list is incomplete or incorrect...
1874 for entity_id in ani_list:
1875 ani_value = config.ani_g_entities[entity_id]
1876 self.log.debug("discovered-ani", entity_id=entity_id, value=ani_value)
1877
1878 for entity_id in uni_list:
1879 uni_value = config.uni_g_entities[entity_id]
1880 self.log.debug("discovered-uni", entity_id=entity_id, value=uni_value)
1881
1882 uni_entities = OrderedDict()
1883 for entity_id in pptp_list:
1884 pptp_value = config.pptp_entities[entity_id]
1885 self.log.debug("discovered-pptp", entity_id=entity_id, value=pptp_value)
1886 uni_entities[entity_id] = UniType.PPTP
1887
1888 for entity_id in veip_list:
1889 veip_value = config.veip_entities[entity_id]
1890 self.log.debug("discovered-veip", entity_id=entity_id, value=veip_value)
1891 uni_entities[entity_id] = UniType.VEIP
1892
1893 uni_id = 0
1894 for entity_id, uni_type in uni_entities.items():
1895 yield self._add_uni_port(device, entity_id, uni_id, uni_type)
Girish Gowdrac5117452020-08-03 11:20:53 -07001896 self._tp_state_map_per_uni[uni_id] = dict()
Matt Jeanneret5e331892019-12-07 21:31:45 -05001897 uni_id += 1
1898
1899 if self._unis:
1900 self._dev_info_loaded = True
1901 else:
1902 yield self.core_proxy.device_reason_update(self.device_id, 'no-usable-unis')
1903 raise Exception("no-usable-unis")
1904
1905 except Exception as e:
1906 self.log.exception('device-info-load', e=e)
1907 self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT, self._mib_in_sync)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001908
Matt Jeanneretc083f462019-03-11 15:02:01 -04001909 @inlineCallbacks
1910 def _add_uni_port(self, device, entity_id, uni_id, uni_type=UniType.PPTP):
Matt Jeanneret5e331892019-12-07 21:31:45 -05001911 self.log.debug('add-uni-port', entity_id=entity_id, uni_id=uni_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001912
Matt Jeanneret5e331892019-12-07 21:31:45 -05001913 intf_id = self._onu_persisted_state.get('intf_id')
1914 onu_id = self._onu_persisted_state.get('onu_id')
1915 uni_no = self.mk_uni_port_num(intf_id, onu_id, uni_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001916
1917 # TODO: Some or parts of this likely need to move to UniPort. especially the format stuff
1918 uni_name = "uni-{}".format(uni_no)
1919
Girish Gowdrae933cd32019-11-21 21:04:41 +05301920 mac_bridge_port_num = uni_id + 1 # TODO +1 is only to test non-zero index
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001921
1922 self.log.debug('uni-port-inputs', uni_no=uni_no, uni_id=uni_id, uni_name=uni_name, uni_type=uni_type,
Yongjie Zhang286099c2019-08-06 13:39:07 -04001923 entity_id=entity_id, mac_bridge_port_num=mac_bridge_port_num, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001924
Girish Gowdra5b499342020-06-16 14:45:51 -07001925 uni_port = UniPort.create(self, uni_name, uni_id, uni_no, uni_name,
1926 device.parent_port_no, device.serial_number,
1927 uni_type,)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001928 uni_port.entity_id = entity_id
1929 uni_port.enabled = True
1930 uni_port.mac_bridge_port_num = mac_bridge_port_num
1931
1932 self.log.debug("created-uni-port", uni=uni_port)
1933
Matt Jeanneret5e331892019-12-07 21:31:45 -05001934 if not self._reconciling:
1935 yield self.core_proxy.port_created(device.id, uni_port.get_port())
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001936
1937 self._unis[uni_port.port_number] = uni_port
1938
Matt Jeanneret5e331892019-12-07 21:31:45 -05001939 self._onu_omci_device.alarm_synchronizer.set_alarm_params(onu_id=onu_id,
Girish Gowdrae933cd32019-11-21 21:04:41 +05301940 uni_ports=self.uni_ports,
1941 serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001942
Matt Jeanneret5e331892019-12-07 21:31:45 -05001943 @inlineCallbacks
1944 def _restore_tech_profile(self):
1945 self.log.debug("reconcile-restoring-tech-profile-tcont-gem-config")
1946
1947 # for every uni that has tech profile config reload all its tcont/alloc_id and gem from the tp path
1948 for entry in self._onu_persisted_state.get('uni_config', list()):
1949 uni_id = entry.get('uni_id')
1950 tp_path = entry.get('tp_path')
1951 if tp_path:
1952 tpstored = yield self.tp_kv_client.get(tp_path)
1953 tpstring = tpstored.decode('ascii')
1954 tp = json.loads(tpstring)
1955
1956 self.log.debug("restoring-tp-instance", tp=tp)
1957
1958 # re-run tech profile config that stores gem and tconts in the self._pon object
1959 # this does not actually re-run the omci, just rebuilds our local data store
1960 self._do_tech_profile_configuration(uni_id, tp)
1961
1962 tp_id = self.extract_tp_id_from_path(tp_path)
1963
1964 # rebuild cache dicts so tp updates and deletes dont get KeyErrors
Girish Gowdrac5117452020-08-03 11:20:53 -07001965 if uni_id not in self._tp_state_map_per_uni:
1966 self._tp_state_map_per_uni[uni_id] = dict()
Matt Jeanneret5e331892019-12-07 21:31:45 -05001967
Girish Gowdrac5117452020-08-03 11:20:53 -07001968 if tp_id not in self._tp_state_map_per_uni[uni_id]:
1969 self._tp_state_map_per_uni[uni_id][tp_id] = TpState(self, uni_id, tp_path)
Matt Jeanneret5e331892019-12-07 21:31:45 -05001970
Girish Gowdrac5117452020-08-03 11:20:53 -07001971 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done = True
Matt Jeanneret5e331892019-12-07 21:31:45 -05001972 else:
1973 self.log.debug("no-assigned-tp-instance", uni_id=uni_id)
1974
1975 # for every loaded tcont from tp check the mib database for its entity_id
1976 # needed for later tp deletes/adds
1977 tcont_idents = self.onu_omci_device.query_mib(Tcont.class_id)
1978 self.log.debug('tcont-idents', tcont_idents=tcont_idents)
1979
1980 for k, v in tcont_idents.items():
1981 if not isinstance(v, dict):
1982 continue
1983 alloc_check = v.get('attributes', {}).get('alloc_id', 0)
1984 tcont = self._pon.tconts.get(alloc_check)
1985 if tcont:
1986 tcont.entity_id = k
1987 self.log.debug('reassigning-tcont-entity-id', entity_id=tcont.entity_id,
1988 alloc_id=tcont.alloc_id)
1989
Matt Jeanneretc083f462019-03-11 15:02:01 -04001990 # TODO NEW CORE: Figure out how to gain this knowledge from the olt. for now cheat terribly.
1991 def mk_uni_port_num(self, intf_id, onu_id, uni_id):
Amit Ghosh65400f12019-11-21 12:04:12 +00001992 MAX_PONS_PER_OLT = 256
1993 MAX_ONUS_PER_PON = 256
Matt Jeanneretc083f462019-03-11 15:02:01 -04001994 MAX_UNIS_PER_ONU = 16
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001995
Matt Jeanneretc083f462019-03-11 15:02:01 -04001996 assert intf_id < MAX_PONS_PER_OLT
1997 assert onu_id < MAX_ONUS_PER_PON
1998 assert uni_id < MAX_UNIS_PER_ONU
Amit Ghosh65400f12019-11-21 12:04:12 +00001999 return intf_id << 12 | onu_id << 4 | uni_id
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04002000
2001 @inlineCallbacks
Devmalya Paulffc89df2019-07-31 17:43:13 -04002002 def onu_active_event(self):
Matteo Scandolod8d73172019-11-26 12:15:15 -07002003 self.log.debug('onu-active-event')
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04002004 try:
Matt Jeanneret5e331892019-12-07 21:31:45 -05002005 # TODO: this is expensive for just getting the olt serial number. replace with direct api call
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04002006 parent_device = yield self.core_proxy.get_device(self.parent_id)
2007 olt_serial_number = parent_device.serial_number
Devmalya Paulffc89df2019-07-31 17:43:13 -04002008 raised_ts = arrow.utcnow().timestamp
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04002009
Matt Jeanneret5e331892019-12-07 21:31:45 -05002010 intf_id = self._onu_persisted_state.get('intf_id')
2011 onu_id = self._onu_persisted_state.get('onu_id')
2012 onu_serial = self._onu_persisted_state.get('serial_number')
2013
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04002014 self.log.debug("onu-indication-context-data",
Matt Jeanneret5e331892019-12-07 21:31:45 -05002015 pon_id=intf_id,
2016 onu_id=onu_id,
Girish Gowdrae933cd32019-11-21 21:04:41 +05302017 registration_id=self.device_id,
2018 device_id=self.device_id,
Matt Jeanneret5e331892019-12-07 21:31:45 -05002019 onu_serial_number=onu_serial,
Girish Gowdrae933cd32019-11-21 21:04:41 +05302020 olt_serial_number=olt_serial_number,
2021 raised_ts=raised_ts)
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04002022
Devmalya Paulffc89df2019-07-31 17:43:13 -04002023 self.log.debug("Trying-to-raise-onu-active-event")
2024 OnuActiveEvent(self.events, self.device_id,
Matt Jeanneret5e331892019-12-07 21:31:45 -05002025 intf_id,
2026 onu_serial,
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04002027 str(self.device_id),
Girish Gowdrae933cd32019-11-21 21:04:41 +05302028 olt_serial_number, raised_ts,
Matt Jeanneret5e331892019-12-07 21:31:45 -05002029 onu_id=onu_id).send(True)
Devmalya Paulffc89df2019-07-31 17:43:13 -04002030 except Exception as active_event_error:
2031 self.log.exception('onu-activated-event-error',
Devmalya Paul1e1b1722020-05-07 02:51:15 -04002032 errmsg=active_event_error)
Matt Jeanneretf4113222019-08-14 19:44:34 -04002033
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002034 @inlineCallbacks
2035 def onu_disabled_event(self):
2036 self.log.debug('onu-disabled-event')
2037 try:
2038 device = yield self.core_proxy.get_device(self.device_id)
2039 parent_device = yield self.core_proxy.get_device(self.parent_id)
2040 olt_serial_number = parent_device.serial_number
2041 raised_ts = arrow.utcnow().timestamp
Devmalya Paul1e1b1722020-05-07 02:51:15 -04002042 intf_id = self._onu_persisted_state.get('intf_id')
2043 onu_id = self._onu_persisted_state.get('onu_id')
2044 onu_serial = self._onu_persisted_state.get('serial_number')
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002045
2046 self.log.debug("onu-indication-context-data",
Devmalya Paul1e1b1722020-05-07 02:51:15 -04002047 pon_id=intf_id,
2048 onu_id=onu_id,
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002049 registration_id=self.device_id,
2050 device_id=self.device_id,
Devmalya Paul1e1b1722020-05-07 02:51:15 -04002051 onu_serial_number=onu_serial,
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002052 olt_serial_number=olt_serial_number,
2053 raised_ts=raised_ts)
2054
2055 self.log.debug("Trying-to-raise-onu-disabled-event")
2056 OnuDisabledEvent(self.events, self.device_id,
Devmalya Paul1e1b1722020-05-07 02:51:15 -04002057 intf_id,
Girish Gowdradc98d812020-03-20 13:04:58 -07002058 device.serial_number,
2059 str(self.device_id),
2060 olt_serial_number, raised_ts,
Devmalya Paul1e1b1722020-05-07 02:51:15 -04002061 onu_id=onu_id).send(True)
2062 except Exception as disable_event_error:
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002063 self.log.exception('onu-disabled-event-error',
Devmalya Paul1e1b1722020-05-07 02:51:15 -04002064 errmsg=disable_event_error)
2065
2066 @inlineCallbacks
2067 def onu_deleted_event(self):
2068 self.log.debug('onu-deleted-event')
2069 try:
2070 device = yield self.core_proxy.get_device(self.device_id)
2071 parent_device = yield self.core_proxy.get_device(self.parent_id)
2072 olt_serial_number = parent_device.serial_number
2073 raised_ts = arrow.utcnow().timestamp
2074 intf_id = self._onu_persisted_state.get('intf_id')
2075 onu_id = self._onu_persisted_state.get('onu_id')
2076 serial_number = self._onu_persisted_state.get('serial_number')
2077
2078 self.log.debug("onu-deleted-event-context-data",
2079 pon_id=intf_id,
2080 onu_id=onu_id,
2081 registration_id=self.device_id,
2082 device_id=self.device_id,
2083 onu_serial_number=serial_number,
2084 olt_serial_number=olt_serial_number,
2085 raised_ts=raised_ts)
2086
2087 OnuDeletedEvent(self.events, self.device_id,
2088 intf_id,
2089 serial_number,
2090 str(self.device_id),
2091 olt_serial_number, raised_ts,
2092 onu_id=onu_id).send(True)
2093 except Exception as deleted_event_error:
2094 self.log.exception('onu-deleted-event-error',
2095 errmsg=deleted_event_error)
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002096
2097 def lock_ports(self, lock=True, device_disabled=False):
Matt Jeanneretf4113222019-08-14 19:44:34 -04002098
2099 def success(response):
2100 self.log.debug('set-onu-ports-state', lock=lock, response=response)
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002101 if device_disabled:
2102 self.onu_disabled_event()
Matt Jeanneretf4113222019-08-14 19:44:34 -04002103
2104 def failure(response):
2105 self.log.error('cannot-set-onu-ports-state', lock=lock, response=response)
2106
2107 task = BrcmUniLockTask(self.omci_agent, self.device_id, lock=lock)
2108 self._deferred = self._onu_omci_device.task_runner.queue_task(task)
2109 self._deferred.addCallbacks(success, failure)
Mahir Gunyele9110a32020-02-20 14:56:50 -08002110
2111 def extract_tp_id_from_path(self, tp_path):
2112 # tp_path is of the format <technology>/<table_id>/<uni_port_name>
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08002113 tp_id = int(tp_path.split(_PATH_SEPERATOR)[1])
2114 return tp_id
onkarkundargia1e2af22020-01-27 11:51:43 +05302115
2116 def start_omci_test_action(self, device, uuid):
2117 """
2118
2119 :param device:
2120 :return:
2121 """
2122 # Code to Run OMCI Test Action
2123 self.log.info('Omci-test-action-request-On', request=device.id)
2124 kwargs_omci_test_action = {
2125 OmciTestRequest.DEFAULT_FREQUENCY_KEY:
2126 OmciTestRequest.DEFAULT_COLLECTION_FREQUENCY
2127 }
2128 serial_number = device.serial_number
2129 if device.connect_status != ConnectStatus.REACHABLE or device.admin_state != AdminState.ENABLED:
2130 return (TestResponse(result=TestResponse.FAILURE))
2131 test_request = OmciTestRequest(self.core_proxy,
2132 self.omci_agent, self.device_id, AniG,
2133 serial_number,
2134 self.logical_device_id, exclusive=False,
2135 uuid=uuid,
2136 **kwargs_omci_test_action)
2137 test_request.perform_test_omci()
2138 return (TestResponse(result=TestResponse.SUCCESS))