blob: 4f53474fc8853fa5b9458e8f4b3bde975fd34df9 [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
khenaidoo9a468962018-09-19 15:33:13 -0400110 if added := agent.clusterDataProxy.Add("/logical_devices", 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
khenaidoo19d7b632018-10-30 10:49:50 -0400116 agent.flowProxy = agent.clusterDataProxy.Root.GetProxy(
117 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
118 false)
119 agent.groupProxy = agent.clusterDataProxy.Root.GetProxy(
120 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
121 false)
122
123 agent.flowProxy.RegisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
124 //agent.groupProxy.RegisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
125
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
khenaidoo4d4802d2018-10-04 21:59:49 -0400196// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
197// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400198func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
199 log.Debug("getLogicalDeviceWithoutLock")
200 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
201 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
202 cloned := proto.Clone(lDevice).(*voltha.LogicalDevice)
203 return cloned, nil
204 }
205 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
206}
207
khenaidoo4d4802d2018-10-04 21:59:49 -0400208// addUNILogicalPort creates a UNI port on the logical device that represents a child device
khenaidoo19d7b632018-10-30 10:49:50 -0400209func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400210 log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400211 // Build the logical device based on information retrieved from the device adapter
212 var portCap *ca.PortCapability
213 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400214
215 //Get UNI port number
216 var uniPort uint32
217 for _, port := range childDevice.Ports {
218 if port.Type == voltha.Port_ETHERNET_UNI {
219 uniPort = port.PortNo
220 }
221 }
222 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, uniPort); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400223 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
224 return err
225 }
khenaidoo92e62c52018-10-03 14:02:54 -0400226 agent.lockLogicalDevice.Lock()
227 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400228 // Get stored logical device
khenaidoo92e62c52018-10-03 14:02:54 -0400229 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400230 return status.Error(codes.NotFound, agent.logicalDeviceId)
231 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400232 log.Infow("!!!!!!!!!!!ADDING-UNI", log.Fields{"deviceId": childDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -0400233 cloned := proto.Clone(ldevice).(*voltha.LogicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -0400234 portCap.Port.RootPort = false
235 //TODO: For now use the channel id assigned by the OLT as logical port number
236 lPortNo := childDevice.ProxyAddress.ChannelId
237 portCap.Port.Id = fmt.Sprintf("uni-%d", lPortNo)
238 portCap.Port.OfpPort.PortNo = lPortNo
239 portCap.Port.OfpPort.Name = portCap.Port.Id
240 portCap.Port.DeviceId = childDevice.Id
241 portCap.Port.DevicePortNo = uniPort
khenaidoo92e62c52018-10-03 14:02:54 -0400242 lp := proto.Clone(portCap.Port).(*voltha.LogicalPort)
243 lp.DeviceId = childDevice.Id
khenaidoob9203542018-09-17 22:56:37 -0400244 cloned.Ports = append(cloned.Ports, lp)
khenaidoo92e62c52018-10-03 14:02:54 -0400245 return agent.updateLogicalDeviceWithoutLock(cloned)
246 }
247}
248
249//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
250func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
251 cloned := proto.Clone(logicalDevice).(*voltha.LogicalDevice)
252 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, cloned, false, "")
253 if afterUpdate == nil {
254 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
255 }
256 return nil
257}
258
khenaidoo19d7b632018-10-30 10:49:50 -0400259//updateFlowTable updates the flow table of that logical device
260func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
261 log.Debug("updateFlowTable")
262 if flow == nil {
263 return nil
264 }
265 switch flow.GetCommand() {
266 case ofp.OfpFlowModCommand_OFPFC_ADD:
267 return agent.flowAdd(flow)
268 case ofp.OfpFlowModCommand_OFPFC_DELETE:
269 return agent.flowDelete(flow)
270 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
271 return agent.flowDeleteStrict(flow)
272 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
273 return agent.flowModify(flow)
274 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
275 return agent.flowModifyStrict(flow)
276 }
277 return status.Errorf(codes.Internal,
278 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
279}
280
281//updateGroupTable updates the group table of that logical device
282func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
283 log.Debug("updateGroupTable")
284 if groupMod == nil {
285 return nil
286 }
287 switch groupMod.GetCommand() {
288 case ofp.OfpGroupModCommand_OFPGC_ADD:
289 return agent.groupAdd(groupMod)
290 case ofp.OfpGroupModCommand_OFPGC_DELETE:
291 return agent.groupDelete(groupMod)
292 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
293 return agent.groupModify(groupMod)
294 }
295 return status.Errorf(codes.Internal,
296 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
297}
298
299//updateFlowsWithoutLock updates the flows in the logical device without locking the logical device. This function
300//must only be called by a function that is holding the lock on the logical device
301func (agent *LogicalDeviceAgent) updateFlowsWithoutLock(flows []*ofp.OfpFlowStats) error {
302 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
303 return status.Error(codes.NotFound, agent.logicalDeviceId)
304 } else {
305 flowsCloned := make([]*ofp.OfpFlowStats, len(flows))
306 copy(flowsCloned, flows)
307 ldevice.Flows.Items = flowsCloned
308 return agent.updateLogicalDeviceWithoutLock(ldevice)
309 }
310}
311
312//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
313//must only be called by a function that is holding the lock on the logical device
314func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
315 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
316 return status.Error(codes.NotFound, agent.logicalDeviceId)
317 } else {
318 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
319 copy(groupsCloned, groups)
320 ldevice.FlowGroups.Items = groupsCloned
321 return agent.updateLogicalDeviceWithoutLock(ldevice)
322 }
323}
324
325//flowAdd adds a flow to the flow table of that logical device
326func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
327 log.Debug("flowAdd")
328 if mod == nil {
329 return nil
330 }
khenaidoo92e62c52018-10-03 14:02:54 -0400331 agent.lockLogicalDevice.Lock()
332 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400333
334 var lDevice *voltha.LogicalDevice
335 var err error
336 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
337 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
338 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
339 }
340
341 var flows []*ofp.OfpFlowStats
342 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
343 flows = lDevice.Flows.Items
344 }
345
346 oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
347 changed := false
348 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
349 if checkOverlap {
350 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
351 // TODO: should this error be notified other than being logged?
352 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
353 } else {
354 // Add flow
355 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
356 flows = append(flows, flow)
357 changed = true
358 }
359 } else {
360 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
361 idx := fu.FindFlows(flows, flow)
362 if idx >= 0 {
363 oldFlow := flows[idx]
364 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
365 flow.ByteCount = oldFlow.ByteCount
366 flow.PacketCount = oldFlow.PacketCount
367 }
368 flows[idx] = flow
369 } else {
370 flows = append(flows, flow)
371 }
372 changed = true
373 }
374 if changed {
375 // Update model
376 if lDevice.Flows == nil {
377 lDevice.Flows = &ofp.Flows{}
378 }
379 lDevice.Flows.Items = flows
380 if err := agent.updateLogicalDeviceWithoutLock(lDevice); err != nil {
381 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
382 return err
383 }
384 }
385 // For now, force the callback to occur
386 go agent.flowTableUpdated(oldData, lDevice.Flows)
387 return nil
388}
389
390//flowDelete deletes a flow from the flow table of that logical device
391func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
392 log.Debug("flowDelete")
393 if mod == nil {
394 return nil
395 }
396 agent.lockLogicalDevice.Lock()
397 defer agent.lockLogicalDevice.Unlock()
398
399 var lDevice *voltha.LogicalDevice
400 var err error
401 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
402 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
403 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
404 }
405 flows := lDevice.Flows.Items
406
407 //build a list of what to keep vs what to delete
408 toKeep := make([]*ofp.OfpFlowStats, 0)
409 for _, f := range flows {
410 if !fu.FlowMatchesMod(f, mod) {
411 toKeep = append(toKeep, f)
412 }
413 }
414
415 //Update flows
416 if len(toKeep) < len(flows) {
417 lDevice.Flows.Items = toKeep
418 if err := agent.updateLogicalDeviceWithoutLock(lDevice); err != nil {
419 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
420 return err
421 }
422 }
423
424 //TODO: send announcement on delete
425 return nil
426}
427
428//flowStatsDelete deletes a flow from the flow table of that logical device
429func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
430 log.Debug("flowStatsDelete")
431 if flow == nil {
432 return nil
433 }
434 agent.lockLogicalDevice.Lock()
435 defer agent.lockLogicalDevice.Unlock()
436
437 var lDevice *voltha.LogicalDevice
438 var err error
439 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
440 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
441 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
442 }
443 flows := lDevice.Flows.Items
444
445 //build a list of what to keep vs what to delete
446 toKeep := make([]*ofp.OfpFlowStats, 0)
447 for _, f := range flows {
448 if !fu.FlowMatch(f, flow) {
449 toKeep = append(toKeep, f)
450 }
451 }
452
453 //Update flows
454 if len(toKeep) < len(flows) {
455 lDevice.Flows.Items = toKeep
456 if err := agent.updateLogicalDeviceWithoutLock(lDevice); err != nil {
457 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
458 return err
459 }
460 }
461 return nil
462}
463
464//flowDeleteStrict deletes a flow from the flow table of that logical device
465func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
466 log.Debug("flowDeleteStrict")
467 if mod == nil {
468 return nil
469 }
470 agent.lockLogicalDevice.Lock()
471 defer agent.lockLogicalDevice.Unlock()
472
473 var lDevice *voltha.LogicalDevice
474 var err error
475 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
476 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
477 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
478 }
479 flows := lDevice.Flows.Items
480 changed := false
481 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
482 idx := fu.FindFlows(flows, flow)
483 if idx >= 0 {
484 flows = append(flows[:idx], flows[idx+1:]...)
485 changed = true
486 } else {
487 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
488 }
489
490 if changed {
491 lDevice.Flows.Items = flows
492 if err := agent.updateLogicalDeviceWithoutLock(lDevice); err != nil {
493 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
494 return err
495 }
496 }
497
498 return nil
499}
500
501//flowModify modifies a flow from the flow table of that logical device
502func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
503 return errors.New("flowModify not implemented")
504}
505
506//flowModifyStrict deletes a flow from the flow table of that logical device
507func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
508 return errors.New("flowModifyStrict not implemented")
509}
510
511func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
512 log.Debug("groupAdd")
513 if groupMod == nil {
514 return nil
515 }
516 agent.lockLogicalDevice.Lock()
517 defer agent.lockLogicalDevice.Unlock()
518
519 var lDevice *voltha.LogicalDevice
520 var err error
521 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
522 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
523 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
524 }
525 groups := lDevice.FlowGroups.Items
526 oldData := proto.Clone(lDevice.FlowGroups).(*voltha.FlowGroups)
527 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
528 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
529 lDevice.FlowGroups.Items = groups
530 if err := agent.updateLogicalDeviceWithoutLock(lDevice); err != nil {
531 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
532 return err
533 }
534 } else {
535 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
536 }
537 // For now, force the callback to occur
538 go agent.groupTableUpdated(oldData, lDevice.FlowGroups)
539 return nil
540}
541
542func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
543 log.Debug("groupDelete")
544 if groupMod == nil {
545 return nil
546 }
547 agent.lockLogicalDevice.Lock()
548 defer agent.lockLogicalDevice.Unlock()
549
550 var lDevice *voltha.LogicalDevice
551 var err error
552 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
553 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
554 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
555 }
556 groups := lDevice.FlowGroups.Items
557 flows := lDevice.Flows.Items
558 groupsChanged := false
559 flowsChanged := false
560 groupId := groupMod.GroupId
561 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
562 //TODO we must delete all flows that point to this group and
563 //signal controller as requested by flow's flag
564 groups = []*ofp.OfpGroupEntry{}
565 groupsChanged = true
566 } else {
567 if idx := fu.FindGroup(groups, groupId); idx == -1 {
568 return nil // Valid case
569 } else {
570 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
571 groups = append(groups[:idx], groups[idx+1:]...)
572 groupsChanged = true
573 }
574 }
575 if groupsChanged || flowsChanged {
576 lDevice.FlowGroups.Items = groups
577 lDevice.Flows.Items = flows
578 if err := agent.updateLogicalDeviceWithoutLock(lDevice); err != nil {
579 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
580 return err
581 }
582 }
583 return nil
584}
585
586func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
587 log.Debug("groupModify")
588 if groupMod == nil {
589 return nil
590 }
591 agent.lockLogicalDevice.Lock()
592 defer agent.lockLogicalDevice.Unlock()
593
594 var lDevice *voltha.LogicalDevice
595 var err error
596 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
597 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
598 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
599 }
600 groups := lDevice.FlowGroups.Items
601 groupsChanged := false
602 groupId := groupMod.GroupId
603 if idx := fu.FindGroup(groups, groupId); idx == -1 {
604 return errors.New(fmt.Sprintf("group-absent:%s", groupId))
605 } else {
606 //replace existing group entry with new group definition
607 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
608 groups[idx] = groupEntry
609 groupsChanged = true
610 }
611 if groupsChanged {
612 lDevice.FlowGroups.Items = groups
613 if err := agent.updateLogicalDeviceWithoutLock(lDevice); err != nil {
614 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
615 return err
616 }
617 }
618 return nil
619}
620
621// deleteLogicalPort removes the logical port
622func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
623 agent.lockLogicalDevice.Lock()
624 defer agent.lockLogicalDevice.Unlock()
625
khenaidoo92e62c52018-10-03 14:02:54 -0400626 // Get the most up to date logical device
627 var logicaldevice *voltha.LogicalDevice
628 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400629 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400630 return nil
631 }
khenaidoo92e62c52018-10-03 14:02:54 -0400632 index := -1
633 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400634 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400635 index = i
636 break
637 }
638 }
639 if index >= 0 {
640 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
641 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
642 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
643 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
644 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
645 }
646 return nil
khenaidoob9203542018-09-17 22:56:37 -0400647}
648
khenaidoo19d7b632018-10-30 10:49:50 -0400649// enableLogicalPort enables the logical port
650func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
651 agent.lockLogicalDevice.Lock()
652 defer agent.lockLogicalDevice.Unlock()
653
654 // Get the most up to date logical device
655 var logicaldevice *voltha.LogicalDevice
656 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
657 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
658 return nil
659 }
660 index := -1
661 for i, logicalPort := range logicaldevice.Ports {
662 if logicalPort.Id == lPort.Id {
663 index = i
664 break
665 }
666 }
667 if index >= 0 {
668 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
669 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
670 }
671 //TODO: Trigger subsequent actions on the device
672 return nil
673}
674
675// disableLogicalPort disabled the logical port
676func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
677 agent.lockLogicalDevice.Lock()
678 defer agent.lockLogicalDevice.Unlock()
679
680 // Get the most up to date logical device
681 var logicaldevice *voltha.LogicalDevice
682 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
683 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
684 return nil
685 }
686 index := -1
687 for i, logicalPort := range logicaldevice.Ports {
688 if logicalPort.Id == lPort.Id {
689 index = i
690 break
691 }
692 }
693 if index >= 0 {
694 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
695 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
696 }
697 //TODO: Trigger subsequent actions on the device
698 return nil
699}
700
khenaidoo89b0e942018-10-21 21:11:33 -0400701func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
702 for _, pNo := range nniPortsNo {
703 if pNo == portNo {
704 return true
705 }
706 }
707 return false
708}
khenaidoo4d4802d2018-10-04 21:59:49 -0400709
khenaidoo89b0e942018-10-21 21:11:33 -0400710func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400711 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400712 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400713 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400714 if ingress == routeLink.Ingress && egress == routeLink.Egress {
715 return route
716 }
717 }
718 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
719 return nil
720}
721
khenaidoo19d7b632018-10-30 10:49:50 -0400722func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400723 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
724 // Get the updated logical device
725 var ld *ca.LogicalDevice
726 routes := make([]graph.RouteHop, 0)
727 var err error
728 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
729 return nil
730 }
731 nniLogicalPortsNo := make([]uint32, 0)
732 for _, logicalPort := range ld.Ports {
733 if logicalPort.RootPort {
734 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
735 }
736 }
737 if len(nniLogicalPortsNo) == 0 {
738 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
739 return nil
740 }
khenaidoo19d7b632018-10-30 10:49:50 -0400741 // Note: A port value of 0 is equivalent to a nil port
742
khenaidoo89b0e942018-10-21 21:11:33 -0400743 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400744 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400745 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400746 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400747 log.Debug("returning-half-route")
748 //This is a trap on the NNI Port
749 //Return a 'half' route to make the flow decomposer logic happy
750 for routeLink, route := range agent.deviceGraph.Routes {
751 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
752 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
753 routes = append(routes, route[1])
754 return routes
755 }
756 }
757 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
758 return nil
759 }
760 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400761 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400762 }
763 //If ingress port is not specified (nil), it may be a wildcarded
764 //route if egress port is OFPP_CONTROLLER or a nni logical port,
765 //in which case we need to create a half-route where only the egress
766 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400767 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400768 // We can use the 2nd hop of any upstream route, so just find the first upstream:
769 for routeLink, route := range agent.deviceGraph.Routes {
770 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
771 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
772 routes = append(routes, route[1])
773 return routes
774 }
775 }
776 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
777 return nil
778 }
779 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400780 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400781 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400782 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400783 routes = append(routes, route[0])
784 routes = append(routes, graph.RouteHop{})
785 return routes
786 }
787 }
788 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
789 return nil
790 }
791
792 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400793 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400794}
795
796// updateRoutes updates the device routes whenever there is a device or port changes relevant to this
797// logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred
798// instead of rebuilding the entire set of routes
799func (agent *LogicalDeviceAgent) updateRoutes() {
khenaidoo19d7b632018-10-30 10:49:50 -0400800 if ld, err := agent.GetLogicalDevice(); err == nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400801 agent.deviceGraph.ComputeRoutes(ld.Ports)
802 }
803}
804
805func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
806 return fu.NewFlowsAndGroups()
807}
808
809func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
810 fg := fu.NewFlowsAndGroups()
811 var device *voltha.Device
812 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400813 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400814 return fg
815 }
816 //set the upstream and downstream ports
817 upstreamPorts := make([]*voltha.Port, 0)
818 downstreamPorts := make([]*voltha.Port, 0)
819 for _, port := range device.Ports {
820 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
821 upstreamPorts = append(upstreamPorts, port)
822 } else if port.Type == voltha.Port_ETHERNET_UNI {
823 downstreamPorts = append(downstreamPorts, port)
824 }
825 }
826 //it is possible that the downstream ports are not created, but the flow_decomposition has already
827 //kicked in. In such scenarios, cut short the processing and return.
828 if len(downstreamPorts) == 0 {
829 return fg
830 }
831 // set up the default flows
832 var fa *fu.FlowArgs
833 fa = &fu.FlowArgs{
834 KV: fu.OfpFlowModArgs{"priority": 500},
835 MatchFields: []*ofp.OfpOxmOfbField{
836 fd.InPort(downstreamPorts[0].PortNo),
837 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
838 },
839 Actions: []*ofp.OfpAction{
840 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400841 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400842 },
843 }
844 fg.AddFlow(fd.MkFlowStat(fa))
845
846 fa = &fu.FlowArgs{
847 KV: fu.OfpFlowModArgs{"priority": 500},
848 MatchFields: []*ofp.OfpOxmOfbField{
849 fd.InPort(downstreamPorts[0].PortNo),
850 fd.VlanVid(0),
851 },
852 Actions: []*ofp.OfpAction{
853 fd.PushVlan(0x8100),
854 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
855 fd.Output(upstreamPorts[0].PortNo),
856 },
857 }
858 fg.AddFlow(fd.MkFlowStat(fa))
859
860 fa = &fu.FlowArgs{
861 KV: fu.OfpFlowModArgs{"priority": 500},
862 MatchFields: []*ofp.OfpOxmOfbField{
863 fd.InPort(upstreamPorts[0].PortNo),
864 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
865 },
866 Actions: []*ofp.OfpAction{
867 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
868 fd.Output(downstreamPorts[0].PortNo),
869 },
870 }
871 fg.AddFlow(fd.MkFlowStat(fa))
872
873 return fg
874}
875
876func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
877 rules := fu.NewDeviceRules()
878 var ld *voltha.LogicalDevice
879 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400880 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400881 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
882 return rules
883 }
884
885 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
886 for deviceId, _ := range deviceNodeIds {
887 if deviceId == ld.RootDeviceId {
888 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
889 } else {
890 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
891 }
892 }
893 return rules
894}
895
896func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
897 // Get latest
898 var lDevice *voltha.LogicalDevice
899 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400900 if lDevice, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400901 return fu.NewDeviceRules()
902 }
903 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo19d7b632018-10-30 10:49:50 -0400904 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
khenaidoo89b0e942018-10-21 21:11:33 -0400905 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
906 agent.DefaultFlowRules = agent.generateDefaultRules()
907 }
908 return agent.DefaultFlowRules
909}
910
911func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
912 lPorts := make([]uint32, 0)
913 var exclPort uint32
914 if len(excludePort) == 1 {
915 exclPort = excludePort[0]
916 }
khenaidoo19d7b632018-10-30 10:49:50 -0400917 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400918 for _, port := range lDevice.Ports {
919 if port.OfpPort.PortNo != exclPort {
920 lPorts = append(lPorts, port.OfpPort.PortNo)
921 }
922 }
923 }
924 return lPorts
925}
khenaidoo19d7b632018-10-30 10:49:50 -0400926
927func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
928 return agent.deviceGraph
929}
930
931//setupDeviceGraph creates the device graph if not done already
932func (agent *LogicalDeviceAgent) setupDeviceGraph() {
933 if agent.deviceGraph == nil {
934 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
935 agent.updateRoutes()
936 }
937}
938
939func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
940 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
941
942 //agent.lockLogicalDevice.Lock()
943 //defer agent.lockLogicalDevice.Unlock()
944
945 var previousData *ofp.Flows
946 var latestData *ofp.Flows
947
948 var ok bool
949 if previousData, ok = args[0].(*ofp.Flows); !ok {
950 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
951 }
952 if latestData, ok = args[1].(*ofp.Flows); !ok {
953 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
954 }
955
956 if reflect.DeepEqual(previousData.Items, latestData.Items) {
957 log.Debug("flow-update-not-required")
958 return nil
959 }
960
961 // Ensure the device graph has been setup
962 agent.setupDeviceGraph()
963
964 var groups *ofp.FlowGroups
965 lDevice, _ := agent.getLogicalDeviceWithoutLock()
966 groups = lDevice.FlowGroups
967 log.Debugw("flowsinfo", log.Fields{"flows": latestData, "groups": groups})
968 //groupsIf := agent.groupProxy.Get("/", 1, false, "")
969 //if groups, ok = groupsIf.(*ofp.FlowGroups); !ok {
970 // log.Errorw("cannot-retrieve-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "group": groupsIf})
971 // //return errors.New("cannot-retrieve-groups")
972 // groups = &ofp.FlowGroups{Items:nil}
973 //}
974 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *latestData, *groups)
975 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
976 for deviceId, value := range deviceRules.GetRules() {
977 agent.deviceMgr.updateFlows(deviceId, value.ListFlows())
978 agent.deviceMgr.updateGroups(deviceId, value.ListGroups())
979 }
980 return nil
981}
982
983func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
984 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
985
986 //agent.lockLogicalDevice.Lock()
987 //defer agent.lockLogicalDevice.Unlock()
988
989 var previousData *ofp.FlowGroups
990 var latestData *ofp.FlowGroups
991
992 var ok bool
993 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
994 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
995 }
996 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
997 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
998 }
999
1000 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1001 log.Debug("flow-update-not-required")
1002 return nil
1003 }
1004
1005 // Ensure the device graph has been setup
1006 agent.setupDeviceGraph()
1007
1008 var flows *ofp.Flows
1009 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1010 flows = lDevice.Flows
1011 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
1012 //flowsIf := agent.flowProxy.Get("/", 1, false, "")
1013 //if flows, ok = flowsIf.(*ofp.Flows); !ok {
1014 // log.Errorw("cannot-retrieve-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "flows": flows})
1015 // //return errors.New("cannot-retrieve-groups")
1016 // flows = &ofp.Flows{Items:nil}
1017 //}
1018 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
1019 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1020 for deviceId, value := range deviceRules.GetRules() {
1021 agent.deviceMgr.updateFlows(deviceId, value.ListFlows())
1022 agent.deviceMgr.updateGroups(deviceId, value.ListGroups())
1023 }
1024 return nil
1025}
khenaidoofdbad6e2018-11-06 22:26:38 -05001026
1027func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut ) {
1028 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1029 outPort := fd.GetPacketOutPort(packet)
1030 //frame := packet.GetData()
1031 //TODO: Use a channel between the logical agent and the device agent
1032 agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet)
1033}
1034
1035
1036func (agent *LogicalDeviceAgent) packetIn(port uint32, packet []byte) {
1037 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet})
1038 packet_in := fd.MkPacketIn(port, packet)
1039 log.Debugw("sending-packet-in", log.Fields{"packet-in": packet_in})
1040}
1041