VOL-3835: Add support for reporting L2 PM counters

Change-Id: Ibe64b94d442b7ce83965824beb18d0a281c64a6b
diff --git a/internal/common/omci/get.go b/internal/common/omci/get.go
index 25ba8ed..f6f32df 100644
--- a/internal/common/omci/get.go
+++ b/internal/common/omci/get.go
@@ -25,6 +25,7 @@
 	me "github.com/opencord/omci-lib-go/generated"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 	log "github.com/sirupsen/logrus"
+	"math/rand"
 	"strconv"
 )
 
@@ -76,6 +77,12 @@
 		response = createAnigResponse(msgObj.AttributeMask, msgObj.EntityInstance)
 	case me.OnuDataClassID:
 		response = createOnuDataResponse(msgObj.AttributeMask, msgObj.EntityInstance, mds)
+	case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID:
+		response = createEthernetFramePerformanceMonitoringHistoryDataUpstreamResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID:
+		response = createEthernetFramePerformanceMonitoringHistoryDataDownstreamResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.EthernetPerformanceMonitoringHistoryDataClassID:
+		response = createEthernetPerformanceMonitoringHistoryDataResponse(msgObj.AttributeMask, msgObj.EntityInstance)
 	default:
 		omciLogger.WithFields(log.Fields{
 			"EntityClass":    msgObj.EntityClass,
@@ -291,38 +298,167 @@
 	}
 }
 
