blob: 04623dbf66eaf87d03bd32b65579900359561a12 [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
Maninderdfadc982020-10-28 14:04:33 +053029 "github.com/opencord/voltha-protos/v4/go/openflow_13"
30 "github.com/opencord/voltha-protos/v4/go/voltha"
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040031 "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
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300264 fmt.Printf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d\n",
265 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
khenaidoo820197c2020-02-13 16:35:33 -0500266
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 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300300 fmt.Printf(
301 "Total Time:%dms, Total Routes:%d NumGetDeviceInvoked:%d\n",
302 time.Since(start)/time.Millisecond,
303 len(ldMgr.deviceRoutes.Routes),
304 onuMgr.numGetDeviceInvoked,
305 )
khenaidoo820197c2020-02-13 16:35:33 -0500306}
307
308func TestDeviceRoutes_AddPort(t *testing.T) {
309 numNNIPort := 2
khenaidoo0db4c812020-05-27 15:27:30 -0400310 numPonPortOnOlt := 16
311 numOnuPerOltPonPort := 256
khenaidoo820197c2020-02-13 16:35:33 -0500312 numUniPerOnu := 4
313 done := make(chan struct{})
314
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300315 fmt.Printf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d\n",
316 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
khenaidoo820197c2020-02-13 16:35:33 -0500317
318 start := time.Now()
319 // Create all the devices and logical device before computing the routes in one go
320 ld := &voltha.LogicalDevice{Id: logicalDeviceID}
321 ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400322 ldMgr := newLogicalDeviceManager(ld, oltDeviceID, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
khenaidoo820197c2020-02-13 16:35:33 -0500323 oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
324 oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
325 onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400326 getDevice := onuMgr.ListDevicePortsHelper
khenaidoo820197c2020-02-13 16:35:33 -0500327 // Start the managers and trigger the routes to be built as the logical ports become available
Kent Hagerman2a07b862020-06-19 15:23:07 -0400328 ctx := context.Background()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000329 go ldMgr.start(ctx, getDevice, true)
khenaidoo820197c2020-02-13 16:35:33 -0500330 go oltMgr.start()
331 go onuMgr.start(numNNIPort+1, numPonPortOnOlt)
332
333 // Wait for all the devices to be created and routes created
334 <-done
335 close(oltMgrChnl)
336 close(ldMgrChnl)
337
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300338 err := ldMgr.deviceRoutes.Print(ctx)
339 assert.NoError(t, err)
khenaidoo820197c2020-02-13 16:35:33 -0500340
341 // Validate the routes are up to date
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400342 assert.True(t, ldMgr.deviceRoutes.isUpToDate(ldMgr.ports))
khenaidoo820197c2020-02-13 16:35:33 -0500343
344 // Validate the expected number of routes
345 assert.EqualValues(t, 2*numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, len(ldMgr.deviceRoutes.Routes))
346
347 // Validate the root ports
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400348 for _, port := range ldMgr.ports {
khenaidoo820197c2020-02-13 16:35:33 -0500349 assert.Equal(t, port.RootPort, ldMgr.deviceRoutes.IsRootPort(port.OfpPort.PortNo))
350 }
351
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300352 fmt.Printf(
353 "Total Time:%dms, Total Routes:%d NumGetDeviceInvoked:%d\n",
354 time.Since(start)/time.Millisecond,
355 len(ldMgr.deviceRoutes.Routes),
356 onuMgr.numGetDeviceInvoked,
357 )
khenaidoo820197c2020-02-13 16:35:33 -0500358}
359
360func TestDeviceRoutes_compareRoutesGeneration(t *testing.T) {
361 numNNIPort := 2
362 numPonPortOnOlt := 8
363 numOnuPerOltPonPort := 32
364 numUniPerOnu := 4
365 done := make(chan struct{})
366
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300367 fmt.Printf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d\n",
368 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
khenaidoo820197c2020-02-13 16:35:33 -0500369
370 // Create all the devices and logical device before computing the routes in one go
371 ld1 := &voltha.LogicalDevice{Id: logicalDeviceID}
372 ldMgrChnl1 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400373 ldMgr1 := newLogicalDeviceManager(ld1, oltDeviceID, ldMgrChnl1, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
khenaidoo820197c2020-02-13 16:35:33 -0500374 oltMgrChnl1 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
375 oltMgr1 := newOltManager(oltDeviceID, ldMgr1, numNNIPort, numPonPortOnOlt, oltMgrChnl1)
376 onuMgr1 := newOnuManager(oltMgr1, numOnuPerOltPonPort, numUniPerOnu, 2)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400377 getDevice := onuMgr1.ListDevicePortsHelper
Rohan Agrawal31f21802020-06-12 05:38:46 +0000378 ctx := context.Background()
khenaidoo820197c2020-02-13 16:35:33 -0500379 // Start the managers. Only the devices are created. No routes will be built.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000380 go ldMgr1.start(ctx, getDevice, false)
khenaidoo820197c2020-02-13 16:35:33 -0500381 go oltMgr1.start()
382 go onuMgr1.start(numNNIPort+1, numPonPortOnOlt)
383
384 // Wait for all the devices to be created
385 <-done
386 close(oltMgrChnl1)
387 close(ldMgrChnl1)
388
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400389 err := ldMgr1.deviceRoutes.ComputeRoutes(context.TODO(), ldMgr1.ports)
khenaidoo820197c2020-02-13 16:35:33 -0500390 assert.Nil(t, err)
391
392 routesGeneratedAllAtOnce := ldMgr1.deviceRoutes.Routes
393
394 done = make(chan struct{})
395 // Create all the devices and logical device before computing the routes in one go
396 ld2 := &voltha.LogicalDevice{Id: logicalDeviceID}
397 ldMgrChnl2 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400398 ldMgr2 := newLogicalDeviceManager(ld2, oltDeviceID, ldMgrChnl2, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
khenaidoo820197c2020-02-13 16:35:33 -0500399 oltMgrChnl2 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
400 oltMgr2 := newOltManager(oltDeviceID, ldMgr2, numNNIPort, numPonPortOnOlt, oltMgrChnl2)
401 onuMgr2 := newOnuManager(oltMgr2, numOnuPerOltPonPort, numUniPerOnu, 2)
402 // Start the managers. Only the devices are created. No routes will be built.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000403 go ldMgr2.start(ctx, getDevice, true)
khenaidoo820197c2020-02-13 16:35:33 -0500404 go oltMgr2.start()
405 go onuMgr2.start(numNNIPort+1, numPonPortOnOlt)
406
407 // Wait for all the devices to be created
408 <-done
409 close(oltMgrChnl2)
410 close(ldMgrChnl2)
411
412 routesGeneratedPerPort := ldMgr1.deviceRoutes.Routes
413 assert.True(t, isEqual(routesGeneratedAllAtOnce, routesGeneratedPerPort))
414}
415
416func TestDeviceRoutes_reverseRoute(t *testing.T) {
417 // Test the typical use case - 2 hops in a route
418 route := make([]Hop, 2)
419 route[0].DeviceID = "d1"
420 route[0].Ingress = 1
421 route[0].Egress = 2
422 route[1].DeviceID = "d2"
423 route[1].Ingress = 10
424 route[1].Egress = 15
425
426 reverseRoute := getReverseRoute(route)
427 assert.Equal(t, 2, len(reverseRoute))
428 assert.Equal(t, "d2", reverseRoute[0].DeviceID)
429 assert.Equal(t, "d1", reverseRoute[1].DeviceID)
430 assert.Equal(t, uint32(15), reverseRoute[0].Ingress)
431 assert.Equal(t, uint32(10), reverseRoute[0].Egress)
432 assert.Equal(t, uint32(2), reverseRoute[1].Ingress)
433 assert.Equal(t, uint32(1), reverseRoute[1].Egress)
434
435 fmt.Println("Reverse of two hops successful.")
436
437 //Test 3 hops in a route
438 route = make([]Hop, 3)
439 route[0].DeviceID = "d1"
440 route[0].Ingress = 1
441 route[0].Egress = 2
442 route[1].DeviceID = "d2"
443 route[1].Ingress = 10
444 route[1].Egress = 15
445 route[2].DeviceID = "d3"
446 route[2].Ingress = 20
447 route[2].Egress = 25
448 reverseRoute = getReverseRoute(route)
449 assert.Equal(t, 3, len(reverseRoute))
450 assert.Equal(t, "d3", reverseRoute[0].DeviceID)
451 assert.Equal(t, "d2", reverseRoute[1].DeviceID)
452 assert.Equal(t, "d1", reverseRoute[2].DeviceID)
453 assert.Equal(t, uint32(25), reverseRoute[0].Ingress)
454 assert.Equal(t, uint32(20), reverseRoute[0].Egress)
455 assert.Equal(t, uint32(15), reverseRoute[1].Ingress)
456 assert.Equal(t, uint32(10), reverseRoute[1].Egress)
457 assert.Equal(t, uint32(2), reverseRoute[2].Ingress)
458 assert.Equal(t, uint32(1), reverseRoute[2].Egress)
459
460 fmt.Println("Reverse of three hops successful.")
461
462 // Test any number of hops in a route
463 numRoutes := rand.Intn(100)
464 route = make([]Hop, numRoutes)
465 deviceIds := make([]string, numRoutes)
466 ingressNos := make([]uint32, numRoutes)
467 egressNos := make([]uint32, numRoutes)
468 for i := 0; i < numRoutes; i++ {
469 deviceIds[i] = fmt.Sprintf("d-%d", i)
470 ingressNos[i] = rand.Uint32()
471 egressNos[i] = rand.Uint32()
472 }
473 for i := 0; i < numRoutes; i++ {
474 route[i].DeviceID = deviceIds[i]
475 route[i].Ingress = ingressNos[i]
476 route[i].Egress = egressNos[i]
477 }
478 reverseRoute = getReverseRoute(route)
479 assert.Equal(t, numRoutes, len(reverseRoute))
480 for i, j := 0, numRoutes-1; j >= 0; i, j = i+1, j-1 {
481 assert.Equal(t, deviceIds[j], reverseRoute[i].DeviceID)
482 assert.Equal(t, egressNos[j], reverseRoute[i].Ingress)
483 assert.Equal(t, ingressNos[j], reverseRoute[i].Egress)
484 }
485
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300486 fmt.Printf("Reverse of %d hops successful.\n", numRoutes)
khenaidoo820197c2020-02-13 16:35:33 -0500487
488 reverseOfReverse := getReverseRoute(reverseRoute)
489 assert.Equal(t, route, reverseOfReverse)
490 fmt.Println("Reverse of reverse successful.")
491}
492
493func isEqual(routes1 map[PathID][]Hop, routes2 map[PathID][]Hop) bool {
494 if routes1 == nil && routes2 == nil {
495 return true
496 }
497 if (routes1 == nil && routes2 != nil) || (routes2 == nil && routes1 != nil) {
498 return false
499 }
500 if len(routes1) != len(routes2) {
501 return false
502 }
503 for routeID1, routeHop1 := range routes1 {
504 found := false
505 for routeID2, routeHop2 := range routes2 {
506 if routeID1 == routeID2 {
507 if !reflect.DeepEqual(routeHop1, routeHop2) {
508 return false
509 }
510 found = true
511 break
512 }
513 }
514 if !found {
515 return false
516 }
517 }
518 return true
519}