blob: 7f1d5ee05ab2470ba00456d28f1c983c3124a6d5 [file] [log] [blame]
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package devices
18
19import (
Matteo Scandolob5913142021-03-19 16:10:18 -070020 "context"
Matteo Scandoloa8eca492021-03-23 09:45:16 -070021 "fmt"
Matteo Scandolob5913142021-03-19 16:10:18 -070022 "github.com/looplab/fsm"
Matteo Scandolof9d43412021-01-12 11:11:34 -080023 "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandolob5913142021-03-19 16:10:18 -070024 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandolo4a036262020-08-17 15:56:13 -070025 "github.com/opencord/bbsim/internal/common"
Matteo Scandolo21195d62021-04-07 14:31:23 -070026 "github.com/opencord/voltha-protos/v4/go/openolt"
Matteo Scandoloa8eca492021-03-23 09:45:16 -070027 "github.com/stretchr/testify/assert"
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070028 "net"
Matteo Scandolo21195d62021-04-07 14:31:23 -070029 "sync"
Matteo Scandolo10f965c2019-09-24 10:40:46 -070030 "testing"
31)
32
Matteo Scandolo8a574812021-05-20 15:18:53 -070033func createMockOlt(numPon int, numOnu int, numUni int, services []ServiceIf) *OltDevice {
Shrey Baid688b4242020-07-10 20:40:10 +053034 olt := &OltDevice{
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +020035 ID: 0,
36 AllocIDs: make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
37 GemPortIDs: make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
38 OmciResponseRate: 10,
Matteo Scandolo10f965c2019-09-24 10:40:46 -070039 }
40
41 for i := 0; i < numPon; i++ {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080042
43 // initialize the resource maps for every PON Ports
44 olt.AllocIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
45 olt.GemPortIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
46
Matteo Scandolo10f965c2019-09-24 10:40:46 -070047 pon := PonPort{
48 ID: uint32(i),
49 }
50
51 for j := 0; j < numOnu; j++ {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080052
53 // initialize the resource maps for every ONU and the first UNI
54 olt.AllocIDs[uint32(i)][uint32(j)] = make(map[uint32]map[int32]map[uint64]bool)
55 olt.GemPortIDs[uint32(i)][uint32(j)] = make(map[uint32]map[int32]map[uint64]bool)
56
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070057 onuId := uint32(i + j)
Matteo Scandolo10f965c2019-09-24 10:40:46 -070058 onu := Onu{
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070059 ID: onuId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070060 PonPort: &pon,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070061 PonPortID: pon.ID,
Matteo Scandolob5913142021-03-19 16:10:18 -070062 InternalState: fsm.NewFSM(
63 OnuStateCreated,
64 // this is fake state machine, we don't care about transition in the OLT
65 // unit tests, we'll use SetState to emulate cases
66 fsm.Events{
67 {Name: OnuTxEnable, Src: []string{}, Dst: OnuStateEnabled},
68 {Name: OnuTxDisable, Src: []string{}, Dst: OnuStateDisabled},
69 },
70 fsm.Callbacks{},
71 ),
72 Channel: make(chan bbsim.Message, 2048),
Matteo Scandolo10f965c2019-09-24 10:40:46 -070073 }
Matteo Scandolo4a036262020-08-17 15:56:13 -070074
Matteo Scandolo8a574812021-05-20 15:18:53 -070075 for k := 0; k < uniPorts; k++ {
76 uni := UniPort{
77 ID: uint32(k + 1),
78 Onu: &onu,
79 logger: uniLogger,
80 }
81 for l, s := range services {
82 service := s.(*Service)
83 service.HwAddress = net.HardwareAddr{0x2e, byte(olt.ID), byte(pon.ID), byte(onuId), byte(k), byte(l)}
84 service.UniPort = &uni
85 uni.Services = append(uni.Services, service)
86 }
87 onu.UniPorts = append(onu.UniPorts, &uni)
Matteo Scandolo4a036262020-08-17 15:56:13 -070088 }
89
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080090 onu.SerialNumber = NewSN(olt.ID, pon.ID, onu.ID)
Matteo Scandolo27428702019-10-11 16:21:16 -070091 pon.Onus = append(pon.Onus, &onu)
Matteo Scandolo10f965c2019-09-24 10:40:46 -070092 }
Matteo Scandolo27428702019-10-11 16:21:16 -070093 olt.Pons = append(olt.Pons, &pon)
Matteo Scandolo10f965c2019-09-24 10:40:46 -070094 }
95 return olt
96}
97
Matteo Scandolo4a036262020-08-17 15:56:13 -070098// check the creation of an OLT with a single Service
99func TestCreateOLT(t *testing.T) {
100
101 common.Services = []common.ServiceYaml{
Matteo Scandolo8a574812021-05-20 15:18:53 -0700102 {Name: "hsia", CTag: 900, CTagAllocation: common.TagAllocationUnique.String(), STag: 900, STagAllocation: common.TagAllocationShared.String(), NeedsEapol: true, NeedsDhcp: true, NeedsIgmp: true},
Matteo Scandolo4a036262020-08-17 15:56:13 -0700103 }
104
105 common.Config = &common.GlobalConfig{
106 Olt: common.OltConfig{
107 ID: 1,
108 PonPorts: 2,
109 OnusPonPort: 2,
110 },
111 }
112
113 olt := CreateOLT(*common.Config, common.Services, true)
114
115 assert.Equal(t, len(olt.Pons), int(common.Config.Olt.PonPorts))
116
117 // count the ONUs
118 onus := 0
119 for _, p := range olt.Pons {
120 onus = onus + len(p.Onus)
121 }
122
123 assert.Equal(t, onus, int(common.Config.Olt.PonPorts*common.Config.Olt.OnusPonPort))
124
Matteo Scandolo8a574812021-05-20 15:18:53 -0700125 // counte the UNIs
126 unis := 0
127 for _, p := range olt.Pons {
128 for _, o := range p.Onus {
129 unis = unis + len(o.UniPorts)
130 }
131 }
132 // NOTE when unis will be configurable this test will need to adapt
133 assert.Equal(t, unis, int(common.Config.Olt.PonPorts*common.Config.Olt.OnusPonPort*uniPorts))
134
Matteo Scandolo4a036262020-08-17 15:56:13 -0700135 // count the services
136 services := 0
137 for _, p := range olt.Pons {
138 for _, o := range p.Onus {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700139 for _, u := range o.UniPorts {
140 uni := u.(*UniPort)
141 services = services + len(uni.Services)
142 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700143 }
144 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700145 // NOTE when unis will be configurable this test will need to adapt
146 assert.Equal(t, services, int(common.Config.Olt.PonPorts)*int(common.Config.Olt.OnusPonPort)*uniPorts*len(common.Services))
Matteo Scandolo4a036262020-08-17 15:56:13 -0700147
Matteo Scandolo8a574812021-05-20 15:18:53 -0700148 s1 := olt.Pons[0].Onus[0].UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700149
150 assert.Equal(t, s1.Name, "hsia")
151 assert.Equal(t, s1.CTag, 900)
152 assert.Equal(t, s1.STag, 900)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700153 assert.Equal(t, "2e:01:00:01:00:00", s1.HwAddress.String())
Matteo Scandolo4a036262020-08-17 15:56:13 -0700154 assert.Equal(t, olt.Pons[0].Onus[0].ID, uint32(1))
155
Matteo Scandolo8a574812021-05-20 15:18:53 -0700156 // each ONU has 4 UNIs, taking up the c-tags
157 s2 := olt.Pons[0].Onus[1].UniPorts[0].(*UniPort).Services[0].(*Service)
158 assert.Equal(t, s2.CTag, 904)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700159 assert.Equal(t, s2.STag, 900)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700160 assert.Equal(t, s2.HwAddress.String(), "2e:01:00:02:00:00")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700161 assert.Equal(t, olt.Pons[0].Onus[1].ID, uint32(2))
162
Matteo Scandolo8a574812021-05-20 15:18:53 -0700163 s3 := olt.Pons[1].Onus[0].UniPorts[0].(*UniPort).Services[0].(*Service)
164 assert.Equal(t, s3.CTag, 908)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700165 assert.Equal(t, s3.STag, 900)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700166 assert.Equal(t, s3.HwAddress.String(), "2e:01:01:01:00:00")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700167 assert.Equal(t, olt.Pons[1].Onus[0].ID, uint32(1))
168
Matteo Scandolo8a574812021-05-20 15:18:53 -0700169 s4 := olt.Pons[1].Onus[1].UniPorts[0].(*UniPort).Services[0].(*Service)
170 assert.Equal(t, s4.CTag, 912)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700171 assert.Equal(t, s4.STag, 900)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700172 assert.Equal(t, s4.HwAddress.String(), "2e:01:01:02:00:00")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700173 assert.Equal(t, olt.Pons[1].Onus[1].ID, uint32(2))
174}
175
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700176func Test_Olt_FindOnuBySn_Success(t *testing.T) {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700177
178 numPon := 4
179 numOnu := 4
180
Matteo Scandolo8a574812021-05-20 15:18:53 -0700181 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700182
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700183 onu, err := olt.FindOnuBySn("BBSM00000303")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700184
185 assert.Equal(t, err, nil)
186 assert.Equal(t, onu.Sn(), "BBSM00000303")
187 assert.Equal(t, onu.ID, uint32(3))
188 assert.Equal(t, onu.PonPortID, uint32(3))
189}
190
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700191func Test_Olt_FindOnuBySn_Error(t *testing.T) {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700192
193 numPon := 1
194 numOnu := 4
195
Matteo Scandolo8a574812021-05-20 15:18:53 -0700196 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700197
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700198 _, err := olt.FindOnuBySn("BBSM00000303")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700199
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700200 assert.Equal(t, err.Error(), "cannot-find-onu-by-serial-number-BBSM00000303")
201}
202
203func Test_Olt_FindOnuByMacAddress_Success(t *testing.T) {
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700204 numPon := 4
205 numOnu := 4
206
Matteo Scandolo4a036262020-08-17 15:56:13 -0700207 services := []ServiceIf{
208 &Service{Name: "hsia"},
209 &Service{Name: "voip"},
210 &Service{Name: "vod"},
211 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700212
Matteo Scandolo8a574812021-05-20 15:18:53 -0700213 olt := createMockOlt(numPon, numOnu, 1, services)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700214
Matteo Scandolo8a574812021-05-20 15:18:53 -0700215 mac := net.HardwareAddr{0x2e, byte(olt.ID), byte(3), byte(6), byte(3), byte(1)}
Matteo Scandolo4a036262020-08-17 15:56:13 -0700216 s, err := olt.FindServiceByMacAddress(mac)
217
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700218 assert.NoError(t, err)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700219
220 service := s.(*Service)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700221
222 assert.Equal(t, err, nil)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700223 assert.Equal(t, service.UniPort.Onu.Sn(), "BBSM00000306")
224 assert.Equal(t, service.UniPort.ID, uint32(4))
225 assert.Equal(t, service.UniPort.Onu.ID, uint32(6))
226 assert.Equal(t, service.UniPort.Onu.PonPortID, uint32(3))
Matteo Scandolo4a036262020-08-17 15:56:13 -0700227
228 assert.Equal(t, service.Name, "voip")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700229}
230
231func Test_Olt_FindOnuByMacAddress_Error(t *testing.T) {
232
233 numPon := 1
234 numOnu := 4
235
Matteo Scandolo8a574812021-05-20 15:18:53 -0700236 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700237
238 mac := net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(3), byte(3)}
239
Matteo Scandolo4a036262020-08-17 15:56:13 -0700240 _, err := olt.FindServiceByMacAddress(mac)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700241
Matteo Scandolo4a036262020-08-17 15:56:13 -0700242 assert.Equal(t, err.Error(), "cannot-find-service-by-mac-address-2e:60:70:13:03:03")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700243}
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700244
245func Test_Olt_GetOnuByFlowId(t *testing.T) {
246 numPon := 4
247 numOnu := 4
248
Matteo Scandolo8a574812021-05-20 15:18:53 -0700249 services := []ServiceIf{
250 &Service{Name: "hsia"},
251 }
252
253 olt := createMockOlt(numPon, numOnu, 1, services)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700254
255 // Add the flows to onus (to be found)
256 onu1, _ := olt.FindOnuBySn("BBSM00000303")
257 flow1 := openolt.Flow{
Shrey Baid688b4242020-07-10 20:40:10 +0530258 FlowId: 64,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700259 Classifier: &openolt.Classifier{},
Matteo Scandolo8a574812021-05-20 15:18:53 -0700260 UniId: 1,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700261 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800262 msg1 := types.OnuFlowUpdateMessage{
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700263 OnuID: onu1.ID,
264 PonPortID: onu1.PonPortID,
265 Flow: &flow1,
266 }
267 onu1.handleFlowAdd(msg1)
268
269 onu2, _ := olt.FindOnuBySn("BBSM00000103")
270 flow2 := openolt.Flow{
Shrey Baid688b4242020-07-10 20:40:10 +0530271 FlowId: 72,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700272 Classifier: &openolt.Classifier{},
Matteo Scandolo8a574812021-05-20 15:18:53 -0700273 UniId: 1,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700274 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800275 msg2 := types.OnuFlowUpdateMessage{
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700276 OnuID: onu2.ID,
277 PonPortID: onu2.PonPortID,
278 Flow: &flow2,
279 }
280 onu2.handleFlowAdd(msg2)
281
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700282 found, err := olt.GetOnuByFlowId(flow1.FlowId)
283
284 assert.Equal(t, err, nil)
285 assert.Equal(t, found.Sn(), onu1.Sn())
Shrey Baid688b4242020-07-10 20:40:10 +0530286}
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800287
288func Test_Olt_storeGemPortId(t *testing.T) {
289
290 const (
291 pon = 1
292 onu = 1
293 uni = 16
294 gem1 = 1024
295 gem2 = 1025
296 )
297
298 numPon := 2
299 numOnu := 2
300
Matteo Scandolo8a574812021-05-20 15:18:53 -0700301 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800302
303 // add a first flow on the ONU
304 flow1 := &openolt.Flow{
305 AccessIntfId: pon,
306 OnuId: onu,
307 PortNo: uni,
308 FlowId: 1,
309 GemportId: gem1,
310 }
311
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700312 olt.storeGemPortIdByFlow(flow1)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800313 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1) // we have 1 gem port
314 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1) // and one flow referencing it
315
316 // add a second flow on the ONU (same gem)
317 flow2 := &openolt.Flow{
318 AccessIntfId: pon,
319 OnuId: onu,
320 PortNo: uni,
321 FlowId: 2,
322 GemportId: gem1,
323 }
324
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700325 olt.storeGemPortIdByFlow(flow2)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800326 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1) // we have 1 gem port
327 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 2) // and two flows referencing it
328
329 // add a third flow on the ONU (different gem)
330 flow3 := &openolt.Flow{
331 AccessIntfId: pon,
332 OnuId: onu,
333 PortNo: uni,
334 FlowId: 2,
335 GemportId: 1025,
336 }
337
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700338 olt.storeGemPortIdByFlow(flow3)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800339 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2) // we have 2 gem ports
340 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 2) // two flows referencing the first one
341 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem2]), 1) // and one flow referencing the second one
342}
343
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700344func Test_Olt_storeGemPortIdReplicatedFlow(t *testing.T) {
345 const (
346 pon = 1
347 onu = 1
348 uni = 16
349 gem1 = 1024
350 gem2 = 1025
351 )
352
353 numPon := 2
354 numOnu := 2
355
Matteo Scandolo8a574812021-05-20 15:18:53 -0700356 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700357
358 // add a flow that needs replication
359 pbitToGemPortMap := make(map[uint32]uint32)
360 pbitToGemPortMap[0] = gem1
361 pbitToGemPortMap[1] = gem2
362 flow1 := &openolt.Flow{
363 AccessIntfId: pon,
364 OnuId: onu,
365 PortNo: uni,
366 FlowId: 1,
367 GemportId: 0,
368 ReplicateFlow: true,
369 PbitToGemport: pbitToGemPortMap,
370 }
371
372 olt.storeGemPortIdByFlow(flow1)
373 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2) // we have 2 gem ports in the flow
374 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1) // and one flow referencing them
375 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem2]), 1) // and one flow referencing them
376}
377
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800378func Test_Olt_freeGemPortId(t *testing.T) {
379 const (
380 pon = 1
381 onu = 1
382 uni = 16
383 gem1 = 1024
384 gem2 = 1025
385 flow1 = 1
386 flow2 = 2
387 flow3 = 3
388 )
389
390 numPon := 2
391 numOnu := 2
392
Matteo Scandolo8a574812021-05-20 15:18:53 -0700393 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800394
395 olt.GemPortIDs[pon][onu][uni] = make(map[int32]map[uint64]bool)
396 olt.GemPortIDs[pon][onu][uni][gem1] = make(map[uint64]bool)
397 olt.GemPortIDs[pon][onu][uni][gem1][flow1] = true
398 olt.GemPortIDs[pon][onu][uni][gem1][flow2] = true
399 olt.GemPortIDs[pon][onu][uni][gem2] = make(map[uint64]bool)
400 olt.GemPortIDs[pon][onu][uni][gem2][flow3] = true
401
402 // remove one flow on the first gem, check that the gem is still allocated as there is still a flow referencing it
403 // NOTE that the flow remove only carries the flow ID, no other information
404 flowGem1 := &openolt.Flow{
405 FlowId: flow1,
406 }
407
408 olt.freeGemPortId(flowGem1)
409 // we still have two unis in the map
410 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2)
411
412 // we should now have a single gem referenced on this UNI
413 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1, "gemport-not-removed")
414
415 // the gem should still reference flow 2
416 assert.Equal(t, olt.GemPortIDs[pon][onu][uni][gem1][flow2], true)
417 // but should not reference flow1
418 _, flow1Exists := olt.GemPortIDs[pon][onu][uni][gem1][flow1]
419 assert.Equal(t, flow1Exists, false)
420
421 // this is the only flow remaining on this gem, the gem should be removed
422 flowGem2 := &openolt.Flow{
423 FlowId: flow2,
424 }
425 olt.freeGemPortId(flowGem2)
426
427 // we should now have a single gem referenced on this UNI
428 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1, "gemport-not-removed")
429
430 // and it should be gem2
431 _, gem1exists := olt.GemPortIDs[pon][onu][uni][gem1]
432 assert.Equal(t, gem1exists, false)
433 _, gem2exists := olt.GemPortIDs[pon][onu][uni][gem2]
434 assert.Equal(t, gem2exists, true)
435}
436
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700437func Test_Olt_freeGemPortIdReplicatedflow(t *testing.T) {
438 const (
439 pon = 1
440 onu = 1
441 uni = 16
442 gem1 = 1024
443 gem2 = 1025
444 flow1 = 1
445 )
446
447 numPon := 2
448 numOnu := 2
449
Matteo Scandolo8a574812021-05-20 15:18:53 -0700450 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700451
452 olt.GemPortIDs[pon][onu][uni] = make(map[int32]map[uint64]bool)
453 olt.GemPortIDs[pon][onu][uni][gem1] = make(map[uint64]bool)
454 olt.GemPortIDs[pon][onu][uni][gem1][flow1] = true
455 olt.GemPortIDs[pon][onu][uni][gem2] = make(map[uint64]bool)
456 olt.GemPortIDs[pon][onu][uni][gem2][flow1] = true
457
458 // this flow was a replicated flow, remove all the gems that are referenced by that flow
459 flowMultiGem := &openolt.Flow{
460 FlowId: flow1,
461 }
462
463 olt.freeGemPortId(flowMultiGem)
464
465 // this flow removes all the gems, so no UNI should be left
466 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 0)
467}
468
Matteo Scandolo21195d62021-04-07 14:31:23 -0700469// testing that we can validate flows while we are adding them
470func Benchmark_validateAndAddFlows(b *testing.B) {
471 const (
472 pon = 0
473 start = 0
474 end = 512
475 )
476
477 for r := 0; r < b.N; r++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700478 olt := createMockOlt(1, 512, 4, []ServiceIf{})
Matteo Scandolo21195d62021-04-07 14:31:23 -0700479
480 wg := sync.WaitGroup{}
481
482 // concurrently adding 1K gems
483 for i := start; i < end; i++ {
484 wg.Add(1)
485 flow := &openolt.Flow{
486 AccessIntfId: pon,
487 OnuId: int32(i),
488 PortNo: uint32(i),
489 GemportId: int32(i),
490 FlowId: uint64(i),
491 }
492 go func(wg *sync.WaitGroup) {
493 olt.storeGemPortIdByFlow(flow)
494 olt.storeAllocId(flow)
495 wg.Done()
496 }(&wg)
497 }
498
499 // at the same time validate flows
500 for i := start; i < end; i++ {
501 wg.Add(1)
502 flow := &openolt.Flow{
503 AccessIntfId: pon,
504 OnuId: int32(i),
505 PortNo: uint32(i),
506 GemportId: 1,
507 FlowId: uint64(i),
508 }
509 go func(wg *sync.WaitGroup) {
510 _ = olt.validateFlow(flow)
511 wg.Done()
512 }(&wg)
513 }
514
515 wg.Wait()
516 // NOTE this tests only fails if there is concurrent access to the map
517 }
518}
519
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800520func Test_Olt_validateFlow(t *testing.T) {
521
522 const (
523 pon0 = 0
524 pon1 = 1
525 onu0 = 0
526 onu1 = 1
527 uniPort = 0
528 usedGemIdPon0 = 1024
529 usedGemIdPon1 = 1025
530 usedAllocIdPon0 = 1
531 usedAllocIdPon1 = 2
532 flowId = 1
533 )
534
535 numPon := 2
536 numOnu := 2
537
Matteo Scandolo8a574812021-05-20 15:18:53 -0700538 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800539
540 olt.GemPortIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
541 olt.GemPortIDs[pon1][onu0][uniPort] = make(map[int32]map[uint64]bool)
542
543 olt.GemPortIDs[pon0][onu0][uniPort][usedGemIdPon0] = make(map[uint64]bool)
544 olt.GemPortIDs[pon0][onu0][uniPort][usedGemIdPon0][flowId] = true
545 olt.GemPortIDs[pon1][onu0][uniPort][usedGemIdPon1] = make(map[uint64]bool)
546 olt.GemPortIDs[pon1][onu0][uniPort][usedGemIdPon1][flowId] = true
547
548 olt.AllocIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
549 olt.AllocIDs[pon1][onu0][uniPort] = make(map[int32]map[uint64]bool)
550 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0] = make(map[uint64]bool)
551 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0][flowId] = true
552 olt.AllocIDs[pon1][onu0][uniPort][usedAllocIdPon1] = make(map[uint64]bool)
553 olt.AllocIDs[pon1][onu0][uniPort][usedAllocIdPon1][flowId] = true
554
555 // a GemPortID can be referenced across multiple flows on the same ONU
556 validGemFlow := &openolt.Flow{
557 AccessIntfId: pon0,
558 OnuId: onu0,
559 GemportId: usedGemIdPon0,
560 }
561
562 err := olt.validateFlow(validGemFlow)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700563 assert.NoError(t, err)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800564
565 // a GemPortID can NOT be referenced across different ONUs on the same PON
566 invalidGemFlow := &openolt.Flow{
567 AccessIntfId: pon0,
568 OnuId: onu1,
569 GemportId: usedGemIdPon0,
570 }
571 err = olt.validateFlow(invalidGemFlow)
572 assert.Error(t, err, "gem-1024-already-in-use-on-uni-0-onu-0")
573
574 // if a flow reference the same GEM on a different PON it's a valid flow
575 invalidGemDifferentPonFlow := &openolt.Flow{
576 AccessIntfId: pon1,
577 OnuId: onu1,
578 GemportId: usedGemIdPon0,
579 }
580 err = olt.validateFlow(invalidGemDifferentPonFlow)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700581 assert.NoError(t, err)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800582
583 // an allocId can be referenced across multiple flows on the same ONU
584 validAllocFlow := &openolt.Flow{
585 AccessIntfId: pon0,
586 OnuId: onu0,
587 AllocId: usedAllocIdPon0,
588 }
589 err = olt.validateFlow(validAllocFlow)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700590 assert.NoError(t, err)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800591
592 // an allocId can NOT be referenced across different ONUs on the same PON
593 invalidAllocFlow := &openolt.Flow{
594 AccessIntfId: pon0,
595 OnuId: onu1,
596 AllocId: usedAllocIdPon0,
597 }
598 err = olt.validateFlow(invalidAllocFlow)
599 assert.Error(t, err, "allocId-1-already-in-use-on-uni-0-onu-0")
600
601 // if a flow reference the same AllocId on a different PON it's a valid flow
602 invalidAllocDifferentPonFlow := &openolt.Flow{
603 AccessIntfId: pon1,
604 OnuId: onu1,
605 AllocId: usedAllocIdPon0,
606 }
607 err = olt.validateFlow(invalidAllocDifferentPonFlow)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700608 assert.NoError(t, err)
609}
610
611func Test_Olt_validateReplicatedFlow(t *testing.T) {
612
613 const (
614 pon0 = 0
615 onu0 = 0
616 onu1 = 1
617 uniPort = 0
618 usedGemId1 = 1024
619 usedGemId2 = 1025
620 usedAllocIdPon0 = 1
621 flowId = 1
622 )
623
624 numPon := 1
625 numOnu := 1
626
Matteo Scandolo8a574812021-05-20 15:18:53 -0700627 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700628
629 // both the gemports referenced in this flow are already allocated
630 olt.GemPortIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
631 olt.GemPortIDs[pon0][onu0][uniPort][usedGemId1] = make(map[uint64]bool)
632 olt.GemPortIDs[pon0][onu0][uniPort][usedGemId1][flowId] = true
633 olt.GemPortIDs[pon0][onu0][uniPort][usedGemId2] = make(map[uint64]bool)
634 olt.GemPortIDs[pon0][onu0][uniPort][usedGemId2][flowId] = true
635
636 olt.AllocIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
637 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0] = make(map[uint64]bool)
638 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0][flowId] = true
639
640 pbitToGemPortMap := make(map[uint32]uint32)
641 pbitToGemPortMap[0] = usedGemId1
642 pbitToGemPortMap[1] = usedGemId2
643
644 // this flow should fail vlidation as the gems are already allocated to Onu0
645 invalidGemFlow := &openolt.Flow{
646 AccessIntfId: pon0,
647 OnuId: onu1,
648 PortNo: uniPort,
649 GemportId: 0,
650 ReplicateFlow: true,
651 PbitToGemport: pbitToGemPortMap,
652 }
653
654 err := olt.validateFlow(invalidGemFlow)
655 assert.NotNil(t, err)
656
657 // PbitToGemport is a map, so any of the two gemPorts can fail first and determine the error message
658 foundError := false
659 switch err.Error() {
660 case fmt.Sprintf("gem-%d-already-in-use-on-uni-%d-onu-%d-replicated-flow-%d", usedGemId2, uniPort, onu0, invalidGemFlow.FlowId):
661 foundError = true
662 case fmt.Sprintf("gem-%d-already-in-use-on-uni-%d-onu-%d-replicated-flow-%d", usedGemId1, uniPort, onu0, invalidGemFlow.FlowId):
663 foundError = true
664
665 }
666 assert.True(t, foundError)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800667}
Matteo Scandolob5913142021-03-19 16:10:18 -0700668
669func Test_Olt_OmciMsgOut(t *testing.T) {
670 numPon := 4
671 numOnu := 4
672
Matteo Scandolo8a574812021-05-20 15:18:53 -0700673 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolob5913142021-03-19 16:10:18 -0700674
675 // a malformed packet should return an error
676 msg := &openolt.OmciMsg{
677 IntfId: 1,
678 OnuId: 1,
679 Pkt: []byte{},
680 }
681 ctx := context.TODO()
682 _, err := olt.OmciMsgOut(ctx, msg)
683 assert.Error(t, err, "olt-received-malformed-omci-packet")
684
685 // a correct packet for a non exiting ONU should throw an error
686 msg = &openolt.OmciMsg{
687 IntfId: 10,
688 OnuId: 25,
689 Pkt: makeOmciSetRequest(t),
690 }
691 _, err = olt.OmciMsgOut(ctx, msg)
692 assert.Error(t, err, "Cannot find PonPort with id 10 in OLT 0")
693
694 // a correct packet for a disabled ONU should be dropped
695 // note that an error is not returned, this is valid in BBsim
696 const (
697 ponId = 1
698 onuId = 1
699 )
700 pon, _ := olt.GetPonById(ponId)
701 onu, _ := pon.GetOnuById(onuId)
702 onu.InternalState.SetState(OnuStateDisabled)
703 msg = &openolt.OmciMsg{
704 IntfId: ponId,
705 OnuId: onuId,
706 Pkt: makeOmciSetRequest(t),
707 }
708 _, err = olt.OmciMsgOut(ctx, msg)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700709 assert.NoError(t, err)
Matteo Scandolob5913142021-03-19 16:10:18 -0700710 assert.Equal(t, len(onu.Channel), 0) // check that no messages have been sent
711
712 // test that the ONU receives a valid packet
713 onu.InternalState.SetState(OnuStateEnabled)
714 _, err = olt.OmciMsgOut(ctx, msg)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700715 assert.NoError(t, err)
Matteo Scandolob5913142021-03-19 16:10:18 -0700716 assert.Equal(t, len(onu.Channel), 1) // check that one message have been sent
717
718}