blob: a3489fc0fe4983ea74c6d82e93848efa9e7a259a [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"
Maninderdfadc982020-10-28 14:04:33 +053025 "github.com/opencord/voltha-lib-go/v4/pkg/log"
26 "github.com/opencord/voltha-protos/v4/go/voltha"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070027 "google.golang.org/grpc/codes"
28 "google.golang.org/grpc/status"
29)
30
Kent Hagerman2a07b862020-06-19 15:23:07 -040031// listDevicePorts returns device ports
32func (agent *Agent) listDevicePorts() map[uint32]*voltha.Port {
33 portIDs := agent.portLoader.ListIDs()
34 ports := make(map[uint32]*voltha.Port, len(portIDs))
35 for portID := range portIDs {
36 if portHandle, have := agent.portLoader.Lock(portID); have {
37 ports[portID] = portHandle.GetReadOnly()
38 portHandle.Unlock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070039 }
40 }
41 return ports
42}
43
Kent Hagerman2a07b862020-06-19 15:23:07 -040044// getPorts retrieves the ports information of the device based on the port type.
45func (agent *Agent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
46 logger.Debugw(ctx, "getPorts", log.Fields{"device-id": agent.deviceID, "port-type": portType})
47 ports := &voltha.Ports{}
48 for _, port := range agent.listDevicePorts() {
49 if port.Type == portType {
50 ports.Items = append(ports.Items, port)
51 }
52 }
53 return ports
54}
55
56func (agent *Agent) getDevicePort(portID uint32) (*voltha.Port, error) {
57 portHandle, have := agent.portLoader.Lock(portID)
58 if !have {
59 return nil, status.Errorf(codes.NotFound, "port-%d", portID)
60 }
61 defer portHandle.Unlock()
62 return portHandle.GetReadOnly(), nil
63}
64
65func (agent *Agent) updatePortsOperState(ctx context.Context, portTypeFilter uint32, operStatus voltha.OperStatus_Types) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +000066 logger.Debugw(ctx, "updatePortsOperState", log.Fields{"device-id": agent.deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -040067
68 for portID := range agent.portLoader.ListIDs() {
69 if portHandle, have := agent.portLoader.Lock(portID); have {
70 if oldPort := portHandle.GetReadOnly(); (1<<oldPort.Type)&portTypeFilter == 0 { // only update port types not included in the mask
71 // clone top-level port struct
72 newPort := *oldPort
73 newPort.OperStatus = operStatus
74 if err := portHandle.Update(ctx, &newPort); err != nil {
75 portHandle.Unlock()
76 return err
77 }
78
79 // Notify the logical device manager to change the port state
80 // Do this for NNI and UNIs only. PON ports are not known by logical device
81 if newPort.Type == voltha.Port_ETHERNET_NNI || newPort.Type == voltha.Port_ETHERNET_UNI {
82 go func(portID uint32, ctx context.Context) {
83 if err := agent.deviceMgr.logicalDeviceMgr.updatePortState(ctx, agent.deviceID, portID, operStatus); err != nil {
84 // TODO: VOL-2707
85 logger.Warnw(ctx, "unable-to-update-logical-port-state", log.Fields{"error": err})
86 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +000087 }(portID, log.WithSpanFromContext(context.Background(), ctx))
Kent Hagerman2a07b862020-06-19 15:23:07 -040088 }
89 }
90 portHandle.Unlock()
91 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070092 }
Kent Hagerman2a07b862020-06-19 15:23:07 -040093 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070094}
95
96func (agent *Agent) updatePortState(ctx context.Context, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070097 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
98 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
99 return status.Errorf(codes.InvalidArgument, "%s", portType)
100 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400101
102 portHandle, have := agent.portLoader.Lock(portNo)
103 if !have {
104 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700105 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400106 defer portHandle.Unlock()
107
108 port := portHandle.GetReadOnly()
109 if port.Type != portType {
110 return nil
111 }
112
113 newPort := *port // clone top-level port struct
114 newPort.OperStatus = operStatus
115 return portHandle.Update(ctx, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700116}
117
118func (agent *Agent) deleteAllPorts(ctx context.Context) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000119 logger.Debugw(ctx, "deleteAllPorts", log.Fields{"device-id": agent.deviceID})
Kent Hagerman2a07b862020-06-19 15:23:07 -0400120
Kent Hagermancba2f302020-07-28 13:37:36 -0400121 device, err := agent.getDeviceReadOnly(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400122 if err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700123 return err
124 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700125
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530126 if device.AdminState != voltha.AdminState_DISABLED && !agent.isDeletionInProgress() {
127 err := status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-admin-state-%v",
128 device.AdminState))
Kent Hagerman2a07b862020-06-19 15:23:07 -0400129 logger.Warnw(ctx, "invalid-state-removing-ports", log.Fields{"state": device.AdminState, "error": err})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700130 return err
131 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700132
Kent Hagerman2a07b862020-06-19 15:23:07 -0400133 for portID := range agent.portLoader.ListIDs() {
134 if portHandle, have := agent.portLoader.Lock(portID); have {
135 if err := portHandle.Delete(ctx); err != nil {
136 portHandle.Unlock()
137 return err
138 }
139 portHandle.Unlock()
140 }
141 }
142 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700143}
144
145func (agent *Agent) addPort(ctx context.Context, port *voltha.Port) error {
divyadesaicb8b59d2020-08-18 09:55:47 +0000146 logger.Debugw(ctx, "addPort", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700147
Kent Hagerman2a07b862020-06-19 15:23:07 -0400148 port.AdminState = voltha.AdminState_ENABLED
149
150 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, port)
151 if err != nil {
152 return err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700153 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400154 defer portHandle.Unlock()
155
156 if created {
157 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700158 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400159
160 oldPort := portHandle.GetReadOnly()
161 if oldPort.Label != "" || oldPort.Type != voltha.Port_PON_OLT {
162 logger.Debugw(ctx, "port already exists", log.Fields{"port": port})
163 return nil
164 }
165
166 // Creation of OLT PON port is being processed after a default PON port was created. Just update it.
167 logger.Infow(ctx, "update-pon-port-created-by-default", log.Fields{"default-port": oldPort, "port-to-add": port})
168 newPort := *oldPort // clone top-level port struct
169 newPort.Label = port.Label
170 newPort.OperStatus = port.OperStatus
171
172 return portHandle.Update(ctx, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700173}
174
175func (agent *Agent) addPeerPort(ctx context.Context, peerPort *voltha.Port_PeerPort) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000176 logger.Debugw(ctx, "adding-peer-peerPort", log.Fields{"device-id": agent.deviceID, "peer-peerPort": peerPort})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700177
Kent Hagerman2a07b862020-06-19 15:23:07 -0400178 var portHandle *port.Handle
179 if agent.isRootDevice {
180 // If an ONU PON port needs to be referenced before the corresponding creation of the OLT PON port, then create the OLT PON port
181 // with default values, and update it later when the OLT PON port creation is processed.
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700182 ponPort := &voltha.Port{
183 PortNo: peerPort.PortNo,
184 Type: voltha.Port_PON_OLT,
185 AdminState: voltha.AdminState_ENABLED,
186 DeviceId: agent.deviceID,
Kent Hagerman2a07b862020-06-19 15:23:07 -0400187 Peers: []*voltha.Port_PeerPort{peerPort},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700188 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400189
190 h, created, err := agent.portLoader.LockOrCreate(ctx, ponPort)
191 if err != nil {
192 return err
193 }
194 defer h.Unlock()
195
196 if created {
197 logger.Infow(ctx, "added-default-pon-port", log.Fields{"device-id": agent.deviceID, "peer": peerPort, "pon-port": ponPort})
198 return nil
199 }
200
201 portHandle = h
202 } else {
203 h, have := agent.portLoader.Lock(peerPort.PortNo)
204 if !have {
205 return nil
206 }
207 defer h.Unlock()
208
209 portHandle = h
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700210 }
211
Kent Hagerman2a07b862020-06-19 15:23:07 -0400212 logger.Debugw(ctx, "found-peer", log.Fields{"device-id": agent.deviceID, "portNo": peerPort.PortNo, "deviceId": agent.deviceID})
213
214 newPort := proto.Clone(portHandle.GetReadOnly()).(*voltha.Port)
215 newPort.Peers = append(newPort.Peers, peerPort)
216
217 return portHandle.Update(ctx, newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700218}
219
Kent Hagerman2a07b862020-06-19 15:23:07 -0400220func (agent *Agent) disablePort(ctx context.Context, portID uint32) error {
221 logger.Debugw(ctx, "disablePort", log.Fields{"device-id": agent.deviceID, "port-no": portID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700222
Kent Hagerman2a07b862020-06-19 15:23:07 -0400223 portHandle, have := agent.portLoader.Lock(portID)
224 if !have {
225 return status.Errorf(codes.InvalidArgument, "%v", portID)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700226 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400227 defer portHandle.Unlock()
228
229 oldPort := portHandle.GetReadOnly()
230
231 if oldPort.Type != voltha.Port_PON_OLT {
232 return status.Errorf(codes.InvalidArgument, "Disabling of Port Type %v unimplemented", oldPort.Type)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700233 }
234
Kent Hagerman2a07b862020-06-19 15:23:07 -0400235 newPort := *oldPort
236 newPort.AdminState = voltha.AdminState_DISABLED
237 if err := portHandle.Update(ctx, &newPort); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700238 return err
239 }
240
241 //send request to adapter
Kent Hagermancba2f302020-07-28 13:37:36 -0400242 device, err := agent.getDeviceReadOnly(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400243 if err != nil {
244 return err
245 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000246 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400247 ch, err := agent.adapterProxy.DisablePort(ctx, device, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700248 if err != nil {
249 cancel()
250 return err
251 }
252 go agent.waitForAdapterResponse(subCtx, cancel, "disablePort", ch, agent.onSuccess, agent.onFailure)
253 return nil
254}
255
Kent Hagerman2a07b862020-06-19 15:23:07 -0400256func (agent *Agent) enablePort(ctx context.Context, portID uint32) error {
257 logger.Debugw(ctx, "enablePort", log.Fields{"device-id": agent.deviceID, "port-no": portID})
258
259 portHandle, have := agent.portLoader.Lock(portID)
260 if !have {
261 return status.Errorf(codes.InvalidArgument, "%v", portID)
262 }
263 defer portHandle.Unlock()
264
265 oldPort := portHandle.GetReadOnly()
266
267 if oldPort.Type != voltha.Port_PON_OLT {
268 return status.Errorf(codes.InvalidArgument, "Enabling of Port Type %v unimplemented", oldPort.Type)
269 }
270
271 newPort := *oldPort
272 newPort.AdminState = voltha.AdminState_ENABLED
273 if err := portHandle.Update(ctx, &newPort); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700274 return err
275 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700276
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700277 //send request to adapter
Kent Hagermancba2f302020-07-28 13:37:36 -0400278 device, err := agent.getDeviceReadOnly(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400279 if err != nil {
280 return err
281 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000282 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400283 ch, err := agent.adapterProxy.EnablePort(ctx, device, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700284 if err != nil {
285 cancel()
286 return err
287 }
288 go agent.waitForAdapterResponse(subCtx, cancel, "enablePort", ch, agent.onSuccess, agent.onFailure)
289 return nil
290}