blob: 27ce04b84eaa986b2c6fa87ad3c4609822609019 [file] [log] [blame]
Kent Hagerman3136fbd2020-05-14 10:30:45 -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 */
16
17package device
18
19import (
20 "context"
21 "fmt"
22
23 "github.com/gogo/protobuf/proto"
24 coreutils "github.com/opencord/voltha-go/rw_core/utils"
25 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
26 "github.com/opencord/voltha-lib-go/v3/pkg/log"
27 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
28 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
29 "github.com/opencord/voltha-protos/v3/go/voltha"
30 "google.golang.org/grpc/codes"
31 "google.golang.org/grpc/status"
32)
33
34// ListLogicalDevicePorts returns logical device ports
35func (agent *LogicalAgent) ListLogicalDevicePorts(ctx context.Context) (*voltha.LogicalPorts, error) {
36 logger.Debug("ListLogicalDevicePorts")
37 logicalDevice, err := agent.GetLogicalDevice(ctx)
38 if err != nil {
39 return nil, err
40 }
41 if logicalDevice == nil {
42 return &voltha.LogicalPorts{}, nil
43 }
44 lPorts := make([]*voltha.LogicalPort, 0)
45 lPorts = append(lPorts, logicalDevice.Ports...)
46 return &voltha.LogicalPorts{Items: lPorts}, nil
47}
48
49func (agent *LogicalAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
50 logger.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
51 var err error
52 if port.Type == voltha.Port_ETHERNET_NNI {
53 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
54 return err
55 }
56 agent.addLogicalPortToMap(port.PortNo, true)
57 } else if port.Type == voltha.Port_ETHERNET_UNI {
58 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
59 return err
60 }
61 agent.addLogicalPortToMap(port.PortNo, false)
62 } else {
63 // Update the device routes to ensure all routes on the logical device have been calculated
64 if err = agent.buildRoutes(ctx); err != nil {
65 // Not an error - temporary state
66 logger.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err})
67 }
68 }
69 return nil
70}
71
72// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
73// added to it. While the logical device was being created we could have received requests to add
74// NNI and UNI ports which were discarded. Now is the time to add them if needed
75func (agent *LogicalAgent) setupLogicalPorts(ctx context.Context) error {
76 logger.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
77 // First add any NNI ports which could have been missing
78 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
79 logger.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
80 return err
81 }
82
83 // Now, set up the UNI ports if needed.
84 children, err := agent.deviceMgr.GetAllChildDevices(ctx, agent.rootDeviceID)
85 if err != nil {
86 logger.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
87 return err
88 }
89 responses := make([]coreutils.Response, 0)
90 for _, child := range children.Items {
91 response := coreutils.NewResponse()
92 responses = append(responses, response)
93 go func(child *voltha.Device) {
94 if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil {
95 logger.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
96 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
97 }
98 response.Done()
99 }(child)
100 }
101 // Wait for completion
102 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
103 return status.Errorf(codes.Aborted, "errors-%s", res)
104 }
105 return nil
106}
107
108// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
109func (agent *LogicalAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
110 logger.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
111 // Build the logical device based on information retrieved from the device adapter
112 var err error
113
114 var device *voltha.Device
115 if device, err = agent.deviceMgr.getDevice(ctx, deviceID); err != nil {
116 logger.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
117 return err
118 }
119
120 //Get UNI port number
121 for _, port := range device.Ports {
122 if port.Type == voltha.Port_ETHERNET_NNI {
123 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
124 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
125 }
126 agent.addLogicalPortToMap(port.PortNo, true)
127 }
128 }
129 return err
130}
131
132// updatePortState updates the port state of the device
133func (agent *LogicalAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
134 logger.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
135 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
136 return err
137 }
138 defer agent.requestQueue.RequestComplete()
139 // Get the latest logical device info
140 original := agent.getLogicalDeviceWithoutLock()
141 updatedPorts := clonePorts(original.Ports)
142 for _, port := range updatedPorts {
143 if port.DeviceId == deviceID && port.DevicePortNo == portNo {
144 if operStatus == voltha.OperStatus_ACTIVE {
145 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
146 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
147 } else {
148 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
149 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
150 }
151 // Update the logical device
152 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
153 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
154 return err
155 }
156 return nil
157 }
158 }
159 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
160}
161
162// updatePortsState updates the ports state related to the device
163func (agent *LogicalAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
164 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
165 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
166 return err
167 }
168 defer agent.requestQueue.RequestComplete()
169 // Get the latest logical device info
170 original := agent.getLogicalDeviceWithoutLock()
171 updatedPorts := clonePorts(original.Ports)
172 for _, port := range updatedPorts {
173 if port.DeviceId == device.Id {
174 if state == voltha.OperStatus_ACTIVE {
175 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
176 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
177 } else {
178 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
179 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
180 }
181 }
182 }
183 // Updating the logical device will trigger the poprt change events to be populated to the controller
184 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
185 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
186 return err
187 }
188 return nil
189}
190
191// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
192func (agent *LogicalAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
193 logger.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
194 // Build the logical device based on information retrieved from the device adapter
195 var err error
196 var added bool
197 //Get UNI port number
198 for _, port := range childDevice.Ports {
199 if port.Type == voltha.Port_ETHERNET_UNI {
200 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
201 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
202 }
203 if added {
204 agent.addLogicalPortToMap(port.PortNo, false)
205 }
206 }
207 }
208 return err
209}
210
211// deleteAllLogicalPorts deletes all logical ports associated with this logical device
212func (agent *LogicalAgent) deleteAllLogicalPorts(ctx context.Context) error {
213 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
214 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
215 return err
216 }
217 defer agent.requestQueue.RequestComplete()
218 // Get the latest logical device info
219 cloned := agent.getLogicalDeviceWithoutLock()
220
221 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, cloned, []*voltha.LogicalPort{}); err != nil {
222 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
223 return err
224 }
225 return nil
226}
227
228// deleteLogicalPort removes the logical port
229func (agent *LogicalAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
230 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
231 return err
232 }
233 defer agent.requestQueue.RequestComplete()
234
235 logicalDevice := agent.getLogicalDeviceWithoutLock()
236
237 index := -1
238 for i, logicalPort := range logicalDevice.Ports {
239 if logicalPort.Id == lPort.Id {
240 index = i
241 break
242 }
243 }
244 if index >= 0 {
245 clonedPorts := clonePorts(logicalDevice.Ports)
246 if index < len(clonedPorts)-1 {
247 copy(clonedPorts[index:], clonedPorts[index+1:])
248 }
249 clonedPorts[len(clonedPorts)-1] = nil
250 clonedPorts = clonedPorts[:len(clonedPorts)-1]
251 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
252 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil {
253 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
254 return err
255 }
256
257 // Remove the logical port from cache
258 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
259 // Reset the logical device routes
260 go func() {
261 if err := agent.buildRoutes(context.Background()); err != nil {
262 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
263 }
264 }()
265 }
266 return nil
267}
268
269// deleteLogicalPorts removes the logical ports associated with that deviceId
270func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
271 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
272 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
273 return err
274 }
275 defer agent.requestQueue.RequestComplete()
276
277 logicalDevice := agent.getLogicalDeviceWithoutLock()
278 lPortstoKeep := []*voltha.LogicalPort{}
279 lPortsNoToDelete := []uint32{}
280 for _, logicalPort := range logicalDevice.Ports {
281 if logicalPort.DeviceId != deviceID {
282 lPortstoKeep = append(lPortstoKeep, logicalPort)
283 } else {
284 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
285 }
286 }
287 logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep})
288 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil {
289 logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID})
290 return err
291 }
292 // Remove the port from the cached logical ports set
293 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
294
295 // Reset the logical device routes
296 go func() {
297 if err := agent.buildRoutes(context.Background()); err != nil {
298 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
299 }
300 }()
301
302 return nil
303}
304
305// enableLogicalPort enables the logical port
306func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
307 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
308 return err
309 }
310 defer agent.requestQueue.RequestComplete()
311
312 logicalDevice := agent.getLogicalDeviceWithoutLock()
313
314 index := -1
315 for i, logicalPort := range logicalDevice.Ports {
316 if logicalPort.Id == lPortID {
317 index = i
318 break
319 }
320 }
321 if index >= 0 {
322 clonedPorts := clonePorts(logicalDevice.Ports)
323 clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
324 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
325 }
326 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
327}
328
329// disableLogicalPort disabled the logical port
330func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
331 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
332 return err
333 }
334 defer agent.requestQueue.RequestComplete()
335
336 // Get the most up to date logical device
337 logicalDevice := agent.getLogicalDeviceWithoutLock()
338 index := -1
339 for i, logicalPort := range logicalDevice.Ports {
340 if logicalPort.Id == lPortID {
341 index = i
342 break
343 }
344 }
345 if index >= 0 {
346 clonedPorts := clonePorts(logicalDevice.Ports)
347 clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
348 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
349 }
350 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
351}
352
353// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
354// added and an eror in case a valid error is encountered. If the port was successfully added it will return
355// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
356// scenario. This also applies to the case where the port was already added.
357func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
358 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
359
360 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
361 return false, err
362 }
363 if agent.portExist(device, port) {
364 logger.Debugw("port-already-exist", log.Fields{"port": port})
365 agent.requestQueue.RequestComplete()
366 return false, nil
367 }
368 agent.requestQueue.RequestComplete()
369
370 var portCap *ic.PortCapability
371 var err error
372 // First get the port capability
373 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
374 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
375 return false, err
376 }
377
378 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
379 return false, err
380 }
381
382 defer agent.requestQueue.RequestComplete()
383 // Double check again if this port has been already added since the getPortCapability could have taken a long time
384 if agent.portExist(device, port) {
385 logger.Debugw("port-already-exist", log.Fields{"port": port})
386 return false, nil
387 }
388
389 portCap.Port.RootPort = true
390 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
391 lp.DeviceId = device.Id
392 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
393 lp.OfpPort.PortNo = port.PortNo
394 lp.OfpPort.Name = lp.Id
395 lp.DevicePortNo = port.PortNo
396
397 ld := agent.getLogicalDeviceWithoutLock()
398
399 clonedPorts := clonePorts(ld.Ports)
400 if clonedPorts == nil {
401 clonedPorts = make([]*voltha.LogicalPort, 0)
402 }
403 clonedPorts = append(clonedPorts, lp)
404
405 if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil {
406 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
407 return false, err
408 }
409
410 // Update the device routes with this new logical port
411 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
412 go func() {
413 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
414 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": lp.OfpPort.PortNo, "error": err})
415 }
416 }()
417
418 return true, nil
419}
420
421func (agent *LogicalAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
422 ldevice := agent.getLogicalDeviceWithoutLock()
423 for _, lPort := range ldevice.Ports {
424 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
425 return true
426 }
427 }
428 return false
429}
430
431// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
432// added and an eror in case a valid error is encountered. If the port was successfully added it will return
433// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
434// scenario. This also applies to the case where the port was already added.
435func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
436 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
437 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
438 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
439 return false, nil
440 }
441 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
442 return false, err
443 }
444
445 if agent.portExist(childDevice, port) {
446 logger.Debugw("port-already-exist", log.Fields{"port": port})
447 agent.requestQueue.RequestComplete()
448 return false, nil
449 }
450 agent.requestQueue.RequestComplete()
451 var portCap *ic.PortCapability
452 var err error
453 // First get the port capability
454 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
455 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
456 return false, err
457 }
458 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
459 return false, err
460 }
461 defer agent.requestQueue.RequestComplete()
462 // Double check again if this port has been already added since the getPortCapability could have taken a long time
463 if agent.portExist(childDevice, port) {
464 logger.Debugw("port-already-exist", log.Fields{"port": port})
465 return false, nil
466 }
467 // Get stored logical device
468 ldevice := agent.getLogicalDeviceWithoutLock()
469
470 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
471 portCap.Port.RootPort = false
472 portCap.Port.Id = port.Label
473 portCap.Port.OfpPort.PortNo = port.PortNo
474 portCap.Port.DeviceId = childDevice.Id
475 portCap.Port.DevicePortNo = port.PortNo
476 clonedPorts := clonePorts(ldevice.Ports)
477 if clonedPorts == nil {
478 clonedPorts = make([]*voltha.LogicalPort, 0)
479 }
480 clonedPorts = append(clonedPorts, portCap.Port)
481 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil {
482 return false, err
483 }
484 // Update the device graph with this new logical port
485 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
486
487 go func() {
488 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
489 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
490 }
491 }()
492
493 return true, nil
494}
495
496func clonePorts(ports []*voltha.LogicalPort) []*voltha.LogicalPort {
497 return proto.Clone(&voltha.LogicalPorts{Items: ports}).(*voltha.LogicalPorts).Items
498}
499
500//updateLogicalDevicePortsWithoutLock updates the
501func (agent *LogicalAgent) updateLogicalDevicePortsWithoutLock(ctx context.Context, device *voltha.LogicalDevice, newPorts []*voltha.LogicalPort) error {
502 oldPorts := device.Ports
503 device.Ports = newPorts
504 if err := agent.updateLogicalDeviceWithoutLock(ctx, device); err != nil {
505 return err
506 }
507 agent.portUpdated(oldPorts, newPorts)
508 return nil
509}
510
511// diff go over two lists of logical ports and return what's new, what's changed and what's removed.
512func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts map[string]*voltha.LogicalPort) {
513 newPorts = make(map[string]*voltha.LogicalPort, len(newList))
514 changedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
515 deletedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
516
517 for _, n := range newList {
518 newPorts[n.Id] = n
519 }
520
521 for _, o := range oldList {
522 if n, have := newPorts[o.Id]; have {
523 delete(newPorts, o.Id) // not new
524 if !proto.Equal(n, o) {
525 changedPorts[n.Id] = n // changed
526 }
527 } else {
528 deletedPorts[o.Id] = o // deleted
529 }
530 }
531
532 return newPorts, changedPorts, deletedPorts
533}
534
535// portUpdated is invoked when a port is updated on the logical device
536func (agent *LogicalAgent) portUpdated(prevPorts, currPorts []*voltha.LogicalPort) interface{} {
537 // Get the difference between the two list
538 newPorts, changedPorts, deletedPorts := diff(prevPorts, currPorts)
539
540 // Send the port change events to the OF controller
541 for _, newP := range newPorts {
542 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
543 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
544 }
545 for _, change := range changedPorts {
546 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
547 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
548 }
549 for _, del := range deletedPorts {
550 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
551 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
552 }
553
554 return nil
555}
556
557//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
558//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
559//device is already held. Therefore it is safe to retrieve the logical device without lock.
560func (agent *LogicalAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
561 lPorts := make([]uint32, 0)
562 var exclPort uint32
563 if len(excludePort) == 1 {
564 exclPort = excludePort[0]
565 }
566 lDevice := agent.getLogicalDeviceWithoutLock()
567 for _, port := range lDevice.Ports {
568 if port.OfpPort.PortNo != exclPort {
569 lPorts = append(lPorts, port.OfpPort.PortNo)
570 }
571 }
572 return lPorts
573}
574
575// helpers for agent.logicalPortsNo
576
577func (agent *LogicalAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
578 agent.lockLogicalPortsNo.Lock()
579 defer agent.lockLogicalPortsNo.Unlock()
580 if exist := agent.logicalPortsNo[portNo]; !exist {
581 agent.logicalPortsNo[portNo] = nniPort
582 }
583}
584
585func (agent *LogicalAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
586 agent.lockLogicalPortsNo.Lock()
587 defer agent.lockLogicalPortsNo.Unlock()
588 for _, lp := range lps {
589 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
590 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
591 }
592 }
593}
594
595func (agent *LogicalAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
596 agent.lockLogicalPortsNo.Lock()
597 defer agent.lockLogicalPortsNo.Unlock()
598 for _, pNo := range portsNo {
599 delete(agent.logicalPortsNo, pNo)
600 }
601}
602
603func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
604 agent.lockLogicalPortsNo.RLock()
605 defer agent.lockLogicalPortsNo.RUnlock()
606 if exist := agent.logicalPortsNo[portNo]; exist {
607 return agent.logicalPortsNo[portNo]
608 }
609 return false
610}
611
612func (agent *LogicalAgent) getFirstNNIPort() (uint32, error) {
613 agent.lockLogicalPortsNo.RLock()
614 defer agent.lockLogicalPortsNo.RUnlock()
615 for portNo, nni := range agent.logicalPortsNo {
616 if nni {
617 return portNo, nil
618 }
619 }
620 return 0, status.Error(codes.NotFound, "No NNI port found")
621}
622
623//GetNNIPorts returns NNI ports.
624func (agent *LogicalAgent) GetNNIPorts() []uint32 {
625 agent.lockLogicalPortsNo.RLock()
626 defer agent.lockLogicalPortsNo.RUnlock()
627 nniPorts := make([]uint32, 0)
628 for portNo, nni := range agent.logicalPortsNo {
629 if nni {
630 nniPorts = append(nniPorts, portNo)
631 }
632 }
633 return nniPorts
634}
635
636// getUNILogicalPortNo returns the UNI logical port number specified in the flow
637func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
638 var uniPort uint32
639 inPortNo := fu.GetInPort(flow)
640 outPortNo := fu.GetOutPort(flow)
641 if agent.isNNIPort(inPortNo) {
642 uniPort = outPortNo
643 } else if agent.isNNIPort(outPortNo) {
644 uniPort = inPortNo
645 }
646 if uniPort != 0 {
647 return uniPort, nil
648 }
649 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
650}