blob: 2d7d21054bb50d1ab1c8ffd51bbdd0ebe000954b [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"
24 "github.com/golang/protobuf/ptypes"
25 "github.com/opencord/voltha-lib-go/v3/pkg/log"
26 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
27 "github.com/opencord/voltha-protos/v3/go/voltha"
28 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
30)
31
32// getPorts retrieves the ports information of the device based on the port type.
33func (agent *Agent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
34 logger.Debugw("getPorts", log.Fields{"device-id": agent.deviceID, "port-type": portType})
35 ports := &voltha.Ports{}
36 if device, _ := agent.deviceMgr.getDevice(ctx, agent.deviceID); device != nil {
37 for _, port := range device.Ports {
38 if port.Type == portType {
39 ports.Items = append(ports.Items, port)
40 }
41 }
42 }
43 return ports
44}
45
46// getPortCapability retrieves the port capability of a device
47func (agent *Agent) getPortCapability(ctx context.Context, portNo uint32) (*ic.PortCapability, error) {
48 logger.Debugw("getPortCapability", log.Fields{"device-id": agent.deviceID})
49 device, err := agent.getDevice(ctx)
50 if err != nil {
51 return nil, err
52 }
53 ch, err := agent.adapterProxy.GetOfpPortInfo(ctx, device, portNo)
54 if err != nil {
55 return nil, err
56 }
57 // Wait for adapter response
58 rpcResponse, ok := <-ch
59 if !ok {
60 return nil, status.Errorf(codes.Aborted, "channel-closed")
61 }
62 if rpcResponse.Err != nil {
63 return nil, rpcResponse.Err
64 }
65 // Successful response
66 portCap := &ic.PortCapability{}
67 if err := ptypes.UnmarshalAny(rpcResponse.Reply, portCap); err != nil {
68 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
69 }
70 return portCap, nil
71}
72func (agent *Agent) updatePortsOperState(ctx context.Context, operStatus voltha.OperStatus_Types) error {
73 logger.Debugw("updatePortsOperState", log.Fields{"device-id": agent.deviceID})
74 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
75 return err
76 }
77 defer agent.requestQueue.RequestComplete()
78 cloned := agent.getDeviceWithoutLock()
79 for _, port := range cloned.Ports {
80 port.OperStatus = operStatus
81 }
82 // Store the device
83 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
84}
85
86func (agent *Agent) updatePortState(ctx context.Context, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_Types) error {
87 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
88 return err
89 }
90 defer agent.requestQueue.RequestComplete()
91 // Work only on latest data
92 // TODO: Get list of ports from device directly instead of the entire device
93 cloned := agent.getDeviceWithoutLock()
94
95 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
96 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
97 return status.Errorf(codes.InvalidArgument, "%s", portType)
98 }
99 for _, port := range cloned.Ports {
100 if port.Type == portType && port.PortNo == portNo {
101 port.OperStatus = operStatus
102 }
103 }
104 logger.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
105 // Store the device
106 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
107}
108
109func (agent *Agent) deleteAllPorts(ctx context.Context) error {
110 logger.Debugw("deleteAllPorts", log.Fields{"deviceId": agent.deviceID})
111 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
112 return err
113 }
114 defer agent.requestQueue.RequestComplete()
115
116 cloned := agent.getDeviceWithoutLock()
117
118 if cloned.AdminState != voltha.AdminState_DISABLED && cloned.AdminState != voltha.AdminState_DELETED {
119 err := status.Error(codes.FailedPrecondition, fmt.Sprintf("invalid-state-%v", cloned.AdminState))
120 logger.Warnw("invalid-state-removing-ports", log.Fields{"state": cloned.AdminState, "error": err})
121 return err
122 }
123 if len(cloned.Ports) == 0 {
124 logger.Debugw("no-ports-present", log.Fields{"deviceId": agent.deviceID})
125 return nil
126 }
127
128 cloned.Ports = []*voltha.Port{}
129 logger.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
130 // Store the device
131 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
132}
133
134func (agent *Agent) addPort(ctx context.Context, port *voltha.Port) error {
135 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
136 return err
137 }
138 defer agent.requestQueue.RequestComplete()
139 logger.Debugw("addPort", log.Fields{"deviceId": agent.deviceID})
140
141 cloned := agent.getDeviceWithoutLock()
142 updatePort := false
143 if cloned.Ports == nil {
144 // First port
145 logger.Debugw("addPort-first-port-to-add", log.Fields{"deviceId": agent.deviceID})
146 cloned.Ports = make([]*voltha.Port, 0)
147 } else {
148 for _, p := range cloned.Ports {
149 if p.Type == port.Type && p.PortNo == port.PortNo {
150 if p.Label == "" && p.Type == voltha.Port_PON_OLT {
151 //Creation of OLT PON port is being processed after a default PON port was created. Just update it.
152 logger.Infow("update-pon-port-created-by-default", log.Fields{"default-port": p, "port-to-add": port})
153 p.Label = port.Label
154 p.OperStatus = port.OperStatus
155 updatePort = true
156 break
157 }
158 logger.Debugw("port already exists", log.Fields{"port": port})
159 return nil
160 }
161 }
162 }
163 if !updatePort {
164 cp := proto.Clone(port).(*voltha.Port)
165 // Set the admin state of the port to ENABLE
166 cp.AdminState = voltha.AdminState_ENABLED
167 cloned.Ports = append(cloned.Ports, cp)
168 }
169 // Store the device
170 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
171}
172
173func (agent *Agent) addPeerPort(ctx context.Context, peerPort *voltha.Port_PeerPort) error {
174 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
175 return err
176 }
177 defer agent.requestQueue.RequestComplete()
178 logger.Debugw("adding-peer-peerPort", log.Fields{"device-id": agent.deviceID, "peer-peerPort": peerPort})
179
180 cloned := agent.getDeviceWithoutLock()
181
182 // Get the peer port on the device based on the peerPort no
183 found := false
184 for _, port := range cloned.Ports {
185 if port.PortNo == peerPort.PortNo { // found peerPort
186 cp := proto.Clone(peerPort).(*voltha.Port_PeerPort)
187 port.Peers = append(port.Peers, cp)
188 logger.Debugw("found-peer", log.Fields{"device-id": agent.deviceID, "portNo": peerPort.PortNo, "deviceId": agent.deviceID})
189 found = true
190 break
191 }
192 }
193 if !found && agent.isRootdevice {
194 // An ONU PON port has been created before the corresponding creation of the OLT PON port. Create the OLT PON port
195 // with default values which will be updated once the OLT PON port creation is processed.
196 ponPort := &voltha.Port{
197 PortNo: peerPort.PortNo,
198 Type: voltha.Port_PON_OLT,
199 AdminState: voltha.AdminState_ENABLED,
200 DeviceId: agent.deviceID,
201 Peers: []*voltha.Port_PeerPort{proto.Clone(peerPort).(*voltha.Port_PeerPort)},
202 }
203 cloned.Ports = append(cloned.Ports, ponPort)
204 logger.Infow("adding-default-pon-port", log.Fields{"device-id": agent.deviceID, "peer": peerPort, "pon-port": ponPort})
205 }
206
207 // Store the device
208 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
209}
210
211func (agent *Agent) disablePort(ctx context.Context, Port *voltha.Port) error {
212 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
213 return err
214 }
215 defer agent.requestQueue.RequestComplete()
216 logger.Debugw("disablePort", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo})
217 var cp *voltha.Port
218 // Get the most up to date the device info
219 device := agent.getDeviceWithoutLock()
220 for _, port := range device.Ports {
221 if port.PortNo == Port.PortNo {
222 port.AdminState = voltha.AdminState_DISABLED
223 cp = proto.Clone(port).(*voltha.Port)
224 break
225
226 }
227 }
228 if cp == nil {
229 return status.Errorf(codes.InvalidArgument, "%v", Port.PortNo)
230 }
231
232 if cp.Type != voltha.Port_PON_OLT {
233 return status.Errorf(codes.InvalidArgument, "Disabling of Port Type %v unimplemented", cp.Type)
234 }
235 // Store the device
236 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
237 logger.Debugw("updateDeviceInStoreWithoutLock error ", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo, "error": err})
238 return err
239 }
240
241 //send request to adapter
242 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
243 ch, err := agent.adapterProxy.DisablePort(ctx, device, cp)
244 if err != nil {
245 cancel()
246 return err
247 }
248 go agent.waitForAdapterResponse(subCtx, cancel, "disablePort", ch, agent.onSuccess, agent.onFailure)
249 return nil
250}
251
252func (agent *Agent) enablePort(ctx context.Context, Port *voltha.Port) error {
253 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
254 return err
255 }
256 defer agent.requestQueue.RequestComplete()
257 logger.Debugw("enablePort", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo})
258
259 var cp *voltha.Port
260 // Get the most up to date the device info
261 device := agent.getDeviceWithoutLock()
262 for _, port := range device.Ports {
263 if port.PortNo == Port.PortNo {
264 port.AdminState = voltha.AdminState_ENABLED
265 cp = proto.Clone(port).(*voltha.Port)
266 break
267 }
268 }
269
270 if cp == nil {
271 return status.Errorf(codes.InvalidArgument, "%v", Port.PortNo)
272 }
273
274 if cp.Type != voltha.Port_PON_OLT {
275 return status.Errorf(codes.InvalidArgument, "Enabling of Port Type %v unimplemented", cp.Type)
276 }
277 // Store the device
278 if err := agent.updateDeviceInStoreWithoutLock(ctx, device, false, ""); err != nil {
279 logger.Debugw("updateDeviceInStoreWithoutLock error ", log.Fields{"device-id": agent.deviceID, "port-no": Port.PortNo, "error": err})
280 return err
281 }
282 //send request to adapter
283 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
284 ch, err := agent.adapterProxy.EnablePort(ctx, device, cp)
285 if err != nil {
286 cancel()
287 return err
288 }
289 go agent.waitForAdapterResponse(subCtx, cancel, "enablePort", ch, agent.onSuccess, agent.onFailure)
290 return nil
291}