[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/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)
+}