blob: 8a69967ffc62b6c9f423a905ae6e1d291ff895b0 [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"
khenaidoo79232702018-12-04 11:00:41 -050025 ic "github.com/opencord/voltha-go/protos/inter_container"
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
khenaidoo79232702018-12-04 11:00:41 -050071 var switchCap *ic.SwitchCapability
khenaidoob9203542018-09-17 22:56:37 -040072 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 }
khenaidoo79232702018-12-04 11:00:41 -050091 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -040092 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
khenaidoo4d4802d2018-10-04 21:59:49 -0400226// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
227// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400228func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
229 log.Debug("getLogicalDeviceWithoutLock")
230 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
231 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
232 cloned := proto.Clone(lDevice).(*voltha.LogicalDevice)
233 return cloned, nil
234 }
235 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
236}
237
khenaidoo4d4802d2018-10-04 21:59:49 -0400238// addUNILogicalPort creates a UNI port on the logical device that represents a child device
khenaidoo19d7b632018-10-30 10:49:50 -0400239func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400240 log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400241 // Build the logical device based on information retrieved from the device adapter
khenaidoo79232702018-12-04 11:00:41 -0500242 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -0400243 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400244
245 //Get UNI port number
246 var uniPort uint32
247 for _, port := range childDevice.Ports {
248 if port.Type == voltha.Port_ETHERNET_UNI {
249 uniPort = port.PortNo
250 }
251 }
252 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, uniPort); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400253 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
254 return err
255 }
khenaidoo92e62c52018-10-03 14:02:54 -0400256 agent.lockLogicalDevice.Lock()
257 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400258 // Get stored logical device
khenaidoo92e62c52018-10-03 14:02:54 -0400259 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400260 return status.Error(codes.NotFound, agent.logicalDeviceId)
261 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400262 log.Infow("!!!!!!!!!!!ADDING-UNI", log.Fields{"deviceId": childDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -0400263 cloned := proto.Clone(ldevice).(*voltha.LogicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -0400264 portCap.Port.RootPort = false
265 //TODO: For now use the channel id assigned by the OLT as logical port number
266 lPortNo := childDevice.ProxyAddress.ChannelId
267 portCap.Port.Id = fmt.Sprintf("uni-%d", lPortNo)
268 portCap.Port.OfpPort.PortNo = lPortNo
269 portCap.Port.OfpPort.Name = portCap.Port.Id
270 portCap.Port.DeviceId = childDevice.Id
271 portCap.Port.DevicePortNo = uniPort
khenaidoo92e62c52018-10-03 14:02:54 -0400272 lp := proto.Clone(portCap.Port).(*voltha.LogicalPort)
273 lp.DeviceId = childDevice.Id
khenaidoob9203542018-09-17 22:56:37 -0400274 cloned.Ports = append(cloned.Ports, lp)
khenaidoo92e62c52018-10-03 14:02:54 -0400275 return agent.updateLogicalDeviceWithoutLock(cloned)
276 }
277}
278
279//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
280func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
281 cloned := proto.Clone(logicalDevice).(*voltha.LogicalDevice)
282 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, cloned, false, "")
283 if afterUpdate == nil {
284 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
285 }
286 return nil
287}
288
khenaidoo19d7b632018-10-30 10:49:50 -0400289//updateFlowTable updates the flow table of that logical device
290func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
291 log.Debug("updateFlowTable")
292 if flow == nil {
293 return nil
294 }
295 switch flow.GetCommand() {
296 case ofp.OfpFlowModCommand_OFPFC_ADD:
297 return agent.flowAdd(flow)
298 case ofp.OfpFlowModCommand_OFPFC_DELETE:
299 return agent.flowDelete(flow)
300 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
301 return agent.flowDeleteStrict(flow)
302 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
303 return agent.flowModify(flow)
304 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
305 return agent.flowModifyStrict(flow)
306 }
307 return status.Errorf(codes.Internal,
308 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
309}
310
311//updateGroupTable updates the group table of that logical device
312func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
313 log.Debug("updateGroupTable")
314 if groupMod == nil {
315 return nil
316 }
317 switch groupMod.GetCommand() {
318 case ofp.OfpGroupModCommand_OFPGC_ADD:
319 return agent.groupAdd(groupMod)
320 case ofp.OfpGroupModCommand_OFPGC_DELETE:
321 return agent.groupDelete(groupMod)
322 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
323 return agent.groupModify(groupMod)
324 }
325 return status.Errorf(codes.Internal,
326 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
327}
328
khenaidoo19d7b632018-10-30 10:49:50 -0400329//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
330//must only be called by a function that is holding the lock on the logical device
331func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
khenaidoo43c82122018-11-22 18:38:28 -0500332 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
333 copy(groupsCloned, groups)
334 if afterUpdate := agent.groupProxy.Update("/", groupsCloned, true, ""); afterUpdate == nil {
335 return errors.New(fmt.Sprintf("update-flow-group-failed:%s", agent.logicalDeviceId))
khenaidoo19d7b632018-10-30 10:49:50 -0400336 }
khenaidoo43c82122018-11-22 18:38:28 -0500337 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400338}
339
340//flowAdd adds a flow to the flow table of that logical device
341func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
342 log.Debug("flowAdd")
343 if mod == nil {
344 return nil
345 }
khenaidoo92e62c52018-10-03 14:02:54 -0400346 agent.lockLogicalDevice.Lock()
347 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400348
349 var lDevice *voltha.LogicalDevice
350 var err error
351 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
352 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
353 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
354 }
355
356 var flows []*ofp.OfpFlowStats
357 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
358 flows = lDevice.Flows.Items
359 }
360
khenaidoo43c82122018-11-22 18:38:28 -0500361 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400362 changed := false
363 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
364 if checkOverlap {
365 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
366 // TODO: should this error be notified other than being logged?
367 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
368 } else {
369 // Add flow
370 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
371 flows = append(flows, flow)
372 changed = true
373 }
374 } else {
375 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
376 idx := fu.FindFlows(flows, flow)
377 if idx >= 0 {
378 oldFlow := flows[idx]
379 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
380 flow.ByteCount = oldFlow.ByteCount
381 flow.PacketCount = oldFlow.PacketCount
382 }
383 flows[idx] = flow
384 } else {
385 flows = append(flows, flow)
386 }
387 changed = true
388 }
389 if changed {
390 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500391 flowsToUpdate := &ofp.Flows{}
392 if lDevice.Flows != nil {
393 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400394 }
khenaidoo43c82122018-11-22 18:38:28 -0500395 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
396 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400397 return err
398 }
399 }
khenaidoo43c82122018-11-22 18:38:28 -0500400 //// For now, force the callback to occur
401 //go agent.flowTableUpdated(oldData, lDevice.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400402 return nil
403}
404
405//flowDelete deletes a flow from the flow table of that logical device
406func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
407 log.Debug("flowDelete")
408 if mod == nil {
409 return nil
410 }
411 agent.lockLogicalDevice.Lock()
412 defer agent.lockLogicalDevice.Unlock()
413
414 var lDevice *voltha.LogicalDevice
415 var err error
416 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
417 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
418 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
419 }
420 flows := lDevice.Flows.Items
421
422 //build a list of what to keep vs what to delete
423 toKeep := make([]*ofp.OfpFlowStats, 0)
424 for _, f := range flows {
425 if !fu.FlowMatchesMod(f, mod) {
426 toKeep = append(toKeep, f)
427 }
428 }
429
430 //Update flows
431 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500432 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
433 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400434 return err
435 }
436 }
437
438 //TODO: send announcement on delete
439 return nil
440}
441
442//flowStatsDelete deletes a flow from the flow table of that logical device
443func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
444 log.Debug("flowStatsDelete")
445 if flow == nil {
446 return nil
447 }
448 agent.lockLogicalDevice.Lock()
449 defer agent.lockLogicalDevice.Unlock()
450
451 var lDevice *voltha.LogicalDevice
452 var err error
453 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
454 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
455 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
456 }
457 flows := lDevice.Flows.Items
458
459 //build a list of what to keep vs what to delete
460 toKeep := make([]*ofp.OfpFlowStats, 0)
461 for _, f := range flows {
462 if !fu.FlowMatch(f, flow) {
463 toKeep = append(toKeep, f)
464 }
465 }
466
467 //Update flows
468 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500469 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400470 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
471 return err
472 }
473 }
474 return nil
475}
476
477//flowDeleteStrict deletes a flow from the flow table of that logical device
478func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
479 log.Debug("flowDeleteStrict")
480 if mod == nil {
481 return nil
482 }
483 agent.lockLogicalDevice.Lock()
484 defer agent.lockLogicalDevice.Unlock()
485
486 var lDevice *voltha.LogicalDevice
487 var err error
488 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
489 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
490 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
491 }
492 flows := lDevice.Flows.Items
493 changed := false
494 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
495 idx := fu.FindFlows(flows, flow)
496 if idx >= 0 {
497 flows = append(flows[:idx], flows[idx+1:]...)
498 changed = true
499 } else {
500 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
501 }
502
503 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500504 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400505 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
506 return err
507 }
508 }
509
510 return nil
511}
512
513//flowModify modifies a flow from the flow table of that logical device
514func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
515 return errors.New("flowModify not implemented")
516}
517
518//flowModifyStrict deletes a flow from the flow table of that logical device
519func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
520 return errors.New("flowModifyStrict not implemented")
521}
522
523func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
524 log.Debug("groupAdd")
525 if groupMod == nil {
526 return nil
527 }
528 agent.lockLogicalDevice.Lock()
529 defer agent.lockLogicalDevice.Unlock()
530
531 var lDevice *voltha.LogicalDevice
532 var err error
533 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
534 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
535 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
536 }
537 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400538 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
539 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500540 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
541 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400542 return err
543 }
544 } else {
545 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
546 }
khenaidoo19d7b632018-10-30 10:49:50 -0400547 return nil
548}
549
550func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
551 log.Debug("groupDelete")
552 if groupMod == nil {
553 return nil
554 }
555 agent.lockLogicalDevice.Lock()
556 defer agent.lockLogicalDevice.Unlock()
557
558 var lDevice *voltha.LogicalDevice
559 var err error
560 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
561 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
562 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
563 }
564 groups := lDevice.FlowGroups.Items
565 flows := lDevice.Flows.Items
566 groupsChanged := false
567 flowsChanged := false
568 groupId := groupMod.GroupId
569 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
570 //TODO we must delete all flows that point to this group and
571 //signal controller as requested by flow's flag
572 groups = []*ofp.OfpGroupEntry{}
573 groupsChanged = true
574 } else {
575 if idx := fu.FindGroup(groups, groupId); idx == -1 {
576 return nil // Valid case
577 } else {
578 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
579 groups = append(groups[:idx], groups[idx+1:]...)
580 groupsChanged = true
581 }
582 }
khenaidoo43c82122018-11-22 18:38:28 -0500583 if groupsChanged {
584 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
585 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400586 return err
587 }
588 }
khenaidoo43c82122018-11-22 18:38:28 -0500589 if flowsChanged {
590 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
591 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
592 return err
593 }
594 }
595
khenaidoo19d7b632018-10-30 10:49:50 -0400596 return nil
597}
598
599func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
600 log.Debug("groupModify")
601 if groupMod == nil {
602 return nil
603 }
604 agent.lockLogicalDevice.Lock()
605 defer agent.lockLogicalDevice.Unlock()
606
607 var lDevice *voltha.LogicalDevice
608 var err error
609 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
610 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
611 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
612 }
613 groups := lDevice.FlowGroups.Items
614 groupsChanged := false
615 groupId := groupMod.GroupId
616 if idx := fu.FindGroup(groups, groupId); idx == -1 {
617 return errors.New(fmt.Sprintf("group-absent:%s", groupId))
618 } else {
619 //replace existing group entry with new group definition
620 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
621 groups[idx] = groupEntry
622 groupsChanged = true
623 }
624 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500625 //lDevice.FlowGroups.Items = groups
626 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400627 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
628 return err
629 }
630 }
631 return nil
632}
633
634// deleteLogicalPort removes the logical port
635func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
636 agent.lockLogicalDevice.Lock()
637 defer agent.lockLogicalDevice.Unlock()
638
khenaidoo92e62c52018-10-03 14:02:54 -0400639 // Get the most up to date logical device
640 var logicaldevice *voltha.LogicalDevice
641 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400642 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400643 return nil
644 }
khenaidoo92e62c52018-10-03 14:02:54 -0400645 index := -1
646 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400647 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400648 index = i
649 break
650 }
651 }
652 if index >= 0 {
653 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
654 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
655 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
656 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
657 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
658 }
659 return nil
khenaidoob9203542018-09-17 22:56:37 -0400660}
661
khenaidoo19d7b632018-10-30 10:49:50 -0400662// enableLogicalPort enables the logical port
663func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
664 agent.lockLogicalDevice.Lock()
665 defer agent.lockLogicalDevice.Unlock()
666
667 // Get the most up to date logical device
668 var logicaldevice *voltha.LogicalDevice
669 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
670 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
671 return nil
672 }
673 index := -1
674 for i, logicalPort := range logicaldevice.Ports {
675 if logicalPort.Id == lPort.Id {
676 index = i
677 break
678 }
679 }
680 if index >= 0 {
681 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
682 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
683 }
684 //TODO: Trigger subsequent actions on the device
685 return nil
686}
687
688// disableLogicalPort disabled the logical port
689func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
690 agent.lockLogicalDevice.Lock()
691 defer agent.lockLogicalDevice.Unlock()
692
693 // Get the most up to date logical device
694 var logicaldevice *voltha.LogicalDevice
695 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
696 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
697 return nil
698 }
699 index := -1
700 for i, logicalPort := range logicaldevice.Ports {
701 if logicalPort.Id == lPort.Id {
702 index = i
703 break
704 }
705 }
706 if index >= 0 {
707 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
708 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
709 }
710 //TODO: Trigger subsequent actions on the device
711 return nil
712}
713
khenaidoo89b0e942018-10-21 21:11:33 -0400714func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
715 for _, pNo := range nniPortsNo {
716 if pNo == portNo {
717 return true
718 }
719 }
720 return false
721}
khenaidoo4d4802d2018-10-04 21:59:49 -0400722
khenaidoo89b0e942018-10-21 21:11:33 -0400723func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400724 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400725 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400726 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400727 if ingress == routeLink.Ingress && egress == routeLink.Egress {
728 return route
729 }
730 }
731 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
732 return nil
733}
734
khenaidoo19d7b632018-10-30 10:49:50 -0400735func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400736 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
737 // Get the updated logical device
khenaidoo79232702018-12-04 11:00:41 -0500738 var ld *ic.LogicalDevice
khenaidoo89b0e942018-10-21 21:11:33 -0400739 routes := make([]graph.RouteHop, 0)
740 var err error
741 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
742 return nil
743 }
744 nniLogicalPortsNo := make([]uint32, 0)
745 for _, logicalPort := range ld.Ports {
746 if logicalPort.RootPort {
747 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
748 }
749 }
750 if len(nniLogicalPortsNo) == 0 {
751 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
752 return nil
753 }
khenaidoo19d7b632018-10-30 10:49:50 -0400754 // Note: A port value of 0 is equivalent to a nil port
755
khenaidoo89b0e942018-10-21 21:11:33 -0400756 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400757 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400758 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400759 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400760 log.Debug("returning-half-route")
761 //This is a trap on the NNI Port
762 //Return a 'half' route to make the flow decomposer logic happy
763 for routeLink, route := range agent.deviceGraph.Routes {
764 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
765 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
766 routes = append(routes, route[1])
767 return routes
768 }
769 }
770 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
771 return nil
772 }
773 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400774 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400775 }
776 //If ingress port is not specified (nil), it may be a wildcarded
777 //route if egress port is OFPP_CONTROLLER or a nni logical port,
778 //in which case we need to create a half-route where only the egress
779 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400780 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400781 // We can use the 2nd hop of any upstream route, so just find the first upstream:
782 for routeLink, route := range agent.deviceGraph.Routes {
783 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
784 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
785 routes = append(routes, route[1])
786 return routes
787 }
788 }
789 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
790 return nil
791 }
792 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400793 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400794 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400795 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400796 routes = append(routes, route[0])
797 routes = append(routes, graph.RouteHop{})
798 return routes
799 }
800 }
801 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
802 return nil
803 }
804
805 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400806 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400807}
808
809// updateRoutes updates the device routes whenever there is a device or port changes relevant to this
810// logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred
811// instead of rebuilding the entire set of routes
812func (agent *LogicalDeviceAgent) updateRoutes() {
khenaidoo19d7b632018-10-30 10:49:50 -0400813 if ld, err := agent.GetLogicalDevice(); err == nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400814 agent.deviceGraph.ComputeRoutes(ld.Ports)
815 }
816}
817
818func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
819 return fu.NewFlowsAndGroups()
820}
821
822func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
823 fg := fu.NewFlowsAndGroups()
824 var device *voltha.Device
825 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400826 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400827 return fg
828 }
829 //set the upstream and downstream ports
830 upstreamPorts := make([]*voltha.Port, 0)
831 downstreamPorts := make([]*voltha.Port, 0)
832 for _, port := range device.Ports {
833 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
834 upstreamPorts = append(upstreamPorts, port)
835 } else if port.Type == voltha.Port_ETHERNET_UNI {
836 downstreamPorts = append(downstreamPorts, port)
837 }
838 }
839 //it is possible that the downstream ports are not created, but the flow_decomposition has already
840 //kicked in. In such scenarios, cut short the processing and return.
841 if len(downstreamPorts) == 0 {
842 return fg
843 }
844 // set up the default flows
845 var fa *fu.FlowArgs
846 fa = &fu.FlowArgs{
847 KV: fu.OfpFlowModArgs{"priority": 500},
848 MatchFields: []*ofp.OfpOxmOfbField{
849 fd.InPort(downstreamPorts[0].PortNo),
850 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
851 },
852 Actions: []*ofp.OfpAction{
853 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400854 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400855 },
856 }
857 fg.AddFlow(fd.MkFlowStat(fa))
858
859 fa = &fu.FlowArgs{
860 KV: fu.OfpFlowModArgs{"priority": 500},
861 MatchFields: []*ofp.OfpOxmOfbField{
862 fd.InPort(downstreamPorts[0].PortNo),
863 fd.VlanVid(0),
864 },
865 Actions: []*ofp.OfpAction{
866 fd.PushVlan(0x8100),
867 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
868 fd.Output(upstreamPorts[0].PortNo),
869 },
870 }
871 fg.AddFlow(fd.MkFlowStat(fa))
872
873 fa = &fu.FlowArgs{
874 KV: fu.OfpFlowModArgs{"priority": 500},
875 MatchFields: []*ofp.OfpOxmOfbField{
876 fd.InPort(upstreamPorts[0].PortNo),
877 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
878 },
879 Actions: []*ofp.OfpAction{
880 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
881 fd.Output(downstreamPorts[0].PortNo),
882 },
883 }
884 fg.AddFlow(fd.MkFlowStat(fa))
885
886 return fg
887}
888
889func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
890 rules := fu.NewDeviceRules()
891 var ld *voltha.LogicalDevice
892 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400893 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400894 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
895 return rules
896 }
897
898 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
899 for deviceId, _ := range deviceNodeIds {
900 if deviceId == ld.RootDeviceId {
901 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
902 } else {
903 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
904 }
905 }
906 return rules
907}
908
909func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
910 // Get latest
911 var lDevice *voltha.LogicalDevice
912 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400913 if lDevice, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400914 return fu.NewDeviceRules()
915 }
916 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo19d7b632018-10-30 10:49:50 -0400917 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
khenaidoo89b0e942018-10-21 21:11:33 -0400918 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
919 agent.DefaultFlowRules = agent.generateDefaultRules()
920 }
921 return agent.DefaultFlowRules
922}
923
924func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
925 lPorts := make([]uint32, 0)
926 var exclPort uint32
927 if len(excludePort) == 1 {
928 exclPort = excludePort[0]
929 }
khenaidoo19d7b632018-10-30 10:49:50 -0400930 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400931 for _, port := range lDevice.Ports {
932 if port.OfpPort.PortNo != exclPort {
933 lPorts = append(lPorts, port.OfpPort.PortNo)
934 }
935 }
936 }
937 return lPorts
938}
khenaidoo19d7b632018-10-30 10:49:50 -0400939
940func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
941 return agent.deviceGraph
942}
943
944//setupDeviceGraph creates the device graph if not done already
945func (agent *LogicalDeviceAgent) setupDeviceGraph() {
946 if agent.deviceGraph == nil {
947 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
948 agent.updateRoutes()
949 }
950}
951
952func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
953 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
954
khenaidoo43c82122018-11-22 18:38:28 -0500955 // Run this callback in it's own go routine since callbacks are not invoked in their own
956 // go routine
957 go func(args ...interface{}) interface{} {
958 //agent.lockLogicalDevice.Lock()
959 //defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400960
khenaidoo43c82122018-11-22 18:38:28 -0500961 var previousData *ofp.Flows
962 var latestData *ofp.Flows
khenaidoo19d7b632018-10-30 10:49:50 -0400963
khenaidoo43c82122018-11-22 18:38:28 -0500964 var ok bool
965 if previousData, ok = args[0].(*ofp.Flows); !ok {
966 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
967 }
968 if latestData, ok = args[1].(*ofp.Flows); !ok {
969 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
970 }
khenaidoo19d7b632018-10-30 10:49:50 -0400971
khenaidoo43c82122018-11-22 18:38:28 -0500972 if reflect.DeepEqual(previousData.Items, latestData.Items) {
973 log.Debug("flow-update-not-required")
974 return nil
975 }
976
977 // Ensure the device graph has been setup
978 agent.setupDeviceGraph()
979
980 var groups *ofp.FlowGroups
981 lDevice, _ := agent.getLogicalDeviceWithoutLock()
982 groups = lDevice.FlowGroups
983 log.Debugw("flowsinfo", log.Fields{"flows": latestData, "groups": groups})
984 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *latestData, *groups)
985 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
986
987 for deviceId, value := range deviceRules.GetRules() {
988 agent.deviceMgr.updateFlows(deviceId, value.ListFlows())
989 agent.deviceMgr.updateGroups(deviceId, value.ListGroups())
990 }
991
khenaidoo19d7b632018-10-30 10:49:50 -0400992 return nil
khenaidoo43c82122018-11-22 18:38:28 -0500993 }(args...)
khenaidoo19d7b632018-10-30 10:49:50 -0400994
khenaidoo19d7b632018-10-30 10:49:50 -0400995 return nil
996}
997
998func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
999 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
1000
khenaidoo43c82122018-11-22 18:38:28 -05001001 // Run this callback in it's own go routine since callbacks are not invoked in their own
1002 // go routine
1003 go func(args ...interface{}) interface{} {
1004 //agent.lockLogicalDevice.Lock()
1005 //defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001006
khenaidoo43c82122018-11-22 18:38:28 -05001007 var previousData *ofp.FlowGroups
1008 var latestData *ofp.FlowGroups
khenaidoo19d7b632018-10-30 10:49:50 -04001009
khenaidoo43c82122018-11-22 18:38:28 -05001010 var ok bool
1011 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
1012 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1013 }
1014 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
1015 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1016 }
khenaidoo19d7b632018-10-30 10:49:50 -04001017
khenaidoo43c82122018-11-22 18:38:28 -05001018 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1019 log.Debug("flow-update-not-required")
1020 return nil
1021 }
1022
1023 // Ensure the device graph has been setup
1024 agent.setupDeviceGraph()
1025
1026 var flows *ofp.Flows
1027 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1028 flows = lDevice.Flows
1029 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
1030 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
1031 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1032 for deviceId, value := range deviceRules.GetRules() {
1033 agent.deviceMgr.updateFlows(deviceId, value.ListFlows())
1034 agent.deviceMgr.updateGroups(deviceId, value.ListGroups())
1035 }
khenaidoo19d7b632018-10-30 10:49:50 -04001036 return nil
khenaidoo43c82122018-11-22 18:38:28 -05001037 }(args...)
khenaidoo19d7b632018-10-30 10:49:50 -04001038
khenaidoo19d7b632018-10-30 10:49:50 -04001039 return nil
1040}
khenaidoofdbad6e2018-11-06 22:26:38 -05001041
khenaidoo43c82122018-11-22 18:38:28 -05001042func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001043 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1044 outPort := fd.GetPacketOutPort(packet)
1045 //frame := packet.GetData()
1046 //TODO: Use a channel between the logical agent and the device agent
1047 agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet)
1048}
1049
khenaidoofdbad6e2018-11-06 22:26:38 -05001050func (agent *LogicalDeviceAgent) packetIn(port uint32, packet []byte) {
1051 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet})
1052 packet_in := fd.MkPacketIn(port, packet)
1053 log.Debugw("sending-packet-in", log.Fields{"packet-in": packet_in})
1054}