blob: 5b070ab27066a639fcc725907fe220b9d84133e6 [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})
Himani Chawlad3dac422021-03-13 02:31:31 +0530337 for {
Himani Chawla1472c682021-03-17 17:11:14 +0530338 select {
339 case message, ok := <-am.eventChannel:
340 if !ok {
341 logger.Info(ctx, "alarm-sync-omci-message-could-not-be-read-from-channel", log.Fields{"device-id": am.pDeviceHandler.deviceID})
342 continue
343 }
344 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID})
Himani Chawlad3dac422021-03-13 02:31:31 +0530345
Himani Chawla1472c682021-03-17 17:11:14 +0530346 switch message.Type {
347 case OMCI:
348 msg, _ := message.Data.(OmciMessage)
349 am.handleOmciMessage(ctx, msg)
350 default:
351 logger.Warn(ctx, "alarm-sync-unknown-message-type-received", log.Fields{"device-id": am.pDeviceHandler.deviceID, "message.Type": message.Type})
352 }
353 case <-am.stopProcessingOmciMessages:
354 logger.Infow(ctx, "alarm-manager-stop-omci-alarm-message-processing-routines", log.Fields{"device-id": am.pDeviceHandler.deviceID})
355 am.onuAlarmManagerLock.Lock()
356 am.processMessage = false
357 am.activeAlarms = nil
358 am.alarmBitMapDB = nil
359 am.alarmUploadNoOfCmds = 0
360 am.alarmUploadSeqNo = 0
361 am.onuAlarmManagerLock.Unlock()
362 return
363
Himani Chawlad3dac422021-03-13 02:31:31 +0530364 }
365 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530366}
367
368func (am *onuAlarmManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
369 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
370 "msg-type": msg.OmciMsg.MessageType, "msg": msg})
371 switch msg.OmciMsg.MessageType {
372 case omci.GetAllAlarmsResponseType:
373 am.handleOmciGetAllAlarmsResponseMessage(ctx, msg)
374 case omci.GetAllAlarmsNextResponseType:
375 am.handleOmciGetAllAlarmNextResponseMessage(ctx, msg)
376 default:
377 logger.Warnw(ctx, "unknown-message-type", log.Fields{"msg-type": msg.OmciMsg.MessageType})
378
379 }
380}
381
382func (am *onuAlarmManager) handleOmciGetAllAlarmsResponseMessage(ctx context.Context, msg OmciMessage) {
383 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsResponse)
384 if msgLayer == nil {
385 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
386 return
387 }
388 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsResponse)
389 if !msgOk {
390 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
391 return
392 }
393 logger.Debugw(ctx, "get-all-alarm-response-data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
394 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
395 logger.Debugw(ctx, "alarm-sync-fsm-is-disabled-ignoring-response-message", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
396 return
397 }
398 am.alarmUploadNoOfCmds = msgObj.NumberOfCommands
399 failureTransition := func() {
400 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
401 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
402 }
403 }
404 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
405 // Reset Onu Alarm Sequence
406 am.onuAlarmManagerLock.Lock()
407 am.resetAlarmSequence()
408 // Get a copy of the alarm bit map db.
409 for alarms, bitmap := range am.alarmBitMapDB {
410 am.oltDbCopy[alarms] = bitmap
411 }
412 am.onuAlarmManagerLock.Unlock()
413 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
414 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
415 // Transition to failure
416 go failureTransition()
417 }
418 } else if am.alarmUploadNoOfCmds == 0 {
419 // Reset Onu Alarm Sequence
420 am.onuAlarmManagerLock.Lock()
421 am.resetAlarmSequence()
422 // Get a copy of the alarm bit map db.
423 for alarms, bitmap := range am.alarmBitMapDB {
424 am.oltDbCopy[alarms] = bitmap
425 }
426 am.onuAlarmManagerLock.Unlock()
427 if am.isAlarmDBDiffPresent(ctx) {
428 // transition to resync state
429 go func() {
430 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
431 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
432 }
433 }()
434 } else {
435 // Transition to sync state
436 go func() {
437 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
438 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
439 }
440 }()
441 }
442 } else {
443 logger.Errorw(ctx, "invalid-number-of-commands-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
444 "upload-no-of-cmds": am.alarmUploadNoOfCmds, "upload-seq-no": am.alarmUploadSeqNo})
445 go failureTransition()
446 }
447}
448
449func (am *onuAlarmManager) handleOmciGetAllAlarmNextResponseMessage(ctx context.Context, msg OmciMessage) {
450 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsNextResponse)
451
452 if msgLayer == nil {
453 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
454 return
455 }
456 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsNextResponse)
457 if !msgOk {
458 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
459 return
460 }
461 logger.Debugw(ctx, "get-all-alarms-next-response-data",
462 log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
463 meClassID := msgObj.AlarmEntityClass
464 meEntityID := msgObj.AlarmEntityInstance
465 meAlarmBitMap := msgObj.AlarmBitMap
466
467 am.onuAlarmManagerLock.Lock()
468 am.onuDBCopy[meAlarmKey{
469 classID: meClassID,
470 instanceID: meEntityID,
471 }] = meAlarmBitMap
472 am.onuAlarmManagerLock.Unlock()
473 failureTransition := func() {
474 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
475 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
476 }
477 }
478 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
479 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
480 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
481 // Transition to failure
482 go failureTransition()
483 } //TODO: needs to handle timeouts
484 } else {
485 if am.isAlarmDBDiffPresent(ctx) {
486 // transition to resync state
487 go func() {
488 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
489 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
490 }
491 }()
492 } else {
493 // Transition to sync state
494 go func() {
495 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
496 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
497 }
498 }()
499 }
500 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530501}
502
503func (am *onuAlarmManager) startOMCIAlarmMessageProcessing(ctx context.Context) {
Himani Chawla1472c682021-03-17 17:11:14 +0530504 logger.Infow(ctx, "alarm-manager-start-omci-alarm-message-processing-routines", log.Fields{"device-id": am.pDeviceHandler.deviceID})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530505 am.onuAlarmManagerLock.Lock()
506 am.processMessage = true
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530507 if am.activeAlarms == nil {
508 am.activeAlarms = make(map[alarmInfo]struct{})
509 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530510 am.alarmBitMapDB = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530511 am.onuAlarmManagerLock.Unlock()
Himani Chawla1472c682021-03-17 17:11:14 +0530512 am.flushAlarmSyncChannels(ctx) // Need to do this first as there might be stale data on the channels and the start state waits on same channels
513
Himani Chawlad3dac422021-03-13 02:31:31 +0530514 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
515 if err := am.alarmSyncFsm.pFsm.Event(asEvStart); err != nil {
516 logger.Errorw(ctx, "alarm-sync-fsm-can-not-go-to-state-starting", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
517 return
518 }
519 } else {
520 logger.Errorw(ctx, "wrong-state-of-alarm-sync-fsm-want-disabled", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current()),
521 "device-id": am.pDeviceHandler.deviceID})
522 return
523 }
524 logger.Debugw(ctx, "alarm-sync-fsm-started", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current())})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530525}
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()
Himani Chawla075f1642021-03-15 19:23:24 +0530581 if sequenceNo != am.lastAlarmSequence && am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval > 0 {
Himani Chawlad3dac422021-03-13 02:31:31 +0530582 // 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}