blob: 40ecbb5825ebf1f3749f68868a4c044c1ddc9a7d [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
Devmalya Paulffc89df2019-07-31 17:43:13 -040091 self.events = None
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -050092 self._pm_metrics = None
93 self._pm_metrics_started = False
94 self._test_request = None
95 self._test_request_started = False
Girish Gowdradc98d812020-03-20 13:04:58 -070096 self._tp = dict() # tp_id -> technology profile definition in KV Store.
Matt Jeanneret5e331892019-12-07 21:31:45 -050097 self._reconciling = False
98
99 # Persisted onu configuration needed in case of reconciliation.
100 self._onu_persisted_state = {
101 'onu_id': None,
102 'intf_id': None,
103 'serial_number': None,
104 'admin_state': None,
105 'oper_state': None,
106 'uni_config': list()
107 }
108
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500109 self._unis = dict() # Port # -> UniPort
110
111 self._pon = None
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500112 self._pon_port_number = 100
113 self.logical_device_id = None
114
115 self._heartbeat = HeartBeat.create(self, device_id)
116
117 # Set up OpenOMCI environment
118 self._onu_omci_device = None
119 self._dev_info_loaded = False
120 self._deferred = None
121
122 self._in_sync_subscription = None
Matt Jeanneretf4113222019-08-14 19:44:34 -0400123 self._port_state_subscription = None
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500124 self._connectivity_subscription = None
125 self._capabilities_subscription = None
126
127 self.mac_bridge_service_profile_entity_id = 0x201
128 self.gal_enet_profile_entity_id = 0x1
129
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400130 # Stores information related to queued vlan filter tasks
131 # 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 -0400132 self._queued_vlan_filter_task = dict()
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500133
Girish Gowdradc98d812020-03-20 13:04:58 -0700134 self._set_vlan = dict() # uni_id, tp_id -> set_vlan_id
Girish Gowdrac5117452020-08-03 11:20:53 -0700135 self._tp_state_map_per_uni = dict() # uni_id -> {dictionary tp_id->TpState}
Matt Jeanneret5e331892019-12-07 21:31:45 -0500136
137 # Paths from kv store
138 ONU_PATH = 'service/voltha/openonu'
139
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500140 # Initialize KV store client
141 self.args = registry('main').get_args()
Matt Jeanneret5e331892019-12-07 21:31:45 -0500142 host, port = self.args.etcd.split(':', 1)
143 self.tp_kv_client = TwistedEtcdStore(host, port, TechProfile.KV_STORE_TECH_PROFILE_PATH_PREFIX)
144 self.onu_kv_client = TwistedEtcdStore(host, port, ONU_PATH)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500145
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500146 @property
147 def enabled(self):
148 return self._enabled
149
150 @enabled.setter
151 def enabled(self, value):
152 if self._enabled != value:
153 self._enabled = value
154
155 @property
156 def omci_agent(self):
157 return self.adapter.omci_agent
158
159 @property
160 def omci_cc(self):
161 return self._onu_omci_device.omci_cc if self._onu_omci_device is not None else None
162
163 @property
164 def heartbeat(self):
165 return self._heartbeat
166
167 @property
168 def uni_ports(self):
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -0500169 return list(self._unis.values())
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500170
171 def uni_port(self, port_no_or_name):
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -0500172 if isinstance(port_no_or_name, six.string_types):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500173 return next((uni for uni in self.uni_ports
174 if uni.name == port_no_or_name), None)
175
176 assert isinstance(port_no_or_name, int), 'Invalid parameter type'
177 return next((uni for uni in self.uni_ports
Girish Gowdrae933cd32019-11-21 21:04:41 +0530178 if uni.port_number == port_no_or_name), None)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500179
180 @property
181 def pon_port(self):
182 return self._pon
183
Girish Gowdraa73ee452019-12-20 18:52:17 +0530184 @property
185 def onu_omci_device(self):
186 return self._onu_omci_device
187
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500188 def receive_message(self, msg):
189 if self.omci_cc is not None:
190 self.omci_cc.receive_message(msg)
191
192 # Called once when the adapter creates the device/onu instance
Matt Jeanneret84e56f62019-02-26 10:48:09 -0500193 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500194 def activate(self, device):
Matteo Scandolod8d73172019-11-26 12:15:15 -0700195 self.log.debug('activate-device', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500196
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500197 assert device.parent_id
Matt Jeanneret0c287892019-02-28 11:48:00 -0500198 assert device.parent_port_no
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500199 assert device.proxy_address.device_id
200
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500201 self.proxy_address = device.proxy_address
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500202 self.parent_id = device.parent_id
Matt Jeanneret0c287892019-02-28 11:48:00 -0500203 self._pon_port_number = device.parent_port_no
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500204 if self.enabled is not True:
Matteo Scandolod8d73172019-11-26 12:15:15 -0700205 self.log.info('activating-new-onu', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500206 # populate what we know. rest comes later after mib sync
Matt Jeanneret0c287892019-02-28 11:48:00 -0500207 device.root = False
Matt Jeannereta32441c2019-03-07 05:16:37 -0500208 device.vendor = 'OpenONU'
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500209 device.reason = 'activating-onu'
210
Matt Jeanneret84e56f62019-02-26 10:48:09 -0500211 # TODO NEW CORE: Need to either get logical device id from core or use regular device id
Matt Jeanneret3b7db442019-04-22 16:29:48 -0400212 # pm_metrics requires a logical device id. For now set to just device_id
213 self.logical_device_id = self.device_id
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500214
Matt Jeanneret5e331892019-12-07 21:31:45 -0500215 self._onu_persisted_state['serial_number'] = device.serial_number
216 try:
217 self.log.debug('updating-onu-state', device_id=self.device_id,
218 onu_persisted_state=self._onu_persisted_state)
219 yield self.onu_kv_client.set(self.device_id, json.dumps(self._onu_persisted_state))
220 except Exception as e:
221 self.log.error('could-not-store-onu-state', device_id=self.device_id,
222 onu_persisted_state=self._onu_persisted_state, e=e)
223 # if we cannot write to storage we can proceed, for now.
224 # later onu indications from the olt will have another chance
225
Matt Jeannereta32441c2019-03-07 05:16:37 -0500226 yield self.core_proxy.device_update(device)
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500227 self.log.debug('device-updated', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500228
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700229 yield self._init_pon_state()
Matteo Scandolod8d73172019-11-26 12:15:15 -0700230 self.log.debug('pon state initialized', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500231
Matt Jeanneret5e331892019-12-07 21:31:45 -0500232 yield self._init_metrics()
233 self.log.debug('metrics initialized', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -0500234
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500235 self.enabled = True
236 else:
237 self.log.info('onu-already-activated')
238
239 # Called once when the adapter needs to re-create device. usually on vcore restart
William Kurkian3a206332019-04-29 11:05:47 -0400240 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500241 def reconcile(self, device):
Matteo Scandolod8d73172019-11-26 12:15:15 -0700242 self.log.debug('reconcile-device', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500243
Matt Jeanneret5e331892019-12-07 21:31:45 -0500244 if self._reconciling:
245 self.log.debug('already-running-reconcile-device', device_id=device.id, serial_number=device.serial_number)
246 return
247
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500248 # first we verify that we got parent reference and proxy info
249 assert device.parent_id
250 assert device.proxy_address.device_id
251
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700252 self.proxy_address = device.proxy_address
253 self.parent_id = device.parent_id
254 self._pon_port_number = device.parent_port_no
255
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500256 if self.enabled is not True:
Matt Jeanneret5e331892019-12-07 21:31:45 -0500257 self._reconciling = True
258 self.log.info('reconciling-openonu-device')
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700259 self.logical_device_id = self.device_id
Matt Jeanneret5e331892019-12-07 21:31:45 -0500260
261 try:
262 query_data = yield self.onu_kv_client.get(device.id)
263 self._onu_persisted_state = json.loads(query_data)
264 self.log.debug('restored-onu-state', device_id=self.device_id,
265 onu_persisted_state=self._onu_persisted_state)
266 except Exception as e:
267 self.log.error('no-stored-onu-state', device_id=device.id, e=e)
268 # there is nothing we can do without data. flag the device as UNKNOWN and cannot reconcile
269 # likely it will take manual steps to delete/re-add this onu
270 yield self.core_proxy.device_reason_update(self.device_id, "cannot-reconcile")
271 yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.UNKNOWN)
272 return
273
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700274 self._init_pon_state()
Matt Jeanneret5e331892019-12-07 21:31:45 -0500275 self.log.debug('pon state initialized', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500276
Matt Jeanneret5e331892019-12-07 21:31:45 -0500277 self._init_metrics()
278 self.log.debug('metrics initialized', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500279
Matt Jeanneret5e331892019-12-07 21:31:45 -0500280 self._subscribe_to_events()
281 # need to restart omci start machines and reload mib database. once db is loaded we can finish reconcile
282 self._onu_omci_device.start(device)
283 self._heartbeat.enabled = True
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500284
285 self.enabled = True
286 else:
287 self.log.info('onu-already-activated')
288
289 @inlineCallbacks
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700290 def _init_pon_state(self):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500291 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 -0500292
293 self._pon = PonPort.create(self, self._pon_port_number)
Matt Jeanneret0c287892019-02-28 11:48:00 -0500294 self._pon.add_peer(self.parent_id, self._pon_port_number)
Matteo Scandolod8d73172019-11-26 12:15:15 -0700295 self.log.debug('adding-pon-port-to-agent',
296 type=self._pon.get_port().type,
297 admin_state=self._pon.get_port().admin_state,
298 oper_status=self._pon.get_port().oper_status,
299 )
Matt Jeanneret0c287892019-02-28 11:48:00 -0500300
Matt Jeanneret5e331892019-12-07 21:31:45 -0500301 if not self._reconciling:
302 yield self.core_proxy.port_created(self.device_id, self._pon.get_port())
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500303
Matteo Scandolod8d73172019-11-26 12:15:15 -0700304 self.log.debug('added-pon-port-to-agent',
305 type=self._pon.get_port().type,
306 admin_state=self._pon.get_port().admin_state,
307 oper_status=self._pon.get_port().oper_status,
308 )
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500309
310 # Create and start the OpenOMCI ONU Device Entry for this ONU
311 self._onu_omci_device = self.omci_agent.add_device(self.device_id,
Matt Jeannereta32441c2019-03-07 05:16:37 -0500312 self.core_proxy,
313 self.adapter_proxy,
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500314 support_classes=self.adapter.broadcom_omci,
315 custom_me_map=self.adapter.custom_me_entities())
316 # Port startup
317 if self._pon is not None:
318 self._pon.enabled = True
319
Matt Jeanneret5e331892019-12-07 21:31:45 -0500320 @inlineCallbacks
321 def _init_metrics(self):
322 self.log.debug('init-metrics', device_id=self.device_id, device_logical_id=self.logical_device_id)
323
324 serial_number = self._onu_persisted_state.get('serial_number')
325
326 ############################################################################
327 # Setup Alarm handler
328 self.events = AdapterEvents(self.core_proxy, self.device_id, self.logical_device_id,
329 serial_number)
330 ############################################################################
331 # Setup PM configuration for this device
332 # Pass in ONU specific options
333 kwargs = {
334 OnuPmMetrics.DEFAULT_FREQUENCY_KEY: OnuPmMetrics.DEFAULT_ONU_COLLECTION_FREQUENCY,
335 'heartbeat': self.heartbeat,
336 OnuOmciPmMetrics.OMCI_DEV_KEY: self._onu_omci_device
337 }
338 self.log.debug('create-pm-metrics', device_id=self.device_id, serial_number=serial_number)
339 self._pm_metrics = OnuPmMetrics(self.events, self.core_proxy, self.device_id,
340 self.logical_device_id, serial_number,
341 grouped=True, freq_override=False, **kwargs)
342 pm_config = self._pm_metrics.make_proto()
343 self._onu_omci_device.set_pm_config(self._pm_metrics.omci_pm.openomci_interval_pm)
344 self.log.debug("initial-pm-config", device_id=self.device_id, serial_number=serial_number)
345
346 if not self._reconciling:
347 yield self.core_proxy.device_pm_config_update(pm_config, init=True)
348
349 # Note, ONU ID and UNI intf set in add_uni_port method
350 self._onu_omci_device.alarm_synchronizer.set_alarm_params(mgr=self.events,
351 ani_ports=[self._pon])
352
353 # Code to Run OMCI Test Action
354 kwargs_omci_test_action = {
355 OmciTestRequest.DEFAULT_FREQUENCY_KEY:
356 OmciTestRequest.DEFAULT_COLLECTION_FREQUENCY
357 }
358 self._test_request = OmciTestRequest(self.core_proxy,
359 self.omci_agent, self.device_id,
360 AniG, serial_number,
361 self.logical_device_id,
362 exclusive=False,
363 **kwargs_omci_test_action)
364
365 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500366 def delete(self, device):
Matteo Scandolod8d73172019-11-26 12:15:15 -0700367 self.log.info('delete-onu', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneret5e331892019-12-07 21:31:45 -0500368 try:
369 yield self.onu_kv_client.delete(device.id)
370 except Exception as e:
371 self.log.error('could-not-delete-onu-state', device_id=device.id, e=e)
372
Devmalya Paul1e1b1722020-05-07 02:51:15 -0400373 try:
374 self._deferred.cancel()
375 self._test_request.stop_collector()
376 self._pm_metrics.stop_collector()
377 self.log.debug('removing-openomci-statemachine')
378 self.omci_agent.remove_device(device.id, cleanup=True)
379 yield self.onu_deleted_event()
380 except Exception as e:
381 self.log.error('could-not-delete-onu', device_id=device.id, e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500382
383 def _create_tconts(self, uni_id, us_scheduler):
384 alloc_id = us_scheduler['alloc_id']
385 q_sched_policy = us_scheduler['q_sched_policy']
386 self.log.debug('create-tcont', us_scheduler=us_scheduler)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800387 # TODO: revisit for multi tconts support
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800388 new_tconts = []
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500389 tcontdict = dict()
390 tcontdict['alloc-id'] = alloc_id
391 tcontdict['q_sched_policy'] = q_sched_policy
392 tcontdict['uni_id'] = uni_id
393
Matt Jeanneret3789d0d2020-01-19 09:03:42 -0500394 tcont = OnuTCont.create(self, tcont=tcontdict)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500395
Girish Gowdra7c1240c2020-07-15 15:06:42 -0700396 success = self._pon.add_tcont(tcont, True)
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500397 if success:
398 new_tconts.append(tcont)
399 self.log.debug('pon-add-tcont', tcont=tcont)
400
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800401 return new_tconts
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500402
403 # Called when there is an olt up indication, providing the gem port id chosen by the olt handler
404 def _create_gemports(self, uni_id, gem_ports, alloc_id_ref, direction):
405 self.log.debug('create-gemport',
406 gem_ports=gem_ports, direction=direction)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530407 new_gem_ports = []
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500408 for gem_port in gem_ports:
409 gemdict = dict()
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800410 if gem_port[IS_MULTICAST] == 'True':
411 gemdict[GEM_PORT_ID] = gem_port['multicast_gem_id']
412 gemdict[IS_MULTICAST] = True
413 else:
414 gemdict[GEM_PORT_ID] = gem_port[GEM_PORT_ID]
415 gemdict[IS_MULTICAST] = False
416
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500417 gemdict['direction'] = direction
418 gemdict['alloc_id_ref'] = alloc_id_ref
419 gemdict['encryption'] = gem_port['aes_encryption']
420 gemdict['discard_config'] = dict()
421 gemdict['discard_config']['max_probability'] = \
422 gem_port['discard_config']['max_probability']
423 gemdict['discard_config']['max_threshold'] = \
424 gem_port['discard_config']['max_threshold']
425 gemdict['discard_config']['min_threshold'] = \
426 gem_port['discard_config']['min_threshold']
427 gemdict['discard_policy'] = gem_port['discard_policy']
428 gemdict['max_q_size'] = gem_port['max_q_size']
429 gemdict['pbit_map'] = gem_port['pbit_map']
430 gemdict['priority_q'] = gem_port['priority_q']
431 gemdict['scheduling_policy'] = gem_port['scheduling_policy']
432 gemdict['weight'] = gem_port['weight']
433 gemdict['uni_id'] = uni_id
434
435 gem_port = OnuGemPort.create(self, gem_port=gemdict)
436
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500437 success = self._pon.add_gem_port(gem_port, True)
438 if success:
439 new_gem_ports.append(gem_port)
440 self.log.debug('pon-add-gemport', gem_port=gem_port)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500441
Girish Gowdrae933cd32019-11-21 21:04:41 +0530442 return new_gem_ports
443
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800444 def _execute_queued_vlan_filter_tasks(self, uni_id, tp_id):
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400445 # During OLT Reboots, ONU Reboots, ONU Disable/Enable, it is seen that vlan_filter
446 # task is scheduled even before tp task. So we queue vlan-filter task if tp_task
447 # or initial-mib-download is not done. Once the tp_task is completed, we execute
448 # such queued vlan-filter tasks
449 try:
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800450 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 -0400451 self.log.info("executing-queued-vlan-filter-task",
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800452 uni_id=uni_id, tp_id=tp_id)
Mahir Gunyela982ec32020-02-25 12:30:37 -0800453 for filter_info in self._queued_vlan_filter_task[uni_id][tp_id]:
454 reactor.callLater(0, self._add_vlan_filter_task, filter_info.get("device"),
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800455 uni_id=uni_id, uni_port=filter_info.get("uni_port"),
456 match_vlan=filter_info.get("match_vlan"),
457 _set_vlan_vid=filter_info.get("set_vlan_vid"),
458 _set_vlan_pcp=filter_info.get("set_vlan_pcp"),
459 tp_id=filter_info.get("tp_id"))
Girish Gowdraaf98a082020-03-05 16:40:51 -0800460 # Now remove the entry from the dictionary
Girish Gowdraaf98a082020-03-05 16:40:51 -0800461 self.log.debug("executed-queued-vlan-filter-task",
462 uni_id=uni_id, tp_id=tp_id)
Girish Gowdraa63eda82020-05-12 13:40:04 -0700463
464 # Now delete the key entry for the tp_id once we have handled the
465 # queued vlan filter tasks for that tp_id
466 del self._queued_vlan_filter_task[uni_id][tp_id]
467 # If the queued vlan filter tasks for all the tp_ids on a given
468 # uni_id is handled, then delete the uni_id key
469 if len(self._queued_vlan_filter_task[uni_id]) == 0:
470 del self._queued_vlan_filter_task[uni_id]
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400471 except Exception as e:
472 self.log.error("vlan-filter-configuration-failed", uni_id=uni_id, error=e)
473
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500474 def _do_tech_profile_configuration(self, uni_id, tp):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500475 us_scheduler = tp['us_scheduler']
476 alloc_id = us_scheduler['alloc_id']
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800477 new_tconts = self._create_tconts(uni_id, us_scheduler)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500478 upstream_gem_port_attribute_list = tp['upstream_gem_port_attribute_list']
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800479 new_upstream_gems = self._create_gemports(uni_id, upstream_gem_port_attribute_list, alloc_id, "UPSTREAM")
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500480 downstream_gem_port_attribute_list = tp['downstream_gem_port_attribute_list']
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800481 new_downstream_gems = self._create_gemports(uni_id, downstream_gem_port_attribute_list, alloc_id, "DOWNSTREAM")
482
483 new_gems = []
484 new_gems.extend(new_upstream_gems)
485 new_gems.extend(new_downstream_gems)
486
487 return new_tconts, new_gems
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500488
Matt Jeanneret5e331892019-12-07 21:31:45 -0500489 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500490 def load_and_configure_tech_profile(self, uni_id, tp_path):
491 self.log.debug("loading-tech-profile-configuration", uni_id=uni_id, tp_path=tp_path)
Mahir Gunyele9110a32020-02-20 14:56:50 -0800492 tp_id = self.extract_tp_id_from_path(tp_path)
Girish Gowdrac5117452020-08-03 11:20:53 -0700493 if tp_id not in self._tp_state_map_per_uni[uni_id]:
494 self._tp_state_map_per_uni[uni_id][tp_id] = TpState(self, uni_id, tp_path)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500495
Girish Gowdrac5117452020-08-03 11:20:53 -0700496 if not self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500497 try:
Girish Gowdrac5117452020-08-03 11:20:53 -0700498 if self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref is not None:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500499 self.log.info("tech-profile-config-already-in-progress",
Girish Gowdrae933cd32019-11-21 21:04:41 +0530500 tp_path=tp_path)
Matt Jeanneret5e331892019-12-07 21:31:45 -0500501 returnValue(None)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500502
Matt Jeanneret5e331892019-12-07 21:31:45 -0500503 tpstored = yield self.tp_kv_client.get(tp_path)
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -0500504 tpstring = tpstored.decode('ascii')
505 tp = json.loads(tpstring)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800506 self._tp[tp_id] = tp
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500507 self.log.debug("tp-instance", tp=tp)
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800508 tconts, gem_ports = self._do_tech_profile_configuration(uni_id, tp)
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700509
William Kurkian3a206332019-04-29 11:05:47 -0400510 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500511 def success(_results):
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800512 self.log.info("tech-profile-config-done-successfully", uni_id=uni_id, tp_id=tp_id)
Girish Gowdrac5117452020-08-03 11:20:53 -0700513 if tp_id in self._tp_state_map_per_uni[uni_id]:
514 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = None
515 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done = True
Chaitrashree G S8fb96782019-08-19 00:10:49 -0400516 # Now execute any vlan filter tasks that were queued for later
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800517 reactor.callInThread(self._execute_queued_vlan_filter_tasks, uni_id, tp_id)
Matt Jeanneretd84c9072020-01-31 06:33:27 -0500518 yield self.core_proxy.device_reason_update(self.device_id, 'tech-profile-config-download-success')
Girish Gowdrae933cd32019-11-21 21:04:41 +0530519
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800520 # Execute mcast task
521 for gem in gem_ports:
Girish Gowdradc98d812020-03-20 13:04:58 -0700522 self.log.debug("checking-multicast-service-for-gem ", gem=gem)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800523 if gem.mcast is True:
Girish Gowdradc98d812020-03-20 13:04:58 -0700524 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 -0800525 reactor.callInThread(self.start_multicast_service, uni_id, tp_path)
526 self.log.debug("started_multicast_service-successfully", tconts=tconts, gems=gem_ports)
527 break
528
William Kurkian3a206332019-04-29 11:05:47 -0400529 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500530 def failure(_reason):
Mahir Gunyel5afa9542020-02-23 22:54:04 -0800531 self.log.warn('tech-profile-config-failure-retrying', uni_id=uni_id, tp_id=tp_id,
Girish Gowdrae933cd32019-11-21 21:04:41 +0530532 _reason=_reason)
Girish Gowdrac5117452020-08-03 11:20:53 -0700533 if tp_id in self._tp_state_map_per_uni[uni_id]:
534 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = None
535 retry = random.randint(1, 5)
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -0500536 reactor.callLater(retry, self.load_and_configure_tech_profile,
537 uni_id, tp_path)
Matt Jeanneretd84c9072020-01-31 06:33:27 -0500538 yield self.core_proxy.device_reason_update(self.device_id,
539 'tech-profile-config-download-failure-retrying')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500540
Mahir Gunyela982ec32020-02-25 12:30:37 -0800541 self.log.info('downloading-tech-profile-configuration', uni_id=uni_id, tp_id=tp_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530542 self.log.debug("tconts-gems-to-install", tconts=tconts, gem_ports=gem_ports)
543
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500544 self.log.debug("current-cached-tconts", tconts=list(self.pon_port.tconts.values()))
545 self.log.debug("current-cached-gem-ports", gem_ports=list(self.pon_port.gem_ports.values()))
546
Girish Gowdrac5117452020-08-03 11:20:53 -0700547 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = \
Mahir Gunyele9110a32020-02-20 14:56:50 -0800548 BrcmTpSetupTask(self.omci_agent, self, uni_id, tconts, gem_ports, tp_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500549 self._deferred = \
Girish Gowdrac5117452020-08-03 11:20:53 -0700550 self._onu_omci_device.task_runner.queue_task(self._tp_state_map_per_uni[uni_id][tp_id].
551 tp_task_ref)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500552 self._deferred.addCallbacks(success, failure)
553
554 except Exception as e:
555 self.log.exception("error-loading-tech-profile", e=e)
556 else:
Girish Gowdradc98d812020-03-20 13:04:58 -0700557 # There is an active tech-profile task ongoing on this UNI port. So, reschedule this task
558 # after a short interval
Girish Gowdrac5117452020-08-03 11:20:53 -0700559 for tpid in self._tp_state_map_per_uni[uni_id]:
560 if self._tp_state_map_per_uni[uni_id][tpid].tp_task_ref is not None:
561 self.log.debug("active-tp-tasks-in-progress-for-uni--scheduling-this-task-for-later",
562 uni_id=uni_id, tp_id=tpid)
563 retry = random.randint(1, 5)
564 reactor.callLater(retry, self.load_and_configure_tech_profile,
565 uni_id, tp_path)
566 return
Girish Gowdradc98d812020-03-20 13:04:58 -0700567
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500568 self.log.info("tech-profile-config-already-done")
Girish Gowdradc98d812020-03-20 13:04:58 -0700569
Girish Gowdrae933cd32019-11-21 21:04:41 +0530570 # Could be a case where TP exists but new gem-ports are getting added dynamically
Matt Jeanneret5e331892019-12-07 21:31:45 -0500571 tpstored = yield self.tp_kv_client.get(tp_path)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530572 tpstring = tpstored.decode('ascii')
573 tp = json.loads(tpstring)
574 upstream_gems = []
575 downstream_gems = []
576 # Find out the new Gem ports that are getting added afresh.
577 for gp in tp['upstream_gem_port_attribute_list']:
578 if self.pon_port.gem_port(gp['gemport_id'], "upstream"):
579 # gem port already exists
580 continue
581 upstream_gems.append(gp)
582 for gp in tp['downstream_gem_port_attribute_list']:
583 if self.pon_port.gem_port(gp['gemport_id'], "downstream"):
584 # gem port already exists
585 continue
586 downstream_gems.append(gp)
587
588 us_scheduler = tp['us_scheduler']
589 alloc_id = us_scheduler['alloc_id']
590
591 if len(upstream_gems) > 0 or len(downstream_gems) > 0:
592 self.log.info("installing-new-gem-ports", upstream_gems=upstream_gems, downstream_gems=downstream_gems)
593 new_upstream_gems = self._create_gemports(uni_id, upstream_gems, alloc_id, "UPSTREAM")
594 new_downstream_gems = self._create_gemports(uni_id, downstream_gems, alloc_id, "DOWNSTREAM")
595 new_gems = []
596 new_gems.extend(new_upstream_gems)
597 new_gems.extend(new_downstream_gems)
598
599 def success(_results):
600 self.log.info("new-gem-ports-successfully-installed", result=_results)
601
602 def failure(_reason):
603 self.log.warn('new-gem-port-install-failed--retrying',
604 _reason=_reason)
605 # Remove gem ports from cache. We will re-add them during the retry
606 for gp in new_gems:
607 self.pon_port.remove_gem_id(gp.gem_id, gp.direction, False)
608
Girish Gowdrac5117452020-08-03 11:20:53 -0700609 retry = random.randint(1, 5)
Matt Jeanneret04ebe8f2020-01-26 01:05:23 -0500610 reactor.callLater(retry, self.load_and_configure_tech_profile,
611 uni_id, tp_path)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530612
Girish Gowdra8777c852020-07-23 12:00:23 -0700613 if self._pon.get_tcont(alloc_id) is None:
614 self.log.error("no-valid-tcont-reference-for-tp-id--not-installing-gem", alloc_id=alloc_id, tp_id=tp_id)
615 return
616
Girish Gowdrac5117452020-08-03 11:20:53 -0700617 self._tp_state_map_per_uni[uni_id][tp_id].tp_task_ref = \
Girish Gowdra8777c852020-07-23 12:00:23 -0700618 BrcmTpSetupTask(self.omci_agent, self, uni_id, [self._pon.get_tcont(alloc_id)], new_gems, tp_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530619 self._deferred = \
Girish Gowdrac5117452020-08-03 11:20:53 -0700620 self._onu_omci_device.task_runner.queue_task(self._tp_state_map_per_uni[uni_id][tp_id].
621 tp_task_ref)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530622 self._deferred.addCallbacks(success, failure)
Girish Gowdradc98d812020-03-20 13:04:58 -0700623
Matt Jeanneret5e331892019-12-07 21:31:45 -0500624 @inlineCallbacks
Girish Gowdradc98d812020-03-20 13:04:58 -0700625 def start_multicast_service(self, uni_id, tp_path, retry_count=0):
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800626 self.log.debug("starting-multicast-service", uni_id=uni_id, tp_path=tp_path)
627 tp_id = self.extract_tp_id_from_path(tp_path)
628 if uni_id in self._set_vlan and tp_id in self._set_vlan[uni_id]:
629 try:
630 tp = self._tp[tp_id]
631 if tp is None:
Matt Jeanneret5e331892019-12-07 21:31:45 -0500632 tpstored = yield self.tp_kv_client.get(tp_path)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800633 tpstring = tpstored.decode('ascii')
634 tp = json.loads(tpstring)
635 if tp is None:
636 self.log.error("cannot-find-tp-to-start-multicast-service", uni_id=uni_id, tp_path=tp_path)
637 return
638 else:
639 self._tp[tp_id] = tp
640
641 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 -0700642
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800643 def success(_results):
644 self.log.debug('multicast-success', uni_id=uni_id)
645 self._multicast_task = None
646
647 def failure(_reason):
648 self.log.warn('multicast-failure', _reason=_reason)
Girish Gowdrac5117452020-08-03 11:20:53 -0700649 retry = random.randint(1, 5)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800650 reactor.callLater(retry, self.start_multicast_service,
Girish Gowdradc98d812020-03-20 13:04:58 -0700651 uni_id, tp_path)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800652
653 self.log.debug('starting-multicast-task', mcast_vlan_id=self._set_vlan[uni_id][tp_id])
654 downstream_gem_port_attribute_list = tp['downstream_gem_port_attribute_list']
655 for i in range(len(downstream_gem_port_attribute_list)):
656 if IS_MULTICAST in downstream_gem_port_attribute_list[i] and \
657 downstream_gem_port_attribute_list[i][IS_MULTICAST] == 'True':
Girish Gowdradc98d812020-03-20 13:04:58 -0700658 dynamic_access_control_list_table = downstream_gem_port_attribute_list[i][
659 'dynamic_access_control_list'].split("-")
660 static_access_control_list_table = downstream_gem_port_attribute_list[i][
661 'static_access_control_list'].split("-")
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800662 multicast_gem_id = downstream_gem_port_attribute_list[i]['multicast_gem_id']
663 break
664
665 self._multicast_task = BrcmMcastTask(self.omci_agent, self, self.device_id, uni_id, tp_id,
Girish Gowdradc98d812020-03-20 13:04:58 -0700666 self._set_vlan[uni_id][tp_id], dynamic_access_control_list_table,
667 static_access_control_list_table, multicast_gem_id)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800668 self._deferred = self._onu_omci_device.task_runner.queue_task(self._multicast_task)
669 self._deferred.addCallbacks(success, failure)
670 except Exception as e:
671 self.log.exception("error-loading-multicast", e=e)
672 else:
Girish Gowdradc98d812020-03-20 13:04:58 -0700673 if retry_count < 30:
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800674 retry_count = +1
Girish Gowdradc98d812020-03-20 13:04:58 -0700675 self.log.debug("going-to-wait-for-flow-to-learn-mcast-vlan", uni_id=uni_id, tp_id=tp_id,
676 retry=retry_count)
Mahir Gunyel5de33fe2020-03-03 22:38:44 -0800677 reactor.callLater(0.5, self.start_multicast_service, uni_id, tp_path, retry_count)
678 else:
Girish Gowdradc98d812020-03-20 13:04:58 -0700679 self.log.error("mcast-vlan-not-configured-yet-failing-mcast-service-conf", uni_id=uni_id, tp_id=tp_id,
680 retry=retry_count)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530681
Girish Gowdraba4b1812020-07-17 12:21:26 -0700682 def _clear_alloc_id_gem_port_from_internal_cache(self, alloc_id=None, gem_port_id=None):
683 tcont = None
684 gem_port = None
685 if alloc_id is not None:
686 self.log.debug("current-cached-tconts", tconts=list(self.pon_port.tconts.values()))
687 for tc in list(self.pon_port.tconts.values()):
688 if tc.alloc_id == alloc_id:
689 self.log.info("removing-tcont-from-internal-cache",
690 alloc_id=alloc_id)
691 tcont = tc
692 self.pon_port.remove_tcont(tc.alloc_id, False)
693
694 if gem_port_id is not None:
695 self.log.debug("current-cached-gem-ports", gem_ports=list(self.pon_port.gem_ports.values()))
696 for gp in list(self.pon_port.gem_ports.values()):
697 if gp.gem_id == gem_port_id:
698 self.log.info("removing-gem-from-internal-cache",
699 gem_port_id=gem_port_id, direction=gp.direction)
700 gem_port = gp
701 self.pon_port.remove_gem_id(gp.gem_id, gp.direction, False)
702
703 return tcont, gem_port
704
Girish Gowdrac5117452020-08-03 11:20:53 -0700705 def _tcont_delete_complete(self, uni_id, tp_id):
706 if not self._tp_state_map_per_uni[uni_id][tp_id].is_all_pon_resource_delete_complete():
707 self.log.info("waiting-for-gem-port-delete-to-complete-before-clearing-tp-states")
708 retry = random.randint(1, 5)
709 reactor.callLater(retry, self._tcont_delete_complete, uni_id, tp_id)
710 return
711 self.log.info("tp-delete-complete")
712 # Clear TP states
713 self._tp_state_map_per_uni[uni_id][tp_id].reset_tp_state()
714 del self._tp_state_map_per_uni[uni_id][tp_id]
715
716 def delete_tech_profile(self, uni_id, tp_path, tcont=None, gem_port=None):
717 alloc_id = None
718 gem_port_id = None
Girish Gowdrae933cd32019-11-21 21:04:41 +0530719 try:
Mahir Gunyele9110a32020-02-20 14:56:50 -0800720 tp_table_id = self.extract_tp_id_from_path(tp_path)
Girish Gowdraba4b1812020-07-17 12:21:26 -0700721 # Extract the current set of TCONT and GEM Ports from the Handler's pon_port that are
722 # relevant to this task's UNI. It won't change. But, the underlying pon_port may change
723 # due to additional tasks on different UNIs. So, it we cannot use the pon_port affter
724 # this initializer
Girish Gowdrac5117452020-08-03 11:20:53 -0700725 alloc_id = tcont.alloc_id if tcont is not None else None
726 gem_port_id = gem_port.gem_id if gem_port is not None else None
727 self._clear_alloc_id_gem_port_from_internal_cache(alloc_id, gem_port_id)
Girish Gowdraba4b1812020-07-17 12:21:26 -0700728
Girish Gowdrac5117452020-08-03 11:20:53 -0700729 if tp_table_id not in self._tp_state_map_per_uni[uni_id]:
Mahir Gunyele9110a32020-02-20 14:56:50 -0800730 self.log.warn("tp-id-is-not-present", uni_id=uni_id, tp_id=tp_table_id)
Naga Manjunathe433c712020-01-02 17:27:20 +0530731 return
732
Girish Gowdrac5117452020-08-03 11:20:53 -0700733 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 -0800734 self.log.error("tp-download-is-not-done-in-order-to-process-tp-delete", uni_id=uni_id,
735 tp_id=tp_table_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530736 return
737
738 if alloc_id is None and gem_port_id is None:
Mahir Gunyele9110a32020-02-20 14:56:50 -0800739 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 +0530740 return
741
Girish Gowdrae933cd32019-11-21 21:04:41 +0530742 @inlineCallbacks
743 def success(_results):
744 if gem_port_id:
745 self.log.info("gem-port-delete-done-successfully")
Girish Gowdrac5117452020-08-03 11:20:53 -0700746 self._tp_state_map_per_uni[uni_id][tp_table_id].pon_resource_delete_complete(TpState.GEM_ID,
747 gem_port_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530748 if alloc_id:
749 self.log.info("tcont-delete-done-successfully")
750 # The deletion of TCONT marks the complete deletion of tech-profile
Girish Gowdrac5117452020-08-03 11:20:53 -0700751 self._tp_state_map_per_uni[uni_id][tp_table_id].pon_resource_delete_complete(TpState.ALLOC_ID,
752 alloc_id)
753 self._tcont_delete_complete(uni_id, tp_table_id)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530754
755 # TODO: There could be multiple TP on the UNI, and also the ONU.
756 # TODO: But the below reason updates for the whole device.
757 yield self.core_proxy.device_reason_update(self.device_id, 'tech-profile-config-delete-success')
758
759 @inlineCallbacks
Girish Gowdraa73ee452019-12-20 18:52:17 +0530760 def failure(_reason):
Girish Gowdrae933cd32019-11-21 21:04:41 +0530761 self.log.warn('tech-profile-delete-failure-retrying',
762 _reason=_reason)
Girish Gowdrac5117452020-08-03 11:20:53 -0700763 retry = random.randint(1, 5)
764 _tcont = self._tp_state_map_per_uni[uni_id][tp_table_id].get_queued_resource_for_delete(TpState.ALLOC_ID, alloc_id)
765 _gem_port = self._tp_state_map_per_uni[uni_id][tp_table_id].get_queued_resource_for_delete(TpState.GEM_ID, gem_port_id)
766 reactor.callLater(retry, self.delete_tech_profile, uni_id, tp_path, _tcont, _gem_port)
Matt Jeanneretd84c9072020-01-31 06:33:27 -0500767 yield self.core_proxy.device_reason_update(self.device_id,
768 'tech-profile-config-delete-failure-retrying')
Girish Gowdrae933cd32019-11-21 21:04:41 +0530769
770 self.log.info('deleting-tech-profile-configuration')
771
Girish Gowdraa73ee452019-12-20 18:52:17 +0530772 if tcont is None and gem_port is None:
773 if alloc_id is not None:
774 self.log.error("tcont-info-corresponding-to-alloc-id-not-found", alloc_id=alloc_id)
775 if gem_port_id is not None:
776 self.log.error("gem-port-info-corresponding-to-gem-port-id-not-found", gem_port_id=gem_port_id)
777 return
778
Girish Gowdrac5117452020-08-03 11:20:53 -0700779 self._tp_state_map_per_uni[uni_id][tp_table_id].tp_task_ref = \
Girish Gowdrae933cd32019-11-21 21:04:41 +0530780 BrcmTpDeleteTask(self.omci_agent, self, uni_id, tp_table_id,
781 tcont=tcont, gem_port=gem_port)
782 self._deferred = \
Girish Gowdrac5117452020-08-03 11:20:53 -0700783 self._onu_omci_device.task_runner.queue_task(self._tp_state_map_per_uni[uni_id][tp_table_id].
784 tp_task_ref)
Girish Gowdrae933cd32019-11-21 21:04:41 +0530785 self._deferred.addCallbacks(success, failure)
786 except Exception as e:
787 self.log.exception("failed-to-delete-tp",
788 e=e, uni_id=uni_id, tp_path=tp_path,
789 alloc_id=alloc_id, gem_port_id=gem_port_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500790
Rohan Agrawalf0f8c292020-06-01 09:30:55 +0000791 def update_pm_config(self, device, pm_configs):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500792 # TODO: This has not been tested
Rohan Agrawalf0f8c292020-06-01 09:30:55 +0000793 self.log.info('update_pm_config', pm_configs=pm_configs)
794 self._pm_metrics.update(pm_configs)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500795
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800796 def remove_onu_flows(self, device, flows):
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500797 self.log.debug('remove-onu-flows')
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800798
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800799 # no point in removing omci flows if the device isnt reachable
800 if device.connect_status != ConnectStatus.REACHABLE or \
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800801 device.admin_state != AdminState.ENABLED:
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800802 self.log.warn("device-disabled-or-offline-skipping-remove-flow",
803 admin=device.admin_state, connect=device.connect_status)
804 return
805
806 for flow in flows:
807 # if incoming flow contains cookie, then remove from ONU
808 if flow.cookie:
809 self.log.debug("remove-flow", device_id=device.id, flow=flow)
810
811 def is_downstream(port):
812 return port == self._pon_port_number
813
814 def is_upstream(port):
815 return not is_downstream(port)
816
817 try:
818 _in_port = fd.get_in_port(flow)
819 assert _in_port is not None
820
821 _out_port = fd.get_out_port(flow) # may be None
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800822
823 if is_downstream(_in_port):
824 self.log.debug('downstream-flow-no-need-to-remove', in_port=_in_port, out_port=_out_port,
825 device_id=device.id)
826 # extended vlan tagging operation will handle it
827 continue
828 elif is_upstream(_in_port):
829 self.log.debug('upstream-flow', in_port=_in_port, out_port=_out_port)
830 if fd.is_dhcp_flow(flow):
831 self.log.debug('The dhcp trap-to-host flow will be discarded', device_id=device.id)
832 return
833
Mahir Gunyel45610b42020-03-16 17:29:01 -0700834 _match_vlan_vid = None
835 for field in fd.get_ofb_fields(flow):
836 if field.type == fd.VLAN_VID:
837 if field.vlan_vid == RESERVED_TRANSPARENT_VLAN and field.vlan_vid_mask == RESERVED_TRANSPARENT_VLAN:
838 _match_vlan_vid = RESERVED_TRANSPARENT_VLAN
839 else:
840 _match_vlan_vid = field.vlan_vid & 0xfff
841 self.log.debug('field-type-vlan-vid',
842 vlan=_match_vlan_vid)
843
844 _set_vlan_vid = None
845 _set_vlan_pcp = None
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800846 # Retrieve the VLAN_VID that needs to be removed from the EVTO rule on the ONU.
847 for action in fd.get_actions(flow):
848 if action.type == fd.SET_FIELD:
849 _field = action.set_field.field.ofb_field
850 assert (action.set_field.field.oxm_class ==
851 OFPXMC_OPENFLOW_BASIC)
852 if _field.type == fd.VLAN_VID:
Mahir Gunyel45610b42020-03-16 17:29:01 -0700853 _set_vlan_vid = _field.vlan_vid & 0xfff
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800854 self.log.debug('vlan-vid-to-remove',
Mahir Gunyel45610b42020-03-16 17:29:01 -0700855 _vlan_vid=_set_vlan_vid, in_port=_in_port)
856 elif _field.type == fd.VLAN_PCP:
857 _set_vlan_pcp = _field.vlan_pcp
858 self.log.debug('set-field-type-vlan-pcp',
859 vlan_pcp=_set_vlan_pcp)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800860
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800861 uni_port = self.uni_port(_in_port)
862 uni_id = _in_port & 0xF
863 else:
864 raise Exception('port should be 1 or 2 by our convention')
865
866 self.log.debug('flow-ports', in_port=_in_port, out_port=_out_port, uni_port=str(uni_port))
867
868 tp_id = self.get_tp_id_in_flow(flow)
Girish Gowdradc98d812020-03-20 13:04:58 -0700869 # The vlan filter remove should be followed by a TP deleted for that TP ID.
870 # Use this information to re-schedule any vlan filter add tasks for the same TP ID again.
871 # First check if the TP download was done, before we access that TP delete is necessary
Girish Gowdrac5117452020-08-03 11:20:53 -0700872 if tp_id in self._tp_state_map_per_uni[uni_id] and \
873 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done is True:
874 self._tp_state_map_per_uni[uni_id][tp_id].is_tp_delete_pending = True
875
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800876 # Deleting flow from ONU.
Mahir Gunyel45610b42020-03-16 17:29:01 -0700877 self._remove_vlan_filter_task(device, uni_id, uni_port=uni_port,
878 _set_vlan_pcp=_set_vlan_pcp,
879 _set_vlan_vid=_set_vlan_vid,
880 match_vlan=_match_vlan_vid,
881 tp_id=tp_id)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800882 # TODO:Delete TD task.
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800883 except Exception as e:
884 self.log.exception('failed-to-remove-flow', e=e)
885
886 def add_onu_flows(self, device, flows):
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500887 self.log.debug('add-onu-flows')
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800888
889 # no point in pushing omci flows if the device isnt reachable
890 if device.connect_status != ConnectStatus.REACHABLE or \
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800891 device.admin_state != AdminState.ENABLED:
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800892 self.log.warn("device-disabled-or-offline-skipping-flow-update",
893 admin=device.admin_state, connect=device.connect_status)
894 return
Girish Gowdra4c11ddb2020-03-03 11:33:24 -0800895
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800896 def is_downstream(port):
897 return port == self._pon_port_number
898
899 def is_upstream(port):
900 return not is_downstream(port)
901
902 for flow in flows:
903 # if incoming flow contains cookie, then add to ONU
904 if flow.cookie:
905 _type = None
906 _port = None
907 _vlan_vid = None
908 _udp_dst = None
909 _udp_src = None
910 _ipv4_dst = None
911 _ipv4_src = None
912 _metadata = None
913 _output = None
914 _push_tpid = None
915 _field = None
916 _set_vlan_vid = None
Mahir Gunyel45610b42020-03-16 17:29:01 -0700917 _set_vlan_pcp = None
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800918 _tunnel_id = None
Girish Gowdra6a73ad62020-06-11 13:40:16 -0700919 _proto = -1
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800920 self.log.debug("add-flow", device_id=device.id, flow=flow)
921
922 try:
923 _in_port = fd.get_in_port(flow)
924 assert _in_port is not None
925
926 _out_port = fd.get_out_port(flow) # may be None
927 tp_id = self.get_tp_id_in_flow(flow)
928 if is_downstream(_in_port):
929 self.log.debug('downstream-flow', in_port=_in_port, out_port=_out_port)
930 # NOTE: We don't care downstream flow because we will copy vlan_id to upstream flow
931 # uni_port = self.uni_port(_out_port)
932 # uni_id = _out_port & 0xF
933 continue
934 elif is_upstream(_in_port):
935 self.log.debug('upstream-flow', in_port=_in_port, out_port=_out_port)
936 uni_port = self.uni_port(_in_port)
937 uni_id = _in_port & 0xF
938 else:
939 raise Exception('port should be 1 or 2 by our convention')
940
941 self.log.debug('flow-ports', in_port=_in_port, out_port=_out_port, uni_port=str(uni_port))
942
943 for field in fd.get_ofb_fields(flow):
944 if field.type == fd.ETH_TYPE:
945 _type = field.eth_type
946 self.log.debug('field-type-eth-type',
947 eth_type=_type)
948
949 elif field.type == fd.IP_PROTO:
950 _proto = field.ip_proto
Girish Gowdra6a73ad62020-06-11 13:40:16 -0700951 if _proto == 2:
952 # Workaround for TT workflow - avoids installing invalid EVTO rule
953 self.log.debug("igmp-trap-flow")
954 break
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800955 self.log.debug('field-type-ip-proto',
956 ip_proto=_proto)
957
958 elif field.type == fd.IN_PORT:
959 _port = field.port
960 self.log.debug('field-type-in-port',
961 in_port=_port)
962 elif field.type == fd.TUNNEL_ID:
963 self.log.debug('field-type-tunnel-id')
964
965 elif field.type == fd.VLAN_VID:
Andrea Campanellacf916ea2020-02-14 10:03:58 +0100966 if field.vlan_vid == RESERVED_TRANSPARENT_VLAN and field.vlan_vid_mask == RESERVED_TRANSPARENT_VLAN:
967 _vlan_vid = RESERVED_TRANSPARENT_VLAN
968 else:
969 _vlan_vid = field.vlan_vid & 0xfff
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800970 self.log.debug('field-type-vlan-vid',
971 vlan=_vlan_vid)
972
973 elif field.type == fd.VLAN_PCP:
974 _vlan_pcp = field.vlan_pcp
975 self.log.debug('field-type-vlan-pcp',
976 pcp=_vlan_pcp)
977
978 elif field.type == fd.UDP_DST:
979 _udp_dst = field.udp_dst
980 self.log.debug('field-type-udp-dst',
981 udp_dst=_udp_dst)
982
983 elif field.type == fd.UDP_SRC:
984 _udp_src = field.udp_src
985 self.log.debug('field-type-udp-src',
986 udp_src=_udp_src)
987
988 elif field.type == fd.IPV4_DST:
989 _ipv4_dst = field.ipv4_dst
990 self.log.debug('field-type-ipv4-dst',
991 ipv4_dst=_ipv4_dst)
992
993 elif field.type == fd.IPV4_SRC:
994 _ipv4_src = field.ipv4_src
995 self.log.debug('field-type-ipv4-src',
996 ipv4_dst=_ipv4_src)
997
998 elif field.type == fd.METADATA:
999 _metadata = field.table_metadata
1000 self.log.debug('field-type-metadata',
1001 metadata=_metadata)
1002
1003 else:
1004 raise NotImplementedError('field.type={}'.format(
1005 field.type))
1006
Girish Gowdra6a73ad62020-06-11 13:40:16 -07001007 if _proto == 2:
1008 # Workaround for TT workflow - avoids installing invalid EVTO rule
1009 self.log.warn("skipping-igmp-trap-flow")
1010 continue
1011
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001012 for action in fd.get_actions(flow):
1013
1014 if action.type == fd.OUTPUT:
1015 _output = action.output.port
1016 self.log.debug('action-type-output',
1017 output=_output, in_port=_in_port)
1018
1019 elif action.type == fd.POP_VLAN:
1020 self.log.debug('action-type-pop-vlan',
1021 in_port=_in_port)
1022
1023 elif action.type == fd.PUSH_VLAN:
1024 _push_tpid = action.push.ethertype
1025 self.log.debug('action-type-push-vlan',
1026 push_tpid=_push_tpid, in_port=_in_port)
1027 if action.push.ethertype != 0x8100:
1028 self.log.error('unhandled-tpid',
1029 ethertype=action.push.ethertype)
1030
1031 elif action.type == fd.SET_FIELD:
1032 _field = action.set_field.field.ofb_field
1033 assert (action.set_field.field.oxm_class ==
1034 OFPXMC_OPENFLOW_BASIC)
1035 self.log.debug('action-type-set-field',
1036 field=_field, in_port=_in_port)
1037 if _field.type == fd.VLAN_VID:
1038 _set_vlan_vid = _field.vlan_vid & 0xfff
1039 self.log.debug('set-field-type-vlan-vid',
1040 vlan_vid=_set_vlan_vid)
1041 elif _field.type == fd.VLAN_PCP:
1042 _set_vlan_pcp = _field.vlan_pcp
1043 self.log.debug('set-field-type-vlan-pcp',
1044 vlan_pcp=_set_vlan_pcp)
1045 else:
1046 self.log.error('unsupported-action-set-field-type',
1047 field_type=_field.type)
1048 else:
1049 self.log.error('unsupported-action-type',
1050 action_type=action.type, in_port=_in_port)
1051
Mahir Gunyel5de33fe2020-03-03 22:38:44 -08001052 if self._set_vlan is not None:
1053 if uni_id not in self._set_vlan:
1054 self._set_vlan[uni_id] = dict()
1055 self._set_vlan[uni_id][tp_id] = _set_vlan_vid
1056 self.log.debug("set_vlan_id-for-tp", _set_vlan_vid=_set_vlan_vid, tp_id=tp_id)
1057
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001058 # OMCI set vlan task can only filter and set on vlan header attributes. Any other openflow
1059 # supported match and action criteria cannot be handled by omci and must be ignored.
1060 if (_set_vlan_vid is None or _set_vlan_vid == 0) and _vlan_vid != RESERVED_TRANSPARENT_VLAN:
1061 self.log.warn('ignoring-flow-that-does-not-set-vlanid', set_vlan_vid=_set_vlan_vid)
1062 elif (_set_vlan_vid is None or _set_vlan_vid == 0) and _vlan_vid == RESERVED_TRANSPARENT_VLAN:
1063 self.log.info('set-vlanid-any', uni_id=uni_id, uni_port=uni_port,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001064 _set_vlan_vid=_vlan_vid,
1065 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1066 tp_id=tp_id)
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001067 self._add_vlan_filter_task(device, uni_id=uni_id, uni_port=uni_port,
1068 _set_vlan_vid=_vlan_vid,
1069 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1070 tp_id=tp_id)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001071 else:
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001072 self.log.info('set-vlanid', uni_id=uni_id, uni_port=uni_port, match_vlan=_vlan_vid,
1073 set_vlan_vid=_set_vlan_vid, _set_vlan_pcp=_set_vlan_pcp, ethType=_type)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001074 self._add_vlan_filter_task(device, uni_id=uni_id, uni_port=uni_port,
1075 _set_vlan_vid=_set_vlan_vid,
1076 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1077 tp_id=tp_id)
1078
1079 except Exception as e:
1080 self.log.exception('failed-to-install-flow', e=e, flow=flow)
1081
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001082 # Calling this assumes the onu is active/ready and had at least an initial mib downloaded. This gets called from
1083 # flow decomposition that ultimately comes from onos
1084 def update_flow_table(self, device, flows):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001085 self.log.debug('update-flow-table', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001086
1087 #
1088 # We need to proxy through the OLT to get to the ONU
1089 # Configuration from here should be using OMCI
1090 #
1091 # self.log.info('bulk-flow-update', device_id=device.id, flows=flows)
1092
1093 # no point in pushing omci flows if the device isnt reachable
1094 if device.connect_status != ConnectStatus.REACHABLE or \
Girish Gowdrae933cd32019-11-21 21:04:41 +05301095 device.admin_state != AdminState.ENABLED:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001096 self.log.warn("device-disabled-or-offline-skipping-flow-update",
1097 admin=device.admin_state, connect=device.connect_status)
1098 return
1099
1100 def is_downstream(port):
1101 return port == self._pon_port_number
1102
1103 def is_upstream(port):
1104 return not is_downstream(port)
1105
1106 for flow in flows:
1107 _type = None
1108 _port = None
1109 _vlan_vid = None
1110 _udp_dst = None
1111 _udp_src = None
1112 _ipv4_dst = None
1113 _ipv4_src = None
1114 _metadata = None
1115 _output = None
1116 _push_tpid = None
1117 _field = None
1118 _set_vlan_vid = None
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001119 _set_vlan_pcp = None
Matt Jeanneretef06d0d2019-04-27 17:36:53 -04001120 _tunnel_id = None
1121
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001122 try:
Girish Gowdraa73ee452019-12-20 18:52:17 +05301123 write_metadata = fd.get_write_metadata(flow)
1124 if write_metadata is None:
1125 self.log.error("do-not-process-flow-without-write-metadata")
1126 return
1127
1128 # extract tp id from flow
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001129 tp_id = self.get_tp_id_in_flow(flow)
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001130 self.log.debug("tp-id-in-flow", tp_id=tp_id)
Girish Gowdraa73ee452019-12-20 18:52:17 +05301131
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001132 _in_port = fd.get_in_port(flow)
1133 assert _in_port is not None
1134
1135 _out_port = fd.get_out_port(flow) # may be None
1136
1137 if is_downstream(_in_port):
1138 self.log.debug('downstream-flow', in_port=_in_port, out_port=_out_port)
1139 uni_port = self.uni_port(_out_port)
Girish Gowdrae933cd32019-11-21 21:04:41 +05301140 uni_id = _out_port & 0xF
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001141 elif is_upstream(_in_port):
1142 self.log.debug('upstream-flow', in_port=_in_port, out_port=_out_port)
1143 uni_port = self.uni_port(_in_port)
Chaitrashree G S8fb96782019-08-19 00:10:49 -04001144 uni_id = _in_port & 0xF
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001145 else:
1146 raise Exception('port should be 1 or 2 by our convention')
1147
1148 self.log.debug('flow-ports', in_port=_in_port, out_port=_out_port, uni_port=str(uni_port))
1149
1150 for field in fd.get_ofb_fields(flow):
1151 if field.type == fd.ETH_TYPE:
1152 _type = field.eth_type
1153 self.log.debug('field-type-eth-type',
1154 eth_type=_type)
1155
1156 elif field.type == fd.IP_PROTO:
1157 _proto = field.ip_proto
1158 self.log.debug('field-type-ip-proto',
1159 ip_proto=_proto)
1160
1161 elif field.type == fd.IN_PORT:
1162 _port = field.port
1163 self.log.debug('field-type-in-port',
1164 in_port=_port)
1165
1166 elif field.type == fd.VLAN_VID:
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001167 if field.vlan_vid == RESERVED_TRANSPARENT_VLAN and field.vlan_vid_mask == RESERVED_TRANSPARENT_VLAN:
1168 _vlan_vid = RESERVED_TRANSPARENT_VLAN
1169 else:
1170 _vlan_vid = field.vlan_vid & 0xfff
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001171 self.log.debug('field-type-vlan-vid',
1172 vlan=_vlan_vid)
1173
1174 elif field.type == fd.VLAN_PCP:
1175 _vlan_pcp = field.vlan_pcp
1176 self.log.debug('field-type-vlan-pcp',
1177 pcp=_vlan_pcp)
1178
1179 elif field.type == fd.UDP_DST:
1180 _udp_dst = field.udp_dst
1181 self.log.debug('field-type-udp-dst',
1182 udp_dst=_udp_dst)
1183
1184 elif field.type == fd.UDP_SRC:
1185 _udp_src = field.udp_src
1186 self.log.debug('field-type-udp-src',
1187 udp_src=_udp_src)
1188
1189 elif field.type == fd.IPV4_DST:
1190 _ipv4_dst = field.ipv4_dst
1191 self.log.debug('field-type-ipv4-dst',
1192 ipv4_dst=_ipv4_dst)
1193
1194 elif field.type == fd.IPV4_SRC:
1195 _ipv4_src = field.ipv4_src
1196 self.log.debug('field-type-ipv4-src',
1197 ipv4_dst=_ipv4_src)
1198
1199 elif field.type == fd.METADATA:
1200 _metadata = field.table_metadata
1201 self.log.debug('field-type-metadata',
1202 metadata=_metadata)
1203
Matt Jeanneretef06d0d2019-04-27 17:36:53 -04001204 elif field.type == fd.TUNNEL_ID:
1205 _tunnel_id = field.tunnel_id
1206 self.log.debug('field-type-tunnel-id',
1207 tunnel_id=_tunnel_id)
1208
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001209
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001210 else:
1211 raise NotImplementedError('field.type={}'.format(
1212 field.type))
1213
1214 for action in fd.get_actions(flow):
1215
1216 if action.type == fd.OUTPUT:
1217 _output = action.output.port
1218 self.log.debug('action-type-output',
1219 output=_output, in_port=_in_port)
1220
1221 elif action.type == fd.POP_VLAN:
1222 self.log.debug('action-type-pop-vlan',
1223 in_port=_in_port)
1224
1225 elif action.type == fd.PUSH_VLAN:
1226 _push_tpid = action.push.ethertype
1227 self.log.debug('action-type-push-vlan',
1228 push_tpid=_push_tpid, in_port=_in_port)
1229 if action.push.ethertype != 0x8100:
1230 self.log.error('unhandled-tpid',
1231 ethertype=action.push.ethertype)
1232
1233 elif action.type == fd.SET_FIELD:
1234 _field = action.set_field.field.ofb_field
1235 assert (action.set_field.field.oxm_class ==
1236 OFPXMC_OPENFLOW_BASIC)
1237 self.log.debug('action-type-set-field',
1238 field=_field, in_port=_in_port)
1239 if _field.type == fd.VLAN_VID:
1240 _set_vlan_vid = _field.vlan_vid & 0xfff
1241 self.log.debug('set-field-type-vlan-vid',
1242 vlan_vid=_set_vlan_vid)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001243 elif _field.type == fd.VLAN_PCP:
1244 _set_vlan_pcp = _field.vlan_pcp
1245 self.log.debug('set-field-type-vlan-pcp',
1246 vlan_pcp=_set_vlan_pcp)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001247 else:
1248 self.log.error('unsupported-action-set-field-type',
1249 field_type=_field.type)
1250 else:
1251 self.log.error('unsupported-action-type',
1252 action_type=action.type, in_port=_in_port)
1253
Mahir Gunyel5de33fe2020-03-03 22:38:44 -08001254 if self._set_vlan is not None:
1255 if uni_id not in self._set_vlan:
1256 self._set_vlan[uni_id] = dict()
1257 self._set_vlan[uni_id][tp_id] = _set_vlan_vid
1258 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 -04001259 # OMCI set vlan task can only filter and set on vlan header attributes. Any other openflow
1260 # supported match and action criteria cannot be handled by omci and must be ignored.
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001261 if (_set_vlan_vid is None or _set_vlan_vid == 0) and _vlan_vid != RESERVED_TRANSPARENT_VLAN:
1262 self.log.warn('ignoring-flow-that-does-not-set-vlanid', set_vlan_vid=_set_vlan_vid)
1263 elif (_set_vlan_vid is None or _set_vlan_vid == 0) and _vlan_vid == RESERVED_TRANSPARENT_VLAN:
1264 self.log.info('set-vlanid-any', uni_id=uni_id, uni_port=uni_port,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001265 _set_vlan_vid=_vlan_vid,
1266 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1267 tp_id=tp_id)
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001268 self._add_vlan_filter_task(device, uni_id=uni_id, uni_port=uni_port,
1269 _set_vlan_vid=_vlan_vid,
1270 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1271 tp_id=tp_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001272 else:
Andrea Campanellacf916ea2020-02-14 10:03:58 +01001273 self.log.info('set-vlanid', uni_id=uni_id, uni_port=uni_port, match_vlan=_vlan_vid,
1274 set_vlan_vid=_set_vlan_vid, _set_vlan_pcp=_set_vlan_pcp, ethType=_type)
1275 self._add_vlan_filter_task(device, uni_id=uni_id, uni_port=uni_port,
1276 _set_vlan_vid=_set_vlan_vid,
1277 _set_vlan_pcp=_set_vlan_pcp, match_vlan=_vlan_vid,
1278 tp_id=tp_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001279 except Exception as e:
1280 self.log.exception('failed-to-install-flow', e=e, flow=flow)
1281
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001282 def _add_vlan_filter_task(self, device, uni_id, uni_port=None, match_vlan=0,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001283 _set_vlan_vid=None, _set_vlan_pcp=8, tp_id=0):
Girish Gowdrac5117452020-08-03 11:20:53 -07001284 if tp_id in self._tp_state_map_per_uni[uni_id] and \
1285 self._tp_state_map_per_uni[uni_id][tp_id].is_tp_delete_pending is True:
Girish Gowdradc98d812020-03-20 13:04:58 -07001286 self.log.debug("pending-del-tp--scheduling-add-vlan-filter-task-for-later")
Girish Gowdrac5117452020-08-03 11:20:53 -07001287 retry = random.randint(1, 5)
1288 reactor.callLater(retry, self._add_vlan_filter_task, device, uni_id, uni_port, match_vlan,
Girish Gowdradc98d812020-03-20 13:04:58 -07001289 _set_vlan_vid, _set_vlan_pcp, tp_id)
1290 return
1291
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001292 self.log.info('_adding_vlan_filter_task', uni_port=uni_port, uni_id=uni_id, tp_id=tp_id, match_vlan=match_vlan,
1293 vlan=_set_vlan_vid, vlan_pcp=_set_vlan_pcp)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001294 assert uni_port is not None
Girish Gowdrac5117452020-08-03 11:20:53 -07001295 if tp_id in self._tp_state_map_per_uni[uni_id] and \
1296 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done is True:
Chaitrashree G S8fb96782019-08-19 00:10:49 -04001297 @inlineCallbacks
1298 def success(_results):
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001299 self.log.info('vlan-tagging-success', uni_port=uni_port, vlan=_set_vlan_vid, tp_id=tp_id,
1300 set_vlan_pcp=_set_vlan_pcp)
Matt Jeanneretd84c9072020-01-31 06:33:27 -05001301 yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-pushed')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001302
Chaitrashree G S8fb96782019-08-19 00:10:49 -04001303 @inlineCallbacks
1304 def failure(_reason):
Girish Gowdraa73ee452019-12-20 18:52:17 +05301305 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 -07001306 retry = random.randint(1, 5)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001307 reactor.callLater(retry,
1308 self._add_vlan_filter_task, device, uni_id, uni_port=uni_port,
1309 match_vlan=match_vlan, _set_vlan_vid=_set_vlan_vid,
1310 _set_vlan_pcp=_set_vlan_pcp, tp_id=tp_id)
Matt Jeanneretd84c9072020-01-31 06:33:27 -05001311 yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-failed-retrying')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001312
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001313 self.log.info('setting-vlan-tag', uni_port=uni_port, uni_id=uni_id, tp_id=tp_id, match_vlan=match_vlan,
1314 vlan=_set_vlan_vid, vlan_pcp=_set_vlan_pcp)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001315 vlan_filter_add_task = BrcmVlanFilterTask(self.omci_agent, self, uni_port, _set_vlan_vid,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001316 match_vlan, _set_vlan_pcp, add_tag=True,
1317 tp_id=tp_id)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001318 self._deferred = self._onu_omci_device.task_runner.queue_task(vlan_filter_add_task)
Chaitrashree G S8fb96782019-08-19 00:10:49 -04001319 self._deferred.addCallbacks(success, failure)
1320 else:
1321 self.log.info('tp-service-specific-task-not-done-adding-request-to-local-cache',
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001322 uni_id=uni_id, tp_id=tp_id)
1323 if uni_id not in self._queued_vlan_filter_task:
1324 self._queued_vlan_filter_task[uni_id] = dict()
Mahir Gunyela982ec32020-02-25 12:30:37 -08001325 if tp_id not in self._queued_vlan_filter_task[uni_id]:
1326 self._queued_vlan_filter_task[uni_id][tp_id] = []
1327 self._queued_vlan_filter_task[uni_id][tp_id].append({"device": device,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001328 "uni_id": uni_id,
1329 "uni_port": uni_port,
1330 "match_vlan": match_vlan,
1331 "set_vlan_vid": _set_vlan_vid,
1332 "set_vlan_pcp": _set_vlan_pcp,
1333 "tp_id": tp_id})
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001334
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001335 def get_tp_id_in_flow(self, flow):
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001336 flow_metadata = fd.get_metadata_from_write_metadata(flow)
1337 tp_id = fd.get_tp_id_from_metadata(flow_metadata)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001338 return tp_id
1339
1340 def _remove_vlan_filter_task(self, device, uni_id, uni_port=None, match_vlan=0,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001341 _set_vlan_vid=None, _set_vlan_pcp=8, tp_id=0):
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001342 assert uni_port is not None
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001343
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001344 @inlineCallbacks
1345 def success(_results):
1346 self.log.info('vlan-untagging-success', _results=_results)
1347 yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-deleted')
1348
1349 @inlineCallbacks
1350 def failure(_reason):
1351 self.log.warn('vlan-untagging-failure', _reason=_reason)
1352 yield self.core_proxy.device_reason_update(self.device_id, 'omci-flows-deletion-failed-retrying')
Girish Gowdrac5117452020-08-03 11:20:53 -07001353 retry = random.randint(1, 5)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001354 reactor.callLater(retry,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001355 self._remove_vlan_filter_task, device, uni_id,
ozgecanetsiace4e37f2020-07-20 10:16:00 +03001356 uni_port=uni_port, match_vlan=match_vlan, _set_vlan_vid=_set_vlan_vid,
1357 _set_vlan_pcp=_set_vlan_pcp, tp_id=tp_id)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001358
1359 self.log.info("remove_vlan_filter_task", tp_id=tp_id)
1360 vlan_remove_task = BrcmVlanFilterTask(self.omci_agent, self, uni_port, _set_vlan_vid,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001361 match_vlan, _set_vlan_pcp, add_tag=False,
1362 tp_id=tp_id)
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001363 self._deferred = self._onu_omci_device.task_runner.queue_task(vlan_remove_task)
1364 self._deferred.addCallbacks(success, failure)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001365
Matt Jeanneret5e331892019-12-07 21:31:45 -05001366 @inlineCallbacks
Matt Jeannereta32441c2019-03-07 05:16:37 -05001367 def process_inter_adapter_message(self, request):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001368 self.log.debug('process-inter-adapter-message', type=request.header.type, from_topic=request.header.from_topic,
1369 to_topic=request.header.to_topic, to_device_id=request.header.to_device_id)
Matt Jeanneret2101f3d2020-03-12 10:13:06 -04001370
1371 if not self.enabled:
1372 self.log.warn('device-not-activated')
1373 reactor.callLater(0.5, self.process_inter_adapter_message, request)
1374 return
1375
Matt Jeannereta32441c2019-03-07 05:16:37 -05001376 try:
Matt Jeanneret5e331892019-12-07 21:31:45 -05001377
1378 update_onu_state = False
1379
Matt Jeannereta32441c2019-03-07 05:16:37 -05001380 if request.header.type == InterAdapterMessageType.OMCI_REQUEST:
1381 omci_msg = InterAdapterOmciMessage()
1382 request.body.Unpack(omci_msg)
Matteo Scandolod8d73172019-11-26 12:15:15 -07001383 self.log.debug('inter-adapter-recv-omci', omci_msg=hexify(omci_msg.message))
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001384
Matt Jeannereta32441c2019-03-07 05:16:37 -05001385 self.receive_message(omci_msg.message)
1386
1387 elif request.header.type == InterAdapterMessageType.ONU_IND_REQUEST:
1388 onu_indication = OnuIndication()
1389 request.body.Unpack(onu_indication)
Matteo Scandolod8d73172019-11-26 12:15:15 -07001390 self.log.debug('inter-adapter-recv-onu-ind', onu_id=onu_indication.onu_id,
1391 oper_state=onu_indication.oper_state, admin_state=onu_indication.admin_state,
1392 serial_number=onu_indication.serial_number)
Matt Jeannereta32441c2019-03-07 05:16:37 -05001393
Matt Jeanneret5e331892019-12-07 21:31:45 -05001394 update_onu_state = True
1395 self._onu_persisted_state['onu_id'] = onu_indication.onu_id
1396 self._onu_persisted_state['intf_id'] = onu_indication.intf_id
1397 self._onu_persisted_state['admin_state'] = onu_indication.admin_state
Mahir Gunyel45610b42020-03-16 17:29:01 -07001398 self._onu_persisted_state['oper_state'] = onu_indication.oper_state
Matt Jeanneret5e331892019-12-07 21:31:45 -05001399
Matt Jeannereta32441c2019-03-07 05:16:37 -05001400 if onu_indication.oper_state == "up":
Matt Jeanneret5e331892019-12-07 21:31:45 -05001401 yield self.create_interface(onu_indication)
Girish Gowdrae933cd32019-11-21 21:04:41 +05301402 elif onu_indication.oper_state == "down" or onu_indication.oper_state == "unreachable":
Matt Jeanneret5e331892019-12-07 21:31:45 -05001403 yield self.update_interface(onu_indication)
Matt Jeannereta32441c2019-03-07 05:16:37 -05001404 else:
Matteo Scandolod8d73172019-11-26 12:15:15 -07001405 self.log.error("unknown-onu-indication", onu_id=onu_indication.onu_id,
1406 serial_number=onu_indication.serial_number)
Matt Jeannereta32441c2019-03-07 05:16:37 -05001407
Matt Jeanneret3bfebff2019-04-12 18:25:03 -04001408 elif request.header.type == InterAdapterMessageType.TECH_PROFILE_DOWNLOAD_REQUEST:
1409 tech_msg = InterAdapterTechProfileDownloadMessage()
1410 request.body.Unpack(tech_msg)
1411 self.log.debug('inter-adapter-recv-tech-profile', tech_msg=tech_msg)
1412
Matt Jeanneret5e331892019-12-07 21:31:45 -05001413 update_onu_state = self._update_onu_persisted_state(tech_msg.uni_id, tp_path=tech_msg.path)
1414 yield self.load_and_configure_tech_profile(tech_msg.uni_id, tech_msg.path)
Matt Jeanneret3bfebff2019-04-12 18:25:03 -04001415
Girish Gowdrae933cd32019-11-21 21:04:41 +05301416 elif request.header.type == InterAdapterMessageType.DELETE_GEM_PORT_REQUEST:
1417 del_gem_msg = InterAdapterDeleteGemPortMessage()
1418 request.body.Unpack(del_gem_msg)
1419 self.log.debug('inter-adapter-recv-del-gem', gem_del_msg=del_gem_msg)
Girish Gowdrac5117452020-08-03 11:20:53 -07001420 tp_id = self.extract_tp_id_from_path(del_gem_msg.tp_path)
1421 uni_id = del_gem_msg.uni_id
1422 gem_port = self._pon.get_gem_port(del_gem_msg.gem_port_id)
1423 self._tp_state_map_per_uni[uni_id][tp_id].queue_pending_delete_pon_resource(TpState.GEM_ID,
1424 gem_port)
Girish Gowdrae933cd32019-11-21 21:04:41 +05301425 self.delete_tech_profile(uni_id=del_gem_msg.uni_id,
Girish Gowdrac5117452020-08-03 11:20:53 -07001426 gem_port=gem_port,
Girish Gowdrae933cd32019-11-21 21:04:41 +05301427 tp_path=del_gem_msg.tp_path)
1428
1429 elif request.header.type == InterAdapterMessageType.DELETE_TCONT_REQUEST:
1430 del_tcont_msg = InterAdapterDeleteTcontMessage()
1431 request.body.Unpack(del_tcont_msg)
1432 self.log.debug('inter-adapter-recv-del-tcont', del_tcont_msg=del_tcont_msg)
1433
Matt Jeanneret5e331892019-12-07 21:31:45 -05001434 # Removal of the tcont/alloc id mapping represents the removal of the tech profile
1435 update_onu_state = self._update_onu_persisted_state(del_tcont_msg.uni_id, tp_path=None)
Girish Gowdrac5117452020-08-03 11:20:53 -07001436 tp_id = self.extract_tp_id_from_path(del_tcont_msg.tp_path)
1437 uni_id = del_tcont_msg.uni_id
1438 tcont = self._pon.get_tcont(del_tcont_msg.alloc_id)
1439 self._tp_state_map_per_uni[uni_id][tp_id].queue_pending_delete_pon_resource(TpState.ALLOC_ID,
1440 tcont)
Girish Gowdrae933cd32019-11-21 21:04:41 +05301441 self.delete_tech_profile(uni_id=del_tcont_msg.uni_id,
Girish Gowdrac5117452020-08-03 11:20:53 -07001442 tcont=tcont,
Girish Gowdrae933cd32019-11-21 21:04:41 +05301443 tp_path=del_tcont_msg.tp_path)
Matt Jeannereta32441c2019-03-07 05:16:37 -05001444 else:
1445 self.log.error("inter-adapter-unhandled-type", request=request)
1446
Matt Jeanneret5e331892019-12-07 21:31:45 -05001447 if update_onu_state:
1448 try:
1449 self.log.debug('updating-onu-state', device_id=self.device_id,
1450 onu_persisted_state=self._onu_persisted_state)
1451 yield self.onu_kv_client.set(self.device_id, json.dumps(self._onu_persisted_state))
1452 except Exception as e:
1453 self.log.error('could-not-store-onu-state', device_id=self.device_id,
1454 onu_persisted_state=self._onu_persisted_state, e=e)
1455 # at this point omci is started and/or indications being processed
1456 # later indications may have a chance to write this state out again
1457
Matt Jeannereta32441c2019-03-07 05:16:37 -05001458 except Exception as e:
1459 self.log.exception("error-processing-inter-adapter-message", e=e)
1460
Matt Jeanneret5e331892019-12-07 21:31:45 -05001461 def _update_onu_persisted_state(self, uni_id, tp_path):
1462 # persist the uni and tech profile path for later reconciliation. update only if changed
1463 update_onu_state = False
1464 found = False
1465 for entry in self._onu_persisted_state.get('uni_config', list()):
1466 if entry.get('uni_id') == uni_id:
1467 found = True
1468 if entry.get('tp_path') != tp_path:
1469 update_onu_state = True
1470 entry['tp_path'] = tp_path
1471
1472 if not found:
1473 update_onu_state = True
1474 uni_tp = {
1475 'uni_id': uni_id,
1476 'tp_path': tp_path
1477 }
1478 self._onu_persisted_state['uni_config'].append(uni_tp)
1479
1480 return update_onu_state
1481
Matt Jeannereta32441c2019-03-07 05:16:37 -05001482 # Called each time there is an onu "up" indication from the olt handler
1483 @inlineCallbacks
1484 def create_interface(self, onu_indication):
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001485 self.log.info('create-interface', onu_id=onu_indication.onu_id,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001486 serial_number=onu_indication.serial_number)
Amit Ghosh028eb202020-02-17 13:34:00 +00001487
1488 # Ignore if onu_indication is received for an already running ONU
1489 if self._onu_omci_device is not None and self._onu_omci_device.active:
1490 self.log.warn('received-onu-indication-for-active-onu', onu_indication=onu_indication)
1491 return
1492
Matt Jeanneretc083f462019-03-11 15:02:01 -04001493 yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.ACTIVATING,
1494 connect_status=ConnectStatus.REACHABLE)
1495
Matt Jeannereta32441c2019-03-07 05:16:37 -05001496 onu_device = yield self.core_proxy.get_device(self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001497
1498 self.log.debug('starting-openomci-statemachine')
1499 self._subscribe_to_events()
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001500 onu_device.reason = "starting-openomci"
Girish Gowdrae933cd32019-11-21 21:04:41 +05301501 reactor.callLater(1, self._onu_omci_device.start, onu_device)
Mahir Gunyel0e6882a2019-10-16 17:02:39 -07001502 yield self.core_proxy.device_reason_update(self.device_id, onu_device.reason)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001503 self._heartbeat.enabled = True
1504
Matt Jeanneret42dad792020-02-01 09:28:27 -05001505 # Called each time there is an onu "down" indication from the olt handler
Matt Jeannereta32441c2019-03-07 05:16:37 -05001506 @inlineCallbacks
1507 def update_interface(self, onu_indication):
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001508 self.log.info('update-interface', onu_id=onu_indication.onu_id,
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001509 serial_number=onu_indication.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001510
Chaitrashree G Sd73fb9b2019-09-09 20:27:30 -04001511 if onu_indication.oper_state == 'down' or onu_indication.oper_state == "unreachable":
Mahir Gunyeld680cb62020-02-18 10:28:12 -08001512 self.log.debug('stopping-openomci-statemachine', device_id=self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001513 reactor.callLater(0, self._onu_omci_device.stop)
1514
Mahir Gunyel5de33fe2020-03-03 22:38:44 -08001515 self._tp = dict()
1516
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001517 # Let TP download happen again
Girish Gowdrac5117452020-08-03 11:20:53 -07001518 for uni_id in self._tp_state_map_per_uni:
1519 self._tp_state_map_per_uni[uni_id].clear()
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001520
Matt Jeanneretf4113222019-08-14 19:44:34 -04001521 yield self.disable_ports(lock_ports=False)
Mahir Gunyel0e6882a2019-10-16 17:02:39 -07001522 yield self.core_proxy.device_reason_update(self.device_id, "stopping-openomci")
1523 yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.DISCOVERED,
1524 connect_status=ConnectStatus.UNREACHABLE)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001525 else:
1526 self.log.debug('not-changing-openomci-statemachine')
1527
Matt Jeanneretf4113222019-08-14 19:44:34 -04001528 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001529 def disable(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001530 self.log.info('disable', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001531 try:
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001532 yield self.disable_ports(lock_ports=True, device_disabled=True)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001533 yield self.core_proxy.device_reason_update(self.device_id, "omci-admin-lock")
1534 yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.UNKNOWN)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001535 except Exception as e:
Matteo Scandolod8d73172019-11-26 12:15:15 -07001536 self.log.exception('exception-in-onu-disable', exception=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001537
William Kurkian3a206332019-04-29 11:05:47 -04001538 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001539 def reenable(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -05001540 self.log.info('reenable', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001541 try:
Matt Jeanneretf4113222019-08-14 19:44:34 -04001542 yield self.core_proxy.device_state_update(device.id,
1543 oper_status=OperStatus.ACTIVE,
1544 connect_status=ConnectStatus.REACHABLE)
1545 yield self.core_proxy.device_reason_update(self.device_id, 'onu-reenabled')
1546 yield self.enable_ports()
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001547 except Exception as e:
Matteo Scandolod8d73172019-11-26 12:15:15 -07001548 self.log.exception('exception-in-onu-reenable', exception=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001549
William Kurkian3a206332019-04-29 11:05:47 -04001550 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001551 def reboot(self):
1552 self.log.info('reboot-device')
William Kurkian3a206332019-04-29 11:05:47 -04001553 device = yield self.core_proxy.get_device(self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001554 if device.connect_status != ConnectStatus.REACHABLE:
1555 self.log.error("device-unreachable")
1556 return
1557
William Kurkian3a206332019-04-29 11:05:47 -04001558 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001559 def success(_results):
1560 self.log.info('reboot-success', _results=_results)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001561 yield self.core_proxy.device_reason_update(self.device_id, 'rebooting')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001562
1563 def failure(_reason):
1564 self.log.info('reboot-failure', _reason=_reason)
1565
1566 self._deferred = self._onu_omci_device.reboot()
1567 self._deferred.addCallbacks(success, failure)
1568
William Kurkian3a206332019-04-29 11:05:47 -04001569 @inlineCallbacks
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001570 def disable_ports(self, lock_ports=True, device_disabled=False):
Mahir Gunyel0e6882a2019-10-16 17:02:39 -07001571 self.log.info('disable-ports', device_id=self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001572
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001573 # TODO: for now only support the first UNI given no requirement for multiple uni yet. Also needed to reduce flow
1574 # load on the core
Matt Jeanneretf4113222019-08-14 19:44:34 -04001575 for port in self.uni_ports:
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001576 if port.mac_bridge_port_num == 1:
1577 port.operstatus = OperStatus.UNKNOWN
1578 self.log.info('disable-port', device_id=self.device_id, port=port)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001579 yield self.core_proxy.port_state_update(self.device_id, Port.ETHERNET_UNI, port.port_number,
1580 port.operstatus)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001581
1582 if lock_ports is True:
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001583 self.lock_ports(lock=True, device_disabled=device_disabled)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001584
William Kurkian3a206332019-04-29 11:05:47 -04001585 @inlineCallbacks
Mahir Gunyel0e6882a2019-10-16 17:02:39 -07001586 def enable_ports(self):
1587 self.log.info('enable-ports', device_id=self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001588
Matt Jeanneretf4113222019-08-14 19:44:34 -04001589 self.lock_ports(lock=False)
1590
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001591 # TODO: for now only support the first UNI given no requirement for multiple uni yet. Also needed to reduce flow
1592 # load on the core
1593 # Given by default all unis are initially active according to omci alarming, we must mimic this.
Matt Jeanneretf4113222019-08-14 19:44:34 -04001594 for port in self.uni_ports:
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001595 if port.mac_bridge_port_num == 1:
Matt Jeanneretf4113222019-08-14 19:44:34 -04001596 port.operstatus = OperStatus.ACTIVE
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001597 self.log.info('enable-port', device_id=self.device_id, port=port)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001598 yield self.core_proxy.port_state_update(self.device_id, Port.ETHERNET_UNI, port.port_number,
1599 port.operstatus)
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001600
1601 # TODO: Normally we would want any uni ethernet link down or uni ethernet link up alarms to register in the core,
1602 # but practically olt provisioning cannot handle the churn of links up, down, then up again typical on startup.
1603 #
1604 # Basically the link state sequence:
1605 # 1) per omci default alarm state, all unis are initially up (no link down alarms received yet)
1606 # 2) a link state down alarm is received for all uni, given the lock command, and also because most unis have nothing plugged in
1607 # 3) a link state up alarm is received for the uni plugged in.
1608 #
1609 # Given the olt (BAL) has to provision all uni, de-provision all uni, and re-provision one uni in quick succession
1610 # and cannot (bug?), we have to skip this and leave uni ports as assumed active. Also all the link state activity
1611 # would have a ripple effect through the core to the controller as well. And is it really worth it?
1612 '''
Matt Jeanneretf4113222019-08-14 19:44:34 -04001613 @inlineCallbacks
1614 def port_state_handler(self, _topic, msg):
1615 self.log.info("port-state-change", _topic=_topic, msg=msg)
1616
1617 onu_id = msg['onu_id']
1618 port_no = msg['port_number']
1619 serial_number = msg['serial_number']
1620 port_status = msg['port_status']
1621 uni_port = self.uni_port(int(port_no))
1622
1623 self.log.debug("port-state-parsed-message", onu_id=onu_id, port_no=port_no, serial_number=serial_number,
1624 port_status=port_status)
1625
1626 if port_status is True:
1627 uni_port.operstatus = OperStatus.ACTIVE
1628 self.log.info('link-up', device_id=self.device_id, port=uni_port)
1629 else:
1630 uni_port.operstatus = OperStatus.UNKNOWN
1631 self.log.info('link-down', device_id=self.device_id, port=uni_port)
1632
1633 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 -05001634 '''
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001635
1636 # Called just before openomci state machine is started. These listen for events from selected state machines,
1637 # most importantly, mib in sync. Which ultimately leads to downloading the mib
1638 def _subscribe_to_events(self):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001639 self.log.debug('subscribe-to-events')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001640
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001641 bus = self._onu_omci_device.event_bus
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001642
1643 # OMCI MIB Database sync status
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001644 topic = OnuDeviceEntry.event_bus_topic(self.device_id,
1645 OnuDeviceEvents.MibDatabaseSyncEvent)
1646 self._in_sync_subscription = bus.subscribe(topic, self.in_sync_handler)
1647
1648 # OMCI Capabilities
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001649 topic = OnuDeviceEntry.event_bus_topic(self.device_id,
1650 OnuDeviceEvents.OmciCapabilitiesEvent)
1651 self._capabilities_subscription = bus.subscribe(topic, self.capabilties_handler)
1652
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001653 # TODO: these alarms seem to be unreliable depending on the environment
1654 # 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 -08001655 # topic = OnuDeviceEntry.event_bus_topic(self.device_id,
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001656 # OnuDeviceEvents.PortEvent)
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08001657 # self._port_state_subscription = bus.subscribe(topic, self.port_state_handler)
Matt Jeanneretfc6cdef2020-02-14 10:14:36 -05001658
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001659 # Called when the mib is in sync
1660 def in_sync_handler(self, _topic, msg):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001661 self.log.debug('in-sync-handler', _topic=_topic, msg=msg)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001662 if self._in_sync_subscription is not None:
1663 try:
1664 in_sync = msg[IN_SYNC_KEY]
1665
1666 if in_sync:
1667 # Only call this once
1668 bus = self._onu_omci_device.event_bus
1669 bus.unsubscribe(self._in_sync_subscription)
1670 self._in_sync_subscription = None
1671
1672 # Start up device_info load
1673 self.log.debug('running-mib-sync')
1674 reactor.callLater(0, self._mib_in_sync)
1675
1676 except Exception as e:
1677 self.log.exception('in-sync', e=e)
1678
1679 def capabilties_handler(self, _topic, _msg):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001680 self.log.debug('capabilities-handler', _topic=_topic, msg=_msg)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001681 if self._capabilities_subscription is not None:
1682 self.log.debug('capabilities-handler-done')
1683
1684 # 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 -04001685 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001686 def _mib_in_sync(self):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001687 self.log.debug('mib-in-sync')
Matt Jeanneretc083f462019-03-11 15:02:01 -04001688 device = yield self.core_proxy.get_device(self.device_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001689
Matt Jeanneret5e331892019-12-07 21:31:45 -05001690 # only notify core if this is a new device. otherwise do not have reconcile generating
1691 # a lot of needless message churn
1692 if not self._reconciling:
1693 yield self.core_proxy.device_reason_update(self.device_id, 'discovery-mibsync-complete')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001694
1695 if self._dev_info_loaded:
Matt Jeanneret5e331892019-12-07 21:31:45 -05001696 self.log.debug('device-info-already-loaded')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001697 else:
Matt Jeanneret5e331892019-12-07 21:31:45 -05001698 # new onu or adapter was restarted. fill up our local data
1699 yield self._load_device_data(device)
1700
1701 if self._check_mib_downloaded():
1702 self.log.debug('mib-already-downloaded')
1703 if not self._reconciling:
1704 yield self.core_proxy.device_state_update(device.id,
1705 oper_status=OperStatus.ACTIVE,
1706 connect_status=ConnectStatus.REACHABLE)
1707 yield self.enable_ports()
1708 else:
1709 self._download_mib(device)
1710
1711 if self._reconciling:
1712 yield self._restore_tech_profile()
1713 self._start_monitoring()
1714 self._reconciling = False
1715 self.log.debug('reconcile-finished')
1716
1717 def _download_mib(self, device):
1718 self.log.debug('downloading-initial-mib-configuration')
1719
1720 @inlineCallbacks
1721 def success(_results):
1722 self.log.debug('mib-download-success', _results=_results)
1723 yield self.core_proxy.device_state_update(device.id,
1724 oper_status=OperStatus.ACTIVE,
1725 connect_status=ConnectStatus.REACHABLE)
1726 yield self.core_proxy.device_reason_update(self.device_id, 'initial-mib-downloaded')
1727 self._mib_download_task = None
1728 yield self.enable_ports()
1729 yield self.onu_active_event()
1730 self._start_monitoring()
1731
1732 @inlineCallbacks
1733 def failure(_reason):
1734 self.log.warn('mib-download-failure-retrying', _reason=_reason)
1735 retry = _STARTUP_RETRY_WAIT * (random.randint(1, 5))
1736 reactor.callLater(retry, self._mib_in_sync)
1737 yield self.core_proxy.device_reason_update(self.device_id, 'initial-mib-download-failure-retrying')
1738
1739 # start by locking all the unis till mib sync and initial mib is downloaded
1740 # this way we can capture the port down/up events when we are ready
1741 self.lock_ports(lock=True)
1742
1743 # Download an initial mib that creates simple bridge that can pass EAP. On success (above) finally set
1744 # the device to active/reachable. This then opens up the handler to openflow pushes from outside
1745 self._mib_download_task = BrcmMibDownloadTask(self.omci_agent, self)
1746 self._deferred = self._onu_omci_device.task_runner.queue_task(self._mib_download_task)
1747 self._deferred.addCallbacks(success, failure)
1748
1749 def _start_monitoring(self):
1750 self.log.debug('starting-monitoring')
1751
1752 # Start collecting stats from the device after a brief pause
1753 if not self._pm_metrics_started:
1754 self._pm_metrics_started = True
Rohan Agrawal36a4e442020-06-29 11:10:32 +00001755 pmstart = _STARTUP_RETRY_WAIT * (random.randint(1, self._pm_metrics.max_skew))
Matt Jeanneret5e331892019-12-07 21:31:45 -05001756 reactor.callLater(pmstart, self._pm_metrics.start_collector)
1757
1758 # Start test requests after a brief pause
1759 if not self._test_request_started:
1760 self._test_request_started = True
1761 tststart = _STARTUP_RETRY_WAIT * (random.randint(1, 5))
1762 reactor.callLater(tststart, self._test_request.start_collector)
1763
1764 def _check_mib_downloaded(self):
1765 self.log.debug('checking-mib-downloaded')
1766 results = False
1767
1768 mac_bridges = self.onu_omci_device.query_mib(MacBridgeServiceProfile.class_id)
1769 self.log.debug('mac-bridges', mac_bridges=mac_bridges)
1770
1771 for k, v in mac_bridges.items():
1772 if not isinstance(v, dict):
1773 continue
1774 # found at least one mac bridge, good enough to say its done, break out
1775 self.log.debug('found-mac-bridge-mib-download-has-been-done', omci_key=k, omci_value=v)
1776 results = True
1777 break
1778
1779 return results
1780
1781 @inlineCallbacks
1782 def _load_device_data(self, device):
1783 self.log.debug('loading-device-data-from-mib', device_id=device.id)
1784
1785 omci_dev = self._onu_omci_device
1786 config = omci_dev.configuration
1787
1788 try:
1789 # sort the lists so we get consistent port ordering.
1790 ani_list = sorted(config.ani_g_entities) if config.ani_g_entities else []
1791 uni_list = sorted(config.uni_g_entities) if config.uni_g_entities else []
1792 pptp_list = sorted(config.pptp_entities) if config.pptp_entities else []
1793 veip_list = sorted(config.veip_entities) if config.veip_entities else []
1794
1795 if ani_list is None or (pptp_list is None and veip_list is None):
1796 yield self.core_proxy.device_reason_update(self.device_id, 'onu-missing-required-elements')
1797 raise Exception("onu-missing-required-elements")
1798
1799 # Currently logging the ani, pptp, veip, and uni for information purposes.
1800 # Actually act on the veip/pptp as its ME is the most correct one to use in later tasks.
1801 # And in some ONU the UNI-G list is incomplete or incorrect...
1802 for entity_id in ani_list:
1803 ani_value = config.ani_g_entities[entity_id]
1804 self.log.debug("discovered-ani", entity_id=entity_id, value=ani_value)
1805
1806 for entity_id in uni_list:
1807 uni_value = config.uni_g_entities[entity_id]
1808 self.log.debug("discovered-uni", entity_id=entity_id, value=uni_value)
1809
1810 uni_entities = OrderedDict()
1811 for entity_id in pptp_list:
1812 pptp_value = config.pptp_entities[entity_id]
1813 self.log.debug("discovered-pptp", entity_id=entity_id, value=pptp_value)
1814 uni_entities[entity_id] = UniType.PPTP
1815
1816 for entity_id in veip_list:
1817 veip_value = config.veip_entities[entity_id]
1818 self.log.debug("discovered-veip", entity_id=entity_id, value=veip_value)
1819 uni_entities[entity_id] = UniType.VEIP
1820
1821 uni_id = 0
1822 for entity_id, uni_type in uni_entities.items():
1823 yield self._add_uni_port(device, entity_id, uni_id, uni_type)
Girish Gowdrac5117452020-08-03 11:20:53 -07001824 self._tp_state_map_per_uni[uni_id] = dict()
Matt Jeanneret5e331892019-12-07 21:31:45 -05001825 uni_id += 1
1826
1827 if self._unis:
1828 self._dev_info_loaded = True
1829 else:
1830 yield self.core_proxy.device_reason_update(self.device_id, 'no-usable-unis')
1831 raise Exception("no-usable-unis")
1832
1833 except Exception as e:
1834 self.log.exception('device-info-load', e=e)
1835 self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT, self._mib_in_sync)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001836
Matt Jeanneretc083f462019-03-11 15:02:01 -04001837 @inlineCallbacks
1838 def _add_uni_port(self, device, entity_id, uni_id, uni_type=UniType.PPTP):
Matt Jeanneret5e331892019-12-07 21:31:45 -05001839 self.log.debug('add-uni-port', entity_id=entity_id, uni_id=uni_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001840
Matt Jeanneret5e331892019-12-07 21:31:45 -05001841 intf_id = self._onu_persisted_state.get('intf_id')
1842 onu_id = self._onu_persisted_state.get('onu_id')
1843 uni_no = self.mk_uni_port_num(intf_id, onu_id, uni_id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001844
1845 # TODO: Some or parts of this likely need to move to UniPort. especially the format stuff
1846 uni_name = "uni-{}".format(uni_no)
1847
Girish Gowdrae933cd32019-11-21 21:04:41 +05301848 mac_bridge_port_num = uni_id + 1 # TODO +1 is only to test non-zero index
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001849
1850 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 -04001851 entity_id=entity_id, mac_bridge_port_num=mac_bridge_port_num, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001852
Girish Gowdra5b499342020-06-16 14:45:51 -07001853 uni_port = UniPort.create(self, uni_name, uni_id, uni_no, uni_name,
1854 device.parent_port_no, device.serial_number,
1855 uni_type,)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001856 uni_port.entity_id = entity_id
1857 uni_port.enabled = True
1858 uni_port.mac_bridge_port_num = mac_bridge_port_num
1859
1860 self.log.debug("created-uni-port", uni=uni_port)
1861
Matt Jeanneret5e331892019-12-07 21:31:45 -05001862 if not self._reconciling:
1863 yield self.core_proxy.port_created(device.id, uni_port.get_port())
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001864
1865 self._unis[uni_port.port_number] = uni_port
1866
Matt Jeanneret5e331892019-12-07 21:31:45 -05001867 self._onu_omci_device.alarm_synchronizer.set_alarm_params(onu_id=onu_id,
Girish Gowdrae933cd32019-11-21 21:04:41 +05301868 uni_ports=self.uni_ports,
1869 serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001870
Matt Jeanneret5e331892019-12-07 21:31:45 -05001871 @inlineCallbacks
1872 def _restore_tech_profile(self):
1873 self.log.debug("reconcile-restoring-tech-profile-tcont-gem-config")
1874
1875 # for every uni that has tech profile config reload all its tcont/alloc_id and gem from the tp path
1876 for entry in self._onu_persisted_state.get('uni_config', list()):
1877 uni_id = entry.get('uni_id')
1878 tp_path = entry.get('tp_path')
1879 if tp_path:
1880 tpstored = yield self.tp_kv_client.get(tp_path)
1881 tpstring = tpstored.decode('ascii')
1882 tp = json.loads(tpstring)
1883
1884 self.log.debug("restoring-tp-instance", tp=tp)
1885
1886 # re-run tech profile config that stores gem and tconts in the self._pon object
1887 # this does not actually re-run the omci, just rebuilds our local data store
1888 self._do_tech_profile_configuration(uni_id, tp)
1889
1890 tp_id = self.extract_tp_id_from_path(tp_path)
1891
1892 # rebuild cache dicts so tp updates and deletes dont get KeyErrors
Girish Gowdrac5117452020-08-03 11:20:53 -07001893 if uni_id not in self._tp_state_map_per_uni:
1894 self._tp_state_map_per_uni[uni_id] = dict()
Matt Jeanneret5e331892019-12-07 21:31:45 -05001895
Girish Gowdrac5117452020-08-03 11:20:53 -07001896 if tp_id not in self._tp_state_map_per_uni[uni_id]:
1897 self._tp_state_map_per_uni[uni_id][tp_id] = TpState(self, uni_id, tp_path)
Matt Jeanneret5e331892019-12-07 21:31:45 -05001898
Girish Gowdrac5117452020-08-03 11:20:53 -07001899 self._tp_state_map_per_uni[uni_id][tp_id].tp_setup_done = True
Matt Jeanneret5e331892019-12-07 21:31:45 -05001900 else:
1901 self.log.debug("no-assigned-tp-instance", uni_id=uni_id)
1902
1903 # for every loaded tcont from tp check the mib database for its entity_id
1904 # needed for later tp deletes/adds
1905 tcont_idents = self.onu_omci_device.query_mib(Tcont.class_id)
1906 self.log.debug('tcont-idents', tcont_idents=tcont_idents)
1907
1908 for k, v in tcont_idents.items():
1909 if not isinstance(v, dict):
1910 continue
1911 alloc_check = v.get('attributes', {}).get('alloc_id', 0)
1912 tcont = self._pon.tconts.get(alloc_check)
1913 if tcont:
1914 tcont.entity_id = k
1915 self.log.debug('reassigning-tcont-entity-id', entity_id=tcont.entity_id,
1916 alloc_id=tcont.alloc_id)
1917
Matt Jeanneretc083f462019-03-11 15:02:01 -04001918 # TODO NEW CORE: Figure out how to gain this knowledge from the olt. for now cheat terribly.
1919 def mk_uni_port_num(self, intf_id, onu_id, uni_id):
Amit Ghosh65400f12019-11-21 12:04:12 +00001920 MAX_PONS_PER_OLT = 256
1921 MAX_ONUS_PER_PON = 256
Matt Jeanneretc083f462019-03-11 15:02:01 -04001922 MAX_UNIS_PER_ONU = 16
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001923
Matt Jeanneretc083f462019-03-11 15:02:01 -04001924 assert intf_id < MAX_PONS_PER_OLT
1925 assert onu_id < MAX_ONUS_PER_PON
1926 assert uni_id < MAX_UNIS_PER_ONU
Amit Ghosh65400f12019-11-21 12:04:12 +00001927 return intf_id << 12 | onu_id << 4 | uni_id
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04001928
1929 @inlineCallbacks
Devmalya Paulffc89df2019-07-31 17:43:13 -04001930 def onu_active_event(self):
Matteo Scandolod8d73172019-11-26 12:15:15 -07001931 self.log.debug('onu-active-event')
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04001932 try:
Matt Jeanneret5e331892019-12-07 21:31:45 -05001933 # TODO: this is expensive for just getting the olt serial number. replace with direct api call
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04001934 parent_device = yield self.core_proxy.get_device(self.parent_id)
1935 olt_serial_number = parent_device.serial_number
Devmalya Paulffc89df2019-07-31 17:43:13 -04001936 raised_ts = arrow.utcnow().timestamp
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04001937
Matt Jeanneret5e331892019-12-07 21:31:45 -05001938 intf_id = self._onu_persisted_state.get('intf_id')
1939 onu_id = self._onu_persisted_state.get('onu_id')
1940 onu_serial = self._onu_persisted_state.get('serial_number')
1941
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04001942 self.log.debug("onu-indication-context-data",
Matt Jeanneret5e331892019-12-07 21:31:45 -05001943 pon_id=intf_id,
1944 onu_id=onu_id,
Girish Gowdrae933cd32019-11-21 21:04:41 +05301945 registration_id=self.device_id,
1946 device_id=self.device_id,
Matt Jeanneret5e331892019-12-07 21:31:45 -05001947 onu_serial_number=onu_serial,
Girish Gowdrae933cd32019-11-21 21:04:41 +05301948 olt_serial_number=olt_serial_number,
1949 raised_ts=raised_ts)
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04001950
Devmalya Paulffc89df2019-07-31 17:43:13 -04001951 self.log.debug("Trying-to-raise-onu-active-event")
1952 OnuActiveEvent(self.events, self.device_id,
Matt Jeanneret5e331892019-12-07 21:31:45 -05001953 intf_id,
1954 onu_serial,
Devmalya Paul7e0be4a2019-05-08 05:18:04 -04001955 str(self.device_id),
Girish Gowdrae933cd32019-11-21 21:04:41 +05301956 olt_serial_number, raised_ts,
Matt Jeanneret5e331892019-12-07 21:31:45 -05001957 onu_id=onu_id).send(True)
Devmalya Paulffc89df2019-07-31 17:43:13 -04001958 except Exception as active_event_error:
1959 self.log.exception('onu-activated-event-error',
Devmalya Paul1e1b1722020-05-07 02:51:15 -04001960 errmsg=active_event_error)
Matt Jeanneretf4113222019-08-14 19:44:34 -04001961
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001962 @inlineCallbacks
1963 def onu_disabled_event(self):
1964 self.log.debug('onu-disabled-event')
1965 try:
1966 device = yield self.core_proxy.get_device(self.device_id)
1967 parent_device = yield self.core_proxy.get_device(self.parent_id)
1968 olt_serial_number = parent_device.serial_number
1969 raised_ts = arrow.utcnow().timestamp
Devmalya Paul1e1b1722020-05-07 02:51:15 -04001970 intf_id = self._onu_persisted_state.get('intf_id')
1971 onu_id = self._onu_persisted_state.get('onu_id')
1972 onu_serial = self._onu_persisted_state.get('serial_number')
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001973
1974 self.log.debug("onu-indication-context-data",
Devmalya Paul1e1b1722020-05-07 02:51:15 -04001975 pon_id=intf_id,
1976 onu_id=onu_id,
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001977 registration_id=self.device_id,
1978 device_id=self.device_id,
Devmalya Paul1e1b1722020-05-07 02:51:15 -04001979 onu_serial_number=onu_serial,
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001980 olt_serial_number=olt_serial_number,
1981 raised_ts=raised_ts)
1982
1983 self.log.debug("Trying-to-raise-onu-disabled-event")
1984 OnuDisabledEvent(self.events, self.device_id,
Devmalya Paul1e1b1722020-05-07 02:51:15 -04001985 intf_id,
Girish Gowdradc98d812020-03-20 13:04:58 -07001986 device.serial_number,
1987 str(self.device_id),
1988 olt_serial_number, raised_ts,
Devmalya Paul1e1b1722020-05-07 02:51:15 -04001989 onu_id=onu_id).send(True)
1990 except Exception as disable_event_error:
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04001991 self.log.exception('onu-disabled-event-error',
Devmalya Paul1e1b1722020-05-07 02:51:15 -04001992 errmsg=disable_event_error)
1993
1994 @inlineCallbacks
1995 def onu_deleted_event(self):
1996 self.log.debug('onu-deleted-event')
1997 try:
1998 device = yield self.core_proxy.get_device(self.device_id)
1999 parent_device = yield self.core_proxy.get_device(self.parent_id)
2000 olt_serial_number = parent_device.serial_number
2001 raised_ts = arrow.utcnow().timestamp
2002 intf_id = self._onu_persisted_state.get('intf_id')
2003 onu_id = self._onu_persisted_state.get('onu_id')
2004 serial_number = self._onu_persisted_state.get('serial_number')
2005
2006 self.log.debug("onu-deleted-event-context-data",
2007 pon_id=intf_id,
2008 onu_id=onu_id,
2009 registration_id=self.device_id,
2010 device_id=self.device_id,
2011 onu_serial_number=serial_number,
2012 olt_serial_number=olt_serial_number,
2013 raised_ts=raised_ts)
2014
2015 OnuDeletedEvent(self.events, self.device_id,
2016 intf_id,
2017 serial_number,
2018 str(self.device_id),
2019 olt_serial_number, raised_ts,
2020 onu_id=onu_id).send(True)
2021 except Exception as deleted_event_error:
2022 self.log.exception('onu-deleted-event-error',
2023 errmsg=deleted_event_error)
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002024
2025 def lock_ports(self, lock=True, device_disabled=False):
Matt Jeanneretf4113222019-08-14 19:44:34 -04002026
2027 def success(response):
2028 self.log.debug('set-onu-ports-state', lock=lock, response=response)
Devmalya Paule2e5f2b2020-03-08 18:50:33 -04002029 if device_disabled:
2030 self.onu_disabled_event()
Matt Jeanneretf4113222019-08-14 19:44:34 -04002031
2032 def failure(response):
2033 self.log.error('cannot-set-onu-ports-state', lock=lock, response=response)
2034
2035 task = BrcmUniLockTask(self.omci_agent, self.device_id, lock=lock)
2036 self._deferred = self._onu_omci_device.task_runner.queue_task(task)
2037 self._deferred.addCallbacks(success, failure)
Mahir Gunyele9110a32020-02-20 14:56:50 -08002038
2039 def extract_tp_id_from_path(self, tp_path):
2040 # tp_path is of the format <technology>/<table_id>/<uni_port_name>
Girish Gowdra4c11ddb2020-03-03 11:33:24 -08002041 tp_id = int(tp_path.split(_PATH_SEPERATOR)[1])
2042 return tp_id
onkarkundargia1e2af22020-01-27 11:51:43 +05302043
2044 def start_omci_test_action(self, device, uuid):
2045 """
2046
2047 :param device:
2048 :return:
2049 """
2050 # Code to Run OMCI Test Action
2051 self.log.info('Omci-test-action-request-On', request=device.id)
2052 kwargs_omci_test_action = {
2053 OmciTestRequest.DEFAULT_FREQUENCY_KEY:
2054 OmciTestRequest.DEFAULT_COLLECTION_FREQUENCY
2055 }
2056 serial_number = device.serial_number
2057 if device.connect_status != ConnectStatus.REACHABLE or device.admin_state != AdminState.ENABLED:
2058 return (TestResponse(result=TestResponse.FAILURE))
2059 test_request = OmciTestRequest(self.core_proxy,
2060 self.omci_agent, self.device_id, AniG,
2061 serial_number,
2062 self.logical_device_id, exclusive=False,
2063 uuid=uuid,
2064 **kwargs_omci_test_action)
2065 test_request.perform_test_omci()
2066 return (TestResponse(result=TestResponse.SUCCESS))