blob: 1efc8194990977bbf66f512aa952eda3cd30913d [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"
24 "sync"
25 "time"
26
27 "github.com/opencord/omci-lib-go"
28 me "github.com/opencord/omci-lib-go/generated"
29 "github.com/opencord/voltha-lib-go/v4/pkg/events/eventif"
30 "github.com/opencord/voltha-lib-go/v4/pkg/log"
31 "github.com/opencord/voltha-protos/v4/go/voltha"
32)
33
34const (
35 circuitPackClassID = me.CircuitPackClassID
36 physicalPathTerminationPointEthernetUniClassID = me.PhysicalPathTerminationPointEthernetUniClassID
37 onuGClassID = me.OnuGClassID
38 aniGClassID = me.AniGClassID
39)
40
41type alarmInfo struct {
42 classID me.ClassID
43 instanceID uint16
44 alarmNo uint8
45}
46
47type alarms map[alarmInfo]struct{}
48
49type onuAlarmManager struct {
50 pDeviceHandler *deviceHandler
51 eventProxy eventif.EventProxy
52 stopProcessingOmciMessages chan bool
53 eventChannel chan Message
54 onuAlarmManagerLock sync.RWMutex
55 processMessage bool
56 activeAlarms alarms
Himani Chawla4c1d4c72021-02-18 12:14:31 +053057 onuEventsList map[onuDevice]onuDeviceEvent
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053058}
59
60type onuDevice struct {
61 classID me.ClassID
62 alarmno uint8
63}
64type onuDeviceEvent struct {
65 EventName string
66 EventCategory eventif.EventCategory
67 EventSubCategory eventif.EventSubCategory
68 EventDescription string
69}
70
71func newAlarmManager(ctx context.Context, dh *deviceHandler) *onuAlarmManager {
72 var alarmManager onuAlarmManager
73 logger.Debugw(ctx, "init-alarmManager", log.Fields{"device-id": dh.deviceID})
74 alarmManager.pDeviceHandler = dh
75 alarmManager.eventProxy = dh.EventProxy // Or event proxy should be on cluster address ??
76 alarmManager.eventChannel = make(chan Message)
77 alarmManager.stopProcessingOmciMessages = make(chan bool)
78 alarmManager.processMessage = false
79 alarmManager.activeAlarms = make(map[alarmInfo]struct{})
Himani Chawla4c1d4c72021-02-18 12:14:31 +053080 alarmManager.onuEventsList = map[onuDevice]onuDeviceEvent{
Himani Chawlaac1f5ad2021-02-04 21:21:54 +053081 {classID: circuitPackClassID, alarmno: 0}: {EventName: "ONU_EQUIPMENT",
82 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu equipment"},
83 {classID: circuitPackClassID, alarmno: 2}: {EventName: "ONU_SELF_TEST_FAIL",
84 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu self-test failure"},
85 {classID: circuitPackClassID, alarmno: 3}: {EventName: "ONU_LASER_EOL",
86 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu laser EOL"},
87 {classID: circuitPackClassID, alarmno: 4}: {EventName: "ONU_TEMP_YELLOW",
88 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature yellow"},
89 {classID: circuitPackClassID, alarmno: 5}: {EventName: "ONU_TEMP_RED",
90 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature red"},
91 {classID: physicalPathTerminationPointEthernetUniClassID, alarmno: 0}: {EventName: "ONU_Ethernet_UNI", EventCategory: voltha.EventCategory_EQUIPMENT,
92 EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "LAN Loss Of Signal"},
93 {classID: onuGClassID, alarmno: 0}: {EventName: "ONU_EQUIPMENT",
94 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu equipment"},
95 {classID: onuGClassID, alarmno: 6}: {EventName: "ONU_SELF_TEST_FAIL",
96 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu self-test failure"},
97 {classID: onuGClassID, alarmno: 7}: {EventName: "ONU_DYING_GASP",
98 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu DYING_GASP"},
99 {classID: onuGClassID, alarmno: 8}: {EventName: "ONU_TEMP_YELLOW",
100 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature yellow"},
101 {classID: onuGClassID, alarmno: 9}: {EventName: "ONU_TEMP_RED",
102 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu temperature red"},
103 {classID: onuGClassID, alarmno: 10}: {EventName: "ONU_VOLTAGE_YELLOW",
104 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu voltage yellow"},
105 {classID: onuGClassID, alarmno: 11}: {EventName: "ONU_VOLTAGE_RED",
106 EventCategory: voltha.EventCategory_ENVIRONMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu voltage red"},
107 {classID: aniGClassID, alarmno: 0}: {EventName: "ONU_LOW_RX_OPTICAL",
108 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu low rx optical power"},
109 {classID: aniGClassID, alarmno: 1}: {EventName: "ONU_HIGH_RX_OPTICAL",
110 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu high rx optical power"},
111 {classID: aniGClassID, alarmno: 4}: {EventName: "ONU_LOW_TX_OPTICAL",
112 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu low tx optical power"},
113 {classID: aniGClassID, alarmno: 5}: {EventName: "ONU_HIGH_TX_OPTICAL",
114 EventCategory: voltha.EventCategory_COMMUNICATION, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu high tx optical power"},
115 {classID: aniGClassID, alarmno: 6}: {EventName: "ONU_LASER_BIAS_CURRENT",
116 EventCategory: voltha.EventCategory_EQUIPMENT, EventSubCategory: voltha.EventSubCategory_ONU, EventDescription: "onu laser bias current"},
117 }
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530118 return &alarmManager
119}
120
121// getDeviceEventData returns the event data for a device
122func (am *onuAlarmManager) getDeviceEventData(ctx context.Context, classID me.ClassID, alarmNo uint8) (onuDeviceEvent, error) {
123 if onuEventDetails, ok := am.onuEventsList[onuDevice{classID: classID, alarmno: alarmNo}]; ok {
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530124 return onuEventDetails, nil
125 }
126 return onuDeviceEvent{}, errors.New("onu Event Detail not found")
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530127}
128
129func (am *onuAlarmManager) startOMCIAlarmMessageProcessing(ctx context.Context) {
130 am.onuAlarmManagerLock.Lock()
131 am.processMessage = true
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530132 if am.activeAlarms == nil {
133 am.activeAlarms = make(map[alarmInfo]struct{})
134 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530135 am.onuAlarmManagerLock.Unlock()
136 if stop := <-am.stopProcessingOmciMessages; stop {
137 am.onuAlarmManagerLock.Lock()
138 am.processMessage = false
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530139 am.activeAlarms = nil
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530140 am.onuAlarmManagerLock.Unlock()
141 }
142}
143
144func (am *onuAlarmManager) handleOmciAlarmNotificationMessage(ctx context.Context, msg OmciMessage) {
145 logger.Debugw(ctx, "OMCI Alarm Notification Msg", log.Fields{"device-id": am.pDeviceHandler.deviceID,
146 "msgType": msg.OmciMsg.MessageType})
147 am.onuAlarmManagerLock.Lock()
148 defer am.onuAlarmManagerLock.Unlock()
149
150 if am.processMessage {
151 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeAlarmNotification)
152 if msgLayer == nil {
153 logger.Errorw(ctx, "Omci Msg layer could not be detected for Alarm Notification",
154 log.Fields{"device-id": am.pDeviceHandler.deviceID})
155 return
156 }
157 msgObj, msgOk := msgLayer.(*omci.AlarmNotificationMsg)
158 if !msgOk {
159 logger.Errorw(ctx, "Omci Msg layer could not be assigned for Alarm Notification",
160 log.Fields{"device-id": am.pDeviceHandler.deviceID})
161 return
162 }
163 //Alarm Notification decoding at omci lib validates that the me class ID supports the
164 // alarm notifications.
165 logger.Debugw(ctx, "Alarm Notification Data", log.Fields{"device-id": am.pDeviceHandler.deviceID, "data-fields": msgObj})
166 if err := am.processAlarmData(ctx, msgObj); err != nil {
167 logger.Errorw(ctx, "unable-to-process-alarm-notification", log.Fields{"device-id": am.pDeviceHandler.deviceID})
168 }
169
170 } else {
171 logger.Warnw(ctx, "ignoring-alarm-notification-received-for-me-as-channel-for-processing-is-closed",
172 log.Fields{"device-id": am.pDeviceHandler.deviceID})
173 }
174}
175
176func (am *onuAlarmManager) processAlarmData(ctx context.Context, msg *omci.AlarmNotificationMsg) error {
177 classID := msg.EntityClass
178 sequenceNo := msg.AlarmSequenceNumber
179 meInstance := msg.EntityInstance
180 alarmBitmap := msg.AlarmBitmap
181 logger.Debugw(ctx, "processing-alarm-data", log.Fields{"class-id": classID, "instance-id": meInstance,
182 "alarmBitMap": alarmBitmap, "sequence-no": sequenceNo})
Himani Chawla4c1d4c72021-02-18 12:14:31 +0530183 if _, present := am.pDeviceHandler.pOnuOmciDevice.pOnuDB.meDb[classID][meInstance]; !present {
184 logger.Errorw(ctx, "me-class-instance-not-present", log.Fields{"class-id": classID, "instance-id": meInstance})
185 return fmt.Errorf("me-class-%d-instance-%d-not-present", classID, meInstance)
186 }
Himani Chawlaac1f5ad2021-02-04 21:21:54 +0530187 /*
188 if sequenceNo > 0 {
189 // TODO Need Auditing if sequence no does not matches, after incrementing the last sequence no by 1
190 }
191 */
192
193 entity, omciErr := me.LoadManagedEntityDefinition(classID,
194 me.ParamData{EntityID: meInstance})
195 if omciErr.StatusCode() != me.Success {
196 //log error and return
197 logger.Error(ctx, "unable-to-get-managed-entity", log.Fields{"class-id": classID, "instance-id": meInstance})
198 return fmt.Errorf("unable-to-get-managed-entity-class-%d-instance-%d", classID, meInstance)
199 }
200 meAlarmMap := entity.GetAlarmMap()
201 if meAlarmMap == nil {
202 logger.Error(ctx, "unable-to-get-managed-entity-alarm-map", log.Fields{"class-id": classID, "instance-id": meInstance})
203 return fmt.Errorf("unable-to-get-managed-entity-alarm-map-%d-instance-%d", classID, meInstance)
204 }
205 // Loop over the supported alarm list for this me
206 for alarmNo := range meAlarmMap {
207 // Check if alarmNo was previously active in the alarms, if yes clear it and remove it from active alarms
208 _, exists := am.activeAlarms[alarmInfo{
209 classID: classID,
210 instanceID: meInstance,
211 alarmNo: alarmNo,
212 }]
213 if exists {
214 // Clear this alarm if It is cleared now, in that case IsAlarmClear would return true
215 cleared, err := msg.IsAlarmClear(alarmNo)
216 if err != nil {
217 logger.Warnw(ctx, "unable-to-find-out-alarm-is-cleared", log.Fields{"class-id": classID,
218 "instance-id": meInstance, "alarm-no": alarmNo})
219 return err
220 }
221 if cleared {
222 // Clear this alarm.
223 am.clearAlarm(ctx, classID, meInstance, alarmNo)
224 }
225 } else {
226 // If alarm entry was not present in the list of active alarms, we need to see if this alarm is now active
227 // or not, if yes then raise it.
228 raised, err := msg.IsAlarmActive(alarmNo)
229 if err != nil {
230 logger.Warnw(ctx, "unable-to-find-out-alarm-is-raised", log.Fields{"class-id": classID,
231 "instance-id": meInstance, "alarm-no": alarmNo})
232 return err
233 }
234 if raised {
235 am.raiseAlarm(ctx, classID, meInstance, alarmNo)
236 }
237 }
238 }
239 return nil
240}
241
242func (am *onuAlarmManager) raiseAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
243 am.activeAlarms[alarmInfo{
244 classID: classID,
245 instanceID: instanceID,
246 alarmNo: alarm,
247 }] = struct{}{}
248 go am.sendAlarm(ctx, classID, instanceID, alarm, true)
249}
250
251func (am *onuAlarmManager) clearAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8) {
252 go am.sendAlarm(ctx, classID, instanceID, alarm, false)
253 delete(am.activeAlarms, alarmInfo{
254 classID: classID,
255 instanceID: instanceID,
256 alarmNo: alarm,
257 })
258}
259
260func (am *onuAlarmManager) getIntfIDAlarm(ctx context.Context, classID me.ClassID, instanceID uint16) *uint32 {
261 var intfID *uint32
262 if classID == circuitPackClassID || classID == physicalPathTerminationPointEthernetUniClassID {
263 for _, uniPort := range am.pDeviceHandler.uniEntityMap {
264 if uniPort.entityID == instanceID {
265 intfID = &uniPort.portNo
266 return intfID
267 }
268 }
269 } else if classID == aniGClassID || classID == onuGClassID {
270 intfID = &am.pDeviceHandler.ponPortNumber
271 return intfID
272 } else {
273 logger.Warnw(ctx, "me-not-supported", log.Fields{"class-id": classID, "instance-id": instanceID})
274 }
275 return nil
276}
277
278func (am *onuAlarmManager) sendAlarm(ctx context.Context, classID me.ClassID, instanceID uint16, alarm uint8, raised bool) {
279 context := make(map[string]string)
280 intfID := am.getIntfIDAlarm(ctx, classID, instanceID)
281 onuID := am.pDeviceHandler.deviceID
282 serialNo := am.pDeviceHandler.pOnuOmciDevice.serialNumber
283 if intfID == nil {
284 logger.Warn(ctx, "intf-id-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
285 return
286 }
287 context["onu-intf-id"] = fmt.Sprintf("%d", *intfID)
288 context["onu-id"] = onuID
289 context["onu-serial-number"] = serialNo
290
291 raisedTimestamp := time.Now().UnixNano()
292 eventDetails, err := am.getDeviceEventData(ctx, classID, alarm)
293 if err != nil {
294 logger.Warn(ctx, "event-details-for-alarm-not-found", log.Fields{"alarm-no": alarm, "class-id": classID})
295 return
296 }
297 suffixDesc := "Raised"
298 if !raised {
299 suffixDesc = "Cleared"
300 }
301 deviceEvent := &voltha.DeviceEvent{
302 ResourceId: onuID,
303 DeviceEventName: fmt.Sprintf("%s_RAISE_EVENT", eventDetails.EventName),
304 Description: fmt.Sprintf("%s Event - %s - %s", eventDetails.EventDescription, eventDetails.EventName,
305 suffixDesc),
306 Context: context,
307 }
308 _ = am.eventProxy.SendDeviceEvent(ctx, deviceEvent, eventDetails.EventCategory, eventDetails.EventSubCategory,
309 raisedTimestamp)
310}