blob: ea94788e26992490cf22b09de3095ff19a47da56 [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 }
78 ld := &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
khenaidoo89b0e942018-10-21 21:11:33 -040079 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
80 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo19d7b632018-10-30 10:49:50 -040081 ld.Flows = &ofp.Flows{Items: nil}
82 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoob9203542018-09-17 22:56:37 -040083
84 //Add logical ports to the logical device based on the number of NNI ports discovered
85 //First get the default port capability - TODO: each NNI port may have different capabilities,
86 //hence. may need to extract the port by the NNI port id defined by the adapter during device
87 //creation
88 var nniPorts *voltha.Ports
khenaidoo92e62c52018-10-03 14:02:54 -040089 if nniPorts, err = agent.deviceMgr.getPorts(ctx, agent.rootDeviceId, voltha.Port_ETHERNET_NNI); err != nil {
khenaidoob9203542018-09-17 22:56:37 -040090 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
91 }
khenaidoo79232702018-12-04 11:00:41 -050092 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -040093 for _, port := range nniPorts.Items {
khenaidoo19d7b632018-10-30 10:49:50 -040094 log.Infow("!!!!!!!NNI PORTS", log.Fields{"NNI": port})
khenaidoob9203542018-09-17 22:56:37 -040095 if portCap, err = agent.deviceMgr.getPortCapability(ctx, agent.rootDeviceId, port.PortNo); err != nil {
96 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
97 return err
98 }
khenaidoo19d7b632018-10-30 10:49:50 -040099 portCap.Port.RootPort = true
khenaidoob9203542018-09-17 22:56:37 -0400100 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo92e62c52018-10-03 14:02:54 -0400101 lp.DeviceId = agent.rootDeviceId
khenaidoo19d7b632018-10-30 10:49:50 -0400102 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
103 lp.OfpPort.PortNo = port.PortNo
104 lp.OfpPort.Name = portCap.Port.Id
105 lp.DevicePortNo = port.PortNo
khenaidoob9203542018-09-17 22:56:37 -0400106 ld.Ports = append(ld.Ports, lp)
107 }
khenaidoo92e62c52018-10-03 14:02:54 -0400108 agent.lockLogicalDevice.Lock()
109 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400110 // Save the logical device
khenaidoo43c82122018-11-22 18:38:28 -0500111 if added := agent.clusterDataProxy.AddWithID("/logical_devices", ld.Id, ld, ""); added == nil {
khenaidoob9203542018-09-17 22:56:37 -0400112 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
113 } else {
114 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
115 }
116
khenaidoo43c82122018-11-22 18:38:28 -0500117 agent.flowProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400118 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
119 false)
khenaidoo43c82122018-11-22 18:38:28 -0500120 agent.groupProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400121 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
122 false)
123
124 agent.flowProxy.RegisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
khenaidoo43c82122018-11-22 18:38:28 -0500125 agent.groupProxy.RegisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
khenaidoo19d7b632018-10-30 10:49:50 -0400126
khenaidoob9203542018-09-17 22:56:37 -0400127 return nil
128}
129
khenaidoo4d4802d2018-10-04 21:59:49 -0400130// stop stops the logical devuce agent. This removes the logical device from the data model.
131func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
132 log.Info("stopping-logical_device-agent")
133 agent.lockLogicalDevice.Lock()
134 defer agent.lockLogicalDevice.Unlock()
135 //Remove the logical device from the model
136 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
137 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
138 } else {
139 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
140 }
141 agent.exitChannel <- 1
142 log.Info("logical_device-agent-stopped")
143}
144
khenaidoo19d7b632018-10-30 10:49:50 -0400145// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
146func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
147 log.Debug("GetLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -0400148 agent.lockLogicalDevice.Lock()
149 defer agent.lockLogicalDevice.Unlock()
150 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
151 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500152 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400153 }
154 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
155}
156
khenaidoo19d7b632018-10-30 10:49:50 -0400157func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
158 log.Debug("!!!!!ListLogicalDevicePorts")
159 agent.lockLogicalDevice.Lock()
160 defer agent.lockLogicalDevice.Unlock()
161 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
162 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
163 lPorts := make([]*voltha.LogicalPort, 0)
164 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500165 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400166 }
167 return &voltha.LogicalPorts{Items: lPorts}, nil
168 }
169 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
170}
171
172// listFlows locks the logical device model and then retrieves the latest flow information
173func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
174 log.Debug("listFlows")
175 agent.lockLogicalDevice.Lock()
176 defer agent.lockLogicalDevice.Unlock()
177 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
178 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
179 return lDevice.Flows.Items
180 }
181 return nil
182}
183
184// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
185func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
186 log.Debug("listFlowGroups")
187 agent.lockLogicalDevice.Lock()
188 defer agent.lockLogicalDevice.Unlock()
189 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
190 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
191 return lDevice.FlowGroups.Items
192 }
193 return nil
194}
195
khenaidoo43c82122018-11-22 18:38:28 -0500196//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
197func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500198 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500199 if afterUpdate == nil {
200 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
201 }
khenaidoo43c82122018-11-22 18:38:28 -0500202 return nil
203}
204
205//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
206func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500207 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500208 if afterUpdate == nil {
209 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
210 }
khenaidoo43c82122018-11-22 18:38:28 -0500211 return nil
212}
213
khenaidoo4d4802d2018-10-04 21:59:49 -0400214// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
215// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400216func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
217 log.Debug("getLogicalDeviceWithoutLock")
218 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 1, false, "")
219 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500220 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400221 }
222 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
223}
224
khenaidoo4d4802d2018-10-04 21:59:49 -0400225// addUNILogicalPort creates a UNI port on the logical device that represents a child device
khenaidoo19d7b632018-10-30 10:49:50 -0400226func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400227 log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400228 // Build the logical device based on information retrieved from the device adapter
khenaidoo79232702018-12-04 11:00:41 -0500229 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -0400230 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400231
232 //Get UNI port number
233 var uniPort uint32
234 for _, port := range childDevice.Ports {
235 if port.Type == voltha.Port_ETHERNET_UNI {
236 uniPort = port.PortNo
237 }
238 }
239 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, uniPort); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400240 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
241 return err
242 }
khenaidoo92e62c52018-10-03 14:02:54 -0400243 agent.lockLogicalDevice.Lock()
244 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400245 // Get stored logical device
khenaidoo92e62c52018-10-03 14:02:54 -0400246 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400247 return status.Error(codes.NotFound, agent.logicalDeviceId)
248 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400249 log.Infow("!!!!!!!!!!!ADDING-UNI", log.Fields{"deviceId": childDevice.Id})
khenaidoo19d7b632018-10-30 10:49:50 -0400250 portCap.Port.RootPort = false
251 //TODO: For now use the channel id assigned by the OLT as logical port number
252 lPortNo := childDevice.ProxyAddress.ChannelId
253 portCap.Port.Id = fmt.Sprintf("uni-%d", lPortNo)
254 portCap.Port.OfpPort.PortNo = lPortNo
255 portCap.Port.OfpPort.Name = portCap.Port.Id
256 portCap.Port.DeviceId = childDevice.Id
257 portCap.Port.DevicePortNo = uniPort
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500258 portCap.Port.DeviceId = childDevice.Id
259 ldevice.Ports = append(ldevice.Ports, portCap.Port)
260 return agent.updateLogicalDeviceWithoutLock(ldevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400261 }
262}
263
264//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
265func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500266 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400267 if afterUpdate == nil {
268 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
269 }
270 return nil
271}
272
khenaidoo19d7b632018-10-30 10:49:50 -0400273//updateFlowTable updates the flow table of that logical device
274func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
275 log.Debug("updateFlowTable")
276 if flow == nil {
277 return nil
278 }
279 switch flow.GetCommand() {
280 case ofp.OfpFlowModCommand_OFPFC_ADD:
281 return agent.flowAdd(flow)
282 case ofp.OfpFlowModCommand_OFPFC_DELETE:
283 return agent.flowDelete(flow)
284 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
285 return agent.flowDeleteStrict(flow)
286 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
287 return agent.flowModify(flow)
288 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
289 return agent.flowModifyStrict(flow)
290 }
291 return status.Errorf(codes.Internal,
292 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
293}
294
295//updateGroupTable updates the group table of that logical device
296func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
297 log.Debug("updateGroupTable")
298 if groupMod == nil {
299 return nil
300 }
301 switch groupMod.GetCommand() {
302 case ofp.OfpGroupModCommand_OFPGC_ADD:
303 return agent.groupAdd(groupMod)
304 case ofp.OfpGroupModCommand_OFPGC_DELETE:
305 return agent.groupDelete(groupMod)
306 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
307 return agent.groupModify(groupMod)
308 }
309 return status.Errorf(codes.Internal,
310 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
311}
312
khenaidoo19d7b632018-10-30 10:49:50 -0400313//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
314//must only be called by a function that is holding the lock on the logical device
315func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
khenaidoo43c82122018-11-22 18:38:28 -0500316 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
317 copy(groupsCloned, groups)
318 if afterUpdate := agent.groupProxy.Update("/", groupsCloned, true, ""); afterUpdate == nil {
319 return errors.New(fmt.Sprintf("update-flow-group-failed:%s", agent.logicalDeviceId))
khenaidoo19d7b632018-10-30 10:49:50 -0400320 }
khenaidoo43c82122018-11-22 18:38:28 -0500321 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400322}
323
324//flowAdd adds a flow to the flow table of that logical device
325func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
326 log.Debug("flowAdd")
327 if mod == nil {
328 return nil
329 }
khenaidoo92e62c52018-10-03 14:02:54 -0400330 agent.lockLogicalDevice.Lock()
331 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400332
333 var lDevice *voltha.LogicalDevice
334 var err error
335 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
336 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
337 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
338 }
339
340 var flows []*ofp.OfpFlowStats
341 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
342 flows = lDevice.Flows.Items
343 }
344
khenaidoo43c82122018-11-22 18:38:28 -0500345 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400346 changed := false
347 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
348 if checkOverlap {
349 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
350 // TODO: should this error be notified other than being logged?
351 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
352 } else {
353 // Add flow
354 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
355 flows = append(flows, flow)
356 changed = true
357 }
358 } else {
359 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
360 idx := fu.FindFlows(flows, flow)
361 if idx >= 0 {
362 oldFlow := flows[idx]
363 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
364 flow.ByteCount = oldFlow.ByteCount
365 flow.PacketCount = oldFlow.PacketCount
366 }
367 flows[idx] = flow
368 } else {
369 flows = append(flows, flow)
370 }
371 changed = true
372 }
373 if changed {
374 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500375 flowsToUpdate := &ofp.Flows{}
376 if lDevice.Flows != nil {
377 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400378 }
khenaidoo43c82122018-11-22 18:38:28 -0500379 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
380 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400381 return err
382 }
383 }
khenaidoo19d7b632018-10-30 10:49:50 -0400384 return nil
385}
386
387//flowDelete deletes a flow from the flow table of that logical device
388func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
389 log.Debug("flowDelete")
390 if mod == nil {
391 return nil
392 }
393 agent.lockLogicalDevice.Lock()
394 defer agent.lockLogicalDevice.Unlock()
395
396 var lDevice *voltha.LogicalDevice
397 var err error
398 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
399 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
400 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
401 }
402 flows := lDevice.Flows.Items
403
404 //build a list of what to keep vs what to delete
405 toKeep := make([]*ofp.OfpFlowStats, 0)
406 for _, f := range flows {
407 if !fu.FlowMatchesMod(f, mod) {
408 toKeep = append(toKeep, f)
409 }
410 }
411
412 //Update flows
413 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500414 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
415 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400416 return err
417 }
418 }
419
420 //TODO: send announcement on delete
421 return nil
422}
423
424//flowStatsDelete deletes a flow from the flow table of that logical device
425func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
426 log.Debug("flowStatsDelete")
427 if flow == nil {
428 return nil
429 }
430 agent.lockLogicalDevice.Lock()
431 defer agent.lockLogicalDevice.Unlock()
432
433 var lDevice *voltha.LogicalDevice
434 var err error
435 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
436 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
437 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
438 }
439 flows := lDevice.Flows.Items
440
441 //build a list of what to keep vs what to delete
442 toKeep := make([]*ofp.OfpFlowStats, 0)
443 for _, f := range flows {
444 if !fu.FlowMatch(f, flow) {
445 toKeep = append(toKeep, f)
446 }
447 }
448
449 //Update flows
450 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500451 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400452 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
453 return err
454 }
455 }
456 return nil
457}
458
459//flowDeleteStrict deletes a flow from the flow table of that logical device
460func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
461 log.Debug("flowDeleteStrict")
462 if mod == nil {
463 return nil
464 }
465 agent.lockLogicalDevice.Lock()
466 defer agent.lockLogicalDevice.Unlock()
467
468 var lDevice *voltha.LogicalDevice
469 var err error
470 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
471 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
472 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
473 }
474 flows := lDevice.Flows.Items
475 changed := false
476 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
477 idx := fu.FindFlows(flows, flow)
478 if idx >= 0 {
479 flows = append(flows[:idx], flows[idx+1:]...)
480 changed = true
481 } else {
482 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
483 }
484
485 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500486 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400487 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
488 return err
489 }
490 }
491
492 return nil
493}
494
495//flowModify modifies a flow from the flow table of that logical device
496func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
497 return errors.New("flowModify not implemented")
498}
499
500//flowModifyStrict deletes a flow from the flow table of that logical device
501func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
502 return errors.New("flowModifyStrict not implemented")
503}
504
505func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
506 log.Debug("groupAdd")
507 if groupMod == nil {
508 return nil
509 }
510 agent.lockLogicalDevice.Lock()
511 defer agent.lockLogicalDevice.Unlock()
512
513 var lDevice *voltha.LogicalDevice
514 var err error
515 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
516 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
517 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
518 }
519 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400520 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
521 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500522 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
523 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400524 return err
525 }
526 } else {
527 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
528 }
khenaidoo19d7b632018-10-30 10:49:50 -0400529 return nil
530}
531
532func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
533 log.Debug("groupDelete")
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
547 flows := lDevice.Flows.Items
548 groupsChanged := false
549 flowsChanged := false
550 groupId := groupMod.GroupId
551 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
552 //TODO we must delete all flows that point to this group and
553 //signal controller as requested by flow's flag
554 groups = []*ofp.OfpGroupEntry{}
555 groupsChanged = true
556 } else {
557 if idx := fu.FindGroup(groups, groupId); idx == -1 {
558 return nil // Valid case
559 } else {
560 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
561 groups = append(groups[:idx], groups[idx+1:]...)
562 groupsChanged = true
563 }
564 }
khenaidoo43c82122018-11-22 18:38:28 -0500565 if groupsChanged {
566 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
567 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400568 return err
569 }
570 }
khenaidoo43c82122018-11-22 18:38:28 -0500571 if flowsChanged {
572 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
573 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
574 return err
575 }
576 }
577
khenaidoo19d7b632018-10-30 10:49:50 -0400578 return nil
579}
580
581func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
582 log.Debug("groupModify")
583 if groupMod == nil {
584 return nil
585 }
586 agent.lockLogicalDevice.Lock()
587 defer agent.lockLogicalDevice.Unlock()
588
589 var lDevice *voltha.LogicalDevice
590 var err error
591 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
592 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
593 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
594 }
595 groups := lDevice.FlowGroups.Items
596 groupsChanged := false
597 groupId := groupMod.GroupId
598 if idx := fu.FindGroup(groups, groupId); idx == -1 {
599 return errors.New(fmt.Sprintf("group-absent:%s", groupId))
600 } else {
601 //replace existing group entry with new group definition
602 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
603 groups[idx] = groupEntry
604 groupsChanged = true
605 }
606 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500607 //lDevice.FlowGroups.Items = groups
608 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400609 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
610 return err
611 }
612 }
613 return nil
614}
615
616// deleteLogicalPort removes the logical port
617func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
618 agent.lockLogicalDevice.Lock()
619 defer agent.lockLogicalDevice.Unlock()
620
khenaidoo92e62c52018-10-03 14:02:54 -0400621 // Get the most up to date logical device
622 var logicaldevice *voltha.LogicalDevice
623 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400624 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400625 return nil
626 }
khenaidoo92e62c52018-10-03 14:02:54 -0400627 index := -1
628 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400629 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400630 index = i
631 break
632 }
633 }
634 if index >= 0 {
635 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
636 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
637 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
638 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
639 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
640 }
641 return nil
khenaidoob9203542018-09-17 22:56:37 -0400642}
643
khenaidoo19d7b632018-10-30 10:49:50 -0400644// enableLogicalPort enables the logical port
645func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
646 agent.lockLogicalDevice.Lock()
647 defer agent.lockLogicalDevice.Unlock()
648
649 // Get the most up to date logical device
650 var logicaldevice *voltha.LogicalDevice
651 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
652 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
653 return nil
654 }
655 index := -1
656 for i, logicalPort := range logicaldevice.Ports {
657 if logicalPort.Id == lPort.Id {
658 index = i
659 break
660 }
661 }
662 if index >= 0 {
663 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
664 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
665 }
666 //TODO: Trigger subsequent actions on the device
667 return nil
668}
669
670// disableLogicalPort disabled the logical port
671func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
672 agent.lockLogicalDevice.Lock()
673 defer agent.lockLogicalDevice.Unlock()
674
675 // Get the most up to date logical device
676 var logicaldevice *voltha.LogicalDevice
677 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
678 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
679 return nil
680 }
681 index := -1
682 for i, logicalPort := range logicaldevice.Ports {
683 if logicalPort.Id == lPort.Id {
684 index = i
685 break
686 }
687 }
688 if index >= 0 {
689 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
690 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
691 }
692 //TODO: Trigger subsequent actions on the device
693 return nil
694}
695
khenaidoo89b0e942018-10-21 21:11:33 -0400696func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
697 for _, pNo := range nniPortsNo {
698 if pNo == portNo {
699 return true
700 }
701 }
702 return false
703}
khenaidoo4d4802d2018-10-04 21:59:49 -0400704
khenaidoo89b0e942018-10-21 21:11:33 -0400705func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400706 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400707 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400708 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400709 if ingress == routeLink.Ingress && egress == routeLink.Egress {
710 return route
711 }
712 }
713 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
714 return nil
715}
716
khenaidoo19d7b632018-10-30 10:49:50 -0400717func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400718 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
719 // Get the updated logical device
khenaidoo79232702018-12-04 11:00:41 -0500720 var ld *ic.LogicalDevice
khenaidoo89b0e942018-10-21 21:11:33 -0400721 routes := make([]graph.RouteHop, 0)
722 var err error
723 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
724 return nil
725 }
726 nniLogicalPortsNo := make([]uint32, 0)
727 for _, logicalPort := range ld.Ports {
728 if logicalPort.RootPort {
729 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
730 }
731 }
732 if len(nniLogicalPortsNo) == 0 {
733 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
734 return nil
735 }
khenaidoo19d7b632018-10-30 10:49:50 -0400736 // Note: A port value of 0 is equivalent to a nil port
737
khenaidoo89b0e942018-10-21 21:11:33 -0400738 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400739 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400740 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400741 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400742 log.Debug("returning-half-route")
743 //This is a trap on the NNI Port
744 //Return a 'half' route to make the flow decomposer logic happy
745 for routeLink, route := range agent.deviceGraph.Routes {
746 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
747 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
748 routes = append(routes, route[1])
749 return routes
750 }
751 }
752 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
753 return nil
754 }
755 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400756 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400757 }
758 //If ingress port is not specified (nil), it may be a wildcarded
759 //route if egress port is OFPP_CONTROLLER or a nni logical port,
760 //in which case we need to create a half-route where only the egress
761 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400762 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400763 // We can use the 2nd hop of any upstream route, so just find the first upstream:
764 for routeLink, route := range agent.deviceGraph.Routes {
765 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
766 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
767 routes = append(routes, route[1])
768 return routes
769 }
770 }
771 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
772 return nil
773 }
774 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400775 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400776 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400777 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400778 routes = append(routes, route[0])
779 routes = append(routes, graph.RouteHop{})
780 return routes
781 }
782 }
783 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
784 return nil
785 }
786
787 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400788 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400789}
790
791// updateRoutes updates the device routes whenever there is a device or port changes relevant to this
792// logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred
793// instead of rebuilding the entire set of routes
794func (agent *LogicalDeviceAgent) updateRoutes() {
khenaidoo19d7b632018-10-30 10:49:50 -0400795 if ld, err := agent.GetLogicalDevice(); err == nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400796 agent.deviceGraph.ComputeRoutes(ld.Ports)
797 }
798}
799
800func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
801 return fu.NewFlowsAndGroups()
802}
803
804func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
805 fg := fu.NewFlowsAndGroups()
806 var device *voltha.Device
807 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400808 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400809 return fg
810 }
811 //set the upstream and downstream ports
812 upstreamPorts := make([]*voltha.Port, 0)
813 downstreamPorts := make([]*voltha.Port, 0)
814 for _, port := range device.Ports {
815 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
816 upstreamPorts = append(upstreamPorts, port)
817 } else if port.Type == voltha.Port_ETHERNET_UNI {
818 downstreamPorts = append(downstreamPorts, port)
819 }
820 }
821 //it is possible that the downstream ports are not created, but the flow_decomposition has already
822 //kicked in. In such scenarios, cut short the processing and return.
823 if len(downstreamPorts) == 0 {
824 return fg
825 }
826 // set up the default flows
827 var fa *fu.FlowArgs
828 fa = &fu.FlowArgs{
829 KV: fu.OfpFlowModArgs{"priority": 500},
830 MatchFields: []*ofp.OfpOxmOfbField{
831 fd.InPort(downstreamPorts[0].PortNo),
832 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
833 },
834 Actions: []*ofp.OfpAction{
835 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400836 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400837 },
838 }
839 fg.AddFlow(fd.MkFlowStat(fa))
840
841 fa = &fu.FlowArgs{
842 KV: fu.OfpFlowModArgs{"priority": 500},
843 MatchFields: []*ofp.OfpOxmOfbField{
844 fd.InPort(downstreamPorts[0].PortNo),
845 fd.VlanVid(0),
846 },
847 Actions: []*ofp.OfpAction{
848 fd.PushVlan(0x8100),
849 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
850 fd.Output(upstreamPorts[0].PortNo),
851 },
852 }
853 fg.AddFlow(fd.MkFlowStat(fa))
854
855 fa = &fu.FlowArgs{
856 KV: fu.OfpFlowModArgs{"priority": 500},
857 MatchFields: []*ofp.OfpOxmOfbField{
858 fd.InPort(upstreamPorts[0].PortNo),
859 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
860 },
861 Actions: []*ofp.OfpAction{
862 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
863 fd.Output(downstreamPorts[0].PortNo),
864 },
865 }
866 fg.AddFlow(fd.MkFlowStat(fa))
867
868 return fg
869}
870
871func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
872 rules := fu.NewDeviceRules()
873 var ld *voltha.LogicalDevice
874 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400875 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400876 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
877 return rules
878 }
879
880 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
881 for deviceId, _ := range deviceNodeIds {
882 if deviceId == ld.RootDeviceId {
883 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
884 } else {
885 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
886 }
887 }
888 return rules
889}
890
891func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
892 // Get latest
893 var lDevice *voltha.LogicalDevice
894 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400895 if lDevice, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400896 return fu.NewDeviceRules()
897 }
898 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo19d7b632018-10-30 10:49:50 -0400899 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
khenaidoo89b0e942018-10-21 21:11:33 -0400900 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
901 agent.DefaultFlowRules = agent.generateDefaultRules()
902 }
903 return agent.DefaultFlowRules
904}
905
906func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
907 lPorts := make([]uint32, 0)
908 var exclPort uint32
909 if len(excludePort) == 1 {
910 exclPort = excludePort[0]
911 }
khenaidoo19d7b632018-10-30 10:49:50 -0400912 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400913 for _, port := range lDevice.Ports {
914 if port.OfpPort.PortNo != exclPort {
915 lPorts = append(lPorts, port.OfpPort.PortNo)
916 }
917 }
918 }
919 return lPorts
920}
khenaidoo19d7b632018-10-30 10:49:50 -0400921
922func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
923 return agent.deviceGraph
924}
925
926//setupDeviceGraph creates the device graph if not done already
927func (agent *LogicalDeviceAgent) setupDeviceGraph() {
928 if agent.deviceGraph == nil {
929 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
930 agent.updateRoutes()
931 }
932}
933
934func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
935 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
936
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500937 var previousData *ofp.Flows
938 var latestData *ofp.Flows
khenaidoo19d7b632018-10-30 10:49:50 -0400939
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500940 var ok bool
941 if previousData, ok = args[0].(*ofp.Flows); !ok {
942 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
943 }
944 if latestData, ok = args[1].(*ofp.Flows); !ok {
945 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
946 }
khenaidoo19d7b632018-10-30 10:49:50 -0400947
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500948 if reflect.DeepEqual(previousData.Items, latestData.Items) {
949 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -0400950 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500951 }
952
953 // Ensure the device graph has been setup
954 agent.setupDeviceGraph()
955
956 var groups *ofp.FlowGroups
957 lDevice, _ := agent.getLogicalDeviceWithoutLock()
958 groups = lDevice.FlowGroups
959 log.Debugw("flowsinfo", log.Fields{"flows": latestData, "groups": groups})
960 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *latestData, *groups)
961 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
962
963 for deviceId, value := range deviceRules.GetRules() {
964 agent.deviceMgr.updateFlows(deviceId, value.ListFlows())
965 agent.deviceMgr.updateGroups(deviceId, value.ListGroups())
966 }
khenaidoo19d7b632018-10-30 10:49:50 -0400967
khenaidoo19d7b632018-10-30 10:49:50 -0400968 return nil
969}
970
971func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
972 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
973
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500974 var previousData *ofp.FlowGroups
975 var latestData *ofp.FlowGroups
khenaidoo19d7b632018-10-30 10:49:50 -0400976
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500977 var ok bool
978 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
979 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
980 }
981 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
982 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
983 }
khenaidoo19d7b632018-10-30 10:49:50 -0400984
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500985 if reflect.DeepEqual(previousData.Items, latestData.Items) {
986 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -0400987 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500988 }
989
990 // Ensure the device graph has been setup
991 agent.setupDeviceGraph()
992
993 var flows *ofp.Flows
994 lDevice, _ := agent.getLogicalDeviceWithoutLock()
995 flows = lDevice.Flows
996 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
997 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
998 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
999 for deviceId, value := range deviceRules.GetRules() {
1000 agent.deviceMgr.updateFlows(deviceId, value.ListFlows())
1001 agent.deviceMgr.updateGroups(deviceId, value.ListGroups())
1002 }
khenaidoo19d7b632018-10-30 10:49:50 -04001003
khenaidoo19d7b632018-10-30 10:49:50 -04001004 return nil
1005}
khenaidoofdbad6e2018-11-06 22:26:38 -05001006
khenaidoo43c82122018-11-22 18:38:28 -05001007func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001008 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1009 outPort := fd.GetPacketOutPort(packet)
1010 //frame := packet.GetData()
1011 //TODO: Use a channel between the logical agent and the device agent
1012 agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet)
1013}
1014
khenaidoofdbad6e2018-11-06 22:26:38 -05001015func (agent *LogicalDeviceAgent) packetIn(port uint32, packet []byte) {
1016 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet})
1017 packet_in := fd.MkPacketIn(port, packet)
1018 log.Debugw("sending-packet-in", log.Fields{"packet-in": packet_in})
1019}