blob: 511ca1335036de3e768aaa9a1daf5520fc84fbf3 [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
khenaidoo8c3303d2019-02-13 14:59:39 -050039 //lastData *voltha.LogicalDevice
khenaidoo92e62c52018-10-03 14:02:54 -040040 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 }
khenaidoo6d055132019-02-12 16:51:19 -050089
khenaidoo297cd252019-02-07 22:10:23 -050090 ld.DatapathId = datapathID
91 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
khenaidoo6d055132019-02-12 16:51:19 -050092 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo297cd252019-02-07 22:10:23 -050093 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
94 ld.Flows = &ofp.Flows{Items: nil}
95 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
96
97 //Add logical ports to the logical device based on the number of NNI ports discovered
98 //First get the default port capability - TODO: each NNI port may have different capabilities,
99 //hence. may need to extract the port by the NNI port id defined by the adapter during device
100 //creation
101 var nniPorts *voltha.Ports
102 if nniPorts, err = agent.deviceMgr.getPorts(ctx, agent.rootDeviceId, voltha.Port_ETHERNET_NNI); err != nil {
103 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
104 }
105 var portCap *ic.PortCapability
106 for _, port := range nniPorts.Items {
107 log.Infow("!!!!!!!NNI PORTS", log.Fields{"NNI": port})
108 if portCap, err = agent.deviceMgr.getPortCapability(ctx, agent.rootDeviceId, port.PortNo); err != nil {
109 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
110 return err
111 }
112 portCap.Port.RootPort = true
113 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
114 lp.DeviceId = agent.rootDeviceId
115 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
116 lp.OfpPort.PortNo = port.PortNo
117 lp.OfpPort.Name = lp.Id
118 lp.DevicePortNo = port.PortNo
119 ld.Ports = append(ld.Ports, lp)
120 }
121 agent.lockLogicalDevice.Lock()
122 //defer agent.lockLogicalDevice.Unlock()
123 // Save the logical device
124 if added := agent.clusterDataProxy.AddWithID("/logical_devices", ld.Id, ld, ""); added == nil {
125 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
126 } else {
127 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
128 }
129 agent.lockLogicalDevice.Unlock()
130 } else {
131 // load from dB - the logical may not exist at this time. On error, just return and the calling function
132 // will destroy this agent.
133 var err error
134 if ld, err = agent.GetLogicalDevice(); err != nil {
135 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
136 return err
137 }
khenaidoo8c3303d2019-02-13 14:59:39 -0500138 // Update the root device Id
139 agent.rootDeviceId = ld.RootDeviceId
khenaidoob9203542018-09-17 22:56:37 -0400140 }
khenaidoo92e62c52018-10-03 14:02:54 -0400141 agent.lockLogicalDevice.Lock()
khenaidoo43c82122018-11-22 18:38:28 -0500142 agent.flowProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400143 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
144 false)
khenaidoo43c82122018-11-22 18:38:28 -0500145 agent.groupProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400146 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
147 false)
148
149 agent.flowProxy.RegisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
khenaidoo43c82122018-11-22 18:38:28 -0500150 agent.groupProxy.RegisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
khenaidoo19d7b632018-10-30 10:49:50 -0400151
khenaidoobcf205b2019-01-25 22:21:14 -0500152 agent.lockLogicalDevice.Unlock()
153
154 // Setup the device graph
155 go agent.setupDeviceGraph()
156
khenaidoob9203542018-09-17 22:56:37 -0400157 return nil
158}
159
khenaidoo4d4802d2018-10-04 21:59:49 -0400160// stop stops the logical devuce agent. This removes the logical device from the data model.
161func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
162 log.Info("stopping-logical_device-agent")
163 agent.lockLogicalDevice.Lock()
164 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500165
166 // Unregister to teh callbacks
167 if agent.flowProxy != nil {
168 agent.flowProxy.UnregisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
169 }
170 if agent.groupProxy != nil {
171 agent.groupProxy.UnregisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
172 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400173 //Remove the logical device from the model
174 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
175 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
176 } else {
177 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
178 }
179 agent.exitChannel <- 1
180 log.Info("logical_device-agent-stopped")
181}
182
khenaidoo19d7b632018-10-30 10:49:50 -0400183// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
184func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
185 log.Debug("GetLogicalDevice")
khenaidoo92e62c52018-10-03 14:02:54 -0400186 agent.lockLogicalDevice.Lock()
187 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500188 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400189 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500190 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400191 }
192 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
193}
194
khenaidoo19d7b632018-10-30 10:49:50 -0400195func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
196 log.Debug("!!!!!ListLogicalDevicePorts")
197 agent.lockLogicalDevice.Lock()
198 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500199 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400200 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
201 lPorts := make([]*voltha.LogicalPort, 0)
202 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500203 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400204 }
205 return &voltha.LogicalPorts{Items: lPorts}, nil
206 }
207 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
208}
209
210// listFlows locks the logical device model and then retrieves the latest flow information
211func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
212 log.Debug("listFlows")
213 agent.lockLogicalDevice.Lock()
214 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500215 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400216 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
217 return lDevice.Flows.Items
218 }
219 return nil
220}
221
222// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
223func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
224 log.Debug("listFlowGroups")
225 agent.lockLogicalDevice.Lock()
226 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500227 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400228 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
229 return lDevice.FlowGroups.Items
230 }
231 return nil
232}
233
khenaidoo43c82122018-11-22 18:38:28 -0500234//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
235func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500236 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500237 if afterUpdate == nil {
238 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
239 }
khenaidoo43c82122018-11-22 18:38:28 -0500240 return nil
241}
242
243//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
244func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500245 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500246 if afterUpdate == nil {
247 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
248 }
khenaidoo43c82122018-11-22 18:38:28 -0500249 return nil
250}
251
khenaidoo4d4802d2018-10-04 21:59:49 -0400252// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
253// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400254func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
255 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo8c3303d2019-02-13 14:59:39 -0500256 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400257 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500258 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400259 }
260 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
261}
262
khenaidoo4d4802d2018-10-04 21:59:49 -0400263// addUNILogicalPort creates a UNI port on the logical device that represents a child device
khenaidoo19d7b632018-10-30 10:49:50 -0400264func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400265 log.Infow("addUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400266 // Build the logical device based on information retrieved from the device adapter
khenaidoo79232702018-12-04 11:00:41 -0500267 var portCap *ic.PortCapability
khenaidoob9203542018-09-17 22:56:37 -0400268 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400269
270 //Get UNI port number
271 var uniPort uint32
272 for _, port := range childDevice.Ports {
273 if port.Type == voltha.Port_ETHERNET_UNI {
274 uniPort = port.PortNo
275 }
276 }
277 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, uniPort); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400278 log.Errorw("error-creating-logical-port", log.Fields{"error": err})
279 return err
280 }
khenaidoo92e62c52018-10-03 14:02:54 -0400281 agent.lockLogicalDevice.Lock()
282 defer agent.lockLogicalDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400283 // Get stored logical device
khenaidoo92e62c52018-10-03 14:02:54 -0400284 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400285 return status.Error(codes.NotFound, agent.logicalDeviceId)
286 } else {
khenaidoobcf205b2019-01-25 22:21:14 -0500287 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
khenaidoo19d7b632018-10-30 10:49:50 -0400288 portCap.Port.RootPort = false
289 //TODO: For now use the channel id assigned by the OLT as logical port number
290 lPortNo := childDevice.ProxyAddress.ChannelId
291 portCap.Port.Id = fmt.Sprintf("uni-%d", lPortNo)
292 portCap.Port.OfpPort.PortNo = lPortNo
293 portCap.Port.OfpPort.Name = portCap.Port.Id
294 portCap.Port.DeviceId = childDevice.Id
295 portCap.Port.DevicePortNo = uniPort
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500296 portCap.Port.DeviceId = childDevice.Id
khenaidoobcf205b2019-01-25 22:21:14 -0500297
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500298 ldevice.Ports = append(ldevice.Ports, portCap.Port)
299 return agent.updateLogicalDeviceWithoutLock(ldevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400300 }
301}
302
303//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
304func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500305 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400306 if afterUpdate == nil {
307 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
308 }
309 return nil
310}
311
khenaidoo19d7b632018-10-30 10:49:50 -0400312//updateFlowTable updates the flow table of that logical device
313func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
314 log.Debug("updateFlowTable")
315 if flow == nil {
316 return nil
317 }
318 switch flow.GetCommand() {
319 case ofp.OfpFlowModCommand_OFPFC_ADD:
320 return agent.flowAdd(flow)
321 case ofp.OfpFlowModCommand_OFPFC_DELETE:
322 return agent.flowDelete(flow)
323 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
324 return agent.flowDeleteStrict(flow)
325 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
326 return agent.flowModify(flow)
327 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
328 return agent.flowModifyStrict(flow)
329 }
330 return status.Errorf(codes.Internal,
331 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
332}
333
334//updateGroupTable updates the group table of that logical device
335func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
336 log.Debug("updateGroupTable")
337 if groupMod == nil {
338 return nil
339 }
340 switch groupMod.GetCommand() {
341 case ofp.OfpGroupModCommand_OFPGC_ADD:
342 return agent.groupAdd(groupMod)
343 case ofp.OfpGroupModCommand_OFPGC_DELETE:
344 return agent.groupDelete(groupMod)
345 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
346 return agent.groupModify(groupMod)
347 }
348 return status.Errorf(codes.Internal,
349 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
350}
351
khenaidoo19d7b632018-10-30 10:49:50 -0400352//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
353//must only be called by a function that is holding the lock on the logical device
354func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
khenaidoo43c82122018-11-22 18:38:28 -0500355 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
356 copy(groupsCloned, groups)
357 if afterUpdate := agent.groupProxy.Update("/", groupsCloned, true, ""); afterUpdate == nil {
358 return errors.New(fmt.Sprintf("update-flow-group-failed:%s", agent.logicalDeviceId))
khenaidoo19d7b632018-10-30 10:49:50 -0400359 }
khenaidoo43c82122018-11-22 18:38:28 -0500360 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400361}
362
363//flowAdd adds a flow to the flow table of that logical device
364func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
365 log.Debug("flowAdd")
366 if mod == nil {
367 return nil
368 }
khenaidoo92e62c52018-10-03 14:02:54 -0400369 agent.lockLogicalDevice.Lock()
370 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400371
372 var lDevice *voltha.LogicalDevice
373 var err error
374 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
375 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
376 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
377 }
378
379 var flows []*ofp.OfpFlowStats
380 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
381 flows = lDevice.Flows.Items
382 }
383
khenaidoo43c82122018-11-22 18:38:28 -0500384 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400385 changed := false
386 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
387 if checkOverlap {
388 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
389 // TODO: should this error be notified other than being logged?
390 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
391 } else {
392 // Add flow
393 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
394 flows = append(flows, flow)
395 changed = true
396 }
397 } else {
398 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
399 idx := fu.FindFlows(flows, flow)
400 if idx >= 0 {
401 oldFlow := flows[idx]
402 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
403 flow.ByteCount = oldFlow.ByteCount
404 flow.PacketCount = oldFlow.PacketCount
405 }
406 flows[idx] = flow
407 } else {
408 flows = append(flows, flow)
409 }
410 changed = true
411 }
412 if changed {
413 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500414 flowsToUpdate := &ofp.Flows{}
415 if lDevice.Flows != nil {
416 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400417 }
khenaidoo43c82122018-11-22 18:38:28 -0500418 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
419 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400420 return err
421 }
422 }
khenaidoo19d7b632018-10-30 10:49:50 -0400423 return nil
424}
425
426//flowDelete deletes a flow from the flow table of that logical device
427func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
428 log.Debug("flowDelete")
429 if mod == nil {
430 return nil
431 }
432 agent.lockLogicalDevice.Lock()
433 defer agent.lockLogicalDevice.Unlock()
434
435 var lDevice *voltha.LogicalDevice
436 var err error
437 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
438 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
439 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
440 }
441 flows := lDevice.Flows.Items
442
443 //build a list of what to keep vs what to delete
444 toKeep := make([]*ofp.OfpFlowStats, 0)
445 for _, f := range flows {
446 if !fu.FlowMatchesMod(f, mod) {
447 toKeep = append(toKeep, f)
448 }
449 }
450
451 //Update flows
452 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500453 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
454 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400455 return err
456 }
457 }
458
459 //TODO: send announcement on delete
460 return nil
461}
462
463//flowStatsDelete deletes a flow from the flow table of that logical device
464func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
465 log.Debug("flowStatsDelete")
466 if flow == nil {
467 return nil
468 }
469 agent.lockLogicalDevice.Lock()
470 defer agent.lockLogicalDevice.Unlock()
471
472 var lDevice *voltha.LogicalDevice
473 var err error
474 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
475 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
476 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
477 }
478 flows := lDevice.Flows.Items
479
480 //build a list of what to keep vs what to delete
481 toKeep := make([]*ofp.OfpFlowStats, 0)
482 for _, f := range flows {
483 if !fu.FlowMatch(f, flow) {
484 toKeep = append(toKeep, f)
485 }
486 }
487
488 //Update flows
489 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500490 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400491 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
492 return err
493 }
494 }
495 return nil
496}
497
498//flowDeleteStrict deletes a flow from the flow table of that logical device
499func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
500 log.Debug("flowDeleteStrict")
501 if mod == nil {
502 return nil
503 }
504 agent.lockLogicalDevice.Lock()
505 defer agent.lockLogicalDevice.Unlock()
506
507 var lDevice *voltha.LogicalDevice
508 var err error
509 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
510 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
511 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
512 }
513 flows := lDevice.Flows.Items
514 changed := false
515 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
516 idx := fu.FindFlows(flows, flow)
517 if idx >= 0 {
518 flows = append(flows[:idx], flows[idx+1:]...)
519 changed = true
520 } else {
521 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
522 }
523
524 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500525 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400526 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
527 return err
528 }
529 }
530
531 return nil
532}
533
534//flowModify modifies a flow from the flow table of that logical device
535func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
536 return errors.New("flowModify not implemented")
537}
538
539//flowModifyStrict deletes a flow from the flow table of that logical device
540func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
541 return errors.New("flowModifyStrict not implemented")
542}
543
544func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
545 log.Debug("groupAdd")
546 if groupMod == nil {
547 return nil
548 }
549 agent.lockLogicalDevice.Lock()
550 defer agent.lockLogicalDevice.Unlock()
551
552 var lDevice *voltha.LogicalDevice
553 var err error
554 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
555 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
556 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
557 }
558 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400559 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
560 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500561 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
562 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400563 return err
564 }
565 } else {
566 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
567 }
khenaidoo19d7b632018-10-30 10:49:50 -0400568 return nil
569}
570
571func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
572 log.Debug("groupDelete")
573 if groupMod == nil {
574 return nil
575 }
576 agent.lockLogicalDevice.Lock()
577 defer agent.lockLogicalDevice.Unlock()
578
579 var lDevice *voltha.LogicalDevice
580 var err error
581 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
582 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
583 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
584 }
585 groups := lDevice.FlowGroups.Items
586 flows := lDevice.Flows.Items
587 groupsChanged := false
588 flowsChanged := false
589 groupId := groupMod.GroupId
590 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
591 //TODO we must delete all flows that point to this group and
592 //signal controller as requested by flow's flag
593 groups = []*ofp.OfpGroupEntry{}
594 groupsChanged = true
595 } else {
596 if idx := fu.FindGroup(groups, groupId); idx == -1 {
597 return nil // Valid case
598 } else {
599 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
600 groups = append(groups[:idx], groups[idx+1:]...)
601 groupsChanged = true
602 }
603 }
khenaidoo43c82122018-11-22 18:38:28 -0500604 if groupsChanged {
605 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
606 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400607 return err
608 }
609 }
khenaidoo43c82122018-11-22 18:38:28 -0500610 if flowsChanged {
611 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
612 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
613 return err
614 }
615 }
616
khenaidoo19d7b632018-10-30 10:49:50 -0400617 return nil
618}
619
620func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
621 log.Debug("groupModify")
622 if groupMod == nil {
623 return nil
624 }
625 agent.lockLogicalDevice.Lock()
626 defer agent.lockLogicalDevice.Unlock()
627
628 var lDevice *voltha.LogicalDevice
629 var err error
630 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
631 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
632 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
633 }
634 groups := lDevice.FlowGroups.Items
635 groupsChanged := false
636 groupId := groupMod.GroupId
637 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500638 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400639 } else {
640 //replace existing group entry with new group definition
641 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
642 groups[idx] = groupEntry
643 groupsChanged = true
644 }
645 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500646 //lDevice.FlowGroups.Items = groups
647 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400648 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
649 return err
650 }
651 }
652 return nil
653}
654
655// deleteLogicalPort removes the logical port
656func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
657 agent.lockLogicalDevice.Lock()
658 defer agent.lockLogicalDevice.Unlock()
659
khenaidoo92e62c52018-10-03 14:02:54 -0400660 // Get the most up to date logical device
661 var logicaldevice *voltha.LogicalDevice
662 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400663 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400664 return nil
665 }
khenaidoo92e62c52018-10-03 14:02:54 -0400666 index := -1
667 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400668 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400669 index = i
670 break
671 }
672 }
673 if index >= 0 {
674 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
675 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
676 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
677 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
678 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
679 }
680 return nil
khenaidoob9203542018-09-17 22:56:37 -0400681}
682
khenaidoo19d7b632018-10-30 10:49:50 -0400683// enableLogicalPort enables the logical port
684func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
685 agent.lockLogicalDevice.Lock()
686 defer agent.lockLogicalDevice.Unlock()
687
688 // Get the most up to date logical device
689 var logicaldevice *voltha.LogicalDevice
690 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
691 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
692 return nil
693 }
694 index := -1
695 for i, logicalPort := range logicaldevice.Ports {
696 if logicalPort.Id == lPort.Id {
697 index = i
698 break
699 }
700 }
701 if index >= 0 {
702 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
703 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
704 }
705 //TODO: Trigger subsequent actions on the device
706 return nil
707}
708
709// disableLogicalPort disabled the logical port
710func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
711 agent.lockLogicalDevice.Lock()
712 defer agent.lockLogicalDevice.Unlock()
713
714 // Get the most up to date logical device
715 var logicaldevice *voltha.LogicalDevice
716 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
717 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
718 return nil
719 }
720 index := -1
721 for i, logicalPort := range logicaldevice.Ports {
722 if logicalPort.Id == lPort.Id {
723 index = i
724 break
725 }
726 }
727 if index >= 0 {
728 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
729 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
730 }
731 //TODO: Trigger subsequent actions on the device
732 return nil
733}
734
khenaidoo89b0e942018-10-21 21:11:33 -0400735func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
736 for _, pNo := range nniPortsNo {
737 if pNo == portNo {
738 return true
739 }
740 }
741 return false
742}
khenaidoo4d4802d2018-10-04 21:59:49 -0400743
khenaidoo89b0e942018-10-21 21:11:33 -0400744func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400745 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400746 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400747 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400748 if ingress == routeLink.Ingress && egress == routeLink.Egress {
749 return route
750 }
751 }
752 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
753 return nil
754}
755
khenaidoo19d7b632018-10-30 10:49:50 -0400756func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400757 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
758 // Get the updated logical device
khenaidoo79232702018-12-04 11:00:41 -0500759 var ld *ic.LogicalDevice
khenaidoo89b0e942018-10-21 21:11:33 -0400760 routes := make([]graph.RouteHop, 0)
761 var err error
762 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
763 return nil
764 }
765 nniLogicalPortsNo := make([]uint32, 0)
766 for _, logicalPort := range ld.Ports {
767 if logicalPort.RootPort {
768 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
769 }
770 }
771 if len(nniLogicalPortsNo) == 0 {
772 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
773 return nil
774 }
khenaidoo19d7b632018-10-30 10:49:50 -0400775 // Note: A port value of 0 is equivalent to a nil port
776
khenaidoo89b0e942018-10-21 21:11:33 -0400777 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400778 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400779 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400780 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400781 log.Debug("returning-half-route")
782 //This is a trap on the NNI Port
783 //Return a 'half' route to make the flow decomposer logic happy
784 for routeLink, route := range agent.deviceGraph.Routes {
785 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
786 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
787 routes = append(routes, route[1])
788 return routes
789 }
790 }
791 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
792 return nil
793 }
794 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400795 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400796 }
797 //If ingress port is not specified (nil), it may be a wildcarded
798 //route if egress port is OFPP_CONTROLLER or a nni logical port,
799 //in which case we need to create a half-route where only the egress
800 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400801 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400802 // We can use the 2nd hop of any upstream route, so just find the first upstream:
803 for routeLink, route := range agent.deviceGraph.Routes {
804 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
805 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
806 routes = append(routes, route[1])
807 return routes
808 }
809 }
810 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
811 return nil
812 }
813 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400814 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400815 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400816 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400817 routes = append(routes, route[0])
818 routes = append(routes, graph.RouteHop{})
819 return routes
820 }
821 }
822 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
823 return nil
824 }
825
826 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400827 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400828}
829
830// updateRoutes updates the device routes whenever there is a device or port changes relevant to this
831// logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred
832// instead of rebuilding the entire set of routes
833func (agent *LogicalDeviceAgent) updateRoutes() {
khenaidoo19d7b632018-10-30 10:49:50 -0400834 if ld, err := agent.GetLogicalDevice(); err == nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400835 agent.deviceGraph.ComputeRoutes(ld.Ports)
836 }
837}
838
839func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
840 return fu.NewFlowsAndGroups()
841}
842
843func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
844 fg := fu.NewFlowsAndGroups()
845 var device *voltha.Device
846 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400847 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400848 return fg
849 }
850 //set the upstream and downstream ports
851 upstreamPorts := make([]*voltha.Port, 0)
852 downstreamPorts := make([]*voltha.Port, 0)
853 for _, port := range device.Ports {
854 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
855 upstreamPorts = append(upstreamPorts, port)
856 } else if port.Type == voltha.Port_ETHERNET_UNI {
857 downstreamPorts = append(downstreamPorts, port)
858 }
859 }
860 //it is possible that the downstream ports are not created, but the flow_decomposition has already
861 //kicked in. In such scenarios, cut short the processing and return.
khenaidoo6d055132019-02-12 16:51:19 -0500862 if len(downstreamPorts) == 0 || len(upstreamPorts) == 0{
khenaidoo89b0e942018-10-21 21:11:33 -0400863 return fg
864 }
865 // set up the default flows
866 var fa *fu.FlowArgs
867 fa = &fu.FlowArgs{
868 KV: fu.OfpFlowModArgs{"priority": 500},
869 MatchFields: []*ofp.OfpOxmOfbField{
870 fd.InPort(downstreamPorts[0].PortNo),
871 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
872 },
873 Actions: []*ofp.OfpAction{
874 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400875 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400876 },
877 }
878 fg.AddFlow(fd.MkFlowStat(fa))
879
880 fa = &fu.FlowArgs{
881 KV: fu.OfpFlowModArgs{"priority": 500},
882 MatchFields: []*ofp.OfpOxmOfbField{
883 fd.InPort(downstreamPorts[0].PortNo),
884 fd.VlanVid(0),
885 },
886 Actions: []*ofp.OfpAction{
887 fd.PushVlan(0x8100),
888 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
889 fd.Output(upstreamPorts[0].PortNo),
890 },
891 }
892 fg.AddFlow(fd.MkFlowStat(fa))
893
894 fa = &fu.FlowArgs{
895 KV: fu.OfpFlowModArgs{"priority": 500},
896 MatchFields: []*ofp.OfpOxmOfbField{
897 fd.InPort(upstreamPorts[0].PortNo),
898 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
899 },
900 Actions: []*ofp.OfpAction{
901 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
902 fd.Output(downstreamPorts[0].PortNo),
903 },
904 }
905 fg.AddFlow(fd.MkFlowStat(fa))
906
907 return fg
908}
909
910func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
911 rules := fu.NewDeviceRules()
912 var ld *voltha.LogicalDevice
913 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400914 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400915 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
916 return rules
917 }
918
919 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
khenaidooca301322019-01-09 23:06:32 -0500920 for deviceId := range deviceNodeIds {
khenaidoo89b0e942018-10-21 21:11:33 -0400921 if deviceId == ld.RootDeviceId {
922 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
923 } else {
924 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
925 }
926 }
927 return rules
928}
929
930func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
931 // Get latest
932 var lDevice *voltha.LogicalDevice
933 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400934 if lDevice, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400935 return fu.NewDeviceRules()
936 }
937 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo19d7b632018-10-30 10:49:50 -0400938 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
khenaidoo89b0e942018-10-21 21:11:33 -0400939 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
940 agent.DefaultFlowRules = agent.generateDefaultRules()
941 }
942 return agent.DefaultFlowRules
943}
944
945func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
946 lPorts := make([]uint32, 0)
947 var exclPort uint32
948 if len(excludePort) == 1 {
949 exclPort = excludePort[0]
950 }
khenaidoo19d7b632018-10-30 10:49:50 -0400951 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400952 for _, port := range lDevice.Ports {
953 if port.OfpPort.PortNo != exclPort {
954 lPorts = append(lPorts, port.OfpPort.PortNo)
955 }
956 }
957 }
958 return lPorts
959}
khenaidoo19d7b632018-10-30 10:49:50 -0400960
961func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
962 return agent.deviceGraph
963}
964
965//setupDeviceGraph creates the device graph if not done already
966func (agent *LogicalDeviceAgent) setupDeviceGraph() {
967 if agent.deviceGraph == nil {
968 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
969 agent.updateRoutes()
970 }
971}
972
973func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
974 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
975
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500976 var previousData *ofp.Flows
977 var latestData *ofp.Flows
khenaidoo19d7b632018-10-30 10:49:50 -0400978
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500979 var ok bool
980 if previousData, ok = args[0].(*ofp.Flows); !ok {
981 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
982 }
983 if latestData, ok = args[1].(*ofp.Flows); !ok {
984 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
985 }
khenaidoo19d7b632018-10-30 10:49:50 -0400986
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500987 if reflect.DeepEqual(previousData.Items, latestData.Items) {
988 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -0400989 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500990 }
991
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500992 var groups *ofp.FlowGroups
993 lDevice, _ := agent.getLogicalDeviceWithoutLock()
994 groups = lDevice.FlowGroups
995 log.Debugw("flowsinfo", log.Fields{"flows": latestData, "groups": groups})
996 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *latestData, *groups)
997 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
998
khenaidooca301322019-01-09 23:06:32 -0500999 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001000 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -05001001 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
1002 log.Error("update-flows-failed", log.Fields{"deviceID":deviceId})
1003 }
1004 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
1005 log.Error("update-groups-failed", log.Fields{"deviceID":deviceId})
1006 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001007 }
khenaidoo19d7b632018-10-30 10:49:50 -04001008
khenaidoo19d7b632018-10-30 10:49:50 -04001009 return nil
1010}
1011
1012func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
1013 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
1014
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001015 var previousData *ofp.FlowGroups
1016 var latestData *ofp.FlowGroups
khenaidoo19d7b632018-10-30 10:49:50 -04001017
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001018 var ok bool
1019 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
1020 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1021 }
1022 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
1023 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1024 }
khenaidoo19d7b632018-10-30 10:49:50 -04001025
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001026 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1027 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -04001028 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001029 }
1030
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001031 var flows *ofp.Flows
1032 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1033 flows = lDevice.Flows
1034 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
1035 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
1036 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidooca301322019-01-09 23:06:32 -05001037 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001038 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -05001039 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
1040 log.Error("update-flows-failed", log.Fields{"deviceID":deviceId})
1041 }
1042 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
1043 log.Error("update-groups-failed", log.Fields{"deviceID":deviceId})
1044 }
khenaidoo19d7b632018-10-30 10:49:50 -04001045
khenaidooca301322019-01-09 23:06:32 -05001046 }
khenaidoo19d7b632018-10-30 10:49:50 -04001047 return nil
1048}
khenaidoofdbad6e2018-11-06 22:26:38 -05001049
khenaidoo43c82122018-11-22 18:38:28 -05001050func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001051 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1052 outPort := fd.GetPacketOutPort(packet)
1053 //frame := packet.GetData()
1054 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001055 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
1056 log.Error("packetout-failed", log.Fields{"logicalDeviceID":agent.rootDeviceId})
1057 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001058}
1059
khenaidoo297cd252019-02-07 22:10:23 -05001060func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1061 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidooca301322019-01-09 23:06:32 -05001062 packetIn := fd.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001063 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001064 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001065}