[SEBA-434] Replacing omci-sim with omci-lib-go
Change-Id: I499afc9ec49bb483467ea93bd6ce3077dd0ccc6e
diff --git a/internal/common/omci/alarms.go b/internal/common/omci/alarms.go
new file mode 100644
index 0000000..aaa2fdd
--- /dev/null
+++ b/internal/common/omci/alarms.go
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+// 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 {
+
+ // 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}
+
+ 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}
+
+ if adminState == 0 {
+ return linkMsgUp
+ } else if adminState == 1 {
+ return linkMsgDown
+ }
+
+ return nil
+}
diff --git a/internal/common/omci/create.go b/internal/common/omci/create.go
new file mode 100644
index 0000000..8e4afb3
--- /dev/null
+++ b/internal/common/omci/create.go
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "encoding/hex"
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+ "strconv"
+)
+
+func ParseCreateRequest(omciPkt gopacket.Packet) (*omci.CreateRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeCreateRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeCreateRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.CreateRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeCreateRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateCreateResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+ msgObj, err := ParseCreateRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ }).Trace("recevied-omci-create-request")
+
+ response := &omci.CreateResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: msgObj.EntityClass,
+ EntityInstance: msgObj.EntityInstance,
+ },
+ Result: me.Success,
+ }
+
+ pkt, err := serialize(omci.CreateResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("cannot-serialize-CreateResponse")
+ return nil, err
+ }
+
+ log.WithFields(log.Fields{
+ "TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+ "pkt": hex.EncodeToString(pkt),
+ }).Trace("omci-create-response")
+
+ return pkt, nil
+}
+
+// methods used by BBR to drive the OMCI state machine
+
+func CreateGalEnetRequest(tid uint16) ([]byte, error) {
+ params := me.ParamData{
+ EntityID: galEthernetEID,
+ Attributes: me.AttributeValueMap{"MaximumGemPayloadSize": maxGemPayloadSize},
+ }
+ meDef, _ := me.NewGalEthernetProfile(params)
+ pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
+ if err != nil {
+ omciLogger.WithField("err", err).Fatalf("Can't generate GalEnetRequest")
+ }
+ return hexEncode(pkt)
+}
+
+func CreateEnableUniRequest(tid uint16, uniId uint16, enabled bool, isPtp bool) ([]byte, error) {
+
+ var _enabled uint8
+ if enabled {
+ _enabled = uint8(1)
+ } else {
+ _enabled = uint8(0)
+ }
+
+ data := me.ParamData{
+ EntityID: uniId,
+ Attributes: me.AttributeValueMap{
+ "AdministrativeState": _enabled,
+ },
+ }
+ var medef *me.ManagedEntity
+ var omciErr me.OmciErrors
+
+ if isPtp {
+ medef, omciErr = me.NewPhysicalPathTerminationPointEthernetUni(data)
+ } else {
+ medef, omciErr = me.NewVirtualEthernetInterfacePoint(data)
+ }
+ if omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ pkt, err := omci.GenFrame(medef, omci.SetRequestType, omci.TransactionID(tid))
+ if err != nil {
+ omciLogger.WithField("err", err).Fatalf("Can't generate EnableUniRequest")
+ }
+ return hexEncode(pkt)
+}
+
+func CreateGemPortRequest(tid uint16) ([]byte, error) {
+ params := me.ParamData{
+ EntityID: gemEID,
+ Attributes: me.AttributeValueMap{
+ "PortId": 1,
+ "TContPointer": 1,
+ "Direction": 0,
+ "TrafficManagementPointerForUpstream": 0,
+ "TrafficDescriptorProfilePointerForUpstream": 0,
+ "UniCounter": 0,
+ "PriorityQueuePointerForDownStream": 0,
+ "EncryptionState": 0,
+ "TrafficDescriptorProfilePointerForDownstream": 0,
+ "EncryptionKeyRing": 0,
+ },
+ }
+ meDef, _ := me.NewGemPortNetworkCtp(params)
+ pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
+ if err != nil {
+ omciLogger.WithField("err", err).Fatalf("Can't generate GemPortRequest")
+ }
+ return hexEncode(pkt)
+}
diff --git a/internal/common/omci/delete.go b/internal/common/omci/delete.go
new file mode 100644
index 0000000..c38d696
--- /dev/null
+++ b/internal/common/omci/delete.go
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+)
+
+func ParseDeleteRequest(omciPkt gopacket.Packet) (*omci.DeleteRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeDeleteRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeDeleteRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.DeleteRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeDeleteRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateDeleteResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+ msgObj, err := ParseDeleteRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ }).Trace("recevied-omci-delete-request")
+
+ response := &omci.DeleteResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: msgObj.EntityClass,
+ EntityInstance: msgObj.EntityInstance,
+ },
+ Result: me.Success,
+ }
+
+ pkt, err := serialize(omci.DeleteResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("cannot-serialize-DeleteResponse")
+ return nil, err
+ }
+
+ return pkt, nil
+}
diff --git a/internal/common/omci/get.go b/internal/common/omci/get.go
new file mode 100644
index 0000000..64a7968
--- /dev/null
+++ b/internal/common/omci/get.go
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "encoding/hex"
+ "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"
+ "strconv"
+)
+
+func ParseGetRequest(omciPkt gopacket.Packet) (*omci.GetRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeGetRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeGetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.GetRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeGetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateGetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+ msgObj, err := ParseGetRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "AttributeMask": fmt.Sprintf("%x", msgObj.AttributeMask),
+ }).Trace("recevied-omci-get-request")
+
+ var response *omci.GetResponse
+ switch msgObj.EntityClass {
+ case me.Onu2GClassID:
+ response = createOnu2gResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.OnuGClassID:
+ response = createOnugResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.SoftwareImageClassID:
+ response = createSoftwareImageResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.IpHostConfigDataClassID:
+ response = createIpHostResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.UniGClassID:
+ response = createUnigResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.PhysicalPathTerminationPointEthernetUniClassID:
+ response = createPptpResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.AniGClassID:
+ response = createAnigResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ case me.OnuDataClassID:
+ response = createOnuDataResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+ default:
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "AttributeMask": fmt.Sprintf("%x", msgObj.AttributeMask),
+ }).Warnf("do-not-know-how-to-handle-get-request-for-me-class")
+ return nil, nil
+ }
+
+ pkt, err := serialize(omci.GetResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ "TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+ }).Error("cannot-serialize-Onu2gResponse")
+ return nil, err
+ }
+
+ log.WithFields(log.Fields{
+ "TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+ "pkt": hex.EncodeToString(pkt),
+ }).Trace("omci-get-response")
+
+ return pkt, nil
+}
+
+func createOnu2gResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+
+ managedEntity, meErr := me.NewOnu2G(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "EquipmentId": toOctets("BBSM", 20),
+ "OpticalNetworkUnitManagementAndControlChannelOmccVersion": 180,
+ "VendorProductCode": 0,
+ "SecurityCapability": 1,
+ "SecurityMode": 1,
+ "TotalPriorityQueueNumber": 1,
+ "TotalTrafficSchedulerNumber": 1,
+ "Deprecated": 1,
+ "TotalGemPortIdNumber": 32,
+ "Sysuptime": 319389947, // NOTE need to be smarter?
+ "ConnectivityCapability": 127,
+ "CurrentConnectivityMode": 5,
+ "QualityOfServiceQosConfigurationFlexibility": 48,
+ "PriorityQueueScaleFactor": 1,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewOnu2G %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.Onu2GClassID,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func createOnugResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuGClassID,
+ EntityInstance: entityID,
+ },
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "VendorId": toOctets("BBSM", 4),
+ "Version": toOctets("v0.0.1", 14),
+ "SerialNumber": toOctets("QkJTTQAKAAE=", 8),
+ "TrafficManagementOption": 0,
+ "Deprecated": 0,
+ "BatteryBackup": 0,
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "OnuSurvivalTime": 10,
+ "LogicalOnuId": toOctets("BBSM", 24),
+ "LogicalPassword": toOctets("BBSM", 12),
+ "CredentialsStatus": 0,
+ "ExtendedTcLayerOptions": 0,
+ },
+ Result: me.Success,
+ AttributeMask: attributeMask,
+ }
+}
+
+func createSoftwareImageResponse(attributeMask uint16, entityInstance uint16) *omci.GetResponse {
+ // NOTE that we need send the response for the correct ME Instance or the adapter won't process it
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.SoftwareImageClassID,
+ EntityInstance: entityInstance,
+ },
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": 0,
+ "Version": toOctets("v0.0.1", 14),
+ "IsCommitted": 1,
+ "IsActive": 1,
+ "IsValid": 1,
+ "ProductCode": toOctets("product-code", 25),
+ "ImageHash": toOctets("broadband-sim", 16),
+ },
+ Result: me.Success,
+ AttributeMask: attributeMask,
+ }
+}
+
+func createIpHostResponse(attributeMask uint16, entityInstance uint16) *omci.GetResponse {
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.IpHostConfigDataClassID,
+ EntityInstance: entityInstance,
+ },
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": 0,
+ "MacAddress": toOctets("aabbcc", 6),
+ },
+ Result: me.Success,
+ AttributeMask: attributeMask,
+ }
+}
+
+func createUnigResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ managedEntity, meErr := me.NewUniG(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "Deprecated": 0,
+ "AdministrativeState": 0,
+ "ManagementCapability": 0,
+ "NonOmciManagementIdentifier": 1,
+ "RelayAgentOptions": 1,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewUniG %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.UniGClassID,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func createPptpResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ managedEntity, meErr := me.NewPhysicalPathTerminationPointEthernetUni(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "ExpectedType": 0,
+ "SensedType": 0,
+ "AutoDetectionConfiguration": 0,
+ "EthernetLoopbackConfiguration": 0,
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "ConfigurationInd": 0,
+ "MaxFrameSize": 0,
+ "DteOrDceInd": 0,
+ "PauseTime": 0,
+ "BridgedOrIpInd": 0,
+ "Arc": 0,
+ "ArcInterval": 0,
+ "PppoeFilter": 0,
+ "PowerControl": 0,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewPhysicalPathTerminationPointEthernetUni %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.PhysicalPathTerminationPointEthernetUniClassID,
+ },
+ 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": 0,
+ "LowerOpticalThreshold": 0,
+ "UpperOpticalThreshold": 0,
+ "OnuResponseTime": 0,
+ "TransmitOpticalLevel": 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,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func createOnuDataResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+ managedEntity, meErr := me.NewOnuData(me.ParamData{
+ EntityID: entityID,
+ Attributes: me.AttributeValueMap{
+ "ManagedEntityId": entityID,
+ "MibDataSync": 0,
+ },
+ })
+
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewOnuData %v", meErr.Error())
+ return nil
+ }
+
+ return &omci.GetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
+ },
+ Attributes: managedEntity.GetAttributeValueMap(),
+ AttributeMask: attributeMask,
+ Result: me.Success,
+ }
+}
+
+func toOctets(str string, size int) []byte {
+ asciiBytes := []byte(str)
+
+ if len(asciiBytes) < size {
+ missing := size - len(asciiBytes)
+ for i := 0; i < missing; i++ {
+ asciiBytes = append(asciiBytes, []byte{0x00}[0])
+ }
+ }
+ return asciiBytes
+}
diff --git a/internal/common/omci/get_test.go b/internal/common/omci/get_test.go
new file mode 100644
index 0000000..0ab6d04
--- /dev/null
+++ b/internal/common/omci/get_test.go
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ "gotest.tools/assert"
+ "testing"
+)
+
+func omciBytesToMsg(t *testing.T, data []byte) (*omci.OMCI, *gopacket.Packet) {
+ packet := gopacket.NewPacket(data, omci.LayerTypeOMCI, gopacket.NoCopy)
+ if packet == nil {
+ t.Fatal("could not decode rxMsg as OMCI")
+ }
+ omciLayer := packet.Layer(omci.LayerTypeOMCI)
+ if omciLayer == nil {
+ t.Fatal("could not decode omci layer")
+ }
+ omciMsg, ok := omciLayer.(*omci.OMCI)
+ if !ok {
+ t.Fatal("could not assign omci layer")
+ }
+ return omciMsg, &packet
+}
+
+func omciToGetResponse(t *testing.T, omciPkt *gopacket.Packet) *omci.GetResponse {
+ msgLayer := (*omciPkt).Layer(omci.LayerTypeGetResponse)
+ if msgLayer == nil {
+ t.Fatal("omci Msg layer could not be detected for GetResponse - handling of MibSyncChan stopped")
+ }
+ msgObj, msgOk := msgLayer.(*omci.GetResponse)
+ if !msgOk {
+ t.Fatal("omci Msg layer could not be assigned for GetResponse - handling of MibSyncChan stopped")
+ }
+ return msgObj
+}
+
+func TestCreateOnu2gResponse(t *testing.T) {
+ response := createOnu2gResponse(40960, 1)
+ data, _ := serialize(omci.GetResponseType, response, 1)
+
+ // emulate the openonu-go behavior:
+ // omci_cc.receiveMessage process the message (creates a gopacket and extracts the OMCI layer) and invokes a callback
+ // in the GetResponse case omci_cc.receiveOmciResponse
+ // then the OmciMessage (gopacket + OMIC layer) is is published on a channel
+ omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+ assert.Equal(t, omciMsg.MessageType, omci.GetResponseType)
+
+ // that is read by myb_sync.processMibSyncMessages
+ // the myb_sync.handleOmciMessage is called and then
+ // myb_sync.handleOmciGetResponseMessage where we extract the GetResponse layer
+ getResponseLayer := omciToGetResponse(t, omciPkt)
+
+ assert.Equal(t, getResponseLayer.Result, me.Success)
+}
+
+func TestCreateOnugResponse(t *testing.T) {
+ response := createOnugResponse(40960, 1)
+ data, _ := serialize(omci.GetResponseType, response, 1)
+
+ omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+ assert.Equal(t, omciMsg.MessageType, omci.GetResponseType)
+
+ getResponseLayer := omciToGetResponse(t, omciPkt)
+
+ assert.Equal(t, getResponseLayer.Result, me.Success)
+}
diff --git a/internal/common/omci/mib_test.go b/internal/common/omci/mib_test.go
new file mode 100644
index 0000000..c73f616
--- /dev/null
+++ b/internal/common/omci/mib_test.go
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ "gotest.tools/assert"
+ "testing"
+)
+
+func TestCreateMibResetResponse(t *testing.T) {
+ data, _ := CreateMibResetResponse(1)
+
+ omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+ assert.Equal(t, omciMsg.MessageType, omci.MibResetResponseType)
+
+ msgLayer := (*omciPkt).Layer(omci.LayerTypeMibResetResponse)
+ msgObj, msgOk := msgLayer.(*omci.MibResetResponse)
+ if !msgOk {
+ t.Fail()
+ }
+
+ assert.Equal(t, msgObj.Result, me.Success)
+}
+
+// types for TestCreateMibUploadNextResponse test
+type mibArgs struct {
+ omciPkt gopacket.Packet
+ omciMsg *omci.OMCI
+}
+
+type mibExpected struct {
+ messageType omci.MessageType
+ transactionId uint16
+ entityClass me.ClassID
+ attributes map[string]interface{}
+}
+
+func createTestMibUploadNextArgs(t *testing.T, tid uint16, seqNumber uint16) mibArgs {
+ mibUploadNext, _ := CreateMibUploadNextRequest(tid, seqNumber)
+ mibUploadNext = hexDecode(mibUploadNext)
+ mibUploadNextMsg, mibUploadNextPkt := omciBytesToMsg(t, mibUploadNext)
+
+ return mibArgs{
+ omciPkt: *mibUploadNextPkt,
+ omciMsg: mibUploadNextMsg,
+ }
+}
+
+func TestCreateMibUploadNextResponse(t *testing.T) {
+
+ tests := []struct {
+ name string
+ args mibArgs
+ want mibExpected
+ }{
+ {"mibUploadNext-0", createTestMibUploadNextArgs(t, 1, 0),
+ mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 1, entityClass: me.OnuDataClassID, attributes: map[string]interface{}{"MibDataSync": uint8(0)}}},
+ {"mibUploadNext-1", createTestMibUploadNextArgs(t, 2, 1),
+ mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 2, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"Type": uint8(47), "NumberOfPorts": uint8(4)}}},
+ {"mibUploadNext-4", createTestMibUploadNextArgs(t, 3, 4),
+ mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 3, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"PowerShedOverride": uint32(0)}}},
+ {"mibUploadNext-10", createTestMibUploadNextArgs(t, 4, 10),
+ mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 4, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"SensedType": uint8(47)}}},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+
+ // create the packet starting from the mibUploadNextRequest
+ data, _ := CreateMibUploadNextResponse(tt.args.omciPkt, tt.args.omciMsg)
+ omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+ assert.Equal(t, omciMsg.MessageType, tt.want.messageType)
+
+ msgLayer := (*omciPkt).Layer(omci.LayerTypeMibUploadNextResponse)
+ msgObj, msgOk := msgLayer.(*omci.MibUploadNextResponse)
+ if !msgOk {
+ t.Fail()
+ }
+
+ assert.Equal(t, omciMsg.TransactionID, tt.want.transactionId) // tid
+ // GetAttribute("ManagedEntityId") returns nil,
+ // msgObj.EntityClass is always OnuDataClassID
+ // how do we check this?
+ //meId, _ := msgObj.ReportedME.GetAttribute("ManagedEntityId")
+ //assert.Equal(t, meId, tt.want.entityClass)
+ //assert.Equal(t, msgObj.EntityClass, tt.want.entityClass)
+
+ fmt.Println(msgObj.EntityInstance, msgObj.ReportedME.GetEntityID())
+
+ for k, v := range tt.want.attributes {
+ attr, _ := msgObj.ReportedME.GetAttribute(k)
+ assert.Equal(t, attr, v)
+ }
+ })
+ }
+
+}
diff --git a/internal/common/omci/mibpackets.go b/internal/common/omci/mibpackets.go
index b21da4d..fe02e5d 100755
--- a/internal/common/omci/mibpackets.go
+++ b/internal/common/omci/mibpackets.go
@@ -18,10 +18,10 @@
import (
"encoding/hex"
- "github.com/cboling/omci"
- me "github.com/cboling/omci/generated"
+ "errors"
"github.com/google/gopacket"
- omcisim "github.com/opencord/omci-sim"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
log "github.com/sirupsen/logrus"
)
@@ -41,6 +41,8 @@
RxHandler rxFrameParser
}
+// NOTE this is basically the same as https://github.com/opencord/voltha-openonu-adapter-go/blob/master/internal/pkg/onuadaptercore/omci_cc.go#L545-L564
+// we should probably move it in "omci-lib-go"
func serialize(msgType omci.MessageType, request gopacket.SerializableLayer, tid uint16) ([]byte, error) {
omciLayer := &omci.OMCI{
TransactionID: tid,
@@ -63,57 +65,11 @@
return dst, nil
}
-func DecodeOmci(payload []byte) (omci.MessageType, gopacket.Packet) {
- // Perform base OMCI decode (common to all requests)
- packet := gopacket.NewPacket(payload, omci.LayerTypeOMCI, gopacket.NoCopy)
-
- if omciLayer := packet.Layer(omci.LayerTypeOMCI); omciLayer != nil {
-
- omciObj, omciOk := omciLayer.(*omci.OMCI)
- if !omciOk {
- panic("Not Expected") // TODO: Do something better or delete...
- }
- if byte(omciObj.MessageType) & ^me.AK == 0 {
- // Not a response, silently discard
- return 0, nil
- }
- return omciObj.MessageType, packet
- }
-
- // FIXME
- // if we can't properly decode the packet, try using shad helper method
- // most likely this won't be necessary once we move omci-sim to use cboling/omci
- // to generate packets
- _, _, msgType, _, _, _, err := omcisim.ParsePkt(payload)
- if err != nil {
- return 0, nil
- }
- if msgType == omcisim.MibReset {
- return omci.MibResetResponseType, nil
- }
- if msgType == omcisim.MibUpload {
- return omci.MibUploadResponseType, nil
- }
- if msgType == omcisim.MibUploadNext {
- return omci.MibUploadNextResponseType, nil
- }
- if msgType == omcisim.Create {
- return omci.CreateResponseType, nil
- }
- if msgType == omcisim.Set {
- return omci.SetResponseType, nil
- }
-
- omciLogger.Warnf("omci-sim returns msgType: %d", msgType)
-
- return 0, nil
-}
-
func CreateMibResetRequest(tid uint16) ([]byte, error) {
request := &omci.MibResetRequest{
MeBasePacket: omci.MeBasePacket{
- EntityClass: me.OnuDataClassId,
+ EntityClass: me.OnuDataClassID,
},
}
pkt, err := serialize(omci.MibResetRequestType, request, tid)
@@ -126,10 +82,29 @@
return hexEncode(pkt)
}
+func CreateMibResetResponse(tid uint16) ([]byte, error) {
+
+ // TODO reset MDX
+ request := &omci.MibResetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
+ },
+ Result: me.Success,
+ }
+ pkt, err := serialize(omci.MibResetResponseType, request, tid)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("Cannot serialize MibResetResponse")
+ return nil, err
+ }
+ return pkt, nil
+}
+
func CreateMibUploadRequest(tid uint16) ([]byte, error) {
request := &omci.MibUploadRequest{
MeBasePacket: omci.MeBasePacket{
- EntityClass: me.OnuDataClassId,
+ EntityClass: me.OnuDataClassID,
// Default Instance ID is 0
},
}
@@ -143,11 +118,31 @@
return hexEncode(pkt)
}
+func CreateMibUploadResponse(tid uint16) ([]byte, error) {
+
+ numberOfCommands := uint16(291) //NOTE should this be configurable? (not until we have moved all the messages away from omci-sim)
+
+ request := &omci.MibUploadResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
+ },
+ NumberOfCommands: numberOfCommands,
+ }
+ pkt, err := serialize(omci.MibUploadResponseType, request, tid)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("Cannot serialize MibUploadResponse")
+ return nil, err
+ }
+ return pkt, nil
+}
+
func CreateMibUploadNextRequest(tid uint16, seqNumber uint16) ([]byte, error) {
request := &omci.MibUploadNextRequest{
MeBasePacket: omci.MeBasePacket{
- EntityClass: me.OnuDataClassId,
+ EntityClass: me.OnuDataClassID,
// Default Instance ID is 0
},
CommandSequenceNumber: seqNumber,
@@ -163,123 +158,299 @@
return hexEncode(pkt)
}
-// Return true if msg is an Omci Test Request
-func IsTestRequest(payload []byte) (bool, error) {
- _, _, msgType, _, _, _, err := omcisim.ParsePkt(payload)
- if err != nil {
- return false, err
+func ParseMibUploadNextRequest(omciPkt gopacket.Packet) (*omci.MibUploadNextRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeMibUploadNextRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeMibUploadNextRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
}
-
- return ((msgType & 0x1F) == 18), nil
+ msgObj, msgOk := msgLayer.(*omci.MibUploadNextRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for MibUploadNextRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
}
-func BuildTestResult(payload []byte) ([]byte, error) {
- transactionId, deviceId, _, class, instance, _, err := omcisim.ParsePkt(payload)
+func CreateMibUploadNextResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+ msgObj, err := ParseMibUploadNextRequest(omciPkt)
if err != nil {
- return []byte{}, err
+ err := "omci Msg layer could not be assigned for LayerTypeGetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
}
- resp := make([]byte, 48)
- resp[0] = byte(transactionId >> 8)
- resp[1] = byte(transactionId & 0xFF)
- resp[2] = 27 // Upper nibble 0x0 is fixed (0000), Lower nibbles defines msg type (TestResult=27)
- resp[3] = deviceId
- resp[4] = byte(class >> 8)
- resp[5] = byte(class & 0xFF)
- resp[6] = byte(instance >> 8)
- resp[7] = byte(instance & 0xFF)
- // Each of these is a 1-byte code
- // follow by a 2-byte (high, low) value
- resp[8] = 1 // power feed voltage
- resp[9] = 0
- resp[10] = 123 // 123 mV, 20 mv res --> 6mv
- resp[11] = 3 // received optical power
- resp[12] = 1
- resp[13] = 200 // 456 decibel-microwatts, 0.002 dB res --> 0.912 db-mw
- resp[14] = 5 // mean optical launch power
- resp[15] = 3
- resp[16] = 21 // 789 uA, 0.002 dB res --> 1.578 db-mw
- resp[17] = 9 // laser bias current
- resp[18] = 3
- resp[19] = 244 // 1012 uA, 2uA res --> 505 ua
- resp[20] = 12 // temperature
- resp[21] = 38
- resp[22] = 148 // 9876 deg C, 1/256 resolution --> 38.57 Deg C
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "CommandSequenceNumber": msgObj.CommandSequenceNumber,
+ }).Trace("received-omci-mibUploadNext-request")
- return resp, nil
-}
+ // depending on the sequenceNumber we'll report a different
+ reportedMe := &me.ManagedEntity{}
+ var meErr me.OmciErrors
+ //var entityInstance uint16
+ switch msgObj.CommandSequenceNumber {
+ case 0:
+ reportedMe, meErr = me.NewOnuData(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.OnuDataClassID,
+ "MibDataSync": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewOnuData %v", meErr.Error())
+ }
-// TODO understand and refactor
-
-func CreateGalEnetRequest(tid uint16) ([]byte, error) {
- params := me.ParamData{
- EntityID: galEthernetEID,
- Attributes: me.AttributeValueMap{"MaximumGemPayloadSize": maxGemPayloadSize},
- }
- meDef, _ := me.NewGalEthernetProfile(params)
- pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
- if err != nil {
- omciLogger.WithField("err", err).Fatalf("Can't generate GalEnetRequest")
- }
- return hexEncode(pkt)
-}
-
-func CreateEnableUniRequest(tid uint16, uniId uint16, enabled bool, isPtp bool) ([]byte, error) {
-
- var _enabled uint8
- if enabled {
- _enabled = uint8(1)
- } else {
- _enabled = uint8(0)
+ case 1:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "Type": 47,
+ "NumberOfPorts": 4,
+ "SerialNumber": toOctets("BBSM-Circuit-Pack", 20),
+ "Version": toOctets("v0.0.1", 20),
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 2:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "VendorId": "ONF",
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "BridgedOrIpInd": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 3:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "EquipmentId": toOctets("BBSM-Circuit-Pack", 20),
+ "CardConfiguration": 0,
+ "TotalTContBufferNumber": 0,
+ "TotalPriorityQueueNumber": 8,
+ "TotalTrafficSchedulerNumber": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 4:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "PowerShedOverride": uint32(0),
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 5:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "Type": 238,
+ "NumberOfPorts": 1,
+ "SerialNumber": toOctets("BBSM-Circuit-Pack-2", 20),
+ "Version": toOctets("v0.0.1", 20),
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 6:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "VendorId": "ONF",
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "BridgedOrIpInd": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 7:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "EquipmentId": toOctets("BBSM-Circuit-Pack", 20),
+ "CardConfiguration": 0,
+ "TotalTContBufferNumber": 8,
+ "TotalPriorityQueueNumber": 40,
+ "TotalTrafficSchedulerNumber": 10,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 8:
+ reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.CircuitPackClassID,
+ "PowerShedOverride": uint32(0),
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+ }
+ case 9, 10, 11, 12:
+ // NOTE we're reporting for different UNIs, the IDs are 257, 258, 259, 260
+ meInstance := 248 + msgObj.CommandSequenceNumber
+ reportedMe, meErr = me.NewPhysicalPathTerminationPointEthernetUni(me.ParamData{
+ EntityID: meInstance,
+ Attributes: me.AttributeValueMap{
+ "ExpectedType": 0,
+ "SensedType": 47,
+ "AutoDetectionConfiguration": 0,
+ "EthernetLoopbackConfiguration": 0,
+ "AdministrativeState": 0,
+ "OperationalState": 0,
+ "ConfigurationInd": 3,
+ "MaxFrameSize": 1518,
+ "DteOrDceInd": 0,
+ "PauseTime": 0,
+ "BridgedOrIpInd": 2,
+ "Arc": 0,
+ "ArcInterval": 0,
+ "PppoeFilter": 0,
+ "PowerControl": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewPhysicalPathTerminationPointEthernetUni %v", meErr.Error())
+ }
+ case 13, 14, 15, 16, 17, 18, 19, 20:
+ // TODO report different MeID (see omci-sim pcap filter "frame[22:2] == 01:06")
+ reportedMe, meErr = me.NewTCont(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.TContClassID,
+ "AllocId": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewTCont %v", meErr.Error())
+ }
+ case 21:
+ reportedMe, meErr = me.NewAniG(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.AniGClassID,
+ "SrIndication": 1,
+ "TotalTcontNumber": 8,
+ "GemBlockLength": 30,
+ "PiggybackDbaReporting": 0,
+ "Deprecated": 0,
+ "SignalFailThreshold": 5,
+ "SignalDegradeThreshold": 9,
+ "Arc": 0,
+ "ArcInterval": 0,
+ "OpticalSignalLevel": 57428,
+ "LowerOpticalThreshold": 255,
+ "UpperOpticalThreshold": 255,
+ "OnuResponseTime": 0,
+ "TransmitOpticalLevel": 3171,
+ "LowerTransmitPowerThreshold": 129,
+ "UpperTransmitPowerThreshold": 129,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewAniG %v", meErr.Error())
+ }
+ case 22, 23, 24, 25:
+ // TODO report different MeID (see omci-sim pcap filter "frame[22:2] == 01:08")
+ reportedMe, meErr = me.NewUniG(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.UniGClassID,
+ "Deprecated": 0,
+ "AdministrativeState": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewUniG %v", meErr.Error())
+ }
+ case 26, 30, 34, 38, 42, 46, 50, 54,
+ 58, 62, 66, 70, 74, 78, 82, 86,
+ 90, 94, 98, 102, 106, 110, 114, 118,
+ 122, 126, 130, 134, 138, 142, 146, 150,
+ 154, 158, 162, 166, 170, 174, 178, 182,
+ 186, 190, 194, 198, 202, 206, 210, 214,
+ 218, 222, 226, 230, 234, 238, 242, 246,
+ 250, 254, 258, 262, 266, 270, 274, 278:
+ case 27, 31, 35, 39, 43, 47, 51, 55,
+ 59, 63, 67, 71, 75, 79, 83, 87,
+ 91, 95, 99, 103, 107, 111, 115, 119,
+ 123, 127, 131, 135, 139, 143, 147, 151,
+ 155, 159, 163, 167, 171, 175, 179, 183,
+ 187, 191, 195, 199, 203, 207, 211, 215,
+ 219, 223, 227, 231, 235, 239, 243, 247,
+ 251, 255, 259, 263, 267, 271, 275, 279:
+ case 28, 32, 36, 40, 44, 48, 52, 56,
+ 60, 64, 68, 72, 76, 80, 84, 88,
+ 92, 96, 100, 104, 108, 112, 116, 120,
+ 124, 128, 132, 136, 140, 144, 148, 152,
+ 156, 160, 164, 168, 172, 176, 180, 184,
+ 188, 192, 196, 200, 204, 208, 212, 216,
+ 220, 224, 228, 232, 236, 240, 244, 248,
+ 252, 256, 260, 264, 268, 272, 276, 280:
+ case 29, 33, 37, 41, 45, 49, 53, 57,
+ 61, 65, 69, 73, 77, 81, 85, 89,
+ 93, 97, 101, 105, 109, 113, 117, 121,
+ 125, 129, 133, 137, 141, 145, 149, 153,
+ 157, 161, 165, 169, 173, 177, 181, 185,
+ 189, 193, 197, 201, 205, 209, 213, 217,
+ 221, 225, 229, 233, 237, 241, 245, 249,
+ 253, 257, 261, 265, 269, 273, 277, 281:
+ reportedMe, meErr = me.NewPriorityQueue(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.PriorityQueueClassID,
+ "QueueConfigurationOption": 0,
+ "MaximumQueueSize": 100,
+ "AllocatedQueueSize": 100,
+ "DiscardBlockCounterResetInterval": 0,
+ "ThresholdValueForDiscardedBlocksDueToBufferOverflow": 0,
+ "RelatedPort": 80010000, // does this need to change?
+ "TrafficSchedulerPointer": 8008, // does this need to change?
+ "Weight": 1,
+ "BackPressureOperation": 1,
+ "BackPressureTime": 0,
+ "BackPressureOccurQueueThreshold": 0,
+ "BackPressureClearQueueThreshold": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewPriorityQueue %v", meErr.Error())
+ }
+ case 282, 283, 284, 285, 286, 287, 288, 289:
+ reportedMe, meErr = me.NewTrafficScheduler(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.TrafficSchedulerClassID,
+ "TContPointer": 8008, // NOTE does this need to change?
+ "TrafficSchedulerPointer": 0,
+ "Policy": 02,
+ "PriorityWeight": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewTrafficScheduler %v", meErr.Error())
+ }
+ case 290:
+ reportedMe, meErr = me.NewOnu2G(me.ParamData{Attributes: me.AttributeValueMap{
+ "ManagedEntityId": me.Onu2GClassID,
+ "TotalPriorityQueueNumber": 40,
+ "SecurityMode": 1,
+ "TotalTrafficSchedulerNumber": 8,
+ "TotalGemPortIdNumber": 0,
+ "Sysuptime": 0,
+ }})
+ if meErr.GetError() != nil {
+ omciLogger.Errorf("NewOnu2G %v", meErr.Error())
+ }
+ default:
+ omciLogger.Warn("unsupported-CommandSequenceNumber-in-mib-upload-next", msgObj.CommandSequenceNumber)
+ return nil, nil
}
- data := me.ParamData{
- EntityID: uniId,
- Attributes: me.AttributeValueMap{
- "AdministrativeState": _enabled,
+ response := &omci.MibUploadNextResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: me.OnuDataClassID,
},
+ ReportedME: *reportedMe,
}
- var medef *me.ManagedEntity
- var omciErr me.OmciErrors
- if isPtp {
- medef, omciErr = me.NewPhysicalPathTerminationPointEthernetUni(data)
- } else {
- medef, omciErr = me.NewVirtualEthernetInterfacePoint(data)
- }
- if omciErr != nil {
- return nil, omciErr.GetError()
- }
- pkt, err := omci.GenFrame(medef, omci.SetRequestType, omci.TransactionID(tid))
+ omciLogger.WithFields(log.Fields{
+ "reportedMe": reportedMe,
+ }).Trace("created-omci-mibUploadNext-response")
+
+ pkt, err := serialize(omci.MibUploadNextResponseType, response, omciMsg.TransactionID)
+
if err != nil {
- omciLogger.WithField("err", err).Fatalf("Can't generate EnableUniRequest")
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Fatalf("Cannot serialize MibUploadNextRequest")
+ return nil, err
}
- return hexEncode(pkt)
-}
-func CreateGemPortRequest(tid uint16) ([]byte, error) {
- params := me.ParamData{
- EntityID: gemEID,
- Attributes: me.AttributeValueMap{
- "PortId": 1,
- "TContPointer": 1,
- "Direction": 0,
- "TrafficManagementPointerForUpstream": 0,
- "TrafficDescriptorProfilePointerForUpstream": 0,
- "UniCounter": 0,
- "PriorityQueuePointerForDownStream": 0,
- "EncryptionState": 0,
- "TrafficDescriptorProfilePointerForDownstream": 0,
- "EncryptionKeyRing": 0,
- },
- }
- meDef, _ := me.NewGemPortNetworkCtp(params)
- pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
- if err != nil {
- omciLogger.WithField("err", err).Fatalf("Can't generate GemPortRequest")
- }
- return hexEncode(pkt)
+ return pkt, nil
}
-
-// END TODO
diff --git a/internal/common/omci/omci_base.go b/internal/common/omci/omci_base.go
new file mode 100644
index 0000000..e74ec4a
--- /dev/null
+++ b/internal/common/omci/omci_base.go
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ log "github.com/sirupsen/logrus"
+)
+
+// ParseOpenOltOmciPacket receive an OMCI packet in the openolt format and returns
+// an OMCI Layer as per omci-lib-go
+func ParseOpenOltOmciPacket(pkt []byte) (gopacket.Packet, *omci.OMCI, error) {
+ rxMsg := hexDecode(pkt)
+
+ // NOTE this is may not be needed, VOLTHA sends the correct message
+ if len(rxMsg) >= 44 {
+ trailerLenData := rxMsg[42:44]
+ trailerLen := binary.BigEndian.Uint16(trailerLenData)
+ if trailerLen != 40 { // invalid base Format entry -> autocorrect
+ binary.BigEndian.PutUint16(rxMsg[42:44], 40)
+ omciLogger.Trace("cc-corrected-omci-message: trailer len inserted")
+ }
+ } else {
+ omciLogger.WithFields(log.Fields{"Length": len(rxMsg)}).Error("received omci-message too small for OmciBaseFormat - abort")
+ return nil, nil, errors.New("received omci-message too small for OmciBaseFormat - abort")
+ }
+
+ packet := gopacket.NewPacket(rxMsg, omci.LayerTypeOMCI, gopacket.NoCopy)
+ if packet == nil {
+ omciLogger.Error("omci-message could not be decoded")
+ return nil, nil, errors.New("omci-message could not be decoded")
+ }
+ omciLayer := packet.Layer(omci.LayerTypeOMCI)
+ if omciLayer == nil {
+ omciLogger.Error("omci-message could not decode omci layer")
+ return nil, nil, fmt.Errorf("omci-message could not decode omci layer")
+ }
+ parsed, ok := omciLayer.(*omci.OMCI)
+ if !ok {
+ omciLogger.Error("omci-message could not assign omci layer")
+ return nil, nil, errors.New("omci-message could not assign omci layer")
+ }
+
+ return packet, parsed, nil
+}
+
+// hexDecode converts the hex encoding to binary
+func hexDecode(pkt []byte) []byte {
+ p := make([]byte, len(pkt)/2)
+ for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
+ // Go figure this ;)
+ u := (pkt[i] & 15) + (pkt[i]>>6)*9
+ l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
+ p[j] = u<<4 + l
+ }
+ return p
+}
diff --git a/internal/common/omci/reboot.go b/internal/common/omci/reboot.go
new file mode 100644
index 0000000..e315044
--- /dev/null
+++ b/internal/common/omci/reboot.go
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+)
+
+func ParseRebootRequest(omciPkt gopacket.Packet) (*omci.RebootRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeRebootRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeRebootRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.RebootRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeRebootRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateRebootResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+ msgObj, err := ParseRebootRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ }).Trace("received-omci-set-request")
+
+ response := &omci.SetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: msgObj.EntityClass,
+ EntityInstance: msgObj.EntityInstance,
+ },
+ Result: me.Success,
+ }
+
+ pkt, err := serialize(omci.RebootResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("cannot-serialize-RebootResponse")
+ return nil, err
+ }
+
+ return pkt, nil
+
+}
diff --git a/internal/common/omci/set.go b/internal/common/omci/set.go
new file mode 100644
index 0000000..eeb621e
--- /dev/null
+++ b/internal/common/omci/set.go
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+ me "github.com/opencord/omci-lib-go/generated"
+ log "github.com/sirupsen/logrus"
+)
+
+func ParseSetRequest(omciPkt gopacket.Packet) (*omci.SetRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeSetRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeSetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.SetRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeSetRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+func CreateSetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+ msgObj, err := ParseSetRequest(omciPkt)
+
+ if err != nil {
+ return nil, err
+ }
+
+ omciLogger.WithFields(log.Fields{
+ "EntityClass": msgObj.EntityClass,
+ "EntityInstance": msgObj.EntityInstance,
+ "AttributeMask": msgObj.AttributeMask,
+ }).Trace("received-omci-set-request")
+
+ response := &omci.SetResponse{
+ MeBasePacket: omci.MeBasePacket{
+ EntityClass: msgObj.EntityClass,
+ EntityInstance: msgObj.EntityInstance,
+ },
+ Result: me.Success,
+ }
+
+ pkt, err := serialize(omci.SetResponseType, response, omciMsg.TransactionID)
+ if err != nil {
+ omciLogger.WithFields(log.Fields{
+ "Err": err,
+ }).Error("cannot-serialize-SetResponse")
+ return nil, err
+ }
+
+ return pkt, nil
+
+}
diff --git a/internal/common/omci/test.go b/internal/common/omci/test.go
new file mode 100644
index 0000000..40398ba
--- /dev/null
+++ b/internal/common/omci/test.go
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/opencord/omci-lib-go"
+)
+
+func ParseTestRequest(omciPkt gopacket.Packet) (*omci.TestRequest, error) {
+ msgLayer := omciPkt.Layer(omci.LayerTypeGetRequest)
+ if msgLayer == nil {
+ err := "omci Msg layer could not be detected for LayerTypeTestRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ msgObj, msgOk := msgLayer.(*omci.TestRequest)
+ if !msgOk {
+ err := "omci Msg layer could not be assigned for LayerTypeTestRequest"
+ omciLogger.Error(err)
+ return nil, errors.New(err)
+ }
+ return msgObj, nil
+}
+
+// Return true if msg is an Omci Test Request
+func IsTestRequest(payload []byte) (bool, error) {
+ _, omciMsg, err := ParseOpenOltOmciPacket(payload)
+ if err != nil {
+ return false, err
+ }
+
+ return omciMsg.MessageType == omci.TestRequestType, nil
+}
+
+func BuildTestResult(payload []byte) ([]byte, error) {
+
+ omciPkt, omciMsg, err := ParseOpenOltOmciPacket(payload)
+
+ //transactionId, deviceId, _, class, instance, _, err := omcisim.ParsePkt(payload)
+
+ if err != nil {
+ return []byte{}, err
+ }
+
+ testRequest, err := ParseTestRequest(omciPkt)
+ if err != nil {
+ return []byte{}, err
+ }
+
+ // TODO create a TestResponse using omci-lib-go
+ resp := make([]byte, 48)
+ resp[0] = byte(omciMsg.TransactionID >> 8)
+ resp[1] = byte(omciMsg.TransactionID & 0xFF)
+ resp[2] = 27 // Upper nibble 0x0 is fixed (0000), Lower nibbles defines msg type (TestResult=27)
+ resp[3] = byte(omciMsg.DeviceIdentifier)
+ resp[4] = byte(omciMsg.MessageType)
+ resp[5] = byte(omciMsg.MessageType & 0xFF)
+ resp[6] = byte(testRequest.EntityInstance >> 8)
+ resp[7] = byte(testRequest.EntityInstance & 0xFF)
+ // Each of these is a 1-byte code
+ // follow by a 2-byte (high, low) value
+ resp[8] = 1 // power feed voltage
+ resp[9] = 0
+ resp[10] = 123 // 123 mV, 20 mv res --> 6mv
+ resp[11] = 3 // received optical power
+ resp[12] = 1
+ resp[13] = 200 // 456 decibel-microwatts, 0.002 dB res --> 0.912 db-mw
+ resp[14] = 5 // mean optical launch power
+ resp[15] = 3
+ resp[16] = 21 // 789 uA, 0.002 dB res --> 1.578 db-mw
+ resp[17] = 9 // laser bias current
+ resp[18] = 3
+ resp[19] = 244 // 1012 uA, 2uA res --> 505 ua
+ resp[20] = 12 // temperature
+ resp[21] = 38
+ resp[22] = 148 // 9876 deg C, 1/256 resolution --> 38.57 Deg C
+
+ return resp, nil
+}