blob: 6bbceb649c40b8c51615dc8aa179990de95c7a8e [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"
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +000024 "reflect"
25 "sync"
26 "time"
27
Himani Chawlad3dac422021-03-13 02:31:31 +053028 "github.com/looplab/fsm"
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053029 "github.com/opencord/omci-lib-go"
30 me "github.com/opencord/omci-lib-go/generated"
31 "github.com/opencord/voltha-lib-go/v4/pkg/events/eventif"
32 "github.com/opencord/voltha-lib-go/v4/pkg/log"
33 "github.com/opencord/voltha-protos/v4/go/voltha"
34)
35
36const (
37 circuitPackClassID = me.CircuitPackClassID
38 physicalPathTerminationPointEthernetUniClassID = me.PhysicalPathTerminationPointEthernetUniClassID
39 onuGClassID = me.OnuGClassID
40 aniGClassID = me.AniGClassID
Himani Chawlad3dac422021-03-13 02:31:31 +053041 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
Himani Chawla075f1642021-03-15 19:23:24 +0530188 if am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval > 0 {
Himani Chawlad3dac422021-03-13 02:31:31 +0530189 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})
Himani Chawla075f1642021-03-15 19:23:24 +0530321 if am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval > 0 {
Himani Chawlad3dac422021-03-13 02:31:31 +0530322 select {
Himani Chawla075f1642021-03-15 19:23:24 +0530323 case <-time.After(am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval):
Himani Chawlad3dac422021-03-13 02:31:31 +0530324 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})
Himani Chawlad3dac422021-03-13 02:31:31 +0530338 for {
Himani Chawla1472c682021-03-17 17:11:14 +0530339 select {
340 case 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 continue
344 }
345 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID})
Himani Chawlad3dac422021-03-13 02:31:31 +0530346
Himani Chawla1472c682021-03-17 17:11:14 +0530347 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 case <-am.stopProcessingOmciMessages:
355 logger.Infow(ctx, "alarm-manager-stop-omci-alarm-message-processing-routines", log.Fields{"device-id": am.pDeviceHandler.deviceID})
356 am.onuAlarmManagerLock.Lock()
357 am.processMessage = false
358 am.activeAlarms = nil
359 am.alarmBitMapDB = nil
360 am.alarmUploadNoOfCmds = 0
361 am.alarmUploadSeqNo = 0
362 am.onuAlarmManagerLock.Unlock()
363 return
364
Himani Chawlad3dac422021-03-13 02:31:31 +0530365 }
366 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530367}
368
369func (am *onuAlarmManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
370 logger.Debugw(ctx, "alarm-sync-omci-message-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
371 "msg-type": msg.OmciMsg.MessageType, "msg": msg})
372 switch msg.OmciMsg.MessageType {
373 case omci.GetAllAlarmsResponseType:
374 am.handleOmciGetAllAlarmsResponseMessage(ctx, msg)
375 case omci.GetAllAlarmsNextResponseType:
376 am.handleOmciGetAllAlarmNextResponseMessage(ctx, msg)
377 default:
378 logger.Warnw(ctx, "unknown-message-type", log.Fields{"msg-type": msg.OmciMsg.MessageType})
379
380 }
381}
382
383func (am *onuAlarmManager) handleOmciGetAllAlarmsResponseMessage(ctx context.Context, msg OmciMessage) {
384 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsResponse)
385 if msgLayer == nil {
386 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
387 return
388 }
389 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsResponse)
390 if !msgOk {
391 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
392 return
393 }
394 logger.Debugw(ctx, "get-all-alarm-response-data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
395 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
396 logger.Debugw(ctx, "alarm-sync-fsm-is-disabled-ignoring-response-message", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
397 return
398 }
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000399 am.onuAlarmManagerLock.Lock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530400 am.alarmUploadNoOfCmds = msgObj.NumberOfCommands
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000401 am.onuAlarmManagerLock.Unlock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530402 failureTransition := func() {
403 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
404 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
405 }
406 }
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000407 am.onuAlarmManagerLock.Lock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530408 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
409 // Reset Onu Alarm Sequence
Himani Chawlad3dac422021-03-13 02:31:31 +0530410 am.resetAlarmSequence()
411 // Get a copy of the alarm bit map db.
412 for alarms, bitmap := range am.alarmBitMapDB {
413 am.oltDbCopy[alarms] = bitmap
414 }
415 am.onuAlarmManagerLock.Unlock()
416 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
417 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
418 // Transition to failure
419 go failureTransition()
420 }
421 } else if am.alarmUploadNoOfCmds == 0 {
422 // Reset Onu Alarm Sequence
Himani Chawlad3dac422021-03-13 02:31:31 +0530423 am.resetAlarmSequence()
424 // Get a copy of the alarm bit map db.
425 for alarms, bitmap := range am.alarmBitMapDB {
426 am.oltDbCopy[alarms] = bitmap
427 }
428 am.onuAlarmManagerLock.Unlock()
429 if am.isAlarmDBDiffPresent(ctx) {
430 // transition to resync state
431 go func() {
432 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
433 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
434 }
435 }()
436 } else {
437 // Transition to sync state
438 go func() {
439 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
440 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
441 }
442 }()
443 }
444 } else {
445 logger.Errorw(ctx, "invalid-number-of-commands-received", log.Fields{"device-id": am.pDeviceHandler.deviceID,
446 "upload-no-of-cmds": am.alarmUploadNoOfCmds, "upload-seq-no": am.alarmUploadSeqNo})
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000447 am.onuAlarmManagerLock.Unlock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530448 go failureTransition()
449 }
450}
451
452func (am *onuAlarmManager) handleOmciGetAllAlarmNextResponseMessage(ctx context.Context, msg OmciMessage) {
453 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetAllAlarmsNextResponse)
454
455 if msgLayer == nil {
456 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected", log.Fields{"device-id": am.pDeviceHandler.deviceID})
457 return
458 }
459 msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsNextResponse)
460 if !msgOk {
461 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned", log.Fields{"device-id": am.pDeviceHandler.deviceID})
462 return
463 }
464 logger.Debugw(ctx, "get-all-alarms-next-response-data",
465 log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
466 meClassID := msgObj.AlarmEntityClass
467 meEntityID := msgObj.AlarmEntityInstance
468 meAlarmBitMap := msgObj.AlarmBitMap
469
470 am.onuAlarmManagerLock.Lock()
471 am.onuDBCopy[meAlarmKey{
472 classID: meClassID,
473 instanceID: meEntityID,
474 }] = meAlarmBitMap
475 am.onuAlarmManagerLock.Unlock()
476 failureTransition := func() {
477 if err := am.alarmSyncFsm.pFsm.Event(asEvFailure); err != nil {
478 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-failure", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
479 }
480 }
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000481 am.onuAlarmManagerLock.RLock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530482 if am.alarmUploadSeqNo < am.alarmUploadNoOfCmds {
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000483 am.onuAlarmManagerLock.RUnlock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530484 if err := am.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetAllAlarmNext(
485 log.WithSpanFromContext(context.TODO(), ctx), am.pDeviceHandler.pOpenOnuAc.omciTimeout, true); err != nil {
486 // Transition to failure
487 go failureTransition()
488 } //TODO: needs to handle timeouts
489 } else {
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000490 am.onuAlarmManagerLock.RUnlock()
Himani Chawlad3dac422021-03-13 02:31:31 +0530491 if am.isAlarmDBDiffPresent(ctx) {
492 // transition to resync state
493 go func() {
494 if err := am.alarmSyncFsm.pFsm.Event(asEvResync); err != nil {
495 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-resynchronizing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
496 }
497 }()
498 } else {
499 // Transition to sync state
500 go func() {
501 if err := am.alarmSyncFsm.pFsm.Event(asEvSuccess); err != nil {
502 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-sync", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
503 }
504 }()
505 }
506 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530507}
508
509func (am *onuAlarmManager) startOMCIAlarmMessageProcessing(ctx context.Context) {
Himani Chawla1472c682021-03-17 17:11:14 +0530510 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 +0530511 am.onuAlarmManagerLock.Lock()
512 am.processMessage = true
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530513 if am.activeAlarms == nil {
514 am.activeAlarms = make(map[alarmInfo]struct{})
515 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530516 am.alarmBitMapDB = make(map[meAlarmKey][alarmBitMapSizeBytes]byte)
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530517 am.onuAlarmManagerLock.Unlock()
Himani Chawla1472c682021-03-17 17:11:14 +0530518 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
519
Himani Chawlad3dac422021-03-13 02:31:31 +0530520 if am.alarmSyncFsm.pFsm.Is(asStDisabled) {
521 if err := am.alarmSyncFsm.pFsm.Event(asEvStart); err != nil {
522 logger.Errorw(ctx, "alarm-sync-fsm-can-not-go-to-state-starting", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
523 return
524 }
525 } else {
526 logger.Errorw(ctx, "wrong-state-of-alarm-sync-fsm-want-disabled", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current()),
527 "device-id": am.pDeviceHandler.deviceID})
528 return
529 }
530 logger.Debugw(ctx, "alarm-sync-fsm-started", log.Fields{"state": string(am.alarmSyncFsm.pFsm.Current())})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530531}
532
533func (am *onuAlarmManager) handleOmciAlarmNotificationMessage(ctx context.Context, msg OmciMessage) {
Himani Chawlad3dac422021-03-13 02:31:31 +0530534 logger.Debugw(ctx, "omci-alarm-notification-msg", log.Fields{"device-id": am.pDeviceHandler.deviceID,
535 "msg-type": msg.OmciMsg.MessageType})
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530536
Himani Chawla7998aa92021-04-07 14:16:52 +0530537 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeAlarmNotification)
538 if msgLayer == nil {
539 logger.Errorw(ctx, "omci-msg-layer-could-not-be-detected-for-alarm-notification",
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530540 log.Fields{"device-id": am.pDeviceHandler.deviceID})
Himani Chawla7998aa92021-04-07 14:16:52 +0530541 return
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530542 }
Himani Chawla7998aa92021-04-07 14:16:52 +0530543 msgObj, msgOk := msgLayer.(*omci.AlarmNotificationMsg)
544 if !msgOk {
545 logger.Errorw(ctx, "omci-msg-layer-could-not-be-assigned-for-alarm-notification",
546 log.Fields{"device-id": am.pDeviceHandler.deviceID})
547 return
548 }
549 //Alarm Notification decoding at omci lib validates that the me class ID supports the
550 // alarm notifications.
551 logger.Debugw(ctx, "alarm-notification-data-received", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
552 if err := am.processAlarmData(ctx, msgObj); err != nil {
553 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
554 }
555
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530556}
557
558func (am *onuAlarmManager) processAlarmData(ctx context.Context, msg *omci.AlarmNotificationMsg) error {
559 classID := msg.EntityClass
560 sequenceNo := msg.AlarmSequenceNumber
561 meInstance := msg.EntityInstance
562 alarmBitmap := msg.AlarmBitmap
563 logger.Debugw(ctx, "processing-alarm-data", log.Fields{"class-id": classID, "instance-id": meInstance,
564 "alarmBitMap": alarmBitmap, "sequence-no": sequenceNo})
Himani Chawla7998aa92021-04-07 14:16:52 +0530565 am.onuAlarmManagerLock.Lock()
566 defer am.onuAlarmManagerLock.Unlock()
567 if !am.processMessage {
568 logger.Warnw(ctx, "ignoring-alarm-notification-received-for-me-as-channel-for-processing-is-closed",
569 log.Fields{"device-id": am.pDeviceHandler.deviceID})
570 return fmt.Errorf("alarm-manager-is-in-stopped-state")
571 }
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530572 if _, present := am.pDeviceHandler.pOnuOmciDevice.pOnuDB.meDb[classID][meInstance]; !present {
573 logger.Errorw(ctx, "me-class-instance-not-present", log.Fields{"class-id": classID, "instance-id": meInstance})
574 return fmt.Errorf("me-class-%d-instance-%d-not-present", classID, meInstance)
575 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530576 if sequenceNo > 0 {
577 if am.alarmSyncFsm.pFsm.Is(asStAuditing) || am.alarmSyncFsm.pFsm.Is(asStResynchronizing) {
578 am.bufferedNotifications = append(am.bufferedNotifications, msg)
579 logger.Debugw(ctx, "adding-notification-to-buffered-notification-list", log.Fields{"device-id": am.pDeviceHandler.deviceID,
580 "notification": msg})
581 return nil
Andrea Campanellace915292021-03-12 17:59:35 +0000582 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530583 am.incrementAlarmSequence()
Himani Chawla075f1642021-03-15 19:23:24 +0530584 if sequenceNo != am.lastAlarmSequence && am.pDeviceHandler.pOnuOmciDevice.alarmAuditInterval > 0 {
Himani Chawlad3dac422021-03-13 02:31:31 +0530585 // signal early audit, if no match(if we are reaching here it means that audit is not going on currently)
586 go func() {
587 if err := am.alarmSyncFsm.pFsm.Event(asEvAudit); err != nil {
588 logger.Debugw(ctx, "alarm-sync-fsm-cannot-go-to-state-auditing", log.Fields{"device-id": am.pDeviceHandler.deviceID, "err": err})
589 }
590 }()
591 }
592 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530593 entity, omciErr := me.LoadManagedEntityDefinition(classID,
594 me.ParamData{EntityID: meInstance})
595 if omciErr.StatusCode() != me.Success {
596 //log error and return
597 logger.Error(ctx, "unable-to-get-managed-entity", log.Fields{"class-id": classID, "instance-id": meInstance})
598 return fmt.Errorf("unable-to-get-managed-entity-class-%d-instance-%d", classID, meInstance)
599 }
600 meAlarmMap := entity.GetAlarmMap()
601 if meAlarmMap == nil {
602 logger.Error(ctx, "unable-to-get-managed-entity-alarm-map", log.Fields{"class-id": classID, "instance-id": meInstance})
603 return fmt.Errorf("unable-to-get-managed-entity-alarm-map-%d-instance-%d", classID, meInstance)
604 }
Himani Chawlad3dac422021-03-13 02:31:31 +0530605
606 am.alarmBitMapDB[meAlarmKey{
607 classID: classID,
608 instanceID: meInstance,
609 }] = alarmBitmap
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530610 // Loop over the supported alarm list for this me
611 for alarmNo := range meAlarmMap {
612 // Check if alarmNo was previously active in the alarms, if yes clear it and remove it from active alarms
613 _, exists := am.activeAlarms[alarmInfo{
614 classID: classID,
615 instanceID: meInstance,
616 alarmNo: alarmNo,
617 }]
618 if exists {
619 // Clear this alarm if It is cleared now, in that case IsAlarmClear would return true
620 cleared, err := msg.IsAlarmClear(alarmNo)
621 if err != nil {
622 logger.Warnw(ctx, "unable-to-find-out-alarm-is-cleared", log.Fields{"class-id": classID,
623 "instance-id": meInstance, "alarm-no": alarmNo})
624 return err
625 }
626 if cleared {
627 // Clear this alarm.
628 am.clearAlarm(ctx, classID, meInstance, alarmNo)
629 }
630 } else {
631 // If alarm entry was not present in the list of active alarms, we need to see if this alarm is now active
632 // or not, if yes then raise it.
633 raised, err := msg.IsAlarmActive(alarmNo)
634 if err != nil {
635 logger.Warnw(ctx, "unable-to-find-out-alarm-is-raised", log.Fields{"class-id": classID,
636 "instance-id": meInstance, "alarm-no": alarmNo})
637 return err
638 }
639 if raised {
640 am.raiseAlarm(ctx, classID, meInstance, alarmNo)
641 }
642 }
643 }
644 return nil
645}
646
647func (am *onuAlarmManager) raiseAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
648 am.activeAlarms[alarmInfo{
649 classID: classID,
650 instanceID: instanceID,
651 alarmNo: alarm,
652 }] = struct{}{}
Himani Chawlad3dac422021-03-13 02:31:31 +0530653
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530654 go am.sendAlarm(ctx, classID, instanceID, alarm, true)
655}
656
657func (am *onuAlarmManager) clearAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
658 go am.sendAlarm(ctx, classID, instanceID, alarm, false)
659 delete(am.activeAlarms, alarmInfo{
660 classID: classID,
661 instanceID: instanceID,
662 alarmNo: alarm,
663 })
Himani Chawlad3dac422021-03-13 02:31:31 +0530664 key := meAlarmKey{
665 classID: classID,
666 instanceID: instanceID,
667 }
668 if am.alarmBitMapDB[key] == [alarmBitMapSizeBytes]byte{0} {
669 delete(am.alarmBitMapDB, key)
670 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530671}
672
673func (am *onuAlarmManager) getIntfIDAlarm(ctx context.Context, classID me.ClassID, instanceID uint16) *uint32 {
674 var intfID *uint32
675 if classID == circuitPackClassID || classID == physicalPathTerminationPointEthernetUniClassID {
676 for _, uniPort := range am.pDeviceHandler.uniEntityMap {
677 if uniPort.entityID == instanceID {
678 intfID = &uniPort.portNo
679 return intfID
680 }
681 }
682 } else if classID == aniGClassID || classID == onuGClassID {
683 intfID = &am.pDeviceHandler.ponPortNumber
684 return intfID
685 } else {
686 logger.Warnw(ctx, "me-not-supported", log.Fields{"class-id": classID, "instance-id": instanceID})
687 }
688 return nil
689}
690
691func (am *onuAlarmManager) sendAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8, raised bool) {
692 context := make(map[string]string)
693 intfID := am.getIntfIDAlarm(ctx, classID, instanceID)
694 onuID := am.pDeviceHandler.deviceID
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000695 am.pDeviceHandler.pOnuOmciDevice.mutexPersOnuConfig.RLock()
Holger Hildebrandtbe523842021-03-10 10:47:18 +0000696 serialNo := am.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersSerialNumber
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000697 am.pDeviceHandler.pOnuOmciDevice.mutexPersOnuConfig.RUnlock()
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530698 if intfID == nil {
699 logger.Warn(ctx, "intf-id-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
700 return
701 }
702 context["onu-intf-id"] = fmt.Sprintf("%d", *intfID)
703 context["onu-id"] = onuID
704 context["onu-serial-number"] = serialNo
705
706 raisedTimestamp := time.Now().UnixNano()
707 eventDetails, err := am.getDeviceEventData(ctx, classID, alarm)
708 if err != nil {
709 logger.Warn(ctx, "event-details-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
710 return
711 }
712 suffixDesc := "Raised"
713 if !raised {
714 suffixDesc = "Cleared"
715 }
716 deviceEvent := &voltha.DeviceEvent{
717 ResourceId: onuID,
718 DeviceEventName: fmt.Sprintf("%s_RAISE_EVENT", eventDetails.EventName),
719 Description: fmt.Sprintf("%s Event - %s - %s", eventDetails.EventDescription, eventDetails.EventName,
720 suffixDesc),
721 Context: context,
722 }
723 _ = am.eventProxy.SendDeviceEvent(ctx, deviceEvent, eventDetails.EventCategory, eventDetails.EventSubCategory,
724 raisedTimestamp)
725}
Himani Chawlad3dac422021-03-13 02:31:31 +0530726
727func (am *onuAlarmManager) isAlarmDBDiffPresent(ctx context.Context) bool {
728 return !reflect.DeepEqual(am.onuDBCopy, am.oltDbCopy)
729}
730
731func (am *onuAlarmManager) incrementAlarmSequence() {
732 //alarm sequence number wraps from 255 to 1.
733 if am.lastAlarmSequence == 255 {
734 am.lastAlarmSequence = 1
735 } else {
736 am.lastAlarmSequence++
737 }
738}
739
740func (am *onuAlarmManager) resetAlarmSequence() {
741 am.lastAlarmSequence = 0
742}
743
744// flushAlarmSyncChannels flushes all alarm sync channels to discard any previous response
745func (am *onuAlarmManager) flushAlarmSyncChannels(ctx context.Context) {
746 // flush alarm sync channel
747 select {
748 case <-am.eventChannel:
749 logger.Debug(ctx, "flushed-alarm-sync-channel")
750 default:
751 }
752 select {
753 case <-am.stopAlarmAuditTimer:
754 logger.Debug(ctx, "flushed-alarm-audit-timer-channel")
755 default:
756 }
757}
758
759// getDeviceEventData returns the event data for a device
760func (am *onuAlarmManager) getDeviceEventData(ctx context.Context, classID me.ClassID, alarmNo uint8) (onuDeviceEvent, error) {
761 if onuEventDetails, ok := am.onuEventsList[onuDevice{classID: classID, alarmno: alarmNo}]; ok {
762 return onuEventDetails, nil
763 }
764 return onuDeviceEvent{}, errors.New("onu Event Detail not found")
765}
Holger Hildebrandt0da7e6f2021-05-12 13:08:43 +0000766
767//ResetAlarmUploadCounters resets alarm upload sequence number and number of commands
768func (am *onuAlarmManager) ResetAlarmUploadCounters() {
769 am.onuAlarmManagerLock.Lock()
770 am.alarmUploadSeqNo = 0
771 am.alarmUploadNoOfCmds = 0
772 am.onuAlarmManagerLock.Unlock()
773}
774
775//IncrementAlarmUploadSeqNo increments alarm upload sequence number
776func (am *onuAlarmManager) IncrementAlarmUploadSeqNo() {
777 am.onuAlarmManagerLock.Lock()
778 am.alarmUploadSeqNo++
779 am.onuAlarmManagerLock.Unlock()
780}
781
782//GetAlarmUploadSeqNo gets alarm upload sequence number
783func (am *onuAlarmManager) GetAlarmUploadSeqNo() uint16 {
784 am.onuAlarmManagerLock.RLock()
785 value := am.alarmUploadSeqNo
786 am.onuAlarmManagerLock.RUnlock()
787 return value
788}