blob: e442d5447b6db71e565e29b2aeee645fecee284f [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"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000026 "github.com/opencord/voltha-protos/v5/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
Mahir Gunyela1753ae2021-06-23 00:24:56 -070075 for k := 0; k < numUni; k++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -070076 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,
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700110 UniPorts: 4,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700111 },
112 }
113
114 olt := CreateOLT(*common.Config, common.Services, true)
115
116 assert.Equal(t, len(olt.Pons), int(common.Config.Olt.PonPorts))
117
118 // count the ONUs
119 onus := 0
120 for _, p := range olt.Pons {
121 onus = onus + len(p.Onus)
122 }
123
124 assert.Equal(t, onus, int(common.Config.Olt.PonPorts*common.Config.Olt.OnusPonPort))
125
Matteo Scandolo8a574812021-05-20 15:18:53 -0700126 // counte the UNIs
127 unis := 0
128 for _, p := range olt.Pons {
129 for _, o := range p.Onus {
130 unis = unis + len(o.UniPorts)
131 }
132 }
133 // NOTE when unis will be configurable this test will need to adapt
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700134 assert.Equal(t, unis, int(common.Config.Olt.PonPorts*common.Config.Olt.OnusPonPort*common.Config.Olt.UniPorts))
Matteo Scandolo8a574812021-05-20 15:18:53 -0700135
Matteo Scandolo4a036262020-08-17 15:56:13 -0700136 // count the services
137 services := 0
138 for _, p := range olt.Pons {
139 for _, o := range p.Onus {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700140 for _, u := range o.UniPorts {
141 uni := u.(*UniPort)
142 services = services + len(uni.Services)
143 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700144 }
145 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700146 // NOTE when unis will be configurable this test will need to adapt
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700147 assert.Equal(t, services, int(common.Config.Olt.PonPorts)*int(common.Config.Olt.OnusPonPort)*int(common.Config.Olt.UniPorts)*len(common.Services))
Matteo Scandolo4a036262020-08-17 15:56:13 -0700148
Matteo Scandolo8a574812021-05-20 15:18:53 -0700149 s1 := olt.Pons[0].Onus[0].UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700150
151 assert.Equal(t, s1.Name, "hsia")
152 assert.Equal(t, s1.CTag, 900)
153 assert.Equal(t, s1.STag, 900)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700154 assert.Equal(t, "2e:01:00:01:00:00", s1.HwAddress.String())
Matteo Scandolo4a036262020-08-17 15:56:13 -0700155 assert.Equal(t, olt.Pons[0].Onus[0].ID, uint32(1))
156
Matteo Scandolo8a574812021-05-20 15:18:53 -0700157 // each ONU has 4 UNIs, taking up the c-tags
158 s2 := olt.Pons[0].Onus[1].UniPorts[0].(*UniPort).Services[0].(*Service)
159 assert.Equal(t, s2.CTag, 904)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700160 assert.Equal(t, s2.STag, 900)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700161 assert.Equal(t, s2.HwAddress.String(), "2e:01:00:02:00:00")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700162 assert.Equal(t, olt.Pons[0].Onus[1].ID, uint32(2))
163
Matteo Scandolo8a574812021-05-20 15:18:53 -0700164 s3 := olt.Pons[1].Onus[0].UniPorts[0].(*UniPort).Services[0].(*Service)
165 assert.Equal(t, s3.CTag, 908)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700166 assert.Equal(t, s3.STag, 900)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700167 assert.Equal(t, s3.HwAddress.String(), "2e:01:01:01:00:00")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700168 assert.Equal(t, olt.Pons[1].Onus[0].ID, uint32(1))
169
Matteo Scandolo8a574812021-05-20 15:18:53 -0700170 s4 := olt.Pons[1].Onus[1].UniPorts[0].(*UniPort).Services[0].(*Service)
171 assert.Equal(t, s4.CTag, 912)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700172 assert.Equal(t, s4.STag, 900)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700173 assert.Equal(t, s4.HwAddress.String(), "2e:01:01:02:00:00")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700174 assert.Equal(t, olt.Pons[1].Onus[1].ID, uint32(2))
175}
176
Matteo Scandolo52d12e32022-02-02 15:30:20 -0800177func TestGetDeviceInfo(t *testing.T) {
178
179 var onusPerPon uint32 = 4
180
181 common.Services = []common.ServiceYaml{
182 {Name: "hsia", CTag: 900, CTagAllocation: common.TagAllocationUnique.String(), STag: 900, STagAllocation: common.TagAllocationShared.String(), NeedsEapol: true, NeedsDhcp: true, NeedsIgmp: true},
183 }
184
185 common.Config = &common.GlobalConfig{
186 Olt: common.OltConfig{
187 ID: 1,
188 PonPorts: 2,
189 OnusPonPort: onusPerPon,
190 UniPorts: 4,
191 },
192 }
193
194 olt := CreateOLT(*common.Config, common.Services, true)
195
196 res, err := olt.GetDeviceInfo(context.Background(), &openolt.Empty{})
197
198 assert.NoError(t, err, "GetDeviceInfo returned error")
199
200 fmt.Println(res)
201 fmt.Println(res.OnuIdEnd - res.OnuIdStart + 1)
202
203 assert.Equal(t, onuIdStart+(onusPerPon-1), res.OnuIdEnd)
204 assert.Equal(t, onuIdStart+(onusPerPon-1), res.Ranges[0].Pools[0].End)
205 assert.Equal(t, onusPerPon, res.OnuIdEnd-res.OnuIdStart+1, "The ONU ID range size is different that the number of ONUs per PON")
206
207 assert.Equal(t, uint32(allocIdStart+(olt.NumOnuPerPon*olt.NumUni*len(common.Services))), res.AllocIdEnd)
208 assert.Equal(t, uint32(gemportIdStart+(olt.NumOnuPerPon*olt.NumUni*len(common.Services))*gemPortIdPerAllocId), res.GemportIdEnd)
209}
210
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700211func Test_Olt_FindOnuBySn_Success(t *testing.T) {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700212
213 numPon := 4
214 numOnu := 4
215
Matteo Scandolo8a574812021-05-20 15:18:53 -0700216 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700217
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700218 onu, err := olt.FindOnuBySn("BBSM00000303")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700219
220 assert.Equal(t, err, nil)
221 assert.Equal(t, onu.Sn(), "BBSM00000303")
222 assert.Equal(t, onu.ID, uint32(3))
223 assert.Equal(t, onu.PonPortID, uint32(3))
224}
225
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700226func Test_Olt_FindOnuBySn_Error(t *testing.T) {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700227
228 numPon := 1
229 numOnu := 4
230
Matteo Scandolo8a574812021-05-20 15:18:53 -0700231 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700232
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700233 _, err := olt.FindOnuBySn("BBSM00000303")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700234
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700235 assert.Equal(t, err.Error(), "cannot-find-onu-by-serial-number-BBSM00000303")
236}
237
238func Test_Olt_FindOnuByMacAddress_Success(t *testing.T) {
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700239 numPon := 4
240 numOnu := 4
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700241 numUni := 4
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700242
Matteo Scandolo4a036262020-08-17 15:56:13 -0700243 services := []ServiceIf{
244 &Service{Name: "hsia"},
245 &Service{Name: "voip"},
246 &Service{Name: "vod"},
247 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700248
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700249 olt := createMockOlt(numPon, numOnu, numUni, services)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700250
Matteo Scandolo8a574812021-05-20 15:18:53 -0700251 mac := net.HardwareAddr{0x2e, byte(olt.ID), byte(3), byte(6), byte(3), byte(1)}
Matteo Scandolo4a036262020-08-17 15:56:13 -0700252 s, err := olt.FindServiceByMacAddress(mac)
253
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700254 assert.NoError(t, err)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700255
256 service := s.(*Service)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700257
258 assert.Equal(t, err, nil)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700259 assert.Equal(t, service.UniPort.Onu.Sn(), "BBSM00000306")
260 assert.Equal(t, service.UniPort.ID, uint32(4))
261 assert.Equal(t, service.UniPort.Onu.ID, uint32(6))
262 assert.Equal(t, service.UniPort.Onu.PonPortID, uint32(3))
Matteo Scandolo4a036262020-08-17 15:56:13 -0700263
264 assert.Equal(t, service.Name, "voip")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700265}
266
267func Test_Olt_FindOnuByMacAddress_Error(t *testing.T) {
268
269 numPon := 1
270 numOnu := 4
271
Matteo Scandolo8a574812021-05-20 15:18:53 -0700272 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700273
274 mac := net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(3), byte(3)}
275
Matteo Scandolo4a036262020-08-17 15:56:13 -0700276 _, err := olt.FindServiceByMacAddress(mac)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700277
Matteo Scandolo4a036262020-08-17 15:56:13 -0700278 assert.Equal(t, err.Error(), "cannot-find-service-by-mac-address-2e:60:70:13:03:03")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700279}
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700280
281func Test_Olt_GetOnuByFlowId(t *testing.T) {
282 numPon := 4
283 numOnu := 4
284
Matteo Scandolo8a574812021-05-20 15:18:53 -0700285 services := []ServiceIf{
286 &Service{Name: "hsia"},
287 }
288
289 olt := createMockOlt(numPon, numOnu, 1, services)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700290
291 // Add the flows to onus (to be found)
292 onu1, _ := olt.FindOnuBySn("BBSM00000303")
293 flow1 := openolt.Flow{
Shrey Baid688b4242020-07-10 20:40:10 +0530294 FlowId: 64,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700295 Classifier: &openolt.Classifier{},
Matteo Scandolo8a574812021-05-20 15:18:53 -0700296 UniId: 1,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700297 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800298 msg1 := types.OnuFlowUpdateMessage{
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700299 OnuID: onu1.ID,
300 PonPortID: onu1.PonPortID,
301 Flow: &flow1,
302 }
303 onu1.handleFlowAdd(msg1)
304
305 onu2, _ := olt.FindOnuBySn("BBSM00000103")
306 flow2 := openolt.Flow{
Shrey Baid688b4242020-07-10 20:40:10 +0530307 FlowId: 72,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700308 Classifier: &openolt.Classifier{},
Matteo Scandolo8a574812021-05-20 15:18:53 -0700309 UniId: 1,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700310 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800311 msg2 := types.OnuFlowUpdateMessage{
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700312 OnuID: onu2.ID,
313 PonPortID: onu2.PonPortID,
314 Flow: &flow2,
315 }
316 onu2.handleFlowAdd(msg2)
317
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700318 found, err := olt.GetOnuByFlowId(flow1.FlowId)
319
320 assert.Equal(t, err, nil)
321 assert.Equal(t, found.Sn(), onu1.Sn())
Shrey Baid688b4242020-07-10 20:40:10 +0530322}
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800323
324func Test_Olt_storeGemPortId(t *testing.T) {
325
326 const (
327 pon = 1
328 onu = 1
329 uni = 16
330 gem1 = 1024
331 gem2 = 1025
332 )
333
334 numPon := 2
335 numOnu := 2
336
Matteo Scandolo8a574812021-05-20 15:18:53 -0700337 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800338
339 // add a first flow on the ONU
340 flow1 := &openolt.Flow{
341 AccessIntfId: pon,
342 OnuId: onu,
343 PortNo: uni,
344 FlowId: 1,
345 GemportId: gem1,
346 }
347
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700348 olt.storeGemPortIdByFlow(flow1)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800349 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1) // we have 1 gem port
350 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1) // and one flow referencing it
351
352 // add a second flow on the ONU (same gem)
353 flow2 := &openolt.Flow{
354 AccessIntfId: pon,
355 OnuId: onu,
356 PortNo: uni,
357 FlowId: 2,
358 GemportId: gem1,
359 }
360
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700361 olt.storeGemPortIdByFlow(flow2)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800362 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1) // we have 1 gem port
363 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 2) // and two flows referencing it
364
365 // add a third flow on the ONU (different gem)
366 flow3 := &openolt.Flow{
367 AccessIntfId: pon,
368 OnuId: onu,
369 PortNo: uni,
370 FlowId: 2,
371 GemportId: 1025,
372 }
373
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700374 olt.storeGemPortIdByFlow(flow3)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800375 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2) // we have 2 gem ports
376 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 2) // two flows referencing the first one
377 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem2]), 1) // and one flow referencing the second one
378}
379
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700380func Test_Olt_storeGemPortIdReplicatedFlow(t *testing.T) {
381 const (
382 pon = 1
383 onu = 1
384 uni = 16
385 gem1 = 1024
386 gem2 = 1025
387 )
388
389 numPon := 2
390 numOnu := 2
391
Matteo Scandolo8a574812021-05-20 15:18:53 -0700392 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700393
394 // add a flow that needs replication
395 pbitToGemPortMap := make(map[uint32]uint32)
396 pbitToGemPortMap[0] = gem1
397 pbitToGemPortMap[1] = gem2
398 flow1 := &openolt.Flow{
399 AccessIntfId: pon,
400 OnuId: onu,
401 PortNo: uni,
402 FlowId: 1,
403 GemportId: 0,
404 ReplicateFlow: true,
405 PbitToGemport: pbitToGemPortMap,
406 }
407
408 olt.storeGemPortIdByFlow(flow1)
409 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2) // we have 2 gem ports in the flow
410 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1) // and one flow referencing them
411 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem2]), 1) // and one flow referencing them
412}
413
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800414func Test_Olt_freeGemPortId(t *testing.T) {
415 const (
416 pon = 1
417 onu = 1
418 uni = 16
419 gem1 = 1024
420 gem2 = 1025
421 flow1 = 1
422 flow2 = 2
423 flow3 = 3
424 )
425
426 numPon := 2
427 numOnu := 2
428
Matteo Scandolo8a574812021-05-20 15:18:53 -0700429 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800430
431 olt.GemPortIDs[pon][onu][uni] = make(map[int32]map[uint64]bool)
432 olt.GemPortIDs[pon][onu][uni][gem1] = make(map[uint64]bool)
433 olt.GemPortIDs[pon][onu][uni][gem1][flow1] = true
434 olt.GemPortIDs[pon][onu][uni][gem1][flow2] = true
435 olt.GemPortIDs[pon][onu][uni][gem2] = make(map[uint64]bool)
436 olt.GemPortIDs[pon][onu][uni][gem2][flow3] = true
437
438 // remove one flow on the first gem, check that the gem is still allocated as there is still a flow referencing it
439 // NOTE that the flow remove only carries the flow ID, no other information
440 flowGem1 := &openolt.Flow{
441 FlowId: flow1,
442 }
443
444 olt.freeGemPortId(flowGem1)
445 // we still have two unis in the map
446 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 2)
447
448 // we should now have a single gem referenced on this UNI
449 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni][gem1]), 1, "gemport-not-removed")
450
451 // the gem should still reference flow 2
452 assert.Equal(t, olt.GemPortIDs[pon][onu][uni][gem1][flow2], true)
453 // but should not reference flow1
454 _, flow1Exists := olt.GemPortIDs[pon][onu][uni][gem1][flow1]
455 assert.Equal(t, flow1Exists, false)
456
457 // this is the only flow remaining on this gem, the gem should be removed
458 flowGem2 := &openolt.Flow{
459 FlowId: flow2,
460 }
461 olt.freeGemPortId(flowGem2)
462
463 // we should now have a single gem referenced on this UNI
464 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 1, "gemport-not-removed")
465
466 // and it should be gem2
467 _, gem1exists := olt.GemPortIDs[pon][onu][uni][gem1]
468 assert.Equal(t, gem1exists, false)
469 _, gem2exists := olt.GemPortIDs[pon][onu][uni][gem2]
470 assert.Equal(t, gem2exists, true)
471}
472
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700473func Test_Olt_freeGemPortIdReplicatedflow(t *testing.T) {
474 const (
475 pon = 1
476 onu = 1
477 uni = 16
478 gem1 = 1024
479 gem2 = 1025
480 flow1 = 1
481 )
482
483 numPon := 2
484 numOnu := 2
485
Matteo Scandolo8a574812021-05-20 15:18:53 -0700486 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700487
488 olt.GemPortIDs[pon][onu][uni] = make(map[int32]map[uint64]bool)
489 olt.GemPortIDs[pon][onu][uni][gem1] = make(map[uint64]bool)
490 olt.GemPortIDs[pon][onu][uni][gem1][flow1] = true
491 olt.GemPortIDs[pon][onu][uni][gem2] = make(map[uint64]bool)
492 olt.GemPortIDs[pon][onu][uni][gem2][flow1] = true
493
494 // this flow was a replicated flow, remove all the gems that are referenced by that flow
495 flowMultiGem := &openolt.Flow{
496 FlowId: flow1,
497 }
498
499 olt.freeGemPortId(flowMultiGem)
500
501 // this flow removes all the gems, so no UNI should be left
502 assert.Equal(t, len(olt.GemPortIDs[pon][onu][uni]), 0)
503}
504
Matteo Scandolo21195d62021-04-07 14:31:23 -0700505// testing that we can validate flows while we are adding them
506func Benchmark_validateAndAddFlows(b *testing.B) {
507 const (
508 pon = 0
509 start = 0
510 end = 512
511 )
512
513 for r := 0; r < b.N; r++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700514 olt := createMockOlt(1, 512, 4, []ServiceIf{})
Matteo Scandolo21195d62021-04-07 14:31:23 -0700515
516 wg := sync.WaitGroup{}
517
518 // concurrently adding 1K gems
519 for i := start; i < end; i++ {
520 wg.Add(1)
521 flow := &openolt.Flow{
522 AccessIntfId: pon,
523 OnuId: int32(i),
524 PortNo: uint32(i),
525 GemportId: int32(i),
526 FlowId: uint64(i),
527 }
528 go func(wg *sync.WaitGroup) {
529 olt.storeGemPortIdByFlow(flow)
530 olt.storeAllocId(flow)
531 wg.Done()
532 }(&wg)
533 }
534
535 // at the same time validate flows
536 for i := start; i < end; i++ {
537 wg.Add(1)
538 flow := &openolt.Flow{
539 AccessIntfId: pon,
540 OnuId: int32(i),
541 PortNo: uint32(i),
542 GemportId: 1,
543 FlowId: uint64(i),
544 }
545 go func(wg *sync.WaitGroup) {
546 _ = olt.validateFlow(flow)
547 wg.Done()
548 }(&wg)
549 }
550
551 wg.Wait()
552 // NOTE this tests only fails if there is concurrent access to the map
553 }
554}
555
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800556func Test_Olt_validateFlow(t *testing.T) {
557
558 const (
559 pon0 = 0
560 pon1 = 1
561 onu0 = 0
562 onu1 = 1
563 uniPort = 0
564 usedGemIdPon0 = 1024
565 usedGemIdPon1 = 1025
566 usedAllocIdPon0 = 1
567 usedAllocIdPon1 = 2
568 flowId = 1
569 )
570
571 numPon := 2
572 numOnu := 2
573
Matteo Scandolo8a574812021-05-20 15:18:53 -0700574 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800575
576 olt.GemPortIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
577 olt.GemPortIDs[pon1][onu0][uniPort] = make(map[int32]map[uint64]bool)
578
579 olt.GemPortIDs[pon0][onu0][uniPort][usedGemIdPon0] = make(map[uint64]bool)
580 olt.GemPortIDs[pon0][onu0][uniPort][usedGemIdPon0][flowId] = true
581 olt.GemPortIDs[pon1][onu0][uniPort][usedGemIdPon1] = make(map[uint64]bool)
582 olt.GemPortIDs[pon1][onu0][uniPort][usedGemIdPon1][flowId] = true
583
584 olt.AllocIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
585 olt.AllocIDs[pon1][onu0][uniPort] = make(map[int32]map[uint64]bool)
586 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0] = make(map[uint64]bool)
587 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0][flowId] = true
588 olt.AllocIDs[pon1][onu0][uniPort][usedAllocIdPon1] = make(map[uint64]bool)
589 olt.AllocIDs[pon1][onu0][uniPort][usedAllocIdPon1][flowId] = true
590
591 // a GemPortID can be referenced across multiple flows on the same ONU
592 validGemFlow := &openolt.Flow{
593 AccessIntfId: pon0,
594 OnuId: onu0,
595 GemportId: usedGemIdPon0,
596 }
597
598 err := olt.validateFlow(validGemFlow)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700599 assert.NoError(t, err)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800600
601 // a GemPortID can NOT be referenced across different ONUs on the same PON
602 invalidGemFlow := &openolt.Flow{
603 AccessIntfId: pon0,
604 OnuId: onu1,
605 GemportId: usedGemIdPon0,
606 }
607 err = olt.validateFlow(invalidGemFlow)
608 assert.Error(t, err, "gem-1024-already-in-use-on-uni-0-onu-0")
609
610 // if a flow reference the same GEM on a different PON it's a valid flow
611 invalidGemDifferentPonFlow := &openolt.Flow{
612 AccessIntfId: pon1,
613 OnuId: onu1,
614 GemportId: usedGemIdPon0,
615 }
616 err = olt.validateFlow(invalidGemDifferentPonFlow)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700617 assert.NoError(t, err)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800618
619 // an allocId can be referenced across multiple flows on the same ONU
620 validAllocFlow := &openolt.Flow{
621 AccessIntfId: pon0,
622 OnuId: onu0,
623 AllocId: usedAllocIdPon0,
624 }
625 err = olt.validateFlow(validAllocFlow)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700626 assert.NoError(t, err)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800627
628 // an allocId can NOT be referenced across different ONUs on the same PON
629 invalidAllocFlow := &openolt.Flow{
630 AccessIntfId: pon0,
631 OnuId: onu1,
632 AllocId: usedAllocIdPon0,
633 }
634 err = olt.validateFlow(invalidAllocFlow)
635 assert.Error(t, err, "allocId-1-already-in-use-on-uni-0-onu-0")
636
637 // if a flow reference the same AllocId on a different PON it's a valid flow
638 invalidAllocDifferentPonFlow := &openolt.Flow{
639 AccessIntfId: pon1,
640 OnuId: onu1,
641 AllocId: usedAllocIdPon0,
642 }
643 err = olt.validateFlow(invalidAllocDifferentPonFlow)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700644 assert.NoError(t, err)
645}
646
647func Test_Olt_validateReplicatedFlow(t *testing.T) {
648
649 const (
650 pon0 = 0
651 onu0 = 0
652 onu1 = 1
653 uniPort = 0
654 usedGemId1 = 1024
655 usedGemId2 = 1025
656 usedAllocIdPon0 = 1
657 flowId = 1
658 )
659
660 numPon := 1
661 numOnu := 1
662
Matteo Scandolo8a574812021-05-20 15:18:53 -0700663 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700664
665 // both the gemports referenced in this flow are already allocated
666 olt.GemPortIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
667 olt.GemPortIDs[pon0][onu0][uniPort][usedGemId1] = make(map[uint64]bool)
668 olt.GemPortIDs[pon0][onu0][uniPort][usedGemId1][flowId] = true
669 olt.GemPortIDs[pon0][onu0][uniPort][usedGemId2] = make(map[uint64]bool)
670 olt.GemPortIDs[pon0][onu0][uniPort][usedGemId2][flowId] = true
671
672 olt.AllocIDs[pon0][onu0][uniPort] = make(map[int32]map[uint64]bool)
673 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0] = make(map[uint64]bool)
674 olt.AllocIDs[pon0][onu0][uniPort][usedAllocIdPon0][flowId] = true
675
676 pbitToGemPortMap := make(map[uint32]uint32)
677 pbitToGemPortMap[0] = usedGemId1
678 pbitToGemPortMap[1] = usedGemId2
679
680 // this flow should fail vlidation as the gems are already allocated to Onu0
681 invalidGemFlow := &openolt.Flow{
682 AccessIntfId: pon0,
683 OnuId: onu1,
684 PortNo: uniPort,
685 GemportId: 0,
686 ReplicateFlow: true,
687 PbitToGemport: pbitToGemPortMap,
688 }
689
690 err := olt.validateFlow(invalidGemFlow)
691 assert.NotNil(t, err)
692
693 // PbitToGemport is a map, so any of the two gemPorts can fail first and determine the error message
694 foundError := false
695 switch err.Error() {
696 case fmt.Sprintf("gem-%d-already-in-use-on-uni-%d-onu-%d-replicated-flow-%d", usedGemId2, uniPort, onu0, invalidGemFlow.FlowId):
697 foundError = true
698 case fmt.Sprintf("gem-%d-already-in-use-on-uni-%d-onu-%d-replicated-flow-%d", usedGemId1, uniPort, onu0, invalidGemFlow.FlowId):
699 foundError = true
700
701 }
702 assert.True(t, foundError)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800703}
Matteo Scandolob5913142021-03-19 16:10:18 -0700704
705func Test_Olt_OmciMsgOut(t *testing.T) {
706 numPon := 4
707 numOnu := 4
708
Matteo Scandolo8a574812021-05-20 15:18:53 -0700709 olt := createMockOlt(numPon, numOnu, 1, []ServiceIf{})
Matteo Scandolob5913142021-03-19 16:10:18 -0700710
711 // a malformed packet should return an error
712 msg := &openolt.OmciMsg{
713 IntfId: 1,
714 OnuId: 1,
715 Pkt: []byte{},
716 }
717 ctx := context.TODO()
718 _, err := olt.OmciMsgOut(ctx, msg)
719 assert.Error(t, err, "olt-received-malformed-omci-packet")
720
721 // a correct packet for a non exiting ONU should throw an error
722 msg = &openolt.OmciMsg{
723 IntfId: 10,
724 OnuId: 25,
725 Pkt: makeOmciSetRequest(t),
726 }
727 _, err = olt.OmciMsgOut(ctx, msg)
728 assert.Error(t, err, "Cannot find PonPort with id 10 in OLT 0")
729
730 // a correct packet for a disabled ONU should be dropped
731 // note that an error is not returned, this is valid in BBsim
732 const (
733 ponId = 1
734 onuId = 1
735 )
736 pon, _ := olt.GetPonById(ponId)
737 onu, _ := pon.GetOnuById(onuId)
738 onu.InternalState.SetState(OnuStateDisabled)
739 msg = &openolt.OmciMsg{
740 IntfId: ponId,
741 OnuId: onuId,
742 Pkt: makeOmciSetRequest(t),
743 }
744 _, err = olt.OmciMsgOut(ctx, msg)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700745 assert.NoError(t, err)
Matteo Scandolob5913142021-03-19 16:10:18 -0700746 assert.Equal(t, len(onu.Channel), 0) // check that no messages have been sent
747
748 // test that the ONU receives a valid packet
749 onu.InternalState.SetState(OnuStateEnabled)
750 _, err = olt.OmciMsgOut(ctx, msg)
Matteo Scandoloa8eca492021-03-23 09:45:16 -0700751 assert.NoError(t, err)
Matteo Scandolob5913142021-03-19 16:10:18 -0700752 assert.Equal(t, len(onu.Channel), 1) // check that one message have been sent
753
754}