-func createAnigResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
-	managedEntity, meErr := me.NewAniG(me.ParamData{
+func createEthernetFramePerformanceMonitoringHistoryDataUpstreamResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	fmt.Printf("createEthernetFramePerformanceMonitoringHistoryDataUpstreamResponse attribute mask = %v", attributeMask)
+	managedEntity, meErr := me.NewEthernetFramePerformanceMonitoringHistoryDataUpstream(me.ParamData{
 		EntityID: entityID,
 		Attributes: me.AttributeValueMap{
-			"ManagedEntityId":             entityID,
-			"SrIndication":                0,
-			"TotalTcontNumber":            0,
-			"GemBlockLength":              0,
-			"PiggybackDbaReporting":       0,
-			"Deprecated":                  0,
-			"SignalFailThreshold":         0,
-			"SignalDegradeThreshold":      0,
-			"Arc":                         0,
-			"ArcInterval":                 0,
-			"OpticalSignalLevel":          0,
-			"LowerOpticalThreshold":       0,
-			"UpperOpticalThreshold":       0,
-			"OnuResponseTime":             0,
-			"TransmitOpticalLevel":        0,
-			"LowerTransmitPowerThreshold": 0,
-			"UpperTransmitPowerThreshold": 0,
+			"ManagedEntityId":         entityID,
+			"IntervalEndTime":         0, // This ideally should increment by 1 every collection interval, but staying 0 for simulation is Ok for now.
+			"ThresholdData12Id":       0,
+			"DropEvents":              rand.Intn(100),
+			"Octets":                  rand.Intn(100),
+			"Packets":                 rand.Intn(100),
+			"BroadcastPackets":        rand.Intn(100),
+			"MulticastPackets":        rand.Intn(100),
+			"CrcErroredPackets":       rand.Intn(100),
+			"UndersizePackets":        rand.Intn(100),
+			"OversizePackets":         rand.Intn(100),
+			"Packets64Octets":         rand.Intn(100),
+			"Packets65To127Octets":    rand.Intn(100),
+			"Packets128To255Octets":   rand.Intn(100),
+			"Packets256To511Octets":   rand.Intn(100),
+			"Packets512To1023Octets":  rand.Intn(100),
+			"Packets1024To1518Octets": rand.Intn(100),
 		},
 	})
 
 	if meErr.GetError() != nil {
-		omciLogger.Errorf("NewAniG %v", meErr.Error())
+		omciLogger.Errorf("NewEthernetFramePerformanceMonitoringHistoryDataUpstream %v", meErr.Error())
 		return nil
 	}
 
+	// L2 PM counters MEs exceed max allowed OMCI payload size.
+	// So the request/responses are always multipart.
+	// First identify the attributes that are not requested in the current GET request.
+	// Then filter out those attributes from the responses in the current GET response.
+	unwantedAttributeMask := ^attributeMask
+	var i uint16
+	for i = 1; i <= 16; i++ { // 1 and 16 because they are allowed valid min and max index keys in AttributeValueMap.
+		// We leave out 0 because that is ManagedEntity and that is a default IE in the map
+		if (1<<(16-i))&unwantedAttributeMask > 0 {
+			if err := managedEntity.DeleteAttributeByIndex(uint(i)); err != nil {
+				omciLogger.Errorf("error deleting attribute at index=%v, err=%v", i, err)
+			}
+		}
+	}
+
 	return &omci.GetResponse{
 		MeBasePacket: omci.MeBasePacket{
-			EntityClass: me.AniGClassID,
+			EntityClass:    me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
+			EntityInstance: entityID,
+		},
+		Attributes:    managedEntity.GetAttributeValueMap(),
+		AttributeMask: attributeMask,
+		Result:        me.Success,
+	}
+}
+
+func createEthernetFramePerformanceMonitoringHistoryDataDownstreamResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	fmt.Printf("createEthernetFramePerformanceMonitoringHistoryDataDownstreamResponse attribute mask = %v", attributeMask)
+	managedEntity, meErr := me.NewEthernetFramePerformanceMonitoringHistoryDataDownstream(me.ParamData{
+		EntityID: entityID,
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId":         entityID,
+			"IntervalEndTime":         0, // This ideally should increment by 1 every collection interval, but staying 0 for simulation is Ok for now.
+			"ThresholdData12Id":       0,
+			"DropEvents":              rand.Intn(100),
+			"Octets":                  rand.Intn(100),
+			"Packets":                 rand.Intn(100),
+			"BroadcastPackets":        rand.Intn(100),
+			"MulticastPackets":        rand.Intn(100),
+			"CrcErroredPackets":       rand.Intn(100),
+			"UndersizePackets":        rand.Intn(100),
+			"OversizePackets":         rand.Intn(100),
+			"Packets64Octets":         rand.Intn(100),
+			"Packets65To127Octets":    rand.Intn(100),
+			"Packets128To255Octets":   rand.Intn(100),
+			"Packets256To511Octets":   rand.Intn(100),
+			"Packets512To1023Octets":  rand.Intn(100),
+			"Packets1024To1518Octets": rand.Intn(100),
+		},
+	})
+
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("NewEthernetFramePerformanceMonitoringHistoryDataDownstream %v", meErr.Error())
+		return nil
+	}
+
+	// L2 PM counters MEs exceed max allowed OMCI payload size.
+	// So the request/responses are always multipart.
+	// First identify the attributes that are not requested in the current GET request.
+	// Then filter out those attributes from the responses in the current GET response.
+	unwantedAttributeMask := ^attributeMask
+	var i uint16
+	for i = 1; i <= 16; i++ { // 1 and 16 because they are allowed valid min and max index keys in AttributeValueMap.
+		// We leave out 0 because that is ManagedEntity and that is a default IE in the map
+		if (1<<(16-i))&unwantedAttributeMask > 0 {
+			if err := managedEntity.DeleteAttributeByIndex(uint(i)); err != nil {
+				omciLogger.Errorf("error deleting attribute at index=%v, err=%v", i, err)
+			}
+		}
+	}
+
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
+			EntityInstance: entityID,
+		},
+		Attributes:    managedEntity.GetAttributeValueMap(),
+		AttributeMask: attributeMask,
+		Result:        me.Success,
+	}
+}
+
+func createEthernetPerformanceMonitoringHistoryDataResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	fmt.Printf("createEthernetPerformanceMonitoringHistoryDataResponse attribute mask = %v", attributeMask)
+	managedEntity, meErr := me.NewEthernetPerformanceMonitoringHistoryData(me.ParamData{
+		EntityID: entityID,
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId":                 entityID,
+			"IntervalEndTime":                 0, // This ideally should increment by 1 every collection interval, but staying 0 for simulation is Ok for now.
+			"ThresholdData12Id":               0,
+			"FcsErrors":                       rand.Intn(100),
+			"ExcessiveCollisionCounter":       rand.Intn(100),
+			"LateCollisionCounter":            rand.Intn(100),
+			"FramesTooLong":                   rand.Intn(100),
+			"BufferOverflowsOnReceive":        rand.Intn(100),
+			"BufferOverflowsOnTransmit":       rand.Intn(100),
+			"SingleCollisionFrameCounter":     rand.Intn(100),
+			"MultipleCollisionsFrameCounter":  rand.Intn(100),
+			"SqeCounter":                      rand.Intn(100),
+			"DeferredTransmissionCounter":     rand.Intn(100),
+			"InternalMacTransmitErrorCounter": rand.Intn(100),
+			"CarrierSenseErrorCounter":        rand.Intn(100),
+			"AlignmentErrorCounter":           rand.Intn(100),
+			"InternalMacReceiveErrorCounter":  rand.Intn(100),
+		},
+	})
+
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("NewEthernetPerformanceMonitoringHistoryData %v", meErr.Error())
+		return nil
+	}
+
+	// L2 PM counters MEs exceed max allowed OMCI payload size.
+	// So the request/responses are always multipart.
+	// First identify the attributes that are not requested in the current GET request.
+	// Then filter out those attributes from the responses in the current GET response.
+	unwantedAttributeMask := ^attributeMask
+	var i uint16
+	for i = 1; i <= 16; i++ { // 1 and 16 because they are allowed valid min and max index keys in AttributeValueMap.
+		// We leave out 0 because that is ManagedEntity and that is a default IE in the map
+		if (1<<(16-i))&unwantedAttributeMask > 0 {
+			if err := managedEntity.DeleteAttributeByIndex(uint(i)); err != nil {
+				omciLogger.Errorf("error deleting attribute at index=%v, err=%v", i, err)
+			}
+		}
+	}
+
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.EthernetPerformanceMonitoringHistoryDataClassID,
+			EntityInstance: entityID,
 		},
 		Attributes:    managedEntity.GetAttributeValueMap(),
 		AttributeMask: attributeMask,
