blob: 6e53d168cc2092e003cfc6f8addd310d93a69beb [file] [log] [blame]
Mahir Gunyelfa6ea272020-06-10 17:03:51 -07001/*
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"
Kent Hagerman2a07b862020-06-19 15:23:07 -040024 "github.com/opencord/voltha-go/rw_core/core/device/port"
Himani Chawlab4c25912020-11-12 17:16:38 +053025 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Maninderdfadc982020-10-28 14:04:33 +053026 "github.com/opencord/voltha-lib-go/v4/pkg/log"
27 "github.com/opencord/voltha-protos/v4/go/voltha"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
30)
31
Kent Hagerman2a07b862020-06-19 15:23:07 -040032// listDevicePorts returns device ports
33func (agent *Agent) listDevicePorts() map[uint32]*voltha.Port {
34 portIDs := agent.portLoader.ListIDs()
35 ports := make(map[uint32]*voltha.Port, len(portIDs))
36 for portID := range portIDs {
37 if portHandle, have := agent.portLoader.Lock(portID); have {
38 ports[portID] = portHandle.GetReadOnly()
39 portHandle.Unlock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070040 }
41 }
42 return ports
43}
44
Kent Hagerman2a07b862020-06-19 15:23:07 -040045// getPorts retrieves the ports information of the device based on the port type.
46func (agent *Agent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
Himani Chawlab4c25912020-11-12 17:16:38 +053047 logger.Debugw(ctx, "get-ports", log.Fields{"device-id": agent.deviceID, "port-type": portType})
Kent Hagerman2a07b862020-06-19 15:23:07 -040048 ports := &voltha.Ports{}
49 for _, port := range agent.listDevicePorts() {
50 if port.Type == portType {
51 ports.Items = append(ports.Items, port)
52 }
53 }
54 return ports
55}
56
57func (agent *Agent) getDevicePort(portID uint32) (*voltha.Port, error) {
58 portHandle, have := agent.portLoader.Lock(portID)
59 if !have {
60 return nil, status.Errorf(codes.NotFound, "port-%d", portID)
61 }
62 defer portHandle.Unlock()
63 return portHandle.GetReadOnly(), nil
64}
65
66func (agent *Agent) updatePortsOperState(ctx context.Context, portTypeFilter uint32, operStatus voltha.OperStatus_Types) error {
Himani Chawlab4c25912020-11-12 17:16:38 +053067 logger.Debugw(ctx, "update-ports-oper-state", log.Fields{"device-id": agent.deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -040068
69 for portID := range agent.portLoader.ListIDs() {
70 if portHandle, have := agent.portLoader.Lock(portID); have {
71 if oldPort := portHandle.GetReadOnly(); (1<<oldPort.Type)&portTypeFilter == 0 { // only update port types not included in the mask
72 // clone top-level port struct
73 newPort := *oldPort
74 newPort.OperStatus = operStatus
75 if err := portHandle.Update(ctx, &newPort); err != nil {
76 portHandle.Unlock()
77 return err
78 }
79
80 // Notify the logical device manager to change the port state
81 // Do this for NNI and UNIs only. PON ports are not known by logical device
82 if newPort.Type == voltha.Port_ETHERNET_NNI || newPort.Type == voltha.Port_ETHERNET_UNI {
Himani Chawlab4c25912020-11-12 17:16:38 +053083 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
84
Kent Hagerman2a07b862020-06-19 15:23:07 -040085 go func(portID uint32, ctx context.Context) {
86 if err := agent.deviceMgr.logicalDeviceMgr.updatePortState(ctx, agent.deviceID, portID, operStatus); err != nil {
87 // TODO: VOL-2707
88 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
89 }
Himani Chawlab4c25912020-11-12 17:16:38 +053090 }(portID, subCtx)
Kent Hagerman2a07b862020-06-19 15:23:07 -040091 }
92 }
93 portHandle.Unlock()
94 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070095 }
Kent Hagerman2a07b862020-06-19 15:23:07 -040096 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070097}
98
99func (agent *Agent) updatePortState(ctx context.Context, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700100 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
101 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
102 return status.Errorf(codes.InvalidArgument, "%s", portType)
103 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400104
105 portHandle, have := agent.portLoader.Lock(portNo)
106 if !have {
107 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700108 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400109 defer portHandle.Unlock()
110
111 port := portHandle.GetReadOnly()
112 if port.Type != portType {
113 return nil
114 }
115
116 newPort := *port // clone top-level port struct
117 newPort.OperStatus = operStatus
118 return portHandle.Update(ctx, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700119}
120
121func (agent *Agent) deleteAllPorts(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530122 logger.Debugw(ctx, "delete-all-ports", log.Fields{"device-id": agent.deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400123
Kent Hagermancba2f302020-07-28 13:37:36 -0400124 device, err := agent.getDeviceReadOnly(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400125 if err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700126 return err
127 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700128
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530129 if device.AdminState != voltha.AdminState_DISABLED && !agent.isDeletionInProgress() {
130 err := status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-admin-state-%v",
131 device.AdminState))
Kent Hagerman2a07b862020-06-19 15:23:07 -0400132 logger.Warnw(ctx, "invalid-state-removing-ports", log.Fields{"state": device.AdminState, "error": err})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700133 return err
134 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700135
Kent Hagerman2a07b862020-06-19 15:23:07 -0400136 for portID := range agent.portLoader.ListIDs() {
137 if portHandle, have := agent.portLoader.Lock(portID); have {
138 if err := portHandle.Delete(ctx); err != nil {
139 portHandle.Unlock()
140 return err
141 }
142 portHandle.Unlock()
143 }
144 }
145 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700146}
147
148func (agent *Agent) addPort(ctx context.Context, port *voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000149 logger.Debugw(ctx, "addPort", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700150
Kent Hagerman2a07b862020-06-19 15:23:07 -0400151 port.AdminState = voltha.AdminState_ENABLED
152
153 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, port)
154 if err != nil {
155 return err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700156 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400157 defer portHandle.Unlock()
158
159 if created {
160 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700161 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400162
163 oldPort := portHandle.GetReadOnly()
164 if oldPort.Label != "" || oldPort.Type != voltha.Port_PON_OLT {
Himani Chawlab4c25912020-11-12 17:16:38 +0530165 logger.Debugw(ctx, "port-already-exists", log.Fields{"port": port})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400166 return nil
167 }
168
169 // Creation of OLT PON port is being processed after a default PON port was created. Just update it.
170 logger.Infow(ctx, "update-pon-port-created-by-default", log.Fields{"default-port": oldPort, "port-to-add": port})
171 newPort := *oldPort // clone top-level port struct
172 newPort.Label = port.Label
173 newPort.OperStatus = port.OperStatus
174
175 return portHandle.Update(ctx, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700176}
177
178func (agent *Agent) addPeerPort(ctx context.Context, peerPort *voltha.Port_PeerPort) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000179 logger.Debugw(ctx, "adding-peer-peerPort", log.Fields{"device-id": agent.deviceID, "peer-peerPort": peerPort})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700180
Kent Hagerman2a07b862020-06-19 15:23:07 -0400181 var portHandle *port.Handle
182 if agent.isRootDevice {
183 // If an ONU PON port needs to be referenced before the corresponding creation of the OLT PON port, then create the OLT PON port
184 // with default values, and update it later when the OLT PON port creation is processed.
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700185 ponPort := &voltha.Port{
186 PortNo: peerPort.PortNo,
187 Type: voltha.Port_PON_OLT,
188 AdminState: voltha.AdminState_ENABLED,
189 DeviceId: agent.deviceID,
Kent Hagerman2a07b862020-06-19 15:23:07 -0400190 Peers: []*voltha.Port_PeerPort{peerPort},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700191 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400192
193 h, created, err := agent.portLoader.LockOrCreate(ctx, ponPort)
194 if err != nil {
195 return err
196 }
197 defer h.Unlock()
198
199 if created {
200 logger.Infow(ctx, "added-default-pon-port", log.Fields{"device-id": agent.deviceID, "peer": peerPort, "pon-port": ponPort})
201 return nil
202 }
203
204 portHandle = h
205 } else {
206 h, have := agent.portLoader.Lock(peerPort.PortNo)
207 if !have {
208 return nil
209 }
210 defer h.Unlock()
211
212 portHandle = h
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700213 }
214
Kent Hagerman2a07b862020-06-19 15:23:07 -0400215 logger.Debugw(ctx, "found-peer", log.Fields{"device-id": agent.deviceID, "portNo": peerPort.PortNo, "deviceId": agent.deviceID})
216
217 newPort := proto.Clone(portHandle.GetReadOnly()).(*voltha.Port)
218 newPort.Peers = append(newPort.Peers, peerPort)
219
220 return portHandle.Update(ctx, newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700221}
222
Kent Hagerman2a07b862020-06-19 15:23:07 -0400223func (agent *Agent) disablePort(ctx context.Context, portID uint32) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530224 logger.Debugw(ctx, "disable-port", log.Fields{"device-id": agent.deviceID, "port-no": portID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700225
Kent Hagerman2a07b862020-06-19 15:23:07 -0400226 portHandle, have := agent.portLoader.Lock(portID)
227 if !have {
228 return status.Errorf(codes.InvalidArgument, "%v", portID)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700229 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400230 defer portHandle.Unlock()
231
232 oldPort := portHandle.GetReadOnly()
233
234 if oldPort.Type != voltha.Port_PON_OLT {
235 return status.Errorf(codes.InvalidArgument, "Disabling of Port Type %v unimplemented", oldPort.Type)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700236 }
237
Kent Hagerman2a07b862020-06-19 15:23:07 -0400238 newPort := *oldPort
239 newPort.AdminState = voltha.AdminState_DISABLED
240 if err := portHandle.Update(ctx, &newPort); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700241 return err
242 }
243
244 //send request to adapter
Kent Hagermancba2f302020-07-28 13:37:36 -0400245 device, err := agent.getDeviceReadOnly(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400246 if err != nil {
247 return err
248 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000249 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530250 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
251
Kent Hagerman2a07b862020-06-19 15:23:07 -0400252 ch, err := agent.adapterProxy.DisablePort(ctx, device, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700253 if err != nil {
254 cancel()
255 return err
256 }
257 go agent.waitForAdapterResponse(subCtx, cancel, "disablePort", ch, agent.onSuccess, agent.onFailure)
258 return nil
259}
260
Kent Hagerman2a07b862020-06-19 15:23:07 -0400261func (agent *Agent) enablePort(ctx context.Context, portID uint32) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530262 logger.Debugw(ctx, "enable-port", log.Fields{"device-id": agent.deviceID, "port-no": portID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400263
264 portHandle, have := agent.portLoader.Lock(portID)
265 if !have {
266 return status.Errorf(codes.InvalidArgument, "%v", portID)
267 }
268 defer portHandle.Unlock()
269
270 oldPort := portHandle.GetReadOnly()
271
272 if oldPort.Type != voltha.Port_PON_OLT {
273 return status.Errorf(codes.InvalidArgument, "Enabling of Port Type %v unimplemented", oldPort.Type)
274 }
275
276 newPort := *oldPort
277 newPort.AdminState = voltha.AdminState_ENABLED
278 if err := portHandle.Update(ctx, &newPort); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700279 return err
280 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700281
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700282 //send request to adapter
Kent Hagermancba2f302020-07-28 13:37:36 -0400283 device, err := agent.getDeviceReadOnly(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400284 if err != nil {
285 return err
286 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000287 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530288 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
289
Kent Hagerman2a07b862020-06-19 15:23:07 -0400290 ch, err := agent.adapterProxy.EnablePort(ctx, device, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700291 if err != nil {
292 cancel()
293 return err
294 }
295 go agent.waitForAdapterResponse(subCtx, cancel, "enablePort", ch, agent.onSuccess, agent.onFailure)
296 return nil
297}