blob: 2901fc4954d763394cf535be7987348f7eb8877b [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
34func (agent *LogicalAgent) listLogicalDevicePorts() map[uint32]*voltha.LogicalPort {
35 logger.Debug("listLogicalDevicePorts")
36 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
47func (agent *LogicalAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
48 logger.Debugw("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 Hagermanfa9d6d42020-05-25 11:49:40 -040051 if err := agent.addNNILogicalPort(ctx, device, 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 Hagermanfa9d6d42020-05-25 11:49:40 -040055 if err := agent.addUNILogicalPort(ctx, device, 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() {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040061 if err := agent.buildRoutes(ctx); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -040062 // Not an error - temporary state
63 logger.Infow("failed-to-update-routes-after-adding-parent-pon-port", log.Fields{"device-id": device.Id, "port": port, "ports-count": len(device.Ports), "error": err})
64 }
65 }()
66 //fallthrough
67 case voltha.Port_PON_ONU:
68 // Add the routes corresponding to that child device
69 go func() {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040070 if err := agent.updateAllRoutes(ctx, device); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -040071 // Not an error - temporary state
72 logger.Infow("failed-to-update-routes-after-adding-child-pon-port", log.Fields{"device-id": device.Id, "port": port, "ports-count": len(device.Ports), "error": err})
73 }
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 {
85 logger.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
86 // First add any NNI ports which could have been missing
87 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
88 logger.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
89 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 {
95 logger.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
96 return err
97 }
98 responses := make([]coreutils.Response, 0)
99 for _, child := range children.Items {
100 response := coreutils.NewResponse()
101 responses = append(responses, response)
102 go func(child *voltha.Device) {
103 if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil {
104 logger.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
105 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
106 }
107 response.Done()
108 }(child)
109 }
110 // Wait for completion
111 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
112 return status.Errorf(codes.Aborted, "errors-%s", res)
113 }
114 return nil
115}
116
117// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
118func (agent *LogicalAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
119 logger.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
120 // Build the logical device based on information retrieved from the device adapter
121 var err error
122
123 var device *voltha.Device
124 if device, err = agent.deviceMgr.getDevice(ctx, deviceID); err != nil {
125 logger.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
126 return err
127 }
128
129 //Get UNI port number
130 for _, port := range device.Ports {
131 if port.Type == voltha.Port_ETHERNET_NNI {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400132 if err = agent.addNNILogicalPort(ctx, device, port); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400133 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
134 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400135 }
136 }
137 return err
138}
139
140// updatePortState updates the port state of the device
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400141func (agent *LogicalAgent) updatePortState(ctx context.Context, portNo uint32, operStatus voltha.OperStatus_Types) error {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400142 logger.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400143
144 portHandle, have := agent.portLoader.Lock(portNo)
145 if !have {
146 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
147 }
148 defer portHandle.Unlock()
149
150 newPort := clonePortSetState(portHandle.GetReadOnly(), operStatus)
151 if err := portHandle.Update(ctx, newPort); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400152 return err
153 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400154 agent.orderedEvents.send(agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
155 return nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400156}
157
158// updatePortsState updates the ports state related to the device
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400159func (agent *LogicalAgent) updatePortsState(ctx context.Context, deviceID string, state voltha.OperStatus_Types) error {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400160 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400161
162 for portNo := range agent.portLoader.ListIDsForDevice(deviceID) {
163 if portHandle, have := agent.portLoader.Lock(portNo); have {
164 newPort := clonePortSetState(portHandle.GetReadOnly(), state)
165 if err := portHandle.Update(ctx, newPort); err != nil {
166 portHandle.Unlock()
167 return err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400168 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400169 agent.orderedEvents.send(agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
170
171 portHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400172 }
173 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400174 return nil
175}
176
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400177func clonePortSetState(oldPort *voltha.LogicalPort, state voltha.OperStatus_Types) *voltha.LogicalPort {
178 newPort := *oldPort // only clone the struct(s) that will be changed
179 newOfpPort := *oldPort.OfpPort
180 newPort.OfpPort = &newOfpPort
181
182 if state == voltha.OperStatus_ACTIVE {
183 newOfpPort.Config = newOfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
184 newOfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
185 } else {
186 newOfpPort.Config = newOfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
187 newOfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
188 }
189 return &newPort
190}
191
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400192// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
193func (agent *LogicalAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
194 logger.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
195 // Build the logical device based on information retrieved from the device adapter
196 var err error
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400197 //Get UNI port number
198 for _, port := range childDevice.Ports {
199 if port.Type == voltha.Port_ETHERNET_UNI {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400200 if err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400201 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
202 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400203 }
204 }
205 return err
206}
207
208// deleteAllLogicalPorts deletes all logical ports associated with this logical device
209func (agent *LogicalAgent) deleteAllLogicalPorts(ctx context.Context) error {
210 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400211
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400212 // for each port
213 for portID := range agent.portLoader.ListIDs() {
214 // TODO: can just call agent.deleteLogicalPort()?
215 if portHandle, have := agent.portLoader.Lock(portID); have {
216 oldPort := portHandle.GetReadOnly()
217 // delete
218 err := portHandle.Delete(ctx)
219 portHandle.Unlock()
220 if err != nil {
221 return err
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400222 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400223 // and send event
224 agent.orderedEvents.send(agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_DELETE, oldPort.OfpPort)
225 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400226 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400227
228 // Reset the logical device routes
229 go func() {
230 if err := agent.buildRoutes(context.Background()); err != nil {
231 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
232 }
233 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400234 return nil
235}
236
237// deleteLogicalPorts removes the logical ports associated with that deviceId
238func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
239 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400240
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400241 // for each port
242 for portNo := range agent.portLoader.ListIDsForDevice(deviceID) {
243 if portHandle, have := agent.portLoader.Lock(portNo); have {
244 // if belongs to this device
245 if oldPort := portHandle.GetReadOnly(); oldPort.DeviceId == deviceID {
246 // delete
247 if err := portHandle.Delete(ctx); err != nil {
248 portHandle.Unlock()
249 return err
250 }
251 // and send event
252 agent.orderedEvents.send(agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_DELETE, oldPort.OfpPort)
253 }
254 portHandle.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400255 }
256 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400257
258 // Reset the logical device routes
259 go func() {
260 if err := agent.buildRoutes(context.Background()); err != nil {
261 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
262 }
263 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400264 return nil
265}
266
267// enableLogicalPort enables the logical port
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400268func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortNo uint32) error {
269 portHandle, have := agent.portLoader.Lock(lPortNo)
270 if !have {
271 return status.Errorf(codes.NotFound, "port-%d-not-exist", lPortNo)
272 }
273 defer portHandle.Unlock()
274
275 oldPort := portHandle.GetReadOnly()
276
277 newPort := *oldPort // only clone the struct(s) that will be changed
278 newOfpPort := *oldPort.OfpPort
279 newPort.OfpPort = &newOfpPort
280
281 newOfpPort.Config = newOfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
282 if err := portHandle.Update(ctx, &newPort); err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400283 return err
284 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400285 agent.orderedEvents.send(agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400286 return nil
287}
288
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400289// disableLogicalPort disabled the logical port
290func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortNo uint32) error {
291 portHandle, have := agent.portLoader.Lock(lPortNo)
292 if !have {
293 return status.Errorf(codes.NotFound, "port-%d-not-exist", lPortNo)
294 }
295 defer portHandle.Unlock()
296
297 oldPort := portHandle.GetReadOnly()
298
299 newPort := *oldPort // only clone the struct(s) that will be changed
300 newOfpPort := *oldPort.OfpPort
301 newPort.OfpPort = &newOfpPort
302
303 newOfpPort.Config = (newOfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
304 if err := portHandle.Update(ctx, &newPort); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400305 return err
306 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400307 agent.orderedEvents.send(agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_MODIFY, newPort.OfpPort)
308 return nil
309}
310
311// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
312// added and an error in case a valid error is encountered. If the port was successfully added it will return
313// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
314// scenario. This also applies to the case where the port was already added.
315func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
khenaidooc6c7bda2020-06-17 17:20:18 -0400316 logger.Debugw("addNNILogicalPort", log.Fields{"logical-device-id": agent.logicalDeviceID, "nni-port": port})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400317
318 label := fmt.Sprintf("nni-%d", port.PortNo)
khenaidooc6c7bda2020-06-17 17:20:18 -0400319 ofpPort := *port.OfpPort
320 ofpPort.HwAddr = append([]uint32{}, port.OfpPort.HwAddr...)
321 ofpPort.PortNo = port.PortNo
322 ofpPort.Name = label
323 nniPort := &voltha.LogicalPort{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400324 RootPort: true,
325 DeviceId: device.Id,
326 Id: label,
327 DevicePortNo: port.PortNo,
khenaidooc6c7bda2020-06-17 17:20:18 -0400328 OfpPort: &ofpPort,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400329 OfpPortStats: &ofp.OfpPortStats{},
330 }
331
khenaidooc6c7bda2020-06-17 17:20:18 -0400332 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, nniPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400333 if err != nil {
334 return err
335 }
336 defer portHandle.Unlock()
337
338 if !created {
339 logger.Debugw("port-already-exist", log.Fields{"port": port})
340 return nil
341 }
342
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400343 // ensure that no events will be sent until this one is
344 queuePosition := agent.orderedEvents.assignQueuePosition()
khenaidoo0db4c812020-05-27 15:27:30 -0400345
346 // Setup the routes for this device and then send the port update event to the OF Controller
347 go func() {
348 // First setup the routes
khenaidooc6c7bda2020-06-17 17:20:18 -0400349 if err := agent.updateRoutes(context.Background(), device, nniPort, agent.listLogicalDevicePorts()); err != nil {
khenaidoo0db4c812020-05-27 15:27:30 -0400350 // This is not an error as we may not have enough logical ports to set up routes or some PON ports have not been
351 // created yet.
khenaidooc6c7bda2020-06-17 17:20:18 -0400352 logger.Infow("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": nniPort.OfpPort.PortNo, "error": err})
khenaidoo0db4c812020-05-27 15:27:30 -0400353 }
354
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400355 // send event, and allow any queued events to be sent as well
khenaidooc6c7bda2020-06-17 17:20:18 -0400356 queuePosition.send(agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_ADD, nniPort.OfpPort)
khenaidoo0db4c812020-05-27 15:27:30 -0400357 }()
khenaidoo0db4c812020-05-27 15:27:30 -0400358 return nil
359}
360
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400361// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
362// added and an error in case a valid error is encountered. If the port was successfully added it will return
363// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
364// scenario. This also applies to the case where the port was already added.
365func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) error {
366 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
367 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
368 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
369 return nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400370 }
khenaidooc6c7bda2020-06-17 17:20:18 -0400371 ofpPort := *port.OfpPort
372 ofpPort.HwAddr = append([]uint32{}, port.OfpPort.HwAddr...)
373 ofpPort.PortNo = port.PortNo
374 uniPort := &voltha.LogicalPort{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400375 RootPort: false,
376 DeviceId: childDevice.Id,
377 Id: port.Label,
378 DevicePortNo: port.PortNo,
khenaidooc6c7bda2020-06-17 17:20:18 -0400379 OfpPort: &ofpPort,
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400380 OfpPortStats: &ofp.OfpPortStats{},
381 }
382
khenaidooc6c7bda2020-06-17 17:20:18 -0400383 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, uniPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400384 if err != nil {
385 return err
386 }
387 defer portHandle.Unlock()
388
389 if !created {
390 logger.Debugw("port-already-exist", log.Fields{"port": port})
391 return nil
392 }
393
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400394 // ensure that no events will be sent until this one is
395 queuePosition := agent.orderedEvents.assignQueuePosition()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400396
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400397 // Setup the routes for this device and then send the port update event to the OF Controller
398 go func() {
399 // First setup the routes
khenaidooc6c7bda2020-06-17 17:20:18 -0400400 if err := agent.updateRoutes(context.Background(), childDevice, uniPort, agent.listLogicalDevicePorts()); err != nil {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400401 // This is not an error as we may not have enough logical ports to set up routes or some PON ports have not been
402 // created yet.
khenaidooc6c7bda2020-06-17 17:20:18 -0400403 logger.Infow("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": uniPort.OfpPort.PortNo, "error": err})
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400404 }
khenaidooc6c7bda2020-06-17 17:20:18 -0400405
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400406 // send event, and allow any queued events to be sent as well
khenaidooc6c7bda2020-06-17 17:20:18 -0400407 queuePosition.send(agent, agent.logicalDeviceID, ofp.OfpPortReason_OFPPR_ADD, uniPort.OfpPort)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400408 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400409 return nil
410}
411
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400412// send is a convenience to avoid calling both assignQueuePosition and qp.send
413func (e *orderedEvents) send(agent *LogicalAgent, deviceID string, reason ofp.OfpPortReason, desc *ofp.OfpPort) {
414 qp := e.assignQueuePosition()
415 go qp.send(agent, deviceID, reason, desc)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400416}
417
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400418// TODO: shouldn't need to guarantee event ordering like this
419// event ordering should really be protected by per-LogicalPort lock
420// once routing uses on-demand calculation only, this should be changed
421// assignQueuePosition ensures that no events will be sent until this thread calls send() on the returned queuePosition
422func (e *orderedEvents) assignQueuePosition() queuePosition {
423 e.mutex.Lock()
424 defer e.mutex.Unlock()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400425
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400426 prev := e.last
427 next := make(chan struct{})
428 e.last = next
429 return queuePosition{
430 prev: prev,
431 next: next,
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400432 }
433}
434
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400435// orderedEvents guarantees the order that events are sent, while allowing events to back up.
436type orderedEvents struct {
437 mutex sync.Mutex
438 last <-chan struct{}
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400439}
440
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400441type queuePosition struct {
442 prev <-chan struct{}
443 next chan<- struct{}
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400444}
445
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400446// send waits for its turn, then sends the event, then notifies the next in line
447func (qp queuePosition) send(agent *LogicalAgent, deviceID string, reason ofp.OfpPortReason, desc *ofp.OfpPort) {
448 if qp.prev != nil {
449 <-qp.prev // wait for turn
450 }
451 agent.ldeviceMgr.SendChangeEvent(deviceID, reason, desc)
452 close(qp.next) // notify next
453}
454
455// GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
456// returns their port numbers.
457func (agent *LogicalAgent) GetWildcardInputPorts(excludePort uint32) map[uint32]struct{} {
458 portIDs := agent.portLoader.ListIDs()
459 delete(portIDs, excludePort)
460 return portIDs
461}
462
463// isNNIPort return true iff the specified port belongs to the parent (OLT) device
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400464func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400465 portHandle, have := agent.portLoader.Lock(portNo)
466 if !have {
467 return false
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400468 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400469 defer portHandle.Unlock()
470
471 // any root-device logical port is an NNI port
472 return portHandle.GetReadOnly().RootPort
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400473}
474
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400475// getAnyNNIPort returns an NNI port
476func (agent *LogicalAgent) getAnyNNIPort() (uint32, error) {
477 for portID := range agent.portLoader.ListIDsForDevice(agent.rootDeviceID) {
478 return portID, nil
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400479 }
480 return 0, status.Error(codes.NotFound, "No NNI port found")
481}
482
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400483//GetNNIPorts returns all NNI ports
484func (agent *LogicalAgent) GetNNIPorts() map[uint32]struct{} {
485 return agent.portLoader.ListIDsForDevice(agent.rootDeviceID)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400486}
487
488// getUNILogicalPortNo returns the UNI logical port number specified in the flow
489func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
490 var uniPort uint32
491 inPortNo := fu.GetInPort(flow)
492 outPortNo := fu.GetOutPort(flow)
493 if agent.isNNIPort(inPortNo) {
494 uniPort = outPortNo
495 } else if agent.isNNIPort(outPortNo) {
496 uniPort = inPortNo
497 }
498 if uniPort != 0 {
499 return uniPort, nil
500 }
501 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
502}