[VOL-3744] Adding MDS support to BBSim

Change-Id: If16511922a032511084c42727c8203ab9c9e75ec
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 36fbb3e..86c70ba 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -79,6 +79,9 @@
 	Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
 
 	// OMCI params
+	MibDataSync uint8
+
+	// OMCI params (Used in BBR)
 	tid       uint16
 	hpTid     uint16
 	seqNumber uint16
@@ -92,13 +95,6 @@
 }
 
 func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, isMock bool) *Onu {
-	b := &backoff.Backoff{
-		//These are the defaults
-		Min:    5 * time.Second,
-		Max:    35 * time.Second,
-		Factor: 1.5,
-		Jitter: false,
-	}
 
 	o := Onu{
 		ID:                  id,
@@ -113,7 +109,7 @@
 		DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
 		Flows:               []FlowKey{},
 		DiscoveryDelay:      delay,
-		Backoff:             b,
+		MibDataSync:         0,
 	}
 	o.SerialNumber = o.NewSN(olt.ID, pon.ID, id)
 	// NOTE this state machine is used to track the operational
@@ -292,6 +288,7 @@
 				msg, _ := message.Data.(bbsim.OnuIndicationMessage)
 				o.sendOnuIndication(msg, stream)
 			case bbsim.OMCI:
+				// these are OMCI messages received by the ONU
 				msg, _ := message.Data.(bbsim.OmciMessage)
 				o.handleOmciRequest(msg, stream)
 			case bbsim.UniStatusAlarm:
@@ -374,6 +371,7 @@
 				}
 				// BBR specific messages
 			case bbsim.OmciIndication:
+				// these are OMCI messages received by BBR (VOLTHA emulator)
 				msg, _ := message.Data.(bbsim.OmciIndicationMessage)
 				o.handleOmciResponse(msg, client)
 			case bbsim.SendEapolFlow:
@@ -644,14 +642,21 @@
 	var responsePkt []byte
 	switch omciMsg.MessageType {
 	case omci.MibResetRequestType:
+		o.MibDataSync = 0
+		onuLogger.WithFields(log.Fields{
+			"IntfId":       o.PonPortID,
+			"OnuId":        o.ID,
+			"SerialNumber": o.Sn(),
+		}).Debug("received-mib-reset-request-resetting-mds")
 		responsePkt, _ = omcilib.CreateMibResetResponse(omciMsg.TransactionID)
 	case omci.MibUploadRequestType:
 		responsePkt, _ = omcilib.CreateMibUploadResponse(omciMsg.TransactionID)
 	case omci.MibUploadNextRequestType:
-		responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg)
+		responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg, o.MibDataSync)
 	case omci.GetRequestType:
-		responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg, o.SerialNumber)
+		responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg, o.SerialNumber, o.MibDataSync)
 	case omci.SetRequestType:
+		o.MibDataSync++
 		responsePkt, _ = omcilib.CreateSetResponse(omciPkt, omciMsg)
 
 		msgObj, _ := omcilib.ParseSetRequest(omciPkt)
@@ -679,8 +684,10 @@
 			}
 		}
 	case omci.CreateRequestType:
+		o.MibDataSync++
 		responsePkt, _ = omcilib.CreateCreateResponse(omciPkt, omciMsg)
 	case omci.DeleteRequestType:
+		o.MibDataSync++
 		responsePkt, _ = omcilib.CreateDeleteResponse(omciPkt, omciMsg)
 	case omci.RebootRequestType:
 
