[VOL-3837] Checking that OnuId, AllocId and GemPorts are unique per PON
Validate that received flow carry valid GemPortId and AllocIds

Change-Id: I1b8928c7a9e580c9711f61320595a449df7c30f5
diff --git a/Makefile b/Makefile
index a993f7f..efeea2d 100644
--- a/Makefile
+++ b/Makefile
@@ -80,7 +80,7 @@
 test-unit: clean local-omci-lib-go # @HELP Execute unit tests
 	@echo "Running unit tests..."
 	@mkdir -p ./tests/results
-	@${GO} test -mod=vendor -v -coverprofile ./tests/results/go-test-coverage.out -covermode count ./... 2>&1 | tee ./tests/results/go-test-results.out ;\
+	@${GO} test -mod=vendor -bench=. -v -coverprofile ./tests/results/go-test-coverage.out -covermode count ./... 2>&1 | tee ./tests/results/go-test-results.out ;\
 	RETURN=$$? ;\
 	${GO_JUNIT_REPORT} < ./tests/results/go-test-results.out > ./tests/results/go-test-results.xml ;\
 	${GOCOVER_COBERTURA} < ./tests/results/go-test-coverage.out > ./tests/results/go-test-coverage.xml ;\
diff --git a/api/bbsim/bbsim.pb.go b/api/bbsim/bbsim.pb.go
index fa00279..b5df9e9 100644
--- a/api/bbsim/bbsim.pb.go
+++ b/api/bbsim/bbsim.pb.go
@@ -54,6 +54,34 @@
 	return fileDescriptor_ef7750073d18011b, []int{0}
 }
 
+type OltAllocatedResourceType_Type int32
+
+const (
+	OltAllocatedResourceType_UNKNOWN  OltAllocatedResourceType_Type = 0
+	OltAllocatedResourceType_ALLOC_ID OltAllocatedResourceType_Type = 1
+	OltAllocatedResourceType_GEM_PORT OltAllocatedResourceType_Type = 2
+)
+
+var OltAllocatedResourceType_Type_name = map[int32]string{
+	0: "UNKNOWN",
+	1: "ALLOC_ID",
+	2: "GEM_PORT",
+}
+
+var OltAllocatedResourceType_Type_value = map[string]int32{
+	"UNKNOWN":  0,
+	"ALLOC_ID": 1,
+	"GEM_PORT": 2,
+}
+
+func (x OltAllocatedResourceType_Type) String() string {
+	return proto.EnumName(OltAllocatedResourceType_Type_name, int32(x))
+}
+
+func (OltAllocatedResourceType_Type) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_ef7750073d18011b, []int{4, 0}
+}
+
 // These types correspond to the messages permitted in the oneof
 // in AlarmIndication in the openolt protos
 type AlarmType_Types int32
@@ -131,15 +159,22 @@
 }
 
 func (AlarmType_Types) EnumDescriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{10, 0}
+	return fileDescriptor_ef7750073d18011b, []int{14, 0}
 }
 
 type PONPort struct {
-	ID                   int32    `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
-	OperState            string   `protobuf:"bytes,2,opt,name=OperState,proto3" json:"OperState,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
+	ID            int32  `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
+	OperState     string `protobuf:"bytes,2,opt,name=OperState,proto3" json:"OperState,omitempty"`
+	InternalState string `protobuf:"bytes,3,opt,name=InternalState,proto3" json:"InternalState,omitempty"`
+	PacketCount   uint64 `protobuf:"varint,4,opt,name=PacketCount,proto3" json:"PacketCount,omitempty"`
+	// ONU ID are reported by VOLTHA in the ActivateOnu call
+	AllocatedOnuIds []*PonAllocatedResources `protobuf:"bytes,5,rep,name=AllocatedOnuIds,proto3" json:"AllocatedOnuIds,omitempty"`
+	// these are the stored resource IDs as reported via OMCI
+	AllocatedGemPorts    []*PonAllocatedResources `protobuf:"bytes,6,rep,name=AllocatedGemPorts,proto3" json:"AllocatedGemPorts,omitempty"`
+	AllocatedAllocIds    []*PonAllocatedResources `protobuf:"bytes,7,rep,name=AllocatedAllocIds,proto3" json:"AllocatedAllocIds,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}                 `json:"-"`
+	XXX_unrecognized     []byte                   `json:"-"`
+	XXX_sizecache        int32                    `json:"-"`
 }
 
 func (m *PONPort) Reset()         { *m = PONPort{} }
@@ -181,6 +216,88 @@
 	return ""
 }
 
+func (m *PONPort) GetInternalState() string {
+	if m != nil {
+		return m.InternalState
+	}
+	return ""
+}
+
+func (m *PONPort) GetPacketCount() uint64 {
+	if m != nil {
+		return m.PacketCount
+	}
+	return 0
+}
+
+func (m *PONPort) GetAllocatedOnuIds() []*PonAllocatedResources {
+	if m != nil {
+		return m.AllocatedOnuIds
+	}
+	return nil
+}
+
+func (m *PONPort) GetAllocatedGemPorts() []*PonAllocatedResources {
+	if m != nil {
+		return m.AllocatedGemPorts
+	}
+	return nil
+}
+
+func (m *PONPort) GetAllocatedAllocIds() []*PonAllocatedResources {
+	if m != nil {
+		return m.AllocatedAllocIds
+	}
+	return nil
+}
+
+type PonAllocatedResources struct {
+	SerialNumber         string   `protobuf:"bytes,1,opt,name=SerialNumber,proto3" json:"SerialNumber,omitempty"`
+	Id                   int32    `protobuf:"varint,2,opt,name=Id,proto3" json:"Id,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *PonAllocatedResources) Reset()         { *m = PonAllocatedResources{} }
+func (m *PonAllocatedResources) String() string { return proto.CompactTextString(m) }
+func (*PonAllocatedResources) ProtoMessage()    {}
+func (*PonAllocatedResources) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ef7750073d18011b, []int{1}
+}
+
+func (m *PonAllocatedResources) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_PonAllocatedResources.Unmarshal(m, b)
+}
+func (m *PonAllocatedResources) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_PonAllocatedResources.Marshal(b, m, deterministic)
+}
+func (m *PonAllocatedResources) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_PonAllocatedResources.Merge(m, src)
+}
+func (m *PonAllocatedResources) XXX_Size() int {
+	return xxx_messageInfo_PonAllocatedResources.Size(m)
+}
+func (m *PonAllocatedResources) XXX_DiscardUnknown() {
+	xxx_messageInfo_PonAllocatedResources.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_PonAllocatedResources proto.InternalMessageInfo
+
+func (m *PonAllocatedResources) GetSerialNumber() string {
+	if m != nil {
+		return m.SerialNumber
+	}
+	return ""
+}
+
+func (m *PonAllocatedResources) GetId() int32 {
+	if m != nil {
+		return m.Id
+	}
+	return 0
+}
+
 type NNIPort struct {
 	ID                   int32    `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
 	OperState            string   `protobuf:"bytes,2,opt,name=OperState,proto3" json:"OperState,omitempty"`
@@ -193,7 +310,7 @@
 func (m *NNIPort) String() string { return proto.CompactTextString(m) }
 func (*NNIPort) ProtoMessage()    {}
 func (*NNIPort) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{1}
+	return fileDescriptor_ef7750073d18011b, []int{2}
 }
 
 func (m *NNIPort) XXX_Unmarshal(b []byte) error {
@@ -245,7 +362,7 @@
 func (m *Olt) String() string { return proto.CompactTextString(m) }
 func (*Olt) ProtoMessage()    {}
 func (*Olt) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{2}
+	return fileDescriptor_ef7750073d18011b, []int{3}
 }
 
 func (m *Olt) XXX_Unmarshal(b []byte) error {
@@ -315,6 +432,163 @@
 	return nil
 }
 
