blob: 8e68318faa9c7ae5109765e81bac11b7e8ac9a69 [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"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070025 "github.com/opencord/voltha-lib-go/v3/pkg/log"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070026 "github.com/opencord/voltha-protos/v3/go/voltha"
27 "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 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000119 logger.Debugw(ctx, "deleteAllPorts", log.Fields{"deviceId": 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
Kent Hagerman2a07b862020-06-19 15:23:07 -0400126 if device.AdminState != voltha.AdminState_DISABLED && device.AdminState != voltha.AdminState_DELETED {
127 err := status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-state-%v", device.AdminState))
128 logger.Warnw(ctx, "invalid-state-removing-ports", log.Fields{"state": device.AdminState, "error": err})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700129 return err
130 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700131
Kent Hagerman2a07b862020-06-19 15:23:07 -0400132 for portID := range agent.portLoader.ListIDs() {
133 if portHandle, have := agent.portLoader.Lock(portID); have {
134 if err := portHandle.Delete(ctx); err != nil {
135 portHandle.Unlock()
136 return err
137 }
138 portHandle.Unlock()
139 }
140 }
141 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700142}
143
144func (agent *Agent) addPort(ctx context.Context, port *voltha.Port) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000145 logger.Debugw(ctx, "addPort", log.Fields{"deviceId": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700146
Kent Hagerman2a07b862020-06-19 15:23:07 -0400147 port.AdminState = voltha.AdminState_ENABLED
148
149 portHandle, created, err := agent.portLoader.LockOrCreate(ctx, port)
150 if err != nil {
151 return err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700152 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400153 defer portHandle.Unlock()
154
155 if created {
156 return nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700157 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400158
159 oldPort := portHandle.GetReadOnly()
160 if oldPort.Label != "" || oldPort.Type != voltha.Port_PON_OLT {
161 logger.Debugw(ctx, "port already exists", log.Fields{"port": port})
162 return nil
163 }
164
165 // Creation of OLT PON port is being processed after a default PON port was created. Just update it.
166 logger.Infow(ctx, "update-pon-port-created-by-default", log.Fields{"default-port": oldPort, "port-to-add": port})
167 newPort := *oldPort // clone top-level port struct
168 newPort.Label = port.Label
169 newPort.OperStatus = port.OperStatus
170
171 return portHandle.Update(ctx, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700172}
173
174func (agent *Agent) addPeerPort(ctx context.Context, peerPort *voltha.Port_PeerPort) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000175 logger.Debugw(ctx, "adding-peer-peerPort", log.Fields{"device-id": agent.deviceID, "peer-peerPort": peerPort})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700176
Kent Hagerman2a07b862020-06-19 15:23:07 -0400177 var portHandle *port.Handle
178 if agent.isRootDevice {
179 // If an ONU PON port needs to be referenced before the corresponding creation of the OLT PON port, then create the OLT PON port
180 // with default values, and update it later when the OLT PON port creation is processed.
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700181 ponPort := &voltha.Port{
182 PortNo: peerPort.PortNo,
183 Type: voltha.Port_PON_OLT,
184 AdminState: voltha.AdminState_ENABLED,
185 DeviceId: agent.deviceID,
Kent Hagerman2a07b862020-06-19 15:23:07 -0400186 Peers: []*voltha.Port_PeerPort{peerPort},
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700187 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400188
189 h, created, err := agent.portLoader.LockOrCreate(ctx, ponPort)
190 if err != nil {
191 return err
192 }
193 defer h.Unlock()
194
195 if created {
196 logger.Infow(ctx, "added-default-pon-port", log.Fields{"device-id": agent.deviceID, "peer": peerPort, "pon-port": ponPort})
197 return nil
198 }
199
200 portHandle = h
201 } else {
202 h, have := agent.portLoader.Lock(peerPort.PortNo)
203 if !have {
204 return nil
205 }
206 defer h.Unlock()
207
208 portHandle = h
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700209 }
210
Kent Hagerman2a07b862020-06-19 15:23:07 -0400211 logger.Debugw(ctx, "found-peer", log.Fields{"device-id": agent.deviceID, "portNo": peerPort.PortNo, "deviceId": agent.deviceID})
212
213 newPort := proto.Clone(portHandle.GetReadOnly()).(*voltha.Port)
214 newPort.Peers = append(newPort.Peers, peerPort)
215
216 return portHandle.Update(ctx, newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700217}
218
Kent Hagerman2a07b862020-06-19 15:23:07 -0400219func (agent *Agent) disablePort(ctx context.Context, portID uint32) error {
220 logger.Debugw(ctx, "disablePort", log.Fields{"device-id": agent.deviceID, "port-no": portID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700221
Kent Hagerman2a07b862020-06-19 15:23:07 -0400222 portHandle, have := agent.portLoader.Lock(portID)
223 if !have {
224 return status.Errorf(codes.InvalidArgument, "%v", portID)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700225 }
Kent Hagerman2a07b862020-06-19 15:23:07 -0400226 defer portHandle.Unlock()
227
228 oldPort := portHandle.GetReadOnly()
229
230 if oldPort.Type != voltha.Port_PON_OLT {
231 return status.Errorf(codes.InvalidArgument, "Disabling of Port Type %v unimplemented", oldPort.Type)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700232 }
233
Kent Hagerman2a07b862020-06-19 15:23:07 -0400234 newPort := *oldPort
235 newPort.AdminState = voltha.AdminState_DISABLED
236 if err := portHandle.Update(ctx, &newPort); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700237 return err
238 }
239
240 //send request to adapter
Kent Hagermancba2f302020-07-28 13:37:36 -0400241 device, err := agent.getDeviceReadOnly(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400242 if err != nil {
243 return err
244 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000245 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400246 ch, err := agent.adapterProxy.DisablePort(ctx, device, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700247 if err != nil {
248 cancel()
249 return err
250 }
251 go agent.waitForAdapterResponse(subCtx, cancel, "disablePort", ch, agent.onSuccess, agent.onFailure)
252 return nil
253}
254
Kent Hagerman2a07b862020-06-19 15:23:07 -0400255func (agent *Agent) enablePort(ctx context.Context, portID uint32) error {
256 logger.Debugw(ctx, "enablePort", log.Fields{"device-id": agent.deviceID, "port-no": portID})
257
258 portHandle, have := agent.portLoader.Lock(portID)
259 if !have {
260 return status.Errorf(codes.InvalidArgument, "%v", portID)
261 }
262 defer portHandle.Unlock()
263
264 oldPort := portHandle.GetReadOnly()
265
266 if oldPort.Type != voltha.Port_PON_OLT {
267 return status.Errorf(codes.InvalidArgument, "Enabling of Port Type %v unimplemented", oldPort.Type)
268 }
269
270 newPort := *oldPort
271 newPort.AdminState = voltha.AdminState_ENABLED
272 if err := portHandle.Update(ctx, &newPort); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700273 return err
274 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700275
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700276 //send request to adapter
Kent Hagermancba2f302020-07-28 13:37:36 -0400277 device, err := agent.getDeviceReadOnly(ctx)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400278 if err != nil {
279 return err
280 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000281 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400282 ch, err := agent.adapterProxy.EnablePort(ctx, device, &newPort)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700283 if err != nil {
284 cancel()
285 return err
286 }
287 go agent.waitForAdapterResponse(subCtx, cancel, "enablePort", ch, agent.onSuccess, agent.onFailure)
288 return nil
289}