blob: 9acda6dc8179fb5a87ce12faeaa6b08a4636b49c [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 */
16
17package graph
18
19import (
20 "errors"
21 "fmt"
22 "github.com/gyuho/goraph"
23 "github.com/opencord/voltha-go/common/log"
24 "github.com/opencord/voltha-go/protos/voltha"
25 "strconv"
26 "strings"
27)
28
29func init() {
30 log.AddPackage(log.JSON, log.DebugLevel, nil)
31}
32
33type RouteHop struct {
34 DeviceID string
35 Ingress uint32
36 Egress uint32
37}
38
39type OFPortLink struct {
40 Ingress uint32
41 Egress uint32
42}
43
44type GetDeviceFunc func(id string) (*voltha.Device, error)
45
46func concatDeviceIdPortId(deviceId string, portId uint32) string {
47 return fmt.Sprintf("%s:%d", deviceId, portId)
48}
49
50func splitIntoDeviceIdPortId(id string) (string, uint32, error) {
51 result := strings.Split(id, ":")
52 if len(result) != 2 {
53 return "", 0, errors.New(fmt.Sprintf("invalid-id-%s", id))
54 }
55 if temp, err := strconv.ParseInt(result[1], 10, 32); err != nil {
56 return "", 0, errors.New(fmt.Sprintf("invalid-id-%s-%s", id, err.Error()))
57 } else {
58 return result[0], uint32(temp), nil
59 }
60}
61
62type DeviceGraph struct {
63 GGraph goraph.Graph
64 getDevice GetDeviceFunc
65 logicalPorts []*voltha.LogicalPort
66 RootPorts map[uint32]uint32
67 Routes map[OFPortLink][]RouteHop
68 boundaryPorts map[string]uint32
69}
70
71func NewDeviceGraph(getDevice GetDeviceFunc) *DeviceGraph {
72 var dg DeviceGraph
73 dg.GGraph = goraph.NewGraph()
74 dg.getDevice = getDevice
75 return &dg
76}
77
78func (dg *DeviceGraph) ComputeRoutes(lps []*voltha.LogicalPort) {
79 dg.logicalPorts = lps
80 // Set the root ports
81 dg.RootPorts = make(map[uint32]uint32)
82 for _, lp := range lps {
83 if lp.RootPort {
84 dg.RootPorts[lp.OfpPort.PortNo] = lp.OfpPort.PortNo
85 }
86 }
87 // set the boundary ports
88 dg.boundaryPorts = make(map[string]uint32)
89 for _, lp := range lps {
90 dg.boundaryPorts[fmt.Sprintf("%s:%d", lp.DeviceId, lp.DevicePortNo)] = lp.OfpPort.PortNo
91 }
92 dg.Routes = make(map[OFPortLink][]RouteHop)
93
94 // Build the graph
95 var device *voltha.Device
96 devicesAdded := make(map[string]string)
97 portsAdded := make(map[string]string)
98 for _, logicalPort := range dg.logicalPorts {
99 device, _ = dg.getDevice(logicalPort.DeviceId)
100 dg.GGraph = dg.addDevice(device, dg.GGraph, &devicesAdded, &portsAdded, dg.boundaryPorts)
101 }
102 dg.Routes = dg.buildRoutes()
103}
104
105func (dg *DeviceGraph) addDevice(device *voltha.Device, g goraph.Graph, devicesAdded *map[string]string, portsAdded *map[string]string,
106 boundaryPorts map[string]uint32) goraph.Graph {
107
108 if device == nil {
109 return g
110 }
111
112 if _, exist := (*devicesAdded)[device.Id]; exist {
113 return g
114 }
115 g.AddNode(goraph.NewNode(device.Id))
116 (*devicesAdded)[device.Id] = device.Id
117
118 var portId string
119 var peerPortId string
120 for _, port := range device.Ports {
121 portId = concatDeviceIdPortId(device.Id, port.PortNo)
122 if _, exist := (*portsAdded)[portId]; !exist {
123 (*portsAdded)[portId] = portId
124 g.AddNode(goraph.NewNode(portId))
125 g.AddEdge(goraph.StringID(device.Id), goraph.StringID(portId), 1)
126 g.AddEdge(goraph.StringID(portId), goraph.StringID(device.Id), 1)
127 }
128 for _, peer := range port.Peers {
129 if _, exist := (*devicesAdded)[peer.DeviceId]; !exist {
130 d, _ := dg.getDevice(peer.DeviceId)
131 g = dg.addDevice(d, g, devicesAdded, portsAdded, boundaryPorts)
132 } else {
133 peerPortId = concatDeviceIdPortId(peer.DeviceId, peer.PortNo)
134 g.AddEdge(goraph.StringID(portId), goraph.StringID(peerPortId), 1)
135 g.AddEdge(goraph.StringID(peerPortId), goraph.StringID(portId), 1)
136 }
137 }
138 }
139 return g
140}
141
142func (dg *DeviceGraph) IsRootPort(port uint32) bool {
143 _, exist := dg.RootPorts[port]
144 return exist
145}
146
147func (dg *DeviceGraph) buildRoutes() map[OFPortLink][]RouteHop {
148 var pathIds []goraph.ID
149 path := make([]RouteHop, 0)
150 paths := make(map[OFPortLink][]RouteHop)
151 var err error
152 var hop RouteHop
153 for source, sourcePort := range dg.boundaryPorts {
154 for target, targetPort := range dg.boundaryPorts {
155 if source == target {
156 continue
157 }
158 //Ignore NNI - NNI Routes
159 if dg.IsRootPort(sourcePort) && dg.IsRootPort(targetPort) {
160 continue
161 }
162
163 //Ignore UNI - UNI Routes
164 if !dg.IsRootPort(sourcePort) && !dg.IsRootPort(targetPort) {
165 continue
166 }
167
168 if pathIds, _, err = goraph.Dijkstra(dg.GGraph, goraph.StringID(source), goraph.StringID(target)); err != nil {
169 log.Errorw("no-path", log.Fields{"source": source, "target": target, "error": err})
170 continue
171 }
172 if len(pathIds)%3 != 0 {
173 continue
174 }
175 var deviceId string
176 var ingressPort uint32
177 var egressPort uint32
178 for i := 0; i < len(pathIds); i = i + 3 {
179 if deviceId, ingressPort, err = splitIntoDeviceIdPortId(pathIds[i].String()); err != nil {
180 log.Errorw("id-error", log.Fields{"source": source, "target": target, "error": err})
181 break
182 }
183 if _, egressPort, err = splitIntoDeviceIdPortId(pathIds[i+2].String()); err != nil {
184 log.Errorw("id-error", log.Fields{"source": source, "target": target, "error": err})
185 break
186 }
187 hop = RouteHop{Ingress: ingressPort, DeviceID: deviceId, Egress: egressPort}
188 path = append(path, hop)
189 }
190 tmp := make([]RouteHop, len(path))
191 copy(tmp, path)
192 path = nil
193 paths[OFPortLink{Ingress: sourcePort, Egress: targetPort}] = tmp
194 }
195 }
196 return paths
197}
198
199func (dg *DeviceGraph) GetDeviceNodeIds() map[string]string {
200 nodeIds := make(map[string]string)
201 nodesMap := dg.GGraph.GetNodes()
202 for id, node := range nodesMap {
203 if len(strings.Split(node.String(), ":")) != 2 { // not port node
204 nodeIds[id.String()] = id.String()
205 }
206 }
207 return nodeIds
208}