SEBA-432
SEBA-565
SEBA-654 (alarms)
implemented
fix Jenkins make errors
fix merge conflicts
address review comments
Change-Id: Ia2e95afb33ce55054afa1fcbd9beb6ada62dd764
diff --git a/core/api_handler.go b/core/api_handler.go
new file mode 100644
index 0000000..eb52977
--- /dev/null
+++ b/core/api_handler.go
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package core
+
+import (
+ "errors"
+ "net"
+ "strconv"
+ "time"
+
+ pb "gerrit.opencord.org/voltha-bbsim/api"
+ "gerrit.opencord.org/voltha-bbsim/common/logger"
+ "gerrit.opencord.org/voltha-bbsim/device"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+// handleONUActivate process ONU status request
+func (s *Server) handleONUStatusRequest(in *pb.ONUInfo) (*pb.ONUs, error) {
+ onuInfo := &pb.ONUs{}
+ if in.OnuSerial != "" { // Get status of single ONU by SerialNumber
+ // Get OpenOlt serial number from string
+ sn, err := getOpenoltSerialNumber(in.OnuSerial)
+ if err != nil {
+ logger.Error("Invalid serial number %s", in.OnuSerial)
+ return onuInfo, status.Errorf(codes.InvalidArgument, "serial: "+in.OnuSerial+" is invalid")
+ }
+ // Get ONU by serial number
+ onu, err := getOnuBySN(s.Onumap, sn)
+ if err != nil {
+ logger.Error("ONU with serial number %v not found", sn)
+ return onuInfo, status.Errorf(codes.NotFound, "serial: "+in.OnuSerial+" not found")
+ }
+ onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
+ } else {
+ // Return error if specified PON port does not exist
+ if _, exist := s.Onumap[in.PonPortId]; !exist {
+ logger.Error("PON port %d not found", in.PonPortId)
+ return onuInfo, status.Errorf(codes.NotFound, "PON Port: "+strconv.Itoa(int(in.PonPortId))+" not found")
+ }
+
+ if in.OnuId != 0 { // Get status of single ONU by ONU-ID
+ for intfid := range s.Onumap {
+ for _, onu := range s.Onumap[intfid] {
+ if in.OnuId == onu.OnuID {
+ onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
+ }
+ }
+ }
+ } else {
+ // Append ONU data
+ for _, onu := range s.Onumap[in.PonPortId] {
+ onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
+ }
+ }
+ }
+
+ return onuInfo, nil
+}
+
+// handleONUActivate method handles ONU activate requests from user.
+func (s *Server) handleONUActivate(in []*pb.ONUInfo) (*pb.BBSimResponse, error) {
+ logger.Info("handleONUActivate request received")
+ logger.Debug("Received values: %+v\n", in)
+
+ // Check if indication is enabled
+ if s.EnableServer == nil {
+ logger.Error(OLTNotEnabled)
+ return &pb.BBSimResponse{}, status.Errorf(codes.FailedPrecondition, OLTNotEnabled)
+ }
+
+ onuaddmap := make(map[uint32][]*device.Onu)
+ var newSerialNums []string
+
+ //Iterate request for each PON port specified
+ for _, onu := range in {
+ intfid := onu.PonPortId
+
+ // Get the free ONU object for the intfid
+ Onu, err := s.GetNextFreeOnu(intfid)
+ if err != nil {
+ markONUsFree(onuaddmap)
+ logger.Error("Failed to get free ONU object for intfID %d :%v", intfid, err)
+ return &pb.BBSimResponse{}, status.Errorf(codes.ResourceExhausted, err.Error())
+ }
+
+ // Check if Serial number is provided by user
+ if onu.OnuSerial != "" {
+ // Get OpenOlt serial number from string
+ sn, err := getOpenoltSerialNumber(onu.OnuSerial)
+ if err != nil {
+ logger.Error("Failed to get OpenOlt serial number %v", err)
+ Onu.InternalState = device.ONU_FREE
+ markONUsFree(onuaddmap)
+ return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "serial number: "+onu.OnuSerial+" is invalid")
+ }
+
+ // Check if serial number is not duplicate in requested ONUs
+ for _, sn := range newSerialNums {
+ if onu.OnuSerial == sn {
+ logger.Error("Duplicate serial number found %s", sn)
+ // Mark ONUs free
+ markONUsFree(onuaddmap)
+ Onu.InternalState = device.ONU_FREE
+ return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "duplicate serial number: "+onu.OnuSerial+" provided")
+ }
+ }
+ newSerialNums = append(newSerialNums, onu.OnuSerial)
+
+ // Check if serial number already exist
+ _, exist := s.getOnuFromSNmap(sn)
+ if exist {
+ logger.Error("Provided serial number %v already exist", sn)
+ // Mark ONUs free
+ markONUsFree(onuaddmap)
+ Onu.InternalState = device.ONU_FREE
+ return &pb.BBSimResponse{}, status.Errorf(codes.AlreadyExists, "serial number: "+onu.OnuSerial+" already exist")
+ }
+
+ // Store user provided serial number in ONU object
+ Onu.SerialNumber = sn
+ }
+ // Store onu object in map for particular intfid
+ onuaddmap[intfid] = append(onuaddmap[intfid], Onu)
+ }
+
+ if len(onuaddmap) >= 1 {
+ //Pass onumap to activateONU to handle indication to VOLTHA
+ s.activateONUs(*s.EnableServer, onuaddmap)
+ }
+
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+}
+
+// handleONUDeactivate deactivates ONU described by a single ONUInfo object
+func (s *Server) handleONUDeactivate(in *pb.ONUInfo) error {
+
+ if s.EnableServer == nil {
+ logger.Error(OLTNotEnabled)
+ return status.Errorf(codes.FailedPrecondition, OLTNotEnabled)
+ }
+
+ if in.OnuSerial != "" {
+ // Get OpenOlt serial number from string
+ serialNumber, err := getOpenoltSerialNumber(in.OnuSerial)
+ if err != nil {
+ logger.Error("Invalid serial number %s", in.OnuSerial)
+ return status.Errorf(codes.InvalidArgument, "serial: "+in.OnuSerial+" is invalid")
+ }
+ // Get ONU by serial number
+ onu, exist := s.getOnuFromSNmap(serialNumber)
+ if !exist {
+ logger.Error("ONU with serial number %s not found", in.OnuSerial)
+ return status.Errorf(codes.NotFound, "serial: "+in.OnuSerial+" not found")
+ }
+
+ if err := s.HandleOnuDeactivate(onu); err != nil {
+ return err
+ }
+ } else {
+ if in.OnuId != 0 { // if provided, delete ONU by ONU ID
+ onu, err := getOnuByID(s.Onumap, in.OnuId, in.PonPortId)
+ if err != nil {
+ return err
+ }
+ if err := s.HandleOnuDeactivate(onu); err != nil {
+ return err
+ }
+ } else { // delete all ONUs on provided port
+ if err := s.DeactivateAllOnuByIntfID(in.PonPortId); err != nil {
+ logger.Error("Failed in handleONUDeactivate: %v", err)
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (s *Server) handleOLTReboot() {
+ logger.Debug("HandleOLTReboot() invoked")
+ logger.Debug("Sending stop to serverActionCh")
+ s.serverActionCh <- OpenOltStop
+ time.Sleep(40 * time.Second)
+
+ logger.Debug("Sending start to serverActionCh")
+ s.serverActionCh <- OpenOltStart
+ for {
+ if s.Olt.GetIntState() == device.OLT_ACTIVE {
+ logger.Info("Info: OLT reactivated")
+ break
+ }
+ time.Sleep(2 * time.Second)
+ }
+ s.sendOnuIndicationsOnOltReboot()
+}
+
+func (s *Server) handleONUHardReboot(onu *device.Onu) {
+ logger.Debug("handleONUHardReboot() invoked")
+ _ = sendDyingGaspInd(*s.EnableServer, onu.IntfID, onu.OnuID)
+ device.UpdateOnusOpStatus(onu.IntfID, onu, "down")
+ // send operstat down to voltha
+ _ = sendOnuInd(*s.EnableServer, onu, s.IndInterval, "down", "up")
+ // Give OEH some time to perform cleanup
+ time.Sleep(30 * time.Second)
+ s.activateOnu(onu)
+}
+
+func (s *Server) handleONUSoftReboot(IntfID uint32, OnuID uint32) {
+ logger.Debug("handleONUSoftReboot() invoked")
+ onu, err := s.GetOnuByID(OnuID, IntfID)
+ if err != nil {
+ logger.Error("No onu found with given OnuID on interface %v", IntfID)
+ }
+ OnuAlarmRequest := &pb.ONUAlarmRequest{
+ OnuSerial: stringifySerialNumber(onu.SerialNumber),
+ AlarmType: OnuLossOfPloam,
+ Status: "on",
+ }
+ // Raise alarm
+ _, err = s.handleOnuAlarm(OnuAlarmRequest)
+ if err != nil {
+ logger.Error(err.Error())
+ }
+ // Clear alarm
+ time.Sleep(10 * time.Second)
+ OnuAlarmRequest.Status = "off"
+ _, err = s.handleOnuAlarm(OnuAlarmRequest)
+ if err != nil {
+ logger.Error(err.Error())
+ }
+}
+
+// GetNextFreeOnu returns free onu object for specified interface ID
+func (s *Server) GetNextFreeOnu(intfid uint32) (*device.Onu, error) {
+ onus, ok := s.Onumap[intfid]
+ if !ok {
+ return nil, errors.New("interface " + strconv.Itoa(int(intfid)) + " not present in ONU map")
+ }
+ for _, onu := range onus {
+ if onu.InternalState == device.ONU_FREE {
+ // If auto generated serial number is already used by some other ONU,
+ // continue to find for other free object
+ snkey := stringifySerialNumber(onu.SerialNumber)
+ if _, exist := s.SNmap.Load(snkey); exist {
+ continue
+ }
+ // Update Onu Internal State
+ onu.InternalState = device.ONU_INACTIVE
+ return onu, nil
+ }
+ }
+ return nil, errors.New("no free ONU found for pon port: " + strconv.Itoa(int(intfid)))
+}
+
+// DeactivateAllOnuByIntfID deletes all ONUs for given PON port ID
+func (s *Server) DeactivateAllOnuByIntfID(intfid uint32) error {
+ for _, onu := range s.Onumap[intfid] {
+ if onu.InternalState == device.ONU_FREE || onu.InternalState == device.ONU_INACTIVE {
+ continue
+ }
+ if err := s.HandleOnuDeactivate(onu); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// HandleOnuDeactivate method handles ONU state changes and sending Indication to voltha
+func (s *Server) HandleOnuDeactivate(onu *device.Onu) error {
+ logger.Debug("Deactivating ONU %d for Intf: %d", onu.OnuID, onu.IntfID)
+
+ // Update ONU internal state to ONU_INACTIVE
+ s.updateDevIntState(onu, device.ONU_INACTIVE)
+
+ // Update ONU operstate to down
+ onu.OperState = "down"
+
+ // Send DyingGasp Alarm to VOLTHA
+ _ = sendDyingGaspInd(*s.EnableServer, onu.IntfID, onu.OnuID)
+ _ = sendOnuInd(*s.EnableServer, onu, s.IndInterval, onu.OperState, "down")
+ return nil
+}
+
+func markONUsFree(onumap map[uint32][]*device.Onu) {
+ for intfid := range onumap {
+ for _, onu := range onumap[intfid] {
+ onu.UpdateIntState(device.ONU_FREE)
+ }
+ }
+}
+
+func copyONUInfo(onu *device.Onu) *pb.ONUInfo {
+ onuData := &pb.ONUInfo{
+ OnuId: onu.OnuID,
+ PonPortId: onu.IntfID,
+ OnuSerial: stringifySerialNumber(onu.SerialNumber),
+ OnuState: device.ONUState[onu.InternalState],
+ OperState: onu.OperState,
+ }
+ return onuData
+}
+
+func (s *Server) fetchPortDetail(intfID uint32, portType string) (*pb.PortInfo, error) {
+ logger.Debug("fetchPortDetail() invoked")
+ portInfo := &pb.PortInfo{}
+ switch portType {
+ case device.IntfNni:
+ if !s.isNniIntfPresentInOlt(intfID) {
+ return &pb.PortInfo{}, errors.New("NNI " + strconv.Itoa(int(intfID)) + " not present in " +
+ strconv.Itoa(int(s.Olt.ID)))
+ }
+ portInfo = &pb.PortInfo{
+ PortType: portType,
+ PortId: intfID,
+ PonPortMaxOnus: 0,
+ PonPortActiveOnus: 0,
+ PortState: s.Olt.NniIntfs[intfID].OperState,
+ AlarmState: device.OLTAlarmStateToString[s.Olt.NniIntfs[intfID].AlarmState],
+ }
+ return portInfo, nil
+
+ case device.IntfPon:
+ if !s.isPonIntfPresentInOlt(intfID) {
+ return &pb.PortInfo{}, errors.New("PON " + strconv.Itoa(int(intfID)) + " not present in OLT-" +
+ strconv.Itoa(int(s.Olt.ID)))
+ }
+ portInfo = &pb.PortInfo{
+ PortType: portType,
+ PortId: intfID,
+ PonPortMaxOnus: int32(len(s.Onumap[uint32(intfID)])),
+ PonPortActiveOnus: s.getNoOfActiveOnuByPortID(intfID),
+ PortState: s.Olt.PonIntfs[intfID].OperState,
+ AlarmState: device.OLTAlarmStateToString[s.Olt.PonIntfs[intfID].AlarmState],
+ }
+ return portInfo, nil
+ default:
+ return &pb.PortInfo{}, errors.New(portType + " is not a valid port type")
+ }
+}
+
+func (s *Server) validateDeviceActionRequest(request *pb.DeviceAction) (*pb.DeviceAction, error) {
+ switch request.DeviceType {
+ case DeviceTypeOnu:
+ if request.DeviceSerialNumber == "" {
+ return request, errors.New("onu serial number can not be blank")
+ }
+
+ if len(request.DeviceSerialNumber) != SerialNumberLength {
+ return request, errors.New("invalid serial number provided")
+ }
+
+ if request.DeviceAction != SoftReboot && request.DeviceAction != HardReboot {
+ return request, errors.New("invalid device action provided")
+ }
+ return request, nil
+ case DeviceTypeOlt:
+ request.DeviceType = DeviceTypeOlt
+ request.DeviceAction = HardReboot
+ return request, nil
+ default:
+ return request, errors.New("invalid device type")
+ }
+}
+
+func (s *Server) getNoOfActiveOnuByPortID(portID uint32) uint32 {
+ var noOfActiveOnus uint32
+ for _, onu := range s.Onumap[portID] {
+ if onu.InternalState == device.ONU_ACTIVE || onu.InternalState == device.ONU_OMCIACTIVE {
+ noOfActiveOnus++
+ }
+ }
+ return noOfActiveOnus
+}
+
+func (s *Server) isPonIntfPresentInOlt(intfID uint32) bool {
+ for _, intf := range s.Olt.PonIntfs {
+ if intf.IntfID == intfID {
+ return true
+ }
+ }
+ return false
+}
+
+func (s *Server) isNniIntfPresentInOlt(intfID uint32) bool {
+ for _, intf := range s.Olt.NniIntfs {
+ if intf.IntfID == intfID {
+ return true
+ }
+ }
+ return false
+}
+
+func getOltIP() net.IP {
+ // TODO make this better
+ conn, err := net.Dial("udp", "8.8.8.8:80")
+ if err != nil {
+ logger.Error(err.Error())
+ return net.IP{}
+ }
+ defer func() {
+ err := conn.Close()
+ if err != nil {
+ logger.Error(err.Error())
+ }
+ }()
+
+ localAddr := conn.LocalAddr().(*net.UDPAddr)
+
+ return localAddr.IP
+}