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