blob: 6665bd420ec5eb95b4ad581b476c2abd37e15b0b [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 Chawlad3dac422021-03-13 02:31:31 +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 Chawlad3dac422021-03-13 02:31:31 +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 Chawlad3dac422021-03-13 02:31:31 +053040 auditInterval = 300
41 defaultTimeoutDelay = 10
42 alarmBitMapSizeBytes = 28
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053043)
44
Himani Chawlad3dac422021-03-13 02:31:31 +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 Chawlad3dac422021-03-13 02:31:31 +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 Chawlad3dac422021-03-13 02:31:31 +053089 alarmBitMapDB alarmBitMapDB
Himani Chawla4c1d4c72021-02-18 12:14:31 +053090 onuEventsList map[onuDevice]onuDeviceEvent
Himani Chawlad3dac422021-03-13 02:31:31 +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 Chawlad3dac422021-03-13 02:31:31 +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 Chawlad3dac422021-03-13 02:31:31 +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 Chawlad3dac422021-03-13 02:31:31 +0530161 alarmManager.alarmSyncFsm = NewAdapterFsm("AlarmSync", dh.deviceID, alarmManager.eventChannel)
162 alarmManager.alarmSyncFsm.pFsm = fsm.NewFSM(
163 asStDisabled,
164 fsm.Events{
165 {Name: asEvStart, Src: []string{asStDisabled}, Dst: asStStarting},
166 {Name: asEvAudit, Src: []string{asStStarting, asStInSync}, Dst: asStAuditing},
167 {Name: asEvSync, Src: []string{asStStarting}, Dst: asStInSync},
168 {Name: asEvSuccess, Src: []string{asStAuditing, asStResynchronizing}, Dst: asStInSync},
169 {Name: asEvFailure, Src: []string{asStAuditing, asStResynchronizing}, Dst: asStAuditing},
170 {Name: asEvResync, Src: []string{asStAuditing}, Dst: asStResynchronizing},
171 {Name: asEvStop, Src: []string{asStDisabled, asStStarting, asStAuditing, asStInSync, asStIdle, asStResynchronizing}, Dst: asStDisabled},
172 },
173 fsm.Callbacks{
174 "enter_state": func(e *fsm.Event) { alarmManager.alarmSyncFsm.logFsmStateChange(ctx, e) },
175 "enter_" + asStStarting: func(e *fsm.Event) { alarmManager.asFsmStarting(ctx, e) },
176 "enter_" + asStAuditing: func(e *fsm.Event) { alarmManager.asFsmAuditing(ctx, e) },
177 "enter_" + asStInSync: func(e *fsm.Event) { alarmManager.asFsmInSync(ctx, e) },
178 "enter_" + asStResynchronizing: func(e *fsm.Event) { alarmManager.asFsmResynchronizing(ctx, e) },
179 },
180 )
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530181 return &alarmManager
182}
183
Himani Chawlad3dac422021-03-13 02:31:31 +0530184func (am *onuAlarmManager) asFsmStarting(ctx context.Context, e *fsm.Event) {
185 logger.Debugw(ctx, "alarm-sync-fsm-start-processing-msgs-in-state", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
186 go am.processAlarmSyncMessages(ctx)
187 // Start the first audit, if audit interval configured, else reach the sync state
188 if auditInterval > 0 {
189 select {
190 //Transition into auditing state, using a very shorter timeout delay here, hence it is the first audit
191 case <-time.After(defaultTimeoutDelay * time.Second):
192 go func() {
193 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
194 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
195 }
196 }()
197 case <-am.stopAlarmAuditTimer:
198 logger.Infow(ctx, "stopping-alarm-timer", log.Fields{"device-id": am.pDeviceHandler.deviceID})
199 return
200 }
201 } else {
202 // Transition into sync state directly.
203 go func() {
204 if err := am.alarmSyncFsm.pFsm.Event(asEvSync); err != nil {
205 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
206 }
207 }()
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530208 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530209}
210
211func (am *onuAlarmManager) asFsmAuditing(ctx context.Context, e *fsm.Event) {
212 logger.Debugw(ctx, "alarm-sync-fsm-start-auditing", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
213 // Always reset the buffered notifications and db copies before starting the audit
214 am.onuAlarmManagerLock.Lock()
215 am.bufferedNotifications = make([]*omci.AlarmNotificationMsg, 0)
216 am.oltDbCopy = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
217 am.onuDBCopy = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
218 am.onuAlarmManagerLock.Unlock()
219 failureTransition := func() {
220 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
221 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
222 }
223 }
224 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarm(log.WithSpanFromContext(context.TODO(), ctx), 0,
225 am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
226 // Transition to failure so that alarm sync can be restarted again
227 go failureTransition()
228 }
229}
230
231func (am *onuAlarmManager) asFsmResynchronizing(ctx context.Context, e *fsm.Event) {
232 logger.Debugw(ctx, "alarm-sync-fsm", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
233 failureTransition := func() {
234 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
235 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
236 }
237 }
238 // See if there is any onu only diff, meaning the class and entity is only in onu DB
239 for alarm := range am.onuDBCopy {
240 if _, exists := am.oltDbCopy[meAlarmKey{
241 classID: alarm.classID,
242 instanceID: alarm.instanceID,
243 }]; !exists {
244 // We need to raise all such alarms as OLT wont have received notification for these alarms
245 omciAlarmMessage := &omci.AlarmNotificationMsg{
246 MeBasePacket: omci.MeBasePacket{
247 EntityClass: alarm.classID,
248 EntityInstance: alarm.instanceID,
249 },
250 AlarmBitmap: am.onuDBCopy[alarm],
251 }
252 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
253 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
254 // Transition to failure.
255 go failureTransition()
256 return
257 }
258 }
259 }
260 // See if there is any olt only diff, meaning the class and entity is only in olt DB
261 for alarm := range am.oltDbCopy {
262 if _, exists := am.onuDBCopy[meAlarmKey{
263 classID: alarm.classID,
264 instanceID: alarm.instanceID,
265 }]; !exists {
266 // We need to clear all such alarms as OLT might have stale data and the alarms are already cleared.
267 omciAlarmMessage := &omci.AlarmNotificationMsg{
268 MeBasePacket: omci.MeBasePacket{
269 EntityClass: alarm.classID,
270 EntityInstance: alarm.instanceID,
271 },
272 AlarmBitmap: am.oltDbCopy[alarm],
273 }
274 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
275 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
276 // Transition to failure
277 go failureTransition()
278 return
279 }
280 }
281 }
282 // See if there is any attribute difference
283 for alarm := range am.onuDBCopy {
284 if _, exists := am.oltDbCopy[alarm]; exists {
285 if am.onuDBCopy[alarm] != am.oltDbCopy[alarm] {
286 omciAlarmMessage := &omci.AlarmNotificationMsg{
287 MeBasePacket: omci.MeBasePacket{
288 EntityClass: alarm.classID,
289 EntityInstance: alarm.instanceID,
290 },
291 AlarmBitmap: am.onuDBCopy[alarm],
292 }
293 // We will assume that onudb is correct always in this case and process the changed bitmap.
294 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
295 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
296 // Transition to failure
297 go failureTransition()
298 return
299 }
300 }
301 }
302 }
303 // Send the buffered notifications if no failure.
304 for _, notif := range am.bufferedNotifications {
305 logger.Debugw(ctx, "processing-buffered-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID,
306 "notification": notif})
307 if err := am.processAlarmData(ctx, notif); err != nil {
308 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
309 go failureTransition()
310 }
311 }
312 go func() {
313 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
314 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
315 }
316 }()
317}
318
319func (am *onuAlarmManager) asFsmInSync(ctx context.Context, e *fsm.Event) {
320 logger.Debugw(ctx, "alarm-sync-fsm", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
321 if auditInterval > 0 {
322 select {
323 case <-time.After(auditInterval * time.Second):
324 go func() {
325 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
326 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
327 }
328 }()
329 case <-am.stopAlarmAuditTimer:
330 logger.Infow(ctx, "stopping-alarm-timer", log.Fields{"device-id": am.pDeviceHandler.deviceID})
331 return
332 }
333 }
334}
335
336func (am *onuAlarmManager) processAlarmSyncMessages(ctx context.Context) {
337 logger.Debugw(ctx, "start-routine-to-process-omci-messages-for-alarm-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID})
338 am.flushAlarmSyncChannels(ctx)
339loop:
340 for {
341 message, ok := <-am.eventChannel
342 if !ok {
343 logger.Info(ctx, "alarm-sync-omci-message-could-not-be-read-from-channel", log.Fields{"device-id": am.pDeviceHandler.deviceID})
344 break loop
345 }
346 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID})
347
348 switch message.Type {
349 case OMCI:
350 msg, _ := message.Data.(OmciMessage)
351 am.handleOmciMessage(ctx, msg)
352 default:
353 logger.Warn(ctx, "alarm-sync-unknown-message-type-received", log.Fields{"device-id": am.pDeviceHandler.deviceID, "message.Type": message.Type})
354 }
355 }
356 logger.Info(ctx, "alarm-sync-stopped-handling-of-alarm-sync-omci-message", log.Fields{"device-id": am.pDeviceHandler.deviceID})
357 _ = am.alarmSyncFsm.pFsm.Event(asEvStop)
358}
359
360func (am *onuAlarmManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
361 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
362 "msg-type": msg.OmciMsg.MessageType, "msg": msg})
363 switch msg.OmciMsg.MessageType {
364 case omci.GetAllAlarmsResponseType:
365 am.handleOmciGetAllAlarmsResponseMessage(ctx, msg)
366 case omci.GetAllAlarmsNextResponseType:
367 am.handleOmciGetAllAlarmNextResponseMessage(ctx, msg)
368 default:
369 logger.Warnw(ctx, "unknown-message-type", log.Fields{"msg-type": msg.OmciMsg.MessageType})
370
371 }
372}
373
374func (am *onuAlarmManager) handleOmciGetAllAlarmsResponseMessage(ctx context.Context, msg OmciMessage) {
375 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsResponse)
376 if msgLayer == nil {
377 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
378 return
379 }
380 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsResponse)
381 if !msgOk {
382 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
383 return
384 }
385 logger.Debugw(ctx, "get-all-alarm-response-data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
386 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
387 logger.Debugw(ctx, "alarm-sync-fsm-is-disabled-ignoring-response-message", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
388 return
389 }
390 am.alarmUploadNoOfCmds = msgObj.NumberOfCommands
391 failureTransition := func() {
392 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
393 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
394 }
395 }
396 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
397 // Reset Onu Alarm Sequence
398 am.onuAlarmManagerLock.Lock()
399 am.resetAlarmSequence()
400 // Get a copy of the alarm bit map db.
401 for alarms, bitmap := range am.alarmBitMapDB {
402 am.oltDbCopy[alarms] = bitmap
403 }
404 am.onuAlarmManagerLock.Unlock()
405 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
406 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
407 // Transition to failure
408 go failureTransition()
409 }
410 } else if am.alarmUploadNoOfCmds == 0 {
411 // Reset Onu Alarm Sequence
412 am.onuAlarmManagerLock.Lock()
413 am.resetAlarmSequence()
414 // Get a copy of the alarm bit map db.
415 for alarms, bitmap := range am.alarmBitMapDB {
416 am.oltDbCopy[alarms] = bitmap
417 }
418 am.onuAlarmManagerLock.Unlock()
419 if am.isAlarmDBDiffPresent(ctx) {
420 // transition to resync state
421 go func() {
422 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
423 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
424 }
425 }()
426 } else {
427 // Transition to sync state
428 go func() {
429 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
430 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
431 }
432 }()
433 }
434 } else {
435 logger.Errorw(ctx, "invalid-number-of-commands-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
436 "upload-no-of-cmds": am.alarmUploadNoOfCmds, "upload-seq-no": am.alarmUploadSeqNo})
437 go failureTransition()
438 }
439}
440
441func (am *onuAlarmManager) handleOmciGetAllAlarmNextResponseMessage(ctx context.Context, msg OmciMessage) {
442 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsNextResponse)
443
444 if msgLayer == nil {
445 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
446 return
447 }
448 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsNextResponse)
449 if !msgOk {
450 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
451 return
452 }
453 logger.Debugw(ctx, "get-all-alarms-next-response-data",
454 log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
455 meClassID := msgObj.AlarmEntityClass
456 meEntityID := msgObj.AlarmEntityInstance
457 meAlarmBitMap := msgObj.AlarmBitMap
458
459 am.onuAlarmManagerLock.Lock()
460 am.onuDBCopy[meAlarmKey{
461 classID: meClassID,
462 instanceID: meEntityID,
463 }] = meAlarmBitMap
464 am.onuAlarmManagerLock.Unlock()
465 failureTransition := func() {
466 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
467 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
468 }
469 }
470 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
471 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
472 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
473 // Transition to failure
474 go failureTransition()
475 } //TODO: needs to handle timeouts
476 } else {
477 if am.isAlarmDBDiffPresent(ctx) {
478 // transition to resync state
479 go func() {
480 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
481 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
482 }
483 }()
484 } else {
485 // Transition to sync state
486 go func() {
487 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
488 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
489 }
490 }()
491 }
492 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530493}
494
495func (am *onuAlarmManager) startOMCIAlarmMessageProcessing(ctx context.Context) {
496 am.onuAlarmManagerLock.Lock()
497 am.processMessage = true
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530498 if am.activeAlarms == nil {
499 am.activeAlarms = make(map[alarmInfo]struct{})
500 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530501 am.alarmBitMapDB = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530502 am.onuAlarmManagerLock.Unlock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530503 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
504 if err := am.alarmSyncFsm.pFsm.Event(asEvStart); err != nil {
505 logger.Errorw(ctx, "alarm-sync-fsm-can-not-go-to-state-starting", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
506 return
507 }
508 } else {
509 logger.Errorw(ctx, "wrong-state-of-alarm-sync-fsm-want-disabled", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current()),
510 "device-id": am.pDeviceHandler.deviceID})
511 return
512 }
513 logger.Debugw(ctx, "alarm-sync-fsm-started", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current())})
514
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530515 if stop := <-am.stopProcessingOmciMessages; stop {
516 am.onuAlarmManagerLock.Lock()
517 am.processMessage = false
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530518 am.activeAlarms = nil
Himani Chawlad3dac422021-03-13 02:31:31 +0530519 am.alarmBitMapDB = nil
520 am.alarmUploadNoOfCmds = 0
521 am.alarmUploadSeqNo = 0
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530522 am.onuAlarmManagerLock.Unlock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530523
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530524 }
525}
526
527func (am *onuAlarmManager) handleOmciAlarmNotificationMessage(ctx context.Context, msg OmciMessage) {
Himani Chawlad3dac422021-03-13 02:31:31 +0530528 logger.Debugw(ctx, "omci-alarm-notification-msg", log.Fields{"device-id": am.pDeviceHandler.deviceID,
529 "msg-type": msg.OmciMsg.MessageType})
530 am.onuAlarmManagerLock.RLock()
531 processMessage := am.processMessage
532 am.onuAlarmManagerLock.RUnlock()
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530533
Himani Chawlad3dac422021-03-13 02:31:31 +0530534 if processMessage {
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530535 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeAlarmNotification)
536 if msgLayer == nil {
Himani Chawlad3dac422021-03-13 02:31:31 +0530537 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected-for-alarm-notification",
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530538 log.Fields{"device-id": am.pDeviceHandler.deviceID})
539 return
540 }
541 msgObj, msgOk := msgLayer.(*omci.AlarmNotificationMsg)
542 if !msgOk {
Himani Chawlad3dac422021-03-13 02:31:31 +0530543 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned-for-alarm-notification",
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530544 log.Fields{"device-id": am.pDeviceHandler.deviceID})
545 return
546 }
547 //Alarm Notification decoding at omci lib validates that the me class ID supports the
548 // alarm notifications.
Himani Chawlad3dac422021-03-13 02:31:31 +0530549 logger.Debugw(ctx, "alarm-notification-data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530550 if err := am.processAlarmData(ctx, msgObj); err != nil {
551 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
552 }
553
554 } else {
555 logger.Warnw(ctx, "ignoring-alarm-notification-received-for-me-as-channel-for-processing-is-closed",
556 log.Fields{"device-id": am.pDeviceHandler.deviceID})
557 }
558}
559
560func (am *onuAlarmManager) processAlarmData(ctx context.Context, msg *omci.AlarmNotificationMsg) error {
561 classID := msg.EntityClass
562 sequenceNo := msg.AlarmSequenceNumber
563 meInstance := msg.EntityInstance
564 alarmBitmap := msg.AlarmBitmap
565 logger.Debugw(ctx, "processing-alarm-data", log.Fields{"class-id": classID, "instance-id": meInstance,
566 "alarmBitMap": alarmBitmap, "sequence-no": sequenceNo})
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530567 if _, present := am.pDeviceHandler.pOnuOmciDevice.pOnuDB.meDb[classID][meInstance]; !present {
568 logger.Errorw(ctx, "me-class-instance-not-present", log.Fields{"class-id": classID, "instance-id": meInstance})
569 return fmt.Errorf("me-class-%d-instance-%d-not-present", classID, meInstance)
570 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530571 am.onuAlarmManagerLock.Lock()
572 defer am.onuAlarmManagerLock.Unlock()
573 if sequenceNo > 0 {
574 if am.alarmSyncFsm.pFsm.Is(asStAuditing) || am.alarmSyncFsm.pFsm.Is(asStResynchronizing) {
575 am.bufferedNotifications = append(am.bufferedNotifications, msg)
576 logger.Debugw(ctx, "adding-notification-to-buffered-notification-list", log.Fields{"device-id": am.pDeviceHandler.deviceID,
577 "notification": msg})
578 return nil
Andrea Campanellace915292021-03-12 17:59:35 +0000579 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530580 am.incrementAlarmSequence()
581 if sequenceNo != am.lastAlarmSequence && auditInterval > 0 {
582 // signal early audit, if no match(if we are reaching here it means that audit is not going on currently)
583 go func() {
584 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
585 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
586 }
587 }()
588 }
589 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530590 entity, omciErr := me.LoadManagedEntityDefinition(classID,
591 me.ParamData{EntityID: meInstance})
592 if omciErr.StatusCode() != me.Success {
593 //log error and return
594 logger.Error(ctx, "unable-to-get-managed-entity", log.Fields{"class-id": classID, "instance-id": meInstance})
595 return fmt.Errorf("unable-to-get-managed-entity-class-%d-instance-%d", classID, meInstance)
596 }
597 meAlarmMap := entity.GetAlarmMap()
598 if meAlarmMap == nil {
599 logger.Error(ctx, "unable-to-get-managed-entity-alarm-map", log.Fields{"class-id": classID, "instance-id": meInstance})
600 return fmt.Errorf("unable-to-get-managed-entity-alarm-map-%d-instance-%d", classID, meInstance)
601 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530602
603 am.alarmBitMapDB[meAlarmKey{
604 classID: classID,
605 instanceID: meInstance,
606 }] = alarmBitmap
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530607 // Loop over the supported alarm list for this me
608 for alarmNo := range meAlarmMap {
609 // Check if alarmNo was previously active in the alarms, if yes clear it and remove it from active alarms
610 _, exists := am.activeAlarms[alarmInfo{
611 classID: classID,
612 instanceID: meInstance,
613 alarmNo: alarmNo,
614 }]
615 if exists {
616 // Clear this alarm if It is cleared now, in that case IsAlarmClear would return true
617 cleared, err := msg.IsAlarmClear(alarmNo)
618 if err != nil {
619 logger.Warnw(ctx, "unable-to-find-out-alarm-is-cleared", log.Fields{"class-id": classID,
620 "instance-id": meInstance, "alarm-no": alarmNo})
621 return err
622 }
623 if cleared {
624 // Clear this alarm.
625 am.clearAlarm(ctx, classID, meInstance, alarmNo)
626 }
627 } else {
628 // If alarm entry was not present in the list of active alarms, we need to see if this alarm is now active
629 // or not, if yes then raise it.
630 raised, err := msg.IsAlarmActive(alarmNo)
631 if err != nil {
632 logger.Warnw(ctx, "unable-to-find-out-alarm-is-raised", log.Fields{"class-id": classID,
633 "instance-id": meInstance, "alarm-no": alarmNo})
634 return err
635 }
636 if raised {
637 am.raiseAlarm(ctx, classID, meInstance, alarmNo)
638 }
639 }
640 }
641 return nil
642}
643
644func (am *onuAlarmManager) raiseAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
645 am.activeAlarms[alarmInfo{
646 classID: classID,
647 instanceID: instanceID,
648 alarmNo: alarm,
649 }] = struct{}{}
Himani Chawlad3dac422021-03-13 02:31:31 +0530650
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530651 go am.sendAlarm(ctx, classID, instanceID, alarm, true)
652}
653
654func (am *onuAlarmManager) clearAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
655 go am.sendAlarm(ctx, classID, instanceID, alarm, false)
656 delete(am.activeAlarms, alarmInfo{
657 classID: classID,
658 instanceID: instanceID,
659 alarmNo: alarm,
660 })
Himani Chawlad3dac422021-03-13 02:31:31 +0530661 key := meAlarmKey{
662 classID: classID,
663 instanceID: instanceID,
664 }
665 if am.alarmBitMapDB[key] == [alarmBitMapSizeBytes]byte{0} {
666 delete(am.alarmBitMapDB, key)
667 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530668}
669
670func (am *onuAlarmManager) getIntfIDAlarm(ctx context.Context, classID me.ClassID, instanceID uint16) *uint32 {
671 var intfID *uint32
672 if classID == circuitPackClassID || classID == physicalPathTerminationPointEthernetUniClassID {
673 for _, uniPort := range am.pDeviceHandler.uniEntityMap {
674 if uniPort.entityID == instanceID {
675 intfID = &uniPort.portNo
676 return intfID
677 }
678 }
679 } else if classID == aniGClassID || classID == onuGClassID {
680 intfID = &am.pDeviceHandler.ponPortNumber
681 return intfID
682 } else {
683 logger.Warnw(ctx, "me-not-supported", log.Fields{"class-id": classID, "instance-id": instanceID})
684 }
685 return nil
686}
687
688func (am *onuAlarmManager) sendAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8, raised bool) {
689 context := make(map[string]string)
690 intfID := am.getIntfIDAlarm(ctx, classID, instanceID)
691 onuID := am.pDeviceHandler.deviceID
Holger Hildebrandtbe523842021-03-10 10:47:18 +0000692 serialNo := am.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersSerialNumber
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530693 if intfID == nil {
694 logger.Warn(ctx, "intf-id-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
695 return
696 }
697 context["onu-intf-id"] = fmt.Sprintf("%d", *intfID)
698 context["onu-id"] = onuID
699 context["onu-serial-number"] = serialNo
700
701 raisedTimestamp := time.Now().UnixNano()
702 eventDetails, err := am.getDeviceEventData(ctx, classID, alarm)
703 if err != nil {
704 logger.Warn(ctx, "event-details-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
705 return
706 }
707 suffixDesc := "Raised"
708 if !raised {
709 suffixDesc = "Cleared"
710 }
711 deviceEvent := &voltha.DeviceEvent{
712 ResourceId: onuID,
713 DeviceEventName: fmt.Sprintf("%s_RAISE_EVENT", eventDetails.EventName),
714 Description: fmt.Sprintf("%s Event - %s - %s", eventDetails.EventDescription, eventDetails.EventName,
715 suffixDesc),
716 Context: context,
717 }
718 _ = am.eventProxy.SendDeviceEvent(ctx, deviceEvent, eventDetails.EventCategory, eventDetails.EventSubCategory,
719 raisedTimestamp)
720}
Himani Chawlad3dac422021-03-13 02:31:31 +0530721
722func (am *onuAlarmManager) isAlarmDBDiffPresent(ctx context.Context) bool {
723 return !reflect.DeepEqual(am.onuDBCopy, am.oltDbCopy)
724}
725
726func (am *onuAlarmManager) incrementAlarmSequence() {
727 //alarm sequence number wraps from 255 to 1.
728 if am.lastAlarmSequence == 255 {
729 am.lastAlarmSequence = 1
730 } else {
731 am.lastAlarmSequence++
732 }
733}
734
735func (am *onuAlarmManager) resetAlarmSequence() {
736 am.lastAlarmSequence = 0
737}
738
739// flushAlarmSyncChannels flushes all alarm sync channels to discard any previous response
740func (am *onuAlarmManager) flushAlarmSyncChannels(ctx context.Context) {
741 // flush alarm sync channel
742 select {
743 case <-am.eventChannel:
744 logger.Debug(ctx, "flushed-alarm-sync-channel")
745 default:
746 }
747 select {
748 case <-am.stopAlarmAuditTimer:
749 logger.Debug(ctx, "flushed-alarm-audit-timer-channel")
750 default:
751 }
752}
753
754// getDeviceEventData returns the event data for a device
755func (am *onuAlarmManager) getDeviceEventData(ctx context.Context, classID me.ClassID, alarmNo uint8) (onuDeviceEvent, error) {
756 if onuEventDetails, ok := am.onuEventsList[onuDevice{classID: classID, alarmno: alarmNo}]; ok {
757 return onuEventDetails, nil
758 }
759 return onuDeviceEvent{}, errors.New("onu Event Detail not found")
760}