blob: 3ae653409768498267e0533021155da37fe1d660 [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"
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"
25 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
26 "github.com/opencord/voltha-lib-go/v3/pkg/log"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040027 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
28 "github.com/opencord/voltha-protos/v3/go/voltha"
29 "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 {
35 logger.Debug(ctx, "listLogicalDevicePorts")
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040036 portIDs := agent.portLoader.ListIDs()
37 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 {
Rohan Agrawal31f21802020-06-12 05:38:46 +000048 logger.Debugw(ctx, "updateLogicalPort", log.Fields{"deviceId": 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() {
Rohan Agrawal31f21802020-06-12 05:38:46 +000061 if err := agent.buildRoutes(context.Background()); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -040062 // Not an error - temporary state
Kent Hagerman2a07b862020-06-19 15:23:07 -040063 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 -040064 }
65 }()
66 //fallthrough
67 case voltha.Port_PON_ONU:
68 // Add the routes corresponding to that child device
69 go func() {
Kent Hagerman2a07b862020-06-19 15:23:07 -040070 if err := agent.updateAllRoutes(context.Background(), device.Id, devicePorts); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -040071 // Not an error - temporary state
Kent Hagerman2a07b862020-06-19 15:23:07 -040072 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 -040073 }
74 }()
75 default:
76 return fmt.Errorf("invalid port type %v", port)
Kent Hagerman3136fbd2020-05-14 10:30:45 -040077 }
78 return nil
79}
80
81// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
82// added to it. While the logical device was being created we could have received requests to add
83// NNI and UNI ports which were discarded. Now is the time to add them if needed
84func (agent *LogicalAgent) setupLogicalPorts(ctx context.Context) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +000085 logger.Infow(ctx, "setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040086 // First add any NNI ports which could have been missing
87 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000088 logger.Errorw(ctx, "error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040089 return err
90 }
91
92 // Now, set up the UNI ports if needed.
93 children, err := agent.deviceMgr.GetAllChildDevices(ctx, agent.rootDeviceID)
94 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000095 logger.Errorw(ctx, "error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040096 return err
97 }
98 responses := make([]coreutils.Response, 0)
99 for _, child := range children.Items {
100 response := coreutils.NewResponse()
101 responses = append(responses, response)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400102 go func(ctx context.Context, child *voltha.Device) {
103 defer response.Done()
104
105 childPorts, err := agent.deviceMgr.listDevicePorts(ctx, child.Id)
106 if err != nil {
107 logger.Error(ctx, "setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
108 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
109 return
110 }
111
112 if err = agent.setupUNILogicalPorts(ctx, child, childPorts); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000113 logger.Error(ctx, "setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400114 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
115 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400116 }(context.Background(), child)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400117 }
118 // Wait for completion
119 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
120 return status.Errorf(codes.Aborted, "errors-%s", res)
121 }
122 return nil
123}
124
125// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
126func (agent *LogicalAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000127 logger.Infow(ctx, "setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400128 // Build the logical device based on information retrieved from the device adapter
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400129
Kent Hagerman2a07b862020-06-19 15:23:07 -0400130 devicePorts, err := agent.deviceMgr.listDevicePorts(ctx, deviceID)
131 if err != nil {
132 logger.Errorw(ctx, "error-retrieving-device-ports", log.Fields{"error": err, "deviceId": deviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400133 return err
134 }
135
136 //Get UNI port number
Kent Hagerman2a07b862020-06-19 15:23:07 -0400137 for _, port := range devicePorts {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400138 if port.Type == voltha.Port_ETHERNET_NNI {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400139 if err = agent.addNNILogicalPort(ctx, deviceID, devicePorts, port); err != nil {
140 logger.Errorw(ctx, "error-adding-NNI-port", log.Fields{"error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400141 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400142 }
143 }
144 return err
145}
146
147// updatePortState updates the port state of the device
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400148func (agent *LogicalAgent) updatePortState(ctx context.Context, portNo uint32, operStatus voltha.OperStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000149 logger.Infow(ctx, "updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400150
151 portHandle, have := agent.portLoader.Lock(portNo)
152 if !have {
153 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
154 }
155 defer portHandle.Unlock()
156
157 newPort := clonePortSetState(portHandle.GetReadOnly(), operStatus)
158 if err := portHandle.Update(ctx, newPort); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400159 return err
160 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000161 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400162 return nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400163}
164
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400165func clonePortSetState(oldPort *voltha.LogicalPort, state voltha.OperStatus_Types) *voltha.LogicalPort {
166 newPort := *oldPort // only clone the struct(s) that will be changed
167 newOfpPort := *oldPort.OfpPort
168 newPort.OfpPort = &newOfpPort
169
170 if state == voltha.OperStatus_ACTIVE {
171 newOfpPort.Config = newOfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
172 newOfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
173 } else {
174 newOfpPort.Config = newOfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
175 newOfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
176 }
177 return &newPort
178}
179
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400180// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
Kent Hagerman2a07b862020-06-19 15:23:07 -0400181func (agent *LogicalAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device, childDevicePorts map[uint32]*voltha.Port) error {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400182 logger.Infow(ctx, "setupUNILogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400183 // Build the logical device based on information retrieved from the device adapter
184 var err error
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400185 //Get UNI port number
Kent Hagerman2a07b862020-06-19 15:23:07 -0400186 for _, port := range childDevicePorts {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400187 if port.Type == voltha.Port_ETHERNET_UNI {
Kent Hagerman2a07b862020-06-19 15:23:07 -0400188 if err = agent.addUNILogicalPort(ctx, childDevice.Id, childDevice.AdminState, childDevice.OperStatus, childDevicePorts, port); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000189 logger.Errorw(ctx, "error-adding-UNI-port", log.Fields{"error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400190 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400191 }
192 }
193 return err
194}
195
196// deleteAllLogicalPorts deletes all logical ports associated with this logical device
197func (agent *LogicalAgent) deleteAllLogicalPorts(ctx context.Context) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000198 logger.Infow(ctx, "updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400199
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400200 // for each port
201 for portID := range agent.portLoader.ListIDs() {
202 // TODO: can just call agent.deleteLogicalPort()?
203 if portHandle, have := agent.portLoader.Lock(portID); have {
204 oldPort := portHandle.GetReadOnly()
205 // delete
206 err := portHandle.Delete(ctx)
207 portHandle.Unlock()
208 if err != nil {
209 return err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400210 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400211 // and send event
Rohan Agrawal31f21802020-06-12 05:38:46 +0000212 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_DELETE, oldPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400213 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400214 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400215
216 // Reset the logical device routes
217 go func() {
218 if err := agent.buildRoutes(context.Background()); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000219 logger.Warnw(ctx, "device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400220 }
221 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400222 return nil
223}
224
225// deleteLogicalPorts removes the logical ports associated with that deviceId
226func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000227 logger.Debugw(ctx, "deleting-logical-ports", log.Fields{"device-id": deviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400228
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400229 // for each port
230 for portNo := range agent.portLoader.ListIDsForDevice(deviceID) {
231 if portHandle, have := agent.portLoader.Lock(portNo); have {
232 // if belongs to this device
233 if oldPort := portHandle.GetReadOnly(); oldPort.DeviceId == deviceID {
234 // delete
235 if err := portHandle.Delete(ctx); err != nil {
236 portHandle.Unlock()
237 return err
238 }
239 // and send event
Rohan Agrawal31f21802020-06-12 05:38:46 +0000240 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_DELETE, oldPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400241 }
242 portHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400243 }
244 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400245
246 // Reset the logical device routes
247 go func() {
248 if err := agent.buildRoutes(context.Background()); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000249 logger.Warnw(ctx, "routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400250 }
251 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400252 return nil
253}
254
255// enableLogicalPort enables the logical port
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400256func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortNo uint32) error {
257 portHandle, have := agent.portLoader.Lock(lPortNo)
258 if !have {
259 return status.Errorf(codes.NotFound, "port-%d-not-exist", lPortNo)
260 }
261 defer portHandle.Unlock()
262
263 oldPort := portHandle.GetReadOnly()
264
265 newPort := *oldPort // only clone the struct(s) that will be changed
266 newOfpPort := *oldPort.OfpPort
267 newPort.OfpPort = &newOfpPort
268
269 newOfpPort.Config = newOfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
270 if err := portHandle.Update(ctx, &newPort); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400271 return err
272 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000273 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400274 return nil
275}
276
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400277// disableLogicalPort disabled the logical port
278func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortNo uint32) error {
279 portHandle, have := agent.portLoader.Lock(lPortNo)
280 if !have {
281 return status.Errorf(codes.NotFound, "port-%d-not-exist", lPortNo)
282 }
283 defer portHandle.Unlock()
284
285 oldPort := portHandle.GetReadOnly()
286
287 newPort := *oldPort // only clone the struct(s) that will be changed
288 newOfpPort := *oldPort.OfpPort
289 newPort.OfpPort = &newOfpPort
290
291 newOfpPort.Config = (newOfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
292 if err := portHandle.Update(ctx, &newPort); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400293 return err
294 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000295 agent.orderedEvents.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400296 return nil
297}
298
299// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
300// added and an error in case a valid error is encountered. If the port was successfully added it will return
301// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
302// scenario. This also applies to the case where the port was already added.
Kent Hagerman2a07b862020-06-19 15:23:07 -0400303func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, deviceID string, devicePorts map[uint32]*voltha.Port, port *voltha.Port) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000304 logger.Debugw(ctx, "addNNILogicalPort", log.Fields{"logical-device-id": agent.logicalDeviceID, "nni-port": port})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400305
306 label := fmt.Sprintf("nni-%d", port.PortNo)
khenaidooc6c7bda2020-06-17 17:20:18 -0400307 ofpPort := *port.OfpPort
308 ofpPort.HwAddr = append([]uint32{}, port.OfpPort.HwAddr...)
309 ofpPort.PortNo = port.PortNo
310 ofpPort.Name = label
311 nniPort := &voltha.LogicalPort{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400312 RootPort: true,
Kent Hagerman2a07b862020-06-19 15:23:07 -0400313 DeviceId: deviceID,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400314 Id: label,
315 DevicePortNo: port.PortNo,
khenaidooc6c7bda2020-06-17 17:20:18 -0400316 OfpPort: &ofpPort,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400317 OfpPortStats: &ofp.OfpPortStats{},
318 }
319
khenaidooc6c7bda2020-06-17 17:20:18 -0400320 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, nniPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400321 if err != nil {
322 return err
323 }
324 defer portHandle.Unlock()
325
326 if !created {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000327 logger.Debugw(ctx, "port-already-exist", log.Fields{"port": port})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400328 return nil
329 }
330
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400331 // ensure that no events will be sent until this one is
332 queuePosition := agent.orderedEvents.assignQueuePosition()
khenaidoo0db4c812020-05-27 15:27:30 -0400333
334 // Setup the routes for this device and then send the port update event to the OF Controller
335 go func() {
336 // First setup the routes
Kent Hagerman2a07b862020-06-19 15:23:07 -0400337 if err := agent.updateRoutes(context.Background(), deviceID, devicePorts, nniPort, agent.listLogicalDevicePorts(ctx)); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400338 // This is not an error as we may not have enough logical ports to set up routes or some PON ports have not been
339 // created yet.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000340 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 -0400341 }
342
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400343 // send event, and allow any queued events to be sent as well
Rohan Agrawal31f21802020-06-12 05:38:46 +0000344 queuePosition.send(ctx, agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_ADD, nniPort.OfpPort)
khenaidoo0db4c812020-05-27 15:27:30 -0400345 }()
khenaidoo0db4c812020-05-27 15:27:30 -0400346 return nil
347}
348
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400349// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
350// added and an error in case a valid error is encountered. If the port was successfully added it will return
351// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
352// scenario. This also applies to the case where the port was already added.
Kent Hagerman2a07b862020-06-19 15:23:07 -0400353func (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 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000354 logger.Debugw(ctx, "addUNILogicalPort", log.Fields{"port": port})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400355 if deviceAdminState != voltha.AdminState_ENABLED || deviceOperStatus != voltha.OperStatus_ACTIVE {
356 logger.Infow(ctx, "device-not-ready", log.Fields{"deviceId": deviceID, "admin": deviceAdminState, "oper": deviceOperStatus})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400357 return nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400358 }
khenaidooc6c7bda2020-06-17 17:20:18 -0400359 ofpPort := *port.OfpPort
360 ofpPort.HwAddr = append([]uint32{}, port.OfpPort.HwAddr...)
361 ofpPort.PortNo = port.PortNo
362 uniPort := &voltha.LogicalPort{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400363 RootPort: false,
Kent Hagerman2a07b862020-06-19 15:23:07 -0400364 DeviceId: deviceID,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400365 Id: port.Label,
366 DevicePortNo: port.PortNo,
khenaidooc6c7bda2020-06-17 17:20:18 -0400367 OfpPort: &ofpPort,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400368 OfpPortStats: &ofp.OfpPortStats{},
369 }
370
khenaidooc6c7bda2020-06-17 17:20:18 -0400371 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, uniPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400372 if err != nil {
373 return err
374 }
375 defer portHandle.Unlock()
376
377 if !created {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000378 logger.Debugw(ctx, "port-already-exist", log.Fields{"port": port})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400379 return nil
380 }
381
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400382 // ensure that no events will be sent until this one is
383 queuePosition := agent.orderedEvents.assignQueuePosition()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400384
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400385 // Setup the routes for this device and then send the port update event to the OF Controller
386 go func() {
387 // First setup the routes
Kent Hagerman2a07b862020-06-19 15:23:07 -0400388 if err := agent.updateRoutes(context.Background(), deviceID, devicePorts, uniPort, agent.listLogicalDevicePorts(ctx)); err != nil {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400389 // This is not an error as we may not have enough logical ports to set up routes or some PON ports have not been
390 // created yet.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000391 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 -0400392 }
khenaidooc6c7bda2020-06-17 17:20:18 -0400393
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400394 // send event, and allow any queued events to be sent as well
Rohan Agrawal31f21802020-06-12 05:38:46 +0000395 queuePosition.send(context.Background(), agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_ADD, uniPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400396 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400397 return nil
398}
399
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400400// send is a convenience to avoid calling both assignQueuePosition and qp.send
Rohan Agrawal31f21802020-06-12 05:38:46 +0000401func (e *orderedEvents) send(ctx context.Context, agent *LogicalAgent, deviceID string, reason ofp.OfpPortReason, desc *ofp.OfpPort) {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400402 qp := e.assignQueuePosition()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000403 go qp.send(context.Background(), agent, deviceID, reason, desc)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400404}
405
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400406// TODO: shouldn't need to guarantee event ordering like this
407// event ordering should really be protected by per-LogicalPort lock
408// once routing uses on-demand calculation only, this should be changed
409// assignQueuePosition ensures that no events will be sent until this thread calls send() on the returned queuePosition
410func (e *orderedEvents) assignQueuePosition() queuePosition {
411 e.mutex.Lock()
412 defer e.mutex.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400413
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400414 prev := e.last
415 next := make(chan struct{})
416 e.last = next
417 return queuePosition{
418 prev: prev,
419 next: next,
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400420 }
421}
422
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400423// orderedEvents guarantees the order that events are sent, while allowing events to back up.
424type orderedEvents struct {
425 mutex sync.Mutex
426 last <-chan struct{}
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400427}
428
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400429type queuePosition struct {
430 prev <-chan struct{}
431 next chan<- struct{}
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400432}
433
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400434// send waits for its turn, then sends the event, then notifies the next in line
Rohan Agrawal31f21802020-06-12 05:38:46 +0000435func (qp queuePosition) send(ctx context.Context, agent *LogicalAgent, deviceID string, reason ofp.OfpPortReason, desc *ofp.OfpPort) {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400436 if qp.prev != nil {
437 <-qp.prev // wait for turn
438 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000439 agent.ldeviceMgr.SendChangeEvent(ctx, deviceID, reason, desc)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400440 close(qp.next) // notify next
441}
442
443// GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
444// returns their port numbers.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000445func (agent *LogicalAgent) GetWildcardInputPorts(ctx context.Context, excludePort uint32) map[uint32]struct{} {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400446 portIDs := agent.portLoader.ListIDs()
447 delete(portIDs, excludePort)
448 return portIDs
449}
450
451// isNNIPort return true iff the specified port belongs to the parent (OLT) device
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400452func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400453 portHandle, have := agent.portLoader.Lock(portNo)
454 if !have {
455 return false
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400456 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400457 defer portHandle.Unlock()
458
459 // any root-device logical port is an NNI port
460 return portHandle.GetReadOnly().RootPort
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400461}
462
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400463// getAnyNNIPort returns an NNI port
464func (agent *LogicalAgent) getAnyNNIPort() (uint32, error) {
465 for portID := range agent.portLoader.ListIDsForDevice(agent.rootDeviceID) {
466 return portID, nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400467 }
468 return 0, status.Error(codes.NotFound, "No NNI port found")
469}
470
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400471//GetNNIPorts returns all NNI ports
472func (agent *LogicalAgent) GetNNIPorts() map[uint32]struct{} {
473 return agent.portLoader.ListIDsForDevice(agent.rootDeviceID)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400474}
475
476// getUNILogicalPortNo returns the UNI logical port number specified in the flow
477func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
478 var uniPort uint32
479 inPortNo := fu.GetInPort(flow)
480 outPortNo := fu.GetOutPort(flow)
481 if agent.isNNIPort(inPortNo) {
482 uniPort = outPortNo
483 } else if agent.isNNIPort(outPortNo) {
484 uniPort = inPortNo
485 }
486 if uniPort != 0 {
487 return uniPort, nil
488 }
489 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
490}