blob: 4fe095b6bc3bc2af23bd476b676ec228c2251708 [file] [log] [blame]
khenaidoo820197c2020-02-13 16:35:33 -05001/*
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 */
16package route
17
18import (
19 "context"
20 "errors"
21 "fmt"
khenaidoo820197c2020-02-13 16:35:33 -050022 "math/rand"
23 "reflect"
24 "strings"
25 "sync"
26 "testing"
27 "time"
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040028
29 "github.com/opencord/voltha-protos/v3/go/openflow_13"
30 "github.com/opencord/voltha-protos/v3/go/voltha"
31 "github.com/stretchr/testify/assert"
khenaidoo820197c2020-02-13 16:35:33 -050032)
33
34const (
35 logicalDeviceID = "ld"
36 oltDeviceID = "olt"
37)
38
khenaidoo0db4c812020-05-27 15:27:30 -040039const testSetupPhase contextKey = "testSetupPhase"
40
41type contextKey string
42
khenaidoo820197c2020-02-13 16:35:33 -050043//portRegistration is a message sent from an OLT device to a logical device to create a logical port
44type portRegistration struct {
45 port *voltha.Port
46 rootPort bool
47}
48
49//onuRegistration is a message sent from an ONU device to an OLT device to register an ONU
50type onuRegistration struct {
51 onu *voltha.Device
52 oltPonNo uint32
53 onuPonNo uint32
54}
55
56type logicalDeviceManager struct {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040057 logicalDeviceID string
58 ports map[uint32]*voltha.LogicalPort
khenaidoo820197c2020-02-13 16:35:33 -050059 deviceRoutes *DeviceRoutes
60 ldChnl chan portRegistration
61 numLogicalPorts int
62 done chan struct{}
63}
64
65func newLogicalDeviceManager(ld *voltha.LogicalDevice, ch chan portRegistration, totalLogicalPorts int, done chan struct{}) *logicalDeviceManager {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040066 ports := make(map[uint32]*voltha.LogicalPort)
67 for _, p := range ld.Ports {
68 ports[p.DevicePortNo] = p
69 }
70
khenaidoo820197c2020-02-13 16:35:33 -050071 return &logicalDeviceManager{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040072 logicalDeviceID: ld.Id,
73 ports: ports,
khenaidoo820197c2020-02-13 16:35:33 -050074 ldChnl: ch,
75 numLogicalPorts: totalLogicalPorts,
76 done: done,
77 }
78}
79
80func (ldM *logicalDeviceManager) start(getDevice GetDeviceFunc, buildRoutes bool) {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040081 ldM.deviceRoutes = NewDeviceRoutes(ldM.logicalDeviceID, getDevice)
khenaidoo820197c2020-02-13 16:35:33 -050082 ofpPortNo := uint32(1)
83 for portReg := range ldM.ldChnl {
84 if portReg.port == nil {
85 // End of registration - exit loop
86 break
87 }
88 lp := &voltha.LogicalPort{
89 Id: portReg.port.Label,
90 OfpPort: &openflow_13.OfpPort{PortNo: ofpPortNo},
91 DeviceId: portReg.port.DeviceId,
92 DevicePortNo: portReg.port.PortNo,
93 RootPort: portReg.rootPort,
94 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040095 ldM.ports[lp.DevicePortNo] = lp
khenaidoo820197c2020-02-13 16:35:33 -050096 if buildRoutes {
khenaidoo0db4c812020-05-27 15:27:30 -040097 device, err := getDevice(context.WithValue(context.Background(), testSetupPhase, true), lp.DeviceId)
98 if err != nil {
99 fmt.Println("Error when getting device:", lp.DeviceId, err)
100 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400101 if err := ldM.deviceRoutes.AddPort(context.Background(), lp, device, ldM.ports); err != nil && !strings.Contains(err.Error(), "code = FailedPrecondition") {
102 fmt.Println("(Error when adding port:", lp, len(ldM.ports), err)
khenaidoo820197c2020-02-13 16:35:33 -0500103 }
104 }
105 ofpPortNo++
106 }
107 // Inform the caller we are now done
108 ldM.done <- struct{}{}
109}
110
111type oltManager struct {
112 olt *voltha.Device
113 logicalDeviceMgr *logicalDeviceManager
114 numNNIPort int
115 numPonPortOnOlt int
116 oltChnl chan onuRegistration
117}
118
119func newOltManager(oltDeviceID string, ldMgr *logicalDeviceManager, numNNIPort int, numPonPortOnOlt int, ch chan onuRegistration) *oltManager {
120 return &oltManager{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400121 olt: &voltha.Device{Id: oltDeviceID, ParentId: ldMgr.logicalDeviceID, Root: true},
khenaidoo820197c2020-02-13 16:35:33 -0500122 logicalDeviceMgr: ldMgr,
123 numNNIPort: numNNIPort,
124 numPonPortOnOlt: numPonPortOnOlt,
125 oltChnl: ch,
126 }
127}
128
129func (oltM *oltManager) start() {
130 oltM.olt.Ports = make([]*voltha.Port, 0)
131 // Setup the OLT nni ports and trigger the nni ports creation
132 for nniPort := 1; nniPort < oltM.numNNIPort+1; nniPort++ {
133 p := &voltha.Port{Label: fmt.Sprintf("nni-%d", nniPort), PortNo: uint32(nniPort), DeviceId: oltM.olt.Id, Type: voltha.Port_ETHERNET_NNI}
134 oltM.olt.Ports = append(oltM.olt.Ports, p)
135 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: p, rootPort: true}
136 }
137
138 // Create OLT pon ports
139 for ponPort := oltM.numNNIPort + 1; ponPort < oltM.numPonPortOnOlt+oltM.numNNIPort+1; ponPort++ {
140 p := voltha.Port{PortNo: uint32(ponPort), DeviceId: oltM.olt.Id, Type: voltha.Port_PON_OLT}
141 oltM.olt.Ports = append(oltM.olt.Ports, &p)
142 }
143
144 // Wait for onu registration
145 for onuReg := range oltM.oltChnl {
146 if onuReg.onu == nil {
147 // All onu has registered - exit the loop
148 break
149 }
150 oltM.registerOnu(onuReg.onu, onuReg.oltPonNo, onuReg.onuPonNo)
151 }
152 // Inform the logical device manager we are done
153 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: nil}
154}
155
156func (oltM *oltManager) registerOnu(onu *voltha.Device, oltPonNo uint32, onuPonNo uint32) {
157 // Update the olt pon peers
158 for _, port := range oltM.olt.Ports {
159 if port.Type == voltha.Port_PON_OLT && port.PortNo == oltPonNo {
160 port.Peers = append(port.Peers, &voltha.Port_PeerPort{DeviceId: onu.Id, PortNo: onuPonNo})
161 }
162 }
163 // For each uni port on the ONU trigger the creation of a logical port
164 for _, port := range onu.Ports {
165 if port.Type == voltha.Port_ETHERNET_UNI {
166 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: port, rootPort: false}
167 }
168 }
169}
170
171type onuManager struct {
172 oltMgr *oltManager
173 numOnus int
174 numUnisPerOnu int
175 startingUniPortNo int
176 numGetDeviceInvoked int
177 numGetDeviceInvokedLock sync.RWMutex
178 deviceLock sync.RWMutex
179 onus []*voltha.Device
180}
181
182func newOnuManager(oltMgr *oltManager, numOnus int, numUnisPerOnu int, startingUniPortNo int) *onuManager {
183 return &onuManager{
184 oltMgr: oltMgr,
185 numOnus: numOnus,
186 numUnisPerOnu: numUnisPerOnu,
187 startingUniPortNo: startingUniPortNo,
188 onus: make([]*voltha.Device, 0),
189 }
190}
191
192func (onuM *onuManager) start(startingOltPeerPortNo int, numPonPortOnOlt int) {
193 var wg sync.WaitGroup
194 for oltPonNo := startingOltPeerPortNo; oltPonNo < startingOltPeerPortNo+numPonPortOnOlt; oltPonNo++ {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400195 for onuID := 0; onuID < onuM.numOnus; onuID++ {
khenaidoo820197c2020-02-13 16:35:33 -0500196 wg.Add(1)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400197 go func(onuID int, oltPonNum int) {
khenaidoo820197c2020-02-13 16:35:33 -0500198 var onu *voltha.Device
199 defer wg.Done()
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400200 id := fmt.Sprintf("%d-onu-%d", oltPonNum, onuID)
khenaidoo820197c2020-02-13 16:35:33 -0500201 onu = &voltha.Device{Id: id, ParentId: onuM.oltMgr.olt.Id, ParentPortNo: uint32(oltPonNum)}
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400202 ponPort := &voltha.Port{Label: fmt.Sprintf("%s:pon-%d", onu.Id, onuID), PortNo: 1, DeviceId: onu.Id, Type: voltha.Port_PON_ONU}
khenaidoo820197c2020-02-13 16:35:33 -0500203 ponPort.Peers = make([]*voltha.Port_PeerPort, 0)
204 peerPort := voltha.Port_PeerPort{DeviceId: onuM.oltMgr.olt.Id, PortNo: uint32(oltPonNum)}
205 ponPort.Peers = append(ponPort.Peers, &peerPort)
206 onu.Ports = make([]*voltha.Port, 0)
207 onu.Ports = append(onu.Ports, ponPort)
208 for j := onuM.startingUniPortNo; j < onuM.numUnisPerOnu+onuM.startingUniPortNo; j++ {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400209 uniPort := &voltha.Port{Label: fmt.Sprintf("%s:uni-%d", onu.Id, j), PortNo: uint32(oltPonNum)<<12 + uint32(onuID+1)<<4 + uint32(j), DeviceId: onu.Id, Type: voltha.Port_ETHERNET_UNI}
khenaidoo820197c2020-02-13 16:35:33 -0500210 onu.Ports = append(onu.Ports, uniPort)
211 }
212 onuM.deviceLock.Lock()
213 onuM.onus = append(onuM.onus, onu)
214 onuM.deviceLock.Unlock()
215 onuM.oltMgr.oltChnl <- onuRegistration{
216 onu: onu,
217 oltPonNo: uint32(oltPonNum),
218 onuPonNo: 1,
219 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400220 }(onuID, oltPonNo)
khenaidoo820197c2020-02-13 16:35:33 -0500221 }
222 }
223 wg.Wait()
224 //send an empty device to indicate the end of onu registration
225 onuM.oltMgr.oltChnl <- onuRegistration{
226 onu: nil,
227 oltPonNo: 0,
228 onuPonNo: 1,
229 }
230}
231
232func (onuM *onuManager) getOnu(deviceID string) *voltha.Device {
233 onuM.deviceLock.Lock()
234 defer onuM.deviceLock.Unlock()
235 for _, onu := range onuM.onus {
236 if onu.Id == deviceID {
237 return onu
238 }
239 }
240 return nil
241}
242
khenaidoo0db4c812020-05-27 15:27:30 -0400243func (onuM *onuManager) GetDeviceHelper(ctx context.Context, id string) (*voltha.Device, error) {
244 if ctx.Value(testSetupPhase) != true {
245 onuM.numGetDeviceInvokedLock.Lock()
246 onuM.numGetDeviceInvoked++
247 onuM.numGetDeviceInvokedLock.Unlock()
248 }
khenaidoo820197c2020-02-13 16:35:33 -0500249 if id == oltDeviceID {
250 return onuM.oltMgr.olt, nil
251 }
252 if onu := onuM.getOnu(id); onu != nil {
253 return onu, nil
254 }
255 return nil, errors.New("not-found")
256}
257
258func TestDeviceRoutes_ComputeRoutes(t *testing.T) {
259 numNNIPort := 2
260 numPonPortOnOlt := 8
khenaidoo0db4c812020-05-27 15:27:30 -0400261 numOnuPerOltPonPort := 256
khenaidoo820197c2020-02-13 16:35:33 -0500262 numUniPerOnu := 4
263 done := make(chan struct{})
264
265 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d",
266 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
267
268 // Create all the devices and logical device before computing the routes in one go
269 ld := &voltha.LogicalDevice{Id: logicalDeviceID}
270 ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
271 ldMgr := newLogicalDeviceManager(ld, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
272 oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
273 oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
274 onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
275 getDevice := onuMgr.GetDeviceHelper
276 // Start the managers. Only the devices are created. No routes will be built.
277 go ldMgr.start(getDevice, false)
278 go oltMgr.start()
279 go onuMgr.start(numNNIPort+1, numPonPortOnOlt)
280
281 // Wait for all the devices to be created
282 <-done
283 close(oltMgrChnl)
284 close(ldMgrChnl)
285
286 // Computes the routes
287 start := time.Now()
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400288 err := ldMgr.deviceRoutes.ComputeRoutes(context.TODO(), ldMgr.ports)
khenaidoo820197c2020-02-13 16:35:33 -0500289 assert.Nil(t, err)
290
291 // Validate the routes are up to date
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400292 assert.True(t, ldMgr.deviceRoutes.isUpToDate(ldMgr.ports))
khenaidoo820197c2020-02-13 16:35:33 -0500293
294 // Validate the expected number of routes
295 assert.EqualValues(t, 2*numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, len(ldMgr.deviceRoutes.Routes))
296
297 // Validate the root ports
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400298 for _, port := range ldMgr.ports {
khenaidoo820197c2020-02-13 16:35:33 -0500299 assert.Equal(t, port.RootPort, ldMgr.deviceRoutes.IsRootPort(port.OfpPort.PortNo))
300 }
301 fmt.Println(fmt.Sprintf("Total Time:%dms, Total Routes:%d NumGetDeviceInvoked:%d", time.Since(start)/time.Millisecond, len(ldMgr.deviceRoutes.Routes), onuMgr.numGetDeviceInvoked))
302}
303
304func TestDeviceRoutes_AddPort(t *testing.T) {
305 numNNIPort := 2
khenaidoo0db4c812020-05-27 15:27:30 -0400306 numPonPortOnOlt := 16
307 numOnuPerOltPonPort := 256
khenaidoo820197c2020-02-13 16:35:33 -0500308 numUniPerOnu := 4
309 done := make(chan struct{})
310
311 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d",
312 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
313
314 start := time.Now()
315 // Create all the devices and logical device before computing the routes in one go
316 ld := &voltha.LogicalDevice{Id: logicalDeviceID}
317 ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
318 ldMgr := newLogicalDeviceManager(ld, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
319 oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
320 oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
321 onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
322 getDevice := onuMgr.GetDeviceHelper
323 // Start the managers and trigger the routes to be built as the logical ports become available
324 go ldMgr.start(getDevice, true)
325 go oltMgr.start()
326 go onuMgr.start(numNNIPort+1, numPonPortOnOlt)
327
328 // Wait for all the devices to be created and routes created
329 <-done
330 close(oltMgrChnl)
331 close(ldMgrChnl)
332
333 ldMgr.deviceRoutes.Print()
334
335 // Validate the routes are up to date
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400336 assert.True(t, ldMgr.deviceRoutes.isUpToDate(ldMgr.ports))
khenaidoo820197c2020-02-13 16:35:33 -0500337
338 // Validate the expected number of routes
339 assert.EqualValues(t, 2*numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, len(ldMgr.deviceRoutes.Routes))
340
341 // Validate the root ports
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400342 for _, port := range ldMgr.ports {
khenaidoo820197c2020-02-13 16:35:33 -0500343 assert.Equal(t, port.RootPort, ldMgr.deviceRoutes.IsRootPort(port.OfpPort.PortNo))
344 }
345
346 fmt.Println(fmt.Sprintf("Total Time:%dms, Total Routes:%d NumGetDeviceInvoked:%d", time.Since(start)/time.Millisecond, len(ldMgr.deviceRoutes.Routes), onuMgr.numGetDeviceInvoked))
347}
348
349func TestDeviceRoutes_compareRoutesGeneration(t *testing.T) {
350 numNNIPort := 2
351 numPonPortOnOlt := 8
352 numOnuPerOltPonPort := 32
353 numUniPerOnu := 4
354 done := make(chan struct{})
355
356 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d",
357 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
358
359 // Create all the devices and logical device before computing the routes in one go
360 ld1 := &voltha.LogicalDevice{Id: logicalDeviceID}
361 ldMgrChnl1 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
362 ldMgr1 := newLogicalDeviceManager(ld1, ldMgrChnl1, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
363 oltMgrChnl1 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
364 oltMgr1 := newOltManager(oltDeviceID, ldMgr1, numNNIPort, numPonPortOnOlt, oltMgrChnl1)
365 onuMgr1 := newOnuManager(oltMgr1, numOnuPerOltPonPort, numUniPerOnu, 2)
366 getDevice := onuMgr1.GetDeviceHelper
367 // Start the managers. Only the devices are created. No routes will be built.
368 go ldMgr1.start(getDevice, false)
369 go oltMgr1.start()
370 go onuMgr1.start(numNNIPort+1, numPonPortOnOlt)
371
372 // Wait for all the devices to be created
373 <-done
374 close(oltMgrChnl1)
375 close(ldMgrChnl1)
376
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400377 err := ldMgr1.deviceRoutes.ComputeRoutes(context.TODO(), ldMgr1.ports)
khenaidoo820197c2020-02-13 16:35:33 -0500378 assert.Nil(t, err)
379
380 routesGeneratedAllAtOnce := ldMgr1.deviceRoutes.Routes
381
382 done = make(chan struct{})
383 // Create all the devices and logical device before computing the routes in one go
384 ld2 := &voltha.LogicalDevice{Id: logicalDeviceID}
385 ldMgrChnl2 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
386 ldMgr2 := newLogicalDeviceManager(ld2, ldMgrChnl2, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
387 oltMgrChnl2 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
388 oltMgr2 := newOltManager(oltDeviceID, ldMgr2, numNNIPort, numPonPortOnOlt, oltMgrChnl2)
389 onuMgr2 := newOnuManager(oltMgr2, numOnuPerOltPonPort, numUniPerOnu, 2)
390 // Start the managers. Only the devices are created. No routes will be built.
391 go ldMgr2.start(getDevice, true)
392 go oltMgr2.start()
393 go onuMgr2.start(numNNIPort+1, numPonPortOnOlt)
394
395 // Wait for all the devices to be created
396 <-done
397 close(oltMgrChnl2)
398 close(ldMgrChnl2)
399
400 routesGeneratedPerPort := ldMgr1.deviceRoutes.Routes
401 assert.True(t, isEqual(routesGeneratedAllAtOnce, routesGeneratedPerPort))
402}
403
404func TestDeviceRoutes_reverseRoute(t *testing.T) {
405 // Test the typical use case - 2 hops in a route
406 route := make([]Hop, 2)
407 route[0].DeviceID = "d1"
408 route[0].Ingress = 1
409 route[0].Egress = 2
410 route[1].DeviceID = "d2"
411 route[1].Ingress = 10
412 route[1].Egress = 15
413
414 reverseRoute := getReverseRoute(route)
415 assert.Equal(t, 2, len(reverseRoute))
416 assert.Equal(t, "d2", reverseRoute[0].DeviceID)
417 assert.Equal(t, "d1", reverseRoute[1].DeviceID)
418 assert.Equal(t, uint32(15), reverseRoute[0].Ingress)
419 assert.Equal(t, uint32(10), reverseRoute[0].Egress)
420 assert.Equal(t, uint32(2), reverseRoute[1].Ingress)
421 assert.Equal(t, uint32(1), reverseRoute[1].Egress)
422
423 fmt.Println("Reverse of two hops successful.")
424
425 //Test 3 hops in a route
426 route = make([]Hop, 3)
427 route[0].DeviceID = "d1"
428 route[0].Ingress = 1
429 route[0].Egress = 2
430 route[1].DeviceID = "d2"
431 route[1].Ingress = 10
432 route[1].Egress = 15
433 route[2].DeviceID = "d3"
434 route[2].Ingress = 20
435 route[2].Egress = 25
436 reverseRoute = getReverseRoute(route)
437 assert.Equal(t, 3, len(reverseRoute))
438 assert.Equal(t, "d3", reverseRoute[0].DeviceID)
439 assert.Equal(t, "d2", reverseRoute[1].DeviceID)
440 assert.Equal(t, "d1", reverseRoute[2].DeviceID)
441 assert.Equal(t, uint32(25), reverseRoute[0].Ingress)
442 assert.Equal(t, uint32(20), reverseRoute[0].Egress)
443 assert.Equal(t, uint32(15), reverseRoute[1].Ingress)
444 assert.Equal(t, uint32(10), reverseRoute[1].Egress)
445 assert.Equal(t, uint32(2), reverseRoute[2].Ingress)
446 assert.Equal(t, uint32(1), reverseRoute[2].Egress)
447
448 fmt.Println("Reverse of three hops successful.")
449
450 // Test any number of hops in a route
451 numRoutes := rand.Intn(100)
452 route = make([]Hop, numRoutes)
453 deviceIds := make([]string, numRoutes)
454 ingressNos := make([]uint32, numRoutes)
455 egressNos := make([]uint32, numRoutes)
456 for i := 0; i < numRoutes; i++ {
457 deviceIds[i] = fmt.Sprintf("d-%d", i)
458 ingressNos[i] = rand.Uint32()
459 egressNos[i] = rand.Uint32()
460 }
461 for i := 0; i < numRoutes; i++ {
462 route[i].DeviceID = deviceIds[i]
463 route[i].Ingress = ingressNos[i]
464 route[i].Egress = egressNos[i]
465 }
466 reverseRoute = getReverseRoute(route)
467 assert.Equal(t, numRoutes, len(reverseRoute))
468 for i, j := 0, numRoutes-1; j >= 0; i, j = i+1, j-1 {
469 assert.Equal(t, deviceIds[j], reverseRoute[i].DeviceID)
470 assert.Equal(t, egressNos[j], reverseRoute[i].Ingress)
471 assert.Equal(t, ingressNos[j], reverseRoute[i].Egress)
472 }
473
474 fmt.Println(fmt.Sprintf("Reverse of %d hops successful.", numRoutes))
475
476 reverseOfReverse := getReverseRoute(reverseRoute)
477 assert.Equal(t, route, reverseOfReverse)
478 fmt.Println("Reverse of reverse successful.")
479}
480
481func isEqual(routes1 map[PathID][]Hop, routes2 map[PathID][]Hop) bool {
482 if routes1 == nil && routes2 == nil {
483 return true
484 }
485 if (routes1 == nil && routes2 != nil) || (routes2 == nil && routes1 != nil) {
486 return false
487 }
488 if len(routes1) != len(routes2) {
489 return false
490 }
491 for routeID1, routeHop1 := range routes1 {
492 found := false
493 for routeID2, routeHop2 := range routes2 {
494 if routeID1 == routeID2 {
495 if !reflect.DeepEqual(routeHop1, routeHop2) {
496 return false
497 }
498 found = true
499 break
500 }
501 }
502 if !found {
503 return false
504 }
505 }
506 return true
507}