@@ -346,7 +482,48 @@
 
 	return &omci.GetResponse{
 		MeBasePacket: omci.MeBasePacket{
-			EntityClass: me.OnuDataClassID,
+			EntityClass:    me.OnuDataClassID,
+			EntityInstance: entityID,
+		},
+		Attributes:    managedEntity.GetAttributeValueMap(),
+		AttributeMask: attributeMask,
+		Result:        me.Success,
+	}
+}
+
+func createAnigResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	managedEntity, meErr := me.NewAniG(me.ParamData{
+		EntityID: entityID,
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId":             entityID,
+			"SrIndication":                0,
+			"TotalTcontNumber":            0,
+			"GemBlockLength":              0,
+			"PiggybackDbaReporting":       0,
+			"Deprecated":                  0,
+			"SignalFailThreshold":         0,
+			"SignalDegradeThreshold":      0,
+			"Arc":                         0,
+			"ArcInterval":                 0,
+			"OpticalSignalLevel":          rand.Intn(16000), // generate some random power level than defaulting to 0
+			"LowerOpticalThreshold":       0,
+			"UpperOpticalThreshold":       0,
+			"OnuResponseTime":             0,
+			"TransmitOpticalLevel":        rand.Intn(16000), // generate some random power level than defaulting to 0
+			"LowerTransmitPowerThreshold": 0,
+			"UpperTransmitPowerThreshold": 0,
+		},
+	})
+
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("NewAniG %v", meErr.Error())
+		return nil
+	}
+
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.AniGClassID,
+			EntityInstance: entityID,
 		},
 		Attributes:    managedEntity.GetAttributeValueMap(),
 		AttributeMask: attributeMask,