blob: 193ba9aee04546782726ceb76830aaa75f3dc467 [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 {
khenaidoo910204f2019-04-08 17:56:40 -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
khenaidoo910204f2019-04-08 17:56:40 -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
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400124 agent.flowProxy = agent.clusterDataProxy.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400125 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceId),
126 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400127 agent.groupProxy = agent.clusterDataProxy.CreateProxy(
khenaidoo19d7b632018-10-30 10:49:50 -0400128 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceId),
129 false)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400130 agent.ldProxy = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -0400131 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
khenaidoo910204f2019-04-08 17:56:40 -0400249func (agent *LogicalDeviceAgent) addLogicalPort(device *voltha.Device, port *voltha.Port) error {
khenaidoo8f474192019-04-03 17:20:44 -0400250 log.Debugw("addLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo8f474192019-04-03 17:20:44 -0400251 var err error
khenaidoofc1314d2019-03-14 09:34:21 -0400252 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400253 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400254 return err
255 }
256 } else if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400257 if _, err = agent.addUNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400258 return err
259 }
260 } else {
261 log.Debugw("invalid-port-type", log.Fields{"deviceId": device.Id, "port": port})
262 return nil
263 }
khenaidoofc1314d2019-03-14 09:34:21 -0400264 return nil
265}
266
267// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
268func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceId string) error {
khenaidoo8f474192019-04-03 17:20:44 -0400269 //now := time.Now()
270 //defer fmt.Println("setupNNILogicalPorts:", deviceId, time.Since(now))
khenaidoofc1314d2019-03-14 09:34:21 -0400271 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400272 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400273 var err error
274
275 var device *voltha.Device
276 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
277 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": device.Id})
278 return err
279 }
280
281 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400282 for _, port := range device.Ports {
283 if port.Type == voltha.Port_ETHERNET_NNI {
khenaidoo910204f2019-04-08 17:56:40 -0400284 if _, err = agent.addNNILogicalPort(device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400285 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400286 }
khenaidoofc1314d2019-03-14 09:34:21 -0400287 }
288 }
khenaidoofc1314d2019-03-14 09:34:21 -0400289 return err
290}
291
khenaidoofc1314d2019-03-14 09:34:21 -0400292// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
293func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
khenaidoo8f474192019-04-03 17:20:44 -0400294 //now := time.Now()
295 //defer fmt.Println("setupUNILogicalPorts:", childDevice.Id, time.Since(now))
khenaidoofc1314d2019-03-14 09:34:21 -0400296 log.Infow("setupUNILogicalPort-start", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
297 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400298 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400299
300 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400301 for _, port := range childDevice.Ports {
302 if port.Type == voltha.Port_ETHERNET_UNI {
khenaidoo910204f2019-04-08 17:56:40 -0400303 if _, err = agent.addUNILogicalPort(childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400304 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400305 }
khenaidoo19d7b632018-10-30 10:49:50 -0400306 }
307 }
khenaidoofc1314d2019-03-14 09:34:21 -0400308 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400309}
310
311//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
312func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(logicalDevice *voltha.LogicalDevice) error {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500313 afterUpdate := agent.clusterDataProxy.Update("/logical_devices/"+agent.logicalDeviceId, logicalDevice, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400314 if afterUpdate == nil {
315 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceId)
316 }
317 return nil
318}
319
khenaidoo19d7b632018-10-30 10:49:50 -0400320//updateFlowTable updates the flow table of that logical device
321func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
322 log.Debug("updateFlowTable")
323 if flow == nil {
324 return nil
325 }
326 switch flow.GetCommand() {
327 case ofp.OfpFlowModCommand_OFPFC_ADD:
328 return agent.flowAdd(flow)
329 case ofp.OfpFlowModCommand_OFPFC_DELETE:
330 return agent.flowDelete(flow)
331 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
332 return agent.flowDeleteStrict(flow)
333 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
334 return agent.flowModify(flow)
335 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
336 return agent.flowModifyStrict(flow)
337 }
338 return status.Errorf(codes.Internal,
339 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, flow.GetCommand())
340}
341
342//updateGroupTable updates the group table of that logical device
343func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
344 log.Debug("updateGroupTable")
345 if groupMod == nil {
346 return nil
347 }
348 switch groupMod.GetCommand() {
349 case ofp.OfpGroupModCommand_OFPGC_ADD:
350 return agent.groupAdd(groupMod)
351 case ofp.OfpGroupModCommand_OFPGC_DELETE:
352 return agent.groupDelete(groupMod)
353 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
354 return agent.groupModify(groupMod)
355 }
356 return status.Errorf(codes.Internal,
357 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceId, groupMod.GetCommand())
358}
359
khenaidoo19d7b632018-10-30 10:49:50 -0400360//updateFlowGroupsWithoutLock updates the flows in the logical device without locking the logical device. This function
361//must only be called by a function that is holding the lock on the logical device
362func (agent *LogicalDeviceAgent) updateFlowGroupsWithoutLock(groups []*ofp.OfpGroupEntry) error {
khenaidoo43c82122018-11-22 18:38:28 -0500363 groupsCloned := make([]*ofp.OfpGroupEntry, len(groups))
364 copy(groupsCloned, groups)
365 if afterUpdate := agent.groupProxy.Update("/", groupsCloned, true, ""); afterUpdate == nil {
366 return errors.New(fmt.Sprintf("update-flow-group-failed:%s", agent.logicalDeviceId))
khenaidoo19d7b632018-10-30 10:49:50 -0400367 }
khenaidoo43c82122018-11-22 18:38:28 -0500368 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400369}
370
371//flowAdd adds a flow to the flow table of that logical device
372func (agent *LogicalDeviceAgent) flowAdd(mod *ofp.OfpFlowMod) error {
373 log.Debug("flowAdd")
374 if mod == nil {
375 return nil
376 }
khenaidoo92e62c52018-10-03 14:02:54 -0400377 agent.lockLogicalDevice.Lock()
378 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400379
380 var lDevice *voltha.LogicalDevice
381 var err error
382 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
383 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
384 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
385 }
386
387 var flows []*ofp.OfpFlowStats
388 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
389 flows = lDevice.Flows.Items
390 }
391
khenaidoo43c82122018-11-22 18:38:28 -0500392 //oldData := proto.Clone(lDevice.Flows).(*voltha.Flows)
khenaidoo19d7b632018-10-30 10:49:50 -0400393 changed := false
394 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
395 if checkOverlap {
396 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
397 // TODO: should this error be notified other than being logged?
398 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
399 } else {
400 // Add flow
401 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
402 flows = append(flows, flow)
403 changed = true
404 }
405 } else {
406 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
407 idx := fu.FindFlows(flows, flow)
408 if idx >= 0 {
409 oldFlow := flows[idx]
410 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
411 flow.ByteCount = oldFlow.ByteCount
412 flow.PacketCount = oldFlow.PacketCount
413 }
414 flows[idx] = flow
415 } else {
416 flows = append(flows, flow)
417 }
418 changed = true
419 }
420 if changed {
421 // Update model
khenaidoo43c82122018-11-22 18:38:28 -0500422 flowsToUpdate := &ofp.Flows{}
423 if lDevice.Flows != nil {
424 flowsToUpdate = &ofp.Flows{Items: flows}
khenaidoo19d7b632018-10-30 10:49:50 -0400425 }
khenaidoo43c82122018-11-22 18:38:28 -0500426 if err := agent.updateLogicalDeviceFlowsWithoutLock(flowsToUpdate); err != nil {
427 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400428 return err
429 }
430 }
khenaidoo19d7b632018-10-30 10:49:50 -0400431 return nil
432}
433
434//flowDelete deletes a flow from the flow table of that logical device
435func (agent *LogicalDeviceAgent) flowDelete(mod *ofp.OfpFlowMod) error {
436 log.Debug("flowDelete")
437 if mod == nil {
438 return nil
439 }
440 agent.lockLogicalDevice.Lock()
441 defer agent.lockLogicalDevice.Unlock()
442
443 var lDevice *voltha.LogicalDevice
444 var err error
445 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
446 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
447 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
448 }
449 flows := lDevice.Flows.Items
450
451 //build a list of what to keep vs what to delete
452 toKeep := make([]*ofp.OfpFlowStats, 0)
453 for _, f := range flows {
454 if !fu.FlowMatchesMod(f, mod) {
455 toKeep = append(toKeep, f)
456 }
457 }
458
459 //Update flows
460 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500461 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
462 log.Errorw("Cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400463 return err
464 }
465 }
466
467 //TODO: send announcement on delete
468 return nil
469}
470
471//flowStatsDelete deletes a flow from the flow table of that logical device
472func (agent *LogicalDeviceAgent) flowStatsDelete(flow *ofp.OfpFlowStats) error {
473 log.Debug("flowStatsDelete")
474 if flow == nil {
475 return nil
476 }
477 agent.lockLogicalDevice.Lock()
478 defer agent.lockLogicalDevice.Unlock()
479
480 var lDevice *voltha.LogicalDevice
481 var err error
482 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
483 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
484 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
485 }
486 flows := lDevice.Flows.Items
487
488 //build a list of what to keep vs what to delete
489 toKeep := make([]*ofp.OfpFlowStats, 0)
490 for _, f := range flows {
491 if !fu.FlowMatch(f, flow) {
492 toKeep = append(toKeep, f)
493 }
494 }
495
496 //Update flows
497 if len(toKeep) < len(flows) {
khenaidoo43c82122018-11-22 18:38:28 -0500498 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: toKeep}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400499 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
500 return err
501 }
502 }
503 return nil
504}
505
506//flowDeleteStrict deletes a flow from the flow table of that logical device
507func (agent *LogicalDeviceAgent) flowDeleteStrict(mod *ofp.OfpFlowMod) error {
508 log.Debug("flowDeleteStrict")
509 if mod == nil {
510 return nil
511 }
512 agent.lockLogicalDevice.Lock()
513 defer agent.lockLogicalDevice.Unlock()
514
515 var lDevice *voltha.LogicalDevice
516 var err error
517 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
518 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
519 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
520 }
521 flows := lDevice.Flows.Items
522 changed := false
523 flow := fd.FlowStatsEntryFromFlowModMessage(mod)
524 idx := fu.FindFlows(flows, flow)
525 if idx >= 0 {
526 flows = append(flows[:idx], flows[idx+1:]...)
527 changed = true
528 } else {
529 return errors.New(fmt.Sprintf("Cannot delete flow - %s", flow))
530 }
531
532 if changed {
khenaidoo43c82122018-11-22 18:38:28 -0500533 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400534 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
535 return err
536 }
537 }
538
539 return nil
540}
541
542//flowModify modifies a flow from the flow table of that logical device
543func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
544 return errors.New("flowModify not implemented")
545}
546
547//flowModifyStrict deletes a flow from the flow table of that logical device
548func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
549 return errors.New("flowModifyStrict not implemented")
550}
551
552func (agent *LogicalDeviceAgent) groupAdd(groupMod *ofp.OfpGroupMod) error {
553 log.Debug("groupAdd")
554 if groupMod == nil {
555 return nil
556 }
557 agent.lockLogicalDevice.Lock()
558 defer agent.lockLogicalDevice.Unlock()
559
560 var lDevice *voltha.LogicalDevice
561 var err error
562 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
563 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
564 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
565 }
566 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -0400567 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
568 groups = append(groups, fd.GroupEntryFromGroupMod(groupMod))
khenaidoo43c82122018-11-22 18:38:28 -0500569 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
570 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400571 return err
572 }
573 } else {
574 return errors.New(fmt.Sprintf("Groups %d already present", groupMod.GroupId))
575 }
khenaidoo19d7b632018-10-30 10:49:50 -0400576 return nil
577}
578
579func (agent *LogicalDeviceAgent) groupDelete(groupMod *ofp.OfpGroupMod) error {
580 log.Debug("groupDelete")
581 if groupMod == nil {
582 return nil
583 }
584 agent.lockLogicalDevice.Lock()
585 defer agent.lockLogicalDevice.Unlock()
586
587 var lDevice *voltha.LogicalDevice
588 var err error
589 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
590 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
591 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
592 }
593 groups := lDevice.FlowGroups.Items
594 flows := lDevice.Flows.Items
595 groupsChanged := false
596 flowsChanged := false
597 groupId := groupMod.GroupId
598 if groupId == uint32(ofp.OfpGroup_OFPG_ALL) {
599 //TODO we must delete all flows that point to this group and
600 //signal controller as requested by flow's flag
601 groups = []*ofp.OfpGroupEntry{}
602 groupsChanged = true
603 } else {
604 if idx := fu.FindGroup(groups, groupId); idx == -1 {
605 return nil // Valid case
606 } else {
607 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupId)
608 groups = append(groups[:idx], groups[idx+1:]...)
609 groupsChanged = true
610 }
611 }
khenaidoo43c82122018-11-22 18:38:28 -0500612 if groupsChanged {
613 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
614 log.Errorw("Cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
khenaidoo19d7b632018-10-30 10:49:50 -0400615 return err
616 }
617 }
khenaidoo43c82122018-11-22 18:38:28 -0500618 if flowsChanged {
619 if err := agent.updateLogicalDeviceFlowsWithoutLock(&ofp.Flows{Items: flows}); err != nil {
620 log.Errorw("Cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
621 return err
622 }
623 }
624
khenaidoo19d7b632018-10-30 10:49:50 -0400625 return nil
626}
627
628func (agent *LogicalDeviceAgent) groupModify(groupMod *ofp.OfpGroupMod) error {
629 log.Debug("groupModify")
630 if groupMod == nil {
631 return nil
632 }
633 agent.lockLogicalDevice.Lock()
634 defer agent.lockLogicalDevice.Unlock()
635
636 var lDevice *voltha.LogicalDevice
637 var err error
638 if lDevice, err = agent.getLogicalDeviceWithoutLock(); err != nil {
639 log.Errorw("no-logical-device-present", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
640 return errors.New(fmt.Sprintf("no-logical-device-present:%s", agent.logicalDeviceId))
641 }
642 groups := lDevice.FlowGroups.Items
643 groupsChanged := false
644 groupId := groupMod.GroupId
645 if idx := fu.FindGroup(groups, groupId); idx == -1 {
khenaidooca301322019-01-09 23:06:32 -0500646 return errors.New(fmt.Sprintf("group-absent:%d", groupId))
khenaidoo19d7b632018-10-30 10:49:50 -0400647 } else {
648 //replace existing group entry with new group definition
649 groupEntry := fd.GroupEntryFromGroupMod(groupMod)
650 groups[idx] = groupEntry
651 groupsChanged = true
652 }
653 if groupsChanged {
khenaidoo43c82122018-11-22 18:38:28 -0500654 //lDevice.FlowGroups.Items = groups
655 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(&ofp.FlowGroups{Items: groups}); err != nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400656 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
657 return err
658 }
659 }
660 return nil
661}
662
663// deleteLogicalPort removes the logical port
664func (agent *LogicalDeviceAgent) deleteLogicalPort(lPort *voltha.LogicalPort) error {
665 agent.lockLogicalDevice.Lock()
666 defer agent.lockLogicalDevice.Unlock()
667
khenaidoo92e62c52018-10-03 14:02:54 -0400668 // Get the most up to date logical device
669 var logicaldevice *voltha.LogicalDevice
670 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
khenaidoo19d7b632018-10-30 10:49:50 -0400671 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
khenaidoob9203542018-09-17 22:56:37 -0400672 return nil
673 }
khenaidoo92e62c52018-10-03 14:02:54 -0400674 index := -1
675 for i, logicalPort := range logicaldevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -0400676 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -0400677 index = i
678 break
679 }
680 }
681 if index >= 0 {
682 copy(logicaldevice.Ports[index:], logicaldevice.Ports[index+1:])
683 logicaldevice.Ports[len(logicaldevice.Ports)-1] = nil
684 logicaldevice.Ports = logicaldevice.Ports[:len(logicaldevice.Ports)-1]
685 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceId})
686 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
687 }
688 return nil
khenaidoob9203542018-09-17 22:56:37 -0400689}
690
khenaidoo19d7b632018-10-30 10:49:50 -0400691// enableLogicalPort enables the logical port
692func (agent *LogicalDeviceAgent) enableLogicalPort(lPort *voltha.LogicalPort) error {
693 agent.lockLogicalDevice.Lock()
694 defer agent.lockLogicalDevice.Unlock()
695
696 // Get the most up to date logical device
697 var logicaldevice *voltha.LogicalDevice
698 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
699 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
700 return nil
701 }
702 index := -1
703 for i, logicalPort := range logicaldevice.Ports {
704 if logicalPort.Id == lPort.Id {
705 index = i
706 break
707 }
708 }
709 if index >= 0 {
710 logicaldevice.Ports[index].OfpPort.Config = logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
711 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
712 }
713 //TODO: Trigger subsequent actions on the device
714 return nil
715}
716
717// disableLogicalPort disabled the logical port
718func (agent *LogicalDeviceAgent) disableLogicalPort(lPort *voltha.LogicalPort) error {
719 agent.lockLogicalDevice.Lock()
720 defer agent.lockLogicalDevice.Unlock()
721
722 // Get the most up to date logical device
723 var logicaldevice *voltha.LogicalDevice
724 if logicaldevice, _ = agent.getLogicalDeviceWithoutLock(); logicaldevice == nil {
725 log.Debugw("no-logical-device", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "logicalPortId": lPort.Id})
726 return nil
727 }
728 index := -1
729 for i, logicalPort := range logicaldevice.Ports {
730 if logicalPort.Id == lPort.Id {
731 index = i
732 break
733 }
734 }
735 if index >= 0 {
736 logicaldevice.Ports[index].OfpPort.Config = (logicaldevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
737 return agent.updateLogicalDeviceWithoutLock(logicaldevice)
738 }
739 //TODO: Trigger subsequent actions on the device
740 return nil
741}
742
khenaidoo89b0e942018-10-21 21:11:33 -0400743func isNNIPort(portNo uint32, nniPortsNo []uint32) bool {
744 for _, pNo := range nniPortsNo {
745 if pNo == portNo {
746 return true
747 }
748 }
749 return false
750}
khenaidoo4d4802d2018-10-04 21:59:49 -0400751
khenaidoo89b0e942018-10-21 21:11:33 -0400752func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -0400753 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -0400754 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400755 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -0400756 if ingress == routeLink.Ingress && egress == routeLink.Egress {
757 return route
758 }
759 }
760 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceId, "ingress": ingress, "egress": egress})
761 return nil
762}
763
khenaidoo19d7b632018-10-30 10:49:50 -0400764func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -0400765 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
766 // Get the updated logical device
khenaidoo79232702018-12-04 11:00:41 -0500767 var ld *ic.LogicalDevice
khenaidoo89b0e942018-10-21 21:11:33 -0400768 routes := make([]graph.RouteHop, 0)
769 var err error
770 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
771 return nil
772 }
773 nniLogicalPortsNo := make([]uint32, 0)
774 for _, logicalPort := range ld.Ports {
775 if logicalPort.RootPort {
776 nniLogicalPortsNo = append(nniLogicalPortsNo, logicalPort.OfpPort.PortNo)
777 }
778 }
779 if len(nniLogicalPortsNo) == 0 {
780 log.Errorw("no-nni-ports", log.Fields{"LogicalDeviceId": ld.Id})
781 return nil
782 }
khenaidoo19d7b632018-10-30 10:49:50 -0400783 // Note: A port value of 0 is equivalent to a nil port
784
khenaidoo89b0e942018-10-21 21:11:33 -0400785 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -0400786 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo89b0e942018-10-21 21:11:33 -0400787 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
khenaidoo19d7b632018-10-30 10:49:50 -0400788 if isNNIPort(ingressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400789 log.Debug("returning-half-route")
790 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -0400791 if len(agent.deviceGraph.Routes) == 0 {
792 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
793 // internal route
khenaidoo910204f2019-04-08 17:56:40 -0400794 hop := graph.RouteHop{DeviceID: ld.RootDeviceId, Ingress: ingressPortNo, Egress: egressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -0400795 routes = append(routes, hop)
796 routes = append(routes, hop)
797 return routes
798 }
khenaidoo89b0e942018-10-21 21:11:33 -0400799 //Return a 'half' route to make the flow decomposer logic happy
800 for routeLink, route := range agent.deviceGraph.Routes {
801 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
802 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
803 routes = append(routes, route[1])
804 return routes
805 }
806 }
807 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
808 return nil
809 }
810 //treat it as if the output port is the first NNI of the OLT
khenaidoo19d7b632018-10-30 10:49:50 -0400811 egressPortNo = nniLogicalPortsNo[0]
khenaidoo89b0e942018-10-21 21:11:33 -0400812 }
813 //If ingress port is not specified (nil), it may be a wildcarded
814 //route if egress port is OFPP_CONTROLLER or a nni logical port,
815 //in which case we need to create a half-route where only the egress
816 //hop is filled, the first hop is nil
khenaidoo19d7b632018-10-30 10:49:50 -0400817 if ingressPortNo == 0 && isNNIPort(egressPortNo, nniLogicalPortsNo) {
khenaidoo89b0e942018-10-21 21:11:33 -0400818 // We can use the 2nd hop of any upstream route, so just find the first upstream:
819 for routeLink, route := range agent.deviceGraph.Routes {
820 if isNNIPort(routeLink.Egress, nniLogicalPortsNo) {
821 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
822 routes = append(routes, route[1])
823 return routes
824 }
825 }
826 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
827 return nil
828 }
829 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -0400830 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400831 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -0400832 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -0400833 routes = append(routes, route[0])
834 routes = append(routes, graph.RouteHop{})
835 return routes
836 }
837 }
838 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "nniPortsNo": nniLogicalPortsNo})
839 return nil
840 }
841
842 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -0400843 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400844}
845
khenaidoo89b0e942018-10-21 21:11:33 -0400846func (agent *LogicalDeviceAgent) rootDeviceDefaultRules() *fu.FlowsAndGroups {
847 return fu.NewFlowsAndGroups()
848}
849
850func (agent *LogicalDeviceAgent) leafDeviceDefaultRules(deviceId string) *fu.FlowsAndGroups {
851 fg := fu.NewFlowsAndGroups()
852 var device *voltha.Device
853 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400854 if device, err = agent.deviceMgr.GetDevice(deviceId); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400855 return fg
856 }
857 //set the upstream and downstream ports
858 upstreamPorts := make([]*voltha.Port, 0)
859 downstreamPorts := make([]*voltha.Port, 0)
860 for _, port := range device.Ports {
861 if port.Type == voltha.Port_PON_ONU || port.Type == voltha.Port_VENET_ONU {
862 upstreamPorts = append(upstreamPorts, port)
863 } else if port.Type == voltha.Port_ETHERNET_UNI {
864 downstreamPorts = append(downstreamPorts, port)
865 }
866 }
867 //it is possible that the downstream ports are not created, but the flow_decomposition has already
868 //kicked in. In such scenarios, cut short the processing and return.
khenaidoo910204f2019-04-08 17:56:40 -0400869 if len(downstreamPorts) == 0 || len(upstreamPorts) == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400870 return fg
871 }
872 // set up the default flows
873 var fa *fu.FlowArgs
874 fa = &fu.FlowArgs{
875 KV: fu.OfpFlowModArgs{"priority": 500},
876 MatchFields: []*ofp.OfpOxmOfbField{
877 fd.InPort(downstreamPorts[0].PortNo),
878 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0),
879 },
880 Actions: []*ofp.OfpAction{
881 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
khenaidoo19d7b632018-10-30 10:49:50 -0400882 fd.Output(upstreamPorts[0].PortNo),
khenaidoo89b0e942018-10-21 21:11:33 -0400883 },
884 }
885 fg.AddFlow(fd.MkFlowStat(fa))
886
887 fa = &fu.FlowArgs{
888 KV: fu.OfpFlowModArgs{"priority": 500},
889 MatchFields: []*ofp.OfpOxmOfbField{
890 fd.InPort(downstreamPorts[0].PortNo),
891 fd.VlanVid(0),
892 },
893 Actions: []*ofp.OfpAction{
894 fd.PushVlan(0x8100),
895 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan)),
896 fd.Output(upstreamPorts[0].PortNo),
897 },
898 }
899 fg.AddFlow(fd.MkFlowStat(fa))
900
901 fa = &fu.FlowArgs{
902 KV: fu.OfpFlowModArgs{"priority": 500},
903 MatchFields: []*ofp.OfpOxmOfbField{
904 fd.InPort(upstreamPorts[0].PortNo),
905 fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | device.Vlan),
906 },
907 Actions: []*ofp.OfpAction{
908 fd.SetField(fd.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 0)),
909 fd.Output(downstreamPorts[0].PortNo),
910 },
911 }
912 fg.AddFlow(fd.MkFlowStat(fa))
913
914 return fg
915}
916
917func (agent *LogicalDeviceAgent) generateDefaultRules() *fu.DeviceRules {
918 rules := fu.NewDeviceRules()
919 var ld *voltha.LogicalDevice
920 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400921 if ld, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400922 log.Warnw("no-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceId})
923 return rules
924 }
925
926 deviceNodeIds := agent.deviceGraph.GetDeviceNodeIds()
khenaidooca301322019-01-09 23:06:32 -0500927 for deviceId := range deviceNodeIds {
khenaidoo89b0e942018-10-21 21:11:33 -0400928 if deviceId == ld.RootDeviceId {
929 rules.AddFlowsAndGroup(deviceId, agent.rootDeviceDefaultRules())
930 } else {
931 rules.AddFlowsAndGroup(deviceId, agent.leafDeviceDefaultRules(deviceId))
932 }
933 }
934 return rules
935}
936
937func (agent *LogicalDeviceAgent) GetAllDefaultRules() *fu.DeviceRules {
938 // Get latest
khenaidoo89b0e942018-10-21 21:11:33 -0400939 var err error
khenaidoo910204f2019-04-08 17:56:40 -0400940 if _, err = agent.GetLogicalDevice(); err != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400941 return fu.NewDeviceRules()
942 }
943 if agent.DefaultFlowRules == nil { // Nothing setup yet
khenaidoo910204f2019-04-08 17:56:40 -0400944 // Setup device graph if needed
945 agent.setupDeviceGraph()
khenaidoo89b0e942018-10-21 21:11:33 -0400946 agent.DefaultFlowRules = agent.generateDefaultRules()
947 }
948 return agent.DefaultFlowRules
949}
950
951func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
952 lPorts := make([]uint32, 0)
953 var exclPort uint32
954 if len(excludePort) == 1 {
955 exclPort = excludePort[0]
956 }
khenaidoo19d7b632018-10-30 10:49:50 -0400957 if lDevice, _ := agent.GetLogicalDevice(); lDevice != nil {
khenaidoo89b0e942018-10-21 21:11:33 -0400958 for _, port := range lDevice.Ports {
959 if port.OfpPort.PortNo != exclPort {
960 lPorts = append(lPorts, port.OfpPort.PortNo)
961 }
962 }
963 }
964 return lPorts
965}
khenaidoo19d7b632018-10-30 10:49:50 -0400966
967func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
968 return agent.deviceGraph
969}
970
971//setupDeviceGraph creates the device graph if not done already
972func (agent *LogicalDeviceAgent) setupDeviceGraph() {
khenaidoo910204f2019-04-08 17:56:40 -0400973 agent.lockLogicalDevice.Lock()
974 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400975 if agent.deviceGraph == nil {
khenaidoo910204f2019-04-08 17:56:40 -0400976 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
977 if ld, err := agent.getLogicalDeviceWithoutLock(); err == nil {
978 agent.deviceGraph.ComputeRoutes(ld.Ports)
979 }
khenaidoo19d7b632018-10-30 10:49:50 -0400980 }
981}
982
khenaidoo910204f2019-04-08 17:56:40 -0400983//updateDeviceGraph updates the device graph if not done already
984func (agent *LogicalDeviceAgent) updateDeviceGraph(lp *voltha.LogicalPort) {
985 if agent.deviceGraph == nil {
986 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceId, agent.deviceMgr.GetDevice)
987 }
988 agent.deviceGraph.AddPort(lp)
989}
990
khenaidoo19d7b632018-10-30 10:49:50 -0400991func (agent *LogicalDeviceAgent) flowTableUpdated(args ...interface{}) interface{} {
992 log.Debugw("flowTableUpdated-callback", log.Fields{"argsLen": len(args)})
993
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500994 var previousData *ofp.Flows
995 var latestData *ofp.Flows
khenaidoo19d7b632018-10-30 10:49:50 -0400996
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500997 var ok bool
998 if previousData, ok = args[0].(*ofp.Flows); !ok {
999 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1000 }
1001 if latestData, ok = args[1].(*ofp.Flows); !ok {
1002 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1003 }
khenaidoo19d7b632018-10-30 10:49:50 -04001004
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001005 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1006 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -04001007 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001008 }
1009
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001010 var groups *ofp.FlowGroups
1011 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1012 groups = lDevice.FlowGroups
1013 log.Debugw("flowsinfo", log.Fields{"flows": latestData, "groups": groups})
1014 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *latestData, *groups)
1015 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1016
khenaidooca301322019-01-09 23:06:32 -05001017 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001018 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -05001019 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001020 log.Error("update-flows-failed", log.Fields{"deviceID": deviceId})
khenaidooca301322019-01-09 23:06:32 -05001021 }
1022 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001023 log.Error("update-groups-failed", log.Fields{"deviceID": deviceId})
khenaidooca301322019-01-09 23:06:32 -05001024 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001025 }
khenaidoo19d7b632018-10-30 10:49:50 -04001026
khenaidoo19d7b632018-10-30 10:49:50 -04001027 return nil
1028}
1029
1030func (agent *LogicalDeviceAgent) groupTableUpdated(args ...interface{}) interface{} {
1031 log.Debugw("groupTableUpdated-callback", log.Fields{"argsLen": len(args)})
1032
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001033 var previousData *ofp.FlowGroups
1034 var latestData *ofp.FlowGroups
khenaidoo19d7b632018-10-30 10:49:50 -04001035
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001036 var ok bool
1037 if previousData, ok = args[0].(*ofp.FlowGroups); !ok {
1038 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1039 }
1040 if latestData, ok = args[1].(*ofp.FlowGroups); !ok {
1041 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1042 }
khenaidoo19d7b632018-10-30 10:49:50 -04001043
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001044 if reflect.DeepEqual(previousData.Items, latestData.Items) {
1045 log.Debug("flow-update-not-required")
khenaidoo19d7b632018-10-30 10:49:50 -04001046 return nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001047 }
1048
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001049 var flows *ofp.Flows
1050 lDevice, _ := agent.getLogicalDeviceWithoutLock()
1051 flows = lDevice.Flows
1052 log.Debugw("groupsinfo", log.Fields{"groups": latestData, "flows": flows})
1053 deviceRules := agent.flowDecomposer.DecomposeRules(agent, *flows, *latestData)
1054 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidooca301322019-01-09 23:06:32 -05001055 var err error
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001056 for deviceId, value := range deviceRules.GetRules() {
khenaidooca301322019-01-09 23:06:32 -05001057 if err = agent.deviceMgr.updateFlows(deviceId, value.ListFlows()); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001058 log.Error("update-flows-failed", log.Fields{"deviceID": deviceId})
khenaidooca301322019-01-09 23:06:32 -05001059 }
1060 if err = agent.deviceMgr.updateGroups(deviceId, value.ListGroups()); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001061 log.Error("update-groups-failed", log.Fields{"deviceID": deviceId})
khenaidooca301322019-01-09 23:06:32 -05001062 }
khenaidoo19d7b632018-10-30 10:49:50 -04001063
khenaidooca301322019-01-09 23:06:32 -05001064 }
khenaidoo19d7b632018-10-30 10:49:50 -04001065 return nil
1066}
khenaidoofdbad6e2018-11-06 22:26:38 -05001067
khenaidoofc1314d2019-03-14 09:34:21 -04001068// portAdded is a callback invoked when a port is added to the logical device.
1069// TODO: To use when POST_ADD is fixed.
1070func (agent *LogicalDeviceAgent) portAdded(args ...interface{}) interface{} {
1071 log.Debugw("portAdded-callback", log.Fields{"argsLen": len(args)})
1072
1073 var port *voltha.LogicalPort
1074
1075 // Sanity check
1076 if args[0] != nil {
1077 log.Warnw("previous-data-not-nil", log.Fields{"args0": args[0]})
1078 }
1079 var ok bool
1080 if port, ok = args[1].(*voltha.LogicalPort); !ok {
1081 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1082 return nil
1083 }
1084
1085 // Set the proxy and callback for that port
1086 agent.portProxiesLock.Lock()
Stephane Barbarie40fd3b22019-04-23 21:50:47 -04001087 agent.portProxies[port.Id] = agent.clusterDataProxy.CreateProxy(
khenaidoofc1314d2019-03-14 09:34:21 -04001088 fmt.Sprintf("/logical_devices/%s/ports/%s", agent.logicalDeviceId, port.Id),
1089 false)
1090 agent.portProxies[port.Id].RegisterCallback(model.POST_UPDATE, agent.portUpdated)
1091 agent.portProxiesLock.Unlock()
1092
1093 // Send the port change event to the OF controller
1094 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001095 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001096
1097 return nil
1098}
1099
1100// portRemoved is a callback invoked when a port is removed from the logical device.
1101// TODO: To use when POST_ADD is fixed.
1102func (agent *LogicalDeviceAgent) portRemoved(args ...interface{}) interface{} {
1103 log.Debugw("portRemoved-callback", log.Fields{"argsLen": len(args)})
1104
1105 var port *voltha.LogicalPort
1106
1107 // Sanity check
1108 if args[1] != nil {
1109 log.Warnw("data-not-nil", log.Fields{"args1": args[1]})
1110 }
1111 var ok bool
1112 if port, ok = args[0].(*voltha.LogicalPort); !ok {
1113 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1114 return nil
1115 }
1116
1117 // Remove the proxy and callback for that port
1118 agent.portProxiesLock.Lock()
1119 agent.portProxies[port.Id].UnregisterCallback(model.POST_UPDATE, agent.portUpdated)
1120 delete(agent.portProxies, port.Id)
1121 agent.portProxiesLock.Unlock()
1122
1123 // Send the port change event to the OF controller
1124 agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001125 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: port.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001126
1127 return nil
1128}
1129
1130// diff go over two lists of logical ports and return what's new, what's changed and what's removed.
khenaidoo910204f2019-04-08 17:56:40 -04001131func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001132 newPorts = make([]*voltha.LogicalPort, 0)
1133 changedPorts = make([]*voltha.LogicalPort, 0)
1134 deletedPorts = make([]*voltha.LogicalPort, 0)
1135 for _, o := range oldList {
1136 found := false
1137 changed := false
1138 for _, n := range newList {
1139 if o.Id == n.Id {
1140 changed = !reflect.DeepEqual(o, n)
1141 found = true
1142 break
1143 }
1144 }
1145 if !found {
1146 deletedPorts = append(deletedPorts, o)
1147 }
1148 if changed {
1149 changedPorts = append(changedPorts, o)
1150 }
1151 }
1152 for _, n := range newList {
1153 found := false
1154 for _, o := range oldList {
1155 if o.Id == n.Id {
1156 found = true
1157 break
1158 }
1159 }
1160 if !found {
1161 newPorts = append(newPorts, n)
1162 }
1163 }
1164 return
1165}
1166
1167// portUpdated is invoked when a port is updated on the logical device. Until
1168// the POST_ADD notification is fixed, we will use the logical device to
1169// update that data.
1170func (agent *LogicalDeviceAgent) portUpdated(args ...interface{}) interface{} {
1171 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1172
1173 var oldLD *voltha.LogicalDevice
1174 var newlD *voltha.LogicalDevice
1175
1176 var ok bool
1177 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1178 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1179 return nil
1180 }
1181 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1182 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1183 return nil
1184 }
1185
1186 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1187 log.Debug("ports-have-not-changed")
1188 return nil
1189 }
1190
1191 // Get the difference between the two list
1192 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1193
1194 // Send the port change events to the OF controller
1195 for _, new := range newPorts {
1196 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001197 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: new.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001198 }
1199 for _, change := range changedPorts {
1200 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001201 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001202 }
1203 for _, del := range deletedPorts {
1204 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceId,
khenaidoo910204f2019-04-08 17:56:40 -04001205 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001206 }
1207
1208 return nil
1209}
1210
khenaidoo8f474192019-04-03 17:20:44 -04001211// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1212// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1213// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1214// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001215func (agent *LogicalDeviceAgent) addNNILogicalPort(device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo8f474192019-04-03 17:20:44 -04001216 //now := time.Now()
1217 //defer fmt.Println("setupNNILogicalPorts:", device.Id, time.Since(now))
khenaidoo1ce37ad2019-03-24 22:07:24 -04001218 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001219 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1220 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1221 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001222 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001223 agent.lockLogicalDevice.RLock()
1224 if agent.portExist(device, port) {
1225 log.Debugw("port-already-exist", log.Fields{"port": port})
1226 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001227 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001228 }
1229 agent.lockLogicalDevice.RUnlock()
1230
khenaidoofc1314d2019-03-14 09:34:21 -04001231 var portCap *ic.PortCapability
1232 var err error
1233 // First get the port capability
1234 if portCap, err = agent.deviceMgr.getPortCapability(nil, device.Id, port.PortNo); err != nil {
1235 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001236 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001237 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001238
1239 agent.lockLogicalDevice.Lock()
1240 defer agent.lockLogicalDevice.Unlock()
1241 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1242 if agent.portExist(device, port) {
1243 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001244 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001245 }
1246
khenaidoofc1314d2019-03-14 09:34:21 -04001247 portCap.Port.RootPort = true
1248 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1249 lp.DeviceId = device.Id
1250 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1251 lp.OfpPort.PortNo = port.PortNo
1252 lp.OfpPort.Name = lp.Id
1253 lp.DevicePortNo = port.PortNo
1254
khenaidoofc1314d2019-03-14 09:34:21 -04001255 var ld *voltha.LogicalDevice
1256 if ld, err = agent.getLogicalDeviceWithoutLock(); err != nil {
1257 log.Errorw("error-retrieving-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001258 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001259 }
1260 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1261 if cloned.Ports == nil {
1262 cloned.Ports = make([]*voltha.LogicalPort, 0)
1263 }
1264 cloned.Ports = append(cloned.Ports, lp)
1265
1266 if err = agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1267 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001268 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001269 }
khenaidoo910204f2019-04-08 17:56:40 -04001270
1271 // Update the device graph with this new logical port
1272 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
1273 go agent.updateDeviceGraph(clonedLP)
1274
khenaidoo8f474192019-04-03 17:20:44 -04001275 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001276}
1277
khenaidoo910204f2019-04-08 17:56:40 -04001278func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo54544ae2019-03-18 13:22:39 -04001279 if ldevice, _ := agent.getLogicalDeviceWithoutLock(); ldevice != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001280 for _, lPort := range ldevice.Ports {
khenaidoo54544ae2019-03-18 13:22:39 -04001281 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
khenaidoofc1314d2019-03-14 09:34:21 -04001282 return true
1283 }
1284 }
1285 }
1286 return false
1287}
1288
khenaidoo8f474192019-04-03 17:20:44 -04001289// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1290// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1291// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1292// scenario. This also applies to the case where the port was already added.
khenaidoo910204f2019-04-08 17:56:40 -04001293func (agent *LogicalDeviceAgent) addUNILogicalPort(childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo8f474192019-04-03 17:20:44 -04001294 //now := time.Now()
1295 //defer fmt.Println("addUNILogicalPort:", childDevice.Id, time.Since(now))
khenaidoofc1314d2019-03-14 09:34:21 -04001296 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001297 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1298 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1299 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001300 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001301 agent.lockLogicalDevice.RLock()
1302 if agent.portExist(childDevice, port) {
1303 log.Debugw("port-already-exist", log.Fields{"port": port})
1304 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001305 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001306 }
1307 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001308 var portCap *ic.PortCapability
1309 var err error
1310 // First get the port capability
1311 if portCap, err = agent.deviceMgr.getPortCapability(nil, childDevice.Id, port.PortNo); err != nil {
1312 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001313 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001314 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001315 agent.lockLogicalDevice.Lock()
1316 defer agent.lockLogicalDevice.Unlock()
1317 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1318 if agent.portExist(childDevice, port) {
1319 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001320 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001321 }
khenaidoofc1314d2019-03-14 09:34:21 -04001322 // Get stored logical device
1323 if ldevice, err := agent.getLogicalDeviceWithoutLock(); err != nil {
khenaidoo8f474192019-04-03 17:20:44 -04001324 return false, status.Error(codes.NotFound, agent.logicalDeviceId)
khenaidoofc1314d2019-03-14 09:34:21 -04001325 } else {
1326 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1327 portCap.Port.RootPort = false
Matt Jeanneret3815e322019-03-12 19:15:49 -04001328 portCap.Port.Id = port.Label
1329 portCap.Port.OfpPort.PortNo = port.PortNo
khenaidoo1ce37ad2019-03-24 22:07:24 -04001330 portCap.Port.OfpPort.Name = childDevice.SerialNumber
khenaidoofc1314d2019-03-14 09:34:21 -04001331 portCap.Port.DeviceId = childDevice.Id
1332 portCap.Port.DevicePortNo = port.PortNo
1333 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1334 if cloned.Ports == nil {
1335 cloned.Ports = make([]*voltha.LogicalPort, 0)
1336 }
1337 cloned.Ports = append(cloned.Ports, portCap.Port)
khenaidoo910204f2019-04-08 17:56:40 -04001338 if err := agent.updateLogicalDeviceWithoutLock(cloned); err != nil {
1339 return false, err
1340 }
1341
1342 // Update the device graph with this new logical port
1343 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1344 go agent.updateDeviceGraph(clonedLP)
1345 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001346 }
1347}
1348
khenaidoo43c82122018-11-22 18:38:28 -05001349func (agent *LogicalDeviceAgent) packetOut(packet *ofp.OfpPacketOut) {
khenaidoofdbad6e2018-11-06 22:26:38 -05001350 log.Debugw("packet-out", log.Fields{"packet": packet.GetInPort()})
1351 outPort := fd.GetPacketOutPort(packet)
1352 //frame := packet.GetData()
1353 //TODO: Use a channel between the logical agent and the device agent
khenaidooca301322019-01-09 23:06:32 -05001354 if err := agent.deviceMgr.packetOut(agent.rootDeviceId, outPort, packet); err != nil {
khenaidoo910204f2019-04-08 17:56:40 -04001355 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceId})
khenaidooca301322019-01-09 23:06:32 -05001356 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001357}
1358
khenaidoo297cd252019-02-07 22:10:23 -05001359func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionId string, packet []byte) {
1360 log.Debugw("packet-in", log.Fields{"port": port, "packet": packet, "transactionId": transactionId})
khenaidooca301322019-01-09 23:06:32 -05001361 packetIn := fd.MkPacketIn(port, packet)
khenaidoo297cd252019-02-07 22:10:23 -05001362 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceId, transactionId, packetIn)
khenaidooca301322019-01-09 23:06:32 -05001363 log.Debugw("sending-packet-in", log.Fields{"packet-in": packetIn})
khenaidoofdbad6e2018-11-06 22:26:38 -05001364}