blob: 8bc2c09a6531de507582ee57e9c645dfc42aa6eb [file] [log] [blame]
Zdravko Bozakov7401ff22019-05-28 22:45:12 +02001/*
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 core
18
19import (
20 "errors"
21 "net"
22 "strconv"
23 "time"
24
Zack Williams2abf3932019-08-05 14:07:05 -070025 pb "github.com/opencord/voltha-bbsim/api"
26 "github.com/opencord/voltha-bbsim/common/logger"
27 "github.com/opencord/voltha-bbsim/device"
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
30)
31
32// handleONUActivate process ONU status request
33func (s *Server) handleONUStatusRequest(in *pb.ONUInfo) (*pb.ONUs, error) {
34 onuInfo := &pb.ONUs{}
35 if in.OnuSerial != "" { // Get status of single ONU by SerialNumber
36 // Get OpenOlt serial number from string
37 sn, err := getOpenoltSerialNumber(in.OnuSerial)
38 if err != nil {
39 logger.Error("Invalid serial number %s", in.OnuSerial)
40 return onuInfo, status.Errorf(codes.InvalidArgument, "serial: "+in.OnuSerial+" is invalid")
41 }
42 // Get ONU by serial number
43 onu, err := getOnuBySN(s.Onumap, sn)
44 if err != nil {
45 logger.Error("ONU with serial number %v not found", sn)
46 return onuInfo, status.Errorf(codes.NotFound, "serial: "+in.OnuSerial+" not found")
47 }
48 onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
49 } else {
50 // Return error if specified PON port does not exist
51 if _, exist := s.Onumap[in.PonPortId]; !exist {
52 logger.Error("PON port %d not found", in.PonPortId)
53 return onuInfo, status.Errorf(codes.NotFound, "PON Port: "+strconv.Itoa(int(in.PonPortId))+" not found")
54 }
55
56 if in.OnuId != 0 { // Get status of single ONU by ONU-ID
57 for intfid := range s.Onumap {
58 for _, onu := range s.Onumap[intfid] {
59 if in.OnuId == onu.OnuID {
60 onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
61 }
62 }
63 }
64 } else {
65 // Append ONU data
66 for _, onu := range s.Onumap[in.PonPortId] {
67 onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
68 }
69 }
70 }
71
72 return onuInfo, nil
73}
74
75// handleONUActivate method handles ONU activate requests from user.
76func (s *Server) handleONUActivate(in []*pb.ONUInfo) (*pb.BBSimResponse, error) {
77 logger.Info("handleONUActivate request received")
78 logger.Debug("Received values: %+v\n", in)
79
80 // Check if indication is enabled
81 if s.EnableServer == nil {
82 logger.Error(OLTNotEnabled)
83 return &pb.BBSimResponse{}, status.Errorf(codes.FailedPrecondition, OLTNotEnabled)
84 }
85
86 onuaddmap := make(map[uint32][]*device.Onu)
87 var newSerialNums []string
88
89 //Iterate request for each PON port specified
90 for _, onu := range in {
91 intfid := onu.PonPortId
92
93 // Get the free ONU object for the intfid
94 Onu, err := s.GetNextFreeOnu(intfid)
95 if err != nil {
96 markONUsFree(onuaddmap)
97 logger.Error("Failed to get free ONU object for intfID %d :%v", intfid, err)
98 return &pb.BBSimResponse{}, status.Errorf(codes.ResourceExhausted, err.Error())
99 }
100
101 // Check if Serial number is provided by user
102 if onu.OnuSerial != "" {
103 // Get OpenOlt serial number from string
104 sn, err := getOpenoltSerialNumber(onu.OnuSerial)
105 if err != nil {
106 logger.Error("Failed to get OpenOlt serial number %v", err)
107 Onu.InternalState = device.ONU_FREE
108 markONUsFree(onuaddmap)
109 return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "serial number: "+onu.OnuSerial+" is invalid")
110 }
111
112 // Check if serial number is not duplicate in requested ONUs
113 for _, sn := range newSerialNums {
114 if onu.OnuSerial == sn {
115 logger.Error("Duplicate serial number found %s", sn)
116 // Mark ONUs free
117 markONUsFree(onuaddmap)
118 Onu.InternalState = device.ONU_FREE
119 return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "duplicate serial number: "+onu.OnuSerial+" provided")
120 }
121 }
122 newSerialNums = append(newSerialNums, onu.OnuSerial)
123
124 // Check if serial number already exist
125 _, exist := s.getOnuFromSNmap(sn)
126 if exist {
127 logger.Error("Provided serial number %v already exist", sn)
128 // Mark ONUs free
129 markONUsFree(onuaddmap)
130 Onu.InternalState = device.ONU_FREE
131 return &pb.BBSimResponse{}, status.Errorf(codes.AlreadyExists, "serial number: "+onu.OnuSerial+" already exist")
132 }
133
134 // Store user provided serial number in ONU object
135 Onu.SerialNumber = sn
136 }
137 // Store onu object in map for particular intfid
138 onuaddmap[intfid] = append(onuaddmap[intfid], Onu)
139 }
140
141 if len(onuaddmap) >= 1 {
142 //Pass onumap to activateONU to handle indication to VOLTHA
143 s.activateONUs(*s.EnableServer, onuaddmap)
144 }
145
146 return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
147}
148
149// handleONUDeactivate deactivates ONU described by a single ONUInfo object
150func (s *Server) handleONUDeactivate(in *pb.ONUInfo) error {
151
152 if s.EnableServer == nil {
153 logger.Error(OLTNotEnabled)
154 return status.Errorf(codes.FailedPrecondition, OLTNotEnabled)
155 }
156
157 if in.OnuSerial != "" {
158 // Get OpenOlt serial number from string
159 serialNumber, err := getOpenoltSerialNumber(in.OnuSerial)
160 if err != nil {
161 logger.Error("Invalid serial number %s", in.OnuSerial)
162 return status.Errorf(codes.InvalidArgument, "serial: "+in.OnuSerial+" is invalid")
163 }
164 // Get ONU by serial number
165 onu, exist := s.getOnuFromSNmap(serialNumber)
166 if !exist {
167 logger.Error("ONU with serial number %s not found", in.OnuSerial)
168 return status.Errorf(codes.NotFound, "serial: "+in.OnuSerial+" not found")
169 }
170
171 if err := s.HandleOnuDeactivate(onu); err != nil {
172 return err
173 }
174 } else {
175 if in.OnuId != 0 { // if provided, delete ONU by ONU ID
176 onu, err := getOnuByID(s.Onumap, in.OnuId, in.PonPortId)
177 if err != nil {
178 return err
179 }
180 if err := s.HandleOnuDeactivate(onu); err != nil {
181 return err
182 }
183 } else { // delete all ONUs on provided port
184 if err := s.DeactivateAllOnuByIntfID(in.PonPortId); err != nil {
185 logger.Error("Failed in handleONUDeactivate: %v", err)
186 return err
187 }
188 }
189 }
190 return nil
191}
192
193func (s *Server) handleOLTReboot() {
194 logger.Debug("HandleOLTReboot() invoked")
195 logger.Debug("Sending stop to serverActionCh")
196 s.serverActionCh <- OpenOltStop
197 time.Sleep(40 * time.Second)
198
199 logger.Debug("Sending start to serverActionCh")
200 s.serverActionCh <- OpenOltStart
201 for {
202 if s.Olt.GetIntState() == device.OLT_ACTIVE {
203 logger.Info("Info: OLT reactivated")
204 break
205 }
206 time.Sleep(2 * time.Second)
207 }
208 s.sendOnuIndicationsOnOltReboot()
209}
210
211func (s *Server) handleONUHardReboot(onu *device.Onu) {
212 logger.Debug("handleONUHardReboot() invoked")
213 _ = sendDyingGaspInd(*s.EnableServer, onu.IntfID, onu.OnuID)
214 device.UpdateOnusOpStatus(onu.IntfID, onu, "down")
215 // send operstat down to voltha
Mahir Gunyel32dfd722019-08-05 16:18:06 +0300216 _ = sendOnuInd(*s.EnableServer, onu, "down", "up")
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200217 // Give OEH some time to perform cleanup
218 time.Sleep(30 * time.Second)
219 s.activateOnu(onu)
220}
221
222func (s *Server) handleONUSoftReboot(IntfID uint32, OnuID uint32) {
223 logger.Debug("handleONUSoftReboot() invoked")
224 onu, err := s.GetOnuByID(OnuID, IntfID)
225 if err != nil {
226 logger.Error("No onu found with given OnuID on interface %v", IntfID)
227 }
228 OnuAlarmRequest := &pb.ONUAlarmRequest{
229 OnuSerial: stringifySerialNumber(onu.SerialNumber),
230 AlarmType: OnuLossOfPloam,
231 Status: "on",
232 }
233 // Raise alarm
234 _, err = s.handleOnuAlarm(OnuAlarmRequest)
235 if err != nil {
236 logger.Error(err.Error())
237 }
238 // Clear alarm
239 time.Sleep(10 * time.Second)
240 OnuAlarmRequest.Status = "off"
241 _, err = s.handleOnuAlarm(OnuAlarmRequest)
242 if err != nil {
243 logger.Error(err.Error())
244 }
245}
246
247// GetNextFreeOnu returns free onu object for specified interface ID
248func (s *Server) GetNextFreeOnu(intfid uint32) (*device.Onu, error) {
249 onus, ok := s.Onumap[intfid]
250 if !ok {
251 return nil, errors.New("interface " + strconv.Itoa(int(intfid)) + " not present in ONU map")
252 }
253 for _, onu := range onus {
254 if onu.InternalState == device.ONU_FREE {
255 // If auto generated serial number is already used by some other ONU,
256 // continue to find for other free object
257 snkey := stringifySerialNumber(onu.SerialNumber)
258 if _, exist := s.SNmap.Load(snkey); exist {
259 continue
260 }
261 // Update Onu Internal State
262 onu.InternalState = device.ONU_INACTIVE
263 return onu, nil
264 }
265 }
266 return nil, errors.New("no free ONU found for pon port: " + strconv.Itoa(int(intfid)))
267}
268
269// DeactivateAllOnuByIntfID deletes all ONUs for given PON port ID
270func (s *Server) DeactivateAllOnuByIntfID(intfid uint32) error {
271 for _, onu := range s.Onumap[intfid] {
272 if onu.InternalState == device.ONU_FREE || onu.InternalState == device.ONU_INACTIVE {
273 continue
274 }
275 if err := s.HandleOnuDeactivate(onu); err != nil {
276 return err
277 }
278 }
279 return nil
280}
281
282// HandleOnuDeactivate method handles ONU state changes and sending Indication to voltha
283func (s *Server) HandleOnuDeactivate(onu *device.Onu) error {
284 logger.Debug("Deactivating ONU %d for Intf: %d", onu.OnuID, onu.IntfID)
285
286 // Update ONU internal state to ONU_INACTIVE
287 s.updateDevIntState(onu, device.ONU_INACTIVE)
288
289 // Update ONU operstate to down
290 onu.OperState = "down"
291
292 // Send DyingGasp Alarm to VOLTHA
293 _ = sendDyingGaspInd(*s.EnableServer, onu.IntfID, onu.OnuID)
Mahir Gunyel32dfd722019-08-05 16:18:06 +0300294 _ = sendOnuInd(*s.EnableServer, onu, onu.OperState, "down")
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200295 return nil
296}
297
298func markONUsFree(onumap map[uint32][]*device.Onu) {
299 for intfid := range onumap {
300 for _, onu := range onumap[intfid] {
301 onu.UpdateIntState(device.ONU_FREE)
302 }
303 }
304}
305
306func copyONUInfo(onu *device.Onu) *pb.ONUInfo {
307 onuData := &pb.ONUInfo{
308 OnuId: onu.OnuID,
309 PonPortId: onu.IntfID,
310 OnuSerial: stringifySerialNumber(onu.SerialNumber),
311 OnuState: device.ONUState[onu.InternalState],
312 OperState: onu.OperState,
313 }
314 return onuData
315}
316
317func (s *Server) fetchPortDetail(intfID uint32, portType string) (*pb.PortInfo, error) {
318 logger.Debug("fetchPortDetail() invoked")
319 portInfo := &pb.PortInfo{}
320 switch portType {
321 case device.IntfNni:
322 if !s.isNniIntfPresentInOlt(intfID) {
323 return &pb.PortInfo{}, errors.New("NNI " + strconv.Itoa(int(intfID)) + " not present in " +
324 strconv.Itoa(int(s.Olt.ID)))
325 }
326 portInfo = &pb.PortInfo{
327 PortType: portType,
328 PortId: intfID,
329 PonPortMaxOnus: 0,
330 PonPortActiveOnus: 0,
331 PortState: s.Olt.NniIntfs[intfID].OperState,
332 AlarmState: device.OLTAlarmStateToString[s.Olt.NniIntfs[intfID].AlarmState],
333 }
334 return portInfo, nil
335
336 case device.IntfPon:
337 if !s.isPonIntfPresentInOlt(intfID) {
338 return &pb.PortInfo{}, errors.New("PON " + strconv.Itoa(int(intfID)) + " not present in OLT-" +
339 strconv.Itoa(int(s.Olt.ID)))
340 }
341 portInfo = &pb.PortInfo{
342 PortType: portType,
343 PortId: intfID,
344 PonPortMaxOnus: int32(len(s.Onumap[uint32(intfID)])),
345 PonPortActiveOnus: s.getNoOfActiveOnuByPortID(intfID),
346 PortState: s.Olt.PonIntfs[intfID].OperState,
347 AlarmState: device.OLTAlarmStateToString[s.Olt.PonIntfs[intfID].AlarmState],
348 }
349 return portInfo, nil
350 default:
351 return &pb.PortInfo{}, errors.New(portType + " is not a valid port type")
352 }
353}
354
355func (s *Server) validateDeviceActionRequest(request *pb.DeviceAction) (*pb.DeviceAction, error) {
356 switch request.DeviceType {
357 case DeviceTypeOnu:
358 if request.DeviceSerialNumber == "" {
359 return request, errors.New("onu serial number can not be blank")
360 }
361
362 if len(request.DeviceSerialNumber) != SerialNumberLength {
363 return request, errors.New("invalid serial number provided")
364 }
365
366 if request.DeviceAction != SoftReboot && request.DeviceAction != HardReboot {
367 return request, errors.New("invalid device action provided")
368 }
369 return request, nil
370 case DeviceTypeOlt:
371 request.DeviceType = DeviceTypeOlt
372 request.DeviceAction = HardReboot
373 return request, nil
374 default:
375 return request, errors.New("invalid device type")
376 }
377}
378
379func (s *Server) getNoOfActiveOnuByPortID(portID uint32) uint32 {
380 var noOfActiveOnus uint32
381 for _, onu := range s.Onumap[portID] {
382 if onu.InternalState == device.ONU_ACTIVE || onu.InternalState == device.ONU_OMCIACTIVE {
383 noOfActiveOnus++
384 }
385 }
386 return noOfActiveOnus
387}
388
389func (s *Server) isPonIntfPresentInOlt(intfID uint32) bool {
390 for _, intf := range s.Olt.PonIntfs {
391 if intf.IntfID == intfID {
392 return true
393 }
394 }
395 return false
396}
397
398func (s *Server) isNniIntfPresentInOlt(intfID uint32) bool {
399 for _, intf := range s.Olt.NniIntfs {
400 if intf.IntfID == intfID {
401 return true
402 }
403 }
404 return false
405}
406
407func getOltIP() net.IP {
408 // TODO make this better
409 conn, err := net.Dial("udp", "8.8.8.8:80")
410 if err != nil {
411 logger.Error(err.Error())
412 return net.IP{}
413 }
414 defer func() {
415 err := conn.Close()
416 if err != nil {
417 logger.Error(err.Error())
418 }
419 }()
420
421 localAddr := conn.LocalAddr().(*net.UDPAddr)
422
423 return localAddr.IP
424}