VOL-3049 patch for alarm notification, audit and sync
Change-Id: I18fa616e94e7c33bbd8c1080bee0ab16afe505da
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index ab7c35f..6c1b5b9 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -22,6 +22,8 @@
"fmt"
pb "github.com/opencord/bbsim/api/bbsim"
"github.com/opencord/bbsim/internal/bbsim/alarmsim"
+ "sync"
+
"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
"github.com/opencord/bbsim/internal/bbsim/responders/eapol"
@@ -124,6 +126,8 @@
DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
TrafficSchedulers *tech_profile.TrafficSchedulers
+ onuAlarmsInfoLock sync.RWMutex
+ onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
}
func (o *Onu) Sn() string {
@@ -158,7 +162,7 @@
"ID": o.ID,
}).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
})
-
+ o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
// NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
o.InternalState = fsm.NewFSM(
OnuStateCreated,
@@ -258,7 +262,6 @@
"OnuSn": o.Sn(),
}).Errorf("Cannot change ONU OperState to down: %s", err.Error())
}
-
// send the OnuIndication DOWN event
msg := bbsim.Message{
Type: bbsim.OnuIndication,
@@ -279,6 +282,9 @@
for _, s := range o.Services {
s.Disable()
}
+ o.onuAlarmsInfoLock.Lock()
+ o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
+ o.onuAlarmsInfoLock.Unlock()
},
// BBR states
"enter_eapol_flow_sent": func(e *fsm.Event) {
@@ -353,23 +359,40 @@
o.handleOmciRequest(msg, stream)
case bbsim.UniStatusAlarm:
msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
- pkt := omcilib.CreateUniStatusAlarm(msg.AdminState, msg.EntityID)
- if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
+ onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
+ MeInstance: msg.EntityID,
+ MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
+ }
+ seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
+ o.onuAlarmsInfoLock.Lock()
+ var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
+ pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
+ if pkt != nil { //pkt will be nil if we are unable to create the alarm
+ if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
+ onuLogger.WithFields(log.Fields{
+ "IntfId": o.PonPortID,
+ "SerialNumber": o.Sn(),
+ "omciPacket": pkt,
+ "adminState": msg.AdminState,
+ "entityID": msg.EntityID,
+ }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
+ alarmInfo.SequenceNo--
+ }
onuLogger.WithFields(log.Fields{
"IntfId": o.PonPortID,
"SerialNumber": o.Sn(),
"omciPacket": pkt,
"adminState": msg.AdminState,
"entityID": msg.EntityID,
- }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
+ }).Trace("UNI-Link-alarm-sent")
+ if alarmBitMap == [28]byte{0} {
+ delete(o.onuAlarmsInfo, onuAlarmMapKey)
+ } else {
+ alarmInfo.AlarmBitMap = alarmBitMap
+ o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
+ }
}
- onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
- "SerialNumber": o.Sn(),
- "omciPacket": pkt,
- "adminState": msg.AdminState,
- "entityID": msg.EntityID,
- }).Trace("UNI-Link-alarm-sent")
+ o.onuAlarmsInfoLock.Unlock()
case bbsim.FlowAdd:
msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
o.handleFlowAdd(msg)
@@ -450,13 +473,9 @@
}
func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
-
sn := new(openolt.SerialNumber)
-
- //sn = new(openolt.SerialNumber)
sn.VendorId = []byte("BBSM")
sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
-
return sn
}
@@ -546,7 +565,7 @@
return err
}
-
+ o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
// TODO if it's the last ONU on the PON, then send a PON LOS
if err := o.InternalState.Event(OnuTxDisable); err != nil {
@@ -591,6 +610,7 @@
}).Errorf("Cannot send LOS: %s", err.Error())
return err
}
+ o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
// Send a ONU Discovery indication
if err := o.InternalState.Event(OnuTxDiscover); err != nil {
@@ -630,6 +650,11 @@
if err != nil {
return err
}
+ raiseAlarm := false
+ if alarmReq.Status == "on" {
+ raiseAlarm = true
+ }
+ o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
return nil
}
@@ -730,13 +755,18 @@
// omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
// are reported during the MIB Upload sequence
adminState := msgObj.Attributes["AdministrativeState"].(uint8)
+ raiseOMCIAlarm := false
+ if adminState == 1 {
+ raiseOMCIAlarm = true
+ }
msg := bbsim.Message{
Type: bbsim.UniStatusAlarm,
Data: bbsim.UniStatusAlarmMessage{
- OnuSN: o.SerialNumber,
- OnuID: o.ID,
- AdminState: adminState,
- EntityID: msgObj.EntityInstance,
+ OnuSN: o.SerialNumber,
+ OnuID: o.ID,
+ AdminState: adminState,
+ EntityID: msgObj.EntityInstance,
+ RaiseOMCIAlarm: raiseOMCIAlarm,
},
}
o.Channel <- msg
@@ -1056,6 +1086,20 @@
"CommittedImageEntityId": o.CommittedImageEntityId,
}).Info("onu-software-image-committed")
}
+ case omci.GetAllAlarmsRequestType:
+ // Reset the alarm sequence number on receiving get all alarms request.
+ o.onuAlarmsInfoLock.Lock()
+ for key, alarmInfo := range o.onuAlarmsInfo {
+ // reset the alarm sequence no
+ alarmInfo.SequenceNo = 0
+ o.onuAlarmsInfo[key] = alarmInfo
+ }
+ o.onuAlarmsInfoLock.Unlock()
+ responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(omciMsg.TransactionID, o.onuAlarmsInfo)
+ case omci.GetAllAlarmsNextRequestType:
+ if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(omciPkt, omciMsg, o.onuAlarmsInfo); errResp != nil {
+ responsePkt = nil //Do not send any response for error case
+ }
default:
onuLogger.WithFields(log.Fields{
"omciBytes": hex.EncodeToString(omciPkt.Data()),
@@ -1527,3 +1571,40 @@
}
return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
}
+
+func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
+ switch alarmType {
+ case "ONU_ALARM_LOS":
+ msg := bbsim.Message{
+ Type: bbsim.UniStatusAlarm,
+ Data: bbsim.UniStatusAlarmMessage{
+ OnuSN: o.SerialNumber,
+ OnuID: o.ID,
+ EntityID: 257,
+ RaiseOMCIAlarm: raiseOMCIAlarm,
+ },
+ }
+ o.Channel <- msg
+ }
+
+}
+
+func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
+ o.onuAlarmsInfoLock.Lock()
+ defer o.onuAlarmsInfoLock.Unlock()
+ if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
+ if alarmInfo.SequenceNo == 255 {
+ alarmInfo.SequenceNo = 1
+ } else {
+ alarmInfo.SequenceNo++
+ }
+ o.onuAlarmsInfo[key] = alarmInfo
+ return alarmInfo.SequenceNo
+ } else {
+ // This is the first time alarm notification message is being sent
+ o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
+ SequenceNo: 1,
+ }
+ return 1
+ }
+}
diff --git a/internal/bbsim/types/messageTypes.go b/internal/bbsim/types/messageTypes.go
index 3afe7fb..4068dfa 100644
--- a/internal/bbsim/types/messageTypes.go
+++ b/internal/bbsim/types/messageTypes.go
@@ -117,10 +117,11 @@
}
type UniStatusAlarmMessage struct {
- OnuSN *openolt.SerialNumber
- OnuID uint32
- AdminState uint8
- EntityID uint16
+ OnuSN *openolt.SerialNumber
+ OnuID uint32
+ AdminState uint8
+ EntityID uint16
+ RaiseOMCIAlarm bool
}
// these are OMCI messages going from the OLT to VOLTHA
diff --git a/internal/common/omci/alarms.go b/internal/common/omci/alarms.go
index aaa2fdd..5d8144b 100644
--- a/internal/common/omci/alarms.go
+++ b/internal/common/omci/alarms.go
@@ -16,32 +16,168 @@
package omci
+import (
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+)
+
+type OnuAlarmInfo struct {
+ SequenceNo uint8
+ AlarmBitMap [28]byte
+}
+type OnuAlarmInfoMapKey struct {
+ MeInstance uint16
+ MeClassID me.ClassID
+}
+
// CreateUniStatusAlarm will generate an Alarm packet to report that the Link is UP or DOWN
// as a consequence of a SetRequest on PhysicalPathTerminationPointEthernetUniClassID
-func CreateUniStatusAlarm(adminState uint8, entityId uint16) []byte {
+func CreateUniStatusAlarm(raiseAlarm bool, entityId uint16, sequenceNo uint8) ([]byte, [28]byte) {
+ notif := &omci.AlarmNotificationMsg{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.PhysicalPathTerminationPointEthernetUniClassID,
+ EntityInstance: entityId,
+ },
+ AlarmSequenceNumber: byte(sequenceNo),
+ }
+ if raiseAlarm {
+ //PPTP class has only 0th bit alarm for UNI LOS
+ if err := notif.ActivateAlarm(0); err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("Cannot Create AlarmNotificationMsg")
+ return nil, [28]byte{}
+ }
+ } else {
+ if err := notif.ClearAlarm(0); err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("Cannot Create AlarmNotificationMsg")
+ return nil, [28]byte{}
+ }
+ }
+ pkt, err := Serialize(omci.AlarmNotificationType, notif, 0)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("Cannot Serialize AlarmNotificationMsg")
+ return nil, [28]byte{}
+ }
+ return pkt, notif.AlarmBitmap
+}
- // TODO generate using omci-lib-go
- linkMsgDown := []byte{
- 0x00, 0x00, 0x10, 0x0a, 0x00, 0x0b, 0x01, 0x01,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+func CreateGetAllAlarmsResponse(tid uint16, onuAlarmDetails map[OnuAlarmInfoMapKey]OnuAlarmInfo) ([]byte, error) {
+ var alarmEntityClass me.ClassID
+ var meInstance uint16
+ var noOfCommands uint16 = 0
+ alarmEntityClass = me.PhysicalPathTerminationPointEthernetUniClassID //Currently doing for PPTP classID
+ meInstance = 257
+ key := OnuAlarmInfoMapKey{
+ MeInstance: meInstance,
+ MeClassID: alarmEntityClass,
+ }
+ if _, ok := onuAlarmDetails[key]; ok {
+ noOfCommands = 1
+ }
+ numberOfCommands := uint16(noOfCommands)
- linkMsgUp := []byte{
- 0x00, 0x00, 0x10, 0x0a, 0x00, 0x0b, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ request := &omci.GetAllAlarmsResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
+ },
+ NumberOfCommands: numberOfCommands,
+ }
+ pkt, err := Serialize(omci.GetAllAlarmsResponseType, request, tid)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("Cannot Serialize GetAllAlarmsResponse")
+ return nil, err
+ }
+ return pkt, nil
+}
+func ParseGetAllAlarmsNextRequest(omciPkt gopacket.Packet) (*omci.GetAllAlarmsNextRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeGetAllAlarmsNextRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeGetAllAlarmsNextRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.GetAllAlarmsNextRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for GetAllAlarmsNextRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
- if adminState == 0 {
- return linkMsgUp
- } else if adminState == 1 {
- return linkMsgDown
+func CreateGetAllAlarmsNextResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, onuAlarmDetails map[OnuAlarmInfoMapKey]OnuAlarmInfo) ([]byte, error) {
+
+ msgObj, err := ParseGetAllAlarmsNextRequest(omciPkt)
+ if err != nil {
+ err := "omci Msg layer could not be assigned for LayerTypeGetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
}
- return nil
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "CommandSequenceNumber": msgObj.CommandSequenceNumber,
+ }).Trace("received-omci-get-all-alarms-next-request")
+
+ var alarmEntityClass me.ClassID
+ var meInstance uint16
+ var alarmBitMap [28]byte
+
+ switch msgObj.CommandSequenceNumber {
+ case 0:
+ alarmEntityClass = me.PhysicalPathTerminationPointEthernetUniClassID
+ meInstance = 257
+ //Checking if the alarm is raised in the bitmap, we will send clear just to generate missed clear alarm and
+ // vice versa.
+ key := OnuAlarmInfoMapKey{
+ MeInstance: meInstance,
+ MeClassID: alarmEntityClass,
+ }
+ if alarmInfo, ok := onuAlarmDetails[key]; ok {
+ alarmBitMap = alarmInfo.AlarmBitMap
+ } else {
+ return nil, fmt.Errorf("alarm-info-for-me-not-present-in-alarm-info-map")
+ }
+ default:
+ omciLogger.Warn("unsupported-CommandSequenceNumber-in-get-all-alarm-next", msgObj.CommandSequenceNumber)
+ return nil, fmt.Errorf("unspported-command-sequence-number-in-get-all-alarms-next")
+ }
+
+ response := &omci.GetAllAlarmsNextResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
+ },
+ AlarmEntityClass: alarmEntityClass,
+ AlarmEntityInstance: meInstance,
+ AlarmBitMap: alarmBitMap,
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "AlarmEntityClass": alarmEntityClass,
+ "AlarmEntityInstance": meInstance,
+ "AlarmBitMap": alarmBitMap,
+ }).Trace("created-omci-getAllAlarmsNext-response")
+
+ pkt, err := Serialize(omci.GetAllAlarmsNextResponseType, response, omciMsg.TransactionID)
+
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Fatalf("Cannot Serialize GetAllAlarmsNextRequest")
+ return nil, err
+ }
+
+ return pkt, nil
}