blob: bda249fc595782bbad44b6fe4dc2a0a9c17e8b76 [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
khenaidoo297cd252019-02-07 22:10:23 -050069func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
70 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId, "loadFromdB": loadFromdB})
71 var ld *voltha.LogicalDevice
72 if !loadFromdB {
73 //Build the logical device based on information retrieved from the device adapter
74 var switchCap *ic.SwitchCapability
75 var err error
76 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
khenaidoob9203542018-09-17 22:56:37 -040077 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
78 return err
79 }
khenaidoo297cd252019-02-07 22:10:23 -050080
81 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
82
83 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
84 var datapathID uint64
85 if datapathID, err = CreateDataPathId(agent.logicalDeviceId); err != nil {
86 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
87 return err
88 }
89 ld.DatapathId = datapathID
90 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
91 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
92 ld.Flows = &ofp.Flows{Items: nil}
93 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
94
95 //Add logical ports to the logical device based on the number of NNI ports discovered
96 //First get the default port capability - TODO: each NNI port may have different capabilities,
97 //hence. may need to extract the port by the NNI port id defined by the adapter during device
98 //creation
99 var nniPorts *voltha.Ports
100 if nniPorts, err = agent.deviceMgr.getPorts(ctx, agent.rootDeviceId, voltha.Port_ETHERNET_NNI); err != nil {
101 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
102 }
103 var portCap *ic.PortCapability
104 for _, port := range nniPorts.Items {
105 log.Infow("!!!!!!!NNI PORTS", log.Fields{"NNI": port})
106 if portCap, err = agent.deviceMgr.getPortCapability(ctx, agent.rootDeviceId, port.PortNo); err != nil {
107 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
108 return err
109 }
110 portCap.Port.RootPort = true
111 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
112 lp.DeviceId = agent.rootDeviceId
113 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
114 lp.OfpPort.PortNo = port.PortNo
115 lp.OfpPort.Name = lp.Id
116 lp.DevicePortNo = port.PortNo
117 ld.Ports = append(ld.Ports, lp)
118 }
119 agent.lockLogicalDevice.Lock()
120 //defer agent.lockLogicalDevice.Unlock()
121 // Save the logical device
122 if added := agent.clusterDataProxy.AddWithID("/logical_devices", ld.Id, ld, ""); added == nil {
123 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
124 } else {
125 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
126 }
127 agent.lockLogicalDevice.Unlock()
128 } else {
129 // load from dB - the logical may not exist at this time. On error, just return and the calling function
130 // will destroy this agent.
131 var err error
132 if ld, err = agent.GetLogicalDevice(); err != nil {
133 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
134 return err
135 }
khenaidoob9203542018-09-17 22:56:37 -0400136 }
khenaidoo92e62c52018-10-03 14:02:54 -0400137 agent.lockLogicalDevice.Lock()
khenaidoo43c82122018-11-22 18:38:28 -0500138 agent.flowProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400139 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
140 false)
khenaidoo43c82122018-11-22 18:38:28 -0500141 agent.groupProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400142 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
143 false)
144
145 agent.flowProxy.RegisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
khenaidoo43c82122018-11-22 18:38:28 -0500146 agent.groupProxy.RegisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
khenaidoo19d7b632018-10-30 10:49:50 -0400147
khenaidoobcf205b2019-01-25 22:21:14 -0500148 agent.lockLogicalDevice.Unlock()
149
150 // Setup the device graph
151 go agent.setupDeviceGraph()
152
khenaidoob9203542018-09-17 22:56:37 -0400153 return nil
154}
155
khenaidoo4d4802d2018-10-04 21:59:49 -0400156// stop stops the logical devuce agent. This removes the logical device from the data model.
157func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
158 log.Info("stopping-logical_device-agent")
159 agent.lockLogicalDevice.Lock()
160 defer agent.lockLogicalDevice.Unlock()
161 //Remove the logical device from the model
162 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
163 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
164 } else {
165 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
166 }
167 agent.exitChannel <- 1
168 log.Info("logical_device-agent-stopped")
169}
170
khenaidoo19d7b632018-10-30 10:49:50 -0400171// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
172func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
173 log.Debug("GetLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -0400174 agent.lockLogicalDevice.Lock()
175 defer agent.lockLogicalDevice.Unlock()
176 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
177 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500178 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400179 }
180 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
181}
182
khenaidoo19d7b632018-10-30 10:49:50 -0400183func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
184 log.Debug("!!!!!ListLogicalDevicePorts")
185 agent.lockLogicalDevice.Lock()
186 defer agent.lockLogicalDevice.Unlock()
187 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
188 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
189 lPorts := make([]*voltha.LogicalPort, 0)
190 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500191 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400192 }
193 return &voltha.LogicalPorts{Items: lPorts}, nil
194 }
195 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
196}
197
198// listFlows locks the logical device model and then retrieves the latest flow information
199func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
200 log.Debug("listFlows")
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.Flows.Items
206 }
207 return nil
208}
209
210// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
211func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
212 log.Debug("listFlowGroups")
213 agent.lockLogicalDevice.Lock()
214 defer agent.lockLogicalDevice.Unlock()
215 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
216 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
217 return lDevice.FlowGroups.Items
218 }
219 return nil
220}
221
khenaidoo43c82122018-11-22 18:38:28 -0500222//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
223func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500224 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500225 if afterUpdate == nil {
226 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
227 }
khenaidoo43c82122018-11-22 18:38:28 -0500228 return nil
229}
230
231//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
232func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500233 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500234 if afterUpdate == nil {
235 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
236 }
khenaidoo43c82122018-11-22 18:38:28 -0500237 return nil
238}
239
khenaidoo4d4802d2018-10-04 21:59:49 -0400240// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
241// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400242func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
243 log.Debug("getLogicalDeviceWithoutLock")
244 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
245 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500246 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400247 }
248 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
249}
250
khenaidoo4d4802d2018-10-04 21:59:49 -0400251// addUNILogicalPort creates a UNI port on the logical device that represents a child device
khenaidoo19d7b632018-10-30 10:49:50 -0400252func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400253 log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400254 // Build the logical device based on information retrieved from the device adapter
khenaidoo79232702018-12-04 11:00:41 -0500255 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -0400256 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400257
258 //Get UNI port number
259 var uniPort uint32
260 for _, port := range childDevice.Ports {
261 if port.Type == voltha.Port_ETHERNET_UNI {
262 uniPort = port.PortNo
263 }
264 }
265 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, uniPort); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400266 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
267 return err
268 }
khenaidoo92e62c52018-10-03 14:02:54 -0400269 agent.lockLogicalDevice.Lock()
270 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400271 // Get stored logical device
khenaidoo92e62c52018-10-03 14:02:54 -0400272 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400273 return status.Error(codes.NotFound, agent.logicalDeviceId)
274 } else {
khenaidoobcf205b2019-01-25 22:21:14 -0500275 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
khenaidoo19d7b632018-10-30 10:49:50 -0400276 portCap.Port.RootPort = false
277 //TODO: For now use the channel id assigned by the OLT as logical port number
278 lPortNo := childDevice.ProxyAddress.ChannelId
279 portCap.Port.Id = fmt.Sprintf("uni-%d", lPortNo)
280 portCap.Port.OfpPort.PortNo = lPortNo
281 portCap.Port.OfpPort.Name = portCap.Port.Id
282 portCap.Port.DeviceId = childDevice.Id
283 portCap.Port.DevicePortNo = uniPort
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500284 portCap.Port.DeviceId = childDevice.Id
khenaidoobcf205b2019-01-25 22:21:14 -0500285
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500286 ldevice.Ports = append(ldevice.Ports, portCap.Port)
287 return agent.updateLogicalDeviceWithoutLock(ldevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400288 }
289}
290
291//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
292func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500293 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400294 if afterUpdate == nil {
295 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
296 }
297 return nil
298}
299
khenaidoo19d7b632018-10-30 10:49:50 -0400300//updateFlowTable updates the flow table of that logical device
301func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
302 log.Debug("updateFlowTable")
303 if flow == nil {
304 return nil
305 }
306 switch flow.GetCommand() {
307 case ofp.OfpFlowModCommand_OFPFC_ADD:
308 return agent.flowAdd(flow)
309 case ofp.OfpFlowModCommand_OFPFC_DELETE:
310 return agent.flowDelete(flow)
311 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
312 return agent.flowDeleteStrict(flow)
313 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
314 return agent.flowModify(flow)
315 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
316 return agent.flowModifyStrict(flow)
317 }
318 return status.Errorf(codes.Internal,
319 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
320}
321
322//updateGroupTable updates the group table of that logical device
323func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
324 log.Debug("updateGroupTable")
325 if groupMod == nil {
326 return nil
327 }
328 switch groupMod.GetCommand() {
329 case ofp.OfpGroupModCommand_OFPGC_ADD:
330 return agent.groupAdd(groupMod)
331 case ofp.OfpGroupModCommand_OFPGC_DELETE:
332 return agent.groupDelete(groupMod)
333 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
334 return agent.groupModify(groupMod)
335 }
336 return status.Errorf(codes.Internal,
337 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
338}
339
khenaidoo19d7b632018-10-30 10:49:50 -0400340//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
341//must only be called by a function that is holding the lock on the logical device
342func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
khenaidoo43c82122018-11-22 18:38:28 -0500343 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
344 copy(groupsCloned, groups)
345 if afterUpdate := agent.groupProxy.Update("/", groupsCloned, true, ""); afterUpdate == nil {
346 return errors.New(fmt.Sprintf("update-flow-group-failed:%s", agent.logicalDeviceId))
khenaidoo19d7b632018-10-30 10:49:50 -0400347 }
khenaidoo43c82122018-11-22 18:38:28 -0500348 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400349}
350
351//flowAdd adds a flow to the flow table of that logical device
352func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
353 log.Debug("flowAdd")
354 if mod == nil {
355 return nil
356 }
khenaidoo92e62c52018-10-03 14:02:54 -0400357 agent.lockLogicalDevice.Lock()
358 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400359
360 var lDevice *voltha.LogicalDevice
361 var err error
362 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
363 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
364 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
365 }
366
367 var flows []*ofp.OfpFlowStats
368 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
369 flows = lDevice.Flows.Items
370 }
371
khenaidoo43c82122018-11-22 18:38:28 -0500372 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400373 changed := false
374 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
375 if checkOverlap {
376 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
377 // TODO: should this error be notified other than being logged?
378 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
379 } else {
380 // Add flow
381 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
382 flows = append(flows, flow)
383 changed = true
384 }
385 } else {
386 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
387 idx := fu.FindFlows(flows, flow)
388 if idx >= 0 {
389 oldFlow := flows[idx]
390 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
391 flow.ByteCount = oldFlow.ByteCount
392 flow.PacketCount = oldFlow.PacketCount
393 }
394 flows[idx] = flow
395 } else {
396 flows = append(flows, flow)
397 }
398 changed = true
399 }
400 if changed {
401 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500402 flowsToUpdate := &ofp.Flows{}
403 if lDevice.Flows != nil {
404 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400405 }
khenaidoo43c82122018-11-22 18:38:28 -0500406 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
407 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400408 return err
409 }
410 }
khenaidoo19d7b632018-10-30 10:49:50 -0400411 return nil
412}
413
414//flowDelete deletes a flow from the flow table of that logical device
415func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
416 log.Debug("flowDelete")
417 if mod == nil {
418 return nil
419 }
420 agent.lockLogicalDevice.Lock()
421 defer agent.lockLogicalDevice.Unlock()
422
423 var lDevice *voltha.LogicalDevice
424 var err error
425 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
426 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
427 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
428 }
429 flows := lDevice.Flows.Items
430
431 //build a list of what to keep vs what to delete
432 toKeep := make([]*ofp.OfpFlowStats, 0)
433 for _, f := range flows {
434 if !fu.FlowMatchesMod(f, mod) {
435 toKeep = append(toKeep, f)
436 }
437 }
438
439 //Update flows
440 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500441 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
442 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400443 return err
444 }
445 }
446
447 //TODO: send announcement on delete
448 return nil
449}
450
451//flowStatsDelete deletes a flow from the flow table of that logical device
452func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
453 log.Debug("flowStatsDelete")
454 if flow == nil {
455 return nil
456 }
457 agent.lockLogicalDevice.Lock()
458 defer agent.lockLogicalDevice.Unlock()
459
460 var lDevice *voltha.LogicalDevice
461 var err error
462 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
463 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
464 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
465 }
466 flows := lDevice.Flows.Items
467
468 //build a list of what to keep vs what to delete
469 toKeep := make([]*ofp.OfpFlowStats, 0)
470 for _, f := range flows {
471 if !fu.FlowMatch(f, flow) {
472 toKeep = append(toKeep, f)
473 }
474 }
475
476 //Update flows
477 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500478 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400479 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
480 return err
481 }
482 }
483 return nil
484}
485
486//flowDeleteStrict deletes a flow from the flow table of that logical device
487func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
488 log.Debug("flowDeleteStrict")
489 if mod == nil {
490 return nil
491 }
492 agent.lockLogicalDevice.Lock()
493 defer agent.lockLogicalDevice.Unlock()
494
495 var lDevice *voltha.LogicalDevice
496 var err error
497 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
498 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
499 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
500 }
501 flows := lDevice.Flows.Items
502 changed := false
503 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
504 idx := fu.FindFlows(flows, flow)
505 if idx >= 0 {
506 flows = append(flows[:idx], flows[idx+1:]...)
507 changed = true
508 } else {
509 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
510 }
511
512 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500513 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400514 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
515 return err
516 }
517 }
518
519 return nil
520}
521
522//flowModify modifies a flow from the flow table of that logical device
523func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
524 return errors.New("flowModify not implemented")
525}
526
527//flowModifyStrict deletes a flow from the flow table of that logical device
528func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
529 return errors.New("flowModifyStrict not implemented")
530}
531
532func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
533 log.Debug("groupAdd")
534 if groupMod == nil {
535 return nil
536 }
537 agent.lockLogicalDevice.Lock()
538 defer agent.lockLogicalDevice.Unlock()
539
540 var lDevice *voltha.LogicalDevice
541 var err error
542 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
543 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
544 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
545 }
546 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400547 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
548 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500549 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
550 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400551 return err
552 }
553 } else {
554 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
555 }
khenaidoo19d7b632018-10-30 10:49:50 -0400556 return nil
557}
558
559func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
560 log.Debug("groupDelete")
561 if groupMod == nil {
562 return nil
563 }
564 agent.lockLogicalDevice.Lock()
565 defer agent.lockLogicalDevice.Unlock()
566
567 var lDevice *voltha.LogicalDevice
568 var err error
569 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
570 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
571 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
572 }
573 groups := lDevice.FlowGroups.Items
574 flows := lDevice.Flows.Items
575 groupsChanged := false
576 flowsChanged := false
577 groupId := groupMod.GroupId
578 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
579 //TODO we must delete all flows that point to this group and
580 //signal controller as requested by flow's flag
581 groups = []*ofp.OfpGroupEntry{}
582 groupsChanged = true
583 } else {
584 if idx := fu.FindGroup(groups, groupId); idx == -1 {
585 return nil // Valid case
586 } else {
587 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
588 groups = append(groups[:idx], groups[idx+1:]...)
589 groupsChanged = true
590 }
591 }
khenaidoo43c82122018-11-22 18:38:28 -0500592 if groupsChanged {
593 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
594 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400595 return err
596 }
597 }
khenaidoo43c82122018-11-22 18:38:28 -0500598 if flowsChanged {
599 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
600 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
601 return err
602 }
603 }
604
khenaidoo19d7b632018-10-30 10:49:50 -0400605 return nil
606}
607
608func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
609 log.Debug("groupModify")
610 if groupMod == nil {
611 return nil
612 }
613 agent.lockLogicalDevice.Lock()
614 defer agent.lockLogicalDevice.Unlock()
615
616 var lDevice *voltha.LogicalDevice
617 var err error
618 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
619 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
620 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
621 }
622 groups := lDevice.FlowGroups.Items
623 groupsChanged := false
624 groupId := groupMod.GroupId
625 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500626 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400627 } else {
628 //replace existing group entry with new group definition
629 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
630 groups[idx] = groupEntry
631 groupsChanged = true
632 }
633 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500634 //lDevice.FlowGroups.Items = groups
635 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400636 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
637 return err
638 }
639 }
640 return nil
641}
642
643// deleteLogicalPort removes the logical port
644func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
645 agent.lockLogicalDevice.Lock()
646 defer agent.lockLogicalDevice.Unlock()
647
khenaidoo92e62c52018-10-03 14:02:54 -0400648 // Get the most up to date logical device
649 var logicaldevice *voltha.LogicalDevice
650 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400651 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400652 return nil
653 }
khenaidoo92e62c52018-10-03 14:02:54 -0400654 index := -1
655 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400656 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400657 index = i
658 break
659 }
660 }
661 if index >= 0 {
662 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
663 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
664 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
665 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
666 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
667 }
668 return nil
khenaidoob9203542018-09-17 22:56:37 -0400669}
670
khenaidoo19d7b632018-10-30 10:49:50 -0400671// enableLogicalPort enables the logical port
672func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
673 agent.lockLogicalDevice.Lock()
674 defer agent.lockLogicalDevice.Unlock()
675
676 // Get the most up to date logical device
677 var logicaldevice *voltha.LogicalDevice
678 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
679 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
680 return nil
681 }
682 index := -1
683 for i, logicalPort := range logicaldevice.Ports {
684 if logicalPort.Id == lPort.Id {
685 index = i
686 break
687 }
688 }
689 if index >= 0 {
690 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
691 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
692 }
693 //TODO: Trigger subsequent actions on the device
694 return nil
695}
696
697// disableLogicalPort disabled the logical port
698func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
699 agent.lockLogicalDevice.Lock()
700 defer agent.lockLogicalDevice.Unlock()
701
702 // Get the most up to date logical device
703 var logicaldevice *voltha.LogicalDevice
704 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
705 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
706 return nil
707 }
708 index := -1
709 for i, logicalPort := range logicaldevice.Ports {
710 if logicalPort.Id == lPort.Id {
711 index = i
712 break
713 }
714 }
715 if index >= 0 {
716 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
717 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
718 }
719 //TODO: Trigger subsequent actions on the device
720 return nil
721}
722
khenaidoo89b0e942018-10-21 21:11:33 -0400723func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
724 for _, pNo := range nniPortsNo {
725 if pNo == portNo {
726 return true
727 }
728 }
729 return false
730}
khenaidoo4d4802d2018-10-04 21:59:49 -0400731
khenaidoo89b0e942018-10-21 21:11:33 -0400732func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400733 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400734 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400735 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400736 if ingress == routeLink.Ingress && egress == routeLink.Egress {
737 return route
738 }
739 }
740 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
741 return nil
742}
743
khenaidoo19d7b632018-10-30 10:49:50 -0400744func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400745 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
746 // Get the updated logical device
khenaidoo79232702018-12-04 11:00:41 -0500747 var ld *ic.LogicalDevice
khenaidoo89b0e942018-10-21 21:11:33 -0400748 routes := make([]graph.RouteHop, 0)
749 var err error
750 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
751 return nil
752 }
753 nniLogicalPortsNo := make([]uint32, 0)
754 for _, logicalPort := range ld.Ports {
755 if logicalPort.RootPort {
756 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
757 }
758 }
759 if len(nniLogicalPortsNo) == 0 {
760 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
761 return nil
762 }
khenaidoo19d7b632018-10-30 10:49:50 -0400763 // Note: A port value of 0 is equivalent to a nil port
764
khenaidoo89b0e942018-10-21 21:11:33 -0400765 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400766 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400767 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400768 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400769 log.Debug("returning-half-route")
770 //This is a trap on the NNI Port
771 //Return a 'half' route to make the flow decomposer logic happy
772 for routeLink, route := range agent.deviceGraph.Routes {
773 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
774 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
775 routes = append(routes, route[1])
776 return routes
777 }
778 }
779 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
780 return nil
781 }
782 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400783 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400784 }
785 //If ingress port is not specified (nil), it may be a wildcarded
786 //route if egress port is OFPP_CONTROLLER or a nni logical port,
787 //in which case we need to create a half-route where only the egress
788 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400789 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400790 // We can use the 2nd hop of any upstream route, so just find the first upstream:
791 for routeLink, route := range agent.deviceGraph.Routes {
792 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
793 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
794 routes = append(routes, route[1])
795 return routes
796 }
797 }
798 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
799 return nil
800 }
801 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400802 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400803 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400804 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400805 routes = append(routes, route[0])
806 routes = append(routes, graph.RouteHop{})
807 return routes
808 }
809 }
810 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
811 return nil
812 }
813
814 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400815 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400816}
817
818// updateRoutes updates the device routes whenever there is a device or port changes relevant to this
819// logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred
820// instead of rebuilding the entire set of routes
821func (agent *LogicalDeviceAgent) updateRoutes() {
khenaidoo19d7b632018-10-30 10:49:50 -0400822 if ld, err := agent.GetLogicalDevice(); err == nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400823 agent.deviceGraph.ComputeRoutes(ld.Ports)
824 }
825}
826
827func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
828 return fu.NewFlowsAndGroups()
829}
830
831func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
832 fg := fu.NewFlowsAndGroups()
833 var device *voltha.Device
834 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400835 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400836 return fg
837 }
838 //set the upstream and downstream ports
839 upstreamPorts := make([]*voltha.Port, 0)
840 downstreamPorts := make([]*voltha.Port, 0)
841 for _, port := range device.Ports {
842 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
843 upstreamPorts = append(upstreamPorts, port)
844 } else if port.Type == voltha.Port_ETHERNET_UNI {
845 downstreamPorts = append(downstreamPorts, port)
846 }
847 }
848 //it is possible that the downstream ports are not created, but the flow_decomposition has already
849 //kicked in. In such scenarios, cut short the processing and return.
850 if len(downstreamPorts) == 0 {
851 return fg
852 }
853 // set up the default flows
854 var fa *fu.FlowArgs
855 fa = &fu.FlowArgs{
856 KV: fu.OfpFlowModArgs{"priority": 500},
857 MatchFields: []*ofp.OfpOxmOfbField{
858 fd.InPort(downstreamPorts[0].PortNo),
859 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
860 },
861 Actions: []*ofp.OfpAction{
862 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400863 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400864 },
865 }
866 fg.AddFlow(fd.MkFlowStat(fa))
867
868 fa = &fu.FlowArgs{
869 KV: fu.OfpFlowModArgs{"priority": 500},
870 MatchFields: []*ofp.OfpOxmOfbField{
871 fd.InPort(downstreamPorts[0].PortNo),
872 fd.VlanVid(0),
873 },
874 Actions: []*ofp.OfpAction{
875 fd.PushVlan(0x8100),
876 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
877 fd.Output(upstreamPorts[0].PortNo),
878 },
879 }
880 fg.AddFlow(fd.MkFlowStat(fa))
881
882 fa = &fu.FlowArgs{
883 KV: fu.OfpFlowModArgs{"priority": 500},
884 MatchFields: []*ofp.OfpOxmOfbField{
885 fd.InPort(upstreamPorts[0].PortNo),
886 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
887 },
888 Actions: []*ofp.OfpAction{
889 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
890 fd.Output(downstreamPorts[0].PortNo),
891 },
892 }
893 fg.AddFlow(fd.MkFlowStat(fa))
894
895 return fg
896}
897
898func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
899 rules := fu.NewDeviceRules()
900 var ld *voltha.LogicalDevice
901 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400902 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400903 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
904 return rules
905 }
906
907 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
khenaidooca301322019-01-09 23:06:32 -0500908 for deviceId := range deviceNodeIds {
khenaidoo89b0e942018-10-21 21:11:33 -0400909 if deviceId == ld.RootDeviceId {
910 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
911 } else {
912 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
913 }
914 }
915 return rules
916}
917
918func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
919 // Get latest
920 var lDevice *voltha.LogicalDevice
921 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400922 if lDevice, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400923 return fu.NewDeviceRules()
924 }
925 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo19d7b632018-10-30 10:49:50 -0400926 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
khenaidoo89b0e942018-10-21 21:11:33 -0400927 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
928 agent.DefaultFlowRules = agent.generateDefaultRules()
929 }
930 return agent.DefaultFlowRules
931}
932
933func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
934 lPorts := make([]uint32, 0)
935 var exclPort uint32
936 if len(excludePort) == 1 {
937 exclPort = excludePort[0]
938 }
khenaidoo19d7b632018-10-30 10:49:50 -0400939 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400940 for _, port := range lDevice.Ports {
941 if port.OfpPort.PortNo != exclPort {
942 lPorts = append(lPorts, port.OfpPort.PortNo)
943 }
944 }
945 }
946 return lPorts
947}
khenaidoo19d7b632018-10-30 10:49:50 -0400948
949func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
950 return agent.deviceGraph
951}
952
953//setupDeviceGraph creates the device graph if not done already
954func (agent *LogicalDeviceAgent) setupDeviceGraph() {
955 if agent.deviceGraph == nil {
956 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
957 agent.updateRoutes()
958 }
959}
960
961func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
962 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
963
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500964 var previousData *ofp.Flows
965 var latestData *ofp.Flows
khenaidoo19d7b632018-10-30 10:49:50 -0400966
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500967 var ok bool
968 if previousData, ok = args[0].(*ofp.Flows); !ok {
969 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
970 }
971 if latestData, ok = args[1].(*ofp.Flows); !ok {
972 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
973 }
khenaidoo19d7b632018-10-30 10:49:50 -0400974
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500975 if reflect.DeepEqual(previousData.Items, latestData.Items) {
976 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -0400977 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500978 }
979
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500980 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
khenaidooca301322019-01-09 23:06:32 -0500987 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500988 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -0500989 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
990 log.Error("update-flows-failed", log.Fields{"deviceID":deviceId})
991 }
992 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
993 log.Error("update-groups-failed", log.Fields{"deviceID":deviceId})
994 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500995 }
khenaidoo19d7b632018-10-30 10:49:50 -0400996
khenaidoo19d7b632018-10-30 10:49:50 -0400997 return nil
998}
999
1000func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
1001 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
1002
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001003 var previousData *ofp.FlowGroups
1004 var latestData *ofp.FlowGroups
khenaidoo19d7b632018-10-30 10:49:50 -04001005
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001006 var ok bool
1007 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
1008 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1009 }
1010 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
1011 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1012 }
khenaidoo19d7b632018-10-30 10:49:50 -04001013
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001014 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1015 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -04001016 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001017 }
1018
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001019 var flows *ofp.Flows
1020 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1021 flows = lDevice.Flows
1022 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
1023 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
1024 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidooca301322019-01-09 23:06:32 -05001025 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001026 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -05001027 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
1028 log.Error("update-flows-failed", log.Fields{"deviceID":deviceId})
1029 }
1030 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
1031 log.Error("update-groups-failed", log.Fields{"deviceID":deviceId})
1032 }
khenaidoo19d7b632018-10-30 10:49:50 -04001033
khenaidooca301322019-01-09 23:06:32 -05001034 }
khenaidoo19d7b632018-10-30 10:49:50 -04001035 return nil
1036}
khenaidoofdbad6e2018-11-06 22:26:38 -05001037
khenaidoo43c82122018-11-22 18:38:28 -05001038func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001039 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1040 outPort := fd.GetPacketOutPort(packet)
1041 //frame := packet.GetData()
1042 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001043 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
1044 log.Error("packetout-failed", log.Fields{"logicalDeviceID":agent.rootDeviceId})
1045 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001046}
1047
khenaidoo297cd252019-02-07 22:10:23 -05001048func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1049 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidooca301322019-01-09 23:06:32 -05001050 packetIn := fd.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001051 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001052 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001053}