blob: cb0c2230681a057725f05daaf3d0fb8655e4f5b2 [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 defaultTimeoutDelay = 10
41 alarmBitMapSizeBytes = 28
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053042)
43
Himani Chawlad3dac422021-03-13 02:31:31 +053044const (
45 // events of alarm sync FSM
46 asEvStart = "asEvStart"
47 asEvStop = "asEvStop"
48 asEvAudit = "asEvAudit"
49 asEvSync = "asEvSync"
50 asEvSuccess = "asEvSuccess"
51 asEvFailure = "asEvFailure"
52 asEvResync = "asEvResync"
53)
54const (
55 // states of alarm sync FSM
56 asStStarting = "asStStarting"
57 asStDisabled = "asStDisabled"
58 asStInSync = "asStInSync"
59 asStAuditing = "asStAuditing"
60 asStResynchronizing = "asStResynchronizing"
61 asStIdle = "asStIdle"
62)
63
64//const cAsFsmIdleState = asStIdle not using idle state currently
65
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053066type alarmInfo struct {
67 classID me.ClassID
68 instanceID uint16
69 alarmNo uint8
70}
71
72type alarms map[alarmInfo]struct{}
73
Himani Chawlad3dac422021-03-13 02:31:31 +053074type meAlarmKey struct {
75 classID me.ClassID
76 instanceID uint16
77}
78
79type alarmBitMapDB map[meAlarmKey][alarmBitMapSizeBytes]byte
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053080type onuAlarmManager struct {
81 pDeviceHandler *deviceHandler
82 eventProxy eventif.EventProxy
83 stopProcessingOmciMessages chan bool
84 eventChannel chan Message
85 onuAlarmManagerLock sync.RWMutex
86 processMessage bool
87 activeAlarms alarms
Himani Chawlad3dac422021-03-13 02:31:31 +053088 alarmBitMapDB alarmBitMapDB
Himani Chawla4c1d4c72021-02-18 12:14:31 +053089 onuEventsList map[onuDevice]onuDeviceEvent
Himani Chawlad3dac422021-03-13 02:31:31 +053090 lastAlarmSequence uint8
91 alarmSyncFsm *AdapterFsm
92 oltDbCopy alarmBitMapDB
93 onuDBCopy alarmBitMapDB
94 bufferedNotifications []*omci.AlarmNotificationMsg
95 alarmUploadSeqNo uint16
96 alarmUploadNoOfCmds uint16
97 stopAlarmAuditTimer chan struct{}
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053098}
99
100type onuDevice struct {
101 classID me.ClassID
102 alarmno uint8
103}
104type onuDeviceEvent struct {
105 EventName string
106 EventCategory eventif.EventCategory
107 EventSubCategory eventif.EventSubCategory
108 EventDescription string
109}
110
111func newAlarmManager(ctx context.Context, dh *deviceHandler) *onuAlarmManager {
112 var alarmManager onuAlarmManager
Himani Chawlad3dac422021-03-13 02:31:31 +0530113 logger.Debugw(ctx, "init-alarm-manager", log.Fields{"device-id": dh.deviceID})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530114 alarmManager.pDeviceHandler = dh
115 alarmManager.eventProxy = dh.EventProxy // Or event proxy should be on cluster address ??
116 alarmManager.eventChannel = make(chan Message)
117 alarmManager.stopProcessingOmciMessages = make(chan bool)
118 alarmManager.processMessage = false
119 alarmManager.activeAlarms = make(map[alarmInfo]struct{})
Himani Chawlad3dac422021-03-13 02:31:31 +0530120 alarmManager.alarmBitMapDB = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
121 alarmManager.stopAlarmAuditTimer = make(chan struct{})
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530122 alarmManager.onuEventsList = map[onuDevice]onuDeviceEvent{
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530123 {classID: circuitPackClassID, alarmno: 0}: {EventName: "ONU_EQUIPMENT",
124 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu equipment"},
125 {classID: circuitPackClassID, alarmno: 2}: {EventName: "ONU_SELF_TEST_FAIL",
126 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu self-test failure"},
127 {classID: circuitPackClassID, alarmno: 3}: {EventName: "ONU_LASER_EOL",
128 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu laser EOL"},
129 {classID: circuitPackClassID, alarmno: 4}: {EventName: "ONU_TEMP_YELLOW",
130 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature yellow"},
131 {classID: circuitPackClassID, alarmno: 5}: {EventName: "ONU_TEMP_RED",
132 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature red"},
133 {classID: physicalPathTerminationPointEthernetUniClassID, alarmno: 0}: {EventName: "ONU_Ethernet_UNI", EventCategory: voltha.EventCategory_EQUIPMENT,
134 EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "LAN Loss Of Signal"},
135 {classID: onuGClassID, alarmno: 0}: {EventName: "ONU_EQUIPMENT",
136 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu equipment"},
137 {classID: onuGClassID, alarmno: 6}: {EventName: "ONU_SELF_TEST_FAIL",
138 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu self-test failure"},
139 {classID: onuGClassID, alarmno: 7}: {EventName: "ONU_DYING_GASP",
140 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu DYING_GASP"},
141 {classID: onuGClassID, alarmno: 8}: {EventName: "ONU_TEMP_YELLOW",
142 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature yellow"},
143 {classID: onuGClassID, alarmno: 9}: {EventName: "ONU_TEMP_RED",
144 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature red"},
145 {classID: onuGClassID, alarmno: 10}: {EventName: "ONU_VOLTAGE_YELLOW",
146 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu voltage yellow"},
147 {classID: onuGClassID, alarmno: 11}: {EventName: "ONU_VOLTAGE_RED",
148 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu voltage red"},
149 {classID: aniGClassID, alarmno: 0}: {EventName: "ONU_LOW_RX_OPTICAL",
150 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu low rx optical power"},
151 {classID: aniGClassID, alarmno: 1}: {EventName: "ONU_HIGH_RX_OPTICAL",
152 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu high rx optical power"},
153 {classID: aniGClassID, alarmno: 4}: {EventName: "ONU_LOW_TX_OPTICAL",
154 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu low tx optical power"},
155 {classID: aniGClassID, alarmno: 5}: {EventName: "ONU_HIGH_TX_OPTICAL",
156 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu high tx optical power"},
157 {classID: aniGClassID, alarmno: 6}: {EventName: "ONU_LASER_BIAS_CURRENT",
158 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu laser bias current"},
159 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530160 alarmManager.alarmSyncFsm = NewAdapterFsm("AlarmSync", dh.deviceID, alarmManager.eventChannel)
161 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 Chawlad3dac422021-03-13 02:31:31 +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
Himani Chawla075f1642021-03-15 19:23:24 +0530187 if am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval > 0 {
Himani Chawlad3dac422021-03-13 02:31:31 +0530188 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 Chawlad3dac422021-03-13 02:31:31 +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 logger.Debugw(ctx, "alarm-sync-fsm", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
232 failureTransition := func() {
233 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
234 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
235 }
236 }
237 // See if there is any onu only diff, meaning the class and entity is only in onu DB
238 for alarm := range am.onuDBCopy {
239 if _, exists := am.oltDbCopy[meAlarmKey{
240 classID: alarm.classID,
241 instanceID: alarm.instanceID,
242 }]; !exists {
243 // We need to raise all such alarms as OLT wont have received notification for these alarms
244 omciAlarmMessage := &omci.AlarmNotificationMsg{
245 MeBasePacket: omci.MeBasePacket{
246 EntityClass: alarm.classID,
247 EntityInstance: alarm.instanceID,
248 },
249 AlarmBitmap: am.onuDBCopy[alarm],
250 }
251 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
252 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
253 // Transition to failure.
254 go failureTransition()
255 return
256 }
257 }
258 }
259 // See if there is any olt only diff, meaning the class and entity is only in olt DB
260 for alarm := range am.oltDbCopy {
261 if _, exists := am.onuDBCopy[meAlarmKey{
262 classID: alarm.classID,
263 instanceID: alarm.instanceID,
264 }]; !exists {
265 // We need to clear all such alarms as OLT might have stale data and the alarms are already cleared.
266 omciAlarmMessage := &omci.AlarmNotificationMsg{
267 MeBasePacket: omci.MeBasePacket{
268 EntityClass: alarm.classID,
269 EntityInstance: alarm.instanceID,
270 },
271 AlarmBitmap: am.oltDbCopy[alarm],
272 }
273 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
274 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
275 // Transition to failure
276 go failureTransition()
277 return
278 }
279 }
280 }
281 // See if there is any attribute difference
282 for alarm := range am.onuDBCopy {
283 if _, exists := am.oltDbCopy[alarm]; exists {
284 if am.onuDBCopy[alarm] != am.oltDbCopy[alarm] {
285 omciAlarmMessage := &omci.AlarmNotificationMsg{
286 MeBasePacket: omci.MeBasePacket{
287 EntityClass: alarm.classID,
288 EntityInstance: alarm.instanceID,
289 },
290 AlarmBitmap: am.onuDBCopy[alarm],
291 }
292 // We will assume that onudb is correct always in this case and process the changed bitmap.
293 if err := am.processAlarmData(ctx, omciAlarmMessage); err != nil {
294 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
295 // Transition to failure
296 go failureTransition()
297 return
298 }
299 }
300 }
301 }
302 // Send the buffered notifications if no failure.
303 for _, notif := range am.bufferedNotifications {
304 logger.Debugw(ctx, "processing-buffered-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID,
305 "notification": notif})
306 if err := am.processAlarmData(ctx, notif); err != nil {
307 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
308 go failureTransition()
309 }
310 }
311 go func() {
312 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
313 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
314 }
315 }()
316}
317
318func (am *onuAlarmManager) asFsmInSync(ctx context.Context, e *fsm.Event) {
319 logger.Debugw(ctx, "alarm-sync-fsm", log.Fields{"state": e.FSM.Current(), "device-id": am.pDeviceHandler.deviceID})
Himani Chawla075f1642021-03-15 19:23:24 +0530320 if am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval > 0 {
Himani Chawlad3dac422021-03-13 02:31:31 +0530321 select {
Himani Chawla075f1642021-03-15 19:23:24 +0530322 case <-time.After(am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval):
Himani Chawlad3dac422021-03-13 02:31:31 +0530323 go func() {
324 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
325 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
326 }
327 }()
328 case <-am.stopAlarmAuditTimer:
329 logger.Infow(ctx, "stopping-alarm-timer", log.Fields{"device-id": am.pDeviceHandler.deviceID})
330 return
331 }
332 }
333}
334
335func (am *onuAlarmManager) processAlarmSyncMessages(ctx context.Context) {
336 logger.Debugw(ctx, "start-routine-to-process-omci-messages-for-alarm-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID})
337 am.flushAlarmSyncChannels(ctx)
338loop:
339 for {
340 message, ok := <-am.eventChannel
341 if !ok {
342 logger.Info(ctx, "alarm-sync-omci-message-could-not-be-read-from-channel", log.Fields{"device-id": am.pDeviceHandler.deviceID})
343 break loop
344 }
345 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID})
346
347 switch message.Type {
348 case OMCI:
349 msg, _ := message.Data.(OmciMessage)
350 am.handleOmciMessage(ctx, msg)
351 default:
352 logger.Warn(ctx, "alarm-sync-unknown-message-type-received", log.Fields{"device-id": am.pDeviceHandler.deviceID, "message.Type": message.Type})
353 }
354 }
355 logger.Info(ctx, "alarm-sync-stopped-handling-of-alarm-sync-omci-message", log.Fields{"device-id": am.pDeviceHandler.deviceID})
356 _ = am.alarmSyncFsm.pFsm.Event(asEvStop)
357}
358
359func (am *onuAlarmManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
360 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
361 "msg-type": msg.OmciMsg.MessageType, "msg": msg})
362 switch msg.OmciMsg.MessageType {
363 case omci.GetAllAlarmsResponseType:
364 am.handleOmciGetAllAlarmsResponseMessage(ctx, msg)
365 case omci.GetAllAlarmsNextResponseType:
366 am.handleOmciGetAllAlarmNextResponseMessage(ctx, msg)
367 default:
368 logger.Warnw(ctx, "unknown-message-type", log.Fields{"msg-type": msg.OmciMsg.MessageType})
369
370 }
371}
372
373func (am *onuAlarmManager) handleOmciGetAllAlarmsResponseMessage(ctx context.Context, msg OmciMessage) {
374 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsResponse)
375 if msgLayer == nil {
376 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
377 return
378 }
379 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsResponse)
380 if !msgOk {
381 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
382 return
383 }
384 logger.Debugw(ctx, "get-all-alarm-response-data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
385 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
386 logger.Debugw(ctx, "alarm-sync-fsm-is-disabled-ignoring-response-message", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
387 return
388 }
389 am.alarmUploadNoOfCmds = msgObj.NumberOfCommands
390 failureTransition := func() {
391 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
392 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
393 }
394 }
395 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
396 // Reset Onu Alarm Sequence
397 am.onuAlarmManagerLock.Lock()
398 am.resetAlarmSequence()
399 // Get a copy of the alarm bit map db.
400 for alarms, bitmap := range am.alarmBitMapDB {
401 am.oltDbCopy[alarms] = bitmap
402 }
403 am.onuAlarmManagerLock.Unlock()
404 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
405 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
406 // Transition to failure
407 go failureTransition()
408 }
409 } else if am.alarmUploadNoOfCmds == 0 {
410 // Reset Onu Alarm Sequence
411 am.onuAlarmManagerLock.Lock()
412 am.resetAlarmSequence()
413 // Get a copy of the alarm bit map db.
414 for alarms, bitmap := range am.alarmBitMapDB {
415 am.oltDbCopy[alarms] = bitmap
416 }
417 am.onuAlarmManagerLock.Unlock()
418 if am.isAlarmDBDiffPresent(ctx) {
419 // transition to resync state
420 go func() {
421 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
422 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
423 }
424 }()
425 } else {
426 // Transition to sync state
427 go func() {
428 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
429 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
430 }
431 }()
432 }
433 } else {
434 logger.Errorw(ctx, "invalid-number-of-commands-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
435 "upload-no-of-cmds": am.alarmUploadNoOfCmds, "upload-seq-no": am.alarmUploadSeqNo})
436 go failureTransition()
437 }
438}
439
440func (am *onuAlarmManager) handleOmciGetAllAlarmNextResponseMessage(ctx context.Context, msg OmciMessage) {
441 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsNextResponse)
442
443 if msgLayer == nil {
444 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
445 return
446 }
447 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsNextResponse)
448 if !msgOk {
449 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
450 return
451 }
452 logger.Debugw(ctx, "get-all-alarms-next-response-data",
453 log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
454 meClassID := msgObj.AlarmEntityClass
455 meEntityID := msgObj.AlarmEntityInstance
456 meAlarmBitMap := msgObj.AlarmBitMap
457
458 am.onuAlarmManagerLock.Lock()
459 am.onuDBCopy[meAlarmKey{
460 classID: meClassID,
461 instanceID: meEntityID,
462 }] = meAlarmBitMap
463 am.onuAlarmManagerLock.Unlock()
464 failureTransition := func() {
465 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
466 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
467 }
468 }
469 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
470 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
471 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
472 // Transition to failure
473 go failureTransition()
474 } //TODO: needs to handle timeouts
475 } else {
476 if am.isAlarmDBDiffPresent(ctx) {
477 // transition to resync state
478 go func() {
479 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
480 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
481 }
482 }()
483 } else {
484 // Transition to sync state
485 go func() {
486 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
487 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
488 }
489 }()
490 }
491 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530492}
493
494func (am *onuAlarmManager) startOMCIAlarmMessageProcessing(ctx context.Context) {
495 am.onuAlarmManagerLock.Lock()
496 am.processMessage = true
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530497 if am.activeAlarms == nil {
498 am.activeAlarms = make(map[alarmInfo]struct{})
499 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530500 am.alarmBitMapDB = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530501 am.onuAlarmManagerLock.Unlock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530502 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
503 if err := am.alarmSyncFsm.pFsm.Event(asEvStart); err != nil {
504 logger.Errorw(ctx, "alarm-sync-fsm-can-not-go-to-state-starting", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
505 return
506 }
507 } else {
508 logger.Errorw(ctx, "wrong-state-of-alarm-sync-fsm-want-disabled", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current()),
509 "device-id": am.pDeviceHandler.deviceID})
510 return
511 }
512 logger.Debugw(ctx, "alarm-sync-fsm-started", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current())})
513
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530514 if stop := <-am.stopProcessingOmciMessages; stop {
515 am.onuAlarmManagerLock.Lock()
516 am.processMessage = false
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530517 am.activeAlarms = nil
Himani Chawlad3dac422021-03-13 02:31:31 +0530518 am.alarmBitMapDB = nil
519 am.alarmUploadNoOfCmds = 0
520 am.alarmUploadSeqNo = 0
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530521 am.onuAlarmManagerLock.Unlock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530522
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530523 }
524}
525
526func (am *onuAlarmManager) handleOmciAlarmNotificationMessage(ctx context.Context, msg OmciMessage) {
Himani Chawlad3dac422021-03-13 02:31:31 +0530527 logger.Debugw(ctx, "omci-alarm-notification-msg", log.Fields{"device-id": am.pDeviceHandler.deviceID,
528 "msg-type": msg.OmciMsg.MessageType})
529 am.onuAlarmManagerLock.RLock()
530 processMessage := am.processMessage
531 am.onuAlarmManagerLock.RUnlock()
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530532
Himani Chawlad3dac422021-03-13 02:31:31 +0530533 if processMessage {
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530534 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeAlarmNotification)
535 if msgLayer == nil {
Himani Chawlad3dac422021-03-13 02:31:31 +0530536 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected-for-alarm-notification",
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530537 log.Fields{"device-id": am.pDeviceHandler.deviceID})
538 return
539 }
540 msgObj, msgOk := msgLayer.(*omci.AlarmNotificationMsg)
541 if !msgOk {
Himani Chawlad3dac422021-03-13 02:31:31 +0530542 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned-for-alarm-notification",
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530543 log.Fields{"device-id": am.pDeviceHandler.deviceID})
544 return
545 }
546 //Alarm Notification decoding at omci lib validates that the me class ID supports the
547 // alarm notifications.
Himani Chawlad3dac422021-03-13 02:31:31 +0530548 logger.Debugw(ctx, "alarm-notification-data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530549 if err := am.processAlarmData(ctx, msgObj); err != nil {
550 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
551 }
552
553 } else {
554 logger.Warnw(ctx, "ignoring-alarm-notification-received-for-me-as-channel-for-processing-is-closed",
555 log.Fields{"device-id": am.pDeviceHandler.deviceID})
556 }
557}
558
559func (am *onuAlarmManager) processAlarmData(ctx context.Context, msg *omci.AlarmNotificationMsg) error {
560 classID := msg.EntityClass
561 sequenceNo := msg.AlarmSequenceNumber
562 meInstance := msg.EntityInstance
563 alarmBitmap := msg.AlarmBitmap
564 logger.Debugw(ctx, "processing-alarm-data", log.Fields{"class-id": classID, "instance-id": meInstance,
565 "alarmBitMap": alarmBitmap, "sequence-no": sequenceNo})
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530566 if _, present := am.pDeviceHandler.pOnuOmciDevice.pOnuDB.meDb[classID][meInstance]; !present {
567 logger.Errorw(ctx, "me-class-instance-not-present", log.Fields{"class-id": classID, "instance-id": meInstance})
568 return fmt.Errorf("me-class-%d-instance-%d-not-present", classID, meInstance)
569 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530570 am.onuAlarmManagerLock.Lock()
571 defer am.onuAlarmManagerLock.Unlock()
572 if sequenceNo > 0 {
573 if am.alarmSyncFsm.pFsm.Is(asStAuditing) || am.alarmSyncFsm.pFsm.Is(asStResynchronizing) {
574 am.bufferedNotifications = append(am.bufferedNotifications, msg)
575 logger.Debugw(ctx, "adding-notification-to-buffered-notification-list", log.Fields{"device-id": am.pDeviceHandler.deviceID,
576 "notification": msg})
577 return nil
Andrea Campanellace915292021-03-12 17:59:35 +0000578 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530579 am.incrementAlarmSequence()
Himani Chawla075f1642021-03-15 19:23:24 +0530580 if sequenceNo != am.lastAlarmSequence && am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval > 0 {
Himani Chawlad3dac422021-03-13 02:31:31 +0530581 // signal early audit, if no match(if we are reaching here it means that audit is not going on currently)
582 go func() {
583 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
584 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
585 }
586 }()
587 }
588 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530589 entity, omciErr := me.LoadManagedEntityDefinition(classID,
590 me.ParamData{EntityID: meInstance})
591 if omciErr.StatusCode() != me.Success {
592 //log error and return
593 logger.Error(ctx, "unable-to-get-managed-entity", log.Fields{"class-id": classID, "instance-id": meInstance})
594 return fmt.Errorf("unable-to-get-managed-entity-class-%d-instance-%d", classID, meInstance)
595 }
596 meAlarmMap := entity.GetAlarmMap()
597 if meAlarmMap == nil {
598 logger.Error(ctx, "unable-to-get-managed-entity-alarm-map", log.Fields{"class-id": classID, "instance-id": meInstance})
599 return fmt.Errorf("unable-to-get-managed-entity-alarm-map-%d-instance-%d", classID, meInstance)
600 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530601
602 am.alarmBitMapDB[meAlarmKey{
603 classID: classID,
604 instanceID: meInstance,
605 }] = alarmBitmap
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530606 // Loop over the supported alarm list for this me
607 for alarmNo := range meAlarmMap {
608 // Check if alarmNo was previously active in the alarms, if yes clear it and remove it from active alarms
609 _, exists := am.activeAlarms[alarmInfo{
610 classID: classID,
611 instanceID: meInstance,
612 alarmNo: alarmNo,
613 }]
614 if exists {
615 // Clear this alarm if It is cleared now, in that case IsAlarmClear would return true
616 cleared, err := msg.IsAlarmClear(alarmNo)
617 if err != nil {
618 logger.Warnw(ctx, "unable-to-find-out-alarm-is-cleared", log.Fields{"class-id": classID,
619 "instance-id": meInstance, "alarm-no": alarmNo})
620 return err
621 }
622 if cleared {
623 // Clear this alarm.
624 am.clearAlarm(ctx, classID, meInstance, alarmNo)
625 }
626 } else {
627 // If alarm entry was not present in the list of active alarms, we need to see if this alarm is now active
628 // or not, if yes then raise it.
629 raised, err := msg.IsAlarmActive(alarmNo)
630 if err != nil {
631 logger.Warnw(ctx, "unable-to-find-out-alarm-is-raised", log.Fields{"class-id": classID,
632 "instance-id": meInstance, "alarm-no": alarmNo})
633 return err
634 }
635 if raised {
636 am.raiseAlarm(ctx, classID, meInstance, alarmNo)
637 }
638 }
639 }
640 return nil
641}
642
643func (am *onuAlarmManager) raiseAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
644 am.activeAlarms[alarmInfo{
645 classID: classID,
646 instanceID: instanceID,
647 alarmNo: alarm,
648 }] = struct{}{}
Himani Chawlad3dac422021-03-13 02:31:31 +0530649
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530650 go am.sendAlarm(ctx, classID, instanceID, alarm, true)
651}
652
653func (am *onuAlarmManager) clearAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
654 go am.sendAlarm(ctx, classID, instanceID, alarm, false)
655 delete(am.activeAlarms, alarmInfo{
656 classID: classID,
657 instanceID: instanceID,
658 alarmNo: alarm,
659 })
Himani Chawlad3dac422021-03-13 02:31:31 +0530660 key := meAlarmKey{
661 classID: classID,
662 instanceID: instanceID,
663 }
664 if am.alarmBitMapDB[key] == [alarmBitMapSizeBytes]byte{0} {
665 delete(am.alarmBitMapDB, key)
666 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530667}
668
669func (am *onuAlarmManager) getIntfIDAlarm(ctx context.Context, classID me.ClassID, instanceID uint16) *uint32 {
670 var intfID *uint32
671 if classID == circuitPackClassID || classID == physicalPathTerminationPointEthernetUniClassID {
672 for _, uniPort := range am.pDeviceHandler.uniEntityMap {
673 if uniPort.entityID == instanceID {
674 intfID = &uniPort.portNo
675 return intfID
676 }
677 }
678 } else if classID == aniGClassID || classID == onuGClassID {
679 intfID = &am.pDeviceHandler.ponPortNumber
680 return intfID
681 } else {
682 logger.Warnw(ctx, "me-not-supported", log.Fields{"class-id": classID, "instance-id": instanceID})
683 }
684 return nil
685}
686
687func (am *onuAlarmManager) sendAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8, raised bool) {
688 context := make(map[string]string)
689 intfID := am.getIntfIDAlarm(ctx, classID, instanceID)
690 onuID := am.pDeviceHandler.deviceID
Holger Hildebrandtbe523842021-03-10 10:47:18 +0000691 serialNo := am.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersSerialNumber
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530692 if intfID == nil {
693 logger.Warn(ctx, "intf-id-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
694 return
695 }
696 context["onu-intf-id"] = fmt.Sprintf("%d", *intfID)
697 context["onu-id"] = onuID
698 context["onu-serial-number"] = serialNo
699
700 raisedTimestamp := time.Now().UnixNano()
701 eventDetails, err := am.getDeviceEventData(ctx, classID, alarm)
702 if err != nil {
703 logger.Warn(ctx, "event-details-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
704 return
705 }
706 suffixDesc := "Raised"
707 if !raised {
708 suffixDesc = "Cleared"
709 }
710 deviceEvent := &voltha.DeviceEvent{
711 ResourceId: onuID,
712 DeviceEventName: fmt.Sprintf("%s_RAISE_EVENT", eventDetails.EventName),
713 Description: fmt.Sprintf("%s Event - %s - %s", eventDetails.EventDescription, eventDetails.EventName,
714 suffixDesc),
715 Context: context,
716 }
717 _ = am.eventProxy.SendDeviceEvent(ctx, deviceEvent, eventDetails.EventCategory, eventDetails.EventSubCategory,
718 raisedTimestamp)
719}
Himani Chawlad3dac422021-03-13 02:31:31 +0530720
721func (am *onuAlarmManager) isAlarmDBDiffPresent(ctx context.Context) bool {
722 return !reflect.DeepEqual(am.onuDBCopy, am.oltDbCopy)
723}
724
725func (am *onuAlarmManager) incrementAlarmSequence() {
726 //alarm sequence number wraps from 255 to 1.
727 if am.lastAlarmSequence == 255 {
728 am.lastAlarmSequence = 1
729 } else {
730 am.lastAlarmSequence++
731 }
732}
733
734func (am *onuAlarmManager) resetAlarmSequence() {
735 am.lastAlarmSequence = 0
736}
737
738// flushAlarmSyncChannels flushes all alarm sync channels to discard any previous response
739func (am *onuAlarmManager) flushAlarmSyncChannels(ctx context.Context) {
740 // flush alarm sync channel
741 select {
742 case <-am.eventChannel:
743 logger.Debug(ctx, "flushed-alarm-sync-channel")
744 default:
745 }
746 select {
747 case <-am.stopAlarmAuditTimer:
748 logger.Debug(ctx, "flushed-alarm-audit-timer-channel")
749 default:
750 }
751}
752
753// getDeviceEventData returns the event data for a device
754func (am *onuAlarmManager) getDeviceEventData(ctx context.Context, classID me.ClassID, alarmNo uint8) (onuDeviceEvent, error) {
755 if onuEventDetails, ok := am.onuEventsList[onuDevice{classID: classID, alarmno: alarmNo}]; ok {
756 return onuEventDetails, nil
757 }
758 return onuDeviceEvent{}, errors.New("onu Event Detail not found")
759}