blob: 7875da757a189dfcad9538d311873d5288c2e0e3 [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
Stephane Barbarie1ab43272018-12-08 21:42:13 -050053func newLogicalDeviceAgent(id string, deviceId string, ldeviceMgr *LogicalDeviceManager,
54 deviceMgr *DeviceManager,
khenaidoo9a468962018-09-19 15:33:13 -040055 cdProxy *model.Proxy) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040056 var agent LogicalDeviceAgent
57 agent.exitChannel = make(chan int, 1)
58 agent.logicalDeviceId = id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050059 agent.rootDeviceId = deviceId
khenaidoob9203542018-09-17 22:56:37 -040060 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040061 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040062 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040063 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040064 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoob9203542018-09-17 22:56:37 -040065 return &agent
66}
67
khenaidoo4d4802d2018-10-04 21:59:49 -040068// start creates the logical device and add it to the data model
69func (agent *LogicalDeviceAgent) start(ctx context.Context) error {
khenaidoo92e62c52018-10-03 14:02:54 -040070 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -040071 //Build the logical device based on information retrieved from the device adapter
khenaidoo79232702018-12-04 11:00:41 -050072 var switchCap *ic.SwitchCapability
khenaidoob9203542018-09-17 22:56:37 -040073 var err error
74 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
75 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
76 return err
77 }
khenaidooca301322019-01-09 23:06:32 -050078
khenaidoob9203542018-09-17 22:56:37 -040079 ld := &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
khenaidooca301322019-01-09 23:06:32 -050080
81 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
82 var datapathID uint64
83 if datapathID, err = CreateDataPathId(agent.logicalDeviceId); err != nil {
84 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
85 return err
86 }
87 ld.DatapathId = datapathID
khenaidoo89b0e942018-10-21 21:11:33 -040088 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
89 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo19d7b632018-10-30 10:49:50 -040090 ld.Flows = &ofp.Flows{Items: nil}
91 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoob9203542018-09-17 22:56:37 -040092
93 //Add logical ports to the logical device based on the number of NNI ports discovered
94 //First get the default port capability - TODO: each NNI port may have different capabilities,
95 //hence. may need to extract the port by the NNI port id defined by the adapter during device
96 //creation
97 var nniPorts *voltha.Ports
khenaidoo92e62c52018-10-03 14:02:54 -040098 if nniPorts, err = agent.deviceMgr.getPorts(ctx, agent.rootDeviceId, voltha.Port_ETHERNET_NNI); err != nil {
khenaidoob9203542018-09-17 22:56:37 -040099 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
100 }
khenaidoo79232702018-12-04 11:00:41 -0500101 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -0400102 for _, port := range nniPorts.Items {
khenaidoo19d7b632018-10-30 10:49:50 -0400103 log.Infow("!!!!!!!NNI PORTS", log.Fields{"NNI": port})
khenaidoob9203542018-09-17 22:56:37 -0400104 if portCap, err = agent.deviceMgr.getPortCapability(ctx, agent.rootDeviceId, port.PortNo); err != nil {
105 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
106 return err
107 }
khenaidoo19d7b632018-10-30 10:49:50 -0400108 portCap.Port.RootPort = true
khenaidoob9203542018-09-17 22:56:37 -0400109 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo92e62c52018-10-03 14:02:54 -0400110 lp.DeviceId = agent.rootDeviceId
khenaidoo19d7b632018-10-30 10:49:50 -0400111 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
112 lp.OfpPort.PortNo = port.PortNo
khenaidoobcf205b2019-01-25 22:21:14 -0500113 lp.OfpPort.Name = lp.Id
khenaidoo19d7b632018-10-30 10:49:50 -0400114 lp.DevicePortNo = port.PortNo
khenaidoob9203542018-09-17 22:56:37 -0400115 ld.Ports = append(ld.Ports, lp)
116 }
khenaidoo92e62c52018-10-03 14:02:54 -0400117 agent.lockLogicalDevice.Lock()
khenaidoobcf205b2019-01-25 22:21:14 -0500118 //defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400119 // Save the logical device
khenaidoo43c82122018-11-22 18:38:28 -0500120 if added := agent.clusterDataProxy.AddWithID("/logical_devices", ld.Id, ld, ""); added == nil {
khenaidoob9203542018-09-17 22:56:37 -0400121 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
122 } else {
123 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
124 }
125
khenaidoo43c82122018-11-22 18:38:28 -0500126 agent.flowProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400127 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
128 false)
khenaidoo43c82122018-11-22 18:38:28 -0500129 agent.groupProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400130 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
131 false)
132
133 agent.flowProxy.RegisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
khenaidoo43c82122018-11-22 18:38:28 -0500134 agent.groupProxy.RegisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
khenaidoo19d7b632018-10-30 10:49:50 -0400135
khenaidoobcf205b2019-01-25 22:21:14 -0500136 agent.lockLogicalDevice.Unlock()
137
138 // Setup the device graph
139 go agent.setupDeviceGraph()
140
khenaidoob9203542018-09-17 22:56:37 -0400141 return nil
142}
143
khenaidoo4d4802d2018-10-04 21:59:49 -0400144// stop stops the logical devuce agent. This removes the logical device from the data model.
145func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
146 log.Info("stopping-logical_device-agent")
147 agent.lockLogicalDevice.Lock()
148 defer agent.lockLogicalDevice.Unlock()
149 //Remove the logical device from the model
150 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
151 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
152 } else {
153 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
154 }
155 agent.exitChannel <- 1
156 log.Info("logical_device-agent-stopped")
157}
158
khenaidoo19d7b632018-10-30 10:49:50 -0400159// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
160func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
161 log.Debug("GetLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -0400162 agent.lockLogicalDevice.Lock()
163 defer agent.lockLogicalDevice.Unlock()
164 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
165 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500166 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400167 }
168 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
169}
170
khenaidoo19d7b632018-10-30 10:49:50 -0400171func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
172 log.Debug("!!!!!ListLogicalDevicePorts")
173 agent.lockLogicalDevice.Lock()
174 defer agent.lockLogicalDevice.Unlock()
175 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
176 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
177 lPorts := make([]*voltha.LogicalPort, 0)
178 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500179 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400180 }
181 return &voltha.LogicalPorts{Items: lPorts}, nil
182 }
183 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
184}
185
186// listFlows locks the logical device model and then retrieves the latest flow information
187func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
188 log.Debug("listFlows")
189 agent.lockLogicalDevice.Lock()
190 defer agent.lockLogicalDevice.Unlock()
191 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
192 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
193 return lDevice.Flows.Items
194 }
195 return nil
196}
197
198// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
199func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
200 log.Debug("listFlowGroups")
201 agent.lockLogicalDevice.Lock()
202 defer agent.lockLogicalDevice.Unlock()
203 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
204 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
205 return lDevice.FlowGroups.Items
206 }
207 return nil
208}
209
khenaidoo43c82122018-11-22 18:38:28 -0500210//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
211func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500212 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500213 if afterUpdate == nil {
214 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
215 }
khenaidoo43c82122018-11-22 18:38:28 -0500216 return nil
217}
218
219//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
220func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500221 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500222 if afterUpdate == nil {
223 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
224 }
khenaidoo43c82122018-11-22 18:38:28 -0500225 return nil
226}
227
khenaidoo4d4802d2018-10-04 21:59:49 -0400228// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
229// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400230func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
231 log.Debug("getLogicalDeviceWithoutLock")
232 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
233 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500234 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400235 }
236 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
237}
238
khenaidoo4d4802d2018-10-04 21:59:49 -0400239// addUNILogicalPort creates a UNI port on the logical device that represents a child device
khenaidoo19d7b632018-10-30 10:49:50 -0400240func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400241 log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400242 // Build the logical device based on information retrieved from the device adapter
khenaidoo79232702018-12-04 11:00:41 -0500243 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -0400244 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400245
246 //Get UNI port number
247 var uniPort uint32
248 for _, port := range childDevice.Ports {
249 if port.Type == voltha.Port_ETHERNET_UNI {
250 uniPort = port.PortNo
251 }
252 }
253 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, uniPort); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400254 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
255 return err
256 }
khenaidoo92e62c52018-10-03 14:02:54 -0400257 agent.lockLogicalDevice.Lock()
258 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400259 // Get stored logical device
khenaidoo92e62c52018-10-03 14:02:54 -0400260 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400261 return status.Error(codes.NotFound, agent.logicalDeviceId)
262 } else {
khenaidoobcf205b2019-01-25 22:21:14 -0500263 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
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
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500272 portCap.Port.DeviceId = childDevice.Id
khenaidoobcf205b2019-01-25 22:21:14 -0500273
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500274 ldevice.Ports = append(ldevice.Ports, portCap.Port)
275 return agent.updateLogicalDeviceWithoutLock(ldevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400276 }
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 {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500281 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400282 if afterUpdate == nil {
283 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
284 }
285 return nil
286}
287
khenaidoo19d7b632018-10-30 10:49:50 -0400288//updateFlowTable updates the flow table of that logical device
289func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
290 log.Debug("updateFlowTable")
291 if flow == nil {
292 return nil
293 }
294 switch flow.GetCommand() {
295 case ofp.OfpFlowModCommand_OFPFC_ADD:
296 return agent.flowAdd(flow)
297 case ofp.OfpFlowModCommand_OFPFC_DELETE:
298 return agent.flowDelete(flow)
299 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
300 return agent.flowDeleteStrict(flow)
301 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
302 return agent.flowModify(flow)
303 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
304 return agent.flowModifyStrict(flow)
305 }
306 return status.Errorf(codes.Internal,
307 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
308}
309
310//updateGroupTable updates the group table of that logical device
311func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
312 log.Debug("updateGroupTable")
313 if groupMod == nil {
314 return nil
315 }
316 switch groupMod.GetCommand() {
317 case ofp.OfpGroupModCommand_OFPGC_ADD:
318 return agent.groupAdd(groupMod)
319 case ofp.OfpGroupModCommand_OFPGC_DELETE:
320 return agent.groupDelete(groupMod)
321 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
322 return agent.groupModify(groupMod)
323 }
324 return status.Errorf(codes.Internal,
325 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
326}
327
khenaidoo19d7b632018-10-30 10:49:50 -0400328//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
329//must only be called by a function that is holding the lock on the logical device
330func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
khenaidoo43c82122018-11-22 18:38:28 -0500331 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
332 copy(groupsCloned, groups)
333 if afterUpdate := agent.groupProxy.Update("/", groupsCloned, true, ""); afterUpdate == nil {
334 return errors.New(fmt.Sprintf("update-flow-group-failed:%s", agent.logicalDeviceId))
khenaidoo19d7b632018-10-30 10:49:50 -0400335 }
khenaidoo43c82122018-11-22 18:38:28 -0500336 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400337}
338
339//flowAdd adds a flow to the flow table of that logical device
340func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
341 log.Debug("flowAdd")
342 if mod == nil {
343 return nil
344 }
khenaidoo92e62c52018-10-03 14:02:54 -0400345 agent.lockLogicalDevice.Lock()
346 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400347
348 var lDevice *voltha.LogicalDevice
349 var err error
350 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
351 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
352 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
353 }
354
355 var flows []*ofp.OfpFlowStats
356 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
357 flows = lDevice.Flows.Items
358 }
359
khenaidoo43c82122018-11-22 18:38:28 -0500360 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400361 changed := false
362 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
363 if checkOverlap {
364 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
365 // TODO: should this error be notified other than being logged?
366 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
367 } else {
368 // Add flow
369 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
370 flows = append(flows, flow)
371 changed = true
372 }
373 } else {
374 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
375 idx := fu.FindFlows(flows, flow)
376 if idx >= 0 {
377 oldFlow := flows[idx]
378 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
379 flow.ByteCount = oldFlow.ByteCount
380 flow.PacketCount = oldFlow.PacketCount
381 }
382 flows[idx] = flow
383 } else {
384 flows = append(flows, flow)
385 }
386 changed = true
387 }
388 if changed {
389 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500390 flowsToUpdate := &ofp.Flows{}
391 if lDevice.Flows != nil {
392 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400393 }
khenaidoo43c82122018-11-22 18:38:28 -0500394 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
395 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400396 return err
397 }
398 }
khenaidoo19d7b632018-10-30 10:49:50 -0400399 return nil
400}
401
402//flowDelete deletes a flow from the flow table of that logical device
403func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
404 log.Debug("flowDelete")
405 if mod == nil {
406 return nil
407 }
408 agent.lockLogicalDevice.Lock()
409 defer agent.lockLogicalDevice.Unlock()
410
411 var lDevice *voltha.LogicalDevice
412 var err error
413 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
414 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
415 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
416 }
417 flows := lDevice.Flows.Items
418
419 //build a list of what to keep vs what to delete
420 toKeep := make([]*ofp.OfpFlowStats, 0)
421 for _, f := range flows {
422 if !fu.FlowMatchesMod(f, mod) {
423 toKeep = append(toKeep, f)
424 }
425 }
426
427 //Update flows
428 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500429 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
430 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400431 return err
432 }
433 }
434
435 //TODO: send announcement on delete
436 return nil
437}
438
439//flowStatsDelete deletes a flow from the flow table of that logical device
440func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
441 log.Debug("flowStatsDelete")
442 if flow == nil {
443 return nil
444 }
445 agent.lockLogicalDevice.Lock()
446 defer agent.lockLogicalDevice.Unlock()
447
448 var lDevice *voltha.LogicalDevice
449 var err error
450 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
451 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
452 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
453 }
454 flows := lDevice.Flows.Items
455
456 //build a list of what to keep vs what to delete
457 toKeep := make([]*ofp.OfpFlowStats, 0)
458 for _, f := range flows {
459 if !fu.FlowMatch(f, flow) {
460 toKeep = append(toKeep, f)
461 }
462 }
463
464 //Update flows
465 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500466 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400467 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
468 return err
469 }
470 }
471 return nil
472}
473
474//flowDeleteStrict deletes a flow from the flow table of that logical device
475func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
476 log.Debug("flowDeleteStrict")
477 if mod == nil {
478 return nil
479 }
480 agent.lockLogicalDevice.Lock()
481 defer agent.lockLogicalDevice.Unlock()
482
483 var lDevice *voltha.LogicalDevice
484 var err error
485 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
486 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
487 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
488 }
489 flows := lDevice.Flows.Items
490 changed := false
491 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
492 idx := fu.FindFlows(flows, flow)
493 if idx >= 0 {
494 flows = append(flows[:idx], flows[idx+1:]...)
495 changed = true
496 } else {
497 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
498 }
499
500 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500501 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400502 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
503 return err
504 }
505 }
506
507 return nil
508}
509
510//flowModify modifies a flow from the flow table of that logical device
511func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
512 return errors.New("flowModify not implemented")
513}
514
515//flowModifyStrict deletes a flow from the flow table of that logical device
516func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
517 return errors.New("flowModifyStrict not implemented")
518}
519
520func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
521 log.Debug("groupAdd")
522 if groupMod == nil {
523 return nil
524 }
525 agent.lockLogicalDevice.Lock()
526 defer agent.lockLogicalDevice.Unlock()
527
528 var lDevice *voltha.LogicalDevice
529 var err error
530 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
531 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
532 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
533 }
534 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400535 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
536 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500537 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
538 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400539 return err
540 }
541 } else {
542 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
543 }
khenaidoo19d7b632018-10-30 10:49:50 -0400544 return nil
545}
546
547func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
548 log.Debug("groupDelete")
549 if groupMod == nil {
550 return nil
551 }
552 agent.lockLogicalDevice.Lock()
553 defer agent.lockLogicalDevice.Unlock()
554
555 var lDevice *voltha.LogicalDevice
556 var err error
557 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
558 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
559 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
560 }
561 groups := lDevice.FlowGroups.Items
562 flows := lDevice.Flows.Items
563 groupsChanged := false
564 flowsChanged := false
565 groupId := groupMod.GroupId
566 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
567 //TODO we must delete all flows that point to this group and
568 //signal controller as requested by flow's flag
569 groups = []*ofp.OfpGroupEntry{}
570 groupsChanged = true
571 } else {
572 if idx := fu.FindGroup(groups, groupId); idx == -1 {
573 return nil // Valid case
574 } else {
575 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
576 groups = append(groups[:idx], groups[idx+1:]...)
577 groupsChanged = true
578 }
579 }
khenaidoo43c82122018-11-22 18:38:28 -0500580 if groupsChanged {
581 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
582 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400583 return err
584 }
585 }
khenaidoo43c82122018-11-22 18:38:28 -0500586 if flowsChanged {
587 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
588 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
589 return err
590 }
591 }
592
khenaidoo19d7b632018-10-30 10:49:50 -0400593 return nil
594}
595
596func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
597 log.Debug("groupModify")
598 if groupMod == nil {
599 return nil
600 }
601 agent.lockLogicalDevice.Lock()
602 defer agent.lockLogicalDevice.Unlock()
603
604 var lDevice *voltha.LogicalDevice
605 var err error
606 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
607 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
608 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
609 }
610 groups := lDevice.FlowGroups.Items
611 groupsChanged := false
612 groupId := groupMod.GroupId
613 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500614 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400615 } else {
616 //replace existing group entry with new group definition
617 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
618 groups[idx] = groupEntry
619 groupsChanged = true
620 }
621 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500622 //lDevice.FlowGroups.Items = groups
623 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400624 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
625 return err
626 }
627 }
628 return nil
629}
630
631// deleteLogicalPort removes the logical port
632func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
633 agent.lockLogicalDevice.Lock()
634 defer agent.lockLogicalDevice.Unlock()
635
khenaidoo92e62c52018-10-03 14:02:54 -0400636 // Get the most up to date logical device
637 var logicaldevice *voltha.LogicalDevice
638 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400639 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400640 return nil
641 }
khenaidoo92e62c52018-10-03 14:02:54 -0400642 index := -1
643 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400644 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400645 index = i
646 break
647 }
648 }
649 if index >= 0 {
650 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
651 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
652 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
653 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
654 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
655 }
656 return nil
khenaidoob9203542018-09-17 22:56:37 -0400657}
658
khenaidoo19d7b632018-10-30 10:49:50 -0400659// enableLogicalPort enables the logical port
660func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
661 agent.lockLogicalDevice.Lock()
662 defer agent.lockLogicalDevice.Unlock()
663
664 // Get the most up to date logical device
665 var logicaldevice *voltha.LogicalDevice
666 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
667 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
668 return nil
669 }
670 index := -1
671 for i, logicalPort := range logicaldevice.Ports {
672 if logicalPort.Id == lPort.Id {
673 index = i
674 break
675 }
676 }
677 if index >= 0 {
678 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
679 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
680 }
681 //TODO: Trigger subsequent actions on the device
682 return nil
683}
684
685// disableLogicalPort disabled the logical port
686func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
687 agent.lockLogicalDevice.Lock()
688 defer agent.lockLogicalDevice.Unlock()
689
690 // Get the most up to date logical device
691 var logicaldevice *voltha.LogicalDevice
692 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
693 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
694 return nil
695 }
696 index := -1
697 for i, logicalPort := range logicaldevice.Ports {
698 if logicalPort.Id == lPort.Id {
699 index = i
700 break
701 }
702 }
703 if index >= 0 {
704 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
705 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
706 }
707 //TODO: Trigger subsequent actions on the device
708 return nil
709}
710
khenaidoo89b0e942018-10-21 21:11:33 -0400711func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
712 for _, pNo := range nniPortsNo {
713 if pNo == portNo {
714 return true
715 }
716 }
717 return false
718}
khenaidoo4d4802d2018-10-04 21:59:49 -0400719
khenaidoo89b0e942018-10-21 21:11:33 -0400720func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400721 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400722 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400723 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400724 if ingress == routeLink.Ingress && egress == routeLink.Egress {
725 return route
726 }
727 }
728 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
729 return nil
730}
731
khenaidoo19d7b632018-10-30 10:49:50 -0400732func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400733 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
734 // Get the updated logical device
khenaidoo79232702018-12-04 11:00:41 -0500735 var ld *ic.LogicalDevice
khenaidoo89b0e942018-10-21 21:11:33 -0400736 routes := make([]graph.RouteHop, 0)
737 var err error
738 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
739 return nil
740 }
741 nniLogicalPortsNo := make([]uint32, 0)
742 for _, logicalPort := range ld.Ports {
743 if logicalPort.RootPort {
744 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
745 }
746 }
747 if len(nniLogicalPortsNo) == 0 {
748 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
749 return nil
750 }
khenaidoo19d7b632018-10-30 10:49:50 -0400751 // Note: A port value of 0 is equivalent to a nil port
752
khenaidoo89b0e942018-10-21 21:11:33 -0400753 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400754 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400755 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400756 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400757 log.Debug("returning-half-route")
758 //This is a trap on the NNI Port
759 //Return a 'half' route to make the flow decomposer logic happy
760 for routeLink, route := range agent.deviceGraph.Routes {
761 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
762 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
763 routes = append(routes, route[1])
764 return routes
765 }
766 }
767 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
768 return nil
769 }
770 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400771 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400772 }
773 //If ingress port is not specified (nil), it may be a wildcarded
774 //route if egress port is OFPP_CONTROLLER or a nni logical port,
775 //in which case we need to create a half-route where only the egress
776 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400777 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400778 // We can use the 2nd hop of any upstream route, so just find the first upstream:
779 for routeLink, route := range agent.deviceGraph.Routes {
780 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
781 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
782 routes = append(routes, route[1])
783 return routes
784 }
785 }
786 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
787 return nil
788 }
789 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400790 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400791 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400792 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400793 routes = append(routes, route[0])
794 routes = append(routes, graph.RouteHop{})
795 return routes
796 }
797 }
798 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
799 return nil
800 }
801
802 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400803 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400804}
805
806// updateRoutes updates the device routes whenever there is a device or port changes relevant to this
807// logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred
808// instead of rebuilding the entire set of routes
809func (agent *LogicalDeviceAgent) updateRoutes() {
khenaidoo19d7b632018-10-30 10:49:50 -0400810 if ld, err := agent.GetLogicalDevice(); err == nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400811 agent.deviceGraph.ComputeRoutes(ld.Ports)
812 }
813}
814
815func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
816 return fu.NewFlowsAndGroups()
817}
818
819func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
820 fg := fu.NewFlowsAndGroups()
821 var device *voltha.Device
822 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400823 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400824 return fg
825 }
826 //set the upstream and downstream ports
827 upstreamPorts := make([]*voltha.Port, 0)
828 downstreamPorts := make([]*voltha.Port, 0)
829 for _, port := range device.Ports {
830 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
831 upstreamPorts = append(upstreamPorts, port)
832 } else if port.Type == voltha.Port_ETHERNET_UNI {
833 downstreamPorts = append(downstreamPorts, port)
834 }
835 }
836 //it is possible that the downstream ports are not created, but the flow_decomposition has already
837 //kicked in. In such scenarios, cut short the processing and return.
838 if len(downstreamPorts) == 0 {
839 return fg
840 }
841 // set up the default flows
842 var fa *fu.FlowArgs
843 fa = &fu.FlowArgs{
844 KV: fu.OfpFlowModArgs{"priority": 500},
845 MatchFields: []*ofp.OfpOxmOfbField{
846 fd.InPort(downstreamPorts[0].PortNo),
847 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
848 },
849 Actions: []*ofp.OfpAction{
850 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400851 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400852 },
853 }
854 fg.AddFlow(fd.MkFlowStat(fa))
855
856 fa = &fu.FlowArgs{
857 KV: fu.OfpFlowModArgs{"priority": 500},
858 MatchFields: []*ofp.OfpOxmOfbField{
859 fd.InPort(downstreamPorts[0].PortNo),
860 fd.VlanVid(0),
861 },
862 Actions: []*ofp.OfpAction{
863 fd.PushVlan(0x8100),
864 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
865 fd.Output(upstreamPorts[0].PortNo),
866 },
867 }
868 fg.AddFlow(fd.MkFlowStat(fa))
869
870 fa = &fu.FlowArgs{
871 KV: fu.OfpFlowModArgs{"priority": 500},
872 MatchFields: []*ofp.OfpOxmOfbField{
873 fd.InPort(upstreamPorts[0].PortNo),
874 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
875 },
876 Actions: []*ofp.OfpAction{
877 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
878 fd.Output(downstreamPorts[0].PortNo),
879 },
880 }
881 fg.AddFlow(fd.MkFlowStat(fa))
882
883 return fg
884}
885
886func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
887 rules := fu.NewDeviceRules()
888 var ld *voltha.LogicalDevice
889 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400890 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400891 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
892 return rules
893 }
894
895 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
khenaidooca301322019-01-09 23:06:32 -0500896 for deviceId := range deviceNodeIds {
khenaidoo89b0e942018-10-21 21:11:33 -0400897 if deviceId == ld.RootDeviceId {
898 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
899 } else {
900 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
901 }
902 }
903 return rules
904}
905
906func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
907 // Get latest
908 var lDevice *voltha.LogicalDevice
909 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400910 if lDevice, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400911 return fu.NewDeviceRules()
912 }
913 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo19d7b632018-10-30 10:49:50 -0400914 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
khenaidoo89b0e942018-10-21 21:11:33 -0400915 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
916 agent.DefaultFlowRules = agent.generateDefaultRules()
917 }
918 return agent.DefaultFlowRules
919}
920
921func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
922 lPorts := make([]uint32, 0)
923 var exclPort uint32
924 if len(excludePort) == 1 {
925 exclPort = excludePort[0]
926 }
khenaidoo19d7b632018-10-30 10:49:50 -0400927 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400928 for _, port := range lDevice.Ports {
929 if port.OfpPort.PortNo != exclPort {
930 lPorts = append(lPorts, port.OfpPort.PortNo)
931 }
932 }
933 }
934 return lPorts
935}
khenaidoo19d7b632018-10-30 10:49:50 -0400936
937func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
938 return agent.deviceGraph
939}
940
941//setupDeviceGraph creates the device graph if not done already
942func (agent *LogicalDeviceAgent) setupDeviceGraph() {
943 if agent.deviceGraph == nil {
944 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
945 agent.updateRoutes()
946 }
947}
948
949func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
950 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
951
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500952 var previousData *ofp.Flows
953 var latestData *ofp.Flows
khenaidoo19d7b632018-10-30 10:49:50 -0400954
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500955 var ok bool
956 if previousData, ok = args[0].(*ofp.Flows); !ok {
957 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
958 }
959 if latestData, ok = args[1].(*ofp.Flows); !ok {
960 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
961 }
khenaidoo19d7b632018-10-30 10:49:50 -0400962
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500963 if reflect.DeepEqual(previousData.Items, latestData.Items) {
964 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -0400965 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500966 }
967
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500968 var groups *ofp.FlowGroups
969 lDevice, _ := agent.getLogicalDeviceWithoutLock()
970 groups = lDevice.FlowGroups
971 log.Debugw("flowsinfo", log.Fields{"flows": latestData, "groups": groups})
972 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *latestData, *groups)
973 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
974
khenaidooca301322019-01-09 23:06:32 -0500975 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500976 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -0500977 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
978 log.Error("update-flows-failed", log.Fields{"deviceID":deviceId})
979 }
980 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
981 log.Error("update-groups-failed", log.Fields{"deviceID":deviceId})
982 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500983 }
khenaidoo19d7b632018-10-30 10:49:50 -0400984
khenaidoo19d7b632018-10-30 10:49:50 -0400985 return nil
986}
987
988func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
989 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
990
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500991 var previousData *ofp.FlowGroups
992 var latestData *ofp.FlowGroups
khenaidoo19d7b632018-10-30 10:49:50 -0400993
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500994 var ok bool
995 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
996 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
997 }
998 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
999 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1000 }
khenaidoo19d7b632018-10-30 10:49:50 -04001001
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001002 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1003 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -04001004 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001005 }
1006
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001007 var flows *ofp.Flows
1008 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1009 flows = lDevice.Flows
1010 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
1011 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
1012 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidooca301322019-01-09 23:06:32 -05001013 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001014 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -05001015 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
1016 log.Error("update-flows-failed", log.Fields{"deviceID":deviceId})
1017 }
1018 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
1019 log.Error("update-groups-failed", log.Fields{"deviceID":deviceId})
1020 }
khenaidoo19d7b632018-10-30 10:49:50 -04001021
khenaidooca301322019-01-09 23:06:32 -05001022 }
khenaidoo19d7b632018-10-30 10:49:50 -04001023 return nil
1024}
khenaidoofdbad6e2018-11-06 22:26:38 -05001025
khenaidoo43c82122018-11-22 18:38:28 -05001026func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001027 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1028 outPort := fd.GetPacketOutPort(packet)
1029 //frame := packet.GetData()
1030 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001031 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
1032 log.Error("packetout-failed", log.Fields{"logicalDeviceID":agent.rootDeviceId})
1033 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001034}
1035
khenaidoofdbad6e2018-11-06 22:26:38 -05001036func (agent *LogicalDeviceAgent) packetIn(port uint32, packet []byte) {
1037 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet})
khenaidooca301322019-01-09 23:06:32 -05001038 packetIn := fd.MkPacketIn(port, packet)
1039 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, packetIn)
1040 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001041}