blob: 85a730f1938003c1a25df89fbeeda3e6ce0fddb3 [file] [log] [blame]
khenaidoo89b0e942018-10-21 21:11:33 -04001/*
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 graph
17
18import (
npujar467fe752020-01-16 20:17:45 +053019 "context"
khenaidoo89b0e942018-10-21 21:11:33 -040020 "errors"
21 "fmt"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080022 "github.com/opencord/voltha-protos/v3/go/openflow_13"
23 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoo89b0e942018-10-21 21:11:33 -040024 "github.com/stretchr/testify/assert"
khenaidoocfe03b92019-06-03 20:06:31 -040025 "math/rand"
khenaidoof934a1e2019-05-01 21:44:09 -040026 "strconv"
27 "strings"
khenaidoo910204f2019-04-08 17:56:40 -040028 "sync"
khenaidoo89b0e942018-10-21 21:11:33 -040029 "testing"
30 "time"
31)
32
khenaidoof934a1e2019-05-01 21:44:09 -040033var (
34 ld voltha.LogicalDevice
35 olt voltha.Device
36 onus map[int][]voltha.Device
npujar1d86a522019-11-14 17:11:16 +053037 logicalDeviceID string
38 oltDeviceID string
khenaidoof934a1e2019-05-01 21:44:09 -040039 numCalled int
40 lock sync.RWMutex
khenaidoo89b0e942018-10-21 21:11:33 -040041)
42
43func init() {
npujar1d86a522019-11-14 17:11:16 +053044 logicalDeviceID = "ld"
45 oltDeviceID = "olt"
khenaidoo910204f2019-04-08 17:56:40 -040046 lock = sync.RWMutex{}
khenaidoof934a1e2019-05-01 21:44:09 -040047}
khenaidoo89b0e942018-10-21 21:11:33 -040048
khenaidoof934a1e2019-05-01 21:44:09 -040049func setupDevices(numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu int) {
50 // Create the OLT and add the NNI ports
npujar1d86a522019-11-14 17:11:16 +053051 olt = voltha.Device{Id: oltDeviceID, ParentId: logicalDeviceID}
khenaidoo89b0e942018-10-21 21:11:33 -040052 olt.Ports = make([]*voltha.Port, 0)
khenaidoof934a1e2019-05-01 21:44:09 -040053 for nniPort := 1; nniPort < numNNIPort+1; nniPort++ {
npujar1d86a522019-11-14 17:11:16 +053054 p := voltha.Port{PortNo: uint32(nniPort), DeviceId: oltDeviceID, Type: voltha.Port_ETHERNET_NNI}
khenaidoof934a1e2019-05-01 21:44:09 -040055 olt.Ports = append(olt.Ports, &p)
56 }
khenaidoo89b0e942018-10-21 21:11:33 -040057
khenaidoof934a1e2019-05-01 21:44:09 -040058 // Create the ONUs and associate them with the OLT
59 onus = make(map[int][]voltha.Device)
60 for pPortNo := numNNIPort + 1; pPortNo < numPonPortOnOlt+numNNIPort+1; pPortNo++ {
61 onusOnPon := make([]voltha.Device, 0)
62 var onu voltha.Device
63 oltPeerPort := uint32(pPortNo)
npujar1d86a522019-11-14 17:11:16 +053064 oltPonPort := voltha.Port{PortNo: uint32(pPortNo), DeviceId: oltDeviceID, Type: voltha.Port_PON_OLT}
khenaidoof934a1e2019-05-01 21:44:09 -040065 oltPonPort.Peers = make([]*voltha.Port_PeerPort, 0)
66 for i := 0; i < numOnuPerOltPonPort; i++ {
67 id := fmt.Sprintf("%d-onu-%d", pPortNo, i)
npujar1d86a522019-11-14 17:11:16 +053068 onu = voltha.Device{Id: id, ParentId: oltDeviceID, ParentPortNo: uint32(pPortNo)}
khenaidoof934a1e2019-05-01 21:44:09 -040069 ponPort := voltha.Port{PortNo: 1, DeviceId: onu.Id, Type: voltha.Port_PON_ONU}
70 ponPort.Peers = make([]*voltha.Port_PeerPort, 0)
npujar1d86a522019-11-14 17:11:16 +053071 peerPort := voltha.Port_PeerPort{DeviceId: oltDeviceID, PortNo: oltPeerPort}
khenaidoof934a1e2019-05-01 21:44:09 -040072 ponPort.Peers = append(ponPort.Peers, &peerPort)
73 onu.Ports = make([]*voltha.Port, 0)
74 onu.Ports = append(onu.Ports, &ponPort)
75 for j := 2; j < numUniPerOnu+2; j++ {
76 uniPort := voltha.Port{PortNo: uint32(j), DeviceId: onu.Id, Type: voltha.Port_ETHERNET_UNI}
77 onu.Ports = append(onu.Ports, &uniPort)
78 }
79 onusOnPon = append(onusOnPon, onu)
80 oltPeerPort := voltha.Port_PeerPort{DeviceId: onu.Id, PortNo: 1}
81 oltPonPort.Peers = append(oltPonPort.Peers, &oltPeerPort)
82 }
83 onus[pPortNo] = onusOnPon
84 olt.Ports = append(olt.Ports, &oltPonPort)
85 }
86
87 // Create the logical device
npujar1d86a522019-11-14 17:11:16 +053088 ld = voltha.LogicalDevice{Id: logicalDeviceID}
khenaidoo89b0e942018-10-21 21:11:33 -040089 ld.Ports = make([]*voltha.LogicalPort, 0)
90 ofpPortNo := 1
khenaidoof934a1e2019-05-01 21:44:09 -040091 var id string
92 //Add olt NNI ports
khenaidoo89b0e942018-10-21 21:11:33 -040093 for i, port := range olt.Ports {
94 if port.Type == voltha.Port_ETHERNET_NNI {
95 id = fmt.Sprintf("nni-%d", i)
96 lp := voltha.LogicalPort{Id: id, DeviceId: olt.Id, DevicePortNo: port.PortNo, OfpPort: &openflow_13.OfpPort{PortNo: uint32(ofpPortNo)}, RootPort: true}
97 ld.Ports = append(ld.Ports, &lp)
98 ofpPortNo = ofpPortNo + 1
99 }
100 }
khenaidoof934a1e2019-05-01 21:44:09 -0400101 //Add onu UNI ports
102 for _, onusOnPort := range onus {
103 for _, onu := range onusOnPort {
104 for j, port := range onu.Ports {
105 if port.Type == voltha.Port_ETHERNET_UNI {
106 id = fmt.Sprintf("%s:uni-%d", onu.Id, j)
107 lp := voltha.LogicalPort{Id: id, DeviceId: onu.Id, DevicePortNo: port.PortNo, OfpPort: &openflow_13.OfpPort{PortNo: uint32(ofpPortNo)}, RootPort: false}
108 ld.Ports = append(ld.Ports, &lp)
109 ofpPortNo = ofpPortNo + 1
110 }
khenaidoo89b0e942018-10-21 21:11:33 -0400111 }
112 }
113 }
114}
115
npujar467fe752020-01-16 20:17:45 +0530116func GetDeviceHelper(_ context.Context, id string) (*voltha.Device, error) {
khenaidoo910204f2019-04-08 17:56:40 -0400117 lock.Lock()
npujar1d86a522019-11-14 17:11:16 +0530118 numCalled++
khenaidoo910204f2019-04-08 17:56:40 -0400119 lock.Unlock()
khenaidoo89b0e942018-10-21 21:11:33 -0400120 if id == "olt" {
121 return &olt, nil
122 }
khenaidoof934a1e2019-05-01 21:44:09 -0400123 // Extract the olt pon port from the id ("<ponport>-onu-<onu number>")
124 res := strings.Split(id, "-")
125 if len(res) == 3 {
126 if ponPort, err := strconv.Atoi(res[0]); err == nil {
127 for _, onu := range onus[ponPort] {
128 if onu.Id == id {
129 return &onu, nil
130 }
131 }
132
khenaidoo89b0e942018-10-21 21:11:33 -0400133 }
134 }
135 return nil, errors.New("Not-found")
136}
137
khenaidoo910204f2019-04-08 17:56:40 -0400138func TestGetRoutesOneShot(t *testing.T) {
khenaidoof934a1e2019-05-01 21:44:09 -0400139 numNNIPort := 1
140 numPonPortOnOlt := 1
141 numOnuPerOltPonPort := 64
142 numUniPerOnu := 1
khenaidoo89b0e942018-10-21 21:11:33 -0400143
khenaidoof934a1e2019-05-01 21:44:09 -0400144 setupDevices(numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
khenaidoo89b0e942018-10-21 21:11:33 -0400145 getDevice := GetDeviceHelper
146
khenaidoof934a1e2019-05-01 21:44:09 -0400147 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d", len(ld.Ports), numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
khenaidoo89b0e942018-10-21 21:11:33 -0400148 // Create a device graph and computes Routes
149 start := time.Now()
npujar1d86a522019-11-14 17:11:16 +0530150 dg := NewDeviceGraph(logicalDeviceID, getDevice)
npujar467fe752020-01-16 20:17:45 +0530151 dg.ComputeRoutes(context.Background(), ld.Ports)
khenaidoo89b0e942018-10-21 21:11:33 -0400152 assert.NotNil(t, dg.GGraph)
khenaidoof934a1e2019-05-01 21:44:09 -0400153 fmt.Println(fmt.Sprintf("Total Time:%dms Total Routes:%d", time.Since(start)/time.Millisecond, len(dg.Routes)))
154 assert.EqualValues(t, (2 * numNNIPort * numPonPortOnOlt * numOnuPerOltPonPort * numUniPerOnu), len(dg.Routes))
khenaidoo910204f2019-04-08 17:56:40 -0400155}
khenaidoo89b0e942018-10-21 21:11:33 -0400156
khenaidoof934a1e2019-05-01 21:44:09 -0400157func TestGetRoutesPerPort(t *testing.T) {
158 numNNIPort := 1
159 numPonPortOnOlt := 1
160 numOnuPerOltPonPort := 64
161 numUniPerOnu := 1
khenaidoo910204f2019-04-08 17:56:40 -0400162
khenaidoof934a1e2019-05-01 21:44:09 -0400163 setupDevices(numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
khenaidoo910204f2019-04-08 17:56:40 -0400164 getDevice := GetDeviceHelper
165
khenaidoof934a1e2019-05-01 21:44:09 -0400166 fmt.Println(fmt.Sprintf("Test: Compute routes per port. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d", len(ld.Ports), numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
167
khenaidoo910204f2019-04-08 17:56:40 -0400168 // Create a device graph and computes Routes
169 start := time.Now()
khenaidoof934a1e2019-05-01 21:44:09 -0400170 var pt time.Time
npujar1d86a522019-11-14 17:11:16 +0530171 dg := NewDeviceGraph(logicalDeviceID, getDevice)
khenaidoof934a1e2019-05-01 21:44:09 -0400172 for k, lp := range ld.Ports {
173 if k == len(ld.Ports)-1 {
174 pt = time.Now()
175 }
npujar467fe752020-01-16 20:17:45 +0530176 dg.AddPort(context.Background(), lp)
khenaidoo910204f2019-04-08 17:56:40 -0400177 }
khenaidoo910204f2019-04-08 17:56:40 -0400178 assert.NotNil(t, dg.GGraph)
khenaidoof934a1e2019-05-01 21:44:09 -0400179 fmt.Println(fmt.Sprintf("Total Time:%dms. Total Routes:%d. LastPort_Time:%dms", time.Since(start)/time.Millisecond, len(dg.Routes), time.Since(pt)/time.Millisecond))
180 assert.EqualValues(t, (2 * numNNIPort * numPonPortOnOlt * numOnuPerOltPonPort * numUniPerOnu), len(dg.Routes))
181}
182
183func TestGetRoutesPerPortMultipleUNIs(t *testing.T) {
184 numNNIPort := 1
185 numPonPortOnOlt := 1
186 numOnuPerOltPonPort := 64
187 numUniPerOnu := 5
188
189 setupDevices(numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
190 getDevice := GetDeviceHelper
191
192 fmt.Println(fmt.Sprintf("Test: Compute routes per port - multiple UNIs. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d", len(ld.Ports), numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
193
194 // Create a device graph and computes Routes
195 start := time.Now()
196 var pt time.Time
npujar1d86a522019-11-14 17:11:16 +0530197 dg := NewDeviceGraph(logicalDeviceID, getDevice)
khenaidoof934a1e2019-05-01 21:44:09 -0400198 for k, lp := range ld.Ports {
199 if k == len(ld.Ports)-1 {
200 pt = time.Now()
201 }
npujar467fe752020-01-16 20:17:45 +0530202 dg.AddPort(context.Background(), lp)
khenaidoof934a1e2019-05-01 21:44:09 -0400203 }
204 assert.NotNil(t, dg.GGraph)
205 fmt.Println(fmt.Sprintf("Total Time:%dms. Total Routes:%d. LastPort_Time:%dms", time.Since(start)/time.Millisecond, len(dg.Routes), time.Since(pt)/time.Millisecond))
206 assert.EqualValues(t, (2 * numNNIPort * numPonPortOnOlt * numOnuPerOltPonPort * numUniPerOnu), len(dg.Routes))
207}
208
209func TestGetRoutesPerPortNoUNI(t *testing.T) {
210 numNNIPort := 1
211 numPonPortOnOlt := 1
212 numOnuPerOltPonPort := 1
213 numUniPerOnu := 0
214
215 setupDevices(numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
216 getDevice := GetDeviceHelper
217 assert.EqualValues(t, 1, len(ld.Ports))
218
219 fmt.Println(fmt.Sprintf("Test: Compute routes per port - no UNI. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d", len(ld.Ports), numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
220
221 // Create a device graph and computes Routes
222 start := time.Now()
223 var pt time.Time
npujar1d86a522019-11-14 17:11:16 +0530224 dg := NewDeviceGraph(logicalDeviceID, getDevice)
khenaidoof934a1e2019-05-01 21:44:09 -0400225 for k, lp := range ld.Ports {
226 if k == len(ld.Ports)-1 {
227 pt = time.Now()
228 }
npujar467fe752020-01-16 20:17:45 +0530229 dg.AddPort(context.Background(), lp)
khenaidoof934a1e2019-05-01 21:44:09 -0400230 }
231 assert.NotNil(t, dg.GGraph)
232 fmt.Println(fmt.Sprintf("Total Time:%dms. Total Routes:%d. LastPort_Time:%dms", time.Since(start)/time.Millisecond, len(dg.Routes), time.Since(pt)/time.Millisecond))
233 assert.EqualValues(t, 0, len(dg.Routes))
234}
235
236func TestGetRoutesPerPortNoONU(t *testing.T) {
237 numNNIPort := 1
238 numPonPortOnOlt := 1
239 numOnuPerOltPonPort := 0
240 numUniPerOnu := 0
241
242 setupDevices(numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
243 getDevice := GetDeviceHelper
244 assert.EqualValues(t, 1, len(ld.Ports))
245
246 fmt.Println(fmt.Sprintf("Test: Compute routes per port - no ONU. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d", len(ld.Ports), numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
247
248 // Create a device graph and computes Routes
249 start := time.Now()
250 var pt time.Time
npujar1d86a522019-11-14 17:11:16 +0530251 dg := NewDeviceGraph(logicalDeviceID, getDevice)
khenaidoof934a1e2019-05-01 21:44:09 -0400252 for k, lp := range ld.Ports {
253 if k == len(ld.Ports)-1 {
254 pt = time.Now()
255 }
npujar467fe752020-01-16 20:17:45 +0530256 dg.AddPort(context.Background(), lp)
khenaidoof934a1e2019-05-01 21:44:09 -0400257 }
258 assert.NotNil(t, dg.GGraph)
259 fmt.Println(fmt.Sprintf("Total Time:%dms. Total Routes:%d. LastPort_Time:%dms", time.Since(start)/time.Millisecond, len(dg.Routes), time.Since(pt)/time.Millisecond))
260 assert.EqualValues(t, 0, len(dg.Routes))
261}
262
263func TestGetRoutesPerPortNoNNI(t *testing.T) {
264 numNNIPort := 0
265 numPonPortOnOlt := 1
266 numOnuPerOltPonPort := 1
267 numUniPerOnu := 1
268
269 setupDevices(numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu)
270 getDevice := GetDeviceHelper
271 assert.EqualValues(t, 1, len(ld.Ports))
272
273 fmt.Println(fmt.Sprintf("Test: Compute routes per port - no NNI. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d", len(ld.Ports), numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
274
275 // Create a device graph and computes Routes
276 start := time.Now()
277 var pt time.Time
npujar1d86a522019-11-14 17:11:16 +0530278 dg := NewDeviceGraph(logicalDeviceID, getDevice)
khenaidoof934a1e2019-05-01 21:44:09 -0400279 for k, lp := range ld.Ports {
280 if k == len(ld.Ports)-1 {
281 pt = time.Now()
282 }
npujar467fe752020-01-16 20:17:45 +0530283 dg.AddPort(context.Background(), lp)
khenaidoof934a1e2019-05-01 21:44:09 -0400284 }
285 assert.NotNil(t, dg.GGraph)
286 fmt.Println(fmt.Sprintf("Total Time:%dms. Total Routes:%d. LastPort_Time:%dms", time.Since(start)/time.Millisecond, len(dg.Routes), time.Since(pt)/time.Millisecond))
287 assert.EqualValues(t, 0, len(dg.Routes))
khenaidoo89b0e942018-10-21 21:11:33 -0400288}
khenaidoocfe03b92019-06-03 20:06:31 -0400289
290func TestReverseRoute(t *testing.T) {
291 // Test the typical use case - 2 hops in a route
292 route := make([]RouteHop, 2)
293 route[0].DeviceID = "d1"
294 route[0].Ingress = 1
295 route[0].Egress = 2
296 route[1].DeviceID = "d2"
297 route[1].Ingress = 10
298 route[1].Egress = 15
299
300 reverseRoute := getReverseRoute(route)
301 assert.Equal(t, 2, len(reverseRoute))
302 assert.Equal(t, "d2", reverseRoute[0].DeviceID)
303 assert.Equal(t, "d1", reverseRoute[1].DeviceID)
304 assert.Equal(t, uint32(15), reverseRoute[0].Ingress)
305 assert.Equal(t, uint32(10), reverseRoute[0].Egress)
306 assert.Equal(t, uint32(2), reverseRoute[1].Ingress)
307 assert.Equal(t, uint32(1), reverseRoute[1].Egress)
308
309 fmt.Println("Reverse of two hops successful.")
310
311 //Test 3 hops in a route
312 route = make([]RouteHop, 3)
313 route[0].DeviceID = "d1"
314 route[0].Ingress = 1
315 route[0].Egress = 2
316 route[1].DeviceID = "d2"
317 route[1].Ingress = 10
318 route[1].Egress = 15
319 route[2].DeviceID = "d3"
320 route[2].Ingress = 20
321 route[2].Egress = 25
322 reverseRoute = getReverseRoute(route)
323 assert.Equal(t, 3, len(reverseRoute))
324 assert.Equal(t, "d3", reverseRoute[0].DeviceID)
325 assert.Equal(t, "d2", reverseRoute[1].DeviceID)
326 assert.Equal(t, "d1", reverseRoute[2].DeviceID)
327 assert.Equal(t, uint32(25), reverseRoute[0].Ingress)
328 assert.Equal(t, uint32(20), reverseRoute[0].Egress)
329 assert.Equal(t, uint32(15), reverseRoute[1].Ingress)
330 assert.Equal(t, uint32(10), reverseRoute[1].Egress)
331 assert.Equal(t, uint32(2), reverseRoute[2].Ingress)
332 assert.Equal(t, uint32(1), reverseRoute[2].Egress)
333
334 fmt.Println("Reverse of three hops successful.")
335
336 // Test any number of hops in a route
337 numRoutes := rand.Intn(100)
338 route = make([]RouteHop, numRoutes)
339 deviceIds := make([]string, numRoutes)
340 ingressNos := make([]uint32, numRoutes)
341 egressNos := make([]uint32, numRoutes)
342 for i := 0; i < numRoutes; i++ {
343 deviceIds[i] = fmt.Sprintf("d-%d", i)
344 ingressNos[i] = rand.Uint32()
345 egressNos[i] = rand.Uint32()
346 }
347 for i := 0; i < numRoutes; i++ {
348 route[i].DeviceID = deviceIds[i]
349 route[i].Ingress = ingressNos[i]
350 route[i].Egress = egressNos[i]
351 }
352 reverseRoute = getReverseRoute(route)
353 assert.Equal(t, numRoutes, len(reverseRoute))
354 for i, j := 0, numRoutes-1; j >= 0; i, j = i+1, j-1 {
355 assert.Equal(t, deviceIds[j], reverseRoute[i].DeviceID)
356 assert.Equal(t, egressNos[j], reverseRoute[i].Ingress)
357 assert.Equal(t, ingressNos[j], reverseRoute[i].Egress)
358 }
359
360 fmt.Println(fmt.Sprintf("Reverse of %d hops successful.", numRoutes))
361
362 reverseOfReverse := getReverseRoute(reverseRoute)
363 assert.Equal(t, route, reverseOfReverse)
364 fmt.Println("Reverse of reverse successful.")
365}