khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 1 | /* |
| 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 | package core |
| 17 | |
| 18 | import ( |
| 19 | "context" |
| 20 | "github.com/gogo/protobuf/proto" |
| 21 | "github.com/opencord/voltha-go/common/log" |
| 22 | "github.com/opencord/voltha-go/db/model" |
| 23 | ca "github.com/opencord/voltha-go/protos/core_adapter" |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame^] | 24 | ofp "github.com/opencord/voltha-go/protos/openflow_13" |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 25 | "github.com/opencord/voltha-go/protos/voltha" |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame^] | 26 | fd "github.com/opencord/voltha-go/rw_core/flow_decomposition" |
| 27 | "github.com/opencord/voltha-go/rw_core/graph" |
| 28 | fu "github.com/opencord/voltha-go/rw_core/utils" |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 29 | "google.golang.org/grpc/codes" |
| 30 | "google.golang.org/grpc/status" |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 31 | "sync" |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 32 | ) |
| 33 | |
| 34 | type LogicalDeviceAgent struct { |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 35 | logicalDeviceId string |
| 36 | lastData *voltha.LogicalDevice |
| 37 | rootDeviceId string |
| 38 | deviceMgr *DeviceManager |
| 39 | ldeviceMgr *LogicalDeviceManager |
| 40 | clusterDataProxy *model.Proxy |
| 41 | exitChannel chan int |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame^] | 42 | deviceGraph *graph.DeviceGraph |
| 43 | DefaultFlowRules *fu.DeviceRules |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 44 | lockLogicalDevice sync.RWMutex |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 45 | } |
| 46 | |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 47 | func newLogicalDeviceAgent(id string, device *voltha.Device, ldeviceMgr *LogicalDeviceManager, deviceMgr *DeviceManager, |
khenaidoo | 9a46896 | 2018-09-19 15:33:13 -0400 | [diff] [blame] | 48 | cdProxy *model.Proxy) *LogicalDeviceAgent { |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 49 | var agent LogicalDeviceAgent |
| 50 | agent.exitChannel = make(chan int, 1) |
| 51 | agent.logicalDeviceId = id |
| 52 | agent.rootDeviceId = device.Id |
| 53 | agent.deviceMgr = deviceMgr |
khenaidoo | 9a46896 | 2018-09-19 15:33:13 -0400 | [diff] [blame] | 54 | agent.clusterDataProxy = cdProxy |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 55 | agent.ldeviceMgr = ldeviceMgr |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame^] | 56 | //agent.deviceGraph = |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 57 | agent.lockLogicalDevice = sync.RWMutex{} |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 58 | return &agent |
| 59 | } |
| 60 | |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 61 | // start creates the logical device and add it to the data model |
| 62 | func (agent *LogicalDeviceAgent) start(ctx context.Context) error { |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 63 | log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId}) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 64 | //Build the logical device based on information retrieved from the device adapter |
| 65 | var switchCap *ca.SwitchCapability |
| 66 | var err error |
| 67 | if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil { |
| 68 | log.Errorw("error-creating-logical-device", log.Fields{"error": err}) |
| 69 | return err |
| 70 | } |
| 71 | ld := &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId} |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame^] | 72 | ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc) |
| 73 | ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 74 | |
| 75 | //Add logical ports to the logical device based on the number of NNI ports discovered |
| 76 | //First get the default port capability - TODO: each NNI port may have different capabilities, |
| 77 | //hence. may need to extract the port by the NNI port id defined by the adapter during device |
| 78 | //creation |
| 79 | var nniPorts *voltha.Ports |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 80 | if nniPorts, err = agent.deviceMgr.getPorts(ctx, agent.rootDeviceId, voltha.Port_ETHERNET_NNI); err != nil { |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 81 | log.Errorw("error-creating-logical-port", log.Fields{"error": err}) |
| 82 | } |
| 83 | var portCap *ca.PortCapability |
| 84 | for _, port := range nniPorts.Items { |
| 85 | log.Infow("NNI PORTS", log.Fields{"NNI": port}) |
| 86 | if portCap, err = agent.deviceMgr.getPortCapability(ctx, agent.rootDeviceId, port.PortNo); err != nil { |
| 87 | log.Errorw("error-creating-logical-device", log.Fields{"error": err}) |
| 88 | return err |
| 89 | } |
| 90 | |
| 91 | lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort) |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 92 | lp.DeviceId = agent.rootDeviceId |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 93 | ld.Ports = append(ld.Ports, lp) |
| 94 | } |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 95 | agent.lockLogicalDevice.Lock() |
| 96 | defer agent.lockLogicalDevice.Unlock() |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 97 | // Save the logical device |
khenaidoo | 9a46896 | 2018-09-19 15:33:13 -0400 | [diff] [blame] | 98 | if added := agent.clusterDataProxy.Add("/logical_devices", ld, ""); added == nil { |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 99 | log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId}) |
| 100 | } else { |
| 101 | log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId}) |
| 102 | } |
| 103 | |
| 104 | return nil |
| 105 | } |
| 106 | |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 107 | // stop stops the logical devuce agent. This removes the logical device from the data model. |
| 108 | func (agent *LogicalDeviceAgent) stop(ctx context.Context) { |
| 109 | log.Info("stopping-logical_device-agent") |
| 110 | agent.lockLogicalDevice.Lock() |
| 111 | defer agent.lockLogicalDevice.Unlock() |
| 112 | //Remove the logical device from the model |
| 113 | if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil { |
| 114 | log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId}) |
| 115 | } else { |
| 116 | log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId}) |
| 117 | } |
| 118 | agent.exitChannel <- 1 |
| 119 | log.Info("logical_device-agent-stopped") |
| 120 | } |
| 121 | |
| 122 | // getLogicalDevice locks the logical device model and then retrieves the latest logical device information |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 123 | func (agent *LogicalDeviceAgent) getLogicalDevice() (*voltha.LogicalDevice, error) { |
| 124 | log.Debug("getLogicalDevice") |
| 125 | agent.lockLogicalDevice.Lock() |
| 126 | defer agent.lockLogicalDevice.Unlock() |
| 127 | logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "") |
| 128 | if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok { |
| 129 | cloned := proto.Clone(lDevice).(*voltha.LogicalDevice) |
| 130 | return cloned, nil |
| 131 | } |
| 132 | return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId) |
| 133 | } |
| 134 | |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 135 | // getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by |
| 136 | // functions that have already acquired the logical device lock to the model |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 137 | func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) { |
| 138 | log.Debug("getLogicalDeviceWithoutLock") |
| 139 | logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "") |
| 140 | if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok { |
| 141 | cloned := proto.Clone(lDevice).(*voltha.LogicalDevice) |
| 142 | return cloned, nil |
| 143 | } |
| 144 | return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId) |
| 145 | } |
| 146 | |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 147 | // addUNILogicalPort creates a UNI port on the logical device that represents a child device |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 148 | func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, portNo uint32) error { |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 149 | log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId}) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 150 | // Build the logical device based on information retrieved from the device adapter |
| 151 | var portCap *ca.PortCapability |
| 152 | var err error |
| 153 | if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, portNo); err != nil { |
| 154 | log.Errorw("error-creating-logical-port", log.Fields{"error": err}) |
| 155 | return err |
| 156 | } |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 157 | agent.lockLogicalDevice.Lock() |
| 158 | defer agent.lockLogicalDevice.Unlock() |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 159 | // Get stored logical device |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 160 | if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil { |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 161 | return status.Error(codes.NotFound, agent.logicalDeviceId) |
| 162 | } else { |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 163 | cloned := proto.Clone(ldevice).(*voltha.LogicalDevice) |
| 164 | lp := proto.Clone(portCap.Port).(*voltha.LogicalPort) |
| 165 | lp.DeviceId = childDevice.Id |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 166 | cloned.Ports = append(cloned.Ports, lp) |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 167 | return agent.updateLogicalDeviceWithoutLock(cloned) |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | //updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it |
| 172 | func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error { |
| 173 | cloned := proto.Clone(logicalDevice).(*voltha.LogicalDevice) |
| 174 | afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, cloned, false, "") |
| 175 | if afterUpdate == nil { |
| 176 | return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId) |
| 177 | } |
| 178 | return nil |
| 179 | } |
| 180 | |
| 181 | // deleteLogicalPort removes the logical port associated with a child device |
| 182 | func (agent *LogicalDeviceAgent) deleteLogicalPort(device *voltha.Device) error { |
| 183 | agent.lockLogicalDevice.Lock() |
| 184 | defer agent.lockLogicalDevice.Unlock() |
| 185 | // Get the most up to date logical device |
| 186 | var logicaldevice *voltha.LogicalDevice |
| 187 | if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil { |
| 188 | log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "deviceId": device.Id}) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 189 | return nil |
| 190 | } |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 191 | index := -1 |
| 192 | for i, logicalPort := range logicaldevice.Ports { |
| 193 | if logicalPort.DeviceId == device.Id { |
| 194 | index = i |
| 195 | break |
| 196 | } |
| 197 | } |
| 198 | if index >= 0 { |
| 199 | copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:]) |
| 200 | logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil |
| 201 | logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1] |
| 202 | log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId}) |
| 203 | return agent.updateLogicalDeviceWithoutLock(logicaldevice) |
| 204 | } |
| 205 | return nil |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 206 | } |
| 207 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame^] | 208 | func isNNIPort(portNo uint32, nniPortsNo []uint32) bool { |
| 209 | for _, pNo := range nniPortsNo { |
| 210 | if pNo == portNo { |
| 211 | return true |
| 212 | } |
| 213 | } |
| 214 | return false |
| 215 | } |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 216 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame^] | 217 | func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop { |
| 218 | for routeLink, route := range agent.deviceGraph.Routes { |
| 219 | if ingress == routeLink.Ingress && egress == routeLink.Egress { |
| 220 | return route |
| 221 | } |
| 222 | } |
| 223 | log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress}) |
| 224 | return nil |
| 225 | } |
| 226 | |
| 227 | func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo *uint32, egressPortNo *uint32) []graph.RouteHop { |
| 228 | agent.lockLogicalDevice.Lock() |
| 229 | defer agent.lockLogicalDevice.Unlock() |
| 230 | log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo}) |
| 231 | // Get the updated logical device |
| 232 | var ld *ca.LogicalDevice |
| 233 | routes := make([]graph.RouteHop, 0) |
| 234 | var err error |
| 235 | if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil { |
| 236 | return nil |
| 237 | } |
| 238 | nniLogicalPortsNo := make([]uint32, 0) |
| 239 | for _, logicalPort := range ld.Ports { |
| 240 | if logicalPort.RootPort { |
| 241 | nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo) |
| 242 | } |
| 243 | } |
| 244 | if len(nniLogicalPortsNo) == 0 { |
| 245 | log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id}) |
| 246 | return nil |
| 247 | } |
| 248 | // Consider different possibilities |
| 249 | if egressPortNo != nil && ((*egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) { |
| 250 | log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo}) |
| 251 | if isNNIPort(*ingressPortNo, nniLogicalPortsNo) { |
| 252 | log.Debug("returning-half-route") |
| 253 | //This is a trap on the NNI Port |
| 254 | //Return a 'half' route to make the flow decomposer logic happy |
| 255 | for routeLink, route := range agent.deviceGraph.Routes { |
| 256 | if isNNIPort(routeLink.Egress, nniLogicalPortsNo) { |
| 257 | routes = append(routes, graph.RouteHop{}) // first hop is set to empty |
| 258 | routes = append(routes, route[1]) |
| 259 | return routes |
| 260 | } |
| 261 | } |
| 262 | log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo}) |
| 263 | return nil |
| 264 | } |
| 265 | //treat it as if the output port is the first NNI of the OLT |
| 266 | egressPortNo = &nniLogicalPortsNo[0] |
| 267 | } |
| 268 | //If ingress port is not specified (nil), it may be a wildcarded |
| 269 | //route if egress port is OFPP_CONTROLLER or a nni logical port, |
| 270 | //in which case we need to create a half-route where only the egress |
| 271 | //hop is filled, the first hop is nil |
| 272 | if ingressPortNo == nil && isNNIPort(*egressPortNo, nniLogicalPortsNo) { |
| 273 | // We can use the 2nd hop of any upstream route, so just find the first upstream: |
| 274 | for routeLink, route := range agent.deviceGraph.Routes { |
| 275 | if isNNIPort(routeLink.Egress, nniLogicalPortsNo) { |
| 276 | routes = append(routes, graph.RouteHop{}) // first hop is set to empty |
| 277 | routes = append(routes, route[1]) |
| 278 | return routes |
| 279 | } |
| 280 | } |
| 281 | log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo}) |
| 282 | return nil |
| 283 | } |
| 284 | //If egress port is not specified (nil), we can also can return a "half" route |
| 285 | if egressPortNo == nil { |
| 286 | for routeLink, route := range agent.deviceGraph.Routes { |
| 287 | if routeLink.Ingress == *ingressPortNo { |
| 288 | routes = append(routes, route[0]) |
| 289 | routes = append(routes, graph.RouteHop{}) |
| 290 | return routes |
| 291 | } |
| 292 | } |
| 293 | log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo}) |
| 294 | return nil |
| 295 | } |
| 296 | |
| 297 | // Return the pre-calculated route |
| 298 | return agent.getPreCalculatedRoute(*ingressPortNo, *egressPortNo) |
| 299 | } |
| 300 | |
| 301 | // updateRoutes updates the device routes whenever there is a device or port changes relevant to this |
| 302 | // logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred |
| 303 | // instead of rebuilding the entire set of routes |
| 304 | func (agent *LogicalDeviceAgent) updateRoutes() { |
| 305 | if ld, err := agent.getLogicalDevice(); err == nil { |
| 306 | agent.deviceGraph.ComputeRoutes(ld.Ports) |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups { |
| 311 | return fu.NewFlowsAndGroups() |
| 312 | } |
| 313 | |
| 314 | func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups { |
| 315 | fg := fu.NewFlowsAndGroups() |
| 316 | var device *voltha.Device |
| 317 | var err error |
| 318 | if device, err = agent.deviceMgr.getDevice(deviceId); err != nil { |
| 319 | return fg |
| 320 | } |
| 321 | //set the upstream and downstream ports |
| 322 | upstreamPorts := make([]*voltha.Port, 0) |
| 323 | downstreamPorts := make([]*voltha.Port, 0) |
| 324 | for _, port := range device.Ports { |
| 325 | if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU { |
| 326 | upstreamPorts = append(upstreamPorts, port) |
| 327 | } else if port.Type == voltha.Port_ETHERNET_UNI { |
| 328 | downstreamPorts = append(downstreamPorts, port) |
| 329 | } |
| 330 | } |
| 331 | //it is possible that the downstream ports are not created, but the flow_decomposition has already |
| 332 | //kicked in. In such scenarios, cut short the processing and return. |
| 333 | if len(downstreamPorts) == 0 { |
| 334 | return fg |
| 335 | } |
| 336 | // set up the default flows |
| 337 | var fa *fu.FlowArgs |
| 338 | fa = &fu.FlowArgs{ |
| 339 | KV: fu.OfpFlowModArgs{"priority": 500}, |
| 340 | MatchFields: []*ofp.OfpOxmOfbField{ |
| 341 | fd.InPort(downstreamPorts[0].PortNo), |
| 342 | fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0), |
| 343 | }, |
| 344 | Actions: []*ofp.OfpAction{ |
| 345 | fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)), |
| 346 | }, |
| 347 | } |
| 348 | fg.AddFlow(fd.MkFlowStat(fa)) |
| 349 | |
| 350 | fa = &fu.FlowArgs{ |
| 351 | KV: fu.OfpFlowModArgs{"priority": 500}, |
| 352 | MatchFields: []*ofp.OfpOxmOfbField{ |
| 353 | fd.InPort(downstreamPorts[0].PortNo), |
| 354 | fd.VlanVid(0), |
| 355 | }, |
| 356 | Actions: []*ofp.OfpAction{ |
| 357 | fd.PushVlan(0x8100), |
| 358 | fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)), |
| 359 | fd.Output(upstreamPorts[0].PortNo), |
| 360 | }, |
| 361 | } |
| 362 | fg.AddFlow(fd.MkFlowStat(fa)) |
| 363 | |
| 364 | fa = &fu.FlowArgs{ |
| 365 | KV: fu.OfpFlowModArgs{"priority": 500}, |
| 366 | MatchFields: []*ofp.OfpOxmOfbField{ |
| 367 | fd.InPort(upstreamPorts[0].PortNo), |
| 368 | fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan), |
| 369 | }, |
| 370 | Actions: []*ofp.OfpAction{ |
| 371 | fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)), |
| 372 | fd.Output(downstreamPorts[0].PortNo), |
| 373 | }, |
| 374 | } |
| 375 | fg.AddFlow(fd.MkFlowStat(fa)) |
| 376 | |
| 377 | return fg |
| 378 | } |
| 379 | |
| 380 | func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules { |
| 381 | rules := fu.NewDeviceRules() |
| 382 | var ld *voltha.LogicalDevice |
| 383 | var err error |
| 384 | if ld, err = agent.getLogicalDevice(); err != nil { |
| 385 | log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId}) |
| 386 | return rules |
| 387 | } |
| 388 | |
| 389 | deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds() |
| 390 | for deviceId, _ := range deviceNodeIds { |
| 391 | if deviceId == ld.RootDeviceId { |
| 392 | rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules()) |
| 393 | } else { |
| 394 | rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId)) |
| 395 | } |
| 396 | } |
| 397 | return rules |
| 398 | } |
| 399 | |
| 400 | func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules { |
| 401 | // Get latest |
| 402 | var lDevice *voltha.LogicalDevice |
| 403 | var err error |
| 404 | if lDevice, err = agent.getLogicalDevice(); err != nil { |
| 405 | return fu.NewDeviceRules() |
| 406 | } |
| 407 | if agent.DefaultFlowRules == nil { // Nothing setup yet |
| 408 | agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.getDevice) |
| 409 | agent.deviceGraph.ComputeRoutes(lDevice.Ports) |
| 410 | agent.DefaultFlowRules = agent.generateDefaultRules() |
| 411 | } |
| 412 | return agent.DefaultFlowRules |
| 413 | } |
| 414 | |
| 415 | func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 { |
| 416 | lPorts := make([]uint32, 0) |
| 417 | var exclPort uint32 |
| 418 | if len(excludePort) == 1 { |
| 419 | exclPort = excludePort[0] |
| 420 | } |
| 421 | if lDevice, _ := agent.getLogicalDevice(); lDevice != nil { |
| 422 | for _, port := range lDevice.Ports { |
| 423 | if port.OfpPort.PortNo != exclPort { |
| 424 | lPorts = append(lPorts, port.OfpPort.PortNo) |
| 425 | } |
| 426 | } |
| 427 | } |
| 428 | return lPorts |
| 429 | } |