blob: 70cb12e5b64eea6115573229da85eb83ac999f54 [file] [log] [blame]
Himani Chawlaac1f5ad2021-02-04 21:21:54 +05301/*
2 * Copyright 2021-present Open Networking Foundation
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//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
19
20import (
21 "context"
22 "errors"
23 "fmt"
Himani Chawlaa2592fe2021-02-25 10:54:36 +053024 "github.com/looplab/fsm"
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053025 "github.com/opencord/omci-lib-go"
26 me "github.com/opencord/omci-lib-go/generated"
27 "github.com/opencord/voltha-lib-go/v4/pkg/events/eventif"
28 "github.com/opencord/voltha-lib-go/v4/pkg/log"
29 "github.com/opencord/voltha-protos/v4/go/voltha"
Himani Chawlaa2592fe2021-02-25 10:54:36 +053030 "reflect"
31 "sync"
32 "time"
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053033)
34
35const (
36 circuitPackClassID = me.CircuitPackClassID
37 physicalPathTerminationPointEthernetUniClassID = me.PhysicalPathTerminationPointEthernetUniClassID
38 onuGClassID = me.OnuGClassID
39 aniGClassID = me.AniGClassID
Himani Chawlaa2592fe2021-02-25 10:54:36 +053040 auditInterval = 300
41 defaultTimeoutDelay = 10
42 alarmBitMapSizeBytes = 28
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053043)
44
Himani Chawlaa2592fe2021-02-25 10:54:36 +053045const (
46 // events of alarm sync FSM
47 asEvStart = "asEvStart"
48 asEvStop = "asEvStop"
49 asEvAudit = "asEvAudit"
50 asEvSync = "asEvSync"
51 asEvSuccess = "asEvSuccess"
52 asEvFailure = "asEvFailure"
53 asEvResync = "asEvResync"
54)
55const (
56 // states of alarm sync FSM
57 asStStarting = "asStStarting"
58 asStDisabled = "asStDisabled"
59 asStInSync = "asStInSync"
60 asStAuditing = "asStAuditing"
61 asStResynchronizing = "asStResynchronizing"
62 asStIdle = "asStIdle"
63)
64
65//const cAsFsmIdleState = asStIdle not using idle state currently
66
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053067type alarmInfo struct {
68 classID me.ClassID
69 instanceID uint16
70 alarmNo uint8
71}
72
73type alarms map[alarmInfo]struct{}
74
Himani Chawlaa2592fe2021-02-25 10:54:36 +053075type meAlarmKey struct {
76 classID me.ClassID
77 instanceID uint16
78}
79
80type alarmBitMapDB map[meAlarmKey][alarmBitMapSizeBytes]byte
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053081type onuAlarmManager struct {
82 pDeviceHandler *deviceHandler
83 eventProxy eventif.EventProxy
84 stopProcessingOmciMessages chan bool
85 eventChannel chan Message
86 onuAlarmManagerLock sync.RWMutex
87 processMessage bool
88 activeAlarms alarms
Himani Chawlaa2592fe2021-02-25 10:54:36 +053089 alarmBitMapDB alarmBitMapDB
Himani Chawla4c1d4c72021-02-18 12:14:31 +053090 onuEventsList map[onuDevice]onuDeviceEvent
Himani Chawlaa2592fe2021-02-25 10:54:36 +053091 lastAlarmSequence uint8
92 alarmSyncFsm *AdapterFsm
93 oltDbCopy alarmBitMapDB
94 onuDBCopy alarmBitMapDB
95 bufferedNotifications []*omci.AlarmNotificationMsg
96 alarmUploadSeqNo uint16
97 alarmUploadNoOfCmds uint16
98 stopAlarmAuditTimer chan struct{}
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053099}
100
101type onuDevice struct {
102 classID me.ClassID
103 alarmno uint8
104}
105type onuDeviceEvent struct {
106 EventName string
107 EventCategory eventif.EventCategory
108 EventSubCategory eventif.EventSubCategory
109 EventDescription string
110}
111
112func newAlarmManager(ctx context.Context, dh *deviceHandler) *onuAlarmManager {
113 var alarmManager onuAlarmManager
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530114 logger.Debugw(ctx, "init-alarm-manager", log.Fields{"device-id": dh.deviceID})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530115 alarmManager.pDeviceHandler = dh
116 alarmManager.eventProxy = dh.EventProxy // Or event proxy should be on cluster address ??
117 alarmManager.eventChannel = make(chan Message)
118 alarmManager.stopProcessingOmciMessages = make(chan bool)
119 alarmManager.processMessage = false
120 alarmManager.activeAlarms = make(map[alarmInfo]struct{})
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530121 alarmManager.alarmBitMapDB = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
122 alarmManager.stopAlarmAuditTimer = make(chan struct{})
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530123 alarmManager.onuEventsList = map[onuDevice]onuDeviceEvent{
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530124 {classID: circuitPackClassID, alarmno: 0}: {EventName: "ONU_EQUIPMENT",
125 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu equipment"},
126 {classID: circuitPackClassID, alarmno: 2}: {EventName: "ONU_SELF_TEST_FAIL",
127 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu self-test failure"},
128 {classID: circuitPackClassID, alarmno: 3}: {EventName: "ONU_LASER_EOL",
129 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu laser EOL"},
130 {classID: circuitPackClassID, alarmno: 4}: {EventName: "ONU_TEMP_YELLOW",
131 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature yellow"},
132 {classID: circuitPackClassID, alarmno: 5}: {EventName: "ONU_TEMP_RED",
133 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature red"},
134 {classID: physicalPathTerminationPointEthernetUniClassID, alarmno: 0}: {EventName: "ONU_Ethernet_UNI", EventCategory: voltha.EventCategory_EQUIPMENT,
135 EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "LAN Loss Of Signal"},
136 {classID: onuGClassID, alarmno: 0}: {EventName: "ONU_EQUIPMENT",
137 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu equipment"},
138 {classID: onuGClassID, alarmno: 6}: {EventName: "ONU_SELF_TEST_FAIL",
139 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu self-test failure"},
140 {classID: onuGClassID, alarmno: 7}: {EventName: "ONU_DYING_GASP",
141 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu DYING_GASP"},
142 {classID: onuGClassID, alarmno: 8}: {EventName: "ONU_TEMP_YELLOW",
143 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature yellow"},
144 {classID: onuGClassID, alarmno: 9}: {EventName: "ONU_TEMP_RED",
145 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature red"},
146 {classID: onuGClassID, alarmno: 10}: {EventName: "ONU_VOLTAGE_YELLOW",
147 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu voltage yellow"},
148 {classID: onuGClassID, alarmno: 11}: {EventName: "ONU_VOLTAGE_RED",
149 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu voltage red"},
150 {classID: aniGClassID, alarmno: 0}: {EventName: "ONU_LOW_RX_OPTICAL",
151 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu low rx optical power"},
152 {classID: aniGClassID, alarmno: 1}: {EventName: "ONU_HIGH_RX_OPTICAL",
153 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu high rx optical power"},
154 {classID: aniGClassID, alarmno: 4}: {EventName: "ONU_LOW_TX_OPTICAL",
155 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu low tx optical power"},
156 {classID: aniGClassID, alarmno: 5}: {EventName: "ONU_HIGH_TX_OPTICAL",
157 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu high tx optical power"},
158 {classID: aniGClassID, alarmno: 6}: {EventName: "ONU_LASER_BIAS_CURRENT",
159 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu laser bias current"},
160 }
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530161 alarmManager.alarmSyncFsm.pFsm = fsm.NewFSM(
162 asStDisabled,
163 fsm.Events{
164 {Name: asEvStart, Src: []string{asStDisabled}, Dst: asStStarting},
165 {Name: asEvAudit, Src: []string{asStStarting, asStInSync}, Dst: asStAuditing},
166 {Name: asEvSync, Src: []string{asStStarting}, Dst: asStInSync},
167 {Name: asEvSuccess, Src: []string{asStAuditing, asStResynchronizing}, Dst: asStInSync},
168 {Name: asEvFailure, Src: []string{asStAuditing, asStResynchronizing}, Dst: asStAuditing},
169 {Name: asEvResync, Src: []string{asStAuditing}, Dst: asStResynchronizing},
170 {Name: asEvStop, Src: []string{asStDisabled, asStStarting, asStAuditing, asStInSync, asStIdle, asStResynchronizing}, Dst: asStDisabled},
171 },
172 fsm.Callbacks{
173 "enter_state": func(e *fsm.Event) { alarmManager.alarmSyncFsm.logFsmStateChange(ctx, e) },
174 "enter_" + asStStarting: func(e *fsm.Event) { alarmManager.asFsmStarting(ctx, e) },
175 "enter_" + asStAuditing: func(e *fsm.Event) { alarmManager.asFsmAuditing(ctx, e) },
176 "enter_" + asStInSync: func(e *fsm.Event) { alarmManager.asFsmInSync(ctx, e) },
177 "enter_" + asStResynchronizing: func(e *fsm.Event) { alarmManager.asFsmResynchronizing(ctx, e) },
178 },
179 )
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530180 return &alarmManager
181}
182
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530183func (am *onuAlarmManager) asFsmStarting(ctx context.Context, e *fsm.Event) {
184 logger.Debugw(ctx, "alarm-sync-fsm-start-processing-msgs-in-state", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
185 go am.processAlarmSyncMessages(ctx)
186 // Start the first audit, if audit interval configured, else reach the sync state
187 if auditInterval > 0 {
188 select {
189 //Transition into auditing state, using a very shorter timeout delay here, hence it is the first audit
190 case <-time.After(defaultTimeoutDelay * time.Second):
191 go func() {
192 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
193 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
194 }
195 }()
196 case <-am.stopAlarmAuditTimer:
197 logger.Infow(ctx, "stopping-alarm-timer", log.Fields{"device-id": am.pDeviceHandler.deviceID})
198 return
199 }
200 } else {
201 // Transition into sync state directly.
202 go func() {
203 if err := am.alarmSyncFsm.pFsm.Event(asEvSync); err != nil {
204 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
205 }
206 }()
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530207 }
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530208}
209
210func (am *onuAlarmManager) asFsmAuditing(ctx context.Context, e *fsm.Event) {
211 logger.Debugw(ctx, "alarm-sync-fsm-start-auditing", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
212 // Always reset the buffered notifications and db copies before starting the audit
213 am.onuAlarmManagerLock.Lock()
214 am.bufferedNotifications = make([]*omci.AlarmNotificationMsg, 0)
215 am.oltDbCopy = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
216 am.onuDBCopy = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
217 am.onuAlarmManagerLock.Unlock()
218 failureTransition := func() {
219 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
220 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
221 }
222 }
223 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarm(log.WithSpanFromContext(context.TODO(), ctx), 0,
224 am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
225 // Transition to failure so that alarm sync can be restarted again
226 go failureTransition()
227 }
228}
229
230func (am *onuAlarmManager) asFsmResynchronizing(ctx context.Context, e *fsm.Event) {
231 failureTransition := func() {
232 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
233 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
234 }
235 }
236 // See if there is any onu only diff, meaning the class and entity is only in onu DB
237 for alarm := range am.onuDBCopy {
238 if _, exists := am.oltDbCopy[meAlarmKey{
239 classID: alarm.classID,
240 instanceID: alarm.instanceID,
241 }]; !exists {
242 // We need to raise all such alarms as OLT wont have received notification for these alarms
243 omciAlarmMessage := &omci.AlarmNotificationMsg{
244 MeBasePacket: omci.MeBasePacket{
245 EntityClass: alarm.classID,
246 EntityInstance: alarm.instanceID,
247 },
248 AlarmBitmap: am.onuDBCopy[alarm],
249 }
250 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
251 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
252 // Transition to failure.
253 go failureTransition()
254 return
255 }
256 }
257 }
258 // See if there is any olt only diff, meaning the class and entity is only in olt DB
259 for alarm := range am.oltDbCopy {
260 if _, exists := am.onuDBCopy[meAlarmKey{
261 classID: alarm.classID,
262 instanceID: alarm.instanceID,
263 }]; !exists {
264 // We need to clear all such alarms as OLT might have stale data and the alarms are already cleared.
265 omciAlarmMessage := &omci.AlarmNotificationMsg{
266 MeBasePacket: omci.MeBasePacket{
267 EntityClass: alarm.classID,
268 EntityInstance: alarm.instanceID,
269 },
270 AlarmBitmap: am.oltDbCopy[alarm],
271 }
272 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
273 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
274 // Transition to failure
275 go failureTransition()
276 return
277 }
278 }
279 }
280 // See if there is any attribute difference
281 for alarm := range am.onuDBCopy {
282 if _, exists := am.oltDbCopy[alarm]; exists {
283 if am.onuDBCopy[alarm] != am.oltDbCopy[alarm] {
284 omciAlarmMessage := &omci.AlarmNotificationMsg{
285 MeBasePacket: omci.MeBasePacket{
286 EntityClass: alarm.classID,
287 EntityInstance: alarm.instanceID,
288 },
289 AlarmBitmap: am.onuDBCopy[alarm],
290 }
291 // We will assume that onudb is correct always in this case and process the changed bitmap.
292 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
293 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
294 // Transition to failure
295 go failureTransition()
296 return
297 }
298 }
299 }
300 }
301 // Send the buffered notifications if no failure.
302 for _, notif := range am.bufferedNotifications {
303 if err := am.processAlarmData(ctx, notif); err != nil {
304 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
305 go failureTransition()
306 }
307 }
308 go func() {
309 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
310 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
311 }
312 }()
313}
314
315func (am *onuAlarmManager) asFsmInSync(ctx context.Context, e *fsm.Event) {
316 logger.Debugw(ctx, "alarm-sync-fsm", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
317 if auditInterval > 0 {
318 select {
319 case <-time.After(auditInterval * time.Second):
320 go func() {
321 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
322 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
323 }
324 }()
325 case <-am.stopAlarmAuditTimer:
326 logger.Infow(ctx, "stopping-alarm-timer", log.Fields{"device-id": am.pDeviceHandler.deviceID})
327 return
328 }
329 }
330}
331
332func (am *onuAlarmManager) processAlarmSyncMessages(ctx context.Context) {
333 logger.Debugw(ctx, "start-routine-to-process-omci-messages-for-alarm-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID})
334 am.flushAlarmSyncChannels(ctx)
335loop:
336 for {
337 message, ok := <-am.eventChannel
338 if !ok {
339 logger.Info(ctx, "alarm-sync-omci-message-could-not-be-read-from-channel", log.Fields{"device-id": am.pDeviceHandler.deviceID})
340 break loop
341 }
342 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID})
343
344 switch message.Type {
345 case OMCI:
346 msg, _ := message.Data.(OmciMessage)
347 am.handleOmciMessage(ctx, msg)
348 default:
349 logger.Warn(ctx, "alarm-sync-unknown-message-type-received", log.Fields{"device-id": am.pDeviceHandler.deviceID, "message.Type": message.Type})
350 }
351 }
352 logger.Info(ctx, "alarm-sync-stopped-handling-of-alarm-sync-omci-message", log.Fields{"device-id": am.pDeviceHandler.deviceID})
353 _ = am.alarmSyncFsm.pFsm.Event(asEvStop)
354}
355
356func (am *onuAlarmManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
357 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
358 "msg-type": msg.OmciMsg.MessageType, "msg": msg})
359 switch msg.OmciMsg.MessageType {
360 case omci.GetAllAlarmsResponseType:
361 am.handleOmciGetAllAlarmsResponseMessage(ctx, msg)
362 case omci.GetAllAlarmsNextResponseType:
363 am.handleOmciGetAllAlarmNextResponseMessage(ctx, msg)
364 default:
365 logger.Warnw(ctx, "unknown-message-type", log.Fields{"msg-type": msg.OmciMsg.MessageType})
366
367 }
368}
369
370func (am *onuAlarmManager) handleOmciGetAllAlarmsResponseMessage(ctx context.Context, msg OmciMessage) {
371 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsResponse)
372 if msgLayer == nil {
373 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
374 return
375 }
376 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsResponse)
377 if !msgOk {
378 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
379 return
380 }
381 logger.Debugw(ctx, "get-all-alarm-response-data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
382 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
383 logger.Debugw(ctx, "alarm-sync-fsm-is-disabled-ignoring-response-message", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
384 return
385 }
386 am.alarmUploadNoOfCmds = msgObj.NumberOfCommands
387 failureTransition := func() {
388 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
389 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
390 }
391 }
392 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
393 // Reset Onu Alarm Sequence
394 am.onuAlarmManagerLock.Lock()
395 am.resetAlarmSequence()
396 // Get a copy of the alarm bit map db.
397 for alarms, bitmap := range am.alarmBitMapDB {
398 am.oltDbCopy[alarms] = bitmap
399 }
400 am.onuAlarmManagerLock.Unlock()
401 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
402 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
403 // Transition to failure
404 go failureTransition()
405 }
406 } else {
407 logger.Errorw(ctx, "invalid-number-of-commands-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
408 "upload-no-of-cmds": am.alarmUploadNoOfCmds, "upload-seq-no": am.alarmUploadSeqNo})
409 go failureTransition()
410 }
411}
412
413func (am *onuAlarmManager) handleOmciGetAllAlarmNextResponseMessage(ctx context.Context, msg OmciMessage) {
414 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsNextResponse)
415
416 if msgLayer == nil {
417 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
418 return
419 }
420 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsNextResponse)
421 if !msgOk {
422 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
423 return
424 }
425 logger.Debugw(ctx, "get-all-alarms-next-response-data",
426 log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
427 meClassID := msgObj.AlarmEntityClass
428 meEntityID := msgObj.AlarmEntityInstance
429 meAlarmBitMap := msgObj.AlarmBitMap
430
431 am.onuAlarmManagerLock.Lock()
432 am.onuDBCopy[meAlarmKey{
433 classID: meClassID,
434 instanceID: meEntityID,
435 }] = meAlarmBitMap
436 am.onuAlarmManagerLock.Unlock()
437 failureTransition := func() {
438 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
439 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
440 }
441 }
442 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
443 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
444 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
445 // Transition to failure
446 go failureTransition()
447 } //TODO: needs to handle timeouts
448 } else {
449 if am.isAlarmDBDiffPresent(ctx) {
450 // transition to resync state
451 go func() {
452 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
453 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
454 }
455 }()
456 } else {
457 // Transition to sync state
458 go failureTransition()
459 }
460 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530461}
462
463func (am *onuAlarmManager) startOMCIAlarmMessageProcessing(ctx context.Context) {
464 am.onuAlarmManagerLock.Lock()
465 am.processMessage = true
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530466 if am.activeAlarms == nil {
467 am.activeAlarms = make(map[alarmInfo]struct{})
468 }
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530469 am.alarmBitMapDB = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530470 am.onuAlarmManagerLock.Unlock()
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530471 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
472 if err := am.alarmSyncFsm.pFsm.Event(ulEvStart); err != nil {
473 logger.Errorw(ctx, "alarm-sync-fsm-can-not-go-to-state-starting", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
474 return
475 }
476 } else {
477 logger.Errorw(ctx, "wrong-state-of-alarm-sync-fsm-want-disabled", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current()),
478 "device-id": am.pDeviceHandler.deviceID})
479 return
480 }
481 logger.Debugw(ctx, "alarm-sync-fsm-started", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current())})
482
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530483 if stop := <-am.stopProcessingOmciMessages; stop {
484 am.onuAlarmManagerLock.Lock()
485 am.processMessage = false
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530486 am.activeAlarms = nil
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530487 am.alarmBitMapDB = nil
488 am.alarmUploadNoOfCmds = 0
489 am.alarmUploadSeqNo = 0
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530490 am.onuAlarmManagerLock.Unlock()
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530491 _ = am.alarmSyncFsm.pFsm.Event(asEvStop)
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530492 }
493}
494
495func (am *onuAlarmManager) handleOmciAlarmNotificationMessage(ctx context.Context, msg OmciMessage) {
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530496 logger.Debugw(ctx, "omci-alarm-notification-msg", log.Fields{"device-id": am.pDeviceHandler.deviceID,
497 "msg-type": msg.OmciMsg.MessageType})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530498 am.onuAlarmManagerLock.Lock()
499 defer am.onuAlarmManagerLock.Unlock()
500
501 if am.processMessage {
502 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeAlarmNotification)
503 if msgLayer == nil {
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530504 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected-for-alarm-notification",
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530505 log.Fields{"device-id": am.pDeviceHandler.deviceID})
506 return
507 }
508 msgObj, msgOk := msgLayer.(*omci.AlarmNotificationMsg)
509 if !msgOk {
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530510 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned-for-alarm-notification",
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530511 log.Fields{"device-id": am.pDeviceHandler.deviceID})
512 return
513 }
514 //Alarm Notification decoding at omci lib validates that the me class ID supports the
515 // alarm notifications.
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530516 logger.Debugw(ctx, "alarm-notification-data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530517 if err := am.processAlarmData(ctx, msgObj); err != nil {
518 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
519 }
520
521 } else {
522 logger.Warnw(ctx, "ignoring-alarm-notification-received-for-me-as-channel-for-processing-is-closed",
523 log.Fields{"device-id": am.pDeviceHandler.deviceID})
524 }
525}
526
527func (am *onuAlarmManager) processAlarmData(ctx context.Context, msg *omci.AlarmNotificationMsg) error {
528 classID := msg.EntityClass
529 sequenceNo := msg.AlarmSequenceNumber
530 meInstance := msg.EntityInstance
531 alarmBitmap := msg.AlarmBitmap
532 logger.Debugw(ctx, "processing-alarm-data", log.Fields{"class-id": classID, "instance-id": meInstance,
533 "alarmBitMap": alarmBitmap, "sequence-no": sequenceNo})
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530534 if _, present := am.pDeviceHandler.pOnuOmciDevice.pOnuDB.meDb[classID][meInstance]; !present {
535 logger.Errorw(ctx, "me-class-instance-not-present", log.Fields{"class-id": classID, "instance-id": meInstance})
536 return fmt.Errorf("me-class-%d-instance-%d-not-present", classID, meInstance)
537 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530538
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530539 if sequenceNo > 0 {
540 if am.alarmSyncFsm.pFsm.Is(asStAuditing) || am.alarmSyncFsm.pFsm.Is(asStResynchronizing) {
541 am.bufferedNotifications = append(am.bufferedNotifications, msg)
542 return nil
543 }
544 am.incrementAlarmSequence()
545 if sequenceNo != am.lastAlarmSequence && auditInterval > 0 {
546 // signal early audit, if no match(if we are reaching here it means that audit is not going on currently)
547 go func() {
548 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
549 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
550 }
551 }()
552 }
553 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530554 entity, omciErr := me.LoadManagedEntityDefinition(classID,
555 me.ParamData{EntityID: meInstance})
556 if omciErr.StatusCode() != me.Success {
557 //log error and return
558 logger.Error(ctx, "unable-to-get-managed-entity", log.Fields{"class-id": classID, "instance-id": meInstance})
559 return fmt.Errorf("unable-to-get-managed-entity-class-%d-instance-%d", classID, meInstance)
560 }
561 meAlarmMap := entity.GetAlarmMap()
562 if meAlarmMap == nil {
563 logger.Error(ctx, "unable-to-get-managed-entity-alarm-map", log.Fields{"class-id": classID, "instance-id": meInstance})
564 return fmt.Errorf("unable-to-get-managed-entity-alarm-map-%d-instance-%d", classID, meInstance)
565 }
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530566 am.alarmBitMapDB[meAlarmKey{
567 classID: classID,
568 instanceID: meInstance,
569 }] = alarmBitmap
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530570 // Loop over the supported alarm list for this me
571 for alarmNo := range meAlarmMap {
572 // Check if alarmNo was previously active in the alarms, if yes clear it and remove it from active alarms
573 _, exists := am.activeAlarms[alarmInfo{
574 classID: classID,
575 instanceID: meInstance,
576 alarmNo: alarmNo,
577 }]
578 if exists {
579 // Clear this alarm if It is cleared now, in that case IsAlarmClear would return true
580 cleared, err := msg.IsAlarmClear(alarmNo)
581 if err != nil {
582 logger.Warnw(ctx, "unable-to-find-out-alarm-is-cleared", log.Fields{"class-id": classID,
583 "instance-id": meInstance, "alarm-no": alarmNo})
584 return err
585 }
586 if cleared {
587 // Clear this alarm.
588 am.clearAlarm(ctx, classID, meInstance, alarmNo)
589 }
590 } else {
591 // If alarm entry was not present in the list of active alarms, we need to see if this alarm is now active
592 // or not, if yes then raise it.
593 raised, err := msg.IsAlarmActive(alarmNo)
594 if err != nil {
595 logger.Warnw(ctx, "unable-to-find-out-alarm-is-raised", log.Fields{"class-id": classID,
596 "instance-id": meInstance, "alarm-no": alarmNo})
597 return err
598 }
599 if raised {
600 am.raiseAlarm(ctx, classID, meInstance, alarmNo)
601 }
602 }
603 }
604 return nil
605}
606
607func (am *onuAlarmManager) raiseAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
608 am.activeAlarms[alarmInfo{
609 classID: classID,
610 instanceID: instanceID,
611 alarmNo: alarm,
612 }] = struct{}{}
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530613
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530614 go am.sendAlarm(ctx, classID, instanceID, alarm, true)
615}
616
617func (am *onuAlarmManager) clearAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
618 go am.sendAlarm(ctx, classID, instanceID, alarm, false)
619 delete(am.activeAlarms, alarmInfo{
620 classID: classID,
621 instanceID: instanceID,
622 alarmNo: alarm,
623 })
624}
625
626func (am *onuAlarmManager) getIntfIDAlarm(ctx context.Context, classID me.ClassID, instanceID uint16) *uint32 {
627 var intfID *uint32
628 if classID == circuitPackClassID || classID == physicalPathTerminationPointEthernetUniClassID {
629 for _, uniPort := range am.pDeviceHandler.uniEntityMap {
630 if uniPort.entityID == instanceID {
631 intfID = &uniPort.portNo
632 return intfID
633 }
634 }
635 } else if classID == aniGClassID || classID == onuGClassID {
636 intfID = &am.pDeviceHandler.ponPortNumber
637 return intfID
638 } else {
639 logger.Warnw(ctx, "me-not-supported", log.Fields{"class-id": classID, "instance-id": instanceID})
640 }
641 return nil
642}
643
644func (am *onuAlarmManager) sendAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8, raised bool) {
645 context := make(map[string]string)
646 intfID := am.getIntfIDAlarm(ctx, classID, instanceID)
647 onuID := am.pDeviceHandler.deviceID
Holger Hildebrandtbe523842021-03-10 10:47:18 +0000648 serialNo := am.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersSerialNumber
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530649 if intfID == nil {
650 logger.Warn(ctx, "intf-id-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
651 return
652 }
653 context["onu-intf-id"] = fmt.Sprintf("%d", *intfID)
654 context["onu-id"] = onuID
655 context["onu-serial-number"] = serialNo
656
657 raisedTimestamp := time.Now().UnixNano()
658 eventDetails, err := am.getDeviceEventData(ctx, classID, alarm)
659 if err != nil {
660 logger.Warn(ctx, "event-details-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
661 return
662 }
663 suffixDesc := "Raised"
664 if !raised {
665 suffixDesc = "Cleared"
666 }
667 deviceEvent := &voltha.DeviceEvent{
668 ResourceId: onuID,
669 DeviceEventName: fmt.Sprintf("%s_RAISE_EVENT", eventDetails.EventName),
670 Description: fmt.Sprintf("%s Event - %s - %s", eventDetails.EventDescription, eventDetails.EventName,
671 suffixDesc),
672 Context: context,
673 }
674 _ = am.eventProxy.SendDeviceEvent(ctx, deviceEvent, eventDetails.EventCategory, eventDetails.EventSubCategory,
675 raisedTimestamp)
676}
Himani Chawlaa2592fe2021-02-25 10:54:36 +0530677
678func (am *onuAlarmManager) isAlarmDBDiffPresent(ctx context.Context) bool {
679 return !reflect.DeepEqual(am.onuDBCopy, am.oltDbCopy)
680}
681
682func (am *onuAlarmManager) incrementAlarmSequence() {
683 //alarm sequence number wraps from 255 to 1.
684 if am.lastAlarmSequence == 255 {
685 am.lastAlarmSequence = 1
686 } else {
687 am.lastAlarmSequence++
688 }
689}
690
691func (am *onuAlarmManager) resetAlarmSequence() {
692 am.lastAlarmSequence = 0
693}
694
695// flushAlarmSyncChannels flushes all alarm sync channels to discard any previous response
696func (am *onuAlarmManager) flushAlarmSyncChannels(ctx context.Context) {
697 // flush alarm sync channel
698 select {
699 case <-am.eventChannel:
700 logger.Debug(ctx, "flushed-alarm-sync-channel")
701 default:
702 }
703 select {
704 case <-am.stopAlarmAuditTimer:
705 logger.Debug(ctx, "flushed-alarm-audit-timer-channel")
706 default:
707 }
708}
709
710// getDeviceEventData returns the event data for a device
711func (am *onuAlarmManager) getDeviceEventData(ctx context.Context, classID me.ClassID, alarmNo uint8) (onuDeviceEvent, error) {
712 if onuEventDetails, ok := am.onuEventsList[onuDevice{classID: classID, alarmno: alarmNo}]; ok {
713 return onuEventDetails, nil
714 }
715 return onuDeviceEvent{}, errors.New("onu Event Detail not found")
716}