[VOL-4111] Dinamically generating the MibDB during ONU creation and use
that to drive the MibUploadNextResponse generation

Change-Id: I67dbbe0700a7fbec802516fc6b2a9aff496022de
diff --git a/internal/bbsim/api/onus_handler.go b/internal/bbsim/api/onus_handler.go
index 8f606d0..9fc73e7 100644
--- a/internal/bbsim/api/onus_handler.go
+++ b/internal/bbsim/api/onus_handler.go
@@ -48,6 +48,7 @@
 				ImageSoftwareExpectedSections: int32(o.ImageSoftwareExpectedSections),
 				ActiveImageEntityId:           int32(o.ActiveImageEntityId),
 				CommittedImageEntityId:        int32(o.CommittedImageEntityId),
+				Unis:                          convertBBsimUniPortsToProtoUniPorts(o.UniPorts),
 			}
 			onus.Items = append(onus.Items, &onu)
 		}
@@ -72,6 +73,7 @@
 		PonPortID:     int32(onu.PonPortID),
 		PortNo:        int32(onu.PortNo),
 		Services:      convertBBsimServicesToProtoServices(onu.Services),
+		Unis:          convertBBsimUniPortsToProtoUniPorts(onu.UniPorts),
 	}
 	return &res, nil
 }
diff --git a/internal/bbsim/api/uni_handler.go b/internal/bbsim/api/uni_handler.go
new file mode 100644
index 0000000..48eb260
--- /dev/null
+++ b/internal/bbsim/api/uni_handler.go
@@ -0,0 +1,55 @@
+/*
+ * 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 api
+
+import (
+	"context"
+	"github.com/opencord/bbsim/api/bbsim"
+	"github.com/opencord/bbsim/internal/bbsim/devices"
+)
+
+func convertBBSimUniPortToProtoUniPort(u *devices.UniPort) *bbsim.UNI {
+	return &bbsim.UNI{
+		ID:        int32(u.ID),
+		OnuID:     int32(u.Onu.ID),
+		OnuSn:     u.Onu.Sn(),
+		MeID:      uint32(u.MeId.ToUint16()),
+		OperState: u.OperState.Current(),
+	}
+}
+
+func convertBBsimUniPortsToProtoUniPorts(list []*devices.UniPort) []*bbsim.UNI {
+	unis := []*bbsim.UNI{}
+	for _, uni := range list {
+		unis = append(unis, convertBBSimUniPortToProtoUniPort(uni))
+	}
+	return unis
+}
+
+func (s BBSimServer) GetOnuUnis(ctx context.Context, req *bbsim.ONURequest) (*bbsim.UNIs, error) {
+	onu, err := s.GetONU(ctx, req)
+
+	if err != nil {
+		return nil, err
+	}
+
+	unis := bbsim.UNIs{
+		Items: onu.Unis,
+	}
+
+	return &unis, nil
+}
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 1afb624..84706fd 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -52,6 +52,7 @@
 
 const (
 	maxOmciMsgCounter = 10
+	uniPorts          = 4 // TODO this will need to be configurable
 )
 
 const (
@@ -109,9 +110,11 @@
 	// PortNo comes with flows and it's used when sending packetIndications,
 	// There is one PortNo per UNI Port, for now we're only storing the first one
 	// FIXME add support for multiple UNIs (each UNI has a different PortNo)
-	PortNo  uint32
-	Flows   []FlowKey
-	FlowIds []uint64 // keep track of the flows we currently have in the ONU
+	// deprecated
+	PortNo   uint32
+	UniPorts []*UniPort
+	Flows    []FlowKey
+	FlowIds  []uint64 // keep track of the flows we currently have in the ONU
 
 	OperState    *fsm.FSM
 	SerialNumber *openolt.SerialNumber
@@ -131,6 +134,7 @@
 	tid       uint16
 	hpTid     uint16
 	seqNumber uint16
+	MibDb     *omcilib.MibDb
 
 	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
@@ -169,7 +173,9 @@
 	// state as requested by VOLTHA
 	o.OperState = getOperStateFSM(func(e *fsm.Event) {
 		onuLogger.WithFields(log.Fields{
-			"ID": o.ID,
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
 		}).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
 	})
 	o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
@@ -308,6 +314,29 @@
 		},
 	)
 
+	for i := 0; i < uniPorts; i++ {
+		uni, err := NewUniPort(uint32(i), &o)
+		if err != nil {
+			onuLogger.WithFields(log.Fields{
+				"OnuId":  o.ID,
+				"IntfId": o.PonPortID,
+				"OnuSn":  o.Sn(),
+				"Err":    err,
+			}).Fatal("cannot-create-uni-port")
+		}
+		o.UniPorts = append(o.UniPorts, uni)
+	}
+
+	mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts))
+	if err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Fatal("cannot-generate-mibdb-for-onu")
+	}
+	o.MibDb = mibDb
+
 	return &o
 }
 
@@ -748,9 +777,9 @@
 			o.PonPort.removeGemPortBySn(o.SerialNumber)
 		}
 	case omci.MibUploadRequestType:
-		responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID)
+		responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
 	case omci.MibUploadNextRequestType:
-		responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync)
+		responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
 	case omci.GetRequestType:
 		onuDown := o.OperState.Current() == "down"
 		responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId, o.CommittedImageEntityId, onuDown)
diff --git a/internal/bbsim/devices/onu_test_helpers.go b/internal/bbsim/devices/onu_test_helpers.go
index 017cc9c..1d48662 100644
--- a/internal/bbsim/devices/onu_test_helpers.go
+++ b/internal/bbsim/devices/onu_test_helpers.go
@@ -19,6 +19,7 @@
 import (
 	"context"
 	"errors"
+	omcilib "github.com/opencord/bbsim/internal/common/omci"
 	"time"
 
 	"github.com/opencord/bbsim/internal/bbsim/types"
@@ -151,6 +152,15 @@
 	}
 	o.SerialNumber = NewSN(0, ponPortId, o.ID)
 	o.Channel = make(chan types.Message, 10)
+
+	unis := []*UniPort{
+		{ID: 0, Onu: &o, MeId: omcilib.GenerateUniPortEntityId(1)},
+		{ID: 1, Onu: &o, MeId: omcilib.GenerateUniPortEntityId(2)},
+		{ID: 2, Onu: &o, MeId: omcilib.GenerateUniPortEntityId(3)},
+		{ID: 3, Onu: &o, MeId: omcilib.GenerateUniPortEntityId(4)},
+	}
+
+	o.UniPorts = unis
 	return &o
 }
 
diff --git a/internal/bbsim/devices/uni_port.go b/internal/bbsim/devices/uni_port.go
new file mode 100644
index 0000000..78640e3
--- /dev/null
+++ b/internal/bbsim/devices/uni_port.go
@@ -0,0 +1,56 @@
+/*
+ * 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 devices
+
+import (
+	"fmt"
+	"github.com/looplab/fsm"
+	omcilib "github.com/opencord/bbsim/internal/common/omci"
+	log "github.com/sirupsen/logrus"
+)
+
+const maxUniPorts = 4
+
+type UniPort struct {
+	ID        uint32
+	MeId      omcilib.EntityID
+	OperState *fsm.FSM
+	Onu       *Onu
+}
+
+func NewUniPort(ID uint32, onu *Onu) (*UniPort, error) {
+
+	// IDs starts from 0, thus the maximum UNI supported is maxUniPorts - 1
+	if ID > (maxUniPorts - 1) {
+		return nil, fmt.Errorf("%d-is-higher-than-the-maximum-supported-unis-%d", ID, maxUniPorts)
+	}
+
+	uni := UniPort{
+		ID:   ID,
+		Onu:  onu,
+		MeId: omcilib.GenerateUniPortEntityId(ID + 1),
+	}
+
+	uni.OperState = getOperStateFSM(func(e *fsm.Event) {
+		onuLogger.WithFields(log.Fields{
+			"ID":    uni.ID,
+			"OnuSn": onu.Sn(),
+		}).Debugf("changing-uni-operstate-from-%s-to-%s", e.Src, e.Dst)
+	})
+
+	return &uni, nil
+}
diff --git a/internal/bbsimctl/commands/onu.go b/internal/bbsimctl/commands/onu.go
index 33bd5ef..a986205 100644
--- a/internal/bbsimctl/commands/onu.go
+++ b/internal/bbsimctl/commands/onu.go
@@ -34,7 +34,8 @@
 
 const (
 	DEFAULT_ONU_DEVICE_HEADER_FORMAT               = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .ImageSoftwareExpectedSections }}\t{{ .ImageSoftwareReceivedSections }}\t{{ .ActiveImageEntityId }}\t{{ .CommittedImageEntityId }}"
-	DEFAULT_ONU_DEVICE_HEADER_FORMAT_WITH_SERVICES = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .ImageSoftwareExpectedSections }}\t{{ .ImageSoftwareReceivedSections }}\t{{ .ActiveImageEntityId }}\t{{ .CommittedImageEntityId }}\t{{ .Services }}"
+	DEFAULT_ONU_DEVICE_HEADER_FORMAT_WITH_SERVICES = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .ImageSoftwareExpectedSections }}\t{{ .ImageSoftwareReceivedSections }}\t{{ .ActiveImageEntityId }}\t{{ .CommittedImageEntityId }}\t{{ .Unis }}\t{{ .Services }}"
+	DEFAULT_UNI_HEADER_FORMAT                      = "table{{ .OnuSn }}\t{{ .OnuID }}\t{{ .ID }}\t{{ .MeID }}\t{{ .OperState }}"
 )
 
 type OnuSnString string
@@ -64,6 +65,12 @@
 	} `positional-args:"yes" required:"yes"`
 }
 
+type ONUUnis struct {
+	Args struct {
+		OnuSn OnuSnString
+	} `positional-args:"yes" required:"yes"`
+}
+
 type ONUShutDown struct {
 	Args struct {
 		OnuSn OnuSnString
@@ -112,6 +119,7 @@
 	List              ONUList              `command:"list"`
 	Get               ONUGet               `command:"get"`
 	Services          ONUServices          `command:"services"`
+	Unis              ONUUnis              `command:"unis"`
 	ShutDown          ONUShutDown          `command:"shutdown"`
 	PowerOn           ONUPowerOn           `command:"poweron"`
 	RestartEapol      ONUEapolRestart      `command:"auth_restart"`
@@ -214,6 +222,31 @@
 	return nil
 }
 
+func (options *ONUUnis) Execute(args []string) error {
+
+	client, conn := connect()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+	req := pb.ONURequest{
+		SerialNumber: string(options.Args.OnuSn),
+	}
+	res, err := client.GetOnuUnis(ctx, &req)
+
+	if err != nil {
+		log.Fatalf("Cannot not get unis for ONU %s: %v", options.Args.OnuSn, err)
+		return err
+	}
+
+	tableFormat := format.Format(DEFAULT_UNI_HEADER_FORMAT)
+	if err := tableFormat.Execute(os.Stdout, true, res.Items); err != nil {
+		log.Fatalf("Error while formatting Unis table: %s", err)
+	}
+
+	return nil
+}
+
 func (options *ONUShutDown) Execute(args []string) error {
 
 	client, conn := connect()
diff --git a/internal/common/omci/get.go b/internal/common/omci/get.go
index 384fc0b..73e53ac 100644
--- a/internal/common/omci/get.go
+++ b/internal/common/omci/get.go
@@ -119,7 +119,7 @@
 		EntityID: entityID,
 		Attributes: me.AttributeValueMap{
 			"ManagedEntityId": entityID,
-			"EquipmentId":     toOctets("12345123451234512345", 20),
+			"EquipmentId":     ToOctets("12345123451234512345", 20),
 			"OpticalNetworkUnitManagementAndControlChannelOmccVersion": 180,
 			"VendorProductCode":                           0,
 			"SecurityCapability":                          1,
@@ -157,8 +157,8 @@
 		EntityID: entityID,
 		Attributes: me.AttributeValueMap{
 			"ManagedEntityId":         entityID,
-			"VendorId":                toOctets("BBSM", 4),
-			"Version":                 toOctets("v0.0.1", 14),
+			"VendorId":                ToOctets("BBSM", 4),
+			"Version":                 ToOctets("v0.0.1", 14),
 			"SerialNumber":            append(onuSn.VendorId, onuSn.VendorSpecific...),
 			"TrafficManagementOption": 0,
 			"Deprecated":              0,
@@ -166,8 +166,8 @@
 			"AdministrativeState":     0,
 			"OperationalState":        0,
 			"OnuSurvivalTime":         10,
-			"LogicalOnuId":            toOctets("BBSM", 24),
-			"LogicalPassword":         toOctets("BBSM", 12),
+			"LogicalOnuId":            ToOctets("BBSM", 24),
+			"LogicalPassword":         ToOctets("BBSM", 12),
 			"CredentialsStatus":       0,
 			"ExtendedTcLayerOptions":  0,
 		},
@@ -224,12 +224,12 @@
 		},
 		Attributes: me.AttributeValueMap{
 			"ManagedEntityId": 0,
-			"Version":         toOctets("00000000000001", 14),
+			"Version":         ToOctets("00000000000001", 14),
 			"IsCommitted":     committed,
 			"IsActive":        active,
 			"IsValid":         1,
-			"ProductCode":     toOctets("product-code", 25),
-			"ImageHash":       toOctets("broadband-sim", 16),
+			"ProductCode":     ToOctets("product-code", 25),
+			"ImageHash":       ToOctets("broadband-sim", 16),
 		},
 		Result:        me.Success,
 		AttributeMask: attributeMask,
@@ -253,7 +253,7 @@
 		},
 		Attributes: me.AttributeValueMap{
 			"ManagedEntityId": 0,
-			"MacAddress":      toOctets("aabbcc", 6),
+			"MacAddress":      ToOctets("aabbcc", 6),
 		},
 		Result:        me.Success,
 		AttributeMask: attributeMask,
@@ -590,7 +590,7 @@
 	}
 }
 
-func toOctets(str string, size int) []byte {
+func ToOctets(str string, size int) []byte {
 	asciiBytes := []byte(str)
 
 	if len(asciiBytes) < size {
diff --git a/internal/common/omci/mib_test.go b/internal/common/omci/mib_test.go
index a4ffbb7..139e3e1 100644
--- a/internal/common/omci/mib_test.go
+++ b/internal/common/omci/mib_test.go
@@ -71,27 +71,99 @@
 
 func TestCreateMibUploadNextResponse(t *testing.T) {
 
+	const uniPortCount = 4
+
+	var (
+		onuDataEntityId = EntityID{0x00, 0x00}
+		onu2gEntityId   = EntityID{0x00, 0x00}
+		anigEntityId    = EntityID{tcontSlotId, aniGId}
+	)
+
+	// create a fake mibDb, we only need to test that given a CommandSequenceNumber
+	// we return the corresponding entry
+	// the only exception is for OnuData in which we need to replace the MibDataSync attribute with the current value
+	mibDb := MibDb{
+		NumberOfCommands: 4,
+		items:            []MibDbEntry{},
+	}
+
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.OnuDataClassID,
+		onuDataEntityId,
+		me.AttributeValueMap{"MibDataSync": 0},
+	})
+
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"Type":          ethernetUnitType,
+			"NumberOfPorts": uniPortCount,
+			"SerialNumber":  ToOctets("BBSM-Circuit-Pack", 20),
+			"Version":       ToOctets("v0.0.1", 20),
+		},
+	})
+
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.AniGClassID,
+		anigEntityId,
+		me.AttributeValueMap{
+			"Arc":                         0,
+			"ArcInterval":                 0,
+			"Deprecated":                  0,
+			"GemBlockLength":              48,
+			"LowerOpticalThreshold":       255,
+			"LowerTransmitPowerThreshold": 129,
+			"OnuResponseTime":             0,
+			"OpticalSignalLevel":          57428,
+			"PiggybackDbaReporting":       0,
+			"SignalDegradeThreshold":      9,
+			"SignalFailThreshold":         5,
+			"SrIndication":                1,
+			"TotalTcontNumber":            8,
+			"TransmitOpticalLevel":        3171,
+			"UpperOpticalThreshold":       255,
+			"UpperTransmitPowerThreshold": 129,
+		},
+	})
+
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.Onu2GClassID,
+		onu2gEntityId,
+		me.AttributeValueMap{
+			"ConnectivityCapability":                      127,
+			"CurrentConnectivityMode":                     0,
+			"Deprecated":                                  1,
+			"PriorityQueueScaleFactor":                    1,
+			"QualityOfServiceQosConfigurationFlexibility": 63,
+			"Sysuptime":                                   0,
+			"TotalGemPortIdNumber":                        8,
+			"TotalPriorityQueueNumber":                    64,
+			"TotalTrafficSchedulerNumber":                 8,
+		},
+	})
+
 	tests := []struct {
 		name string
 		args mibArgs
 		want mibExpected
 	}{
 		{"mibUploadNext-0", createTestMibUploadNextArgs(t, 1, 0),
-
-			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 1, entityID: 0, entityClass: me.OnuDataClassID, attributes: map[string]interface{}{"MibDataSync": MDS}}},
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 1, entityID: onuDataEntityId.ToUint16(), entityClass: me.OnuDataClassID, attributes: map[string]interface{}{"MibDataSync": MDS}}},
 		{"mibUploadNext-1", createTestMibUploadNextArgs(t, 2, 1),
-			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 2, entityID: 257, 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, entityID: 257, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"PowerShedOverride": uint32(0)}}},
-		{"mibUploadNext-10", createTestMibUploadNextArgs(t, 4, 10),
-			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 4, entityID: 258, entityClass: me.PhysicalPathTerminationPointEthernetUniClassID, attributes: map[string]interface{}{"SensedType": uint8(47)}}},
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 2, entityID: circuitPackEntityID.ToUint16(), entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"Type": uint8(47), "NumberOfPorts": uint8(4)}}},
+		{"mibUploadNext-2", createTestMibUploadNextArgs(t, 3, 2),
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 3, entityID: anigEntityId.ToUint16(), entityClass: me.AniGClassID, attributes: map[string]interface{}{"GemBlockLength": uint16(48)}}},
+		{"mibUploadNext-3", createTestMibUploadNextArgs(t, 4, 3),
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 4, entityID: onuDataEntityId.ToUint16(), entityClass: me.Onu2GClassID, attributes: map[string]interface{}{"TotalPriorityQueueNumber": uint16(64)}}},
 	}
 
 	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, MDS)
+			data, err := CreateMibUploadNextResponse(tt.args.omciPkt, tt.args.omciMsg, MDS, &mibDb)
+			assert.NilError(t, err)
 			omciMsg, omciPkt := omciBytesToMsg(t, data)
 
 			assert.Equal(t, omciMsg.MessageType, tt.want.messageType)
@@ -107,65 +179,15 @@
 			assert.Equal(t, msgObj.ReportedME.GetEntityID(), tt.want.entityID)
 
 			for k, v := range tt.want.attributes {
-				attr, _ := msgObj.ReportedME.GetAttribute(k)
+				attr, err := msgObj.ReportedME.GetAttribute(k)
+				assert.NilError(t, err)
 				assert.Equal(t, attr, v)
 			}
 		})
 	}
-}
 
-type pqueueExpected struct {
-	entityId    uint16
-	relatedPort uint32
-}
-
-func TestGeneratePriorityQueueMe(t *testing.T) {
-
-	tests := []struct {
-		name     string
-		sequence uint16
-		want     pqueueExpected
-	}{
-		{"generate-pq-downstream-1", 26,
-			pqueueExpected{entityId: 1, relatedPort: 16842752}},
-		{"generate-pq-downstream-2", 30,
-			pqueueExpected{entityId: 2, relatedPort: 16842753}},
-		{"generate-pq-downstream-3", 58,
-			pqueueExpected{entityId: 9, relatedPort: 16842760}},
-		{"generate-pq-upstream-1", 28,
-			pqueueExpected{entityId: 32769, relatedPort: 2147549184}},
-		{"generate-pq-upstream-2", 32,
-			pqueueExpected{entityId: 32770, relatedPort: 2147549185}},
-		{"generate-pq-upstream-3", 60,
-			pqueueExpected{entityId: 32777, relatedPort: 2147614720}},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			reportedMe, meErr := GeneratePriorityQueueMe(tt.sequence)
-			if meErr.GetError() != nil {
-				t.Fatal(meErr.Error())
-			}
-
-			assert.Equal(t, reportedMe.GetEntityID(), tt.want.entityId)
-
-			relatedPort, _ := reportedMe.GetAttribute("RelatedPort")
-			assert.Equal(t, relatedPort, tt.want.relatedPort)
-		})
-	}
-
-	// test that the related ports are unique
-	allRelatedPorts := make(map[uint32]struct{})
-	for v := 26; v <= 281; v++ {
-		reportedMe, meErr := GeneratePriorityQueueMe(uint16(v))
-		if meErr.GetError() != nil {
-			t.Fatal(meErr.Error())
-		}
-		relatedPort, _ := reportedMe.GetAttribute("RelatedPort")
-		allRelatedPorts[relatedPort.(uint32)] = struct{}{}
-	}
-
-	// we report 128 queues total, but each of them is comprised of 2 messages
-	// that's why the 256 iterations
-	assert.Equal(t, len(allRelatedPorts), 128)
+	// now try to get a non existing command from the DB anche expect an error
+	args := createTestMibUploadNextArgs(t, 1, 20)
+	_, err := CreateMibUploadNextResponse(args.omciPkt, args.omciMsg, MDS, &mibDb)
+	assert.Error(t, err, "mibdb-does-not-contain-item")
 }
diff --git a/internal/common/omci/mibpackets.go b/internal/common/omci/mibpackets.go
index 6d22200..8db0709 100755
--- a/internal/common/omci/mibpackets.go
+++ b/internal/common/omci/mibpackets.go
@@ -23,25 +23,12 @@
 	"github.com/opencord/omci-lib-go"
 	me "github.com/opencord/omci-lib-go/generated"
 	log "github.com/sirupsen/logrus"
-	"strconv"
 )
 
 var omciLogger = log.WithFields(log.Fields{
 	"module": "OMCI",
 })
 
-// we have a fixed number of 8 T-CONTS
-var reportedTcontsMeId = []uint16{
-	32769,
-	32770,
-	32771,
-	32772,
-	32773,
-	32774,
-	32775,
-	32776,
-}
-
 // 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) {
@@ -112,10 +99,7 @@
 	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)
-
+func CreateMibUploadResponse(tid uint16, numberOfCommands uint16) ([]byte, error) {
 	request := &omci.MibUploadResponse{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass: me.OnuDataClassID,
@@ -168,7 +152,7 @@
 	return msgObj, nil
 }
 
-func CreateMibUploadNextResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, mds uint8) ([]byte, error) {
+func CreateMibUploadNextResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, mds uint8, mibDb *MibDb) ([]byte, error) {
 
 	msgObj, err := ParseMibUploadNextRequest(omciPkt)
 	if err != nil {
@@ -183,256 +167,28 @@
 		"CommandSequenceNumber": msgObj.CommandSequenceNumber,
 	}).Trace("received-omci-mibUploadNext-request")
 
-	var reportedMe *me.ManagedEntity
-	var meErr me.OmciErrors
+	if msgObj.CommandSequenceNumber > mibDb.NumberOfCommands {
+		omciLogger.WithFields(log.Fields{
+			"CommandSequenceNumber": msgObj.CommandSequenceNumber,
+			"MibDbNumberOfCommands": mibDb.NumberOfCommands,
+		}).Error("mibdb-does-not-contain-item")
+		return nil, fmt.Errorf("mibdb-does-not-contain-item")
+	}
+	currentEntry := mibDb.items[int(msgObj.CommandSequenceNumber)]
+	reportedMe, meErr := me.LoadManagedEntityDefinition(currentEntry.classId, me.ParamData{
+		EntityID:   currentEntry.entityId.ToUint16(),
+		Attributes: currentEntry.params,
+	})
 
-	switch msgObj.CommandSequenceNumber {
-	case 0:
-		reportedMe, meErr = me.NewOnuData(me.ParamData{Attributes: me.AttributeValueMap{
-			"MibDataSync": mds,
-		}})
-		if meErr.GetError() != nil {
-			omciLogger.Errorf("NewOnuData %v", meErr.Error())
-		}
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("Error while generating %s: %v", currentEntry.classId.String(), meErr.Error())
+	}
 
-	case 1:
-		reportedMe, meErr = me.NewCircuitPack(me.ParamData{
-			EntityID: 257, // first UNI
-			Attributes: me.AttributeValueMap{
-				"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())
+	if reportedMe.GetClassID() == me.OnuDataClassID {
+		// if this is ONU-Data we need to replace the MDS
+		if err := reportedMe.SetAttribute("MibDataSync", mds); err.GetError() != nil {
+			omciLogger.Errorf("Error while setting mds in %s: %v", currentEntry.classId.String(), meErr.Error())
 		}
-	case 2:
-		reportedMe, meErr = me.NewCircuitPack(me.ParamData{
-			EntityID: 257, // first UNI
-			Attributes: me.AttributeValueMap{
-				"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{
-			EntityID: 257, // first UNI
-			Attributes: me.AttributeValueMap{
-				"EquipmentId":                 toOctets("BBSM-Circuit-Pack", 20),
-				"CardConfiguration":           0,
-				"TotalTContBufferNumber":      8,
-				"TotalPriorityQueueNumber":    8,
-				"TotalTrafficSchedulerNumber": 16,
-			}})
-		if meErr.GetError() != nil {
-			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
-		}
-	case 4:
-		reportedMe, meErr = me.NewCircuitPack(me.ParamData{
-			EntityID: 257, // first UNI
-			Attributes: me.AttributeValueMap{
-				"PowerShedOverride": uint32(0),
-			}})
-		if meErr.GetError() != nil {
-			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
-		}
-	case 5:
-		reportedMe, meErr = me.NewCircuitPack(me.ParamData{
-			EntityID: 257,
-			Attributes: me.AttributeValueMap{
-				"Type":          238,
-				"NumberOfPorts": 4, //number of UNI for this device
-				"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{
-			EntityID: 257, // first UNI
-			Attributes: me.AttributeValueMap{
-				"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{
-			EntityID: 257, // first UNI
-			Attributes: me.AttributeValueMap{
-				"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 8:
-		reportedMe, meErr = me.NewCircuitPack(me.ParamData{
-			EntityID: 257, // first UNI
-			Attributes: me.AttributeValueMap{
-				"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:
-		reportedMe, meErr = me.NewTCont(me.ParamData{
-			// NOTE fetch the correct T-CONT MeID based on the sequence number
-			EntityID: reportedTcontsMeId[msgObj.CommandSequenceNumber-13],
-			Attributes: me.AttributeValueMap{
-				"AllocId": 65535,
-			},
-		})
-		if meErr.GetError() != nil {
-			omciLogger.Errorf("NewTCont %v", meErr.Error())
-		}
-	case 21:
-		reportedMe, meErr = me.NewAniG(me.ParamData{
-			EntityID: 32769, // same as the first T-CONT
-			Attributes: me.AttributeValueMap{
-				"Arc":                         0,
-				"ArcInterval":                 0,
-				"Deprecated":                  0,
-				"GemBlockLength":              48,
-				"LowerOpticalThreshold":       255,
-				"LowerTransmitPowerThreshold": 129,
-				"OnuResponseTime":             0,
-				"OpticalSignalLevel":          57428,
-				"PiggybackDbaReporting":       0,
-				"SignalDegradeThreshold":      9,
-				"SignalFailThreshold":         5,
-				"SrIndication":                1,
-				"TotalTcontNumber":            8,
-				"TransmitOpticalLevel":        3171,
-				"UpperOpticalThreshold":       255,
-				"UpperTransmitPowerThreshold": 129,
-			},
-		})
-		if meErr.GetError() != nil {
-			omciLogger.Errorf("NewAniG %v", meErr.Error())
-		}
-	case 22, 23, 24, 25:
-		// NOTE we're reporting for different UNIs, the IDs are 257, 258, 259, 260
-		meInstance := 235 + msgObj.CommandSequenceNumber
-		reportedMe, meErr = me.NewUniG(me.ParamData{
-			EntityID: meInstance,
-			Attributes: me.AttributeValueMap{
-				"AdministrativeState":         0,
-				"Deprecated":                  0,
-				"ManagementCapability":        0,
-				"NonOmciManagementIdentifier": 0,
-				"RelayAgentOptions":           0,
-			}})
-		if meErr.GetError() != nil {
-			omciLogger.Errorf("NewUniG %v", meErr.Error())
-		}
-	// Prior-Q with mask downstream
-	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,
-		// Prior-Q with attribute list downstream
-		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,
-		// Prior-Q with mask upstream
-		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,
-		// Prior-Q with attribute list upstream
-		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 = GeneratePriorityQueueMe(msgObj.CommandSequenceNumber)
-
-		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{
-			"TContPointer":            32768, // 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{
-			"ConnectivityCapability":                      127,
-			"CurrentConnectivityMode":                     0,
-			"Deprecated":                                  1,
-			"PriorityQueueScaleFactor":                    1,
-			"QualityOfServiceQosConfigurationFlexibility": 63,
-			"Sysuptime":                                   0,
-			"TotalGemPortIdNumber":                        8,
-			"TotalPriorityQueueNumber":                    64,
-			"TotalTrafficSchedulerNumber":                 8,
-		}})
-		if meErr.GetError() != nil {
-			omciLogger.Errorf("NewOnu2G %v", meErr.Error())
-		}
-	default:
-		omciLogger.Warn("unsupported-CommandSequenceNumber-in-mib-upload-next", msgObj.CommandSequenceNumber)
-		return nil, nil
 	}
 
 	response := &omci.MibUploadNextResponse{
@@ -457,83 +213,3 @@
 
 	return pkt, nil
 }
-
-func GeneratePriorityQueueMe(sequence uint16) (*me.ManagedEntity, me.OmciErrors) {
-
-	iteration := sequence - 26
-
-	// we report 256 messages for priority queues,
-	// 128 downstream and 128 upstream
-	// we repeat 64 times the quartet:
-	// - downstream with mask
-	// - downstream with attributes (same MeID as the previous)
-	// - upstream with mask
-	// - upstream with attributes (same MeID as the previous)
-
-	// very ugly way to define whether the priority queue is upstream or downstream
-	// (first 2 blocks are downstream, second two are upstream)
-	// for example sequence 26, 27 are downstream
-	// sequence 28, 29 are upstream
-	isDownstream := ((sequence-26)%4 == 0) || ((sequence-27)%4 == 0)
-	// entityIds are:
-	// - 1 to 64 for downstream (hex 0001 to 0040)
-	// - 32769 to 32832 for upstream (hex 8001 to 8040)
-	var entityId uint16
-	if isDownstream {
-		entityId = (iteration)/4 + 1
-	} else {
-		entityId = (iteration)/4 + 32769
-	}
-
-	var relatedPort uint32
-	if isDownstream {
-		// downstream the related port is:
-		// - Circuit Pack/ UNI port of UNI Port (01 01/04)
-		// - priority 0 to 15 -> iteration%16
-
-		// every 16 iteration (of 4 commands) we move to the next the TCONT MeID
-		uniPort := int(iteration/64) + 1
-		priority := (iteration / 4) % 16
-
-		// concat the uniPort and priority in an hex string
-		// we have a single circuit pack, so we hardcode it
-		v := fmt.Sprintf("010%x000%x", uniPort, priority)
-
-		// convert back to int
-		k, _ := strconv.ParseInt(v, 16, 64)
-		relatedPort = uint32(k)
-	} else {
-		// upstream the related port is:
-		// - Tcont MeID -> reportedTcontsMeId[ceil(iteration/4/8)]
-		// - priority 0 to 7 -> iteration%8
-
-		// every 8 iteration (of 4 commands) we move to the next the TCONT MeID
-		tcontMe := reportedTcontsMeId[int(iteration/32)]
-		priority := (iteration / 4) % 8
-
-		// concat the tcontMe and priority in an hex string
-		v := fmt.Sprintf("%x000%x", tcontMe, priority)
-
-		// convert back to int
-		k, _ := strconv.ParseInt(v, 16, 64)
-		relatedPort = uint32(k)
-	}
-
-	return me.NewPriorityQueue(me.ParamData{
-		EntityID: entityId,
-		Attributes: me.AttributeValueMap{
-			"QueueConfigurationOption":                            0,
-			"MaximumQueueSize":                                    100,
-			"AllocatedQueueSize":                                  100,
-			"DiscardBlockCounterResetInterval":                    0,
-			"ThresholdValueForDiscardedBlocksDueToBufferOverflow": 0,
-			"RelatedPort":                                         relatedPort,
-			"TrafficSchedulerPointer":                             264,
-			"Weight":                                              1,
-			"BackPressureOperation":                               1,
-			"BackPressureTime":                                    0,
-			"BackPressureOccurQueueThreshold":                     0,
-			"BackPressureClearQueueThreshold":                     0,
-		},
-	})
-}
diff --git a/internal/common/omci/onu_mib_db.go b/internal/common/omci/onu_mib_db.go
new file mode 100644
index 0000000..c8696a7
--- /dev/null
+++ b/internal/common/omci/onu_mib_db.go
@@ -0,0 +1,362 @@
+/*
+ * 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"
+	"encoding/hex"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+type MibDbEntry struct {
+	classId  me.ClassID
+	entityId EntityID
+	params   me.AttributeValueMap
+}
+
+type MibDb struct {
+	NumberOfCommands uint16
+	items            []MibDbEntry
+}
+
+type EntityID []byte
+
+func (e EntityID) ToString() string {
+	return hex.EncodeToString(e)
+}
+
+func (e EntityID) ToUint16() uint16 {
+	return binary.BigEndian.Uint16(e)
+}
+
+func (e EntityID) ToUint32() uint32 {
+	return binary.BigEndian.Uint32(e)
+}
+
+const (
+	cardHolderOnuType byte = 0x01 // ONU is a single piece of integrated equipment
+	ethernetUnitType  byte = 0x2f // Ethernet BASE-T
+	xgsPonUnitType    byte = 0xee // XG-PON10G10
+	cardHolderSlotID  byte = 0x01
+	tcontSlotId       byte = 0x80 // why is this not the same as the cardHolderSlotID, it does not point to anything
+	aniGId            byte = 0x01
+
+	upstreamPriorityQueues   = 8  // Number of queues for each T-CONT
+	downstreamPriorityQueues = 16 // Number of queues for each PPTP
+	tconts                   = 8  // NOTE will we ever need to configure this?
+	// trafficSchedulers        = 8  // NOTE will we ever need to configure this?
+)
+
+var (
+	cardHolderEntityID  = EntityID{cardHolderOnuType, cardHolderSlotID}
+	circuitPackEntityID = cardHolderEntityID // is the same as that of the cardholder ME containing this circuit pack instance
+)
+
+func GenerateUniPortEntityId(id uint32) EntityID {
+	return EntityID{cardHolderSlotID, byte(id)}
+}
+
+// creates a MIB database for a ONU
+// CircuitPack and CardHolder are static, everything else can be configured
+func GenerateMibDatabase(uniPortCount int) (*MibDb, error) {
+
+	mibDb := MibDb{
+		items: []MibDbEntry{},
+	}
+
+	// the first element to return is the ONU-Data
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.OnuDataClassID,
+		EntityID{0x00, 0x00},
+		me.AttributeValueMap{"MibDataSync": 0}, // FIXME this needs to be parametrized before sending the response
+	})
+
+	// then we report the CardHolder
+	// NOTE we have not report it till now, so leave it commented out
+	//mibDb.items = append(mibDb.items, MibDbEntry{
+	//	me.CardholderClassID,
+	//	cardHolderEntityID,
+	//	me.AttributeValueMap{
+	//		"ActualPlugInUnitType":   cardHolderOnuType,
+	//		"ExpectedPlugInUnitType": ethernetUnitType,
+	//	},
+	//})
+
+	// circuitPack XG-PON10G10
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"Type":          xgsPonUnitType,
+			"NumberOfPorts": 1, // NOTE is this the ANI port? must be
+			"SerialNumber":  ToOctets("BBSM-Circuit-Pack-ani", 20),
+			"Version":       ToOctets("v0.0.1", 20),
+		},
+	})
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"VendorId":            "ONF",
+			"AdministrativeState": 0,
+			"OperationalState":    0,
+			"BridgedOrIpInd":      0,
+		},
+	})
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"EquipmentId":                 ToOctets("BBSM-Circuit-Pack", 20),
+			"CardConfiguration":           0,
+			"TotalTContBufferNumber":      8,
+			"TotalPriorityQueueNumber":    8,
+			"TotalTrafficSchedulerNumber": 0,
+		},
+	})
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"PowerShedOverride": uint32(0),
+		},
+	})
+
+	// ANI-G
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.AniGClassID,
+		EntityID{tcontSlotId, aniGId},
+		me.AttributeValueMap{
+			"Arc":                         0,
+			"ArcInterval":                 0,
+			"Deprecated":                  0,
+			"GemBlockLength":              48,
+			"LowerOpticalThreshold":       255,
+			"LowerTransmitPowerThreshold": 129,
+			"OnuResponseTime":             0,
+			"OpticalSignalLevel":          57428,
+			"PiggybackDbaReporting":       0,
+			"SignalDegradeThreshold":      9,
+			"SignalFailThreshold":         5,
+			"SrIndication":                1,
+			"TotalTcontNumber":            8,
+			"TransmitOpticalLevel":        3171,
+			"UpperOpticalThreshold":       255,
+			"UpperTransmitPowerThreshold": 129,
+		},
+	})
+
+	// circuitPack Ethernet
+	// NOTE the circuit pack is divided in multiple messages as too big to fit in a single one
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"Type":          ethernetUnitType,
+			"NumberOfPorts": uniPortCount,
+			"SerialNumber":  ToOctets("BBSM-Circuit-Pack", 20),
+			"Version":       ToOctets("v0.0.1", 20),
+		},
+	})
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"VendorId":            "ONF",
+			"AdministrativeState": 0,
+			"OperationalState":    0,
+			"BridgedOrIpInd":      0,
+		},
+	})
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"EquipmentId":                 ToOctets("BBSM-Circuit-Pack", 20),
+			"CardConfiguration":           0,
+			"TotalTContBufferNumber":      8,
+			"TotalPriorityQueueNumber":    8,
+			"TotalTrafficSchedulerNumber": 16,
+		},
+	})
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.CircuitPackClassID,
+		circuitPackEntityID,
+		me.AttributeValueMap{
+			"PowerShedOverride": uint32(0),
+		},
+	})
+
+	// PPTP and UNI-Gs
+	// NOTE this are dependent on the number of UNI this ONU supports
+	// Through an identical ID, the UNI-G ME is implicitly linked to an instance of a PPTP
+	for i := 1; i <= uniPortCount; i++ {
+		uniEntityId := GenerateUniPortEntityId(uint32(i))
+
+		mibDb.items = append(mibDb.items, MibDbEntry{
+			me.PhysicalPathTerminationPointEthernetUniClassID,
+			uniEntityId,
+			me.AttributeValueMap{
+				"ExpectedType":                  0,
+				"SensedType":                    ethernetUnitType,
+				"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,
+			},
+		})
+
+		mibDb.items = append(mibDb.items, MibDbEntry{
+			me.UniGClassID,
+			uniEntityId,
+			me.AttributeValueMap{
+				"AdministrativeState":         0,
+				"Deprecated":                  0,
+				"ManagementCapability":        0,
+				"NonOmciManagementIdentifier": 0,
+				"RelayAgentOptions":           0,
+			},
+		})
+
+		// Downstream Queues (related to PPTP)
+		// 16 priorities queues for each UNI Ports
+		// EntityID = cardHolderSlotID + Uni EntityID (0101)
+		for j := 1; j <= downstreamPriorityQueues; j++ {
+			queueEntityId := EntityID{cardHolderSlotID, byte(j)}
+
+			// we first report the PriorityQueue without any attribute
+			mibDb.items = append(mibDb.items, MibDbEntry{
+				me.PriorityQueueClassID,
+				queueEntityId, //was not reported in the original implementation
+				me.AttributeValueMap{},
+			})
+
+			// then we report it with the required attributes
+			// In the downstream direction, the first byte is the slot number and the second byte is the port number of the queue's destination port.
+			relatedPort := append(uniEntityId, 0x00, byte(j))
+			mibDb.items = append(mibDb.items, MibDbEntry{
+				me.PriorityQueueClassID,
+				queueEntityId, //was not reported in the original implementation
+				me.AttributeValueMap{
+					"QueueConfigurationOption":                            0,
+					"MaximumQueueSize":                                    100,
+					"AllocatedQueueSize":                                  100,
+					"DiscardBlockCounterResetInterval":                    0,
+					"ThresholdValueForDiscardedBlocksDueToBufferOverflow": 0,
+					"RelatedPort":                                         relatedPort.ToUint32(),
+					"TrafficSchedulerPointer":                             0, //it was hardcoded to 0x0108 in the current implementation
+					"Weight":                                              1,
+					"BackPressureOperation":                               1,
+					"BackPressureTime":                                    0,
+					"BackPressureOccurQueueThreshold":                     0,
+					"BackPressureClearQueueThreshold":                     0,
+				},
+			})
+		}
+	}
+
+	// T-CONTS and Traffic Schedulers
+	for i := 1; i <= tconts; i++ {
+		tcontEntityId := EntityID{tcontSlotId, byte(i)}
+
+		mibDb.items = append(mibDb.items, MibDbEntry{
+			me.TContClassID,
+			tcontEntityId,
+			me.AttributeValueMap{
+				"AllocId": 65535,
+			},
+		})
+
+		tsEntityId := EntityID{cardHolderSlotID, byte(i)}
+		mibDb.items = append(mibDb.items, MibDbEntry{
+			me.TrafficSchedulerClassID,
+			tsEntityId, //was not reported in the original implementation
+			me.AttributeValueMap{
+				"TContPointer":            tcontEntityId.ToUint16(), // was hardcoded to a non-existing t-cont
+				"TrafficSchedulerPointer": 0,
+				"Policy":                  02,
+				"PriorityWeight":          0,
+			},
+		})
+
+		for j := 1; j <= upstreamPriorityQueues; j++ {
+			queueEntityId := EntityID{tcontSlotId, byte(j)}
+			// Upstream Queues (related to traffic schedulers)
+			// 8 priorities queues per TCONT
+			// EntityID = tcontSlotId + Uni EntityID (8001)
+
+			// we first report the PriorityQueue without any attribute
+			mibDb.items = append(mibDb.items, MibDbEntry{
+				me.PriorityQueueClassID,
+				queueEntityId, //was not reported in the original implementation
+				me.AttributeValueMap{},
+			})
+
+			// then we report it with the required attributes
+			// In the upstream direction, the first 2 bytes are the ME ID of the associated T- CONT, the first byte of which is a slot number, the second byte a T-CONT number.
+			relatedPort := append(tcontEntityId, 0x00, byte(j))
+			mibDb.items = append(mibDb.items, MibDbEntry{
+				me.PriorityQueueClassID,
+				queueEntityId, //was not reported in the original implementation
+				me.AttributeValueMap{
+					"QueueConfigurationOption":                            0,
+					"MaximumQueueSize":                                    100,
+					"AllocatedQueueSize":                                  100,
+					"DiscardBlockCounterResetInterval":                    0,
+					"ThresholdValueForDiscardedBlocksDueToBufferOverflow": 0,
+					"RelatedPort":                                         relatedPort.ToUint32(),
+					"TrafficSchedulerPointer":                             tsEntityId.ToUint16(), //it was hardcoded to 0x0108 in the current implementation
+					"Weight":                                              1,
+					"BackPressureOperation":                               1,
+					"BackPressureTime":                                    0,
+					"BackPressureOccurQueueThreshold":                     0,
+					"BackPressureClearQueueThreshold":                     0,
+				},
+			})
+		}
+	}
+
+	// ONU-2g
+	mibDb.items = append(mibDb.items, MibDbEntry{
+		me.Onu2GClassID,
+		EntityID{0x00, 0x00},
+		me.AttributeValueMap{
+			"ConnectivityCapability":                      127,
+			"CurrentConnectivityMode":                     0,
+			"Deprecated":                                  1,
+			"PriorityQueueScaleFactor":                    1,
+			"QualityOfServiceQosConfigurationFlexibility": 63,
+			"Sysuptime":                                   0,
+			"TotalGemPortIdNumber":                        8,
+			"TotalPriorityQueueNumber":                    64,
+			"TotalTrafficSchedulerNumber":                 8,
+		},
+	})
+
+	mibDb.NumberOfCommands = uint16(len(mibDb.items))
+
+	return &mibDb, nil
+}
diff --git a/internal/common/omci/onu_mib_db_test.go b/internal/common/omci/onu_mib_db_test.go
new file mode 100644
index 0000000..cea0daf
--- /dev/null
+++ b/internal/common/omci/onu_mib_db_test.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 (
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestEntityID_ToUint16(t *testing.T) {
+	var id EntityID
+	var res uint16
+
+	id = EntityID{0x01, 0x01}
+	res = id.ToUint16()
+	assert.Equal(t, uint16(257), res)
+
+	id = EntityID{0x00, 0x00}
+	res = id.ToUint16()
+	assert.Equal(t, uint16(0), res)
+}
+
+func Test_GenerateMibDatabase(t *testing.T) {
+	const uniPortCount = 4
+	mibDb, err := GenerateMibDatabase(uniPortCount)
+
+	expectedItems := 9                     //ONU-G + 2 Circuit Packs (4 messages each)
+	expectedItems += 2 * uniPortCount      // 1 PPTP and 1 UniG per UNI
+	expectedItems += 1                     // ANI-G
+	expectedItems += 2 * tconts            // T-CONT and traffic schedulers
+	expectedItems += 1                     // ONU-2g
+	expectedItems += 2 * 8 * tconts        // 8 upstream queues for each T-CONT, and we report each queue twice
+	expectedItems += 2 * 16 * uniPortCount // 16 downstream queues for each T-CONT, and we report each queue twice
+
+	assert.NoError(t, err)
+	assert.NotNil(t, mibDb)
+	assert.Equal(t, expectedItems, int(mibDb.NumberOfCommands))
+
+	// now try to serialize all messages to check on the attributes
+	for _, entry := range mibDb.items {
+		reportedMe, meErr := me.LoadManagedEntityDefinition(entry.classId, me.ParamData{
+			EntityID:   entry.entityId.ToUint16(),
+			Attributes: entry.params,
+		})
+		assert.NoError(t, meErr.GetError())
+
+		response := &omci.MibUploadNextResponse{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass: me.OnuDataClassID,
+			},
+			ReportedME: *reportedMe,
+		}
+
+		_, err := Serialize(omci.MibUploadNextResponseType, response, uint16(10))
+		assert.NoError(t, err)
+	}
+
+}