blob: 719b6b8f3a661651d5e80dc50b626786f2b87f3f [file] [log] [blame]
Kent Hagerman3136fbd2020-05-14 10:30:45 -04001/*
Joey Armstrong5f51f2e2023-01-17 17:06:26 -05002 * Copyright 2018-2023 Open Networking Foundation (ONF) and the ONF Contributors
Kent Hagerman3136fbd2020-05-14 10:30:45 -04003
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"
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040022 "sync"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040023
Kent Hagerman3136fbd2020-05-14 10:30:45 -040024 coreutils "github.com/opencord/voltha-go/rw_core/utils"
khenaidood948f772021-08-11 17:49:24 -040025 fu "github.com/opencord/voltha-lib-go/v7/pkg/flows"
26 "github.com/opencord/voltha-lib-go/v7/pkg/log"
27 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
28 "github.com/opencord/voltha-protos/v5/go/voltha"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040029 "google.golang.org/grpc/codes"
30 "google.golang.org/grpc/status"
31)
32
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040033// listLogicalDevicePorts returns logical device ports
Rohan Agrawal31f21802020-06-12 05:38:46 +000034func (agent *LogicalAgent) listLogicalDevicePorts(ctx context.Context) map[uint32]*voltha.LogicalPort {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040035 portIDs := agent.portLoader.ListIDs()
khenaidoo7585a962021-06-10 16:15:38 -040036 logger.Debugw(ctx, "list-logical-device-ports", log.Fields{"num-ports": len(portIDs)})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040037 ret := make(map[uint32]*voltha.LogicalPort, len(portIDs))
38 for portID := range portIDs {
39 if portHandle, have := agent.portLoader.Lock(portID); have {
40 ret[portID] = portHandle.GetReadOnly()
41 portHandle.Unlock()
42 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -040043 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040044 return ret
Kent Hagerman3136fbd2020-05-14 10:30:45 -040045}
46
Kent Hagerman2a07b862020-06-19 15:23:07 -040047func (agent *LogicalAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, devicePorts map[uint32]*voltha.Port, port *voltha.Port) error {
Himani Chawlab4c25912020-11-12 17:16:38 +053048 logger.Debugw(ctx, "update-logical-port", log.Fields{"device-id": device.Id, "port": port})
khenaidoo0db4c812020-05-27 15:27:30 -040049 switch port.Type {
50 case voltha.Port_ETHERNET_NNI:
Kent Hagerman2a07b862020-06-19 15:23:07 -040051 if err := agent.addNNILogicalPort(ctx, device.Id, devicePorts, port); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -040052 return err
53 }
khenaidoo0db4c812020-05-27 15:27:30 -040054 case voltha.Port_ETHERNET_UNI:
Kent Hagerman2a07b862020-06-19 15:23:07 -040055 if err := agent.addUNILogicalPort(ctx, device.Id, device.AdminState, device.OperStatus, devicePorts, port); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -040056 return err
57 }
khenaidoo0db4c812020-05-27 15:27:30 -040058 case voltha.Port_PON_OLT:
59 // Rebuilt the routes on Parent PON port addition
60 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +053061 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
62
63 if err := agent.buildRoutes(subCtx); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -040064 // Not an error - temporary state
Kent Hagerman2a07b862020-06-19 15:23:07 -040065 logger.Infow(ctx, "failed-to-update-routes-after-adding-parent-pon-port", log.Fields{"device-id": device.Id, "port": port, "ports-count": len(devicePorts), "error": err})
khenaidoo0db4c812020-05-27 15:27:30 -040066 }
67 }()
68 //fallthrough
69 case voltha.Port_PON_ONU:
70 // Add the routes corresponding to that child device
71 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +053072 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
73 if err := agent.updateAllRoutes(subCtx, device.Id, devicePorts); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -040074 // Not an error - temporary state
Kent Hagerman2a07b862020-06-19 15:23:07 -040075 logger.Infow(ctx, "failed-to-update-routes-after-adding-child-pon-port", log.Fields{"device-id": device.Id, "port": port, "ports-count": len(devicePorts), "error": err})
khenaidoo0db4c812020-05-27 15:27:30 -040076 }
77 }()
78 default:
79 return fmt.Errorf("invalid port type %v", port)
Kent Hagerman3136fbd2020-05-14 10:30:45 -040080 }
81 return nil
82}
83
84// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
85// added to it. While the logical device was being created we could have received requests to add
86// NNI and UNI ports which were discarded. Now is the time to add them if needed
87func (agent *LogicalAgent) setupLogicalPorts(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +053088 logger.Infow(ctx, "setup-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040089 // First add any NNI ports which could have been missing
90 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +053091 logger.Errorw(ctx, "error-setting-up-nni-ports", log.Fields{"error": err, "device-id": agent.rootDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040092 return err
93 }
94
95 // Now, set up the UNI ports if needed.
khenaidood948f772021-08-11 17:49:24 -040096 children, err := agent.deviceMgr.getAllChildDevices(ctx, agent.rootDeviceID)
Kent Hagerman3136fbd2020-05-14 10:30:45 -040097 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +000098 logger.Errorw(ctx, "error-getting-child-devices", log.Fields{"error": err, "device-id": agent.rootDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040099 return err
100 }
101 responses := make([]coreutils.Response, 0)
102 for _, child := range children.Items {
103 response := coreutils.NewResponse()
104 responses = append(responses, response)
Himani Chawlab4c25912020-11-12 17:16:38 +0530105 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400106 go func(ctx context.Context, child *voltha.Device) {
107 defer response.Done()
108
109 childPorts, err := agent.deviceMgr.listDevicePorts(ctx, child.Id)
110 if err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530111 logger.Error(ctx, "setting-up-uni-ports-failed", log.Fields{"device-id": child.Id})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400112 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
113 return
114 }
115
116 if err = agent.setupUNILogicalPorts(ctx, child, childPorts); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530117 logger.Error(ctx, "setting-up-uni-ports-failed", log.Fields{"device-id": child.Id})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400118 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
119 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530120 }(subCtx, child)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400121 }
122 // Wait for completion
khenaidood948f772021-08-11 17:49:24 -0400123 if res := coreutils.WaitForNilOrErrorResponses(agent.internalTimeout, responses...); res != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400124 return status.Errorf(codes.Aborted, "errors-%s", res)
125 }
126 return nil
127}
128
129// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
130func (agent *LogicalAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530131 logger.Infow(ctx, "setup-nni-logical-ports-start", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400132 // Build the logical device based on information retrieved from the device adapter
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400133
Kent Hagerman2a07b862020-06-19 15:23:07 -0400134 devicePorts, err := agent.deviceMgr.listDevicePorts(ctx, deviceID)
135 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000136 logger.Errorw(ctx, "error-retrieving-device-ports", log.Fields{"error": err, "device-id": deviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400137 return err
138 }
139
140 //Get UNI port number
Kent Hagerman2a07b862020-06-19 15:23:07 -0400141 for _, port := range devicePorts {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400142 if port.Type == voltha.Port_ETHERNET_NNI {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400143 if err = agent.addNNILogicalPort(ctx, deviceID, devicePorts, port); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530144 logger.Errorw(ctx, "error-adding-nni-port", log.Fields{"error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400145 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400146 }
147 }
148 return err
149}
150
151// updatePortState updates the port state of the device
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400152func (agent *LogicalAgent) updatePortState(ctx context.Context, portNo uint32, operStatus voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530153 logger.Infow(ctx, "update-port-state-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "port-no": portNo, "state": operStatus})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400154
155 portHandle, have := agent.portLoader.Lock(portNo)
156 if !have {
157 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
158 }
159 defer portHandle.Unlock()
160
161 newPort := clonePortSetState(portHandle.GetReadOnly(), operStatus)
162 if err := portHandle.Update(ctx, newPort); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400163 return err
164 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000165 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400166 return nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400167}
168
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400169func clonePortSetState(oldPort *voltha.LogicalPort, state voltha.OperStatus_Types) *voltha.LogicalPort {
170 newPort := *oldPort // only clone the struct(s) that will be changed
171 newOfpPort := *oldPort.OfpPort
172 newPort.OfpPort = &newOfpPort
173
174 if state == voltha.OperStatus_ACTIVE {
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300175 newOfpPort.Config &= ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400176 newOfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
177 } else {
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300178 newOfpPort.Config |= uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400179 newOfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
180 }
181 return &newPort
182}
183
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400184// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
Kent Hagerman2a07b862020-06-19 15:23:07 -0400185func (agent *LogicalAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device, childDevicePorts map[uint32]*voltha.Port) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530186 logger.Infow(ctx, "setup-uni-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400187 // Build the logical device based on information retrieved from the device adapter
188 var err error
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400189 //Get UNI port number
Kent Hagerman2a07b862020-06-19 15:23:07 -0400190 for _, port := range childDevicePorts {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400191 if port.Type == voltha.Port_ETHERNET_UNI {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400192 if err = agent.addUNILogicalPort(ctx, childDevice.Id, childDevice.AdminState, childDevice.OperStatus, childDevicePorts, port); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530193 logger.Errorw(ctx, "error-adding-uni-port", log.Fields{"error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400194 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400195 }
196 }
197 return err
198}
199
200// deleteAllLogicalPorts deletes all logical ports associated with this logical device
201func (agent *LogicalAgent) deleteAllLogicalPorts(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530202 logger.Infow(ctx, "update-ports-state-start", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400203
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400204 // for each port
205 for portID := range agent.portLoader.ListIDs() {
206 // TODO: can just call agent.deleteLogicalPort()?
207 if portHandle, have := agent.portLoader.Lock(portID); have {
208 oldPort := portHandle.GetReadOnly()
209 // delete
210 err := portHandle.Delete(ctx)
211 portHandle.Unlock()
212 if err != nil {
213 return err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400214 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400215 // and send event
Rohan Agrawal31f21802020-06-12 05:38:46 +0000216 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_DELETE, oldPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400217 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400218 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400219
220 // Reset the logical device routes
221 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530222 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
khenaidood948f772021-08-11 17:49:24 -0400223 if err := agent.removeRoutes(subCtx); err != nil {
224 logger.Warnw(ctx, "error-removing-routes", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400225 }
226 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400227 return nil
228}
229
230// deleteLogicalPorts removes the logical ports associated with that deviceId
231func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000232 logger.Debugw(ctx, "deleting-logical-ports", log.Fields{"device-id": deviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400233
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400234 // for each port
235 for portNo := range agent.portLoader.ListIDsForDevice(deviceID) {
236 if portHandle, have := agent.portLoader.Lock(portNo); have {
237 // if belongs to this device
238 if oldPort := portHandle.GetReadOnly(); oldPort.DeviceId == deviceID {
239 // delete
240 if err := portHandle.Delete(ctx); err != nil {
241 portHandle.Unlock()
242 return err
243 }
244 // and send event
Rohan Agrawal31f21802020-06-12 05:38:46 +0000245 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_DELETE, oldPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400246 }
247 portHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400248 }
249 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400250
251 // Reset the logical device routes
252 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530253 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
254 if err := agent.buildRoutes(subCtx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000255 logger.Warnw(ctx, "routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400256 }
257 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400258 return nil
259}
260
261// enableLogicalPort enables the logical port
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400262func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortNo uint32) error {
263 portHandle, have := agent.portLoader.Lock(lPortNo)
264 if !have {
265 return status.Errorf(codes.NotFound, "port-%d-not-exist", lPortNo)
266 }
267 defer portHandle.Unlock()
268
269 oldPort := portHandle.GetReadOnly()
270
271 newPort := *oldPort // only clone the struct(s) that will be changed
272 newOfpPort := *oldPort.OfpPort
273 newPort.OfpPort = &newOfpPort
274
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +0300275 newOfpPort.Config &= ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400276 if err := portHandle.Update(ctx, &newPort); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400277 return err
278 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000279 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400280 return nil
281}
282
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400283// disableLogicalPort disabled the logical port
284func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortNo uint32) error {
285 portHandle, have := agent.portLoader.Lock(lPortNo)
286 if !have {
287 return status.Errorf(codes.NotFound, "port-%d-not-exist", lPortNo)
288 }
289 defer portHandle.Unlock()
290
291 oldPort := portHandle.GetReadOnly()
292
293 newPort := *oldPort // only clone the struct(s) that will be changed
294 newOfpPort := *oldPort.OfpPort
295 newPort.OfpPort = &newOfpPort
296
297 newOfpPort.Config = (newOfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
298 if err := portHandle.Update(ctx, &newPort); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400299 return err
300 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000301 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400302 return nil
303}
304
305// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
306// added and an error in case a valid error is encountered. If the port was successfully added it will return
307// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
308// scenario. This also applies to the case where the port was already added.
Kent Hagerman2a07b862020-06-19 15:23:07 -0400309func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, deviceID string, devicePorts map[uint32]*voltha.Port, port *voltha.Port) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530310 logger.Debugw(ctx, "add-nni-logical-port", log.Fields{"logical-device-id": agent.logicalDeviceID, "nni-port": port})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400311
312 label := fmt.Sprintf("nni-%d", port.PortNo)
khenaidooc6c7bda2020-06-17 17:20:18 -0400313 ofpPort := *port.OfpPort
314 ofpPort.HwAddr = append([]uint32{}, port.OfpPort.HwAddr...)
315 ofpPort.PortNo = port.PortNo
316 ofpPort.Name = label
317 nniPort := &voltha.LogicalPort{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400318 RootPort: true,
Kent Hagerman2a07b862020-06-19 15:23:07 -0400319 DeviceId: deviceID,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400320 Id: label,
321 DevicePortNo: port.PortNo,
khenaidooc6c7bda2020-06-17 17:20:18 -0400322 OfpPort: &ofpPort,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400323 OfpPortStats: &ofp.OfpPortStats{},
324 }
325
khenaidooc6c7bda2020-06-17 17:20:18 -0400326 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, nniPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400327 if err != nil {
328 return err
329 }
330 defer portHandle.Unlock()
331
332 if !created {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000333 logger.Debugw(ctx, "port-already-exist", log.Fields{"port": port})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400334 return nil
335 }
336
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400337 // ensure that no events will be sent until this one is
338 queuePosition := agent.orderedEvents.assignQueuePosition()
khenaidoo0db4c812020-05-27 15:27:30 -0400339
340 // Setup the routes for this device and then send the port update event to the OF Controller
341 go func() {
342 // First setup the routes
Himani Chawlab4c25912020-11-12 17:16:38 +0530343 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
344 if err := agent.updateRoutes(subCtx, deviceID, devicePorts, nniPort, agent.listLogicalDevicePorts(ctx)); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400345 // This is not an error as we may not have enough logical ports to set up routes or some PON ports have not been
346 // created yet.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000347 logger.Infow(ctx, "routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": nniPort.OfpPort.PortNo, "error": err})
khenaidoo0db4c812020-05-27 15:27:30 -0400348 }
349
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400350 // send event, and allow any queued events to be sent as well
Rohan Agrawal31f21802020-06-12 05:38:46 +0000351 queuePosition.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_ADD, nniPort.OfpPort)
khenaidoo0db4c812020-05-27 15:27:30 -0400352 }()
khenaidoo0db4c812020-05-27 15:27:30 -0400353 return nil
354}
355
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400356// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
357// added and an error in case a valid error is encountered. If the port was successfully added it will return
358// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
359// scenario. This also applies to the case where the port was already added.
Kent Hagerman2a07b862020-06-19 15:23:07 -0400360func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, deviceID string, deviceAdminState voltha.AdminState_Types, deviceOperStatus voltha.OperStatus_Types, devicePorts map[uint32]*voltha.Port, port *voltha.Port) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530361 logger.Debugw(ctx, "add-uni-logical-port", log.Fields{"port": port})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400362 if deviceAdminState != voltha.AdminState_ENABLED || deviceOperStatus != voltha.OperStatus_ACTIVE {
divyadesaicb8b59d2020-08-18 09:55:47 +0000363 logger.Infow(ctx, "device-not-ready", log.Fields{"device-id": deviceID, "admin": deviceAdminState, "oper": deviceOperStatus})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400364 return nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400365 }
khenaidooc6c7bda2020-06-17 17:20:18 -0400366 ofpPort := *port.OfpPort
367 ofpPort.HwAddr = append([]uint32{}, port.OfpPort.HwAddr...)
368 ofpPort.PortNo = port.PortNo
369 uniPort := &voltha.LogicalPort{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400370 RootPort: false,
Kent Hagerman2a07b862020-06-19 15:23:07 -0400371 DeviceId: deviceID,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400372 Id: port.Label,
373 DevicePortNo: port.PortNo,
khenaidooc6c7bda2020-06-17 17:20:18 -0400374 OfpPort: &ofpPort,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400375 OfpPortStats: &ofp.OfpPortStats{},
376 }
377
khenaidooc6c7bda2020-06-17 17:20:18 -0400378 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, uniPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400379 if err != nil {
380 return err
381 }
382 defer portHandle.Unlock()
383
384 if !created {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000385 logger.Debugw(ctx, "port-already-exist", log.Fields{"port": port})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400386 return nil
387 }
388
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400389 // ensure that no events will be sent until this one is
390 queuePosition := agent.orderedEvents.assignQueuePosition()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400391
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400392 // Setup the routes for this device and then send the port update event to the OF Controller
393 go func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530394 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400395 // First setup the routes
Himani Chawlab4c25912020-11-12 17:16:38 +0530396 if err := agent.updateRoutes(subCtx, deviceID, devicePorts, uniPort, agent.listLogicalDevicePorts(ctx)); err != nil {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400397 // This is not an error as we may not have enough logical ports to set up routes or some PON ports have not been
398 // created yet.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000399 logger.Infow(ctx, "routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": uniPort.OfpPort.PortNo, "error": err})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400400 }
khenaidooc6c7bda2020-06-17 17:20:18 -0400401
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400402 // send event, and allow any queued events to be sent as well
Himani Chawlab4c25912020-11-12 17:16:38 +0530403 queuePosition.send(subCtx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_ADD, uniPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400404 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400405 return nil
406}
Himani Chawla40af2702021-01-27 15:06:30 +0530407func (e *orderedEvents) waitForAllEventsToBeSent(ctx context.Context, cancel context.CancelFunc) error {
408 defer cancel()
409 ch := make(chan struct{})
410 e.sendCompletion(ch)
411 select {
412 case <-ctx.Done():
413 logger.Error(ctx, "timeout-while-waiting-for-event-queue-to-be-cleared")
414 return ctx.Err()
415 case <-ch:
416 logger.Debug(ctx, "event-queue-is-empty")
417 return nil
418 }
419}
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400420
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400421// send is a convenience to avoid calling both assignQueuePosition and qp.send
Rohan Agrawal31f21802020-06-12 05:38:46 +0000422func (e *orderedEvents) send(ctx context.Context, agent *LogicalAgent, deviceID string, reason ofp.OfpPortReason, desc *ofp.OfpPort) {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400423 qp := e.assignQueuePosition()
Himani Chawlab4c25912020-11-12 17:16:38 +0530424 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
425 go qp.send(subCtx, agent, deviceID, reason, desc)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400426}
427
Himani Chawla40af2702021-01-27 15:06:30 +0530428// sendCompletion will make sure that given channel is notified when queue is empty
429func (e *orderedEvents) sendCompletion(ch chan struct{}) {
430 qp := e.assignQueuePosition()
431 go qp.sendCompletion(ch)
432}
433
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400434// TODO: shouldn't need to guarantee event ordering like this
435// event ordering should really be protected by per-LogicalPort lock
436// once routing uses on-demand calculation only, this should be changed
437// assignQueuePosition ensures that no events will be sent until this thread calls send() on the returned queuePosition
438func (e *orderedEvents) assignQueuePosition() queuePosition {
439 e.mutex.Lock()
440 defer e.mutex.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400441
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400442 prev := e.last
443 next := make(chan struct{})
444 e.last = next
445 return queuePosition{
446 prev: prev,
447 next: next,
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400448 }
449}
450
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400451// orderedEvents guarantees the order that events are sent, while allowing events to back up.
452type orderedEvents struct {
453 mutex sync.Mutex
454 last <-chan struct{}
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400455}
456
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400457type queuePosition struct {
458 prev <-chan struct{}
459 next chan<- struct{}
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400460}
461
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400462// send waits for its turn, then sends the event, then notifies the next in line
Rohan Agrawal31f21802020-06-12 05:38:46 +0000463func (qp queuePosition) send(ctx context.Context, agent *LogicalAgent, deviceID string, reason ofp.OfpPortReason, desc *ofp.OfpPort) {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400464 if qp.prev != nil {
465 <-qp.prev // wait for turn
466 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000467 agent.ldeviceMgr.SendChangeEvent(ctx, deviceID, reason, desc)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400468 close(qp.next) // notify next
Himani Chawla40af2702021-01-27 15:06:30 +0530469
470}
471
472// sendCompletion waits for its turn, then notifies the given channel that queue is empty
473func (qp queuePosition) sendCompletion(ch chan struct{}) {
474 if qp.prev != nil {
475 <-qp.prev // wait for turn
476 }
477 close(ch)
478 close(qp.next)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400479}
480
481// GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
482// returns their port numbers.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000483func (agent *LogicalAgent) GetWildcardInputPorts(ctx context.Context, excludePort uint32) map[uint32]struct{} {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400484 portIDs := agent.portLoader.ListIDs()
485 delete(portIDs, excludePort)
486 return portIDs
487}
488
489// isNNIPort return true iff the specified port belongs to the parent (OLT) device
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400490func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400491 portHandle, have := agent.portLoader.Lock(portNo)
492 if !have {
493 return false
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400494 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400495 defer portHandle.Unlock()
496
497 // any root-device logical port is an NNI port
498 return portHandle.GetReadOnly().RootPort
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400499}
500
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400501// getAnyNNIPort returns an NNI port
502func (agent *LogicalAgent) getAnyNNIPort() (uint32, error) {
503 for portID := range agent.portLoader.ListIDsForDevice(agent.rootDeviceID) {
504 return portID, nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400505 }
506 return 0, status.Error(codes.NotFound, "No NNI port found")
507}
508
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400509//GetNNIPorts returns all NNI ports
510func (agent *LogicalAgent) GetNNIPorts() map[uint32]struct{} {
511 return agent.portLoader.ListIDsForDevice(agent.rootDeviceID)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400512}
513
514// getUNILogicalPortNo returns the UNI logical port number specified in the flow
515func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400516 inPortNo := fu.GetInPort(flow)
517 outPortNo := fu.GetOutPort(flow)
khenaidood948f772021-08-11 17:49:24 -0400518 if inPortNo == 0 && outPortNo == 0 {
519 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400520 }
khenaidood948f772021-08-11 17:49:24 -0400521 if inPortNo != 0 && !agent.isNNIPort(inPortNo) {
522 return inPortNo, nil
523 }
524 if outPortNo != 0 && !agent.isNNIPort(outPortNo) {
525 return outPortNo, nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400526 }
527 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
528}