blob: 60692e5a4585e57b04cfdd686a89f420e88ab9d0 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -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 core
17
18import (
19 "context"
khenaidoo19d7b632018-10-30 10:49:50 -040020 "errors"
21 "fmt"
khenaidoob9203542018-09-17 22:56:37 -040022 "github.com/gogo/protobuf/proto"
23 "github.com/opencord/voltha-go/common/log"
24 "github.com/opencord/voltha-go/db/model"
25 ca "github.com/opencord/voltha-go/protos/core_adapter"
khenaidoo89b0e942018-10-21 21:11:33 -040026 ofp "github.com/opencord/voltha-go/protos/openflow_13"
khenaidoob9203542018-09-17 22:56:37 -040027 "github.com/opencord/voltha-go/protos/voltha"
khenaidoo89b0e942018-10-21 21:11:33 -040028 fd "github.com/opencord/voltha-go/rw_core/flow_decomposition"
29 "github.com/opencord/voltha-go/rw_core/graph"
30 fu "github.com/opencord/voltha-go/rw_core/utils"
khenaidoob9203542018-09-17 22:56:37 -040031 "google.golang.org/grpc/codes"
32 "google.golang.org/grpc/status"
khenaidoo19d7b632018-10-30 10:49:50 -040033 "reflect"
khenaidoo92e62c52018-10-03 14:02:54 -040034 "sync"
khenaidoob9203542018-09-17 22:56:37 -040035)
36
37type LogicalDeviceAgent struct {
khenaidoo92e62c52018-10-03 14:02:54 -040038 logicalDeviceId string
39 lastData *voltha.LogicalDevice
40 rootDeviceId string
41 deviceMgr *DeviceManager
42 ldeviceMgr *LogicalDeviceManager
43 clusterDataProxy *model.Proxy
44 exitChannel chan int
khenaidoo89b0e942018-10-21 21:11:33 -040045 deviceGraph *graph.DeviceGraph
46 DefaultFlowRules *fu.DeviceRules
khenaidoo19d7b632018-10-30 10:49:50 -040047 flowProxy *model.Proxy
48 groupProxy *model.Proxy
khenaidoo92e62c52018-10-03 14:02:54 -040049 lockLogicalDevice sync.RWMutex
khenaidoo19d7b632018-10-30 10:49:50 -040050 flowDecomposer *fd.FlowDecomposer
khenaidoob9203542018-09-17 22:56:37 -040051}
52
khenaidoo4d4802d2018-10-04 21:59:49 -040053func newLogicalDeviceAgent(id string, device *voltha.Device, ldeviceMgr *LogicalDeviceManager, deviceMgr *DeviceManager,
khenaidoo9a468962018-09-19 15:33:13 -040054 cdProxy *model.Proxy) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040055 var agent LogicalDeviceAgent
56 agent.exitChannel = make(chan int, 1)
57 agent.logicalDeviceId = id
58 agent.rootDeviceId = device.Id
59 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040060 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040061 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040062 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040063 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoob9203542018-09-17 22:56:37 -040064 return &agent
65}
66
khenaidoo4d4802d2018-10-04 21:59:49 -040067// start creates the logical device and add it to the data model
68func (agent *LogicalDeviceAgent) start(ctx context.Context) error {
khenaidoo92e62c52018-10-03 14:02:54 -040069 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -040070 //Build the logical device based on information retrieved from the device adapter
71 var switchCap *ca.SwitchCapability
72 var err error
73 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
74 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
75 return err
76 }
77 ld := &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
khenaidoo89b0e942018-10-21 21:11:33 -040078 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
79 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo19d7b632018-10-30 10:49:50 -040080 ld.Flows = &ofp.Flows{Items: nil}
81 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoob9203542018-09-17 22:56:37 -040082
83 //Add logical ports to the logical device based on the number of NNI ports discovered
84 //First get the default port capability - TODO: each NNI port may have different capabilities,
85 //hence. may need to extract the port by the NNI port id defined by the adapter during device
86 //creation
87 var nniPorts *voltha.Ports
khenaidoo92e62c52018-10-03 14:02:54 -040088 if nniPorts, err = agent.deviceMgr.getPorts(ctx, agent.rootDeviceId, voltha.Port_ETHERNET_NNI); err != nil {
khenaidoob9203542018-09-17 22:56:37 -040089 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
90 }
91 var portCap *ca.PortCapability
92 for _, port := range nniPorts.Items {
khenaidoo19d7b632018-10-30 10:49:50 -040093 log.Infow("!!!!!!!NNI PORTS", log.Fields{"NNI": port})
khenaidoob9203542018-09-17 22:56:37 -040094 if portCap, err = agent.deviceMgr.getPortCapability(ctx, agent.rootDeviceId, port.PortNo); err != nil {
95 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
96 return err
97 }
khenaidoo19d7b632018-10-30 10:49:50 -040098 portCap.Port.RootPort = true
khenaidoob9203542018-09-17 22:56:37 -040099 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo92e62c52018-10-03 14:02:54 -0400100 lp.DeviceId = agent.rootDeviceId
khenaidoo19d7b632018-10-30 10:49:50 -0400101 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
102 lp.OfpPort.PortNo = port.PortNo
103 lp.OfpPort.Name = portCap.Port.Id
104 lp.DevicePortNo = port.PortNo
khenaidoob9203542018-09-17 22:56:37 -0400105 ld.Ports = append(ld.Ports, lp)
106 }
khenaidoo92e62c52018-10-03 14:02:54 -0400107 agent.lockLogicalDevice.Lock()
108 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400109 // Save the logical device
khenaidoo43c82122018-11-22 18:38:28 -0500110 if added := agent.clusterDataProxy.AddWithID("/logical_devices", ld.Id, ld, ""); added == nil {
khenaidoob9203542018-09-17 22:56:37 -0400111 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
112 } else {
113 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
114 }
115
khenaidoo43c82122018-11-22 18:38:28 -0500116 agent.flowProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400117 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
118 false)
khenaidoo43c82122018-11-22 18:38:28 -0500119 agent.groupProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400120 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
121 false)
122
123 agent.flowProxy.RegisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
khenaidoo43c82122018-11-22 18:38:28 -0500124 agent.groupProxy.RegisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
khenaidoo19d7b632018-10-30 10:49:50 -0400125
khenaidoob9203542018-09-17 22:56:37 -0400126 return nil
127}
128
khenaidoo4d4802d2018-10-04 21:59:49 -0400129// stop stops the logical devuce agent. This removes the logical device from the data model.
130func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
131 log.Info("stopping-logical_device-agent")
132 agent.lockLogicalDevice.Lock()
133 defer agent.lockLogicalDevice.Unlock()
134 //Remove the logical device from the model
135 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
136 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
137 } else {
138 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
139 }
140 agent.exitChannel <- 1
141 log.Info("logical_device-agent-stopped")
142}
143
khenaidoo19d7b632018-10-30 10:49:50 -0400144// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
145func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
146 log.Debug("GetLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -0400147 agent.lockLogicalDevice.Lock()
148 defer agent.lockLogicalDevice.Unlock()
149 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
150 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
151 cloned := proto.Clone(lDevice).(*voltha.LogicalDevice)
152 return cloned, nil
153 }
154 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
155}
156
khenaidoo19d7b632018-10-30 10:49:50 -0400157func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
158 log.Debug("!!!!!ListLogicalDevicePorts")
159 agent.lockLogicalDevice.Lock()
160 defer agent.lockLogicalDevice.Unlock()
161 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
162 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
163 lPorts := make([]*voltha.LogicalPort, 0)
164 for _, port := range lDevice.Ports {
165 lPorts = append(lPorts, proto.Clone(port).(*voltha.LogicalPort))
166 }
167 return &voltha.LogicalPorts{Items: lPorts}, nil
168 }
169 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
170}
171
172// listFlows locks the logical device model and then retrieves the latest flow information
173func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
174 log.Debug("listFlows")
175 agent.lockLogicalDevice.Lock()
176 defer agent.lockLogicalDevice.Unlock()
177 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
178 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
179 return lDevice.Flows.Items
180 }
181 return nil
182}
183
184// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
185func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
186 log.Debug("listFlowGroups")
187 agent.lockLogicalDevice.Lock()
188 defer agent.lockLogicalDevice.Unlock()
189 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
190 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
191 return lDevice.FlowGroups.Items
192 }
193 return nil
194}
195
khenaidoo43c82122018-11-22 18:38:28 -0500196//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
197func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
198 cloned := proto.Clone(flows).(*ofp.Flows)
199 afterUpdate := agent.flowProxy.Update("/", cloned, false, "")
200 if afterUpdate == nil {
201 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
202 }
203 // TODO: Remove this code when the model update is fixed
204 ld, _ := agent.getLogicalDeviceWithoutLock()
205 clonedDevice := proto.Clone(ld).(*voltha.LogicalDevice)
206 clonedDevice.Flows = proto.Clone(flows).(*ofp.Flows)
207 agent.updateLogicalDeviceWithoutLock(clonedDevice)
208 return nil
209}
210
211//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
212func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
213 cloned := proto.Clone(flowGroups).(*ofp.FlowGroups)
214 afterUpdate := agent.groupProxy.Update("/", cloned, false, "")
215 if afterUpdate == nil {
216 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
217 }
218 // TODO: Remove this code when the model update is fixed
219 ld, _ := agent.getLogicalDeviceWithoutLock()
220 clonedDevice := proto.Clone(ld).(*voltha.LogicalDevice)
221 clonedDevice.FlowGroups = proto.Clone(flowGroups).(*ofp.FlowGroups)
222 agent.updateLogicalDeviceWithoutLock(clonedDevice)
223 return nil
224}
225
226
khenaidoo4d4802d2018-10-04 21:59:49 -0400227// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
228// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400229func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
230 log.Debug("getLogicalDeviceWithoutLock")
231 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
232 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
233 cloned := proto.Clone(lDevice).(*voltha.LogicalDevice)
234 return cloned, nil
235 }
236 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
237}
238
khenaidoo4d4802d2018-10-04 21:59:49 -0400239// addUNILogicalPort creates a UNI port on the logical device that represents a child device
khenaidoo19d7b632018-10-30 10:49:50 -0400240func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400241 log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400242 // Build the logical device based on information retrieved from the device adapter
243 var portCap *ca.PortCapability
244 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400245
246 //Get UNI port number
247 var uniPort uint32
248 for _, port := range childDevice.Ports {
249 if port.Type == voltha.Port_ETHERNET_UNI {
250 uniPort = port.PortNo
251 }
252 }
253 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, uniPort); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400254 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
255 return err
256 }
khenaidoo92e62c52018-10-03 14:02:54 -0400257 agent.lockLogicalDevice.Lock()
258 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400259 // Get stored logical device
khenaidoo92e62c52018-10-03 14:02:54 -0400260 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400261 return status.Error(codes.NotFound, agent.logicalDeviceId)
262 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400263 log.Infow("!!!!!!!!!!!ADDING-UNI", log.Fields{"deviceId": childDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -0400264 cloned := proto.Clone(ldevice).(*voltha.LogicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -0400265 portCap.Port.RootPort = false
266 //TODO: For now use the channel id assigned by the OLT as logical port number
267 lPortNo := childDevice.ProxyAddress.ChannelId
268 portCap.Port.Id = fmt.Sprintf("uni-%d", lPortNo)
269 portCap.Port.OfpPort.PortNo = lPortNo
270 portCap.Port.OfpPort.Name = portCap.Port.Id
271 portCap.Port.DeviceId = childDevice.Id
272 portCap.Port.DevicePortNo = uniPort
khenaidoo92e62c52018-10-03 14:02:54 -0400273 lp := proto.Clone(portCap.Port).(*voltha.LogicalPort)
274 lp.DeviceId = childDevice.Id
khenaidoob9203542018-09-17 22:56:37 -0400275 cloned.Ports = append(cloned.Ports, lp)
khenaidoo92e62c52018-10-03 14:02:54 -0400276 return agent.updateLogicalDeviceWithoutLock(cloned)
277 }
278}
279
280//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
281func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
282 cloned := proto.Clone(logicalDevice).(*voltha.LogicalDevice)
283 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, cloned, false, "")
284 if afterUpdate == nil {
285 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
286 }
287 return nil
288}
289
khenaidoo19d7b632018-10-30 10:49:50 -0400290//updateFlowTable updates the flow table of that logical device
291func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
292 log.Debug("updateFlowTable")
293 if flow == nil {
294 return nil
295 }
296 switch flow.GetCommand() {
297 case ofp.OfpFlowModCommand_OFPFC_ADD:
298 return agent.flowAdd(flow)
299 case ofp.OfpFlowModCommand_OFPFC_DELETE:
300 return agent.flowDelete(flow)
301 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
302 return agent.flowDeleteStrict(flow)
303 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
304 return agent.flowModify(flow)
305 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
306 return agent.flowModifyStrict(flow)
307 }
308 return status.Errorf(codes.Internal,
309 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
310}
311
312//updateGroupTable updates the group table of that logical device
313func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
314 log.Debug("updateGroupTable")
315 if groupMod == nil {
316 return nil
317 }
318 switch groupMod.GetCommand() {
319 case ofp.OfpGroupModCommand_OFPGC_ADD:
320 return agent.groupAdd(groupMod)
321 case ofp.OfpGroupModCommand_OFPGC_DELETE:
322 return agent.groupDelete(groupMod)
323 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
324 return agent.groupModify(groupMod)
325 }
326 return status.Errorf(codes.Internal,
327 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
328}
329
khenaidoo19d7b632018-10-30 10:49:50 -0400330
331//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
332//must only be called by a function that is holding the lock on the logical device
333func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
khenaidoo43c82122018-11-22 18:38:28 -0500334 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
335 copy(groupsCloned, groups)
336 if afterUpdate := agent.groupProxy.Update("/", groupsCloned, true, ""); afterUpdate == nil {
337 return errors.New(fmt.Sprintf("update-flow-group-failed:%s", agent.logicalDeviceId))
khenaidoo19d7b632018-10-30 10:49:50 -0400338 }
khenaidoo43c82122018-11-22 18:38:28 -0500339 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400340}
341
342//flowAdd adds a flow to the flow table of that logical device
343func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
344 log.Debug("flowAdd")
345 if mod == nil {
346 return nil
347 }
khenaidoo92e62c52018-10-03 14:02:54 -0400348 agent.lockLogicalDevice.Lock()
349 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400350
351 var lDevice *voltha.LogicalDevice
352 var err error
353 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
354 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
355 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
356 }
357
358 var flows []*ofp.OfpFlowStats
359 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
360 flows = lDevice.Flows.Items
361 }
362
khenaidoo43c82122018-11-22 18:38:28 -0500363 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400364 changed := false
365 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
366 if checkOverlap {
367 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
368 // TODO: should this error be notified other than being logged?
369 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
370 } else {
371 // Add flow
372 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
373 flows = append(flows, flow)
374 changed = true
375 }
376 } else {
377 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
378 idx := fu.FindFlows(flows, flow)
379 if idx >= 0 {
380 oldFlow := flows[idx]
381 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
382 flow.ByteCount = oldFlow.ByteCount
383 flow.PacketCount = oldFlow.PacketCount
384 }
385 flows[idx] = flow
386 } else {
387 flows = append(flows, flow)
388 }
389 changed = true
390 }
391 if changed {
392 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500393 flowsToUpdate := &ofp.Flows{}
394 if lDevice.Flows != nil {
395 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400396 }
khenaidoo43c82122018-11-22 18:38:28 -0500397 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
398 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400399 return err
400 }
401 }
khenaidoo43c82122018-11-22 18:38:28 -0500402 //// For now, force the callback to occur
403 //go agent.flowTableUpdated(oldData, lDevice.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400404 return nil
405}
406
407//flowDelete deletes a flow from the flow table of that logical device
408func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
409 log.Debug("flowDelete")
410 if mod == nil {
411 return nil
412 }
413 agent.lockLogicalDevice.Lock()
414 defer agent.lockLogicalDevice.Unlock()
415
416 var lDevice *voltha.LogicalDevice
417 var err error
418 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
419 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
420 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
421 }
422 flows := lDevice.Flows.Items
423
424 //build a list of what to keep vs what to delete
425 toKeep := make([]*ofp.OfpFlowStats, 0)
426 for _, f := range flows {
427 if !fu.FlowMatchesMod(f, mod) {
428 toKeep = append(toKeep, f)
429 }
430 }
431
432 //Update flows
433 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500434 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
435 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400436 return err
437 }
438 }
439
440 //TODO: send announcement on delete
441 return nil
442}
443
444//flowStatsDelete deletes a flow from the flow table of that logical device
445func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
446 log.Debug("flowStatsDelete")
447 if flow == nil {
448 return nil
449 }
450 agent.lockLogicalDevice.Lock()
451 defer agent.lockLogicalDevice.Unlock()
452
453 var lDevice *voltha.LogicalDevice
454 var err error
455 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
456 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
457 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
458 }
459 flows := lDevice.Flows.Items
460
461 //build a list of what to keep vs what to delete
462 toKeep := make([]*ofp.OfpFlowStats, 0)
463 for _, f := range flows {
464 if !fu.FlowMatch(f, flow) {
465 toKeep = append(toKeep, f)
466 }
467 }
468
469 //Update flows
470 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500471 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400472 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
473 return err
474 }
475 }
476 return nil
477}
478
479//flowDeleteStrict deletes a flow from the flow table of that logical device
480func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
481 log.Debug("flowDeleteStrict")
482 if mod == nil {
483 return nil
484 }
485 agent.lockLogicalDevice.Lock()
486 defer agent.lockLogicalDevice.Unlock()
487
488 var lDevice *voltha.LogicalDevice
489 var err error
490 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
491 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
492 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
493 }
494 flows := lDevice.Flows.Items
495 changed := false
496 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
497 idx := fu.FindFlows(flows, flow)
498 if idx >= 0 {
499 flows = append(flows[:idx], flows[idx+1:]...)
500 changed = true
501 } else {
502 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
503 }
504
505 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500506 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400507 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
508 return err
509 }
510 }
511
512 return nil
513}
514
515//flowModify modifies a flow from the flow table of that logical device
516func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
517 return errors.New("flowModify not implemented")
518}
519
520//flowModifyStrict deletes a flow from the flow table of that logical device
521func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
522 return errors.New("flowModifyStrict not implemented")
523}
524
525func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
526 log.Debug("groupAdd")
527 if groupMod == nil {
528 return nil
529 }
530 agent.lockLogicalDevice.Lock()
531 defer agent.lockLogicalDevice.Unlock()
532
533 var lDevice *voltha.LogicalDevice
534 var err error
535 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
536 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
537 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
538 }
539 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400540 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
541 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500542 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
543 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400544 return err
545 }
546 } else {
547 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
548 }
khenaidoo19d7b632018-10-30 10:49:50 -0400549 return nil
550}
551
552func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
553 log.Debug("groupDelete")
554 if groupMod == nil {
555 return nil
556 }
557 agent.lockLogicalDevice.Lock()
558 defer agent.lockLogicalDevice.Unlock()
559
560 var lDevice *voltha.LogicalDevice
561 var err error
562 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
563 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
564 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
565 }
566 groups := lDevice.FlowGroups.Items
567 flows := lDevice.Flows.Items
568 groupsChanged := false
569 flowsChanged := false
570 groupId := groupMod.GroupId
571 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
572 //TODO we must delete all flows that point to this group and
573 //signal controller as requested by flow's flag
574 groups = []*ofp.OfpGroupEntry{}
575 groupsChanged = true
576 } else {
577 if idx := fu.FindGroup(groups, groupId); idx == -1 {
578 return nil // Valid case
579 } else {
580 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
581 groups = append(groups[:idx], groups[idx+1:]...)
582 groupsChanged = true
583 }
584 }
khenaidoo43c82122018-11-22 18:38:28 -0500585 if groupsChanged {
586 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
587 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400588 return err
589 }
590 }
khenaidoo43c82122018-11-22 18:38:28 -0500591 if flowsChanged {
592 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
593 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
594 return err
595 }
596 }
597
khenaidoo19d7b632018-10-30 10:49:50 -0400598 return nil
599}
600
601func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
602 log.Debug("groupModify")
603 if groupMod == nil {
604 return nil
605 }
606 agent.lockLogicalDevice.Lock()
607 defer agent.lockLogicalDevice.Unlock()
608
609 var lDevice *voltha.LogicalDevice
610 var err error
611 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
612 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
613 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
614 }
615 groups := lDevice.FlowGroups.Items
616 groupsChanged := false
617 groupId := groupMod.GroupId
618 if idx := fu.FindGroup(groups, groupId); idx == -1 {
619 return errors.New(fmt.Sprintf("group-absent:%s", groupId))
620 } else {
621 //replace existing group entry with new group definition
622 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
623 groups[idx] = groupEntry
624 groupsChanged = true
625 }
626 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500627 //lDevice.FlowGroups.Items = groups
628 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400629 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
630 return err
631 }
632 }
633 return nil
634}
635
636// deleteLogicalPort removes the logical port
637func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
638 agent.lockLogicalDevice.Lock()
639 defer agent.lockLogicalDevice.Unlock()
640
khenaidoo92e62c52018-10-03 14:02:54 -0400641 // Get the most up to date logical device
642 var logicaldevice *voltha.LogicalDevice
643 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400644 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400645 return nil
646 }
khenaidoo92e62c52018-10-03 14:02:54 -0400647 index := -1
648 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400649 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400650 index = i
651 break
652 }
653 }
654 if index >= 0 {
655 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
656 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
657 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
658 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
659 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
660 }
661 return nil
khenaidoob9203542018-09-17 22:56:37 -0400662}
663
khenaidoo19d7b632018-10-30 10:49:50 -0400664// enableLogicalPort enables the logical port
665func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
666 agent.lockLogicalDevice.Lock()
667 defer agent.lockLogicalDevice.Unlock()
668
669 // Get the most up to date logical device
670 var logicaldevice *voltha.LogicalDevice
671 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
672 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
673 return nil
674 }
675 index := -1
676 for i, logicalPort := range logicaldevice.Ports {
677 if logicalPort.Id == lPort.Id {
678 index = i
679 break
680 }
681 }
682 if index >= 0 {
683 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
684 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
685 }
686 //TODO: Trigger subsequent actions on the device
687 return nil
688}
689
690// disableLogicalPort disabled the logical port
691func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
692 agent.lockLogicalDevice.Lock()
693 defer agent.lockLogicalDevice.Unlock()
694
695 // Get the most up to date logical device
696 var logicaldevice *voltha.LogicalDevice
697 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
698 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
699 return nil
700 }
701 index := -1
702 for i, logicalPort := range logicaldevice.Ports {
703 if logicalPort.Id == lPort.Id {
704 index = i
705 break
706 }
707 }
708 if index >= 0 {
709 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
710 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
711 }
712 //TODO: Trigger subsequent actions on the device
713 return nil
714}
715
khenaidoo89b0e942018-10-21 21:11:33 -0400716func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
717 for _, pNo := range nniPortsNo {
718 if pNo == portNo {
719 return true
720 }
721 }
722 return false
723}
khenaidoo4d4802d2018-10-04 21:59:49 -0400724
khenaidoo89b0e942018-10-21 21:11:33 -0400725func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400726 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400727 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400728 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400729 if ingress == routeLink.Ingress && egress == routeLink.Egress {
730 return route
731 }
732 }
733 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
734 return nil
735}
736
khenaidoo19d7b632018-10-30 10:49:50 -0400737func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400738 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
739 // Get the updated logical device
740 var ld *ca.LogicalDevice
741 routes := make([]graph.RouteHop, 0)
742 var err error
743 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
744 return nil
745 }
746 nniLogicalPortsNo := make([]uint32, 0)
747 for _, logicalPort := range ld.Ports {
748 if logicalPort.RootPort {
749 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
750 }
751 }
752 if len(nniLogicalPortsNo) == 0 {
753 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
754 return nil
755 }
khenaidoo19d7b632018-10-30 10:49:50 -0400756 // Note: A port value of 0 is equivalent to a nil port
757
khenaidoo89b0e942018-10-21 21:11:33 -0400758 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400759 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400760 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400761 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400762 log.Debug("returning-half-route")
763 //This is a trap on the NNI Port
764 //Return a 'half' route to make the flow decomposer logic happy
765 for routeLink, route := range agent.deviceGraph.Routes {
766 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
767 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
768 routes = append(routes, route[1])
769 return routes
770 }
771 }
772 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
773 return nil
774 }
775 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400776 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400777 }
778 //If ingress port is not specified (nil), it may be a wildcarded
779 //route if egress port is OFPP_CONTROLLER or a nni logical port,
780 //in which case we need to create a half-route where only the egress
781 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400782 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400783 // We can use the 2nd hop of any upstream route, so just find the first upstream:
784 for routeLink, route := range agent.deviceGraph.Routes {
785 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
786 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
787 routes = append(routes, route[1])
788 return routes
789 }
790 }
791 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
792 return nil
793 }
794 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400795 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400796 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400797 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400798 routes = append(routes, route[0])
799 routes = append(routes, graph.RouteHop{})
800 return routes
801 }
802 }
803 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
804 return nil
805 }
806
807 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400808 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400809}
810
811// updateRoutes updates the device routes whenever there is a device or port changes relevant to this
812// logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred
813// instead of rebuilding the entire set of routes
814func (agent *LogicalDeviceAgent) updateRoutes() {
khenaidoo19d7b632018-10-30 10:49:50 -0400815 if ld, err := agent.GetLogicalDevice(); err == nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400816 agent.deviceGraph.ComputeRoutes(ld.Ports)
817 }
818}
819
820func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
821 return fu.NewFlowsAndGroups()
822}
823
824func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
825 fg := fu.NewFlowsAndGroups()
826 var device *voltha.Device
827 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400828 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400829 return fg
830 }
831 //set the upstream and downstream ports
832 upstreamPorts := make([]*voltha.Port, 0)
833 downstreamPorts := make([]*voltha.Port, 0)
834 for _, port := range device.Ports {
835 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
836 upstreamPorts = append(upstreamPorts, port)
837 } else if port.Type == voltha.Port_ETHERNET_UNI {
838 downstreamPorts = append(downstreamPorts, port)
839 }
840 }
841 //it is possible that the downstream ports are not created, but the flow_decomposition has already
842 //kicked in. In such scenarios, cut short the processing and return.
843 if len(downstreamPorts) == 0 {
844 return fg
845 }
846 // set up the default flows
847 var fa *fu.FlowArgs
848 fa = &fu.FlowArgs{
849 KV: fu.OfpFlowModArgs{"priority": 500},
850 MatchFields: []*ofp.OfpOxmOfbField{
851 fd.InPort(downstreamPorts[0].PortNo),
852 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
853 },
854 Actions: []*ofp.OfpAction{
855 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400856 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400857 },
858 }
859 fg.AddFlow(fd.MkFlowStat(fa))
860
861 fa = &fu.FlowArgs{
862 KV: fu.OfpFlowModArgs{"priority": 500},
863 MatchFields: []*ofp.OfpOxmOfbField{
864 fd.InPort(downstreamPorts[0].PortNo),
865 fd.VlanVid(0),
866 },
867 Actions: []*ofp.OfpAction{
868 fd.PushVlan(0x8100),
869 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
870 fd.Output(upstreamPorts[0].PortNo),
871 },
872 }
873 fg.AddFlow(fd.MkFlowStat(fa))
874
875 fa = &fu.FlowArgs{
876 KV: fu.OfpFlowModArgs{"priority": 500},
877 MatchFields: []*ofp.OfpOxmOfbField{
878 fd.InPort(upstreamPorts[0].PortNo),
879 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
880 },
881 Actions: []*ofp.OfpAction{
882 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
883 fd.Output(downstreamPorts[0].PortNo),
884 },
885 }
886 fg.AddFlow(fd.MkFlowStat(fa))
887
888 return fg
889}
890
891func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
892 rules := fu.NewDeviceRules()
893 var ld *voltha.LogicalDevice
894 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400895 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400896 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
897 return rules
898 }
899
900 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
901 for deviceId, _ := range deviceNodeIds {
902 if deviceId == ld.RootDeviceId {
903 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
904 } else {
905 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
906 }
907 }
908 return rules
909}
910
911func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
912 // Get latest
913 var lDevice *voltha.LogicalDevice
914 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400915 if lDevice, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400916 return fu.NewDeviceRules()
917 }
918 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo19d7b632018-10-30 10:49:50 -0400919 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
khenaidoo89b0e942018-10-21 21:11:33 -0400920 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
921 agent.DefaultFlowRules = agent.generateDefaultRules()
922 }
923 return agent.DefaultFlowRules
924}
925
926func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
927 lPorts := make([]uint32, 0)
928 var exclPort uint32
929 if len(excludePort) == 1 {
930 exclPort = excludePort[0]
931 }
khenaidoo19d7b632018-10-30 10:49:50 -0400932 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400933 for _, port := range lDevice.Ports {
934 if port.OfpPort.PortNo != exclPort {
935 lPorts = append(lPorts, port.OfpPort.PortNo)
936 }
937 }
938 }
939 return lPorts
940}
khenaidoo19d7b632018-10-30 10:49:50 -0400941
942func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
943 return agent.deviceGraph
944}
945
946//setupDeviceGraph creates the device graph if not done already
947func (agent *LogicalDeviceAgent) setupDeviceGraph() {
948 if agent.deviceGraph == nil {
949 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
950 agent.updateRoutes()
951 }
952}
953
954func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
955 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
956
khenaidoo43c82122018-11-22 18:38:28 -0500957 // Run this callback in it's own go routine since callbacks are not invoked in their own
958 // go routine
959 go func(args ...interface{}) interface{} {
960 //agent.lockLogicalDevice.Lock()
961 //defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400962
khenaidoo43c82122018-11-22 18:38:28 -0500963 var previousData *ofp.Flows
964 var latestData *ofp.Flows
khenaidoo19d7b632018-10-30 10:49:50 -0400965
khenaidoo43c82122018-11-22 18:38:28 -0500966 var ok bool
967 if previousData, ok = args[0].(*ofp.Flows); !ok {
968 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
969 }
970 if latestData, ok = args[1].(*ofp.Flows); !ok {
971 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
972 }
khenaidoo19d7b632018-10-30 10:49:50 -0400973
khenaidoo43c82122018-11-22 18:38:28 -0500974 if reflect.DeepEqual(previousData.Items, latestData.Items) {
975 log.Debug("flow-update-not-required")
976 return nil
977 }
978
979 // Ensure the device graph has been setup
980 agent.setupDeviceGraph()
981
982 var groups *ofp.FlowGroups
983 lDevice, _ := agent.getLogicalDeviceWithoutLock()
984 groups = lDevice.FlowGroups
985 log.Debugw("flowsinfo", log.Fields{"flows": latestData, "groups": groups})
986 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *latestData, *groups)
987 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
988
989 for deviceId, value := range deviceRules.GetRules() {
990 agent.deviceMgr.updateFlows(deviceId, value.ListFlows())
991 agent.deviceMgr.updateGroups(deviceId, value.ListGroups())
992 }
993
khenaidoo19d7b632018-10-30 10:49:50 -0400994 return nil
khenaidoo43c82122018-11-22 18:38:28 -0500995 }(args...)
khenaidoo19d7b632018-10-30 10:49:50 -0400996
khenaidoo19d7b632018-10-30 10:49:50 -0400997 return nil
998}
999
1000func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
1001 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
1002
khenaidoo43c82122018-11-22 18:38:28 -05001003 // Run this callback in it's own go routine since callbacks are not invoked in their own
1004 // go routine
1005 go func(args ...interface{}) interface{} {
1006 //agent.lockLogicalDevice.Lock()
1007 //defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001008
khenaidoo43c82122018-11-22 18:38:28 -05001009 var previousData *ofp.FlowGroups
1010 var latestData *ofp.FlowGroups
khenaidoo19d7b632018-10-30 10:49:50 -04001011
khenaidoo43c82122018-11-22 18:38:28 -05001012 var ok bool
1013 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
1014 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1015 }
1016 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
1017 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1018 }
khenaidoo19d7b632018-10-30 10:49:50 -04001019
khenaidoo43c82122018-11-22 18:38:28 -05001020 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1021 log.Debug("flow-update-not-required")
1022 return nil
1023 }
1024
1025 // Ensure the device graph has been setup
1026 agent.setupDeviceGraph()
1027
1028 var flows *ofp.Flows
1029 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1030 flows = lDevice.Flows
1031 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
1032 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
1033 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1034 for deviceId, value := range deviceRules.GetRules() {
1035 agent.deviceMgr.updateFlows(deviceId, value.ListFlows())
1036 agent.deviceMgr.updateGroups(deviceId, value.ListGroups())
1037 }
khenaidoo19d7b632018-10-30 10:49:50 -04001038 return nil
khenaidoo43c82122018-11-22 18:38:28 -05001039 }(args...)
khenaidoo19d7b632018-10-30 10:49:50 -04001040
khenaidoo19d7b632018-10-30 10:49:50 -04001041 return nil
1042}
khenaidoofdbad6e2018-11-06 22:26:38 -05001043
khenaidoo43c82122018-11-22 18:38:28 -05001044func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001045 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1046 outPort := fd.GetPacketOutPort(packet)
1047 //frame := packet.GetData()
1048 //TODO: Use a channel between the logical agent and the device agent
1049 agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet)
1050}
1051
khenaidoofdbad6e2018-11-06 22:26:38 -05001052func (agent *LogicalDeviceAgent) packetIn(port uint32, packet []byte) {
1053 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet})
1054 packet_in := fd.MkPacketIn(port, packet)
1055 log.Debugw("sending-packet-in", log.Fields{"packet-in": packet_in})
1056}