+type OltAllocatedResourceType struct {
+	Type                 OltAllocatedResourceType_Type `protobuf:"varint,1,opt,name=type,proto3,enum=bbsim.OltAllocatedResourceType_Type" json:"type,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}                      `json:"-"`
+	XXX_unrecognized     []byte                        `json:"-"`
+	XXX_sizecache        int32                         `json:"-"`
+}
+
+func (m *OltAllocatedResourceType) Reset()         { *m = OltAllocatedResourceType{} }
+func (m *OltAllocatedResourceType) String() string { return proto.CompactTextString(m) }
+func (*OltAllocatedResourceType) ProtoMessage()    {}
+func (*OltAllocatedResourceType) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ef7750073d18011b, []int{4}
+}
+
+func (m *OltAllocatedResourceType) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_OltAllocatedResourceType.Unmarshal(m, b)
+}
+func (m *OltAllocatedResourceType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_OltAllocatedResourceType.Marshal(b, m, deterministic)
+}
+func (m *OltAllocatedResourceType) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_OltAllocatedResourceType.Merge(m, src)
+}
+func (m *OltAllocatedResourceType) XXX_Size() int {
+	return xxx_messageInfo_OltAllocatedResourceType.Size(m)
+}
+func (m *OltAllocatedResourceType) XXX_DiscardUnknown() {
+	xxx_messageInfo_OltAllocatedResourceType.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OltAllocatedResourceType proto.InternalMessageInfo
+
+func (m *OltAllocatedResourceType) GetType() OltAllocatedResourceType_Type {
+	if m != nil {
+		return m.Type
+	}
+	return OltAllocatedResourceType_UNKNOWN
+}
+
+type OltAllocatedResource struct {
+	Type                 string   `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"`
+	PonPortId            uint32   `protobuf:"varint,2,opt,name=PonPortId,proto3" json:"PonPortId,omitempty"`
+	OnuId                uint32   `protobuf:"varint,3,opt,name=OnuId,proto3" json:"OnuId,omitempty"`
+	PortNo               uint32   `protobuf:"varint,4,opt,name=PortNo,proto3" json:"PortNo,omitempty"`
+	ResourceId           int32    `protobuf:"varint,5,opt,name=ResourceId,proto3" json:"ResourceId,omitempty"`
+	FlowId               uint64   `protobuf:"varint,6,opt,name=FlowId,proto3" json:"FlowId,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *OltAllocatedResource) Reset()         { *m = OltAllocatedResource{} }
+func (m *OltAllocatedResource) String() string { return proto.CompactTextString(m) }
+func (*OltAllocatedResource) ProtoMessage()    {}
+func (*OltAllocatedResource) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ef7750073d18011b, []int{5}
+}
+
+func (m *OltAllocatedResource) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_OltAllocatedResource.Unmarshal(m, b)
+}
+func (m *OltAllocatedResource) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_OltAllocatedResource.Marshal(b, m, deterministic)
+}
+func (m *OltAllocatedResource) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_OltAllocatedResource.Merge(m, src)
+}
+func (m *OltAllocatedResource) XXX_Size() int {
+	return xxx_messageInfo_OltAllocatedResource.Size(m)
+}
+func (m *OltAllocatedResource) XXX_DiscardUnknown() {
+	xxx_messageInfo_OltAllocatedResource.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OltAllocatedResource proto.InternalMessageInfo
+
+func (m *OltAllocatedResource) GetType() string {
+	if m != nil {
+		return m.Type
+	}
+	return ""
+}
+
+func (m *OltAllocatedResource) GetPonPortId() uint32 {
+	if m != nil {
+		return m.PonPortId
+	}
+	return 0
+}
+
+func (m *OltAllocatedResource) GetOnuId() uint32 {
+	if m != nil {
+		return m.OnuId
+	}
+	return 0
+}
+
+func (m *OltAllocatedResource) GetPortNo() uint32 {
+	if m != nil {
+		return m.PortNo
+	}
+	return 0
+}
+
+func (m *OltAllocatedResource) GetResourceId() int32 {
+	if m != nil {
+		return m.ResourceId
+	}
+	return 0
+}
+
+func (m *OltAllocatedResource) GetFlowId() uint64 {
+	if m != nil {
+		return m.FlowId
+	}
+	return 0
+}
+
+type OltAllocatedResources struct {
+	Resources            []*OltAllocatedResource `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}                `json:"-"`
+	XXX_unrecognized     []byte                  `json:"-"`
+	XXX_sizecache        int32                   `json:"-"`
+}
+
+func (m *OltAllocatedResources) Reset()         { *m = OltAllocatedResources{} }
+func (m *OltAllocatedResources) String() string { return proto.CompactTextString(m) }
+func (*OltAllocatedResources) ProtoMessage()    {}
+func (*OltAllocatedResources) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ef7750073d18011b, []int{6}
+}
+
+func (m *OltAllocatedResources) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_OltAllocatedResources.Unmarshal(m, b)
+}
+func (m *OltAllocatedResources) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_OltAllocatedResources.Marshal(b, m, deterministic)
+}
+func (m *OltAllocatedResources) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_OltAllocatedResources.Merge(m, src)
+}
+func (m *OltAllocatedResources) XXX_Size() int {
+	return xxx_messageInfo_OltAllocatedResources.Size(m)
+}
+func (m *OltAllocatedResources) XXX_DiscardUnknown() {
+	xxx_messageInfo_OltAllocatedResources.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OltAllocatedResources proto.InternalMessageInfo
+
+func (m *OltAllocatedResources) GetResources() []*OltAllocatedResource {
+	if m != nil {
+		return m.Resources
+	}
+	return nil
+}
+
 type ONU struct {
 	ID                            int32      `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
 	SerialNumber                  string     `protobuf:"bytes,2,opt,name=SerialNumber,proto3" json:"SerialNumber,omitempty"`
@@ -337,7 +611,7 @@
 func (m *ONU) String() string { return proto.CompactTextString(m) }
 func (*ONU) ProtoMessage()    {}
 func (*ONU) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{3}
+	return fileDescriptor_ef7750073d18011b, []int{7}
 }
 
 func (m *ONU) XXX_Unmarshal(b []byte) error {
@@ -465,7 +739,7 @@
 func (m *Service) String() string { return proto.CompactTextString(m) }
 func (*Service) ProtoMessage()    {}
 func (*Service) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{4}
+	return fileDescriptor_ef7750073d18011b, []int{8}
 }
 
 func (m *Service) XXX_Unmarshal(b []byte) error {
@@ -588,7 +862,7 @@
 func (m *ONUTrafficSchedulers) String() string { return proto.CompactTextString(m) }
 func (*ONUTrafficSchedulers) ProtoMessage()    {}
 func (*ONUTrafficSchedulers) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{5}
+	return fileDescriptor_ef7750073d18011b, []int{9}
 }
 
 func (m *ONUTrafficSchedulers) XXX_Unmarshal(b []byte) error {
@@ -627,7 +901,7 @@
 func (m *ONUs) String() string { return proto.CompactTextString(m) }
 func (*ONUs) ProtoMessage()    {}
 func (*ONUs) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{6}
+	return fileDescriptor_ef7750073d18011b, []int{10}
 }
 
 func (m *ONUs) XXX_Unmarshal(b []byte) error {
@@ -666,7 +940,7 @@
 func (m *Services) String() string { return proto.CompactTextString(m) }
 func (*Services) ProtoMessage()    {}
 func (*Services) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{7}
+	return fileDescriptor_ef7750073d18011b, []int{11}
 }
 
 func (m *Services) XXX_Unmarshal(b []byte) error {
@@ -705,7 +979,7 @@
 func (m *ONURequest) String() string { return proto.CompactTextString(m) }
 func (*ONURequest) ProtoMessage()    {}
 func (*ONURequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{8}
+	return fileDescriptor_ef7750073d18011b, []int{12}
 }
 
 func (m *ONURequest) XXX_Unmarshal(b []byte) error {
@@ -744,7 +1018,7 @@
 func (m *PONRequest) String() string { return proto.CompactTextString(m) }
 func (*PONRequest) ProtoMessage()    {}
 func (*PONRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{9}
+	return fileDescriptor_ef7750073d18011b, []int{13}
 }
 
 func (m *PONRequest) XXX_Unmarshal(b []byte) error {
@@ -782,7 +1056,7 @@
 func (m *AlarmType) String() string { return proto.CompactTextString(m) }
 func (*AlarmType) ProtoMessage()    {}
 func (*AlarmType) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{10}
+	return fileDescriptor_ef7750073d18011b, []int{14}
 }
 
 func (m *AlarmType) XXX_Unmarshal(b []byte) error {
@@ -815,7 +1089,7 @@
 func (m *AlarmParameter) String() string { return proto.CompactTextString(m) }
 func (*AlarmParameter) ProtoMessage()    {}
 func (*AlarmParameter) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{11}
+	return fileDescriptor_ef7750073d18011b, []int{15}
 }
 
 func (m *AlarmParameter) XXX_Unmarshal(b []byte) error {
@@ -867,7 +1141,7 @@
 func (m *ONUAlarmRequest) String() string { return proto.CompactTextString(m) }
 func (*ONUAlarmRequest) ProtoMessage()    {}
 func (*ONUAlarmRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{12}
+	return fileDescriptor_ef7750073d18011b, []int{16}
 }
 
 func (m *ONUAlarmRequest) XXX_Unmarshal(b []byte) error {
@@ -930,7 +1204,7 @@
 func (m *OLTAlarmRequest) String() string { return proto.CompactTextString(m) }
 func (*OLTAlarmRequest) ProtoMessage()    {}
 func (*OLTAlarmRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{13}
+	return fileDescriptor_ef7750073d18011b, []int{17}
 }
 
 func (m *OLTAlarmRequest) XXX_Unmarshal(b []byte) error {
@@ -986,7 +1260,7 @@
 func (m *VersionNumber) String() string { return proto.CompactTextString(m) }
 func (*VersionNumber) ProtoMessage()    {}
 func (*VersionNumber) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{14}
+	return fileDescriptor_ef7750073d18011b, []int{18}
 }
 
 func (m *VersionNumber) XXX_Unmarshal(b []byte) error {
@@ -1047,7 +1321,7 @@
 func (m *LogLevel) String() string { return proto.CompactTextString(m) }
 func (*LogLevel) ProtoMessage()    {}
 func (*LogLevel) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{15}
+	return fileDescriptor_ef7750073d18011b, []int{19}
 }
 
 func (m *LogLevel) XXX_Unmarshal(b []byte) error {
@@ -1094,7 +1368,7 @@
 func (m *Response) String() string { return proto.CompactTextString(m) }
 func (*Response) ProtoMessage()    {}
 func (*Response) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{16}
+	return fileDescriptor_ef7750073d18011b, []int{20}
 }
 
 func (m *Response) XXX_Unmarshal(b []byte) error {
@@ -1142,7 +1416,7 @@
 func (m *IgmpRequest) String() string { return proto.CompactTextString(m) }
 func (*IgmpRequest) ProtoMessage()    {}
 func (*IgmpRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{17}
+	return fileDescriptor_ef7750073d18011b, []int{21}
 }
 
 func (m *IgmpRequest) XXX_Unmarshal(b []byte) error {
@@ -1196,7 +1470,7 @@
 func (m *Flows) String() string { return proto.CompactTextString(m) }
 func (*Flows) ProtoMessage()    {}
 func (*Flows) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{18}
+	return fileDescriptor_ef7750073d18011b, []int{22}
 }
 
 func (m *Flows) XXX_Unmarshal(b []byte) error {
@@ -1242,7 +1516,7 @@
 func (m *Timeout) String() string { return proto.CompactTextString(m) }
 func (*Timeout) ProtoMessage()    {}
 func (*Timeout) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{19}
+	return fileDescriptor_ef7750073d18011b, []int{23}
 }
 
 func (m *Timeout) XXX_Unmarshal(b []byte) error {
@@ -1280,7 +1554,7 @@
 func (m *Empty) String() string { return proto.CompactTextString(m) }
 func (*Empty) ProtoMessage()    {}
 func (*Empty) Descriptor() ([]byte, []int) {
-	return fileDescriptor_ef7750073d18011b, []int{20}
+	return fileDescriptor_ef7750073d18011b, []int{24}
 }
 
 func (m *Empty) XXX_Unmarshal(b []byte) error {
@@ -1303,10 +1577,15 @@
 
 func init() {
 	proto.RegisterEnum("bbsim.SubActionTypes", SubActionTypes_name, SubActionTypes_value)
+	proto.RegisterEnum("bbsim.OltAllocatedResourceType_Type", OltAllocatedResourceType_Type_name, OltAllocatedResourceType_Type_value)
 	proto.RegisterEnum("bbsim.AlarmType_Types", AlarmType_Types_name, AlarmType_Types_value)
 	proto.RegisterType((*PONPort)(nil), "bbsim.PONPort")
+	proto.RegisterType((*PonAllocatedResources)(nil), "bbsim.PonAllocatedResources")
 	proto.RegisterType((*NNIPort)(nil), "bbsim.NNIPort")
 	proto.RegisterType((*Olt)(nil), "bbsim.Olt")
+	proto.RegisterType((*OltAllocatedResourceType)(nil), "bbsim.OltAllocatedResourceType")
+	proto.RegisterType((*OltAllocatedResource)(nil), "bbsim.OltAllocatedResource")
+	proto.RegisterType((*OltAllocatedResources)(nil), "bbsim.OltAllocatedResources")
 	proto.RegisterType((*ONU)(nil), "bbsim.ONU")
 	proto.RegisterType((*Service)(nil), "bbsim.Service")
 	proto.RegisterType((*ONUTrafficSchedulers)(nil), "bbsim.ONUTrafficSchedulers")
@@ -1330,112 +1609,128 @@
 func init() { proto.RegisterFile("api/bbsim/bbsim.proto", fileDescriptor_ef7750073d18011b) }
 
 var fileDescriptor_ef7750073d18011b = []byte{
-	// 1668 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xcd, 0x72, 0xdb, 0xc8,
-	0x11, 0xe6, 0x8f, 0xf8, 0xd7, 0x14, 0x29, 0x68, 0x6c, 0x6b, 0x51, 0x5a, 0x6f, 0xcc, 0x42, 0x9c,
-	0x94, 0xec, 0xca, 0xca, 0x6b, 0x3b, 0xd9, 0x78, 0x8f, 0x30, 0x09, 0xd1, 0x88, 0x29, 0x00, 0x35,
-	0x20, 0xe5, 0xf2, 0x09, 0x05, 0x91, 0x23, 0x0a, 0x55, 0x20, 0x40, 0x03, 0x43, 0x29, 0x7a, 0x80,
-	0x3c, 0x43, 0xee, 0x79, 0xa2, 0x3c, 0x41, 0x6e, 0xc9, 0x3d, 0x95, 0x17, 0x48, 0xcd, 0x60, 0x00,
-	0x02, 0x24, 0xb5, 0x91, 0x73, 0xd9, 0x0b, 0x0b, 0xf3, 0x75, 0x7f, 0xdd, 0x3d, 0x3d, 0x3d, 0xdd,
-	0x53, 0x84, 0x27, 0xee, 0xd2, 0x7b, 0x75, 0x79, 0x19, 0x7b, 0x8b, 0xe4, 0xf7, 0x74, 0x19, 0x85,
-	0x34, 0x44, 0x35, 0xbe, 0x38, 0xfe, 0xf6, 0x26, 0xf4, 0xe9, 0xb5, 0xeb, 0x70, 0x30, 0x7e, 0x15,
-	0x2e, 0x49, 0x10, 0xfa, 0x34, 0xd1, 0x39, 0xee, 0x15, 0x85, 0x94, 0x4c, 0xaf, 0xd9, 0xf7, 0x95,
-	0xe7, 0x93, 0x44, 0x43, 0xf9, 0x23, 0x34, 0x2c, 0xd3, 0xb0, 0xc2, 0x88, 0xa2, 0x2e, 0x54, 0xf4,
-	0x81, 0x5c, 0xee, 0x95, 0x4f, 0x6a, 0xb8, 0xa2, 0x0f, 0xd0, 0x53, 0x68, 0x99, 0x4b, 0x12, 0xd9,
-	0xd4, 0xa5, 0x44, 0xae, 0xf4, 0xca, 0x27, 0x2d, 0xbc, 0x06, 0x18, 0xd1, 0x30, 0xf4, 0xff, 0x83,
-	0xf8, 0xcf, 0x32, 0x54, 0x4d, 0x7f, 0x9b, 0xa5, 0xc0, 0xbe, 0x4d, 0x22, 0xcf, 0xf5, 0x8d, 0xd5,
-	0xe2, 0x92, 0x44, 0x82, 0x58, 0xc0, 0x8a, 0x96, 0xab, 0x1b, 0x96, 0xd1, 0x73, 0xe8, 0xe8, 0x01,
-	0x25, 0x51, 0xe0, 0xfa, 0x89, 0xc6, 0x1e, 0xd7, 0x28, 0x82, 0xdc, 0xaf, 0x25, 0x37, 0xb8, 0xa8,
-	0xa2, 0x5b, 0xe8, 0x25, 0x34, 0xc5, 0x46, 0x62, 0xb9, 0xd6, 0xab, 0x9e, 0xb4, 0xdf, 0x74, 0x4f,
-	0x93, 0x3c, 0x0b, 0x18, 0x67, 0x72, 0xa6, 0x2b, 0xb2, 0x15, 0xcb, 0xf5, 0x82, 0xae, 0x80, 0x71,
-	0x26, 0x57, 0xfe, 0x53, 0x85, 0xaa, 0x69, 0x4c, 0x7e, 0xb1, 0x7d, 0x3e, 0x85, 0x96, 0x15, 0x06,
-	0x2c, 0x16, 0x7d, 0x20, 0xd7, 0xb8, 0xfb, 0x35, 0xc0, 0xa4, 0x1f, 0x6e, 0xd5, 0xd9, 0x2c, 0x22,
-	0x71, 0x2c, 0x37, 0x13, 0x0f, 0x19, 0x80, 0x8e, 0xa0, 0xce, 0xf4, 0x8c, 0x50, 0x6e, 0x71, 0xa2,
-	0x58, 0xb1, 0xfd, 0xc7, 0x24, 0xba, 0xf1, 0xa6, 0x24, 0x96, 0xa1, 0xb0, 0x7f, 0x3b, 0x81, 0x71,
-	0x26, 0x47, 0x03, 0xf8, 0x4e, 0x5f, 0xb8, 0x73, 0x62, 0x87, 0x57, 0xf4, 0xd6, 0x8d, 0x88, 0xf6,
-	0xe7, 0x25, 0x99, 0x52, 0x32, 0xb3, 0xc9, 0x94, 0x7a, 0x61, 0x10, 0xcb, 0x6d, 0x6e, 0xfa, 0xe7,
-	0x95, 0xb6, 0xac, 0x60, 0x32, 0x25, 0xde, 0x4d, 0xce, 0xca, 0xfe, 0x0e, 0x2b, 0x9b, 0x4a, 0xe8,
-	0x07, 0x78, 0xa4, 0x4e, 0xa9, 0x77, 0x43, 0xb8, 0x9a, 0x16, 0x50, 0x8f, 0xde, 0xe9, 0x33, 0xb9,
-	0xc3, 0xb9, 0xbb, 0x44, 0xe8, 0x47, 0x38, 0xea, 0x87, 0x8b, 0x85, 0x47, 0x29, 0x99, 0x15, 0x49,
-	0x5d, 0x4e, 0xba, 0x47, 0xaa, 0xfc, 0xbb, 0x02, 0x0d, 0x91, 0x0b, 0x84, 0x60, 0xcf, 0x70, 0x17,
-	0x84, 0x9f, 0x7d, 0x0b, 0xf3, 0xef, 0x62, 0xde, 0x2b, 0x9b, 0x79, 0x7f, 0x0c, 0x35, 0x33, 0x58,
-	0xd9, 0x81, 0x38, 0xf3, 0x64, 0xc1, 0xec, 0xd8, 0x63, 0x77, 0xce, 0x8f, 0xb9, 0x86, 0xf9, 0x37,
-	0xc3, 0xfa, 0x0c, 0x4b, 0x0e, 0x96, 0x7f, 0xa3, 0x5f, 0x01, 0x18, 0x84, 0xcc, 0x62, 0xcd, 0x5d,
-	0x86, 0xbe, 0x5c, 0xef, 0x95, 0x4f, 0x9a, 0x38, 0x87, 0x30, 0xdf, 0x7c, 0x35, 0xb8, 0x9e, 0x2e,
-	0xf9, 0x05, 0x68, 0xe2, 0x35, 0x90, 0x49, 0xf5, 0xf9, 0x62, 0xc9, 0x2b, 0x22, 0x95, 0x32, 0x00,
-	0xc9, 0xd0, 0x18, 0x92, 0x05, 0x2b, 0x03, 0x51, 0x12, 0xe9, 0x92, 0x79, 0xe5, 0xe6, 0x93, 0x52,
-	0x04, 0x1e, 0x78, 0x0e, 0x61, 0x76, 0x99, 0xfd, 0x44, 0xdc, 0x4e, 0x76, 0x9c, 0x01, 0xdb, 0xb5,
-	0xbc, 0x7f, 0x4f, 0x2d, 0xeb, 0xc3, 0x73, 0x2b, 0xd1, 0xe8, 0x24, 0x36, 0x32, 0x40, 0x71, 0xe1,
-	0xb1, 0x69, 0x4c, 0xc6, 0x91, 0x7b, 0x75, 0xe5, 0x4d, 0xed, 0xe9, 0x35, 0x99, 0xad, 0x7c, 0x12,
-	0xc5, 0x48, 0x87, 0x03, 0xca, 0xc0, 0x35, 0xc4, 0x8f, 0xa2, 0xfd, 0xe6, 0xd9, 0x69, 0xa1, 0x13,
-	0x6e, 0x31, 0xf1, 0x26, 0x4f, 0x39, 0x81, 0x3d, 0xd3, 0x98, 0xc4, 0xa8, 0x07, 0x35, 0x8f, 0x92,
-	0x05, 0x33, 0xc4, 0xaa, 0x1f, 0x44, 0xf5, 0x9b, 0xc6, 0x04, 0x27, 0x02, 0xe5, 0x07, 0x68, 0xda,
-	0xe9, 0x15, 0x78, 0x5e, 0xd4, 0xde, 0xbc, 0x2b, 0x19, 0x03, 0x18, 0x9f, 0x7c, 0x59, 0x91, 0x98,
-	0x6e, 0xb5, 0x87, 0xf2, 0x76, 0x7b, 0x50, 0x5e, 0x02, 0x58, 0xa6, 0x91, 0x32, 0x72, 0x17, 0x7d,
-	0xc6, 0xd5, 0x3b, 0xeb, 0x8b, 0x3e, 0x53, 0xfe, 0x51, 0x85, 0x96, 0xea, 0xbb, 0xd1, 0x62, 0x7c,
-	0xb7, 0x24, 0xca, 0xdf, 0xab, 0x50, 0x63, 0x1f, 0x31, 0x6a, 0x40, 0x75, 0x64, 0xda, 0x52, 0x09,
-	0x75, 0x01, 0x06, 0x9f, 0x75, 0x63, 0xe8, 0x0c, 0x55, 0xdb, 0x92, 0xca, 0xa8, 0x03, 0x2d, 0xd3,
-	0x98, 0x38, 0xea, 0x48, 0xc5, 0xe7, 0x52, 0x05, 0x7d, 0x03, 0x8f, 0xd8, 0xd2, 0x1e, 0xab, 0x78,
-	0x3c, 0xb1, 0x9c, 0x33, 0x55, 0x1f, 0x4d, 0xb0, 0x26, 0x55, 0xd1, 0x11, 0x20, 0x2e, 0xd0, 0x87,
-	0x86, 0x3a, 0x72, 0x06, 0xda, 0x10, 0xab, 0x03, 0x4d, 0xda, 0x4b, 0x09, 0x03, 0xac, 0x9f, 0x8d,
-	0x1d, 0xf3, 0xcc, 0xf9, 0xa4, 0x1b, 0x03, 0xf3, 0x93, 0x54, 0x43, 0x4f, 0x41, 0x66, 0x82, 0x91,
-	0x69, 0xdb, 0x0c, 0x37, 0xcf, 0xfb, 0xba, 0xd3, 0xff, 0xa0, 0x1a, 0x86, 0x36, 0x92, 0xea, 0x99,
-	0x1f, 0x6e, 0xce, 0xce, 0xfc, 0x34, 0xd0, 0x0b, 0xf8, 0x0d, 0x13, 0x8c, 0xb1, 0x6a, 0xd8, 0xe7,
-	0xba, 0x6d, 0xeb, 0xa6, 0xe1, 0xe8, 0xc6, 0x58, 0xc3, 0x67, 0x1a, 0xd6, 0x8c, 0xbe, 0xe6, 0x7c,
-	0x52, 0xb1, 0xa1, 0x1b, 0x43, 0xa9, 0x89, 0x8e, 0xe1, 0x88, 0x87, 0xde, 0x1f, 0xeb, 0x17, 0xea,
-	0x98, 0x29, 0xa6, 0x66, 0x5a, 0x48, 0xe6, 0x45, 0xe2, 0x58, 0xd8, 0xec, 0x6b, 0xb6, 0xcd, 0xf6,
-	0xab, 0x61, 0x6c, 0x62, 0x09, 0x50, 0x0f, 0x9e, 0xe6, 0xe3, 0xfa, 0xa8, 0x7d, 0x76, 0xec, 0xcf,
-	0x46, 0x3f, 0xe3, 0xb6, 0xd1, 0x13, 0x38, 0x64, 0x1a, 0xfa, 0x78, 0xe2, 0x58, 0xa6, 0xc1, 0x72,
-	0x31, 0xb6, 0xa5, 0x7d, 0x74, 0x08, 0x9d, 0x2c, 0x53, 0x8c, 0x2e, 0x75, 0x36, 0xa1, 0xf7, 0x52,
-	0x37, 0xdd, 0x58, 0x0a, 0x59, 0x7d, 0x87, 0xed, 0x42, 0x3a, 0x48, 0xf3, 0x51, 0x10, 0xf4, 0x45,
-	0x54, 0x12, 0x42, 0xd0, 0xcd, 0x4b, 0xcf, 0x74, 0xe9, 0x10, 0x3d, 0x82, 0x83, 0x3c, 0xa6, 0x9e,
-	0xeb, 0x12, 0x52, 0xde, 0x41, 0x97, 0x9f, 0xaf, 0xe5, 0x46, 0xee, 0x82, 0x50, 0x12, 0x21, 0x09,
-	0xaa, 0x1f, 0xc9, 0x9d, 0xa8, 0x1c, 0xf6, 0xc9, 0xfa, 0xca, 0x85, 0xeb, 0xaf, 0xd2, 0x69, 0x9c,
-	0x2c, 0x94, 0xbf, 0x95, 0xb9, 0x3d, 0xce, 0xce, 0x15, 0x53, 0x56, 0x2d, 0xc2, 0xc2, 0x1a, 0x78,
-	0xd0, 0xec, 0x3a, 0x82, 0x3a, 0xbb, 0x96, 0xab, 0x58, 0x34, 0x31, 0xb1, 0x42, 0x7f, 0x00, 0xc8,
-	0x42, 0x8c, 0xe5, 0x3d, 0x7e, 0x23, 0x9e, 0x88, 0x1b, 0x51, 0xdc, 0x00, 0xce, 0x29, 0x2a, 0x5f,
-	0xe0, 0xc0, 0x1c, 0x8d, 0x0b, 0x31, 0xf6, 0xa0, 0xcd, 0xdb, 0xc3, 0x95, 0x3b, 0x25, 0x62, 0xb4,
-	0x76, 0x70, 0x1e, 0xca, 0xba, 0x0a, 0x5b, 0xf2, 0x9d, 0x54, 0x72, 0x5d, 0x25, 0x05, 0xef, 0x8b,
-	0x54, 0xf9, 0x4b, 0x19, 0x3a, 0x17, 0x24, 0x8a, 0xbd, 0x30, 0x10, 0x7b, 0x92, 0xa1, 0x71, 0x93,
-	0x00, 0x22, 0x27, 0xe9, 0x92, 0xe5, 0xeb, 0x72, 0xe5, 0xf9, 0xb3, 0xb1, 0xb7, 0xc8, 0xde, 0x3a,
-	0x19, 0xc0, 0x7a, 0xe3, 0x94, 0xcf, 0x89, 0x0f, 0x6e, 0x7c, 0x2d, 0xbc, 0xe4, 0x10, 0xc6, 0x9e,
-	0x7b, 0x54, 0x04, 0x91, 0x4c, 0xf1, 0x35, 0xa0, 0xbc, 0x83, 0xe6, 0x28, 0x9c, 0x8f, 0xc8, 0x0d,
-	0xf1, 0xd9, 0x09, 0xfa, 0xec, 0x43, 0xf8, 0x4f, 0x16, 0x6c, 0x07, 0x53, 0xd7, 0xf7, 0xc5, 0x49,
-	0x34, 0xb1, 0x58, 0x29, 0x1a, 0x34, 0x31, 0x89, 0x97, 0x61, 0x10, 0x13, 0xf4, 0x0c, 0xda, 0x31,
-	0xb7, 0xe7, 0x4c, 0xc3, 0x19, 0x11, 0x0f, 0x11, 0x48, 0xa0, 0x7e, 0x38, 0x23, 0x6c, 0x73, 0x0b,
-	0x12, 0xc7, 0xee, 0x3c, 0xdd, 0x40, 0xba, 0x54, 0xfe, 0x5a, 0x86, 0x36, 0xeb, 0xfe, 0x69, 0xe2,
-	0x5f, 0x40, 0xdd, 0x0c, 0x56, 0x98, 0x7c, 0x11, 0x7d, 0xf4, 0x30, 0xd7, 0xfe, 0x12, 0x15, 0x2c,
-	0x14, 0xd0, 0x4f, 0xb0, 0x6f, 0xaf, 0x2e, 0x55, 0x3e, 0x7f, 0x2f, 0x5c, 0x9f, 0x5b, 0xee, 0x66,
-	0xe7, 0x9d, 0x89, 0x78, 0x2f, 0xc2, 0x05, 0x55, 0x56, 0x64, 0xc3, 0x28, 0x5c, 0x2d, 0xd3, 0x29,
-	0x99, 0xa4, 0xad, 0x80, 0x29, 0x1f, 0xa1, 0x76, 0xe6, 0x87, 0xb7, 0x31, 0xfa, 0x0e, 0xe0, 0xca,
-	0x0f, 0x6f, 0x9d, 0x69, 0xb8, 0x0a, 0x68, 0xda, 0xfd, 0x18, 0xd2, 0x67, 0x00, 0xfa, 0x35, 0xd4,
-	0xd8, 0x82, 0x8d, 0x5a, 0x56, 0x6f, 0x9d, 0xd3, 0xf4, 0x7d, 0xcc, 0xd8, 0x38, 0x91, 0x29, 0xcf,
-	0xa0, 0xc1, 0x4e, 0x2b, 0x5c, 0x51, 0x96, 0xe6, 0x19, 0xf1, 0xdd, 0x3b, 0x61, 0x29, 0x59, 0x28,
-	0x0d, 0xa8, 0x69, 0x8b, 0x25, 0xbd, 0x7b, 0xf9, 0x1a, 0xba, 0xc5, 0xd0, 0x51, 0x13, 0xf6, 0xfe,
-	0x64, 0xea, 0x86, 0x54, 0x42, 0x2d, 0xa8, 0x8d, 0x34, 0xf5, 0x42, 0x93, 0xca, 0x08, 0xa0, 0xce,
-	0xc0, 0x8b, 0xb7, 0x52, 0xe5, 0xcd, 0xbf, 0x00, 0x6a, 0xef, 0xdf, 0xdb, 0xde, 0x02, 0xbd, 0x82,
-	0x86, 0xa8, 0x2a, 0xb4, 0x2f, 0xf2, 0xc0, 0xad, 0x1e, 0x3f, 0x16, 0xab, 0x42, 0xcd, 0x29, 0x25,
-	0xf4, 0x1a, 0xda, 0x36, 0xa1, 0x59, 0x09, 0x1c, 0x08, 0xb5, 0x14, 0x38, 0xde, 0x04, 0x94, 0x12,
-	0x7a, 0x0e, 0xf5, 0x21, 0xa1, 0xec, 0x79, 0x5d, 0x74, 0x91, 0x0d, 0x2a, 0x9f, 0x2a, 0x25, 0xf4,
-	0x3d, 0x80, 0x15, 0xde, 0x92, 0x28, 0x0c, 0xb6, 0x35, 0x53, 0xa3, 0x69, 0xfd, 0x28, 0x25, 0x74,
-	0x0a, 0x6d, 0xfb, 0x7a, 0x45, 0x67, 0xe1, 0xed, 0xc3, 0xf4, 0x7f, 0x07, 0x2d, 0x4c, 0x2e, 0xc3,
-	0x90, 0x3e, 0x48, 0x9b, 0xe5, 0x94, 0x86, 0xcb, 0x39, 0xb6, 0xfa, 0x6c, 0x30, 0x92, 0xe8, 0x7f,
-	0x53, 0xde, 0xc0, 0x81, 0x4d, 0xdd, 0x88, 0x7e, 0x0d, 0xe7, 0x47, 0x38, 0xc4, 0x24, 0xde, 0x60,
-	0xa5, 0x13, 0x59, 0x1c, 0xff, 0x2e, 0xde, 0x8b, 0x24, 0xa3, 0xc6, 0x04, 0x6d, 0x57, 0xfb, 0x71,
-	0x6e, 0xfe, 0x2b, 0x25, 0xf4, 0x5b, 0xf6, 0x46, 0xa2, 0xfc, 0x9d, 0x50, 0x0c, 0xa7, 0xbd, 0x56,
-	0x8b, 0x93, 0x7c, 0x0e, 0x09, 0xcd, 0x5e, 0x09, 0xbb, 0x43, 0x4f, 0xc5, 0x3c, 0xf4, 0x2e, 0xb3,
-	0x1b, 0xac, 0x32, 0xca, 0x8e, 0x50, 0x76, 0xf0, 0xde, 0xe6, 0xce, 0x6d, 0x77, 0xfc, 0xf7, 0xe4,
-	0x56, 0x90, 0x54, 0xdf, 0xdf, 0xb1, 0x99, 0x1d, 0x9c, 0x9f, 0xe0, 0x30, 0xe7, 0x28, 0x36, 0x03,
-	0xcb, 0x34, 0x32, 0x77, 0xeb, 0x97, 0xca, 0x6e, 0x77, 0x59, 0x29, 0x3e, 0x38, 0xc4, 0xd7, 0xd0,
-	0x15, 0x9c, 0x07, 0x47, 0xf8, 0x0e, 0xa4, 0xb5, 0x9b, 0xaf, 0x0a, 0xf0, 0xf7, 0xb0, 0x2f, 0xea,
-	0x26, 0x79, 0x44, 0x3f, 0x2c, 0xc4, 0xb7, 0xd0, 0x16, 0x2c, 0xfe, 0xb6, 0x7e, 0x18, 0xe9, 0x3d,
-	0x3c, 0xb1, 0xf9, 0x39, 0xf3, 0x69, 0xa7, 0x07, 0x33, 0x6f, 0xea, 0xb2, 0x4e, 0x83, 0x8e, 0xd6,
-	0xf4, 0xfc, 0x20, 0xfc, 0x19, 0x1b, 0x3e, 0xbd, 0xd7, 0x46, 0x71, 0x98, 0xee, 0xb2, 0xf1, 0x3d,
-	0x34, 0x87, 0x84, 0x26, 0xfd, 0x75, 0x47, 0xe4, 0x69, 0xb2, 0xb9, 0x02, 0xcf, 0xed, 0x41, 0xff,
-	0xda, 0x0d, 0xe6, 0x84, 0x8d, 0x8a, 0xe4, 0xbd, 0x8e, 0x84, 0x4a, 0x6e, 0x78, 0xec, 0x72, 0xf4,
-	0x11, 0xbe, 0x49, 0x0a, 0x7b, 0xfb, 0xed, 0xbe, 0xc3, 0xef, 0xb7, 0x6b, 0x68, 0x4b, 0x5f, 0x29,
-	0x5d, 0xd6, 0xf9, 0x1f, 0x1a, 0x6f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x62, 0x43, 0x1a, 0x58,
-	0x2f, 0x11, 0x00, 0x00,
+	// 1930 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x41, 0x72, 0xdb, 0xca,
+	0x11, 0x15, 0x49, 0x51, 0x24, 0x9b, 0x22, 0x05, 0x8d, 0x2d, 0x7d, 0x94, 0xac, 0x1f, 0xab, 0x10,
+	0x27, 0x65, 0xbb, 0xf2, 0xe5, 0x6f, 0x39, 0xf9, 0xb1, 0x97, 0x30, 0x09, 0xd1, 0xf8, 0xa2, 0x00,
+	0xd4, 0x80, 0x94, 0xcb, 0x95, 0x05, 0x0b, 0x22, 0x46, 0x12, 0x2b, 0x20, 0x40, 0x03, 0x43, 0x29,
+	0x3a, 0x40, 0xce, 0x90, 0x7d, 0x0e, 0x90, 0x4b, 0xe4, 0x02, 0x39, 0x41, 0xb2, 0xca, 0x01, 0x52,
+	0xb9, 0x40, 0x6a, 0x06, 0x03, 0x10, 0x20, 0x21, 0x9b, 0x5e, 0x65, 0xc3, 0x42, 0xbf, 0xee, 0xd7,
+	0xd3, 0xd3, 0xdd, 0xe8, 0x19, 0x10, 0xf6, 0x9c, 0xd9, 0xe4, 0xd5, 0xe5, 0x65, 0x34, 0x99, 0xc6,
+	0xbf, 0xc7, 0xb3, 0x30, 0xa0, 0x01, 0xaa, 0x72, 0xe1, 0xe0, 0xc9, 0x6d, 0xe0, 0xd1, 0x1b, 0x67,
+	0xc4, 0xc1, 0xe8, 0x55, 0x30, 0x23, 0x7e, 0xe0, 0xd1, 0xd8, 0xe6, 0xe0, 0x28, 0xaf, 0xa4, 0x64,
+	0x7c, 0xc3, 0x9e, 0xaf, 0x26, 0x1e, 0x89, 0x2d, 0x94, 0x7f, 0x95, 0xa1, 0x66, 0x99, 0x86, 0x15,
+	0x84, 0x14, 0xb5, 0xa1, 0xac, 0x77, 0xe5, 0xd2, 0x51, 0xe9, 0x79, 0x15, 0x97, 0xf5, 0x2e, 0x3a,
+	0x84, 0x86, 0x39, 0x23, 0xa1, 0x4d, 0x1d, 0x4a, 0xe4, 0xf2, 0x51, 0xe9, 0x79, 0x03, 0x2f, 0x00,
+	0xf4, 0x0c, 0x5a, 0xba, 0x4f, 0x49, 0xe8, 0x3b, 0x5e, 0x6c, 0x51, 0xe1, 0x16, 0x79, 0x10, 0x1d,
+	0x41, 0xd3, 0x72, 0xc6, 0x7f, 0x24, 0xb4, 0x13, 0xcc, 0x7d, 0x2a, 0x6f, 0x1e, 0x95, 0x9e, 0x6f,
+	0xe2, 0x2c, 0x84, 0x4e, 0x61, 0x47, 0xf5, 0xbc, 0x60, 0xec, 0x50, 0xe2, 0x9a, 0xfe, 0x5c, 0x77,
+	0x23, 0xb9, 0x7a, 0x54, 0x79, 0xde, 0x3c, 0x39, 0x3c, 0x8e, 0xb7, 0x6b, 0x05, 0x7e, 0x6a, 0x80,
+	0x49, 0x14, 0xcc, 0xc3, 0x31, 0x89, 0xf0, 0x32, 0x09, 0xfd, 0x0c, 0xbb, 0x29, 0xd4, 0x23, 0x53,
+	0xb6, 0xa3, 0x48, 0xde, 0x5a, 0xc3, 0xd3, 0x2a, 0x2d, 0xe7, 0x8b, 0x3f, 0xb0, 0xa8, 0x6a, 0xdf,
+	0xe4, 0x2b, 0xa1, 0x29, 0x67, 0xb0, 0x57, 0x68, 0x8b, 0x14, 0xd8, 0xb6, 0x49, 0x38, 0x71, 0x3c,
+	0x63, 0x3e, 0xbd, 0x24, 0x21, 0x4f, 0x7c, 0x03, 0xe7, 0x30, 0x5e, 0x12, 0x97, 0xe7, 0x9e, 0x95,
+	0xc4, 0x55, 0x7e, 0x0f, 0x35, 0xc3, 0xd0, 0xbf, 0xbd, 0x5a, 0xca, 0xbf, 0x4b, 0x50, 0x31, 0xbd,
+	0x55, 0xd6, 0x72, 0x10, 0xe5, 0x82, 0x20, 0x72, 0x9e, 0x2b, 0x5f, 0xed, 0x83, 0xcd, 0xa2, 0x3e,
+	0x60, 0xeb, 0x5a, 0x72, 0x8d, 0xab, 0xca, 0xba, 0x85, 0x5e, 0x42, 0x5d, 0x6c, 0x24, 0x29, 0x77,
+	0x5b, 0x24, 0x56, 0xc0, 0x38, 0xd5, 0x33, 0x5b, 0xd1, 0xa2, 0x49, 0x41, 0x13, 0x5b, 0x01, 0xe3,
+	0x54, 0xaf, 0xfc, 0xb9, 0x04, 0xb2, 0xe9, 0xd1, 0x95, 0x74, 0x0f, 0xee, 0x67, 0x04, 0xbd, 0x85,
+	0x4d, 0x7a, 0x3f, 0x23, 0x7c, 0xfb, 0xed, 0x93, 0x67, 0xc2, 0xc9, 0x43, 0xe6, 0xc7, 0xec, 0x07,
+	0x73, 0x86, 0xf2, 0x0a, 0x36, 0xb9, 0x87, 0x26, 0xd4, 0x86, 0xc6, 0x99, 0x61, 0x7e, 0x34, 0xa4,
+	0x0d, 0xb4, 0x0d, 0x75, 0xb5, 0xdf, 0x37, 0x3b, 0x23, 0xbd, 0x2b, 0x95, 0x98, 0xd4, 0xd3, 0xce,
+	0x47, 0x96, 0x89, 0x07, 0x52, 0x59, 0xf9, 0x5b, 0x09, 0x1e, 0x17, 0x39, 0x46, 0x28, 0xf6, 0x24,
+	0xaa, 0x1d, 0x7b, 0x3d, 0x84, 0x86, 0x15, 0xf8, 0x6c, 0x03, 0xa2, 0xd8, 0x2d, 0xbc, 0x00, 0xd0,
+	0x63, 0xa8, 0xf2, 0x16, 0xe7, 0xa9, 0x6f, 0xe1, 0x58, 0x40, 0xfb, 0xb0, 0xc5, 0xf4, 0x46, 0xc0,
+	0xf3, 0xdd, 0xc2, 0x42, 0x42, 0xbf, 0x00, 0x48, 0xd6, 0xd2, 0x5d, 0xb9, 0xca, 0x0b, 0x9d, 0x41,
+	0x18, 0xef, 0xd4, 0x0b, 0xee, 0x74, 0x57, 0xde, 0xe2, 0xef, 0xa2, 0x90, 0x14, 0x0c, 0x7b, 0x45,
+	0xf1, 0x46, 0xe8, 0x1d, 0x34, 0xc2, 0x44, 0x90, 0x4b, 0x3c, 0xfd, 0x4f, 0xbe, 0x90, 0x39, 0xbc,
+	0xb0, 0x56, 0xfe, 0x5b, 0x81, 0x8a, 0x69, 0x0c, 0xff, 0x6f, 0x4d, 0x97, 0xc9, 0x6b, 0x57, 0xa4,
+	0x62, 0x01, 0x30, 0xed, 0x87, 0x3b, 0xd5, 0x75, 0x43, 0x12, 0x45, 0x72, 0x3d, 0x5e, 0x21, 0x05,
+	0x32, 0xf9, 0x6d, 0x70, 0x62, 0x92, 0xdf, 0x97, 0x50, 0x8f, 0x48, 0x78, 0x3b, 0x61, 0xd9, 0x80,
+	0x5c, 0x33, 0xda, 0x31, 0x8c, 0x53, 0x3d, 0xea, 0xc2, 0xf7, 0xfa, 0xd4, 0xb9, 0x26, 0x76, 0x70,
+	0x45, 0xef, 0x9c, 0x90, 0x68, 0x7f, 0x9a, 0x91, 0x31, 0x25, 0xae, 0x4d, 0xc6, 0x74, 0x12, 0xf8,
+	0x91, 0xdc, 0xe4, 0xae, 0xbf, 0x6c, 0xb4, 0xe2, 0x05, 0x93, 0x31, 0x99, 0xdc, 0x66, 0xbc, 0x6c,
+	0x17, 0x78, 0x59, 0x36, 0x42, 0x3f, 0xc2, 0x23, 0x75, 0x4c, 0x27, 0xb7, 0x84, 0x9b, 0x69, 0x3e,
+	0x9d, 0xd0, 0x7b, 0xdd, 0x95, 0x5b, 0x9c, 0x5b, 0xa4, 0x42, 0x3f, 0xc1, 0x7e, 0x27, 0x98, 0x4e,
+	0x27, 0x94, 0x12, 0x37, 0x4f, 0x6a, 0x73, 0xd2, 0x03, 0x5a, 0xe5, 0x3f, 0x65, 0xa8, 0x89, 0x5c,
+	0xb0, 0x6e, 0x37, 0x9c, 0x69, 0xda, 0xed, 0xec, 0x39, 0x9f, 0xf7, 0xf2, 0x72, 0xde, 0xe3, 0x6e,
+	0xb7, 0x7d, 0x51, 0xf3, 0x58, 0x60, 0x7e, 0xec, 0x81, 0x73, 0xcd, 0xcb, 0x5c, 0xc5, 0xfc, 0x99,
+	0x61, 0x1d, 0x86, 0xc5, 0x85, 0xe5, 0xcf, 0xac, 0xfb, 0x0d, 0x42, 0xdc, 0x48, 0x73, 0x66, 0x81,
+	0xc7, 0x3b, 0xbc, 0x8e, 0x33, 0x08, 0x5b, 0x9b, 0x4b, 0xdd, 0x9b, 0xf1, 0x8c, 0x4f, 0xa3, 0x3a,
+	0x5e, 0x00, 0xa9, 0x56, 0xbf, 0x9e, 0xce, 0x78, 0x47, 0x24, 0x5a, 0x06, 0x20, 0x19, 0x6a, 0xe2,
+	0x80, 0x10, 0x2d, 0x91, 0x88, 0x6c, 0x55, 0xee, 0x3e, 0x6e, 0x45, 0xe0, 0x81, 0x67, 0x10, 0xe6,
+	0x97, 0xf9, 0x8f, 0xd5, 0xcd, 0x78, 0xc7, 0x29, 0xb0, 0xda, 0xcb, 0xdb, 0x0f, 0xf4, 0xb2, 0xde,
+	0x3b, 0xb7, 0x62, 0x8b, 0x56, 0xec, 0x23, 0x05, 0x14, 0x07, 0x1e, 0x9b, 0xc6, 0x70, 0x10, 0x3a,
+	0x57, 0x57, 0x93, 0xb1, 0x3d, 0xbe, 0x21, 0xee, 0xdc, 0x23, 0x61, 0x84, 0x74, 0xd8, 0xa1, 0x0c,
+	0x5c, 0x40, 0xbc, 0x14, 0xcd, 0x93, 0xa7, 0xc7, 0xb9, 0xcb, 0xc0, 0x0a, 0x13, 0x2f, 0xf3, 0x94,
+	0xe7, 0xb0, 0x69, 0x1a, 0xc3, 0x08, 0x1d, 0x41, 0x75, 0x42, 0xc9, 0x34, 0x99, 0x05, 0x90, 0xcc,
+	0x02, 0x63, 0x88, 0x63, 0x85, 0xf2, 0x23, 0xd4, 0xed, 0xe4, 0x15, 0x78, 0x96, 0xb7, 0x5e, 0x7e,
+	0x57, 0x52, 0x06, 0x30, 0x3e, 0xf9, 0x3c, 0x27, 0x11, 0x5d, 0xe7, 0x60, 0x54, 0x5e, 0x02, 0x58,
+	0xa6, 0x91, 0x30, 0x72, 0x03, 0xb4, 0xb4, 0x34, 0x40, 0x95, 0x7f, 0x56, 0xa0, 0xa1, 0x7a, 0x4e,
+	0x38, 0x65, 0xc3, 0x56, 0xf9, 0x47, 0x05, 0xaa, 0xec, 0x21, 0x42, 0x35, 0xa8, 0xf4, 0x4d, 0x5b,
+	0xda, 0x40, 0x6d, 0x80, 0xee, 0x27, 0xdd, 0xe8, 0x8d, 0x7a, 0xaa, 0x6d, 0x49, 0x25, 0xd4, 0x82,
+	0x86, 0x69, 0x0c, 0x47, 0x6a, 0x5f, 0xc5, 0xe7, 0x52, 0x19, 0x7d, 0x07, 0x8f, 0x98, 0x68, 0x0f,
+	0x54, 0x3c, 0x18, 0x5a, 0xa3, 0x53, 0x55, 0xef, 0x0f, 0xb1, 0x26, 0x55, 0xd0, 0x3e, 0x20, 0xae,
+	0xd0, 0x7b, 0x86, 0xda, 0x1f, 0x75, 0xb5, 0x1e, 0x56, 0xbb, 0x9a, 0xb4, 0x99, 0x10, 0xba, 0x58,
+	0x3f, 0x1d, 0x8c, 0xcc, 0xd3, 0xd1, 0x47, 0xdd, 0xe8, 0x9a, 0x1f, 0xa5, 0x2a, 0x3a, 0x04, 0x99,
+	0x29, 0xfa, 0xa6, 0x6d, 0x33, 0xdc, 0x3c, 0xef, 0xe8, 0xa3, 0xce, 0x07, 0xd5, 0x30, 0xb4, 0xbe,
+	0xb4, 0x95, 0xae, 0xc3, 0xdd, 0xd9, 0xe9, 0x3a, 0x35, 0xf4, 0x02, 0x7e, 0xc5, 0x14, 0x03, 0xac,
+	0x1a, 0xf6, 0xb9, 0x6e, 0xdb, 0xba, 0x69, 0x8c, 0x74, 0x63, 0xa0, 0xe1, 0x53, 0x0d, 0x6b, 0x46,
+	0x47, 0x1b, 0x7d, 0x54, 0xb1, 0xa1, 0x1b, 0x3d, 0xa9, 0x8e, 0x0e, 0x60, 0x9f, 0x87, 0xde, 0x19,
+	0xe8, 0x17, 0xea, 0x80, 0x19, 0x26, 0x6e, 0x1a, 0x48, 0xe6, 0x4d, 0x32, 0xb2, 0xb0, 0xd9, 0xd1,
+	0x6c, 0x9b, 0xed, 0x57, 0xc3, 0xd8, 0xc4, 0x12, 0xa0, 0x23, 0x38, 0xcc, 0xc6, 0x75, 0xa6, 0x7d,
+	0x1a, 0xd9, 0x9f, 0x8c, 0x4e, 0xca, 0x6d, 0xa2, 0x3d, 0xd8, 0x65, 0x16, 0xfa, 0x60, 0x38, 0xb2,
+	0x4c, 0x83, 0xe5, 0x62, 0x60, 0x4b, 0xdb, 0x68, 0x17, 0x5a, 0x69, 0xa6, 0x18, 0x5d, 0x6a, 0x2d,
+	0x43, 0xef, 0xa5, 0x76, 0xb2, 0xb1, 0x04, 0xb2, 0x3a, 0x23, 0xb6, 0x0b, 0x69, 0x27, 0xc9, 0x47,
+	0x4e, 0xd1, 0x11, 0x51, 0x49, 0x08, 0x41, 0x3b, 0xab, 0x3d, 0xd5, 0xa5, 0x5d, 0xf4, 0x08, 0x76,
+	0xb2, 0x98, 0x7a, 0xae, 0x4b, 0x48, 0x79, 0x0b, 0x6d, 0x5e, 0x5f, 0xcb, 0x09, 0x9d, 0x29, 0xa1,
+	0x24, 0x44, 0x12, 0x54, 0xce, 0xc8, 0xbd, 0xe8, 0x1c, 0xf6, 0xc8, 0xe6, 0xca, 0x85, 0xe3, 0xcd,
+	0x93, 0xab, 0x51, 0x2c, 0x28, 0x7f, 0x2d, 0x71, 0x7f, 0x9c, 0x9d, 0x69, 0xa6, 0xb4, 0x5b, 0x84,
+	0x87, 0x05, 0xb0, 0xd6, 0xd9, 0xb5, 0x0f, 0x5b, 0xec, 0xb5, 0x9c, 0x47, 0x62, 0x88, 0x09, 0x09,
+	0xfd, 0x0e, 0x20, 0x0d, 0x31, 0x92, 0x37, 0xf9, 0x1b, 0xb1, 0x27, 0xde, 0x88, 0xfc, 0x06, 0x70,
+	0xc6, 0x50, 0xf9, 0x0c, 0x3b, 0x66, 0x7f, 0x90, 0x8b, 0xf1, 0x08, 0x9a, 0x7c, 0x3c, 0x5c, 0x39,
+	0x63, 0x22, 0x8e, 0xd6, 0x16, 0xce, 0x42, 0xe9, 0x54, 0x61, 0x22, 0xdf, 0x49, 0x39, 0x33, 0x55,
+	0x12, 0xf0, 0xa1, 0x48, 0xd9, 0x35, 0xaa, 0x75, 0x41, 0xc2, 0x68, 0x12, 0xf8, 0x62, 0x4f, 0x32,
+	0xd4, 0x6e, 0x63, 0x40, 0xe4, 0x24, 0x11, 0x59, 0xbe, 0x2e, 0xe7, 0x13, 0xcf, 0x1d, 0x4c, 0xa6,
+	0xe9, 0xc5, 0x33, 0x05, 0xd8, 0x6c, 0x1c, 0xf3, 0x73, 0xe2, 0x83, 0x13, 0xdd, 0x88, 0x55, 0x32,
+	0x08, 0x63, 0x5f, 0x4f, 0xa8, 0x08, 0x22, 0x3e, 0xc5, 0x17, 0x80, 0xf2, 0x16, 0xea, 0xfd, 0xe0,
+	0xba, 0x4f, 0x6e, 0x89, 0xc7, 0x2a, 0xe8, 0xb1, 0x07, 0xb1, 0x7e, 0x2c, 0xb0, 0x1d, 0x8c, 0x1d,
+	0xcf, 0x13, 0x95, 0xa8, 0x63, 0x21, 0x29, 0x1a, 0xd4, 0x31, 0x89, 0x66, 0x81, 0x1f, 0x11, 0xf4,
+	0x14, 0x9a, 0x11, 0xf7, 0x37, 0x1a, 0x07, 0x2e, 0x11, 0x17, 0x11, 0x88, 0xa1, 0x4e, 0xe0, 0x12,
+	0xb6, 0xb9, 0x29, 0x89, 0x22, 0xe7, 0x3a, 0xd9, 0x40, 0x22, 0x2a, 0x7f, 0x29, 0x41, 0x93, 0x4d,
+	0xff, 0x24, 0xf1, 0x2f, 0x60, 0xcb, 0xf4, 0xe7, 0x98, 0x7c, 0x16, 0x73, 0x74, 0x37, 0x33, 0xfe,
+	0x62, 0x13, 0x2c, 0x0c, 0xd0, 0x3b, 0xd8, 0xb6, 0xe7, 0x97, 0x2a, 0x3f, 0x7f, 0x2f, 0x1c, 0x8f,
+	0x7b, 0x6e, 0xa7, 0xf5, 0x4e, 0x55, 0x7c, 0x16, 0xe1, 0x9c, 0x29, 0x6b, 0xb2, 0x5e, 0x18, 0xcc,
+	0x67, 0xc9, 0x29, 0x19, 0xa7, 0x2d, 0x87, 0x29, 0x67, 0x50, 0x65, 0x57, 0xb7, 0x08, 0x7d, 0x0f,
+	0x70, 0xe5, 0x05, 0x77, 0xa3, 0x31, 0xff, 0xc2, 0x12, 0xd3, 0x8f, 0x21, 0xf1, 0xf7, 0xd5, 0x2f,
+	0xa1, 0xca, 0x04, 0x76, 0xd4, 0xb2, 0x7e, 0x6b, 0x1d, 0x27, 0x9f, 0x88, 0x8c, 0x8d, 0x63, 0x9d,
+	0xf2, 0x14, 0x6a, 0xac, 0x5a, 0xc1, 0x9c, 0xb2, 0x34, 0xbb, 0xc4, 0x73, 0xee, 0x85, 0xa7, 0x58,
+	0x50, 0x6a, 0x50, 0xd5, 0xa6, 0x33, 0x7a, 0xff, 0xf2, 0x35, 0xb4, 0xf3, 0xa1, 0xa3, 0x3a, 0x6c,
+	0xfe, 0x6c, 0xea, 0xec, 0x42, 0xdc, 0x80, 0x6a, 0x5f, 0x53, 0x2f, 0x34, 0xa9, 0x84, 0x00, 0xb6,
+	0x18, 0x78, 0xf1, 0x46, 0x2a, 0x9f, 0xfc, 0xbd, 0x09, 0xd5, 0xf7, 0xef, 0xed, 0xc9, 0x14, 0xbd,
+	0x82, 0x9a, 0xe8, 0x2a, 0xb4, 0x2d, 0xf2, 0xc0, 0xbd, 0x1e, 0x3c, 0x16, 0x52, 0xae, 0xe7, 0x94,
+	0x0d, 0xf4, 0x1a, 0x9a, 0x36, 0xa1, 0x69, 0x0b, 0xec, 0x08, 0xb3, 0x04, 0x38, 0x58, 0x06, 0x94,
+	0x0d, 0xf4, 0x0c, 0xb6, 0x7a, 0x84, 0xb2, 0x6f, 0x9d, 0xfc, 0x12, 0xb0, 0xb8, 0xb4, 0x2a, 0x1b,
+	0xe8, 0x0f, 0x20, 0xc7, 0x56, 0x05, 0x37, 0xde, 0xa7, 0x5f, 0xf9, 0x30, 0x38, 0x38, 0xfc, 0x82,
+	0x41, 0xa4, 0x6c, 0xa0, 0x1f, 0x00, 0xac, 0xe0, 0x8e, 0x84, 0x81, 0xbf, 0x1a, 0x46, 0x12, 0x71,
+	0xd2, 0x9c, 0xca, 0x06, 0x3a, 0x86, 0xa6, 0x7d, 0x33, 0xa7, 0x6e, 0x70, 0xb7, 0x9e, 0xfd, 0x6f,
+	0xa0, 0x81, 0xc9, 0x65, 0x10, 0xd0, 0xb5, 0xac, 0x59, 0xc1, 0x68, 0x30, 0xbb, 0xc6, 0x56, 0x87,
+	0x9d, 0xba, 0x24, 0xfc, 0x3a, 0xe5, 0x04, 0x76, 0x6c, 0xea, 0x84, 0xf4, 0x5b, 0x38, 0x3f, 0xc1,
+	0x2e, 0x26, 0xd1, 0x12, 0x2b, 0x39, 0xee, 0x45, 0x6f, 0x15, 0xf1, 0x5e, 0xc4, 0xe5, 0x32, 0x86,
+	0x68, 0xf5, 0x55, 0x3a, 0xc8, 0x5c, 0x2e, 0x94, 0x0d, 0xf4, 0x6b, 0x76, 0x01, 0xa3, 0xfc, 0x12,
+	0x92, 0x0f, 0xa7, 0xb9, 0x30, 0x8b, 0xe2, 0x7c, 0xf6, 0x08, 0x4d, 0xaf, 0x20, 0xc5, 0xa1, 0x27,
+	0x6a, 0x1e, 0x7a, 0x9b, 0xf9, 0xf5, 0xe7, 0x29, 0xa5, 0x20, 0x94, 0x02, 0xde, 0x9b, 0x4c, 0xdd,
+	0x8a, 0xe3, 0x7f, 0x20, 0xb7, 0x82, 0xa4, 0x7a, 0x5e, 0xc1, 0x66, 0x0a, 0x38, 0xef, 0x60, 0x37,
+	0xb3, 0x50, 0x64, 0xfa, 0x96, 0x69, 0xa4, 0xcb, 0x2d, 0xae, 0x41, 0xc5, 0xcb, 0xa5, 0xad, 0xb8,
+	0x76, 0x88, 0xaf, 0xa1, 0x2d, 0x38, 0x6b, 0x47, 0xf8, 0x16, 0xa4, 0xc5, 0x32, 0xdf, 0x14, 0xe0,
+	0x6f, 0x61, 0x5b, 0xf4, 0x4d, 0x7c, 0x43, 0x5f, 0x2f, 0xc4, 0x37, 0xd0, 0x14, 0x2c, 0x7e, 0x71,
+	0x5f, 0x8f, 0xf4, 0x1e, 0xf6, 0x6c, 0x5e, 0x67, 0x7e, 0x94, 0xea, 0xbe, 0x3b, 0x19, 0x3b, 0x6c,
+	0x8c, 0xa1, 0xfd, 0x05, 0x3d, 0x7b, 0xca, 0x7e, 0xc1, 0x07, 0x7b, 0xf1, 0x1f, 0xf0, 0x91, 0x3f,
+	0xa9, 0x8b, 0x7c, 0xfc, 0x00, 0xf5, 0x1e, 0xa1, 0xf1, 0xf0, 0x2e, 0x88, 0x3c, 0x49, 0x36, 0x37,
+	0xe0, 0xb9, 0xdd, 0xe9, 0xdc, 0x38, 0xfe, 0x35, 0x61, 0xe7, 0x50, 0xfc, 0x31, 0x80, 0x84, 0x49,
+	0xe6, 0x64, 0x2a, 0x5a, 0xe8, 0x0c, 0xbe, 0x8b, 0x1b, 0x7b, 0xf5, 0xc3, 0xa0, 0x60, 0xdd, 0x27,
+	0x0b, 0x68, 0xc5, 0x5e, 0xd9, 0xb8, 0xdc, 0xe2, 0x7f, 0x18, 0xbe, 0xf9, 0x5f, 0x00, 0x00, 0x00,
+	0xff, 0xff, 0x86, 0x40, 0xa9, 0x75, 0x8f, 0x14, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -1456,6 +1751,7 @@
 	SetLogLevel(ctx context.Context, in *LogLevel, opts ...grpc.CallOption) (*LogLevel, error)
 	// Get current status of OLT
 	GetOlt(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Olt, error)
+	GetOltAllocatedResources(ctx context.Context, in *OltAllocatedResourceType, opts ...grpc.CallOption) (*OltAllocatedResources, error)
 	// Poweron OLT
 	PoweronOlt(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Response, error)
 	// Shutdown OLT
@@ -1539,6 +1835,15 @@
 	return out, nil
 }
 
+func (c *bBSimClient) GetOltAllocatedResources(ctx context.Context, in *OltAllocatedResourceType, opts ...grpc.CallOption) (*OltAllocatedResources, error) {
+	out := new(OltAllocatedResources)
+	err := c.cc.Invoke(ctx, "/bbsim.BBSim/GetOltAllocatedResources", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *bBSimClient) PoweronOlt(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Response, error) {
 	out := new(Response)
 	err := c.cc.Invoke(ctx, "/bbsim.BBSim/PoweronOlt", in, out, opts...)
@@ -1754,6 +2059,7 @@
 	SetLogLevel(context.Context, *LogLevel) (*LogLevel, error)
 	// Get current status of OLT
 	GetOlt(context.Context, *Empty) (*Olt, error)
+	GetOltAllocatedResources(context.Context, *OltAllocatedResourceType) (*OltAllocatedResources, error)
 	// Poweron OLT
 	PoweronOlt(context.Context, *Empty) (*Response, error)
 	// Shutdown OLT
@@ -1815,6 +2121,9 @@
 func (*UnimplementedBBSimServer) GetOlt(ctx context.Context, req *Empty) (*Olt, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method GetOlt not implemented")
 }
+func (*UnimplementedBBSimServer) GetOltAllocatedResources(ctx context.Context, req *OltAllocatedResourceType) (*OltAllocatedResources, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetOltAllocatedResources not implemented")
+}
 func (*UnimplementedBBSimServer) PoweronOlt(ctx context.Context, req *Empty) (*Response, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method PoweronOlt not implemented")
 }
@@ -1943,6 +2252,24 @@
 	return interceptor(ctx, in, info, handler)
 }
 
+func _BBSim_GetOltAllocatedResources_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(OltAllocatedResourceType)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(BBSimServer).GetOltAllocatedResources(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/bbsim.BBSim/GetOltAllocatedResources",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(BBSimServer).GetOltAllocatedResources(ctx, req.(*OltAllocatedResourceType))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _BBSim_PoweronOlt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(Empty)
 	if err := dec(in); err != nil {
@@ -2374,6 +2701,10 @@
 			Handler:    _BBSim_GetOlt_Handler,
 		},
 		{
+			MethodName: "GetOltAllocatedResources",
+			Handler:    _BBSim_GetOltAllocatedResources_Handler,
+		},
+		{
 			MethodName: "PoweronOlt",
 			Handler:    _BBSim_PoweronOlt_Handler,
 		},
diff --git a/api/bbsim/bbsim.proto b/api/bbsim/bbsim.proto
index cf511b3..e6a253d 100644
--- a/api/bbsim/bbsim.proto
+++ b/api/bbsim/bbsim.proto
@@ -22,6 +22,18 @@
 message PONPort {
     int32 ID = 1;
     string OperState = 2;
+    string InternalState = 3;
+    uint64 PacketCount = 4;
+    // ONU ID are reported by VOLTHA in the ActivateOnu call
+    repeated PonAllocatedResources AllocatedOnuIds = 5;
+    // these are the stored resource IDs as reported via OMCI
+    repeated PonAllocatedResources AllocatedGemPorts = 6;
+    repeated PonAllocatedResources AllocatedAllocIds = 7;
+}
+
+message PonAllocatedResources {
+    string SerialNumber = 1;
+    int32 Id = 2;
 }
 
 message NNIPort {
@@ -39,6 +51,28 @@
     repeated PONPort PONPorts = 6;
 }
 
+message OltAllocatedResourceType {
+    enum Type {
+        UNKNOWN = 0;
+        ALLOC_ID = 1;
+        GEM_PORT = 2;
+    }
+    Type type = 1;
+}
+
+message OltAllocatedResource {
+    string Type = 1;
+    uint32 PonPortId = 2;
+    uint32 OnuId = 3;
+    uint32 PortNo = 4;
+    int32 ResourceId = 5;
+    uint64 FlowId = 6;
+}
+
+message OltAllocatedResources {
+    repeated OltAllocatedResource resources = 1;
+}
+
 message ONU {
     int32 ID = 1;
     string SerialNumber = 2;
@@ -199,6 +233,10 @@
     // Get current status of OLT
     rpc GetOlt (Empty) returns (Olt) {
     }
+
+    rpc GetOltAllocatedResources (OltAllocatedResourceType) returns (OltAllocatedResources) {
+    }
+
     // Poweron OLT
     rpc PoweronOlt (Empty) returns (Response) {
     }
diff --git a/go.mod b/go.mod
index 3b018ed..c6b5401 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@
 	github.com/olekukonko/tablewriter v0.0.4
 	github.com/opencord/cordctl v0.0.0-20190909161711-01e9c1f04bf4
 	github.com/opencord/device-management-interface v0.11.0
-	github.com/opencord/omci-lib-go v0.16.1
+	github.com/opencord/omci-lib-go v0.16.2
 	github.com/opencord/voltha-protos/v4 v4.0.15
 	github.com/pkg/errors v0.8.1 // indirect
 	github.com/sirupsen/logrus v1.4.2
diff --git a/go.sum b/go.sum
index 5718e49..79d8368 100644
--- a/go.sum
+++ b/go.sum
@@ -87,8 +87,8 @@
 github.com/opencord/cordctl v0.0.0-20190909161711-01e9c1f04bf4/go.mod h1:/+3S0pwQUy7HeKnH0KfKp5W6hmh/LdZzuZTNT/m7vA4=
 github.com/opencord/device-management-interface v0.11.0 h1:hoKjrkQWPr0IFXWn6HbGdV1Bk5v0gijM7P4VjUJvNh8=
 github.com/opencord/device-management-interface v0.11.0/go.mod h1:G1owSqGBGaqllrwtjxfLTsy9EDsGhdhmqkJM3XOnPD0=
-github.com/opencord/omci-lib-go v0.16.1 h1:vYCqT3kN1bs2IfQXS3X/I106qY40zJfYimLLTcZ2QWY=
-github.com/opencord/omci-lib-go v0.16.1/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
+github.com/opencord/omci-lib-go v0.16.2 h1:ywbaZLrLV+6VgyXV3I1LysdErt5HQutcin1CaaGRkA4=
+github.com/opencord/omci-lib-go v0.16.2/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
 github.com/opencord/voltha-protos/v4 v4.0.15 h1:TOKYlt/75w5pxT44HeYfo2kqKvqmHzVpUkiCHOMJTN8=
 github.com/opencord/voltha-protos/v4 v4.0.15/go.mod h1:W/OIFIyvFh/C0vchRUuarIsMylEhzCRM9pNxLvkPtKc=
 github.com/pierrec/lz4 v2.4.1+incompatible h1:mFe7ttWaflA46Mhqh+jUfjp2qTbPYxLB2/OyBppH9dg=
diff --git a/internal/bbsim/api/grpc_api_server.go b/internal/bbsim/api/grpc_api_server.go
index 01c7f4f..ec25a10 100644
--- a/internal/bbsim/api/grpc_api_server.go
+++ b/internal/bbsim/api/grpc_api_server.go
@@ -19,6 +19,7 @@
 import (
 	"context"
 	"fmt"
+	"google.golang.org/grpc/status"
 	"strings"
 	"time"
 
@@ -67,9 +68,43 @@
 	}
 
 	for _, pon := range olt.Pons {
+
+		allocatedOnuIds := []*bbsim.PonAllocatedResources{}
+		allocatedAllocIds := []*bbsim.PonAllocatedResources{}
+		allocatedGemPorts := []*bbsim.PonAllocatedResources{}
+
+		for k, v := range pon.AllocatedOnuIds {
+			resource := &bbsim.PonAllocatedResources{
+				SerialNumber: common.OnuSnToString(v),
+				Id:           int32(k),
+			}
+			allocatedOnuIds = append(allocatedOnuIds, resource)
+		}
+
+		for k, v := range pon.AllocatedGemPorts {
+			resource := &bbsim.PonAllocatedResources{
+				SerialNumber: common.OnuSnToString(v),
+				Id:           int32(k),
+			}
+			allocatedGemPorts = append(allocatedGemPorts, resource)
+		}
+
+		for k, v := range pon.AllocatedAllocIds {
+			resource := &bbsim.PonAllocatedResources{
+				SerialNumber: common.OnuSnToString(v),
+				Id:           int32(k),
+			}
+			allocatedAllocIds = append(allocatedAllocIds, resource)
+		}
+
 		p := bbsim.PONPort{
-			ID:        int32(pon.ID),
-			OperState: pon.OperState.Current(),
+			ID:                int32(pon.ID),
+			OperState:         pon.OperState.Current(),
+			InternalState:     pon.InternalState.Current(),
+			PacketCount:       pon.PacketCount,
+			AllocatedOnuIds:   allocatedOnuIds,
+			AllocatedAllocIds: allocatedAllocIds,
+			AllocatedGemPorts: allocatedGemPorts,
 		}
 		pons = append(pons, &p)
 	}
@@ -91,6 +126,48 @@
 	return &res, nil
 }
 
+// takes a nested map and return a proto
+func resourcesMapToresourcesProto(resourceType bbsim.OltAllocatedResourceType_Type, resources map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool) *bbsim.OltAllocatedResources {
+	proto := &bbsim.OltAllocatedResources{
+		Resources: []*bbsim.OltAllocatedResource{},
+	}
+	for ponId, ponValues := range resources {
+		for onuId, onuValues := range ponValues {
+			for uniId, uniValues := range onuValues {
+				for allocId, flows := range uniValues {
+					for flow := range flows {
+						resource := &bbsim.OltAllocatedResource{
+							Type:       resourceType.String(),
+							PonPortId:  ponId,
+							OnuId:      onuId,
+							PortNo:     uniId,
+							ResourceId: allocId,
+							FlowId:     flow,
+						}
+						proto.Resources = append(proto.Resources, resource)
+					}
+				}
+			}
+		}
+	}
+	return proto
+}
+
+func (s BBSimServer) GetOltAllocatedResources(ctx context.Context, req *bbsim.OltAllocatedResourceType) (*bbsim.OltAllocatedResources, error) {
+	o := devices.GetOLT()
+
+	switch req.Type {
+	case bbsim.OltAllocatedResourceType_UNKNOWN:
+		return nil, status.Errorf(codes.InvalidArgument, "resource-type-%s-is-invalid", req.Type)
+	case bbsim.OltAllocatedResourceType_ALLOC_ID:
+		return resourcesMapToresourcesProto(bbsim.OltAllocatedResourceType_ALLOC_ID, o.AllocIDs), nil
+	case bbsim.OltAllocatedResourceType_GEM_PORT:
+		return resourcesMapToresourcesProto(bbsim.OltAllocatedResourceType_GEM_PORT, o.GemPortIDs), nil
+	default:
+		return nil, status.Errorf(codes.InvalidArgument, "unkown-resource-type-%s", req.Type)
+	}
+}
+
 func (s BBSimServer) PoweronOlt(ctx context.Context, req *bbsim.Empty) (*bbsim.Response, error) {
 	res := &bbsim.Response{}
 	o := devices.GetOLT()
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index f9ef936..87b9da4 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -90,6 +90,13 @@
 
 	OpenoltStream openolt.Openolt_EnableIndicationServer
 	enablePerf    bool
+
+	// Allocated Resources
+	// this data are to verify that the openolt adapter does not duplicate resources
+	AllocIDsLock   sync.RWMutex
+	AllocIDs       map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool // map[ponPortId]map[OnuId]map[PortNo]map[AllocIds]map[FlowId]bool
+	GemPortIDsLock sync.RWMutex
+	GemPortIDs     map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool // map[ponPortId]map[OnuId]map[PortNo]map[GemPortIDs]map[FlowId]bool
 }
 
 var olt OltDevice
@@ -123,6 +130,8 @@
 		PortStatsInterval:   options.Olt.PortStatsInterval,
 		dhcpServer:          dhcp.NewDHCPServer(),
 		PreviouslyConnected: false,
+		AllocIDs:            make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
+		GemPortIDs:          make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
 	}
 
 	if val, ok := ControlledActivationModes[options.BBSim.ControlledActivation]; ok {
@@ -149,6 +158,10 @@
 				oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
 			},
 			"enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
+			"enter_deleted": func(e *fsm.Event) {
+				// remove all the resource allocations
+				olt.clearAllResources()
+			},
 		},
 	)
 
@@ -169,6 +182,11 @@
 
 	// create PON ports
 	for i := 0; i < olt.NumPon; i++ {
+
+		// initialize the resource maps for every PON Ports
+		olt.AllocIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
+		olt.GemPortIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
+
 		p := CreatePonPort(&olt, uint32(i))
 
 		// create ONU devices
@@ -253,6 +271,12 @@
 		// in-band management
 		o.Nnis[0].OperState.SetState("down")
 	}
+
+	for ponId := range o.Pons {
+		// initialize the resource maps for every PON Ports
+		olt.AllocIDs[uint32(ponId)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
+		olt.GemPortIDs[uint32(ponId)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
+	}
 }
 
 func (o *OltDevice) RestartOLT() error {
@@ -822,16 +846,14 @@
 	publishEvent("ONU-activate-indication-received", int32(onu.IntfId), int32(onu.OnuId), onuSnToString(onu.SerialNumber))
 
 	pon, _ := o.GetPonById(onu.IntfId)
+
+	// Initialize the resource maps for this ONU
+	olt.AllocIDs[onu.IntfId][onu.OnuId] = make(map[uint32]map[int32]map[uint64]bool)
+	olt.GemPortIDs[onu.IntfId][onu.OnuId] = make(map[uint32]map[int32]map[uint64]bool)
+
 	_onu, _ := pon.GetOnuBySn(onu.SerialNumber)
 	_onu.SetID(onu.OnuId)
 
-	if err := _onu.OperState.Event("enable"); err != nil {
-		oltLogger.WithFields(log.Fields{
-			"IntfId": _onu.PonPortID,
-			"OnuSn":  _onu.Sn(),
-			"OnuId":  _onu.ID,
-		}).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
-	}
 	if err := _onu.InternalState.Event(OnuTxEnable); err != nil {
 		oltLogger.WithFields(log.Fields{
 			"IntfId": _onu.PonPortID,
@@ -845,7 +867,7 @@
 	return new(openolt.Empty), nil
 }
 
-func (o *OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
+func (o *OltDevice) DeactivateOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
 	oltLogger.Error("DeactivateOnu not implemented")
 	return new(openolt.Empty), nil
 }
@@ -1056,6 +1078,21 @@
 			}
 		}
 
+		// validate that the flow reference correct IDs (Alloc, Gem)
+		if err := o.validateFlow(flow); err != nil {
+			oltLogger.WithFields(log.Fields{
+				"OnuId":        flow.OnuId,
+				"IntfId":       flow.AccessIntfId,
+				"Flow":         flow,
+				"SerialNumber": onu.Sn(),
+				"err":          err,
+			}).Error("invalid-flow-for-onu")
+			return nil, err
+		}
+
+		o.storeGemPortId(flow)
+		o.storeAllocId(flow)
+
 		msg := types.Message{
 			Type: types.FlowAdd,
 			Data: types.OnuFlowUpdateMessage{
@@ -1074,10 +1111,22 @@
 func (o *OltDevice) FlowRemove(_ context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
 
 	oltLogger.WithFields(log.Fields{
-		"FlowId":   flow.FlowId,
-		"FlowType": flow.FlowType,
+		"AllocId":       flow.AllocId,
+		"Cookie":        flow.Cookie,
+		"FlowId":        flow.FlowId,
+		"FlowType":      flow.FlowType,
+		"GemportId":     flow.GemportId,
+		"IntfId":        flow.AccessIntfId,
+		"OnuId":         flow.OnuId,
+		"PortNo":        flow.PortNo,
+		"UniID":         flow.UniId,
+		"ReplicateFlow": flow.ReplicateFlow,
+		"PbitToGemport": flow.PbitToGemport,
 	}).Debug("OLT receives FlowRemove")
 
+	olt.freeGemPortId(flow)
+	olt.freeAllocId(flow)
+
 	if !o.enablePerf { // remove only if flow were stored
 		flowKey := FlowKey{
 			ID:        flow.FlowId,
@@ -1177,11 +1226,6 @@
 
 func (o *OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
 
-	oltLogger.WithFields(log.Fields{
-		"oltId":    o.ID,
-		"PonPorts": o.NumPon,
-	}).Info("OLT receives GetDeviceInfo call from VOLTHA")
-
 	intfIDs := []uint32{}
 	for i := 0; i < o.NumPon; i++ {
 		intfIDs = append(intfIDs, uint32(i))
@@ -1538,3 +1582,179 @@
 func (o *OltDevice) GetOnuStatistics(ctx context.Context, in *openolt.Onu) (*openolt.OnuStatistics, error) {
 	return &openolt.OnuStatistics{}, nil
 }
+
+func (o *OltDevice) storeAllocId(flow *openolt.Flow) {
+	o.AllocIDsLock.Lock()
+	defer o.AllocIDsLock.Unlock()
+
+	oltLogger.WithFields(log.Fields{
+		"IntfId":  flow.AccessIntfId,
+		"OnuId":   flow.OnuId,
+		"PortNo":  flow.PortNo,
+		"AllocId": flow.AllocId,
+	}).Trace("storing-alloc-id-via-flow")
+
+	if _, ok := o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo]; !ok {
+		o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo] = make(map[int32]map[uint64]bool)
+	}
+	if _, ok := o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.AllocId]; !ok {
+		o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.AllocId] = make(map[uint64]bool)
+	}
+	o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.AllocId][flow.FlowId] = true
+}
+
+func (o *OltDevice) freeAllocId(flow *openolt.Flow) {
+	// if this is the last flow referencing the AllocId then remove it
+	o.AllocIDsLock.Lock()
+	defer o.AllocIDsLock.Unlock()
+
+	oltLogger.WithFields(log.Fields{
+		"IntfId":    flow.AccessIntfId,
+		"OnuId":     flow.OnuId,
+		"PortNo":    flow.PortNo,
+		"GemportId": flow.GemportId,
+	}).Trace("freeing-alloc-id-via-flow")
+
+	// NOTE look at the freeGemPortId implementation for comments and context
+	for ponId, ponValues := range o.AllocIDs {
+		for onuId, onuValues := range ponValues {
+			for uniId, uniValues := range onuValues {
+				for allocId, flows := range uniValues {
+					for flowId := range flows {
+						// if the flow matches, remove it from the map.
+						if flow.FlowId == flowId {
+							delete(o.AllocIDs[ponId][onuId][uniId][allocId], flow.FlowId)
+						}
+						// if that was the last flow for a particular allocId, remove the entire allocId
+						if len(o.AllocIDs[ponId][onuId][uniId][allocId]) == 0 {
+							delete(o.AllocIDs[ponId][onuId][uniId], allocId)
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+func (o *OltDevice) storeGemPortId(flow *openolt.Flow) {
+	o.GemPortIDsLock.Lock()
+	defer o.GemPortIDsLock.Unlock()
+
+	oltLogger.WithFields(log.Fields{
+		"IntfId":    flow.AccessIntfId,
+		"OnuId":     flow.OnuId,
+		"PortNo":    flow.PortNo,
+		"GemportId": flow.GemportId,
+	}).Trace("storing-gem-port-id-via-flow")
+
+	if _, ok := o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo]; !ok {
+		o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo] = make(map[int32]map[uint64]bool)
+	}
+	if _, ok := o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.GemportId]; !ok {
+		o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.GemportId] = make(map[uint64]bool)
+	}
+	o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.GemportId][flow.FlowId] = true
+}
+
+func (o *OltDevice) freeGemPortId(flow *openolt.Flow) {
+	// if this is the last flow referencing the GemPort then remove it
+	o.GemPortIDsLock.Lock()
+	defer o.GemPortIDsLock.Unlock()
+
+	oltLogger.WithFields(log.Fields{
+		"IntfId":    flow.AccessIntfId,
+		"OnuId":     flow.OnuId,
+		"PortNo":    flow.PortNo,
+		"GemportId": flow.GemportId,
+	}).Trace("freeing-gem-port-id-via-flow")
+
+	// NOTE that this loop is not very performant, it would be better if the flow carries
+	// the same information that it carries during a FlowAdd. If so we can directly remove
+	// items from the map
+
+	//delete(o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.GemportId], flow.FlowId)
+	//if len(o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.GemportId]) == 0 {
+	//	delete(o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo], flow.GemportId)
+	//}
+
+	// NOTE this loop assumes that flow IDs are unique per device
+	for ponId, ponValues := range o.GemPortIDs {
+		for onuId, onuValues := range ponValues {
+			for uniId, uniValues := range onuValues {
+				for gemId, flows := range uniValues {
+					for flowId := range flows {
+						// if the flow matches, remove it from the map.
+						if flow.FlowId == flowId {
+							delete(o.GemPortIDs[ponId][onuId][uniId][gemId], flow.FlowId)
+						}
+						// if that was the last flow for a particular gem, remove the entire gem
+						if len(o.GemPortIDs[ponId][onuId][uniId][gemId]) == 0 {
+							delete(o.GemPortIDs[ponId][onuId][uniId], gemId)
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+// validateFlow checks that:
+// - the AllocId is not used in any flow referencing other ONUs/UNIs on the same PON
+// - the GemPortId is not used in any flow referencing other ONUs/UNIs on the same PON
+func (o *OltDevice) validateFlow(flow *openolt.Flow) error {
+
+	// validate gemPort
+	o.GemPortIDsLock.RLock()
+	allocatedGems := o.GemPortIDs[uint32(flow.AccessIntfId)]
+	o.GemPortIDsLock.RUnlock()
+	for onuId, onu := range allocatedGems {
+		if onuId == uint32(flow.OnuId) {
+			continue
+		}
+		for uniId, uni := range onu {
+			for gem := range uni {
+				if gem == flow.GemportId {
+					return fmt.Errorf("gem-%d-already-in-use-on-uni-%d-onu-%d", gem, uniId, onuId)
+				}
+			}
+		}
+	}
+
+	o.AllocIDsLock.RLock()
+	allocatedAllocIds := o.AllocIDs[uint32(flow.AccessIntfId)]
+	o.AllocIDsLock.RUnlock()
+	for onuId, onu := range allocatedAllocIds {
+		if onuId == uint32(flow.OnuId) {
+			continue
+		}
+		for uniId, uni := range onu {
+			for allocId := range uni {
+				if allocId == flow.AllocId {
+					return fmt.Errorf("allocId-%d-already-in-use-on-uni-%d-onu-%d", allocId, uniId, onuId)
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
+// clearAllResources is invoked up OLT Reboot to remove all the allocated
+// GemPorts, AllocId and ONU-IDs across the PONs
+func (o *OltDevice) clearAllResources() {
+
+	// remove the resources received via flows
+	o.GemPortIDsLock.Lock()
+	o.GemPortIDs = make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool)
+	o.GemPortIDsLock.Unlock()
+	o.AllocIDsLock.Lock()
+	o.AllocIDs = make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool)
+	o.AllocIDsLock.Unlock()
+
+	// remove the resources received via OMCI
+	for _, pon := range o.Pons {
+		pon.removeAllAllocIds()
+		pon.removeAllGemPorts()
+		pon.removeAllOnuIds()
+	}
+}
diff --git a/internal/bbsim/devices/olt_test.go b/internal/bbsim/devices/olt_test.go
index 154942b..acbe7a7 100644
--- a/internal/bbsim/devices/olt_test.go
+++ b/internal/bbsim/devices/olt_test.go
@@ -28,15 +28,27 @@
 
 func createMockOlt(numPon int, numOnu int, services []ServiceIf) *OltDevice {
 	olt := &OltDevice{
-		ID: 0,
+		ID:         0,
+		AllocIDs:   make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
+		GemPortIDs: make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
 	}
 
 	for i := 0; i < numPon; i++ {
+
+		// initialize the resource maps for every PON Ports
+		olt.AllocIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
+		olt.GemPortIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
+
 		pon := PonPort{
 			ID: uint32(i),
 		}
 
 		for j := 0; j < numOnu; j++ {
+
+			// initialize the resource maps for every ONU and the first UNI
+			olt.AllocIDs[uint32(i)][uint32(j)] = make(map[uint32]map[int32]map[uint64]bool)
+			olt.GemPortIDs[uint32(i)][uint32(j)] = make(map[uint32]map[int32]map[uint64]bool)
+
 			onuId := uint32(i + j)
 			onu := Onu{
 				ID:        onuId,
@@ -51,7 +63,7 @@
 				onu.Services = append(onu.Services, service)
 			}
 
-			onu.SerialNumber = onu.NewSN(olt.ID, pon.ID, onu.ID)
+			onu.SerialNumber = NewSN(olt.ID, pon.ID, onu.ID)
 			pon.Onus = append(pon.Onus, &onu)
 		}
 		olt.Pons = append(olt.Pons, &pon)
@@ -227,3 +239,209 @@
 	assert.Equal(t, err, nil)
 	assert.Equal(t, found.Sn(), onu1.Sn())
 }
+
+func Test_Olt_storeGemPortId(t *testing.T) {
+
+	const (
+		pon  = 1
+		onu  = 1
+		uni  = 16
+		gem1 = 1024
+		gem2 = 1025
+	)
+
+	numPon := 2
+	numOnu := 2
+
+	olt := createMockOlt(numPon, numOnu, []ServiceIf{})
+
+	// add a first flow on the ONU
+	flow1 := &openolt.Flow{
+		AccessIntfId: pon,
+		OnuId:        onu,
+		PortNo:       uni,
+		FlowId:       1,
+		GemportId:    gem1,
+	}
+
+	olt.storeGemPortId(flow1)
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1)       // we have 1 gem port
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1) // and one flow referencing it
+
+	// add a second flow on the ONU (same gem)
+	flow2 := &openolt.Flow{
+		AccessIntfId: pon,
+		OnuId:        onu,
+		PortNo:       uni,
+		FlowId:       2,
+		GemportId:    gem1,
+	}
+
+	olt.storeGemPortId(flow2)
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1)       // we have 1 gem port
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 2) // and two flows referencing it
+
+	// add a third flow on the ONU (different gem)
+	flow3 := &openolt.Flow{
+		AccessIntfId: pon,
+		OnuId:        onu,
+		PortNo:       uni,
+		FlowId:       2,
+		GemportId:    1025,
+	}
+
+	olt.storeGemPortId(flow3)
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2)       // we have 2 gem ports
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 2) // two flows referencing the first one
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem2]), 1) // and one flow referencing the second one
+}
+
+func Test_Olt_freeGemPortId(t *testing.T) {
+	const (
+		pon   = 1
+		onu   = 1
+		uni   = 16
+		gem1  = 1024
+		gem2  = 1025
+		flow1 = 1
+		flow2 = 2
+		flow3 = 3
+	)
+
+	numPon := 2
+	numOnu := 2
+
+	olt := createMockOlt(numPon, numOnu, []ServiceIf{})
+
+	olt.GemPortIDs[pon][onu][uni] = make(map[int32]map[uint64]bool)
+	olt.GemPortIDs[pon][onu][uni][gem1] = make(map[uint64]bool)
+	olt.GemPortIDs[pon][onu][uni][gem1][flow1] = true
+	olt.GemPortIDs[pon][onu][uni][gem1][flow2] = true
+	olt.GemPortIDs[pon][onu][uni][gem2] = make(map[uint64]bool)
+	olt.GemPortIDs[pon][onu][uni][gem2][flow3] = true
+
+	// remove one flow on the first gem, check that the gem is still allocated as there is still a flow referencing it
+	// NOTE that the flow remove only carries the flow ID, no other information
+	flowGem1 := &openolt.Flow{
+		FlowId: flow1,
+	}
+
+	olt.freeGemPortId(flowGem1)
+	// we still have two unis in the map
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2)
+
+	// we should now have a single gem referenced on this UNI
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1, "gemport-not-removed")
+
+	// the gem should still reference flow 2
+	assert.Equal(t, olt.GemPortIDs[pon][onu][uni][gem1][flow2], true)
+	// but should not reference flow1
+	_, flow1Exists := olt.GemPortIDs[pon][onu][uni][gem1][flow1]
+	assert.Equal(t, flow1Exists, false)
+
+	// this is the only flow remaining on this gem, the gem should be removed
+	flowGem2 := &openolt.Flow{
+		FlowId: flow2,
+	}
+	olt.freeGemPortId(flowGem2)
+
+	// we should now have a single gem referenced on this UNI
+	assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1, "gemport-not-removed")
+
+	// and it should be gem2
+	_, gem1exists := olt.GemPortIDs[pon][onu][uni][gem1]
+	assert.Equal(t, gem1exists, false)
+	_, gem2exists := olt.GemPortIDs[pon][onu][uni][gem2]
+	assert.Equal(t, gem2exists, true)
+}
+
+func Test_Olt_validateFlow(t *testing.T) {
+
+	const (
+		pon0            = 0
+		pon1            = 1
+		onu0            = 0
+		onu1            = 1
+		uniPort         = 0
+		usedGemIdPon0   = 1024
+		usedGemIdPon1   = 1025
+		usedAllocIdPon0 = 1
+		usedAllocIdPon1 = 2
+		flowId          = 1
+	)
+
+	numPon := 2
+	numOnu := 2
+
+	olt := createMockOlt(numPon, numOnu, []ServiceIf{})
+
+	olt.GemPortIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
+	olt.GemPortIDs[pon1][onu0][uniPort] = make(map[int32]map[uint64]bool)
+
+	olt.GemPortIDs[pon0][onu0][uniPort][usedGemIdPon0] = make(map[uint64]bool)
+	olt.GemPortIDs[pon0][onu0][uniPort][usedGemIdPon0][flowId] = true
+	olt.GemPortIDs[pon1][onu0][uniPort][usedGemIdPon1] = make(map[uint64]bool)
+	olt.GemPortIDs[pon1][onu0][uniPort][usedGemIdPon1][flowId] = true
+
+	olt.AllocIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
+	olt.AllocIDs[pon1][onu0][uniPort] = make(map[int32]map[uint64]bool)
+	olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0] = make(map[uint64]bool)
+	olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0][flowId] = true
+	olt.AllocIDs[pon1][onu0][uniPort][usedAllocIdPon1] = make(map[uint64]bool)
+	olt.AllocIDs[pon1][onu0][uniPort][usedAllocIdPon1][flowId] = true
+
+	// a GemPortID can be referenced across multiple flows on the same ONU
+	validGemFlow := &openolt.Flow{
+		AccessIntfId: pon0,
+		OnuId:        onu0,
+		GemportId:    usedGemIdPon0,
+	}
+
+	err := olt.validateFlow(validGemFlow)
+	assert.NilError(t, err)
+
+	// a GemPortID can NOT be referenced across different ONUs on the same PON
+	invalidGemFlow := &openolt.Flow{
+		AccessIntfId: pon0,
+		OnuId:        onu1,
+		GemportId:    usedGemIdPon0,
+	}
+	err = olt.validateFlow(invalidGemFlow)
+	assert.Error(t, err, "gem-1024-already-in-use-on-uni-0-onu-0")
+
+	// if a flow reference the same GEM on a different PON it's a valid flow
+	invalidGemDifferentPonFlow := &openolt.Flow{
+		AccessIntfId: pon1,
+		OnuId:        onu1,
+		GemportId:    usedGemIdPon0,
+	}
+	err = olt.validateFlow(invalidGemDifferentPonFlow)
+	assert.NilError(t, err)
+
+	// an allocId can be referenced across multiple flows on the same ONU
+	validAllocFlow := &openolt.Flow{
+		AccessIntfId: pon0,
+		OnuId:        onu0,
+		AllocId:      usedAllocIdPon0,
+	}
+	err = olt.validateFlow(validAllocFlow)
+	assert.NilError(t, err)
+
+	// an allocId can NOT be referenced across different ONUs on the same PON
+	invalidAllocFlow := &openolt.Flow{
+		AccessIntfId: pon0,
+		OnuId:        onu1,
+		AllocId:      usedAllocIdPon0,
+	}
+	err = olt.validateFlow(invalidAllocFlow)
+	assert.Error(t, err, "allocId-1-already-in-use-on-uni-0-onu-0")
+
+	// if a flow reference the same AllocId on a different PON it's a valid flow
+	invalidAllocDifferentPonFlow := &openolt.Flow{
+		AccessIntfId: pon1,
+		OnuId:        onu1,
+		AllocId:      usedAllocIdPon0,
+	}
+	err = olt.validateFlow(invalidAllocDifferentPonFlow)
+	assert.NilError(t, err)
+}
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index fd7eca0..ab7c35f 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -22,14 +22,13 @@
 	"fmt"
 	pb "github.com/opencord/bbsim/api/bbsim"
 	"github.com/opencord/bbsim/internal/bbsim/alarmsim"
-	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
-	me "github.com/opencord/omci-lib-go/generated"
-	"strconv"
-
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
 	"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
 	"github.com/opencord/bbsim/internal/bbsim/responders/eapol"
+	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+	me "github.com/opencord/omci-lib-go/generated"
 	"net"
+	"strconv"
 	"time"
 
 	"github.com/google/gopacket/layers"
@@ -102,11 +101,9 @@
 	// 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
-	// deprecated (gemPort is on a Service basis)
-	GemPortAdded bool
-	Flows        []FlowKey
-	FlowIds      []uint64 // keep track of the flows we currently have in the ONU
+	PortNo  uint32
+	Flows   []FlowKey
+	FlowIds []uint64 // keep track of the flows we currently have in the ONU
 
 	OperState    *fsm.FSM
 	SerialNumber *openolt.SerialNumber
@@ -153,7 +150,7 @@
 		ActiveImageEntityId:           0, // when we start the SoftwareImage with ID 0 is active and committed
 		CommittedImageEntityId:        0,
 	}
-	o.SerialNumber = o.NewSN(olt.ID, pon.ID, id)
+	o.SerialNumber = NewSN(olt.ID, pon.ID, id)
 	// NOTE this state machine is used to track the operational
 	// state as requested by VOLTHA
 	o.OperState = getOperStateFSM(func(e *fsm.Event) {
@@ -217,6 +214,18 @@
 				o.Channel <- msg
 			},
 			"enter_enabled": func(event *fsm.Event) {
+
+				if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
+					onuLogger.WithFields(log.Fields{
+						"IntfId":       o.PonPortID,
+						"OnuId":        o.ID,
+						"SerialNumber": o.Sn(),
+					}).Errorf("received-omci-with-sn-%s", common.OnuSnToString(sn))
+					return
+				} else {
+					o.PonPort.storeOnuId(o.ID, o.SerialNumber)
+				}
+
 				msg := bbsim.Message{
 					Type: bbsim.OnuIndication,
 					Data: bbsim.OnuIndicationMessage{
@@ -235,9 +244,11 @@
 			"enter_disabled": func(event *fsm.Event) {
 
 				// clean the ONU state
-				o.GemPortAdded = false
 				o.PortNo = 0
 				o.Flows = []FlowKey{}
+				o.PonPort.removeOnuId(o.ID)
+				o.PonPort.removeAllocId(o.SerialNumber)
+				o.PonPort.removeGemPortBySn(o.SerialNumber)
 
 				// set the OperState to disabled
 				if err := o.OperState.Event("disable"); err != nil {
@@ -438,7 +449,7 @@
 	}).Debug("Stopped handling ONU Indication Channel")
 }
 
-func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
+func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
 
 	sn := new(openolt.SerialNumber)
 
@@ -477,10 +488,8 @@
 }
 
 func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
-	// NOTE voltha returns an ID, but if we use that ID then it complains:
-	// expected_onu_id: 1, received_onu_id: 1024, event: ONU-id-mismatch, can happen if both voltha and the olt rebooted
-	// so we're using the internal ID that is 1
-	// o.ID = msg.OnuID
+	// NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
+	// and stored in the Onu struct via onu.SetID
 
 	indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
 		IntfId:       o.PonPortID,
@@ -495,11 +504,12 @@
 		return
 	}
 	onuLogger.WithFields(log.Fields{
-		"IntfId":     o.PonPortID,
-		"OnuId":      o.ID,
-		"OperState":  msg.OperState.String(),
-		"AdminState": msg.OperState.String(),
-		"OnuSn":      o.Sn(),
+		"IntfId":      o.PonPortID,
+		"OnuId":       o.ID,
+		"VolthaOnuId": msg.OnuID,
+		"OperState":   msg.OperState.String(),
+		"AdminState":  msg.OperState.String(),
+		"OnuSn":       o.Sn(),
 	}).Debug("Sent Indication_OnuInd")
 
 }
@@ -707,10 +717,7 @@
 	case omci.GetRequestType:
 		responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId, o.CommittedImageEntityId)
 	case omci.SetRequestType:
-		if responsePkt, errResp = omcilib.CreateSetResponse(omciPkt, omciMsg); errResp == nil {
-			o.MibDataSync++
-		}
-
+		success := true
 		msgObj, _ := omcilib.ParseSetRequest(omciPkt)
 		switch msgObj.EntityClass {
 		case me.PhysicalPathTerminationPointEthernetUniClassID:
@@ -734,12 +741,101 @@
 				}
 				o.Channel <- msg
 			}
+		case me.TContClassID:
+			allocId := msgObj.Attributes["AllocId"].(uint16)
+
+			// if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
+			// otherwise we are adding it
+			if allocId == 255 || allocId == 65535 {
+				onuLogger.WithFields(log.Fields{
+					"IntfId":       o.PonPortID,
+					"OnuId":        o.ID,
+					"TContId":      msgObj.EntityInstance,
+					"AllocId":      allocId,
+					"SerialNumber": o.Sn(),
+				}).Trace("freeing-alloc-id-via-omci")
+				o.PonPort.removeAllocId(o.SerialNumber)
+			} else {
+				if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
+					onuLogger.WithFields(log.Fields{
+						"IntfId":       o.PonPortID,
+						"OnuId":        o.ID,
+						"AllocId":      allocId,
+						"SerialNumber": o.Sn(),
+					}).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
+					success = false
+				} else {
+					onuLogger.WithFields(log.Fields{
+						"IntfId":       o.PonPortID,
+						"OnuId":        o.ID,
+						"TContId":      msgObj.EntityInstance,
+						"AllocId":      allocId,
+						"SerialNumber": o.Sn(),
+					}).Trace("storing-alloc-id-via-omci")
+					o.PonPort.storeAllocId(allocId, o.SerialNumber)
+				}
+			}
+
+		}
+
+		if success {
+			if responsePkt, errResp = omcilib.CreateSetResponse(omciPkt, omciMsg, me.Success); errResp == nil {
+				o.MibDataSync++
+			}
+		} else {
+			responsePkt, _ = omcilib.CreateSetResponse(omciPkt, omciMsg, me.AttributeFailure)
 		}
 	case omci.CreateRequestType:
-		if responsePkt, errResp = omcilib.CreateCreateResponse(omciPkt, omciMsg); errResp == nil {
-			o.MibDataSync++
+		// check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
+		var used bool
+		var sn *openolt.SerialNumber
+		msgObj, err := omcilib.ParseCreateRequest(omciPkt)
+		if err == nil {
+			if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
+				if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
+					onuLogger.WithFields(log.Fields{
+						"IntfId":       o.PonPortID,
+						"OnuId":        o.ID,
+						"GemPortId":    msgObj.EntityInstance,
+						"SerialNumber": o.Sn(),
+					}).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
+				} else {
+					onuLogger.WithFields(log.Fields{
+						"IntfId":       o.PonPortID,
+						"OnuId":        o.ID,
+						"GemPortId":    msgObj.EntityInstance,
+						"SerialNumber": o.Sn(),
+					}).Trace("storing-gem-port-id-via-omci")
+					o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
+				}
+			}
+		}
+
+		// if the gemPort is valid then increment the MDS and return a successful response
+		// otherwise fail the request
+		// for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
+		// validation this check will need to be rewritten
+		if !used {
+			if responsePkt, errResp = omcilib.CreateCreateResponse(omciPkt, omciMsg, me.Success); errResp == nil {
+				o.MibDataSync++
+			}
+		} else {
+			responsePkt, _ = omcilib.CreateCreateResponse(omciPkt, omciMsg, me.ProcessingError)
 		}
 	case omci.DeleteRequestType:
+		msgObj, err := omcilib.ParseDeleteRequest(omciPkt)
+		if err == nil {
+			if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
+				onuLogger.WithFields(log.Fields{
+					"IntfId":       o.PonPortID,
+					"OnuId":        o.ID,
+					"GemPortId":    msgObj.EntityInstance,
+					"SerialNumber": o.Sn(),
+				}).Trace("freeing-gem-port-id-via-omci")
+				o.PonPort.removeGemPort(msgObj.EntityInstance)
+			}
+		}
+
 		if responsePkt, errResp = omcilib.CreateDeleteResponse(omciPkt, omciMsg); errResp == nil {
 			o.MibDataSync++
 		}
@@ -1037,6 +1133,7 @@
 
 func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
 	onuLogger.WithFields(log.Fields{
+		"AllocId":           msg.Flow.AllocId,
 		"Cookie":            msg.Flow.Cookie,
 		"DstPort":           msg.Flow.Classifier.DstPort,
 		"FlowId":            msg.Flow.FlowId,
@@ -1123,7 +1220,6 @@
 			"OnuId":        o.ID,
 			"SerialNumber": o.Sn(),
 		}).Info("Resetting GemPort")
-		o.GemPortAdded = false
 
 		// check if ONU delete is performed and
 		// terminate the ONU's ProcessOnuMessages Go routine
@@ -1245,25 +1341,7 @@
 
 		if o.seqNumber > 290 {
 			// NOTE we are done with the MIB Upload (290 is the number of messages the omci-sim library will respond to)
-			galEnet, _ := omcilib.CreateGalEnetRequest(o.getNextTid(false))
-			sendOmciMsg(galEnet, o.PonPortID, o.ID, o.SerialNumber, "CreateGalEnetRequest", client)
-		} else {
-			mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
-			sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
-		}
-	case omci.CreateResponseType:
-		// NOTE Creating a GemPort,
-		// BBsim actually doesn't care about the values, so we can do we want with the parameters
-		// In the same way we can create a GemPort even without setting up UNIs/TConts/...
-		// but we need the GemPort to trigger the state change
-
-		if !o.GemPortAdded {
-			// NOTE this sends a CreateRequestType and BBSim replies with a CreateResponseType
-			// thus we send this request only once
-			gemReq, _ := omcilib.CreateGemPortRequest(o.getNextTid(false))
-			sendOmciMsg(gemReq, o.PonPortID, o.ID, o.SerialNumber, "CreateGemPortRequest", client)
-			o.GemPortAdded = true
-		} else {
+			// start sending the flows, we don't care about the OMCI setup in BBR, just that a lot of messages can go through
 			if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
 				onuLogger.WithFields(log.Fields{
 					"OnuId":  o.ID,
@@ -1271,6 +1349,9 @@
 					"OnuSn":  o.Sn(),
 				}).Errorf("Error while transitioning ONU State %v", err)
 			}
+		} else {
+			mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
+			sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
 		}
 	}
 }
@@ -1290,14 +1371,16 @@
 		UniId:         int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
 		FlowId:        uint64(o.ID),
 		FlowType:      "downstream",
-		AllocId:       int32(0),
 		NetworkIntfId: int32(0),
-		GemportId:     int32(1), // FIXME use the same value as CreateGemPortRequest PortID, do not hardcode
 		Classifier:    &classifierProto,
 		Action:        &actionProto,
 		Priority:      int32(100),
 		Cookie:        uint64(o.ID),
-		PortNo:        uint32(o.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
+		PortNo:        o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
+		// AllocId and GemPorts need to be unique per PON
+		// for now use the ONU-ID, will need to change once we support multiple UNIs
+		AllocId:   int32(o.ID),
+		GemportId: int32(o.ID),
 	}
 
 	if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
@@ -1307,6 +1390,7 @@
 			"FlowId":       downstreamFlow.FlowId,
 			"PortNo":       downstreamFlow.PortNo,
 			"SerialNumber": common.OnuSnToString(o.SerialNumber),
+			"Err":          err,
 		}).Fatalf("Failed to add EAPOL Flow")
 	}
 	log.WithFields(log.Fields{
@@ -1338,14 +1422,16 @@
 		UniId:         int32(0), // FIXME do not hardcode this
 		FlowId:        uint64(o.ID),
 		FlowType:      "downstream",
-		AllocId:       int32(0),
 		NetworkIntfId: int32(0),
-		GemportId:     int32(1), // FIXME use the same value as CreateGemPortRequest PortID, do not hardcode
 		Classifier:    &classifierProto,
 		Action:        &actionProto,
 		Priority:      int32(100),
 		Cookie:        uint64(o.ID),
-		PortNo:        uint32(o.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
+		PortNo:        o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
+		// AllocId and GemPorts need to be unique per PON
+		// for now use the ONU-ID, will need to change once we support multiple UNIs
+		AllocId:   int32(o.ID),
+		GemportId: int32(o.ID),
 	}
 
 	if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
@@ -1355,6 +1441,7 @@
 			"FlowId":       downstreamFlow.FlowId,
 			"PortNo":       downstreamFlow.PortNo,
 			"SerialNumber": common.OnuSnToString(o.SerialNumber),
+			"Err":          err,
 		}).Fatalf("Failed to send DHCP Flow")
 	}
 	log.WithFields(log.Fields{
diff --git a/internal/bbsim/devices/onu_flow_test.go b/internal/bbsim/devices/onu_flow_test.go
index e0ad9fe..b116843 100644
--- a/internal/bbsim/devices/onu_flow_test.go
+++ b/internal/bbsim/devices/onu_flow_test.go
@@ -100,8 +100,6 @@
 		fsm.Callbacks{},
 	)
 
-	onu.GemPortAdded = true
-
 	onu.FlowIds = []uint64{64}
 
 	flow := openolt.Flow{
@@ -115,7 +113,6 @@
 	}
 	onu.handleFlowRemove(msg)
 	assert.Equal(t, len(onu.FlowIds), 0)
-	assert.Equal(t, onu.GemPortAdded, false)
 }
 
 func TestOnu_HhandleEAPOLStart(t *testing.T) {
@@ -429,8 +426,6 @@
 	// one we received with the EAPOL flow
 	onu := createMockOnu(1, 1)
 
-	onu.GemPortAdded = false
-
 	onu.InternalState = fsm.NewFSM(
 		"enabled",
 		fsm.Events{
diff --git a/internal/bbsim/devices/onu_omci_test.go b/internal/bbsim/devices/onu_omci_test.go
index 4b9cc26..4d706b9 100644
--- a/internal/bbsim/devices/onu_omci_test.go
+++ b/internal/bbsim/devices/onu_omci_test.go
@@ -17,6 +17,7 @@
 package devices
 
 import (
+	"github.com/google/gopacket"
 	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
 	omcilib "github.com/opencord/bbsim/internal/common/omci"
 	"github.com/opencord/omci-lib-go"
@@ -27,7 +28,6 @@
 )
 
 var mockAttr = me.AttributeValueMap{
-	"ManagedEntityId":                     12,
 	"PortId":                              0,
 	"TContPointer":                        0,
 	"Direction":                           0,
@@ -46,6 +46,7 @@
 		},
 		Attributes: mockAttr,
 	}
+
 	omciPkt, err := omcilib.Serialize(omci.CreateRequestType, omciReq, 66)
 	if err != nil {
 		t.Fatal(err.Error())
@@ -119,6 +120,34 @@
 	}
 }
 
+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 omciToCreateResponse(t *testing.T, omciPkt *gopacket.Packet) *omci.CreateResponse {
+	msgLayer := (*omciPkt).Layer(omci.LayerTypeCreateResponse)
+	if msgLayer == nil {
+		t.Fatal("omci Msg layer could not be detected for CreateResponse - handling of MibSyncChan stopped")
+	}
+	msgObj, msgOk := msgLayer.(*omci.CreateResponse)
+	if !msgOk {
+		t.Fatal("omci Msg layer could not be assigned for CreateResponse - handling of MibSyncChan stopped")
+	}
+	return msgObj
+}
+
 func Test_MibDataSyncIncrease(t *testing.T) {
 	onu := createMockOnu(1, 1)
 
@@ -174,3 +203,39 @@
 	onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciDeleteRequest(t)), stream)
 	assert.Equal(t, onu.MibDataSync, uint8(0))
 }
+
+func Test_GemPortValidation(t *testing.T) {
+
+	// setup
+	onu := createMockOnu(1, 1)
+
+	stream := &mockStream{
+		Calls: make(map[int]*openolt.Indication),
+	}
+
+	// create a gem port via OMCI (gemPortId 12)
+	onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciCreateRequest(t)), stream)
+
+	// the first time we created the gemPort
+	// the MDS should be incremented
+	assert.Equal(t, stream.CallCount, 1)
+	assert.Equal(t, onu.MibDataSync, uint8(1))
+
+	// and the OMCI response status should be me.Success
+	indication := stream.Calls[1].GetOmciInd()
+	_, omciPkt := omciBytesToMsg(t, indication.Pkt)
+	responseLayer := omciToCreateResponse(t, omciPkt)
+	assert.Equal(t, responseLayer.Result, me.Success)
+
+	// send a request to create the same gem port via OMCI (gemPortId 12)
+	onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciCreateRequest(t)), stream)
+
+	// this time the MDS should not be incremented
+	assert.Equal(t, stream.CallCount, 2)
+	assert.Equal(t, onu.MibDataSync, uint8(1))
+
+	// and the OMCI response status should be me.ProcessingError
+	_, omciPkt = omciBytesToMsg(t, stream.Calls[2].GetOmciInd().Pkt)
+	responseLayer = omciToCreateResponse(t, omciPkt)
+	assert.Equal(t, responseLayer.Result, me.ProcessingError)
+}
diff --git a/internal/bbsim/devices/onu_state_machine_test.go b/internal/bbsim/devices/onu_state_machine_test.go
index 6f62540..f0fd232 100644
--- a/internal/bbsim/devices/onu_state_machine_test.go
+++ b/internal/bbsim/devices/onu_state_machine_test.go
@@ -37,7 +37,6 @@
 	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	onu.PortNo = 16
-	onu.GemPortAdded = true
 	onu.Flows = []FlowKey{
 		{ID: 1, Direction: "upstream"},
 		{ID: 2, Direction: "downstream"},
@@ -46,7 +45,6 @@
 	_ = onu.InternalState.Event(OnuTxDisable)
 	assert.Equal(t, onu.InternalState.Current(), OnuStateDisabled)
 
-	assert.Equal(t, onu.GemPortAdded, false)
 	assert.Equal(t, onu.PortNo, uint32(0))
 	assert.Equal(t, len(onu.Flows), 0)
 }
@@ -95,7 +93,6 @@
 	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	// succeed
-	onu.GemPortAdded = true
 	_ = onu.InternalState.Event("start_auth")
 	assert.Equal(t, onu.InternalState.Current(), "auth_started")
 }
@@ -104,8 +101,6 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.GemPortAdded = true
-
 	onu.InternalState.SetState("auth_started")
 
 	assert.Equal(t, onu.InternalState.Current(), "auth_started")
@@ -168,8 +163,6 @@
 	onu.InternalState.SetState("eap_response_success_received")
 	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
 
-	onu.GemPortAdded = false
-
 	err := onu.InternalState.Event("start_dhcp")
 	if err == nil {
 		t.Fail()
@@ -181,7 +174,6 @@
 func Test_Onu_StateMachine_dhcp_start(t *testing.T) {
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
-	onu.GemPortAdded = true
 
 	onu.InternalState.SetState("eap_response_success_received")
 	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
@@ -195,8 +187,6 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.GemPortAdded = true
-
 	onu.InternalState.SetState("dhcp_started")
 
 	assert.Equal(t, onu.InternalState.Current(), "dhcp_started")
diff --git a/internal/bbsim/devices/onu_test_helpers.go b/internal/bbsim/devices/onu_test_helpers.go
index f0d5dab..2f18199 100644
--- a/internal/bbsim/devices/onu_test_helpers.go
+++ b/internal/bbsim/devices/onu_test_helpers.go
@@ -137,15 +137,16 @@
 // this method creates a fake ONU used in the tests
 func createMockOnu(id uint32, ponPortId uint32) *Onu {
 	o := Onu{
-		ID:           id,
-		PonPortID:    ponPortId,
-		PortNo:       0,
-		GemPortAdded: true,
+		ID:        id,
+		PonPortID: ponPortId,
+		PortNo:    0,
 		PonPort: &PonPort{
-			Olt: &OltDevice{},
+			AllocatedGemPorts: make(map[uint16]*openolt.SerialNumber),
+			AllocatedAllocIds: make(map[uint16]*openolt.SerialNumber),
+			Olt:               &OltDevice{},
 		},
 	}
-	o.SerialNumber = o.NewSN(0, ponPortId, o.ID)
+	o.SerialNumber = NewSN(0, ponPortId, o.ID)
 	o.Channel = make(chan types.Message, 10)
 	return &o
 }
@@ -155,11 +156,10 @@
 	olt := OltDevice{
 		ID: 0,
 	}
-	pon := PonPort{
-		ID:  1,
-		Olt: &olt,
-	}
-	onu := CreateONU(&olt, &pon, 1, time.Duration(1*time.Millisecond), true)
+
+	pon := CreatePonPort(&olt, 1)
+
+	onu := CreateONU(&olt, pon, 1, time.Duration(1*time.Millisecond), true)
 	// NOTE we need this in order to create the OnuChannel
 	_ = onu.InternalState.Event(OnuTxInitialize)
 	onu.DiscoveryRetryDelay = 100 * time.Millisecond
diff --git a/internal/bbsim/devices/pon.go b/internal/bbsim/devices/pon.go
index 1e0483d..3d74eb1 100644
--- a/internal/bbsim/devices/pon.go
+++ b/internal/bbsim/devices/pon.go
@@ -19,6 +19,7 @@
 import (
 	"bytes"
 	"fmt"
+	"sync"
 
 	"github.com/looplab/fsm"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
@@ -37,17 +38,30 @@
 	// PON Attributes
 	OperState *fsm.FSM
 	Type      string
+
+	// Allocated resources
+	// Some resources (eg: OnuId, AllocId and GemPorts) have to be unique per PON port
+	// we are keeping a list so that we can throw an error in cases we receive duplicates
+	AllocatedGemPorts     map[uint16]*openolt.SerialNumber
+	allocatedGemPortsLock sync.RWMutex
+	AllocatedOnuIds       map[uint32]*openolt.SerialNumber
+	allocatedOnuIdsLock   sync.RWMutex
+	AllocatedAllocIds     map[uint16]*openolt.SerialNumber
+	allocatedAllocIdsLock sync.RWMutex
 }
 
 // CreatePonPort creates pon port object
 func CreatePonPort(olt *OltDevice, id uint32) *PonPort {
 
 	ponPort := PonPort{
-		NumOnu: olt.NumOnuPerPon,
-		ID:     id,
-		Type:   "pon",
-		Olt:    olt,
-		Onus:   []*Onu{},
+		NumOnu:            olt.NumOnuPerPon,
+		ID:                id,
+		Type:              "pon",
+		Olt:               olt,
+		Onus:              []*Onu{},
+		AllocatedGemPorts: make(map[uint16]*openolt.SerialNumber),
+		AllocatedOnuIds:   make(map[uint32]*openolt.SerialNumber),
+		AllocatedAllocIds: make(map[uint16]*openolt.SerialNumber),
 	}
 
 	ponPort.InternalState = fsm.NewFSM(
@@ -170,7 +184,7 @@
 	return &ponPort
 }
 
-func (p PonPort) GetOnuBySn(sn *openolt.SerialNumber) (*Onu, error) {
+func (p *PonPort) GetOnuBySn(sn *openolt.SerialNumber) (*Onu, error) {
 	for _, onu := range p.Onus {
 		if bytes.Equal(onu.SerialNumber.VendorSpecific, sn.VendorSpecific) {
 			return onu, nil
@@ -179,7 +193,7 @@
 	return nil, fmt.Errorf("Cannot find Onu with serial number %d in PonPort %d", sn, p.ID)
 }
 
-func (p PonPort) GetOnuById(id uint32) (*Onu, error) {
+func (p *PonPort) GetOnuById(id uint32) (*Onu, error) {
 	for _, onu := range p.Onus {
 		if onu.ID == id {
 			return onu, nil
@@ -189,7 +203,7 @@
 }
 
 // GetNumOfActiveOnus returns number of active ONUs for PON port
-func (p PonPort) GetNumOfActiveOnus() uint32 {
+func (p *PonPort) GetNumOfActiveOnus() uint32 {
 	var count uint32 = 0
 	for _, onu := range p.Onus {
 		if onu.InternalState.Current() == OnuStateInitialized || onu.InternalState.Current() == OnuStateCreated || onu.InternalState.Current() == OnuStateDisabled {
@@ -199,3 +213,111 @@
 	}
 	return count
 }
+
+// storeOnuId adds the Id to the ONU Ids already allocated to this PON port
+func (p *PonPort) storeOnuId(onuId uint32, onuSn *openolt.SerialNumber) {
+	p.allocatedOnuIdsLock.Lock()
+	defer p.allocatedOnuIdsLock.Unlock()
+	p.AllocatedOnuIds[onuId] = onuSn
+}
+
+// removeOnuId removes the OnuId from the allocated resources
+func (p *PonPort) removeOnuId(onuId uint32) {
+	p.allocatedOnuIdsLock.Lock()
+	defer p.allocatedOnuIdsLock.Unlock()
+	delete(p.AllocatedOnuIds, onuId)
+}
+
+func (p *PonPort) removeAllOnuIds() {
+	p.allocatedOnuIdsLock.Lock()
+	defer p.allocatedOnuIdsLock.Unlock()
+	p.AllocatedOnuIds = make(map[uint32]*openolt.SerialNumber)
+}
+
+// isOnuIdAllocated returns whether this OnuId is already in use on this PON
+func (p *PonPort) isOnuIdAllocated(onuId uint32) (bool, *openolt.SerialNumber) {
+	p.allocatedOnuIdsLock.RLock()
+	defer p.allocatedOnuIdsLock.RUnlock()
+
+	if _, ok := p.AllocatedOnuIds[onuId]; ok {
+		return true, p.AllocatedOnuIds[onuId]
+	}
+	return false, nil
+}
+
+// storeGemPort adds the gemPortId to the gemports already allocated to this PON port
+func (p *PonPort) storeGemPort(gemPortId uint16, onuSn *openolt.SerialNumber) {
+	p.allocatedGemPortsLock.Lock()
+	defer p.allocatedGemPortsLock.Unlock()
+	p.AllocatedGemPorts[gemPortId] = onuSn
+}
+
+// removeGemPort removes the gemPortId from the allocated resources
+func (p *PonPort) removeGemPort(gemPortId uint16) {
+	p.allocatedGemPortsLock.Lock()
+	defer p.allocatedGemPortsLock.Unlock()
+	delete(p.AllocatedGemPorts, gemPortId)
+}
+
+func (p *PonPort) removeGemPortBySn(onuSn *openolt.SerialNumber) {
+	p.allocatedGemPortsLock.Lock()
+	defer p.allocatedGemPortsLock.Unlock()
+	for gemPort, sn := range p.AllocatedGemPorts {
+		if sn == onuSn {
+			delete(p.AllocatedGemPorts, gemPort)
+		}
+	}
+}
+
+func (p *PonPort) removeAllGemPorts() {
+	p.allocatedGemPortsLock.Lock()
+	defer p.allocatedGemPortsLock.Unlock()
+	p.AllocatedGemPorts = make(map[uint16]*openolt.SerialNumber)
+}
+
+// isGemPortAllocated returns whether this gemPort is already in use on this PON
+func (p *PonPort) isGemPortAllocated(gemPortId uint16) (bool, *openolt.SerialNumber) {
+	p.allocatedGemPortsLock.RLock()
+	defer p.allocatedGemPortsLock.RUnlock()
+
+	if _, ok := p.AllocatedGemPorts[gemPortId]; ok {
+		return true, p.AllocatedGemPorts[gemPortId]
+	}
+	return false, nil
+}
+
+// storeAllocId adds the Id to the ONU Ids already allocated to this PON port
+func (p *PonPort) storeAllocId(allocId uint16, onuSn *openolt.SerialNumber) {
+	p.allocatedAllocIdsLock.Lock()
+	defer p.allocatedAllocIdsLock.Unlock()
+	p.AllocatedAllocIds[allocId] = onuSn
+}
+
+// removeAllocId removes the AllocId from the allocated resources
+// this is done via SN as the AllocId is not remove but set to a default value
+func (p *PonPort) removeAllocId(onuSn *openolt.SerialNumber) {
+	p.allocatedAllocIdsLock.Lock()
+	defer p.allocatedAllocIdsLock.Unlock()
+	for allocId, sn := range p.AllocatedAllocIds {
+		if sn == onuSn {
+			delete(p.AllocatedAllocIds, allocId)
+		}
+	}
+}
+
+func (p *PonPort) removeAllAllocIds() {
+	p.allocatedAllocIdsLock.Lock()
+	defer p.allocatedAllocIdsLock.Unlock()
+	p.AllocatedAllocIds = make(map[uint16]*openolt.SerialNumber)
+}
+
+// isAllocIdAllocated returns whether this AllocId is already in use on this PON
+func (p *PonPort) isAllocIdAllocated(allocId uint16) (bool, *openolt.SerialNumber) {
+	p.allocatedAllocIdsLock.RLock()
+	defer p.allocatedAllocIdsLock.RUnlock()
+
+	if _, ok := p.AllocatedAllocIds[allocId]; ok {
+		return true, p.AllocatedAllocIds[allocId]
+	}
+	return false, nil
+}
diff --git a/internal/bbsim/devices/pon_test.go b/internal/bbsim/devices/pon_test.go
new file mode 100644
index 0000000..45e1861
--- /dev/null
+++ b/internal/bbsim/devices/pon_test.go
@@ -0,0 +1,151 @@
+/*
+ * 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 (
+	"github.com/opencord/voltha-protos/v4/go/openolt"
+	"github.com/stretchr/testify/assert"
+	"sync"
+	"testing"
+)
+
+var sn1 = NewSN(0, 0, 1)
+var sn2 = NewSN(0, 0, 2)
+var sn3 = NewSN(0, 0, 3)
+
+// NOTE that we are using a benchmark test to actually test concurrency
+func Benchmark_storeGemPort(b *testing.B) {
+	pon := PonPort{
+		AllocatedGemPorts: make(map[uint16]*openolt.SerialNumber),
+	}
+
+	wg := sync.WaitGroup{}
+	wg.Add(3)
+
+	// concurrently add multiple ports
+	go func(wg *sync.WaitGroup) { pon.storeGemPort(1, sn1); wg.Done() }(&wg)
+	go func(wg *sync.WaitGroup) { pon.storeGemPort(2, sn2); wg.Done() }(&wg)
+	go func(wg *sync.WaitGroup) { pon.storeGemPort(3, sn3); wg.Done() }(&wg)
+
+	wg.Wait()
+
+	assert.Equal(b, len(pon.AllocatedGemPorts), 3)
+}
+
+func Benchmark_removeGemPort(b *testing.B) {
+	pon := PonPort{
+		AllocatedGemPorts: make(map[uint16]*openolt.SerialNumber),
+	}
+
+	pon.storeGemPort(1, sn1)
+	pon.storeGemPort(2, sn2)
+	pon.storeGemPort(3, sn3)
+
+	assert.Equal(b, len(pon.AllocatedGemPorts), 3)
+
+	wg := sync.WaitGroup{}
+	wg.Add(3)
+
+	// concurrently add multiple ports
+	go func(wg *sync.WaitGroup) { pon.removeGemPort(1); wg.Done() }(&wg)
+	go func(wg *sync.WaitGroup) { pon.removeGemPort(2); wg.Done() }(&wg)
+	go func(wg *sync.WaitGroup) { pon.removeGemPort(3); wg.Done() }(&wg)
+
+	wg.Wait()
+
+	assert.Equal(b, len(pon.AllocatedGemPorts), 0)
+}
+
+func Test_removeGemPort(t *testing.T) {
+	pon := &PonPort{
+		AllocatedGemPorts: make(map[uint16]*openolt.SerialNumber),
+	}
+
+	pon.storeGemPort(1, sn1)
+	pon.storeGemPort(2, sn2)
+	assert.Equal(t, len(pon.AllocatedGemPorts), 2)
+
+	// remove a non exiting gemPort
+	pon.removeGemPort(3)
+	assert.Equal(t, len(pon.AllocatedGemPorts), 2)
+
+	// remove an existing gemPort
+	pon.removeGemPort(1)
+	assert.Equal(t, len(pon.AllocatedGemPorts), 1)
+
+}
+
+func Test_removeGemPortBySn(t *testing.T) {
+	pon := &PonPort{
+		AllocatedGemPorts: make(map[uint16]*openolt.SerialNumber),
+	}
+
+	pon.storeGemPort(1, sn1)
+	pon.storeGemPort(2, sn2)
+	assert.Equal(t, len(pon.AllocatedGemPorts), 2)
+
+	// remove a non exiting gemPort
+	pon.removeGemPortBySn(sn1)
+	assert.Equal(t, len(pon.AllocatedGemPorts), 1)
+	assert.Nil(t, pon.AllocatedGemPorts[1])
+	assert.Equal(t, pon.AllocatedGemPorts[2], sn2)
+}
+
+func Test_isGemPortAllocated(t *testing.T) {
+	pon := &PonPort{
+		AllocatedGemPorts: make(map[uint16]*openolt.SerialNumber),
+	}
+
+	pon.storeGemPort(1, sn1)
+
+	assert.Equal(t, len(pon.AllocatedGemPorts), 1)
+
+	free, sn := pon.isGemPortAllocated(1)
+
+	assert.Equal(t, free, true)
+	assert.Equal(t, sn, sn1)
+
+	used, sn_ := pon.isGemPortAllocated(2)
+
+	assert.Equal(t, used, false)
+	assert.Nil(t, sn_)
+}
+
+// the allocId is never removed, is always set to either 255 or 65535
+func Test_removeAllocId(t *testing.T) {
+
+	const (
+		allocId1 = 1024
+		allocId2 = 1025
+	)
+
+	pon := &PonPort{
+		AllocatedAllocIds: make(map[uint16]*openolt.SerialNumber),
+	}
+
+	pon.AllocatedAllocIds[allocId1] = sn1
+	pon.AllocatedAllocIds[allocId2] = sn2
+
+	assert.Equal(t, len(pon.AllocatedAllocIds), 2)
+
+	pon.removeAllocId(sn1)
+
+	assert.Equal(t, len(pon.AllocatedAllocIds), 1)
+	assert.Nil(t, pon.AllocatedAllocIds[allocId1])
+	assert.Equal(t, pon.AllocatedAllocIds[allocId2], sn2)
+
+}
diff --git a/internal/bbsim/responders/dhcp/dhcp_test.go b/internal/bbsim/responders/dhcp/dhcp_test.go
index 7b598a0..3334e82 100644
--- a/internal/bbsim/responders/dhcp/dhcp_test.go
+++ b/internal/bbsim/responders/dhcp/dhcp_test.go
@@ -18,7 +18,6 @@
 
 import (
 	"errors"
-	"fmt"
 	"net"
 	"testing"
 
@@ -68,10 +67,6 @@
 	xid2 := macAddressToTxId(mac2)
 	xid3 := macAddressToTxId(mac3)
 
-	fmt.Println(xid1)
-	fmt.Println(xid2)
-	fmt.Println(xid3)
-
 	assert.NotEqual(t, xid1, xid2)
 	assert.NotEqual(t, xid1, xid3)
 	assert.NotEqual(t, xid2, xid3)
diff --git a/internal/bbsim/responders/sadis/sadis_test.go b/internal/bbsim/responders/sadis/sadis_test.go
index 76facb5..a3ca6df 100644
--- a/internal/bbsim/responders/sadis/sadis_test.go
+++ b/internal/bbsim/responders/sadis/sadis_test.go
@@ -38,7 +38,7 @@
 
 	mac := net.HardwareAddr{0x2e, 0x60, 0x01, byte(1), byte(1), byte(0)}
 
-	onu.SerialNumber = onu.NewSN(0, onu.PonPortID, onu.ID)
+	onu.SerialNumber = devices.NewSN(0, onu.PonPortID, onu.ID)
 	onu.Services = []devices.ServiceIf{
 		&devices.Service{Name: "hsia", CTag: 923, STag: 900, NeedsEapol: true, NeedsDhcp: true, NeedsIgmp: true, HwAddress: mac, TechnologyProfileID: 64},
 	}
diff --git a/internal/bbsimctl/commands/helpers.go b/internal/bbsimctl/commands/helpers.go
new file mode 100644
index 0000000..f2a9ee1
--- /dev/null
+++ b/internal/bbsimctl/commands/helpers.go
@@ -0,0 +1,34 @@
+/*
+ * 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 commands
+
+import (
+	pb "github.com/opencord/bbsim/api/bbsim"
+	"github.com/opencord/bbsim/internal/bbsimctl/config"
+	log "github.com/sirupsen/logrus"
+	"google.golang.org/grpc"
+)
+
+func connect() (pb.BBSimClient, *grpc.ClientConn) {
+	conn, err := grpc.Dial(config.GlobalConfig.Server, grpc.WithInsecure())
+
+	if err != nil {
+		log.Fatalf("did not connect: %v", err)
+		return nil, conn
+	}
+	return pb.NewBBSimClient(conn), conn
+}
diff --git a/internal/bbsimctl/commands/olt.go b/internal/bbsimctl/commands/olt.go
index bed3733..1789c86 100644
--- a/internal/bbsimctl/commands/olt.go
+++ b/internal/bbsimctl/commands/olt.go
@@ -22,6 +22,7 @@
 	"fmt"
 	"os"
 	"strconv"
+	"strings"
 
 	"github.com/jessevdk/go-flags"
 	"github.com/olekukonko/tablewriter"
@@ -29,12 +30,13 @@
 	"github.com/opencord/bbsim/internal/bbsimctl/config"
 	"github.com/opencord/cordctl/pkg/format"
 	log "github.com/sirupsen/logrus"
-	"google.golang.org/grpc"
 )
 
 const (
-	DEFAULT_OLT_DEVICE_HEADER_FORMAT = "table{{ .ID }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .IP }}"
-	DEFAULT_PORT_HEADER_FORMAT       = "table{{ .ID }}\t{{ .OperState }}"
+	DEFAULT_OLT_DEVICE_HEADER_FORMAT    = "table{{ .ID }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .IP }}"
+	DEFAULT_OLT_RESOURCES_HEADER_FORMAT = "table{{ .Type }}\t{{ .PonPortId }}\t{{ .OnuId }}\t{{ .PortNo }}\t{{ .ResourceId }}\t{{ .FlowId }}"
+	DEFAULT_NNI_PORT_HEADER_FORMAT      = "table{{ .ID }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .PacketCount }}"
+	DEFAULT_PON_PORT_HEADER_FORMAT      = "table{{ .ID }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .PacketCount }}\t{{ .AllocatedOnuIds }}\t{{ .AllocatedGemPorts }}\t{{ .AllocatedAllocIds }}"
 )
 
 type OltGet struct{}
@@ -64,8 +66,16 @@
 
 type OltShutdownAllOnus struct{}
 
+type oltResourcesType string
+type OltResources struct {
+	Args struct {
+		Type oltResourcesType
+	} `positional-args:"yes" required:"yes"`
+}
+
 type oltOptions struct {
 	Get             OltGet             `command:"get"`
+	GetResources    OltResources       `command:"resources"`
 	NNI             OltNNIs            `command:"nnis"`
 	PON             OltPONs            `command:"pons"`
 	Shutdown        OltShutdown        `command:"shutdown"`
@@ -85,19 +95,12 @@
 }
 
 func getOLT() *pb.Olt {
-	conn, err := grpc.Dial(config.GlobalConfig.Server, grpc.WithInsecure())
-	if err != nil {
-		log.Fatalf("did not connect: %v", err)
-		return nil
-	}
+	client, conn := connect()
 	defer conn.Close()
-	c := pb.NewBBSimClient(conn)
-
-	// Contact the server and print out its response.
 
 	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
 	defer cancel()
-	olt, err := c.GetOlt(ctx, &pb.Empty{})
+	olt, err := client.GetOlt(ctx, &pb.Empty{})
 	if err != nil {
 		log.Fatalf("could not get OLT: %v", err)
 		return nil
@@ -120,12 +123,34 @@
 	return nil
 }
 
+func (o *OltResources) Execute(args []string) error {
+	client, conn := connect()
+	defer conn.Close()
+
+	resourceType := pb.OltAllocatedResourceType_Type_value[string(o.Args.Type)]
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+	resources, err := client.GetOltAllocatedResources(ctx, &pb.OltAllocatedResourceType{Type: pb.OltAllocatedResourceType_Type(resourceType)})
+
+	if err != nil {
+		log.Fatalf("could not get OLT resources: %v", err)
+		return nil
+	}
+
+	tableFormat := format.Format(DEFAULT_OLT_RESOURCES_HEADER_FORMAT)
+	if err := tableFormat.Execute(os.Stdout, true, resources.Resources); err != nil {
+		return err
+	}
+	return nil
+}
+
 func (o *OltNNIs) Execute(args []string) error {
 	olt := getOLT()
 
 	printOltHeader("NNI Ports for", olt)
 
-	tableFormat := format.Format(DEFAULT_PORT_HEADER_FORMAT)
+	tableFormat := format.Format(DEFAULT_NNI_PORT_HEADER_FORMAT)
 	_ = tableFormat.Execute(os.Stdout, true, olt.NNIPorts)
 
 	return nil
@@ -136,7 +161,7 @@
 
 	printOltHeader("PON Ports for", olt)
 
-	tableFormat := format.Format(DEFAULT_PORT_HEADER_FORMAT)
+	tableFormat := format.Format(DEFAULT_PON_PORT_HEADER_FORMAT)
 	_ = tableFormat.Execute(os.Stdout, true, olt.PONPorts)
 
 	return nil
@@ -354,3 +379,13 @@
 	fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
 	return nil
 }
+
+func (rt *oltResourcesType) Complete(match string) []flags.Completion {
+	list := make([]flags.Completion, 0)
+	for k := range pb.OltAllocatedResourceType_Type_value {
+		if strings.HasPrefix(k, strings.ToUpper(match)) && k != pb.OltAllocatedResourceType_UNKNOWN.String() {
+			list = append(list, flags.Completion{Item: k})
+		}
+	}
+	return list
+}
diff --git a/internal/bbsimctl/commands/onu.go b/internal/bbsimctl/commands/onu.go
index 78923e0..33bd5ef 100644
--- a/internal/bbsimctl/commands/onu.go
+++ b/internal/bbsimctl/commands/onu.go
@@ -30,7 +30,6 @@
 	"github.com/opencord/bbsim/internal/bbsimctl/config"
 	"github.com/opencord/cordctl/pkg/format"
 	log "github.com/sirupsen/logrus"
-	"google.golang.org/grpc"
 )
 
 const (
@@ -127,16 +126,6 @@
 	_, _ = parser.AddCommand("onu", "ONU Commands", "Commands to query and manipulate ONU devices", &ONUOptions{})
 }
 
-func connect() (pb.BBSimClient, *grpc.ClientConn) {
-	conn, err := grpc.Dial(config.GlobalConfig.Server, grpc.WithInsecure())
-
-	if err != nil {
-		log.Fatalf("did not connect: %v", err)
-		return nil, conn
-	}
-	return pb.NewBBSimClient(conn), conn
-}
-
 func getONUs() *pb.ONUs {
 
 	client, conn := connect()
diff --git a/internal/common/logger.go b/internal/common/logger.go
index cc6e48d..ce17bb5 100644
--- a/internal/common/logger.go
+++ b/internal/common/logger.go
@@ -21,6 +21,11 @@
 func SetLogLevel(logger *log.Logger, level string, caller bool) {
 
 	logger.SetReportCaller(caller)
+	Formatter := new(log.TextFormatter)
+	Formatter.TimestampFormat = "2006-01-02T15:04:05.999999999Z07:00"
+	Formatter.FullTimestamp = true
+	//Formatter.ForceColors = true
+	logger.SetFormatter(Formatter)
 
 	switch level {
 	case "trace":
diff --git a/internal/common/omci/create.go b/internal/common/omci/create.go
index c1e2b0b..d3c88b3 100644
--- a/internal/common/omci/create.go
+++ b/internal/common/omci/create.go
@@ -42,7 +42,7 @@
 	return msgObj, nil
 }
 
-func CreateCreateResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+func CreateCreateResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, result me.Results) ([]byte, error) {
 
 	msgObj, err := ParseCreateRequest(omciPkt)
 
@@ -60,7 +60,7 @@
 			EntityClass:    msgObj.EntityClass,
 			EntityInstance: msgObj.EntityInstance,
 		},
-		Result: me.Success,
+		Result: result,
 	}
 
 	pkt, err := Serialize(omci.CreateResponseType, response, omciMsg.TransactionID)
@@ -78,75 +78,3 @@
 
 	return pkt, nil
 }
-
-// methods used by BBR to drive the OMCI state machine
-
-func CreateGalEnetRequest(tid uint16) ([]byte, error) {
-	params := me.ParamData{
-		EntityID:   1,
-		Attributes: me.AttributeValueMap{"MaximumGemPayloadSize": 48},
-	}
-	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: 1,
-		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/create_test.go b/internal/common/omci/create_test.go
new file mode 100644
index 0000000..33d3a3e
--- /dev/null
+++ b/internal/common/omci/create_test.go
@@ -0,0 +1,103 @@
+/*
+ * 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 omciToCreateResponse(t *testing.T, omciPkt *gopacket.Packet) *omci.CreateResponse {
+	msgLayer := (*omciPkt).Layer(omci.LayerTypeCreateResponse)
+	if msgLayer == nil {
+		t.Fatal("omci Msg layer could not be detected for CreateResponse - handling of MibSyncChan stopped")
+	}
+	msgObj, msgOk := msgLayer.(*omci.CreateResponse)
+	if !msgOk {
+		t.Fatal("omci Msg layer could not be assigned for CreateResponse - handling of MibSyncChan stopped")
+	}
+	return msgObj
+}
+
+type createArgs struct {
+	omciPkt []byte
+	result  me.Results
+}
+
+type createWant struct {
+	result me.Results
+}
+
+func TestCreateResponse(t *testing.T) {
+
+	// generate a CreateRequest packet to create a GemPort
+	omciReq := &omci.CreateRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.GemPortNetworkCtpClassID,
+			EntityInstance: 12,
+		},
+		Attributes: me.AttributeValueMap{
+			"PortId":                              0,
+			"TContPointer":                        0,
+			"Direction":                           0,
+			"TrafficManagementPointerForUpstream": 0,
+			"TrafficDescriptorProfilePointerForUpstream":   0,
+			"PriorityQueuePointerForDownStream":            0,
+			"TrafficDescriptorProfilePointerForDownstream": 0,
+			"EncryptionKeyRing":                            0,
+		},
+	}
+	omciPkt, err := Serialize(omci.CreateRequestType, omciReq, 66)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	omciPkt, _ = HexEncode(omciPkt)
+
+	tests := []struct {
+		name string
+		args createArgs
+		want createWant
+	}{
+		{"createSuccess",
+			createArgs{omciPkt, me.Success},
+			createWant{me.Success},
+		},
+		{"createProcessingError",
+			createArgs{omciPkt, me.ProcessingError},
+			createWant{me.ProcessingError},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			pkt, msg, _ := ParseOpenOltOmciPacket(tt.args.omciPkt)
+			requestPkt, _ := CreateCreateResponse(pkt, msg, tt.args.result)
+
+			omciMsg, omciPkt := omciBytesToMsg(t, requestPkt)
+
+			assert.Equal(t, omciMsg.MessageType, omci.CreateResponseType)
+
+			getResponseLayer := omciToCreateResponse(t, omciPkt)
+
+			assert.Equal(t, getResponseLayer.Result, tt.want.result)
+
+		})
+	}
+}
diff --git a/internal/common/omci/get_test.go b/internal/common/omci/get_test.go
index ca580ed..d995bba 100644
--- a/internal/common/omci/get_test.go
+++ b/internal/common/omci/get_test.go
@@ -55,12 +55,12 @@
 	return msgObj
 }
 
-type args struct {
+type getArgs struct {
 	generatedPkt  *omci.GetResponse
 	transactionId uint16
 }
 
-type want struct {
+type getWant struct {
 	transactionId uint16
 	attributes    map[string]interface{}
 }
@@ -77,20 +77,20 @@
 
 	tests := []struct {
 		name string
-		args args
-		want want
+		args getArgs
+		want getWant
 	}{
 		{"getOnu2gResponse",
-			args{createOnu2gResponse(57344, 10), 1},
-			want{1, map[string]interface{}{"OpticalNetworkUnitManagementAndControlChannelOmccVersion": uint8(180)}},
+			getArgs{createOnu2gResponse(57344, 10), 1},
+			getWant{1, map[string]interface{}{"OpticalNetworkUnitManagementAndControlChannelOmccVersion": uint8(180)}},
 		},
 		{"getOnugResponse",
-			args{createOnugResponse(40960, 10, sn), 1},
-			want{1, map[string]interface{}{}},
+			getArgs{createOnugResponse(40960, 10, sn), 1},
+			getWant{1, map[string]interface{}{}},
 		},
 		{"getOnuDataResponse",
-			args{createOnuDataResponse(32768, 10, 129), 2},
-			want{2, map[string]interface{}{"MibDataSync": uint8(129)}},
+			getArgs{createOnuDataResponse(32768, 10, 129), 2},
+			getWant{2, map[string]interface{}{"MibDataSync": uint8(129)}},
 		},
 	}
 	for _, tt := range tests {
diff --git a/internal/common/omci/set.go b/internal/common/omci/set.go
index 64f048f..73e17df 100644
--- a/internal/common/omci/set.go
+++ b/internal/common/omci/set.go
@@ -40,7 +40,7 @@
 	return msgObj, nil
 }
 
-func CreateSetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+func CreateSetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, result me.Results) ([]byte, error) {
 
 	msgObj, err := ParseSetRequest(omciPkt)
 
@@ -59,7 +59,7 @@
 			EntityClass:    msgObj.EntityClass,
 			EntityInstance: msgObj.EntityInstance,
 		},
-		Result: me.Success,
+		Result: result,
 	}
 
 	pkt, err := Serialize(omci.SetResponseType, response, omciMsg.TransactionID)
diff --git a/vendor/github.com/opencord/omci-lib-go/VERSION b/vendor/github.com/opencord/omci-lib-go/VERSION
index 2a0970c..201a22c 100644
--- a/vendor/github.com/opencord/omci-lib-go/VERSION
+++ b/vendor/github.com/opencord/omci-lib-go/VERSION
@@ -1 +1 @@
-0.16.1
+0.16.2
diff --git a/vendor/github.com/opencord/omci-lib-go/messagetypes.go b/vendor/github.com/opencord/omci-lib-go/messagetypes.go
index 42a0d42..f0ff447 100644
--- a/vendor/github.com/opencord/omci-lib-go/messagetypes.go
+++ b/vendor/github.com/opencord/omci-lib-go/messagetypes.go
@@ -271,7 +271,7 @@
 // DecodeFromBytes decodes the given bytes of a Create Response into this layer
 func (omci *CreateResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+3)
 	if err != nil {
 		return err
 	}
@@ -397,7 +397,7 @@
 // DecodeFromBytes decodes the given bytes of a Delete Response into this layer
 func (omci *DeleteResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -460,7 +460,7 @@
 // DecodeFromBytes decodes the given bytes of a Set Request into this layer
 func (omci *SetRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -567,7 +567,7 @@
 // DecodeFromBytes decodes the given bytes of a Set Response into this layer
 func (omci *SetResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 5)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+5)
 	if err != nil {
 		return err
 	}
@@ -636,7 +636,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Request into this layer
 func (omci *GetRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -703,7 +703,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Response into this layer
 func (omci *GetResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+3)
 	if err != nil {
 		return err
 	}
@@ -870,7 +870,7 @@
 // DecodeFromBytes decodes the given bytes of a Get All Alarms Request into this layer
 func (omci *GetAllAlarmsRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -948,7 +948,7 @@
 // DecodeFromBytes decodes the given bytes of a Get All Alarms Response into this layer
 func (omci *GetAllAlarmsResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -1021,7 +1021,7 @@
 // DecodeFromBytes decodes the given bytes of a Get All Alarms Next Request into this layer
 func (omci *GetAllAlarmsNextRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -1097,7 +1097,7 @@
 // DecodeFromBytes decodes the given bytes of a Get All Alarms Next Response into this layer
 func (omci *GetAllAlarmsNextResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 4 + 28)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+4+28)
 	if err != nil {
 		return err
 	}
@@ -1240,7 +1240,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Upload Response into this layer
 func (omci *MibUploadResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -1313,7 +1313,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Upload Next Request into this layer
 func (omci *MibUploadNextRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -1386,7 +1386,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Upload Next Response into this layer
 func (omci *MibUploadNextResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 6)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+6)
 	if err != nil {
 		return err
 	}
@@ -1511,7 +1511,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Reset Response into this layer
 func (omci *MibResetResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -1684,7 +1684,7 @@
 // DecodeFromBytes decodes the given bytes of an Alarm Notification into this layer
 func (omci *AlarmNotificationMsg) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 28)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+28)
 	if err != nil {
 		return err
 	}
@@ -1770,7 +1770,7 @@
 // DecodeFromBytes decodes the given bytes of an Attribute Value Change notification into this layer
 func (omci *AttributeValueChangeMsg) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -1855,7 +1855,7 @@
 // DecodeFromBytes decodes the given bytes of a Test Request into this layer
 func (omci *TestRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 5)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+5)
 	if err != nil {
 		return err
 	}
@@ -1891,7 +1891,7 @@
 // DecodeFromBytes decodes the given bytes of a Test Response into this layer
 func (omci *TestResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -1931,7 +1931,7 @@
 
 // DecodeFromBytes decodes the given bytes of a Start Software Download Request into this layer
 func (omci *StartSoftwareDownloadRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 4)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+4)
 	if err != nil {
 		return err
 	}
@@ -2033,7 +2033,7 @@
 // DecodeFromBytes decodes the given bytes of a Start Software Download Response into this layer
 func (omci *StartSoftwareDownloadResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+3)
 	if err != nil {
 		return err
 	}
@@ -2155,7 +2155,7 @@
 // DecodeFromBytes decodes the given bytes of a Download Section Request into this layer
 func (omci *DownloadSectionRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -2228,7 +2228,7 @@
 // DecodeFromBytes decodes the given bytes of a Download Section Response into this layer
 func (omci *DownloadSectionResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -2313,7 +2313,7 @@
 // DecodeFromBytes decodes the given bytes of an End Software Download Request into this layer
 func (omci *EndSoftwareDownloadRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 7)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+7)
 	if err != nil {
 		return err
 	}
@@ -2406,7 +2406,7 @@
 // DecodeFromBytes decodes the given bytes of an End Software Download Response into this layer
 func (omci *EndSoftwareDownloadResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -2525,7 +2525,7 @@
 // DecodeFromBytes decodes the given bytes of an Activate Software Request into this layer
 func (omci *ActivateSoftwareRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -2604,7 +2604,7 @@
 // DecodeFromBytes decodes the given bytes of an Activate Softwre Response into this layer
 func (omci *ActivateSoftwareResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -2735,6 +2735,7 @@
 //
 type CommitSoftwareResponse struct {
 	MeBasePacket
+	Result me.Results
 }
 
 func (omci *CommitSoftwareResponse) String() string {
@@ -2744,7 +2745,7 @@
 // DecodeFromBytes decodes the given bytes of a Commit Softwar Response into this layer
 func (omci *CommitSoftwareResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -2753,7 +2754,7 @@
 	if omciErr.StatusCode() != me.Success {
 		return omciErr.GetError()
 	}
-	// ME needs to support End Software Download
+	// ME needs to support Commit Software
 	if !me.SupportsMsgType(meDefinition, me.CommitSoftware) {
 		return me.NewProcessingError("managed entity does not support Commit Software Message-Type")
 	}
@@ -2761,6 +2762,12 @@
 	if omci.EntityClass != me.SoftwareImageClassID {
 		return me.NewProcessingError("invalid Entity Class for Commit Software response")
 	}
+	omci.Result = me.Results(data[4])
+	if omci.Result > me.Results(6) {
+		msg := fmt.Sprintf("invalid results for Commit Software response: %v, must be 0..6",
+			omci.Result)
+		return errors.New(msg)
+	}
 	return nil
 }
 
@@ -2782,7 +2789,7 @@
 	if omciErr.StatusCode() != me.Success {
 		return omciErr.GetError()
 	}
-	// ME needs to support End Software Download
+	// ME needs to support Commit Software
 	if !me.SupportsMsgType(meDefinition, me.CommitSoftware) {
 		return me.NewProcessingError("managed entity does not support Commit Message-Type")
 	}
@@ -2790,6 +2797,16 @@
 	if omci.EntityClass != me.SoftwareImageClassID {
 		return me.NewProcessingError("invalid Entity Class for Commit Software response")
 	}
+	bytes, err := b.AppendBytes(1)
+	if err != nil {
+		return err
+	}
+	bytes[0] = byte(omci.Result)
+	if omci.Result > me.Results(6) {
+		msg := fmt.Sprintf("invalid results for Commit Software response: %v, must be 0..6",
+			omci.Result)
+		return errors.New(msg)
+	}
 	return nil
 }
 
@@ -2813,7 +2830,7 @@
 // DecodeFromBytes decodes the given bytes of a Synchronize Time Request into this layer
 func (omci *SynchronizeTimeRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 7)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+7)
 	if err != nil {
 		return err
 	}
@@ -2893,7 +2910,7 @@
 // DecodeFromBytes decodes the given bytes of a Synchronize Time Response into this layer
 func (omci *SynchronizeTimeResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -2981,7 +2998,7 @@
 // DecodeFromBytes decodes the given bytes of a Reboot Request into this layer
 func (omci *RebootRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -3052,7 +3069,7 @@
 // DecodeFromBytes decodes the given bytes of a Reboot Response into this layer
 func (omci *RebootResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
 	if err != nil {
 		return err
 	}
@@ -3123,7 +3140,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Next Request into this layer
 func (omci *GetNextRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 4)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+4)
 	if err != nil {
 		return err
 	}
@@ -3194,7 +3211,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Next Response into this layer
 func (omci *GetNextResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+3)
 	if err != nil {
 		return err
 	}
@@ -3350,7 +3367,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Current Data Request into this layer
 func (omci *GetCurrentDataRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+2)
 	if err != nil {
 		return err
 	}
@@ -3416,7 +3433,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Current Data Respnse into this layer
 func (omci *GetCurrentDataResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+3)
 	if err != nil {
 		return err
 	}
@@ -3503,7 +3520,7 @@
 // DecodeFromBytes decodes the given bytes of a Set Table Request into this layer
 func (omci *SetTableRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 6 + 2)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 6+2)
 	if err != nil {
 		return err
 	}
@@ -3540,7 +3557,7 @@
 // DecodeFromBytes decodes the given bytes of a Set Table Response into this layer
 func (omci *SetTableResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p, 6 + 1)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 6+1)
 	if err != nil {
 		return err
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 93d6658..ddc585d 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -74,7 +74,7 @@
 github.com/opencord/cordctl/pkg/format
 # github.com/opencord/device-management-interface v0.11.0
 github.com/opencord/device-management-interface/go/dmi
-# github.com/opencord/omci-lib-go v0.16.1
+# github.com/opencord/omci-lib-go v0.16.2
 github.com/opencord/omci-lib-go
 github.com/opencord/omci-lib-go/generated
 # github.com/opencord/voltha-protos/v4 v4.0.15