blob: 71002c799986dc3cccbeedceebf9984317cf45c0 [file] [log] [blame]
khenaidoo820197c2020-02-13 16:35:33 -05001/*
2 * Copyright 2020-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 route
18
19import (
20 "context"
khenaidoo787224a2020-04-16 18:08:47 -040021 "errors"
khenaidoo820197c2020-02-13 16:35:33 -050022 "fmt"
23 "github.com/opencord/voltha-lib-go/v3/pkg/log"
24 "github.com/opencord/voltha-protos/v3/go/voltha"
25 "google.golang.org/grpc/codes"
26 "google.golang.org/grpc/status"
27 "sync"
28)
29
khenaidoo787224a2020-04-16 18:08:47 -040030var ErrNoRoute = errors.New("no route")
31
khenaidoo820197c2020-02-13 16:35:33 -050032// Hop represent a route hop
33type Hop struct {
34 DeviceID string
35 Ingress uint32
36 Egress uint32
37}
38
39// PathID is the identification of a route between two logical ports
40type PathID struct {
41 Ingress uint32
42 Egress uint32
43}
44
45type OFPortLink struct {
46 Ingress uint32
47 Egress uint32
48}
49
50// GetDeviceFunc returns device function
51type GetDeviceFunc func(ctx context.Context, id string) (*voltha.Device, error)
52
53// DeviceRoutes represent the set of routes between logical ports of a logical device
54type DeviceRoutes struct {
55 logicalDeviceID string
56 getDeviceFromModel GetDeviceFunc
khenaidoo0db4c812020-05-27 15:27:30 -040057 logicalPorts map[uint32]*voltha.LogicalPort
khenaidoo820197c2020-02-13 16:35:33 -050058 RootPorts map[uint32]uint32
59 rootPortsLock sync.RWMutex
60 Routes map[PathID][]Hop
61 routeBuildLock sync.RWMutex
62 devicesPonPorts map[string][]*voltha.Port
khenaidoo0db4c812020-05-27 15:27:30 -040063 childConnectionPort map[string]uint32
khenaidoo820197c2020-02-13 16:35:33 -050064}
65
66// NewDeviceRoutes creates device graph instance
67func NewDeviceRoutes(logicalDeviceID string, getDevice GetDeviceFunc) *DeviceRoutes {
68 var dr DeviceRoutes
69 dr.logicalDeviceID = logicalDeviceID
70 dr.getDeviceFromModel = getDevice
71 dr.RootPorts = make(map[uint32]uint32)
72 dr.Routes = make(map[PathID][]Hop)
73 dr.devicesPonPorts = make(map[string][]*voltha.Port)
khenaidoo0db4c812020-05-27 15:27:30 -040074 dr.childConnectionPort = make(map[string]uint32)
75 dr.logicalPorts = make(map[uint32]*voltha.LogicalPort)
Girish Kumarf56a4682020-03-20 20:07:46 +000076 logger.Debug("new device routes created ...")
khenaidoo820197c2020-02-13 16:35:33 -050077 return &dr
78}
79
80//IsRootPort returns true if the port is a root port on a logical device
81func (dr *DeviceRoutes) IsRootPort(port uint32) bool {
82 dr.rootPortsLock.RLock()
83 defer dr.rootPortsLock.RUnlock()
84 _, exist := dr.RootPorts[port]
85 return exist
86}
87
khenaidoo0db4c812020-05-27 15:27:30 -040088func (dr *DeviceRoutes) GetRoute(ctx context.Context, ingress, egress uint32) ([]Hop, error) {
89 dr.routeBuildLock.Lock()
90 defer dr.routeBuildLock.Unlock()
91
92 if route, exist := dr.Routes[PathID{Ingress: ingress, Egress: egress}]; exist {
93 return route, nil
94 }
95
96 uniPort, nniPort, err := dr.getLogicalPorts(ingress, egress)
97 if err != nil {
98 return nil, fmt.Errorf("no route from:%d to:%d %w", ingress, egress, err)
99 }
100
101 childPonPort, err := dr.getChildPonPort(ctx, uniPort.DeviceId)
102 if err != nil {
103 return nil, err
104 }
105 rootDevicePonPort, err := dr.getParentPonPort(ctx, nniPort.DeviceId, uniPort.DeviceId)
106 if err != nil {
107 return nil, err
108 }
109
110 dr.Routes[PathID{Ingress: nniPort.OfpPort.PortNo, Egress: uniPort.DevicePortNo}] = []Hop{
111 {DeviceID: nniPort.DeviceId, Ingress: nniPort.DevicePortNo, Egress: rootDevicePonPort},
112 {DeviceID: uniPort.DeviceId, Ingress: childPonPort, Egress: uniPort.DevicePortNo},
113 }
114 dr.Routes[PathID{Ingress: uniPort.DevicePortNo, Egress: nniPort.OfpPort.PortNo}] = getReverseRoute(
115 dr.Routes[PathID{Ingress: nniPort.OfpPort.PortNo, Egress: uniPort.DevicePortNo}])
116
117 return dr.Routes[PathID{Ingress: ingress, Egress: egress}], nil
118
119}
120
khenaidoo820197c2020-02-13 16:35:33 -0500121//ComputeRoutes calculates all the routes between the logical ports. This will clear up any existing route
122func (dr *DeviceRoutes) ComputeRoutes(ctx context.Context, lps []*voltha.LogicalPort) error {
123 dr.routeBuildLock.Lock()
124 defer dr.routeBuildLock.Unlock()
125
Girish Kumarf56a4682020-03-20 20:07:46 +0000126 logger.Debugw("computing-all-routes", log.Fields{"len-logical-ports": len(lps)})
khenaidoo820197c2020-02-13 16:35:33 -0500127 var err error
128 defer func() {
129 // On error, clear the routes - any flow request or a port add/delete will trigger the rebuild
130 if err != nil {
131 dr.reset()
132 }
133 }()
134
135 if len(lps) < 2 {
khenaidoo787224a2020-04-16 18:08:47 -0400136 return fmt.Errorf("not enough logical port :%w", ErrNoRoute)
khenaidoo820197c2020-02-13 16:35:33 -0500137 }
138
139 dr.reset()
khenaidoo820197c2020-02-13 16:35:33 -0500140
141 // Setup the physical ports to logical ports map, the nni ports as well as the root ports map
142 physPortToLogicalPortMap := make(map[string]uint32)
143 nniPorts := make([]*voltha.LogicalPort, 0)
144 for _, lp := range lps {
145 physPortToLogicalPortMap[concatDeviceIDPortID(lp.DeviceId, lp.DevicePortNo)] = lp.OfpPort.PortNo
146 if lp.RootPort {
147 nniPorts = append(nniPorts, lp)
148 dr.RootPorts[lp.OfpPort.PortNo] = lp.OfpPort.PortNo
149 }
khenaidoo0db4c812020-05-27 15:27:30 -0400150 dr.logicalPorts[lp.OfpPort.PortNo] = lp
khenaidoo820197c2020-02-13 16:35:33 -0500151 }
khenaidoo0db4c812020-05-27 15:27:30 -0400152
khenaidoo820197c2020-02-13 16:35:33 -0500153 if len(nniPorts) == 0 {
khenaidoo787224a2020-04-16 18:08:47 -0400154 return fmt.Errorf("no nni port :%w", ErrNoRoute)
khenaidoo820197c2020-02-13 16:35:33 -0500155 }
156 var rootDevice *voltha.Device
157 var childDevice *voltha.Device
158 var copyFromNNIPort *voltha.LogicalPort
159 for idx, nniPort := range nniPorts {
160 if idx == 0 {
161 copyFromNNIPort = nniPort
162 } else if len(dr.Routes) > 0 {
163 dr.copyFromExistingNNIRoutes(nniPort, copyFromNNIPort)
164 return nil
165 }
166 // Get root device
khenaidoo0db4c812020-05-27 15:27:30 -0400167 rootDevice, err = dr.getDeviceWithCacheUpdate(ctx, nniPort.DeviceId)
khenaidoo820197c2020-02-13 16:35:33 -0500168 if err != nil {
169 return err
170 }
171 if len(rootDevice.Ports) == 0 {
172 err = status.Errorf(codes.FailedPrecondition, "no-port-%s", rootDevice.Id)
173 return err
174 }
175 for _, rootDevicePort := range rootDevice.Ports {
176 if rootDevicePort.Type == voltha.Port_PON_OLT {
Girish Kumarf56a4682020-03-20 20:07:46 +0000177 logger.Debugw("peers", log.Fields{"root-device-id": rootDevice.Id, "port-no": rootDevicePort.PortNo, "len-peers": len(rootDevicePort.Peers)})
khenaidoo820197c2020-02-13 16:35:33 -0500178 for _, rootDevicePeer := range rootDevicePort.Peers {
khenaidoo0db4c812020-05-27 15:27:30 -0400179 childDevice, err = dr.getDeviceWithCacheUpdate(ctx, rootDevicePeer.DeviceId)
khenaidoo820197c2020-02-13 16:35:33 -0500180 if err != nil {
181 return err
182 }
khenaidoo0db4c812020-05-27 15:27:30 -0400183 childPonPort, err := dr.getChildPonPort(ctx, childDevice.Id)
184 if err != nil {
khenaidoo820197c2020-02-13 16:35:33 -0500185 return err
186 }
khenaidoo820197c2020-02-13 16:35:33 -0500187 for _, childDevicePort := range childDevice.Ports {
188 if childDevicePort.Type == voltha.Port_ETHERNET_UNI {
189 childLogicalPort, exist := physPortToLogicalPortMap[concatDeviceIDPortID(childDevice.Id, childDevicePort.PortNo)]
190 if !exist {
191 // This can happen if this logical port has not been created yet for that device
192 continue
193 }
194 dr.Routes[PathID{Ingress: nniPort.OfpPort.PortNo, Egress: childLogicalPort}] = []Hop{
195 {DeviceID: rootDevice.Id, Ingress: nniPort.DevicePortNo, Egress: rootDevicePort.PortNo},
196 {DeviceID: childDevice.Id, Ingress: childPonPort, Egress: childDevicePort.PortNo},
197 }
198 dr.Routes[PathID{Ingress: childLogicalPort, Egress: nniPort.OfpPort.PortNo}] = getReverseRoute(
199 dr.Routes[PathID{Ingress: nniPort.OfpPort.PortNo, Egress: childLogicalPort}])
200 }
201 }
202 }
203 }
204 }
205 }
206 return nil
207}
208
khenaidoo0db4c812020-05-27 15:27:30 -0400209// AddPort augments the current set of routes with new routes corresponding to the logical port "lp". If the routes have
210// not been built yet then use logical port "lps" to compute all current routes (lps includes lp)
211func (dr *DeviceRoutes) AddPort(ctx context.Context, lp *voltha.LogicalPort, device *voltha.Device, lps []*voltha.LogicalPort) error {
212 logger.Debugw("add-port-to-routes", log.Fields{"port": lp, "count-logical-ports": len(lps)})
213
214 // Adding NNI port
215 if lp.RootPort {
216 return dr.AddNNIPort(ctx, lp, device, lps)
khenaidoo820197c2020-02-13 16:35:33 -0500217 }
218
khenaidoo0db4c812020-05-27 15:27:30 -0400219 // Adding UNI port
220 return dr.AddUNIPort(ctx, lp, device, lps)
221}
222
223// AddUNIPort setup routes between the logical UNI port lp and all registered NNI ports
224func (dr *DeviceRoutes) AddUNIPort(ctx context.Context, lp *voltha.LogicalPort, device *voltha.Device, lps []*voltha.LogicalPort) error {
225 logger.Debugw("add-uni-port-to-routes", log.Fields{"port": lp, "count-logical-ports": len(lps)})
226
227 dr.routeBuildLock.Lock()
228 defer dr.routeBuildLock.Unlock()
229
230 // Add port to logical ports
231 dr.logicalPorts[lp.OfpPort.PortNo] = lp
232
233 // Update internal structures with device data
234 dr.updateCache(device)
235
236 // Adding a UNI port
237 childPonPort, err := dr.getChildPonPort(ctx, lp.DeviceId)
238 if err != nil {
239 return err
240 }
241 rootDevicePonPort, err := dr.getParentPonPort(ctx, device.ParentId, device.Id)
242 if err != nil {
243 return err
244 }
245
246 // Adding a UNI port
247 for _, lPort := range lps {
248 if lPort.RootPort {
249 dr.Routes[PathID{Ingress: lPort.OfpPort.PortNo, Egress: lp.OfpPort.PortNo}] = []Hop{
250 {DeviceID: lPort.DeviceId, Ingress: lPort.DevicePortNo, Egress: rootDevicePonPort},
251 {DeviceID: lp.DeviceId, Ingress: childPonPort, Egress: lp.DevicePortNo},
252 }
253 dr.Routes[PathID{Ingress: lp.OfpPort.PortNo, Egress: lPort.OfpPort.PortNo}] = getReverseRoute(
254 dr.Routes[PathID{Ingress: lPort.OfpPort.PortNo, Egress: lp.OfpPort.PortNo}])
255 }
khenaidoo820197c2020-02-13 16:35:33 -0500256 }
257 return nil
258}
259
khenaidoo0db4c812020-05-27 15:27:30 -0400260// AddNNIPort setup routes between the logical NNI port lp and all registered UNI ports
261func (dr *DeviceRoutes) AddNNIPort(ctx context.Context, lp *voltha.LogicalPort, device *voltha.Device, lps []*voltha.LogicalPort) error {
262 logger.Debugw("add-port-to-routes", log.Fields{"port": lp, "logical-ports-count": len(lps), "device-id": device.Id})
khenaidoo820197c2020-02-13 16:35:33 -0500263
264 dr.routeBuildLock.Lock()
khenaidoo820197c2020-02-13 16:35:33 -0500265 defer dr.routeBuildLock.Unlock()
khenaidoo0db4c812020-05-27 15:27:30 -0400266
267 // Update internal structures with device data
268 dr.updateCache(device)
269
270 // Setup the physical ports to logical ports map, the nni ports as well as the root ports map
271 physPortToLogicalPortMap := make(map[string]uint32)
272 for _, lp := range lps {
273 physPortToLogicalPortMap[concatDeviceIDPortID(lp.DeviceId, lp.DevicePortNo)] = lp.OfpPort.PortNo
274 if lp.RootPort {
275 dr.rootPortsLock.Lock()
276 dr.RootPorts[lp.OfpPort.PortNo] = lp.OfpPort.PortNo
277 dr.rootPortsLock.Unlock()
278 }
279 dr.logicalPorts[lp.OfpPort.PortNo] = lp
khenaidoo820197c2020-02-13 16:35:33 -0500280 }
281
khenaidoo0db4c812020-05-27 15:27:30 -0400282 for _, rootDevicePort := range device.Ports {
283 if rootDevicePort.Type == voltha.Port_PON_OLT {
284 logger.Debugw("peers", log.Fields{"root-device-id": device.Id, "port-no": rootDevicePort.PortNo, "len-peers": len(rootDevicePort.Peers)})
285 for _, rootDevicePeer := range rootDevicePort.Peers {
286 childDevice, err := dr.getDeviceWithCacheUpdate(ctx, rootDevicePeer.DeviceId)
287 if err != nil {
288 continue
289 }
290
291 childPonPort, err := dr.getChildPonPort(ctx, childDevice.Id)
292 if err != nil {
293 continue
294 }
295
296 for _, childDevicePort := range childDevice.Ports {
297 childLogicalPort, exist := physPortToLogicalPortMap[concatDeviceIDPortID(childDevice.Id, childDevicePort.PortNo)]
298 if !exist {
299 // This can happen if this logical port has not been created yet for that device
300 continue
301 }
302
303 if childDevicePort.Type == voltha.Port_ETHERNET_UNI {
304 dr.Routes[PathID{Ingress: lp.OfpPort.PortNo, Egress: childLogicalPort}] = []Hop{
305 {DeviceID: device.Id, Ingress: lp.DevicePortNo, Egress: rootDevicePort.PortNo},
306 {DeviceID: childDevice.Id, Ingress: childPonPort, Egress: childDevicePort.PortNo},
307 }
308 dr.Routes[PathID{Ingress: childLogicalPort, Egress: lp.OfpPort.PortNo}] = getReverseRoute(
309 dr.Routes[PathID{Ingress: lp.OfpPort.PortNo, Egress: childLogicalPort}])
310 }
311 }
khenaidoo820197c2020-02-13 16:35:33 -0500312 }
313 }
314 }
khenaidoo0db4c812020-05-27 15:27:30 -0400315 return nil
316}
khenaidoo820197c2020-02-13 16:35:33 -0500317
khenaidoo0db4c812020-05-27 15:27:30 -0400318// AddAllPorts setups up new routes using all ports on the device. lps includes the device's logical port
319func (dr *DeviceRoutes) AddAllPorts(ctx context.Context, device *voltha.Device, lps []*voltha.LogicalPort) error {
320 logger.Debugw("add-all-port-to-routes", log.Fields{"logical-ports-count": len(lps), "device-id": device.Id})
321 for _, lp := range lps {
322 if lp.DeviceId == device.Id {
323 if err := dr.AddPort(ctx, lp, device, lps); err != nil {
khenaidoo820197c2020-02-13 16:35:33 -0500324 return err
325 }
khenaidoo820197c2020-02-13 16:35:33 -0500326 }
khenaidoo820197c2020-02-13 16:35:33 -0500327 }
328 return nil
329}
330
331// Print prints routes
332func (dr *DeviceRoutes) Print() error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000333 logger.Debugw("Print", log.Fields{"logical-device-id": dr.logicalDeviceID, "logical-ports": dr.logicalPorts})
334 if logger.V(log.DebugLevel) {
khenaidoo820197c2020-02-13 16:35:33 -0500335 output := ""
336 routeNumber := 1
337 for k, v := range dr.Routes {
338 key := fmt.Sprintf("LP:%d->LP:%d", k.Ingress, k.Egress)
339 val := ""
340 for _, i := range v {
341 val += fmt.Sprintf("{%d->%s->%d},", i.Ingress, i.DeviceID, i.Egress)
342 }
343 val = val[:len(val)-1]
344 output += fmt.Sprintf("%d:{%s=>%s} ", routeNumber, key, fmt.Sprintf("[%s]", val))
345 routeNumber++
346 }
347 if len(dr.Routes) == 0 {
Girish Kumarf56a4682020-03-20 20:07:46 +0000348 logger.Debugw("no-routes-found", log.Fields{"logical-device-id": dr.logicalDeviceID})
khenaidoo820197c2020-02-13 16:35:33 -0500349 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000350 logger.Debugw("graph_routes", log.Fields{"lDeviceId": dr.logicalDeviceID, "Routes": output})
khenaidoo820197c2020-02-13 16:35:33 -0500351 }
352 }
353 return nil
354}
355
khenaidoo0db4c812020-05-27 15:27:30 -0400356// isUpToDate returns true if device is up to date
357func (dr *DeviceRoutes) isUpToDate(ld *voltha.LogicalDevice) bool {
khenaidoo820197c2020-02-13 16:35:33 -0500358 dr.routeBuildLock.Lock()
359 defer dr.routeBuildLock.Unlock()
360 numNNI, numUNI := 0, 0
361 if ld != nil {
362 if len(dr.logicalPorts) != len(ld.Ports) {
363 return false
364 }
365 numNNI = len(dr.RootPorts)
366 numUNI = len(ld.Ports) - numNNI
367 }
368 return len(dr.Routes) == numNNI*numUNI*2
369}
370
khenaidoo0db4c812020-05-27 15:27:30 -0400371// IsRoutesEmpty returns true if there are no routes
372func (dr *DeviceRoutes) IsRoutesEmpty() bool {
373 dr.routeBuildLock.RLock()
374 defer dr.routeBuildLock.RUnlock()
375 return len(dr.Routes) == 0
376}
377
378// GetHalfRoute returns a half route that has only the egress hop set or the ingress hop set
379func (dr *DeviceRoutes) GetHalfRoute(nniAsEgress bool, ingress, egress uint32) ([]Hop, error) {
380 dr.routeBuildLock.RLock()
381 defer dr.routeBuildLock.RUnlock()
382 routes := make([]Hop, 0)
383 for routeLink, path := range dr.Routes {
384 // If nniAsEgress is set then the half route will only have the egress hop set where the egress port needs to be
385 // an NNI port
386 if nniAsEgress {
387 // Prioritize a specific egress NNI port if set
388 if egress != 0 && dr.IsRootPort(egress) && routeLink.Egress == egress {
389 routes = append(routes, Hop{})
390 routes = append(routes, path[1])
391 return routes, nil
392 }
393 if egress == 0 && dr.IsRootPort(routeLink.Egress) {
394 routes = append(routes, Hop{})
395 routes = append(routes, path[1])
396 return routes, nil
397 }
398 } else {
399 // Here we use the first route whose ingress port matches the ingress input parameter
400 if ingress != 0 && routeLink.Ingress == ingress {
401 routes = append(routes, path[0])
402 routes = append(routes, Hop{})
403 return routes, nil
khenaidoo820197c2020-02-13 16:35:33 -0500404 }
405 }
406 }
khenaidoo0db4c812020-05-27 15:27:30 -0400407 return routes, fmt.Errorf("no half route found for ingress port %d, egress port %d and nni as egress %t", ingress, egress, nniAsEgress)
khenaidoo820197c2020-02-13 16:35:33 -0500408}
409
khenaidoo0db4c812020-05-27 15:27:30 -0400410//getDeviceWithCacheUpdate returns the from the model and updates the PON ports map of that device.
411func (dr *DeviceRoutes) getDeviceWithCacheUpdate(ctx context.Context, deviceID string) (*voltha.Device, error) {
khenaidoo820197c2020-02-13 16:35:33 -0500412 device, err := dr.getDeviceFromModel(ctx, deviceID)
413 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000414 logger.Errorw("device-not-found", log.Fields{"deviceId": deviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500415 return nil, err
416 }
khenaidoo0db4c812020-05-27 15:27:30 -0400417 dr.updateCache(device)
khenaidoo820197c2020-02-13 16:35:33 -0500418 return device, nil
419}
420
421//copyFromExistingNNIRoutes copies routes from an existing set of NNI routes
422func (dr *DeviceRoutes) copyFromExistingNNIRoutes(newNNIPort *voltha.LogicalPort, copyFromNNIPort *voltha.LogicalPort) {
423 updatedRoutes := make(map[PathID][]Hop)
424 for key, val := range dr.Routes {
425 if key.Ingress == copyFromNNIPort.OfpPort.PortNo {
426 updatedRoutes[PathID{Ingress: newNNIPort.OfpPort.PortNo, Egress: key.Egress}] = []Hop{
427 {DeviceID: newNNIPort.DeviceId, Ingress: newNNIPort.DevicePortNo, Egress: val[0].Egress},
428 val[1],
429 }
430 }
431 if key.Egress == copyFromNNIPort.OfpPort.PortNo {
432 updatedRoutes[PathID{Ingress: key.Ingress, Egress: newNNIPort.OfpPort.PortNo}] = []Hop{
433 val[0],
434 {DeviceID: newNNIPort.DeviceId, Ingress: val[1].Ingress, Egress: newNNIPort.DevicePortNo},
435 }
436 }
437 updatedRoutes[key] = val
438 }
439 dr.Routes = updatedRoutes
440}
441
442// reset cleans up the device graph
443func (dr *DeviceRoutes) reset() {
444 dr.rootPortsLock.Lock()
445 dr.RootPorts = make(map[uint32]uint32)
446 dr.rootPortsLock.Unlock()
khenaidoo820197c2020-02-13 16:35:33 -0500447 dr.Routes = make(map[PathID][]Hop)
khenaidoo0db4c812020-05-27 15:27:30 -0400448 dr.logicalPorts = make(map[uint32]*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -0500449 dr.devicesPonPorts = make(map[string][]*voltha.Port)
khenaidoo0db4c812020-05-27 15:27:30 -0400450 dr.childConnectionPort = make(map[string]uint32)
khenaidoo820197c2020-02-13 16:35:33 -0500451}
452
453//concatDeviceIdPortId formats a portid using the device id and the port number
454func concatDeviceIDPortID(deviceID string, portNo uint32) string {
455 return fmt.Sprintf("%s:%d", deviceID, portNo)
456}
457
458//getReverseRoute returns the reverse of the route
459func getReverseRoute(route []Hop) []Hop {
460 reverse := make([]Hop, len(route))
461 for i, j := 0, len(route)-1; j >= 0; i, j = i+1, j-1 {
462 reverse[i].DeviceID, reverse[i].Ingress, reverse[i].Egress = route[j].DeviceID, route[j].Egress, route[j].Ingress
463 }
464 return reverse
465}
khenaidoo0db4c812020-05-27 15:27:30 -0400466
467// getChildPonPort returns the child PON port number either from cache or from the model. If it is from the model then
468// it updates the PON ports map of that device.
469func (dr *DeviceRoutes) getChildPonPort(ctx context.Context, deviceID string) (uint32, error) {
470 if port, exist := dr.devicesPonPorts[deviceID]; exist {
471 // Return only the first PON port of that child device
472 return port[0].PortNo, nil
473 }
474
475 // Get child device from model
476 if _, err := dr.getDeviceWithCacheUpdate(ctx, deviceID); err != nil {
477 logger.Errorw("device-not-found", log.Fields{"device-id": deviceID, "error": err})
478 return 0, err
479 }
480
481 // Try again
482 if port, exist := dr.devicesPonPorts[deviceID]; exist {
483 // Return only the first PON port of that child device
484 return port[0].PortNo, nil
485 }
486
487 return 0, fmt.Errorf("pon port not found %s", deviceID)
488}
489
490// getParentPonPort returns the parent PON port of the child device
491func (dr *DeviceRoutes) getParentPonPort(ctx context.Context, deviceID string, childDeviceID string) (uint32, error) {
492 if pNo, exist := dr.childConnectionPort[childDeviceID]; exist {
493 return pNo, nil
494 }
495
496 // Get parent device from the model
497 if _, err := dr.getDeviceWithCacheUpdate(ctx, deviceID); err != nil {
498 logger.Errorw("device-not-found", log.Fields{"deviceId": deviceID, "error": err})
499 return 0, err
500 }
501 // Try again
502 if pNo, exist := dr.childConnectionPort[childDeviceID]; exist {
503 return pNo, nil
504 }
505 return 0, fmt.Errorf("pon port associated with child device %s not found", childDeviceID)
506}
507
508func (dr *DeviceRoutes) updateCache(device *voltha.Device) {
509 for _, port := range device.Ports {
510 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_PON_OLT {
511 dr.devicesPonPorts[device.Id] = append(dr.devicesPonPorts[device.Id], port)
512 for _, peer := range port.Peers {
513 if port.Type == voltha.Port_PON_ONU {
514 dr.childConnectionPort[port.DeviceId] = peer.PortNo
515 } else {
516 dr.childConnectionPort[peer.DeviceId] = port.PortNo
517 }
518 }
519 }
520 }
521}
522
523func (dr *DeviceRoutes) getLogicalPorts(ingress, egress uint32) (uniPort, nniPort *voltha.LogicalPort, err error) {
524 inPort, exist := dr.logicalPorts[ingress]
525 if !exist {
526 err = fmt.Errorf("ingress port %d not found", ingress)
527 return
528 }
529 outPort, exist := dr.logicalPorts[egress]
530 if !exist {
531 err = fmt.Errorf("egress port %d not found", egress)
532 return
533 }
534
535 if inPort.RootPort {
536 nniPort = inPort
537 uniPort = outPort
538 } else {
539 nniPort = outPort
540 uniPort = inPort
541 }
542
543 return
544}