diff --git a/internal/bbsim/devices/onu_omci_test.go b/internal/bbsim/devices/onu_omci_test.go
new file mode 100644
index 0000000..4b9cc26
--- /dev/null
+++ b/internal/bbsim/devices/onu_omci_test.go
@@ -0,0 +1,176 @@
+/*
+ * 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 (
+	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+	omcilib "github.com/opencord/bbsim/internal/common/omci"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/voltha-protos/v4/go/openolt"
+	"gotest.tools/assert"
+	"testing"
+)
+
+var mockAttr = me.AttributeValueMap{
+	"ManagedEntityId":                     12,
+	"PortId":                              0,
+	"TContPointer":                        0,
+	"Direction":                           0,
+	"TrafficManagementPointerForUpstream": 0,
+	"TrafficDescriptorProfilePointerForUpstream":   0,
+	"PriorityQueuePointerForDownStream":            0,
+	"TrafficDescriptorProfilePointerForDownstream": 0,
+	"EncryptionKeyRing":                            0,
+}
+
+func makeOmciCreateRequest(t *testing.T) []byte {
+	omciReq := &omci.CreateRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.GemPortNetworkCtpClassID,
+			EntityInstance: 12,
+		},
+		Attributes: mockAttr,
+	}
+	omciPkt, err := omcilib.Serialize(omci.CreateRequestType, omciReq, 66)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	omciPkt, _ = omcilib.HexEncode(omciPkt)
+
+	return omciPkt
+}
+
+func makeOmciSetRequest(t *testing.T) []byte {
+	omciReq := &omci.SetRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.GemPortNetworkCtpClassID,
+			EntityInstance: 12,
+		},
+		Attributes: mockAttr,
+	}
+	omciPkt, err := omcilib.Serialize(omci.SetRequestType, omciReq, 66)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	omciPkt, _ = omcilib.HexEncode(omciPkt)
+
+	return omciPkt
+}
+
+func makeOmciDeleteRequest(t *testing.T) []byte {
+	omciReq := &omci.DeleteRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.GemPortNetworkCtpClassID,
+			EntityInstance: 12,
+		},
+	}
+	omciPkt, err := omcilib.Serialize(omci.DeleteRequestType, omciReq, 66)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	omciPkt, _ = omcilib.HexEncode(omciPkt)
+
+	return omciPkt
+}
+
+func makeOmciMibResetRequest(t *testing.T) []byte {
+	omciReq := &omci.MibResetRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.OnuDataClassID,
+		},
+	}
+	omciPkt, err := omcilib.Serialize(omci.MibResetRequestType, omciReq, 66)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	omciPkt, _ = omcilib.HexEncode(omciPkt)
+
+	return omciPkt
+}
+
+func makeOmciMessage(t *testing.T, onu *Onu, pkt []byte) bbsim.OmciMessage {
+	return bbsim.OmciMessage{
+		OnuSN: onu.SerialNumber,
+		OnuID: onu.ID,
+		OmciMsg: &openolt.OmciMsg{
+			IntfId: onu.PonPortID,
+			OnuId:  onu.ID,
+			Pkt:    pkt,
+		},
+	}
+}
+
+func Test_MibDataSyncIncrease(t *testing.T) {
+	onu := createMockOnu(1, 1)
+
+	assert.Equal(t, onu.MibDataSync, uint8(0))
+
+	stream := &mockStream{
+		Calls: make(map[int]*openolt.Indication),
+	}
+
+	// send a Create and check that MDS has been increased
+	onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciCreateRequest(t)), stream)
+	assert.Equal(t, onu.MibDataSync, uint8(1))
+
+	// send a Set and check that MDS has been increased
+	onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciSetRequest(t)), stream)
+	assert.Equal(t, onu.MibDataSync, uint8(2))
+
+	// send a Delete and check that MDS has been increased
+	onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciDeleteRequest(t)), stream)
+	assert.Equal(t, onu.MibDataSync, uint8(3))
+
+	// TODO once supported MDS should increase for:
+	// - Start software download
+	// - End software download
+	// - Activate software
+	// - Commit software
+}
+
+func Test_MibDataSyncReset(t *testing.T) {
+	onu := createMockOnu(1, 1)
+	onu.MibDataSync = 192
+	assert.Equal(t, onu.MibDataSync, uint8(192))
+
+	stream := &mockStream{
+		Calls: make(map[int]*openolt.Indication),
+	}
+
+	// send a MibReset and check that MDS has reset to 0
+	onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciMibResetRequest(t)), stream)
+	assert.Equal(t, onu.MibDataSync, uint8(0))
+}
+
+func Test_MibDataSyncRotation(t *testing.T) {
+	onu := createMockOnu(1, 1)
+	onu.MibDataSync = 255
+	assert.Equal(t, onu.MibDataSync, uint8(255))
+
+	stream := &mockStream{
+		Calls: make(map[int]*openolt.Indication),
+	}
+
+	// send a request that increases the MDS, but once we're at 255 we should go back to 0 (8bit)
+	onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciDeleteRequest(t)), stream)
+	assert.Equal(t, onu.MibDataSync, uint8(0))
+}