blob: 732e9cf2b6c13bdf862fc3b2e1b5d758ef6d974c [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"
khenaidoo89b0e942018-10-21 21:11:33 -040025 fd "github.com/opencord/voltha-go/rw_core/flow_decomposition"
26 "github.com/opencord/voltha-go/rw_core/graph"
27 fu "github.com/opencord/voltha-go/rw_core/utils"
khenaidoo8f474192019-04-03 17:20:44 -040028 ic "github.com/opencord/voltha-protos/go/inter_container"
29 ofp "github.com/opencord/voltha-protos/go/openflow_13"
30 "github.com/opencord/voltha-protos/go/voltha"
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
khenaidoofc1314d2019-03-14 09:34:21 -040049 ldProxy *model.Proxy
50 portProxies map[string]*model.Proxy
51 portProxiesLock sync.RWMutex
khenaidoo92e62c52018-10-03 14:02:54 -040052 lockLogicalDevice sync.RWMutex
khenaidoo19d7b632018-10-30 10:49:50 -040053 flowDecomposer *fd.FlowDecomposer
khenaidoob9203542018-09-17 22:56:37 -040054}
55
Stephane Barbarie1ab43272018-12-08 21:42:13 -050056func newLogicalDeviceAgent(id string, deviceId string, ldeviceMgr *LogicalDeviceManager,
57 deviceMgr *DeviceManager,
khenaidoo9a468962018-09-19 15:33:13 -040058 cdProxy *model.Proxy) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040059 var agent LogicalDeviceAgent
60 agent.exitChannel = make(chan int, 1)
61 agent.logicalDeviceId = id
Stephane Barbarie1ab43272018-12-08 21:42:13 -050062 agent.rootDeviceId = deviceId
khenaidoob9203542018-09-17 22:56:37 -040063 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040064 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040065 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040066 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040067 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoofc1314d2019-03-14 09:34:21 -040068 agent.portProxies = make(map[string]*model.Proxy)
69 agent.portProxiesLock = sync.RWMutex{}
khenaidoob9203542018-09-17 22:56:37 -040070 return &agent
71}
72
khenaidoo4d4802d2018-10-04 21:59:49 -040073// start creates the logical device and add it to the data model
khenaidoo297cd252019-02-07 22:10:23 -050074func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
75 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceId, "loadFromdB": loadFromdB})
76 var ld *voltha.LogicalDevice
77 if !loadFromdB {
78 //Build the logical device based on information retrieved from the device adapter
79 var switchCap *ic.SwitchCapability
80 var err error
81 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceId); err != nil {
khenaidoob9203542018-09-17 22:56:37 -040082 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
83 return err
84 }
khenaidoo297cd252019-02-07 22:10:23 -050085 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceId, RootDeviceId: agent.rootDeviceId}
86
87 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
88 var datapathID uint64
89 if datapathID, err = CreateDataPathId(agent.logicalDeviceId); err != nil {
90 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
91 return err
92 }
93 ld.DatapathId = datapathID
94 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
khenaidoo6d055132019-02-12 16:51:19 -050095 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo297cd252019-02-07 22:10:23 -050096 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
97 ld.Flows = &ofp.Flows{Items: nil}
98 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
99
khenaidoo297cd252019-02-07 22:10:23 -0500100 agent.lockLogicalDevice.Lock()
khenaidoo297cd252019-02-07 22:10:23 -0500101 // Save the logical device
102 if added := agent.clusterDataProxy.AddWithID("/logical_devices", ld.Id, ld, ""); added == nil {
103 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
104 } else {
105 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
106 }
107 agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400108
109 // TODO: Set the NNI ports in a separate call once the port update issue is fixed.
110 go agent.setupNNILogicalPorts(ctx, agent.rootDeviceId)
khenaidoo297cd252019-02-07 22:10:23 -0500111 } else {
112 // load from dB - the logical may not exist at this time. On error, just return and the calling function
113 // will destroy this agent.
114 var err error
115 if ld, err = agent.GetLogicalDevice(); err != nil {
116 log.Warnw("failed-to-load-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
117 return err
118 }
khenaidoo8c3303d2019-02-13 14:59:39 -0500119 // Update the root device Id
120 agent.rootDeviceId = ld.RootDeviceId
khenaidoob9203542018-09-17 22:56:37 -0400121 }
khenaidoo92e62c52018-10-03 14:02:54 -0400122 agent.lockLogicalDevice.Lock()
khenaidoofc1314d2019-03-14 09:34:21 -0400123
khenaidoo43c82122018-11-22 18:38:28 -0500124 agent.flowProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400125 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
126 false)
khenaidoo43c82122018-11-22 18:38:28 -0500127 agent.groupProxy = agent.clusterDataProxy.Root.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400128 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
129 false)
khenaidoofc1314d2019-03-14 09:34:21 -0400130 agent.ldProxy = agent.clusterDataProxy.Root.CreateProxy(
131 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceId),
132 false)
khenaidoo19d7b632018-10-30 10:49:50 -0400133
134 agent.flowProxy.RegisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
khenaidoo43c82122018-11-22 18:38:28 -0500135 agent.groupProxy.RegisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
khenaidoo19d7b632018-10-30 10:49:50 -0400136
khenaidoofc1314d2019-03-14 09:34:21 -0400137 // TODO: Use a port proxy once the POST_ADD is fixed
138 agent.ldProxy.RegisterCallback(model.POST_UPDATE, agent.portUpdated)
khenaidoobcf205b2019-01-25 22:21:14 -0500139
khenaidoofc1314d2019-03-14 09:34:21 -0400140 agent.lockLogicalDevice.Unlock()
khenaidoobcf205b2019-01-25 22:21:14 -0500141
khenaidoob9203542018-09-17 22:56:37 -0400142 return nil
143}
144
khenaidoo4d4802d2018-10-04 21:59:49 -0400145// stop stops the logical devuce agent. This removes the logical device from the data model.
146func (agent *LogicalDeviceAgent) stop(ctx context.Context) {
147 log.Info("stopping-logical_device-agent")
148 agent.lockLogicalDevice.Lock()
149 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500150
151 // Unregister to teh callbacks
152 if agent.flowProxy != nil {
153 agent.flowProxy.UnregisterCallback(model.POST_UPDATE, agent.flowTableUpdated)
154 }
155 if agent.groupProxy != nil {
156 agent.groupProxy.UnregisterCallback(model.POST_UPDATE, agent.groupTableUpdated)
157 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400158 //Remove the logical device from the model
159 if removed := agent.clusterDataProxy.Remove("/logical_devices/"+agent.logicalDeviceId, ""); removed == nil {
160 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
161 } else {
162 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
163 }
164 agent.exitChannel <- 1
165 log.Info("logical_device-agent-stopped")
166}
167
khenaidoo19d7b632018-10-30 10:49:50 -0400168// GetLogicalDevice locks the logical device model and then retrieves the latest logical device information
169func (agent *LogicalDeviceAgent) GetLogicalDevice() (*voltha.LogicalDevice, error) {
170 log.Debug("GetLogicalDevice")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400171 agent.lockLogicalDevice.RLock()
172 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500173 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400174 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500175 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400176 }
177 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
178}
179
khenaidoo19d7b632018-10-30 10:49:50 -0400180func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() (*voltha.LogicalPorts, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400181 log.Debug("ListLogicalDevicePorts")
182 agent.lockLogicalDevice.RLock()
183 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500184 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400185 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
186 lPorts := make([]*voltha.LogicalPort, 0)
187 for _, port := range lDevice.Ports {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500188 lPorts = append(lPorts, port)
khenaidoo19d7b632018-10-30 10:49:50 -0400189 }
190 return &voltha.LogicalPorts{Items: lPorts}, nil
191 }
192 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
193}
194
195// listFlows locks the logical device model and then retrieves the latest flow information
196func (agent *LogicalDeviceAgent) listFlows() []*ofp.OfpFlowStats {
197 log.Debug("listFlows")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400198 agent.lockLogicalDevice.RLock()
199 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500200 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400201 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
202 return lDevice.Flows.Items
203 }
204 return nil
205}
206
207// listFlowGroups locks the logical device model and then retrieves the latest flow groups information
208func (agent *LogicalDeviceAgent) listFlowGroups() []*ofp.OfpGroupEntry {
209 log.Debug("listFlowGroups")
khenaidoo1ce37ad2019-03-24 22:07:24 -0400210 agent.lockLogicalDevice.RLock()
211 defer agent.lockLogicalDevice.RUnlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500212 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo19d7b632018-10-30 10:49:50 -0400213 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
214 return lDevice.FlowGroups.Items
215 }
216 return nil
217}
218
khenaidoo43c82122018-11-22 18:38:28 -0500219//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
220func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(flows *ofp.Flows) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500221 afterUpdate := agent.flowProxy.Update("/", flows, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500222 if afterUpdate == nil {
223 return status.Errorf(codes.Internal, "failed-updating-logical-device-flows:%s", agent.logicalDeviceId)
224 }
khenaidoo43c82122018-11-22 18:38:28 -0500225 return nil
226}
227
228//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
229func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(flowGroups *ofp.FlowGroups) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500230 afterUpdate := agent.groupProxy.Update("/", flowGroups, false, "")
khenaidoo43c82122018-11-22 18:38:28 -0500231 if afterUpdate == nil {
232 return status.Errorf(codes.Internal, "failed-updating-logical-device-flow-groups:%s", agent.logicalDeviceId)
233 }
khenaidoo43c82122018-11-22 18:38:28 -0500234 return nil
235}
236
khenaidoo4d4802d2018-10-04 21:59:49 -0400237// getLogicalDeviceWithoutLock retrieves a logical device from the model without locking it. This is used only by
238// functions that have already acquired the logical device lock to the model
khenaidoo92e62c52018-10-03 14:02:54 -0400239func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() (*voltha.LogicalDevice, error) {
240 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo8c3303d2019-02-13 14:59:39 -0500241 logicalDevice := agent.clusterDataProxy.Get("/logical_devices/"+agent.logicalDeviceId, 0, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400242 if lDevice, ok := logicalDevice.(*voltha.LogicalDevice); ok {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400243 //log.Debug("getLogicalDeviceWithoutLock", log.Fields{"ldevice": lDevice})
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500244 return lDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400245 }
246 return nil, status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceId)
247}
248
khenaidoofc1314d2019-03-14 09:34:21 -0400249
250func (agent *LogicalDeviceAgent) addLogicalPort (device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400251 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
252 var changed bool
253 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400254 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo8f474192019-04-03 17:20:44 -0400255 if changed, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400256 return err
257 }
258 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo8f474192019-04-03 17:20:44 -0400259 if changed, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400260 return err
261 }
262 } else {
263 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
264 return nil
265 }
khenaidoo8f474192019-04-03 17:20:44 -0400266 if changed {
267 go agent.setupDeviceGraph()
268 }
khenaidoofc1314d2019-03-14 09:34:21 -0400269 return nil
270}
271
272// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
273func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
khenaidoo8f474192019-04-03 17:20:44 -0400274 //now := time.Now()
275 //defer fmt.Println("setupNNILogicalPorts:", deviceId, time.Since(now))
khenaidoofc1314d2019-03-14 09:34:21 -0400276 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400277 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400278 var err error
279
280 var device *voltha.Device
281 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
282 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": device.Id})
283 return err
284 }
285
286 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400287 changesMade := false
288 for _, port := range device.Ports {
khenaidoo8f474192019-04-03 17:20:44 -0400289 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -0400290 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo8f474192019-04-03 17:20:44 -0400291 if changed, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400292 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
293 } else {
khenaidoo8f474192019-04-03 17:20:44 -0400294 changesMade = changed || changesMade
khenaidoofc1314d2019-03-14 09:34:21 -0400295 }
khenaidoofc1314d2019-03-14 09:34:21 -0400296 }
297 }
298 if changesMade {
299 go agent.setupDeviceGraph()
300 }
301 return err
302}
303
304
305// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
306func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo8f474192019-04-03 17:20:44 -0400307 //now := time.Now()
308 //defer fmt.Println("setupUNILogicalPorts:", childDevice.Id, time.Since(now))
khenaidoofc1314d2019-03-14 09:34:21 -0400309 log.Infow("setupUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
310 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400311 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400312
313 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400314 changesMade := false
khenaidoo19d7b632018-10-30 10:49:50 -0400315 for _, port := range childDevice.Ports {
khenaidoo8f474192019-04-03 17:20:44 -0400316 changed := false
khenaidoo19d7b632018-10-30 10:49:50 -0400317 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo8f474192019-04-03 17:20:44 -0400318 if changed, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400319 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
320 } else {
khenaidoo8f474192019-04-03 17:20:44 -0400321 changesMade = changed || changesMade
khenaidoofc1314d2019-03-14 09:34:21 -0400322 }
khenaidoo19d7b632018-10-30 10:49:50 -0400323 }
324 }
khenaidoofc1314d2019-03-14 09:34:21 -0400325 if changesMade {
326 go agent.setupDeviceGraph()
khenaidoob9203542018-09-17 22:56:37 -0400327 }
khenaidoofc1314d2019-03-14 09:34:21 -0400328 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400329}
330
331//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
332func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500333 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400334 if afterUpdate == nil {
335 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
336 }
337 return nil
338}
339
khenaidoo19d7b632018-10-30 10:49:50 -0400340//updateFlowTable updates the flow table of that logical device
341func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
342 log.Debug("updateFlowTable")
343 if flow == nil {
344 return nil
345 }
346 switch flow.GetCommand() {
347 case ofp.OfpFlowModCommand_OFPFC_ADD:
348 return agent.flowAdd(flow)
349 case ofp.OfpFlowModCommand_OFPFC_DELETE:
350 return agent.flowDelete(flow)
351 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
352 return agent.flowDeleteStrict(flow)
353 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
354 return agent.flowModify(flow)
355 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
356 return agent.flowModifyStrict(flow)
357 }
358 return status.Errorf(codes.Internal,
359 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
360}
361
362//updateGroupTable updates the group table of that logical device
363func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
364 log.Debug("updateGroupTable")
365 if groupMod == nil {
366 return nil
367 }
368 switch groupMod.GetCommand() {
369 case ofp.OfpGroupModCommand_OFPGC_ADD:
370 return agent.groupAdd(groupMod)
371 case ofp.OfpGroupModCommand_OFPGC_DELETE:
372 return agent.groupDelete(groupMod)
373 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
374 return agent.groupModify(groupMod)
375 }
376 return status.Errorf(codes.Internal,
377 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
378}
379
khenaidoo19d7b632018-10-30 10:49:50 -0400380//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
381//must only be called by a function that is holding the lock on the logical device
382func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
khenaidoo43c82122018-11-22 18:38:28 -0500383 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
384 copy(groupsCloned, groups)
385 if afterUpdate := agent.groupProxy.Update("/", groupsCloned, true, ""); afterUpdate == nil {
386 return errors.New(fmt.Sprintf("update-flow-group-failed:%s", agent.logicalDeviceId))
khenaidoo19d7b632018-10-30 10:49:50 -0400387 }
khenaidoo43c82122018-11-22 18:38:28 -0500388 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400389}
390
391//flowAdd adds a flow to the flow table of that logical device
392func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
393 log.Debug("flowAdd")
394 if mod == nil {
395 return nil
396 }
khenaidoo92e62c52018-10-03 14:02:54 -0400397 agent.lockLogicalDevice.Lock()
398 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400399
400 var lDevice *voltha.LogicalDevice
401 var err error
402 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
403 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
404 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
405 }
406
407 var flows []*ofp.OfpFlowStats
408 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
409 flows = lDevice.Flows.Items
410 }
411
khenaidoo43c82122018-11-22 18:38:28 -0500412 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400413 changed := false
414 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
415 if checkOverlap {
416 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
417 // TODO: should this error be notified other than being logged?
418 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
419 } else {
420 // Add flow
421 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
422 flows = append(flows, flow)
423 changed = true
424 }
425 } else {
426 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
427 idx := fu.FindFlows(flows, flow)
428 if idx >= 0 {
429 oldFlow := flows[idx]
430 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
431 flow.ByteCount = oldFlow.ByteCount
432 flow.PacketCount = oldFlow.PacketCount
433 }
434 flows[idx] = flow
435 } else {
436 flows = append(flows, flow)
437 }
438 changed = true
439 }
440 if changed {
441 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500442 flowsToUpdate := &ofp.Flows{}
443 if lDevice.Flows != nil {
444 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400445 }
khenaidoo43c82122018-11-22 18:38:28 -0500446 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
447 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400448 return err
449 }
450 }
khenaidoo19d7b632018-10-30 10:49:50 -0400451 return nil
452}
453
454//flowDelete deletes a flow from the flow table of that logical device
455func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
456 log.Debug("flowDelete")
457 if mod == nil {
458 return nil
459 }
460 agent.lockLogicalDevice.Lock()
461 defer agent.lockLogicalDevice.Unlock()
462
463 var lDevice *voltha.LogicalDevice
464 var err error
465 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
466 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
467 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
468 }
469 flows := lDevice.Flows.Items
470
471 //build a list of what to keep vs what to delete
472 toKeep := make([]*ofp.OfpFlowStats, 0)
473 for _, f := range flows {
474 if !fu.FlowMatchesMod(f, mod) {
475 toKeep = append(toKeep, f)
476 }
477 }
478
479 //Update flows
480 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500481 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
482 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400483 return err
484 }
485 }
486
487 //TODO: send announcement on delete
488 return nil
489}
490
491//flowStatsDelete deletes a flow from the flow table of that logical device
492func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
493 log.Debug("flowStatsDelete")
494 if flow == nil {
495 return nil
496 }
497 agent.lockLogicalDevice.Lock()
498 defer agent.lockLogicalDevice.Unlock()
499
500 var lDevice *voltha.LogicalDevice
501 var err error
502 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
503 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
504 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
505 }
506 flows := lDevice.Flows.Items
507
508 //build a list of what to keep vs what to delete
509 toKeep := make([]*ofp.OfpFlowStats, 0)
510 for _, f := range flows {
511 if !fu.FlowMatch(f, flow) {
512 toKeep = append(toKeep, f)
513 }
514 }
515
516 //Update flows
517 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500518 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400519 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
520 return err
521 }
522 }
523 return nil
524}
525
526//flowDeleteStrict deletes a flow from the flow table of that logical device
527func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
528 log.Debug("flowDeleteStrict")
529 if mod == nil {
530 return nil
531 }
532 agent.lockLogicalDevice.Lock()
533 defer agent.lockLogicalDevice.Unlock()
534
535 var lDevice *voltha.LogicalDevice
536 var err error
537 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
538 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
539 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
540 }
541 flows := lDevice.Flows.Items
542 changed := false
543 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
544 idx := fu.FindFlows(flows, flow)
545 if idx >= 0 {
546 flows = append(flows[:idx], flows[idx+1:]...)
547 changed = true
548 } else {
549 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
550 }
551
552 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500553 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400554 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
555 return err
556 }
557 }
558
559 return nil
560}
561
562//flowModify modifies a flow from the flow table of that logical device
563func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
564 return errors.New("flowModify not implemented")
565}
566
567//flowModifyStrict deletes a flow from the flow table of that logical device
568func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
569 return errors.New("flowModifyStrict not implemented")
570}
571
572func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
573 log.Debug("groupAdd")
574 if groupMod == nil {
575 return nil
576 }
577 agent.lockLogicalDevice.Lock()
578 defer agent.lockLogicalDevice.Unlock()
579
580 var lDevice *voltha.LogicalDevice
581 var err error
582 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
583 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
584 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
585 }
586 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400587 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
588 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500589 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
590 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400591 return err
592 }
593 } else {
594 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
595 }
khenaidoo19d7b632018-10-30 10:49:50 -0400596 return nil
597}
598
599func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
600 log.Debug("groupDelete")
601 if groupMod == nil {
602 return nil
603 }
604 agent.lockLogicalDevice.Lock()
605 defer agent.lockLogicalDevice.Unlock()
606
607 var lDevice *voltha.LogicalDevice
608 var err error
609 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
610 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
611 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
612 }
613 groups := lDevice.FlowGroups.Items
614 flows := lDevice.Flows.Items
615 groupsChanged := false
616 flowsChanged := false
617 groupId := groupMod.GroupId
618 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
619 //TODO we must delete all flows that point to this group and
620 //signal controller as requested by flow's flag
621 groups = []*ofp.OfpGroupEntry{}
622 groupsChanged = true
623 } else {
624 if idx := fu.FindGroup(groups, groupId); idx == -1 {
625 return nil // Valid case
626 } else {
627 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
628 groups = append(groups[:idx], groups[idx+1:]...)
629 groupsChanged = true
630 }
631 }
khenaidoo43c82122018-11-22 18:38:28 -0500632 if groupsChanged {
633 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
634 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400635 return err
636 }
637 }
khenaidoo43c82122018-11-22 18:38:28 -0500638 if flowsChanged {
639 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
640 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
641 return err
642 }
643 }
644
khenaidoo19d7b632018-10-30 10:49:50 -0400645 return nil
646}
647
648func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
649 log.Debug("groupModify")
650 if groupMod == nil {
651 return nil
652 }
653 agent.lockLogicalDevice.Lock()
654 defer agent.lockLogicalDevice.Unlock()
655
656 var lDevice *voltha.LogicalDevice
657 var err error
658 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
659 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
660 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
661 }
662 groups := lDevice.FlowGroups.Items
663 groupsChanged := false
664 groupId := groupMod.GroupId
665 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500666 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400667 } else {
668 //replace existing group entry with new group definition
669 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
670 groups[idx] = groupEntry
671 groupsChanged = true
672 }
673 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500674 //lDevice.FlowGroups.Items = groups
675 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400676 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
677 return err
678 }
679 }
680 return nil
681}
682
683// deleteLogicalPort removes the logical port
684func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
685 agent.lockLogicalDevice.Lock()
686 defer agent.lockLogicalDevice.Unlock()
687
khenaidoo92e62c52018-10-03 14:02:54 -0400688 // Get the most up to date logical device
689 var logicaldevice *voltha.LogicalDevice
690 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400691 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400692 return nil
693 }
khenaidoo92e62c52018-10-03 14:02:54 -0400694 index := -1
695 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400696 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400697 index = i
698 break
699 }
700 }
701 if index >= 0 {
702 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
703 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
704 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
705 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
706 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
707 }
708 return nil
khenaidoob9203542018-09-17 22:56:37 -0400709}
710
khenaidoo19d7b632018-10-30 10:49:50 -0400711// enableLogicalPort enables the logical port
712func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
713 agent.lockLogicalDevice.Lock()
714 defer agent.lockLogicalDevice.Unlock()
715
716 // Get the most up to date logical device
717 var logicaldevice *voltha.LogicalDevice
718 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
719 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
720 return nil
721 }
722 index := -1
723 for i, logicalPort := range logicaldevice.Ports {
724 if logicalPort.Id == lPort.Id {
725 index = i
726 break
727 }
728 }
729 if index >= 0 {
730 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
731 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
732 }
733 //TODO: Trigger subsequent actions on the device
734 return nil
735}
736
737// disableLogicalPort disabled the logical port
738func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
739 agent.lockLogicalDevice.Lock()
740 defer agent.lockLogicalDevice.Unlock()
741
742 // Get the most up to date logical device
743 var logicaldevice *voltha.LogicalDevice
744 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
745 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
746 return nil
747 }
748 index := -1
749 for i, logicalPort := range logicaldevice.Ports {
750 if logicalPort.Id == lPort.Id {
751 index = i
752 break
753 }
754 }
755 if index >= 0 {
756 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
757 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
758 }
759 //TODO: Trigger subsequent actions on the device
760 return nil
761}
762
khenaidoo89b0e942018-10-21 21:11:33 -0400763func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
764 for _, pNo := range nniPortsNo {
765 if pNo == portNo {
766 return true
767 }
768 }
769 return false
770}
khenaidoo4d4802d2018-10-04 21:59:49 -0400771
khenaidoo89b0e942018-10-21 21:11:33 -0400772func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400773 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400774 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400775 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400776 if ingress == routeLink.Ingress && egress == routeLink.Egress {
777 return route
778 }
779 }
780 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
781 return nil
782}
783
khenaidoo19d7b632018-10-30 10:49:50 -0400784func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400785 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
786 // Get the updated logical device
khenaidoo79232702018-12-04 11:00:41 -0500787 var ld *ic.LogicalDevice
khenaidoo89b0e942018-10-21 21:11:33 -0400788 routes := make([]graph.RouteHop, 0)
789 var err error
790 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
791 return nil
792 }
793 nniLogicalPortsNo := make([]uint32, 0)
794 for _, logicalPort := range ld.Ports {
795 if logicalPort.RootPort {
796 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
797 }
798 }
799 if len(nniLogicalPortsNo) == 0 {
800 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
801 return nil
802 }
khenaidoo19d7b632018-10-30 10:49:50 -0400803 // Note: A port value of 0 is equivalent to a nil port
804
khenaidoo89b0e942018-10-21 21:11:33 -0400805 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400806 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400807 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400808 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400809 log.Debug("returning-half-route")
810 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -0400811 if len(agent.deviceGraph.Routes) == 0 {
812 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
813 // internal route
814 hop := graph.RouteHop{DeviceID:ld.RootDeviceId, Ingress:ingressPortNo, Egress:egressPortNo}
815 routes = append(routes, hop)
816 routes = append(routes, hop)
817 return routes
818 }
khenaidoo89b0e942018-10-21 21:11:33 -0400819 //Return a 'half' route to make the flow decomposer logic happy
820 for routeLink, route := range agent.deviceGraph.Routes {
821 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
822 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
823 routes = append(routes, route[1])
824 return routes
825 }
826 }
827 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
828 return nil
829 }
830 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400831 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400832 }
833 //If ingress port is not specified (nil), it may be a wildcarded
834 //route if egress port is OFPP_CONTROLLER or a nni logical port,
835 //in which case we need to create a half-route where only the egress
836 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400837 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400838 // We can use the 2nd hop of any upstream route, so just find the first upstream:
839 for routeLink, route := range agent.deviceGraph.Routes {
840 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
841 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
842 routes = append(routes, route[1])
843 return routes
844 }
845 }
846 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
847 return nil
848 }
849 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400850 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400851 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400852 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400853 routes = append(routes, route[0])
854 routes = append(routes, graph.RouteHop{})
855 return routes
856 }
857 }
858 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
859 return nil
860 }
861
862 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400863 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400864}
865
866// updateRoutes updates the device routes whenever there is a device or port changes relevant to this
867// logical device. TODO: Add more heuristics to this process to update the routes where a change has occurred
868// instead of rebuilding the entire set of routes
869func (agent *LogicalDeviceAgent) updateRoutes() {
khenaidoo19d7b632018-10-30 10:49:50 -0400870 if ld, err := agent.GetLogicalDevice(); err == nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400871 agent.deviceGraph.ComputeRoutes(ld.Ports)
872 }
873}
874
875func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
876 return fu.NewFlowsAndGroups()
877}
878
879func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
880 fg := fu.NewFlowsAndGroups()
881 var device *voltha.Device
882 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400883 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400884 return fg
885 }
886 //set the upstream and downstream ports
887 upstreamPorts := make([]*voltha.Port, 0)
888 downstreamPorts := make([]*voltha.Port, 0)
889 for _, port := range device.Ports {
890 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
891 upstreamPorts = append(upstreamPorts, port)
892 } else if port.Type == voltha.Port_ETHERNET_UNI {
893 downstreamPorts = append(downstreamPorts, port)
894 }
895 }
896 //it is possible that the downstream ports are not created, but the flow_decomposition has already
897 //kicked in. In such scenarios, cut short the processing and return.
khenaidoo6d055132019-02-12 16:51:19 -0500898 if len(downstreamPorts) == 0 || len(upstreamPorts) == 0{
khenaidoo89b0e942018-10-21 21:11:33 -0400899 return fg
900 }
901 // set up the default flows
902 var fa *fu.FlowArgs
903 fa = &fu.FlowArgs{
904 KV: fu.OfpFlowModArgs{"priority": 500},
905 MatchFields: []*ofp.OfpOxmOfbField{
906 fd.InPort(downstreamPorts[0].PortNo),
907 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
908 },
909 Actions: []*ofp.OfpAction{
910 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400911 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400912 },
913 }
914 fg.AddFlow(fd.MkFlowStat(fa))
915
916 fa = &fu.FlowArgs{
917 KV: fu.OfpFlowModArgs{"priority": 500},
918 MatchFields: []*ofp.OfpOxmOfbField{
919 fd.InPort(downstreamPorts[0].PortNo),
920 fd.VlanVid(0),
921 },
922 Actions: []*ofp.OfpAction{
923 fd.PushVlan(0x8100),
924 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
925 fd.Output(upstreamPorts[0].PortNo),
926 },
927 }
928 fg.AddFlow(fd.MkFlowStat(fa))
929
930 fa = &fu.FlowArgs{
931 KV: fu.OfpFlowModArgs{"priority": 500},
932 MatchFields: []*ofp.OfpOxmOfbField{
933 fd.InPort(upstreamPorts[0].PortNo),
934 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
935 },
936 Actions: []*ofp.OfpAction{
937 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
938 fd.Output(downstreamPorts[0].PortNo),
939 },
940 }
941 fg.AddFlow(fd.MkFlowStat(fa))
942
943 return fg
944}
945
946func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
947 rules := fu.NewDeviceRules()
948 var ld *voltha.LogicalDevice
949 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400950 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400951 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
952 return rules
953 }
954
955 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
khenaidooca301322019-01-09 23:06:32 -0500956 for deviceId := range deviceNodeIds {
khenaidoo89b0e942018-10-21 21:11:33 -0400957 if deviceId == ld.RootDeviceId {
958 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
959 } else {
960 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
961 }
962 }
963 return rules
964}
965
966func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
967 // Get latest
968 var lDevice *voltha.LogicalDevice
969 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400970 if lDevice, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400971 return fu.NewDeviceRules()
972 }
973 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo19d7b632018-10-30 10:49:50 -0400974 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
khenaidoo89b0e942018-10-21 21:11:33 -0400975 agent.deviceGraph.ComputeRoutes(lDevice.Ports)
976 agent.DefaultFlowRules = agent.generateDefaultRules()
977 }
978 return agent.DefaultFlowRules
979}
980
981func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
982 lPorts := make([]uint32, 0)
983 var exclPort uint32
984 if len(excludePort) == 1 {
985 exclPort = excludePort[0]
986 }
khenaidoo19d7b632018-10-30 10:49:50 -0400987 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400988 for _, port := range lDevice.Ports {
989 if port.OfpPort.PortNo != exclPort {
990 lPorts = append(lPorts, port.OfpPort.PortNo)
991 }
992 }
993 }
994 return lPorts
995}
khenaidoo19d7b632018-10-30 10:49:50 -0400996
997func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
998 return agent.deviceGraph
999}
1000
1001//setupDeviceGraph creates the device graph if not done already
1002func (agent *LogicalDeviceAgent) setupDeviceGraph() {
1003 if agent.deviceGraph == nil {
1004 agent.deviceGraph = graph.NewDeviceGraph(agent.deviceMgr.GetDevice)
1005 agent.updateRoutes()
1006 }
1007}
1008
1009func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
1010 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
1011
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001012 var previousData *ofp.Flows
1013 var latestData *ofp.Flows
khenaidoo19d7b632018-10-30 10:49:50 -04001014
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001015 var ok bool
1016 if previousData, ok = args[0].(*ofp.Flows); !ok {
1017 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1018 }
1019 if latestData, ok = args[1].(*ofp.Flows); !ok {
1020 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1021 }
khenaidoo19d7b632018-10-30 10:49:50 -04001022
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001023 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1024 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -04001025 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001026 }
1027
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001028 var groups *ofp.FlowGroups
1029 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1030 groups = lDevice.FlowGroups
1031 log.Debugw("flowsinfo", log.Fields{"flows": latestData, "groups": groups})
1032 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *latestData, *groups)
1033 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1034
khenaidooca301322019-01-09 23:06:32 -05001035 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001036 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -05001037 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
1038 log.Error("update-flows-failed", log.Fields{"deviceID":deviceId})
1039 }
1040 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
1041 log.Error("update-groups-failed", log.Fields{"deviceID":deviceId})
1042 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001043 }
khenaidoo19d7b632018-10-30 10:49:50 -04001044
khenaidoo19d7b632018-10-30 10:49:50 -04001045 return nil
1046}
1047
1048func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
1049 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
1050
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001051 var previousData *ofp.FlowGroups
1052 var latestData *ofp.FlowGroups
khenaidoo19d7b632018-10-30 10:49:50 -04001053
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001054 var ok bool
1055 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
1056 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1057 }
1058 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
1059 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1060 }
khenaidoo19d7b632018-10-30 10:49:50 -04001061
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001062 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1063 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -04001064 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001065 }
1066
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001067 var flows *ofp.Flows
1068 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1069 flows = lDevice.Flows
1070 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
1071 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
1072 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidooca301322019-01-09 23:06:32 -05001073 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001074 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -05001075 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
1076 log.Error("update-flows-failed", log.Fields{"deviceID":deviceId})
1077 }
1078 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
1079 log.Error("update-groups-failed", log.Fields{"deviceID":deviceId})
1080 }
khenaidoo19d7b632018-10-30 10:49:50 -04001081
khenaidooca301322019-01-09 23:06:32 -05001082 }
khenaidoo19d7b632018-10-30 10:49:50 -04001083 return nil
1084}
khenaidoofdbad6e2018-11-06 22:26:38 -05001085
khenaidoofc1314d2019-03-14 09:34:21 -04001086// portAdded is a callback invoked when a port is added to the logical device.
1087// TODO: To use when POST_ADD is fixed.
1088func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1089 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1090
1091 var port *voltha.LogicalPort
1092
1093 // Sanity check
1094 if args[0] != nil {
1095 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1096 }
1097 var ok bool
1098 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1099 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1100 return nil
1101 }
1102
1103 // Set the proxy and callback for that port
1104 agent.portProxiesLock.Lock()
1105 agent.portProxies[port.Id] = agent.clusterDataProxy.Root.CreateProxy(
1106 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1107 false)
1108 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1109 agent.portProxiesLock.Unlock()
1110
1111 // Send the port change event to the OF controller
1112 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
1113 &ofp.OfpPortStatus{Reason:ofp.OfpPortReason_OFPPR_ADD, Desc:port.OfpPort})
1114
1115 return nil
1116}
1117
1118// portRemoved is a callback invoked when a port is removed from the logical device.
1119// TODO: To use when POST_ADD is fixed.
1120func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1121 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1122
1123 var port *voltha.LogicalPort
1124
1125 // Sanity check
1126 if args[1] != nil {
1127 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1128 }
1129 var ok bool
1130 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1131 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1132 return nil
1133 }
1134
1135 // Remove the proxy and callback for that port
1136 agent.portProxiesLock.Lock()
1137 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1138 delete(agent.portProxies, port.Id)
1139 agent.portProxiesLock.Unlock()
1140
1141 // Send the port change event to the OF controller
1142 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
1143 &ofp.OfpPortStatus{Reason:ofp.OfpPortReason_OFPPR_DELETE, Desc:port.OfpPort})
1144
1145 return nil
1146}
1147
1148// diff go over two lists of logical ports and return what's new, what's changed and what's removed.
1149func diff(oldList , newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
1150 newPorts = make([]*voltha.LogicalPort, 0)
1151 changedPorts = make([]*voltha.LogicalPort, 0)
1152 deletedPorts = make([]*voltha.LogicalPort, 0)
1153 for _, o := range oldList {
1154 found := false
1155 changed := false
1156 for _, n := range newList {
1157 if o.Id == n.Id {
1158 changed = !reflect.DeepEqual(o, n)
1159 found = true
1160 break
1161 }
1162 }
1163 if !found {
1164 deletedPorts = append(deletedPorts, o)
1165 }
1166 if changed {
1167 changedPorts = append(changedPorts, o)
1168 }
1169 }
1170 for _, n := range newList {
1171 found := false
1172 for _, o := range oldList {
1173 if o.Id == n.Id {
1174 found = true
1175 break
1176 }
1177 }
1178 if !found {
1179 newPorts = append(newPorts, n)
1180 }
1181 }
1182 return
1183}
1184
1185// portUpdated is invoked when a port is updated on the logical device. Until
1186// the POST_ADD notification is fixed, we will use the logical device to
1187// update that data.
1188func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1189 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1190
1191 var oldLD *voltha.LogicalDevice
1192 var newlD *voltha.LogicalDevice
1193
1194 var ok bool
1195 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1196 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1197 return nil
1198 }
1199 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1200 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1201 return nil
1202 }
1203
1204 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1205 log.Debug("ports-have-not-changed")
1206 return nil
1207 }
1208
1209 // Get the difference between the two list
1210 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1211
1212 // Send the port change events to the OF controller
1213 for _, new := range newPorts {
1214 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
1215 &ofp.OfpPortStatus{Reason:ofp.OfpPortReason_OFPPR_ADD, Desc:new.OfpPort})
1216 }
1217 for _, change := range changedPorts {
1218 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
1219 &ofp.OfpPortStatus{Reason:ofp.OfpPortReason_OFPPR_MODIFY, Desc:change.OfpPort})
1220 }
1221 for _, del := range deletedPorts {
1222 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
1223 &ofp.OfpPortStatus{Reason:ofp.OfpPortReason_OFPPR_DELETE, Desc:del.OfpPort})
1224 }
1225
1226 return nil
1227}
1228
1229
khenaidoo8f474192019-04-03 17:20:44 -04001230// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1231// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1232// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1233// scenario. This also applies to the case where the port was already added.
1234func (agent *LogicalDeviceAgent) addNNILogicalPort (device *voltha.Device, port *voltha.Port) (bool, error) {
1235 //now := time.Now()
1236 //defer fmt.Println("setupNNILogicalPorts:", device.Id, time.Since(now))
khenaidoo1ce37ad2019-03-24 22:07:24 -04001237 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001238 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1239 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1240 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001241 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001242 agent.lockLogicalDevice.RLock()
1243 if agent.portExist(device, port) {
1244 log.Debugw("port-already-exist", log.Fields{"port": port})
1245 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001246 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001247 }
1248 agent.lockLogicalDevice.RUnlock()
1249
khenaidoofc1314d2019-03-14 09:34:21 -04001250 var portCap *ic.PortCapability
1251 var err error
1252 // First get the port capability
1253 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1254 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001255 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001256 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001257
1258 agent.lockLogicalDevice.Lock()
1259 defer agent.lockLogicalDevice.Unlock()
1260 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1261 if agent.portExist(device, port) {
1262 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001263 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001264 }
1265
khenaidoofc1314d2019-03-14 09:34:21 -04001266 portCap.Port.RootPort = true
1267 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1268 lp.DeviceId = device.Id
1269 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1270 lp.OfpPort.PortNo = port.PortNo
1271 lp.OfpPort.Name = lp.Id
1272 lp.DevicePortNo = port.PortNo
1273
khenaidoofc1314d2019-03-14 09:34:21 -04001274 var ld *voltha.LogicalDevice
1275 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1276 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001277 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001278 }
1279 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1280 if cloned.Ports == nil {
1281 cloned.Ports = make([]*voltha.LogicalPort, 0)
1282 }
1283 cloned.Ports = append(cloned.Ports, lp)
1284
1285 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1286 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001287 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001288 }
khenaidoo8f474192019-04-03 17:20:44 -04001289 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001290}
1291
1292func (agent *LogicalDeviceAgent) portExist (device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001293 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001294 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001295 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001296 return true
1297 }
1298 }
1299 }
1300 return false
1301}
1302
khenaidoo8f474192019-04-03 17:20:44 -04001303
1304// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1305// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1306// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1307// scenario. This also applies to the case where the port was already added.
1308func (agent *LogicalDeviceAgent) addUNILogicalPort (childDevice *voltha.Device, port *voltha.Port) (bool, error) {
1309 //now := time.Now()
1310 //defer fmt.Println("addUNILogicalPort:", childDevice.Id, time.Since(now))
khenaidoofc1314d2019-03-14 09:34:21 -04001311 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001312 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1313 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1314 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001315 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001316 agent.lockLogicalDevice.RLock()
1317 if agent.portExist(childDevice, port) {
1318 log.Debugw("port-already-exist", log.Fields{"port": port})
1319 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001320 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001321 }
1322 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001323 var portCap *ic.PortCapability
1324 var err error
1325 // First get the port capability
1326 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1327 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001328 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001329 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001330 agent.lockLogicalDevice.Lock()
1331 defer agent.lockLogicalDevice.Unlock()
1332 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1333 if agent.portExist(childDevice, port) {
1334 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001335 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001336 }
khenaidoofc1314d2019-03-14 09:34:21 -04001337 // Get stored logical device
1338 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001339 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001340 } else {
1341 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1342 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001343 portCap.Port.Id = port.Label
1344 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoo1ce37ad2019-03-24 22:07:24 -04001345 portCap.Port.OfpPort.Name = childDevice.SerialNumber
khenaidoofc1314d2019-03-14 09:34:21 -04001346 portCap.Port.DeviceId = childDevice.Id
1347 portCap.Port.DevicePortNo = port.PortNo
1348 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1349 if cloned.Ports == nil {
1350 cloned.Ports = make([]*voltha.LogicalPort, 0)
1351 }
1352 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo8f474192019-04-03 17:20:44 -04001353 return true, agent.updateLogicalDeviceWithoutLock(cloned)
khenaidoofc1314d2019-03-14 09:34:21 -04001354 }
1355}
1356
khenaidoo43c82122018-11-22 18:38:28 -05001357func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001358 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1359 outPort := fd.GetPacketOutPort(packet)
1360 //frame := packet.GetData()
1361 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001362 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
1363 log.Error("packetout-failed", log.Fields{"logicalDeviceID":agent.rootDeviceId})
1364 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001365}
1366
khenaidoo297cd252019-02-07 22:10:23 -05001367func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1368 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidooca301322019-01-09 23:06:32 -05001369 packetIn := fd.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001370 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001371 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001372}