blob: 38578376f012d314d02330364036b9ed53bc481b [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 {
Kent Hagerman2a07b862020-06-19 15:23:07 -040051 onuID string
52 onuPorts map[uint32]*voltha.Port
khenaidoo820197c2020-02-13 16:35:33 -050053 oltPonNo uint32
54 onuPonNo uint32
55}
56
57type logicalDeviceManager struct {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040058 logicalDeviceID string
Kent Hagerman2a07b862020-06-19 15:23:07 -040059 rootDeviceID string
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040060 ports map[uint32]*voltha.LogicalPort
khenaidoo820197c2020-02-13 16:35:33 -050061 deviceRoutes *DeviceRoutes
62 ldChnl chan portRegistration
63 numLogicalPorts int
64 done chan struct{}
65}
66
Kent Hagerman2a07b862020-06-19 15:23:07 -040067func newLogicalDeviceManager(ld *voltha.LogicalDevice, rootDeviceID string, ch chan portRegistration, totalLogicalPorts int, done chan struct{}) *logicalDeviceManager {
khenaidoo820197c2020-02-13 16:35:33 -050068 return &logicalDeviceManager{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040069 logicalDeviceID: ld.Id,
Kent Hagerman2a07b862020-06-19 15:23:07 -040070 rootDeviceID: rootDeviceID,
71 ports: make(map[uint32]*voltha.LogicalPort),
khenaidoo820197c2020-02-13 16:35:33 -050072 ldChnl: ch,
73 numLogicalPorts: totalLogicalPorts,
74 done: done,
75 }
76}
77
Kent Hagerman2a07b862020-06-19 15:23:07 -040078func (ldM *logicalDeviceManager) start(ctx context.Context, listDevicePorts listDevicePortsFunc, buildRoutes bool) {
79 ldM.deviceRoutes = NewDeviceRoutes(ldM.logicalDeviceID, ldM.rootDeviceID, listDevicePorts)
khenaidoo820197c2020-02-13 16:35:33 -050080 ofpPortNo := uint32(1)
81 for portReg := range ldM.ldChnl {
82 if portReg.port == nil {
83 // End of registration - exit loop
84 break
85 }
86 lp := &voltha.LogicalPort{
87 Id: portReg.port.Label,
88 OfpPort: &openflow_13.OfpPort{PortNo: ofpPortNo},
89 DeviceId: portReg.port.DeviceId,
90 DevicePortNo: portReg.port.PortNo,
91 RootPort: portReg.rootPort,
92 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040093 ldM.ports[lp.DevicePortNo] = lp
khenaidoo820197c2020-02-13 16:35:33 -050094 if buildRoutes {
Kent Hagerman2a07b862020-06-19 15:23:07 -040095 devicePorts, err := listDevicePorts(context.WithValue(context.Background(), testSetupPhase, true), lp.DeviceId)
khenaidoo0db4c812020-05-27 15:27:30 -040096 if err != nil {
97 fmt.Println("Error when getting device:", lp.DeviceId, err)
98 }
Kent Hagerman2a07b862020-06-19 15:23:07 -040099 if err := ldM.deviceRoutes.AddPort(context.Background(), lp, lp.DeviceId, devicePorts, ldM.ports); err != nil && !strings.Contains(err.Error(), "code = FailedPrecondition") {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400100 fmt.Println("(Error when adding port:", lp, len(ldM.ports), err)
khenaidoo820197c2020-02-13 16:35:33 -0500101 }
102 }
103 ofpPortNo++
104 }
105 // Inform the caller we are now done
106 ldM.done <- struct{}{}
107}
108
109type oltManager struct {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400110 oltID string
111 oltPorts map[uint32]*voltha.Port
khenaidoo820197c2020-02-13 16:35:33 -0500112 logicalDeviceMgr *logicalDeviceManager
113 numNNIPort int
114 numPonPortOnOlt int
115 oltChnl chan onuRegistration
116}
117
118func newOltManager(oltDeviceID string, ldMgr *logicalDeviceManager, numNNIPort int, numPonPortOnOlt int, ch chan onuRegistration) *oltManager {
119 return &oltManager{
Kent Hagerman2a07b862020-06-19 15:23:07 -0400120 oltID: oltDeviceID, // ParentId: ldMgr.logicalDeviceID, Root: true},
121 oltPorts: make(map[uint32]*voltha.Port),
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() {
khenaidoo820197c2020-02-13 16:35:33 -0500130 // Setup the OLT nni ports and trigger the nni ports creation
131 for nniPort := 1; nniPort < oltM.numNNIPort+1; nniPort++ {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400132 p := &voltha.Port{Label: fmt.Sprintf("nni-%d", nniPort), PortNo: uint32(nniPort), DeviceId: oltM.oltID, Type: voltha.Port_ETHERNET_NNI}
133 oltM.oltPorts[p.PortNo] = p
khenaidoo820197c2020-02-13 16:35:33 -0500134 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: p, rootPort: true}
135 }
136
137 // Create OLT pon ports
138 for ponPort := oltM.numNNIPort + 1; ponPort < oltM.numPonPortOnOlt+oltM.numNNIPort+1; ponPort++ {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400139 p := &voltha.Port{PortNo: uint32(ponPort), DeviceId: oltM.oltID, Type: voltha.Port_PON_OLT}
140 oltM.oltPorts[p.PortNo] = p
khenaidoo820197c2020-02-13 16:35:33 -0500141 }
142
143 // Wait for onu registration
144 for onuReg := range oltM.oltChnl {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400145 if onuReg.onuPorts == nil {
khenaidoo820197c2020-02-13 16:35:33 -0500146 // All onu has registered - exit the loop
147 break
148 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400149 oltM.registerOnu(onuReg.onuID, onuReg.onuPorts, onuReg.oltPonNo, onuReg.onuPonNo)
khenaidoo820197c2020-02-13 16:35:33 -0500150 }
151 // Inform the logical device manager we are done
152 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: nil}
153}
154
Kent Hagerman2a07b862020-06-19 15:23:07 -0400155func (oltM *oltManager) registerOnu(onuID string, onuPorts map[uint32]*voltha.Port, oltPonNo uint32, onuPonNo uint32) {
khenaidoo820197c2020-02-13 16:35:33 -0500156 // Update the olt pon peers
Kent Hagerman2a07b862020-06-19 15:23:07 -0400157 for _, port := range oltM.oltPorts {
khenaidoo820197c2020-02-13 16:35:33 -0500158 if port.Type == voltha.Port_PON_OLT && port.PortNo == oltPonNo {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400159 port.Peers = append(port.Peers, &voltha.Port_PeerPort{DeviceId: onuID, PortNo: onuPonNo})
khenaidoo820197c2020-02-13 16:35:33 -0500160 }
161 }
162 // For each uni port on the ONU trigger the creation of a logical port
Kent Hagerman2a07b862020-06-19 15:23:07 -0400163 for _, port := range onuPorts {
khenaidoo820197c2020-02-13 16:35:33 -0500164 if port.Type == voltha.Port_ETHERNET_UNI {
165 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: port, rootPort: false}
166 }
167 }
168}
169
170type onuManager struct {
171 oltMgr *oltManager
172 numOnus int
173 numUnisPerOnu int
174 startingUniPortNo int
175 numGetDeviceInvoked int
176 numGetDeviceInvokedLock sync.RWMutex
177 deviceLock sync.RWMutex
178 onus []*voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -0400179 onuPorts map[string]map[uint32]*voltha.Port
khenaidoo820197c2020-02-13 16:35:33 -0500180}
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),
Kent Hagerman2a07b862020-06-19 15:23:07 -0400189 onuPorts: make(map[string]map[uint32]*voltha.Port),
khenaidoo820197c2020-02-13 16:35:33 -0500190 }
191}
192
193func (onuM *onuManager) start(startingOltPeerPortNo int, numPonPortOnOlt int) {
194 var wg sync.WaitGroup
195 for oltPonNo := startingOltPeerPortNo; oltPonNo < startingOltPeerPortNo+numPonPortOnOlt; oltPonNo++ {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400196 for onuID := 0; onuID < onuM.numOnus; onuID++ {
khenaidoo820197c2020-02-13 16:35:33 -0500197 wg.Add(1)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400198 go func(onuID int, oltPonNum int) {
khenaidoo820197c2020-02-13 16:35:33 -0500199 var onu *voltha.Device
200 defer wg.Done()
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400201 id := fmt.Sprintf("%d-onu-%d", oltPonNum, onuID)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400202 onu = &voltha.Device{Id: id, ParentId: onuM.oltMgr.oltID, ParentPortNo: uint32(oltPonNum)}
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400203 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 -0500204 ponPort.Peers = make([]*voltha.Port_PeerPort, 0)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400205 peerPort := voltha.Port_PeerPort{DeviceId: onuM.oltMgr.oltID, PortNo: uint32(oltPonNum)}
khenaidoo820197c2020-02-13 16:35:33 -0500206 ponPort.Peers = append(ponPort.Peers, &peerPort)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400207 onuPorts := make(map[uint32]*voltha.Port)
208 onuPorts[ponPort.PortNo] = ponPort
khenaidoo820197c2020-02-13 16:35:33 -0500209 for j := onuM.startingUniPortNo; j < onuM.numUnisPerOnu+onuM.startingUniPortNo; j++ {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400210 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}
Kent Hagerman2a07b862020-06-19 15:23:07 -0400211 onuPorts[uniPort.PortNo] = uniPort
khenaidoo820197c2020-02-13 16:35:33 -0500212 }
213 onuM.deviceLock.Lock()
214 onuM.onus = append(onuM.onus, onu)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400215 onuM.onuPorts[id] = onuPorts
khenaidoo820197c2020-02-13 16:35:33 -0500216 onuM.deviceLock.Unlock()
217 onuM.oltMgr.oltChnl <- onuRegistration{
Kent Hagerman2a07b862020-06-19 15:23:07 -0400218 onuID: onu.Id,
219 onuPorts: onuPorts,
khenaidoo820197c2020-02-13 16:35:33 -0500220 oltPonNo: uint32(oltPonNum),
221 onuPonNo: 1,
222 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400223 }(onuID, oltPonNo)
khenaidoo820197c2020-02-13 16:35:33 -0500224 }
225 }
226 wg.Wait()
227 //send an empty device to indicate the end of onu registration
228 onuM.oltMgr.oltChnl <- onuRegistration{
Kent Hagerman2a07b862020-06-19 15:23:07 -0400229 onuPorts: nil,
khenaidoo820197c2020-02-13 16:35:33 -0500230 oltPonNo: 0,
231 onuPonNo: 1,
232 }
233}
234
Kent Hagerman2a07b862020-06-19 15:23:07 -0400235func (onuM *onuManager) getOnuPorts(deviceID string) (map[uint32]*voltha.Port, bool) {
khenaidoo820197c2020-02-13 16:35:33 -0500236 onuM.deviceLock.Lock()
237 defer onuM.deviceLock.Unlock()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400238 ports, have := onuM.onuPorts[deviceID]
239 return ports, have
khenaidoo820197c2020-02-13 16:35:33 -0500240}
241
Kent Hagerman2a07b862020-06-19 15:23:07 -0400242func (onuM *onuManager) ListDevicePortsHelper(ctx context.Context, id string) (map[uint32]*voltha.Port, error) {
khenaidoo0db4c812020-05-27 15:27:30 -0400243 if ctx.Value(testSetupPhase) != true {
244 onuM.numGetDeviceInvokedLock.Lock()
245 onuM.numGetDeviceInvoked++
246 onuM.numGetDeviceInvokedLock.Unlock()
247 }
khenaidoo820197c2020-02-13 16:35:33 -0500248 if id == oltDeviceID {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400249 return onuM.oltMgr.oltPorts, nil
khenaidoo820197c2020-02-13 16:35:33 -0500250 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400251 if onuPorts, have := onuM.getOnuPorts(id); have {
252 return onuPorts, nil
khenaidoo820197c2020-02-13 16:35:33 -0500253 }
254 return nil, errors.New("not-found")
255}
256
257func TestDeviceRoutes_ComputeRoutes(t *testing.T) {
258 numNNIPort := 2
259 numPonPortOnOlt := 8
khenaidoo0db4c812020-05-27 15:27:30 -0400260 numOnuPerOltPonPort := 256
khenaidoo820197c2020-02-13 16:35:33 -0500261 numUniPerOnu := 4
262 done := make(chan struct{})
263
264 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d",
265 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
266
267 // Create all the devices and logical device before computing the routes in one go
268 ld := &voltha.LogicalDevice{Id: logicalDeviceID}
269 ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400270 ldMgr := newLogicalDeviceManager(ld, oltDeviceID, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
khenaidoo820197c2020-02-13 16:35:33 -0500271 oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
272 oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
273 onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
khenaidoo820197c2020-02-13 16:35:33 -0500274 // Start the managers. Only the devices are created. No routes will be built.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000275 ctx := context.Background()
Kent Hagerman2a07b862020-06-19 15:23:07 -0400276 go ldMgr.start(ctx, onuMgr.ListDevicePortsHelper, false)
khenaidoo820197c2020-02-13 16:35:33 -0500277 go oltMgr.start()
278 go onuMgr.start(numNNIPort+1, numPonPortOnOlt)
279
280 // Wait for all the devices to be created
281 <-done
282 close(oltMgrChnl)
283 close(ldMgrChnl)
284
285 // Computes the routes
286 start := time.Now()
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400287 err := ldMgr.deviceRoutes.ComputeRoutes(context.TODO(), ldMgr.ports)
khenaidoo820197c2020-02-13 16:35:33 -0500288 assert.Nil(t, err)
289
290 // Validate the routes are up to date
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400291 assert.True(t, ldMgr.deviceRoutes.isUpToDate(ldMgr.ports))
khenaidoo820197c2020-02-13 16:35:33 -0500292
293 // Validate the expected number of routes
294 assert.EqualValues(t, 2*numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, len(ldMgr.deviceRoutes.Routes))
295
296 // Validate the root ports
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400297 for _, port := range ldMgr.ports {
khenaidoo820197c2020-02-13 16:35:33 -0500298 assert.Equal(t, port.RootPort, ldMgr.deviceRoutes.IsRootPort(port.OfpPort.PortNo))
299 }
300 fmt.Println(fmt.Sprintf("Total Time:%dms, Total Routes:%d NumGetDeviceInvoked:%d", time.Since(start)/time.Millisecond, len(ldMgr.deviceRoutes.Routes), onuMgr.numGetDeviceInvoked))
301}
302
303func TestDeviceRoutes_AddPort(t *testing.T) {
304 numNNIPort := 2
khenaidoo0db4c812020-05-27 15:27:30 -0400305 numPonPortOnOlt := 16
306 numOnuPerOltPonPort := 256
khenaidoo820197c2020-02-13 16:35:33 -0500307 numUniPerOnu := 4
308 done := make(chan struct{})
309
310 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d",
311 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
312
313 start := time.Now()
314 // Create all the devices and logical device before computing the routes in one go
315 ld := &voltha.LogicalDevice{Id: logicalDeviceID}
316 ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400317 ldMgr := newLogicalDeviceManager(ld, oltDeviceID, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
khenaidoo820197c2020-02-13 16:35:33 -0500318 oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
319 oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
320 onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400321 getDevice := onuMgr.ListDevicePortsHelper
khenaidoo820197c2020-02-13 16:35:33 -0500322 // Start the managers and trigger the routes to be built as the logical ports become available
Kent Hagerman2a07b862020-06-19 15:23:07 -0400323 ctx := context.Background()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000324 go ldMgr.start(ctx, getDevice, true)
khenaidoo820197c2020-02-13 16:35:33 -0500325 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
Rohan Agrawal31f21802020-06-12 05:38:46 +0000333 ldMgr.deviceRoutes.Print(ctx)
khenaidoo820197c2020-02-13 16:35:33 -0500334
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)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400362 ldMgr1 := newLogicalDeviceManager(ld1, oltDeviceID, ldMgrChnl1, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
khenaidoo820197c2020-02-13 16:35:33 -0500363 oltMgrChnl1 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
364 oltMgr1 := newOltManager(oltDeviceID, ldMgr1, numNNIPort, numPonPortOnOlt, oltMgrChnl1)
365 onuMgr1 := newOnuManager(oltMgr1, numOnuPerOltPonPort, numUniPerOnu, 2)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400366 getDevice := onuMgr1.ListDevicePortsHelper
Rohan Agrawal31f21802020-06-12 05:38:46 +0000367 ctx := context.Background()
khenaidoo820197c2020-02-13 16:35:33 -0500368 // Start the managers. Only the devices are created. No routes will be built.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000369 go ldMgr1.start(ctx, getDevice, false)
khenaidoo820197c2020-02-13 16:35:33 -0500370 go oltMgr1.start()
371 go onuMgr1.start(numNNIPort+1, numPonPortOnOlt)
372
373 // Wait for all the devices to be created
374 <-done
375 close(oltMgrChnl1)
376 close(ldMgrChnl1)
377
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400378 err := ldMgr1.deviceRoutes.ComputeRoutes(context.TODO(), ldMgr1.ports)
khenaidoo820197c2020-02-13 16:35:33 -0500379 assert.Nil(t, err)
380
381 routesGeneratedAllAtOnce := ldMgr1.deviceRoutes.Routes
382
383 done = make(chan struct{})
384 // Create all the devices and logical device before computing the routes in one go
385 ld2 := &voltha.LogicalDevice{Id: logicalDeviceID}
386 ldMgrChnl2 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400387 ldMgr2 := newLogicalDeviceManager(ld2, oltDeviceID, ldMgrChnl2, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
khenaidoo820197c2020-02-13 16:35:33 -0500388 oltMgrChnl2 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
389 oltMgr2 := newOltManager(oltDeviceID, ldMgr2, numNNIPort, numPonPortOnOlt, oltMgrChnl2)
390 onuMgr2 := newOnuManager(oltMgr2, numOnuPerOltPonPort, numUniPerOnu, 2)
391 // Start the managers. Only the devices are created. No routes will be built.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000392 go ldMgr2.start(ctx, getDevice, true)
khenaidoo820197c2020-02-13 16:35:33 -0500393 go oltMgr2.start()
394 go onuMgr2.start(numNNIPort+1, numPonPortOnOlt)
395
396 // Wait for all the devices to be created
397 <-done
398 close(oltMgrChnl2)
399 close(ldMgrChnl2)
400
401 routesGeneratedPerPort := ldMgr1.deviceRoutes.Routes
402 assert.True(t, isEqual(routesGeneratedAllAtOnce, routesGeneratedPerPort))
403}
404
405func TestDeviceRoutes_reverseRoute(t *testing.T) {
406 // Test the typical use case - 2 hops in a route
407 route := make([]Hop, 2)
408 route[0].DeviceID = "d1"
409 route[0].Ingress = 1
410 route[0].Egress = 2
411 route[1].DeviceID = "d2"
412 route[1].Ingress = 10
413 route[1].Egress = 15
414
415 reverseRoute := getReverseRoute(route)
416 assert.Equal(t, 2, len(reverseRoute))
417 assert.Equal(t, "d2", reverseRoute[0].DeviceID)
418 assert.Equal(t, "d1", reverseRoute[1].DeviceID)
419 assert.Equal(t, uint32(15), reverseRoute[0].Ingress)
420 assert.Equal(t, uint32(10), reverseRoute[0].Egress)
421 assert.Equal(t, uint32(2), reverseRoute[1].Ingress)
422 assert.Equal(t, uint32(1), reverseRoute[1].Egress)
423
424 fmt.Println("Reverse of two hops successful.")
425
426 //Test 3 hops in a route
427 route = make([]Hop, 3)
428 route[0].DeviceID = "d1"
429 route[0].Ingress = 1
430 route[0].Egress = 2
431 route[1].DeviceID = "d2"
432 route[1].Ingress = 10
433 route[1].Egress = 15
434 route[2].DeviceID = "d3"
435 route[2].Ingress = 20
436 route[2].Egress = 25
437 reverseRoute = getReverseRoute(route)
438 assert.Equal(t, 3, len(reverseRoute))
439 assert.Equal(t, "d3", reverseRoute[0].DeviceID)
440 assert.Equal(t, "d2", reverseRoute[1].DeviceID)
441 assert.Equal(t, "d1", reverseRoute[2].DeviceID)
442 assert.Equal(t, uint32(25), reverseRoute[0].Ingress)
443 assert.Equal(t, uint32(20), reverseRoute[0].Egress)
444 assert.Equal(t, uint32(15), reverseRoute[1].Ingress)
445 assert.Equal(t, uint32(10), reverseRoute[1].Egress)
446 assert.Equal(t, uint32(2), reverseRoute[2].Ingress)
447 assert.Equal(t, uint32(1), reverseRoute[2].Egress)
448
449 fmt.Println("Reverse of three hops successful.")
450
451 // Test any number of hops in a route
452 numRoutes := rand.Intn(100)
453 route = make([]Hop, numRoutes)
454 deviceIds := make([]string, numRoutes)
455 ingressNos := make([]uint32, numRoutes)
456 egressNos := make([]uint32, numRoutes)
457 for i := 0; i < numRoutes; i++ {
458 deviceIds[i] = fmt.Sprintf("d-%d", i)
459 ingressNos[i] = rand.Uint32()
460 egressNos[i] = rand.Uint32()
461 }
462 for i := 0; i < numRoutes; i++ {
463 route[i].DeviceID = deviceIds[i]
464 route[i].Ingress = ingressNos[i]
465 route[i].Egress = egressNos[i]
466 }
467 reverseRoute = getReverseRoute(route)
468 assert.Equal(t, numRoutes, len(reverseRoute))
469 for i, j := 0, numRoutes-1; j >= 0; i, j = i+1, j-1 {
470 assert.Equal(t, deviceIds[j], reverseRoute[i].DeviceID)
471 assert.Equal(t, egressNos[j], reverseRoute[i].Ingress)
472 assert.Equal(t, ingressNos[j], reverseRoute[i].Egress)
473 }
474
475 fmt.Println(fmt.Sprintf("Reverse of %d hops successful.", numRoutes))
476
477 reverseOfReverse := getReverseRoute(reverseRoute)
478 assert.Equal(t, route, reverseOfReverse)
479 fmt.Println("Reverse of reverse successful.")
480}
481
482func isEqual(routes1 map[PathID][]Hop, routes2 map[PathID][]Hop) bool {
483 if routes1 == nil && routes2 == nil {
484 return true
485 }
486 if (routes1 == nil && routes2 != nil) || (routes2 == nil && routes1 != nil) {
487 return false
488 }
489 if len(routes1) != len(routes2) {
490 return false
491 }
492 for routeID1, routeHop1 := range routes1 {
493 found := false
494 for routeID2, routeHop2 := range routes2 {
495 if routeID1 == routeID2 {
496 if !reflect.DeepEqual(routeHop1, routeHop2) {
497 return false
498 }
499 found = true
500 break
501 }
502 }
503 if !found {
504 return false
505 }
506 }
507 return true
508}