blob: acbe7a7a0c9880f4f619e122977a0200af9aab29 [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 Scandolof9d43412021-01-12 11:11:34 -080020 "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandolo4a036262020-08-17 15:56:13 -070021 "github.com/opencord/bbsim/internal/common"
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070022 "net"
Matteo Scandolo10f965c2019-09-24 10:40:46 -070023 "testing"
Shrey Baid688b4242020-07-10 20:40:10 +053024
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070025 "github.com/opencord/voltha-protos/v4/go/openolt"
Shrey Baid688b4242020-07-10 20:40:10 +053026 "gotest.tools/assert"
Matteo Scandolo10f965c2019-09-24 10:40:46 -070027)
28
Matteo Scandolo4a036262020-08-17 15:56:13 -070029func createMockOlt(numPon int, numOnu int, services []ServiceIf) *OltDevice {
Shrey Baid688b4242020-07-10 20:40:10 +053030 olt := &OltDevice{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080031 ID: 0,
32 AllocIDs: make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
33 GemPortIDs: make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
Matteo Scandolo10f965c2019-09-24 10:40:46 -070034 }
35
36 for i := 0; i < numPon; i++ {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080037
38 // initialize the resource maps for every PON Ports
39 olt.AllocIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
40 olt.GemPortIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
41
Matteo Scandolo10f965c2019-09-24 10:40:46 -070042 pon := PonPort{
43 ID: uint32(i),
44 }
45
46 for j := 0; j < numOnu; j++ {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080047
48 // initialize the resource maps for every ONU and the first UNI
49 olt.AllocIDs[uint32(i)][uint32(j)] = make(map[uint32]map[int32]map[uint64]bool)
50 olt.GemPortIDs[uint32(i)][uint32(j)] = make(map[uint32]map[int32]map[uint64]bool)
51
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070052 onuId := uint32(i + j)
Matteo Scandolo10f965c2019-09-24 10:40:46 -070053 onu := Onu{
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070054 ID: onuId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070055 PonPort: &pon,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070056 PonPortID: pon.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -070057 }
Matteo Scandolo4a036262020-08-17 15:56:13 -070058
59 for k, s := range services {
60 service := s.(*Service)
61 service.HwAddress = net.HardwareAddr{0x2e, 0x60, byte(olt.ID), byte(pon.ID), byte(onuId), byte(k)}
62 service.Onu = &onu
63 onu.Services = append(onu.Services, service)
64 }
65
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080066 onu.SerialNumber = NewSN(olt.ID, pon.ID, onu.ID)
Matteo Scandolo27428702019-10-11 16:21:16 -070067 pon.Onus = append(pon.Onus, &onu)
Matteo Scandolo10f965c2019-09-24 10:40:46 -070068 }
Matteo Scandolo27428702019-10-11 16:21:16 -070069 olt.Pons = append(olt.Pons, &pon)
Matteo Scandolo10f965c2019-09-24 10:40:46 -070070 }
71 return olt
72}
73
Matteo Scandolo4a036262020-08-17 15:56:13 -070074// check the creation of an OLT with a single Service
75func TestCreateOLT(t *testing.T) {
76
77 common.Services = []common.ServiceYaml{
78 {Name: "hsia", CTag: 900, CTagAllocation: common.TagAllocationUnique.String(), STag: 900, STagAllocation: common.TagAllocationShared.String(), NeedsEapol: true, NeedsDchp: true, NeedsIgmp: true},
79 }
80
81 common.Config = &common.GlobalConfig{
82 Olt: common.OltConfig{
83 ID: 1,
84 PonPorts: 2,
85 OnusPonPort: 2,
86 },
87 }
88
89 olt := CreateOLT(*common.Config, common.Services, true)
90
91 assert.Equal(t, len(olt.Pons), int(common.Config.Olt.PonPorts))
92
93 // count the ONUs
94 onus := 0
95 for _, p := range olt.Pons {
96 onus = onus + len(p.Onus)
97 }
98
99 assert.Equal(t, onus, int(common.Config.Olt.PonPorts*common.Config.Olt.OnusPonPort))
100
101 // count the services
102 services := 0
103 for _, p := range olt.Pons {
104 for _, o := range p.Onus {
105 services = services + len(o.Services)
106 }
107 }
108
109 assert.Equal(t, services, int(common.Config.Olt.PonPorts)*int(common.Config.Olt.OnusPonPort)*len(common.Services))
110
111 s1 := olt.Pons[0].Onus[0].Services[0].(*Service)
112
113 assert.Equal(t, s1.Name, "hsia")
114 assert.Equal(t, s1.CTag, 900)
115 assert.Equal(t, s1.STag, 900)
116 assert.Equal(t, s1.HwAddress.String(), "2e:60:01:00:01:00")
117 assert.Equal(t, olt.Pons[0].Onus[0].ID, uint32(1))
118
119 s2 := olt.Pons[0].Onus[1].Services[0].(*Service)
120 assert.Equal(t, s2.CTag, 901)
121 assert.Equal(t, s2.STag, 900)
122 assert.Equal(t, s2.HwAddress.String(), "2e:60:01:00:02:00")
123 assert.Equal(t, olt.Pons[0].Onus[1].ID, uint32(2))
124
125 s3 := olt.Pons[1].Onus[0].Services[0].(*Service)
126 assert.Equal(t, s3.CTag, 902)
127 assert.Equal(t, s3.STag, 900)
128 assert.Equal(t, s3.HwAddress.String(), "2e:60:01:01:01:00")
129 assert.Equal(t, olt.Pons[1].Onus[0].ID, uint32(1))
130
131 s4 := olt.Pons[1].Onus[1].Services[0].(*Service)
132 assert.Equal(t, s4.CTag, 903)
133 assert.Equal(t, s4.STag, 900)
134 assert.Equal(t, s4.HwAddress.String(), "2e:60:01:01:02:00")
135 assert.Equal(t, olt.Pons[1].Onus[1].ID, uint32(2))
136}
137
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700138func Test_Olt_FindOnuBySn_Success(t *testing.T) {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700139
140 numPon := 4
141 numOnu := 4
142
Matteo Scandolo4a036262020-08-17 15:56:13 -0700143 olt := createMockOlt(numPon, numOnu, []ServiceIf{})
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700144
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700145 onu, err := olt.FindOnuBySn("BBSM00000303")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700146
147 assert.Equal(t, err, nil)
148 assert.Equal(t, onu.Sn(), "BBSM00000303")
149 assert.Equal(t, onu.ID, uint32(3))
150 assert.Equal(t, onu.PonPortID, uint32(3))
151}
152
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700153func Test_Olt_FindOnuBySn_Error(t *testing.T) {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700154
155 numPon := 1
156 numOnu := 4
157
Matteo Scandolo4a036262020-08-17 15:56:13 -0700158 olt := createMockOlt(numPon, numOnu, []ServiceIf{})
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700159
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700160 _, err := olt.FindOnuBySn("BBSM00000303")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700161
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700162 assert.Equal(t, err.Error(), "cannot-find-onu-by-serial-number-BBSM00000303")
163}
164
165func Test_Olt_FindOnuByMacAddress_Success(t *testing.T) {
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700166 numPon := 4
167 numOnu := 4
168
Matteo Scandolo4a036262020-08-17 15:56:13 -0700169 services := []ServiceIf{
170 &Service{Name: "hsia"},
171 &Service{Name: "voip"},
172 &Service{Name: "vod"},
173 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700174
Matteo Scandolo4a036262020-08-17 15:56:13 -0700175 olt := createMockOlt(numPon, numOnu, services)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700176
Matteo Scandolo4a036262020-08-17 15:56:13 -0700177 mac := net.HardwareAddr{0x2e, 0x60, byte(olt.ID), byte(3), byte(6), byte(1)}
178 s, err := olt.FindServiceByMacAddress(mac)
179
180 assert.NilError(t, err)
181
182 service := s.(*Service)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700183
184 assert.Equal(t, err, nil)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700185 assert.Equal(t, service.Onu.Sn(), "BBSM00000306")
186 assert.Equal(t, service.Onu.ID, uint32(6))
187 assert.Equal(t, service.Onu.PonPortID, uint32(3))
188
189 assert.Equal(t, service.Name, "voip")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700190}
191
192func Test_Olt_FindOnuByMacAddress_Error(t *testing.T) {
193
194 numPon := 1
195 numOnu := 4
196
Matteo Scandolo4a036262020-08-17 15:56:13 -0700197 olt := createMockOlt(numPon, numOnu, []ServiceIf{})
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700198
199 mac := net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(3), byte(3)}
200
Matteo Scandolo4a036262020-08-17 15:56:13 -0700201 _, err := olt.FindServiceByMacAddress(mac)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700202
Matteo Scandolo4a036262020-08-17 15:56:13 -0700203 assert.Equal(t, err.Error(), "cannot-find-service-by-mac-address-2e:60:70:13:03:03")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700204}
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700205
206func Test_Olt_GetOnuByFlowId(t *testing.T) {
207 numPon := 4
208 numOnu := 4
209
Matteo Scandolo4a036262020-08-17 15:56:13 -0700210 olt := createMockOlt(numPon, numOnu, []ServiceIf{})
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700211
212 // Add the flows to onus (to be found)
213 onu1, _ := olt.FindOnuBySn("BBSM00000303")
214 flow1 := openolt.Flow{
Shrey Baid688b4242020-07-10 20:40:10 +0530215 FlowId: 64,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700216 Classifier: &openolt.Classifier{},
217 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800218 msg1 := types.OnuFlowUpdateMessage{
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700219 OnuID: onu1.ID,
220 PonPortID: onu1.PonPortID,
221 Flow: &flow1,
222 }
223 onu1.handleFlowAdd(msg1)
224
225 onu2, _ := olt.FindOnuBySn("BBSM00000103")
226 flow2 := openolt.Flow{
Shrey Baid688b4242020-07-10 20:40:10 +0530227 FlowId: 72,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700228 Classifier: &openolt.Classifier{},
229 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800230 msg2 := types.OnuFlowUpdateMessage{
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700231 OnuID: onu2.ID,
232 PonPortID: onu2.PonPortID,
233 Flow: &flow2,
234 }
235 onu2.handleFlowAdd(msg2)
236
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700237 found, err := olt.GetOnuByFlowId(flow1.FlowId)
238
239 assert.Equal(t, err, nil)
240 assert.Equal(t, found.Sn(), onu1.Sn())
Shrey Baid688b4242020-07-10 20:40:10 +0530241}
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800242
243func Test_Olt_storeGemPortId(t *testing.T) {
244
245 const (
246 pon = 1
247 onu = 1
248 uni = 16
249 gem1 = 1024
250 gem2 = 1025
251 )
252
253 numPon := 2
254 numOnu := 2
255
256 olt := createMockOlt(numPon, numOnu, []ServiceIf{})
257
258 // add a first flow on the ONU
259 flow1 := &openolt.Flow{
260 AccessIntfId: pon,
261 OnuId: onu,
262 PortNo: uni,
263 FlowId: 1,
264 GemportId: gem1,
265 }
266
267 olt.storeGemPortId(flow1)
268 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1) // we have 1 gem port
269 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1) // and one flow referencing it
270
271 // add a second flow on the ONU (same gem)
272 flow2 := &openolt.Flow{
273 AccessIntfId: pon,
274 OnuId: onu,
275 PortNo: uni,
276 FlowId: 2,
277 GemportId: gem1,
278 }
279
280 olt.storeGemPortId(flow2)
281 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1) // we have 1 gem port
282 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 2) // and two flows referencing it
283
284 // add a third flow on the ONU (different gem)
285 flow3 := &openolt.Flow{
286 AccessIntfId: pon,
287 OnuId: onu,
288 PortNo: uni,
289 FlowId: 2,
290 GemportId: 1025,
291 }
292
293 olt.storeGemPortId(flow3)
294 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2) // we have 2 gem ports
295 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 2) // two flows referencing the first one
296 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem2]), 1) // and one flow referencing the second one
297}
298
299func Test_Olt_freeGemPortId(t *testing.T) {
300 const (
301 pon = 1
302 onu = 1
303 uni = 16
304 gem1 = 1024
305 gem2 = 1025
306 flow1 = 1
307 flow2 = 2
308 flow3 = 3
309 )
310
311 numPon := 2
312 numOnu := 2
313
314 olt := createMockOlt(numPon, numOnu, []ServiceIf{})
315
316 olt.GemPortIDs[pon][onu][uni] = make(map[int32]map[uint64]bool)
317 olt.GemPortIDs[pon][onu][uni][gem1] = make(map[uint64]bool)
318 olt.GemPortIDs[pon][onu][uni][gem1][flow1] = true
319 olt.GemPortIDs[pon][onu][uni][gem1][flow2] = true
320 olt.GemPortIDs[pon][onu][uni][gem2] = make(map[uint64]bool)
321 olt.GemPortIDs[pon][onu][uni][gem2][flow3] = true
322
323 // remove one flow on the first gem, check that the gem is still allocated as there is still a flow referencing it
324 // NOTE that the flow remove only carries the flow ID, no other information
325 flowGem1 := &openolt.Flow{
326 FlowId: flow1,
327 }
328
329 olt.freeGemPortId(flowGem1)
330 // we still have two unis in the map
331 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2)
332
333 // we should now have a single gem referenced on this UNI
334 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1, "gemport-not-removed")
335
336 // the gem should still reference flow 2
337 assert.Equal(t, olt.GemPortIDs[pon][onu][uni][gem1][flow2], true)
338 // but should not reference flow1
339 _, flow1Exists := olt.GemPortIDs[pon][onu][uni][gem1][flow1]
340 assert.Equal(t, flow1Exists, false)
341
342 // this is the only flow remaining on this gem, the gem should be removed
343 flowGem2 := &openolt.Flow{
344 FlowId: flow2,
345 }
346 olt.freeGemPortId(flowGem2)
347
348 // we should now have a single gem referenced on this UNI
349 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1, "gemport-not-removed")
350
351 // and it should be gem2
352 _, gem1exists := olt.GemPortIDs[pon][onu][uni][gem1]
353 assert.Equal(t, gem1exists, false)
354 _, gem2exists := olt.GemPortIDs[pon][onu][uni][gem2]
355 assert.Equal(t, gem2exists, true)
356}
357
358func Test_Olt_validateFlow(t *testing.T) {
359
360 const (
361 pon0 = 0
362 pon1 = 1
363 onu0 = 0
364 onu1 = 1
365 uniPort = 0
366 usedGemIdPon0 = 1024
367 usedGemIdPon1 = 1025
368 usedAllocIdPon0 = 1
369 usedAllocIdPon1 = 2
370 flowId = 1
371 )
372
373 numPon := 2
374 numOnu := 2
375
376 olt := createMockOlt(numPon, numOnu, []ServiceIf{})
377
378 olt.GemPortIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
379 olt.GemPortIDs[pon1][onu0][uniPort] = make(map[int32]map[uint64]bool)
380
381 olt.GemPortIDs[pon0][onu0][uniPort][usedGemIdPon0] = make(map[uint64]bool)
382 olt.GemPortIDs[pon0][onu0][uniPort][usedGemIdPon0][flowId] = true
383 olt.GemPortIDs[pon1][onu0][uniPort][usedGemIdPon1] = make(map[uint64]bool)
384 olt.GemPortIDs[pon1][onu0][uniPort][usedGemIdPon1][flowId] = true
385
386 olt.AllocIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
387 olt.AllocIDs[pon1][onu0][uniPort] = make(map[int32]map[uint64]bool)
388 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0] = make(map[uint64]bool)
389 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0][flowId] = true
390 olt.AllocIDs[pon1][onu0][uniPort][usedAllocIdPon1] = make(map[uint64]bool)
391 olt.AllocIDs[pon1][onu0][uniPort][usedAllocIdPon1][flowId] = true
392
393 // a GemPortID can be referenced across multiple flows on the same ONU
394 validGemFlow := &openolt.Flow{
395 AccessIntfId: pon0,
396 OnuId: onu0,
397 GemportId: usedGemIdPon0,
398 }
399
400 err := olt.validateFlow(validGemFlow)
401 assert.NilError(t, err)
402
403 // a GemPortID can NOT be referenced across different ONUs on the same PON
404 invalidGemFlow := &openolt.Flow{
405 AccessIntfId: pon0,
406 OnuId: onu1,
407 GemportId: usedGemIdPon0,
408 }
409 err = olt.validateFlow(invalidGemFlow)
410 assert.Error(t, err, "gem-1024-already-in-use-on-uni-0-onu-0")
411
412 // if a flow reference the same GEM on a different PON it's a valid flow
413 invalidGemDifferentPonFlow := &openolt.Flow{
414 AccessIntfId: pon1,
415 OnuId: onu1,
416 GemportId: usedGemIdPon0,
417 }
418 err = olt.validateFlow(invalidGemDifferentPonFlow)
419 assert.NilError(t, err)
420
421 // an allocId can be referenced across multiple flows on the same ONU
422 validAllocFlow := &openolt.Flow{
423 AccessIntfId: pon0,
424 OnuId: onu0,
425 AllocId: usedAllocIdPon0,
426 }
427 err = olt.validateFlow(validAllocFlow)
428 assert.NilError(t, err)
429
430 // an allocId can NOT be referenced across different ONUs on the same PON
431 invalidAllocFlow := &openolt.Flow{
432 AccessIntfId: pon0,
433 OnuId: onu1,
434 AllocId: usedAllocIdPon0,
435 }
436 err = olt.validateFlow(invalidAllocFlow)
437 assert.Error(t, err, "allocId-1-already-in-use-on-uni-0-onu-0")
438
439 // if a flow reference the same AllocId on a different PON it's a valid flow
440 invalidAllocDifferentPonFlow := &openolt.Flow{
441 AccessIntfId: pon1,
442 OnuId: onu1,
443 AllocId: usedAllocIdPon0,
444 }
445 err = olt.validateFlow(invalidAllocDifferentPonFlow)
446 assert.NilError(t, err)
447}