SEBA-758 send periodic port stats to voltha
SEBA-790 get flow, gemport, and tcont information through API
fix lint errors

Change-Id: I10909e1992eba71d8e54c976ccbcea8778e35539
diff --git a/core/api_handler.go b/core/api_handler.go
index 8bc2c09..470f365 100644
--- a/core/api_handler.go
+++ b/core/api_handler.go
@@ -22,16 +22,26 @@
 	"strconv"
 	"time"
 
-	pb "github.com/opencord/voltha-bbsim/api"
+	api "github.com/opencord/voltha-bbsim/api"
 	"github.com/opencord/voltha-bbsim/common/logger"
 	"github.com/opencord/voltha-bbsim/device"
+	"github.com/opencord/voltha-bbsim/flow"
+	openolt "github.com/opencord/voltha-protos/go/openolt"
 	"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{}
+// Constants for reboot delays
+const (
+	OltRebootDelay     = 40
+	OnuSoftRebootDelay = 10
+	OnuHardRebootDelay = 30
+)
+
+// handleONUStatusRequest process ONU status request
+func (s *Server) handleONUStatusRequest(in *api.ONUInfo) (*api.ONUs, error) {
+	logger.Trace("handleONUStatusRequest() invoked")
+	onuInfo := &api.ONUs{}
 	if in.OnuSerial != "" { // Get status of single ONU by SerialNumber
 		// Get OpenOlt serial number from string
 		sn, err := getOpenoltSerialNumber(in.OnuSerial)
@@ -73,14 +83,14 @@
 }
 
 // handleONUActivate method handles ONU activate requests from user.
-func (s *Server) handleONUActivate(in []*pb.ONUInfo) (*pb.BBSimResponse, error) {
-	logger.Info("handleONUActivate request received")
+func (s *Server) handleONUActivate(in []*api.ONUInfo) (*api.BBSimResponse, error) {
+	logger.Trace("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)
+		return &api.BBSimResponse{}, status.Errorf(codes.FailedPrecondition, OLTNotEnabled)
 	}
 
 	onuaddmap := make(map[uint32][]*device.Onu)
@@ -90,12 +100,21 @@
 	for _, onu := range in {
 		intfid := onu.PonPortId
 
+		if !s.isPonIntfPresentInOlt(intfid) {
+			return &api.BBSimResponse{}, status.Errorf(codes.OutOfRange, "PON-"+strconv.Itoa(int(intfid))+
+				" not present in OLT-"+strconv.Itoa(int(s.Olt.ID)))
+		}
+
+		if s.Olt.PonIntfs[intfid].AlarmState == device.PonLosRaised {
+			return &api.BBSimResponse{}, status.Errorf(codes.FailedPrecondition, "pon-"+strconv.Itoa(int(intfid))+" is not active")
+		}
+
 		// 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())
+			return &api.BBSimResponse{}, status.Errorf(codes.ResourceExhausted, err.Error())
 		}
 
 		// Check if Serial number is provided by user
@@ -104,9 +123,9 @@
 			sn, err := getOpenoltSerialNumber(onu.OnuSerial)
 			if err != nil {
 				logger.Error("Failed to get OpenOlt serial number %v", err)
-				Onu.InternalState = device.ONU_FREE
+				Onu.InternalState = device.OnuFree
 				markONUsFree(onuaddmap)
-				return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "serial number: "+onu.OnuSerial+" is invalid")
+				return &api.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "serial number: "+onu.OnuSerial+" is invalid")
 			}
 
 			// Check if serial number is not duplicate in requested ONUs
@@ -115,8 +134,8 @@
 					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")
+					Onu.InternalState = device.OnuFree
+					return &api.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "duplicate serial number: "+onu.OnuSerial+" provided")
 				}
 			}
 			newSerialNums = append(newSerialNums, onu.OnuSerial)
@@ -127,8 +146,8 @@
 				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")
+				Onu.InternalState = device.OnuFree
+				return &api.BBSimResponse{}, status.Errorf(codes.AlreadyExists, "serial number: "+onu.OnuSerial+" already exist")
 			}
 
 			// Store user provided serial number in ONU object
@@ -143,11 +162,12 @@
 		s.activateONUs(*s.EnableServer, onuaddmap)
 	}
 
-	return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+	return &api.BBSimResponse{StatusMsg: RequestAccepted}, nil
 }
 
 // handleONUDeactivate deactivates ONU described by a single ONUInfo object
-func (s *Server) handleONUDeactivate(in *pb.ONUInfo) error {
+func (s *Server) handleONUDeactivate(in *api.ONUInfo) error {
+	logger.Trace("handleONUDeactivate() invoked")
 
 	if s.EnableServer == nil {
 		logger.Error(OLTNotEnabled)
@@ -191,15 +211,32 @@
 }
 
 func (s *Server) handleOLTReboot() {
-	logger.Debug("HandleOLTReboot() invoked")
+	logger.Trace("HandleOLTReboot() invoked")
 	logger.Debug("Sending stop to serverActionCh")
 	s.serverActionCh <- OpenOltStop
-	time.Sleep(40 * time.Second)
+
+	// Delete all flows
+	err := flow.DeleteAllFlows()
+	if err != nil {
+		logger.Warn("%v", err)
+	}
+
+	// clear flowMap
+	s.FlowMap = make(map[device.FlowKey]*openolt.Flow)
+
+	// clear flow IDs from ONU objects
+	for intfID := range s.Onumap {
+		for _, onu := range s.Onumap[intfID] {
+			onu.Flows = nil
+		}
+	}
+
+	time.Sleep(OltRebootDelay * time.Second)
 
 	logger.Debug("Sending start to serverActionCh")
 	s.serverActionCh <- OpenOltStart
 	for {
-		if s.Olt.GetIntState() == device.OLT_ACTIVE {
+		if s.Olt.GetIntState() == device.OltActive {
 			logger.Info("Info: OLT reactivated")
 			break
 		}
@@ -209,23 +246,24 @@
 }
 
 func (s *Server) handleONUHardReboot(onu *device.Onu) {
-	logger.Debug("handleONUHardReboot() invoked")
+	logger.Trace("handleONUHardReboot() invoked")
 	_ = sendDyingGaspInd(*s.EnableServer, onu.IntfID, onu.OnuID)
 	device.UpdateOnusOpStatus(onu.IntfID, onu, "down")
 	// send operstat down to voltha
 	_ = sendOnuInd(*s.EnableServer, onu, "down", "up")
 	// Give OEH some time to perform cleanup
-	time.Sleep(30 * time.Second)
+	time.Sleep(OnuHardRebootDelay * time.Second)
 	s.activateOnu(onu)
 }
 
 func (s *Server) handleONUSoftReboot(IntfID uint32, OnuID uint32) {
-	logger.Debug("handleONUSoftReboot() invoked")
+	logger.Trace("handleONUSoftReboot() invoked")
 	onu, err := s.GetOnuByID(OnuID, IntfID)
 	if err != nil {
 		logger.Error("No onu found with given OnuID on interface %v", IntfID)
+		return
 	}
-	OnuAlarmRequest := &pb.ONUAlarmRequest{
+	OnuAlarmRequest := &api.ONUAlarmRequest{
 		OnuSerial: stringifySerialNumber(onu.SerialNumber),
 		AlarmType: OnuLossOfPloam,
 		Status:    "on",
@@ -236,7 +274,7 @@
 		logger.Error(err.Error())
 	}
 	// Clear alarm
-	time.Sleep(10 * time.Second)
+	time.Sleep(OnuSoftRebootDelay * time.Second)
 	OnuAlarmRequest.Status = "off"
 	_, err = s.handleOnuAlarm(OnuAlarmRequest)
 	if err != nil {
@@ -246,12 +284,13 @@
 
 // GetNextFreeOnu returns free onu object for specified interface ID
 func (s *Server) GetNextFreeOnu(intfid uint32) (*device.Onu, error) {
+	logger.Trace("GetNextFreeOnu() invoked")
 	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 onu.InternalState == device.OnuFree {
 			// If auto generated serial number is already used by some other ONU,
 			// continue to find for other free object
 			snkey := stringifySerialNumber(onu.SerialNumber)
@@ -259,7 +298,7 @@
 				continue
 			}
 			// Update Onu Internal State
-			onu.InternalState = device.ONU_INACTIVE
+			onu.InternalState = device.OnuInactive
 			return onu, nil
 		}
 	}
@@ -268,8 +307,9 @@
 
 // DeactivateAllOnuByIntfID deletes all ONUs for given PON port ID
 func (s *Server) DeactivateAllOnuByIntfID(intfid uint32) error {
+	logger.Trace("DeactivateAllOnuByIntfID() invoked")
 	for _, onu := range s.Onumap[intfid] {
-		if onu.InternalState == device.ONU_FREE || onu.InternalState == device.ONU_INACTIVE {
+		if onu.InternalState == device.OnuFree || onu.InternalState == device.OnuInactive {
 			continue
 		}
 		if err := s.HandleOnuDeactivate(onu); err != nil {
@@ -281,10 +321,11 @@
 
 // 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)
+	logger.Trace("HandleOnuDeactivate() invoked")
+	logger.Info("Deactivating ONU %d for Intf: %d", onu.OnuID, onu.IntfID)
 
 	// Update ONU internal state to ONU_INACTIVE
-	s.updateDevIntState(onu, device.ONU_INACTIVE)
+	s.updateDevIntState(onu, device.OnuInactive)
 
 	// Update ONU operstate to down
 	onu.OperState = "down"
@@ -296,80 +337,106 @@
 }
 
 func markONUsFree(onumap map[uint32][]*device.Onu) {
+	logger.Trace("markONUsFree() invoked")
 	for intfid := range onumap {
 		for _, onu := range onumap[intfid] {
-			onu.UpdateIntState(device.ONU_FREE)
+			onu.UpdateIntState(device.OnuFree)
 		}
 	}
 }
 
-func copyONUInfo(onu *device.Onu) *pb.ONUInfo {
-	onuData := &pb.ONUInfo{
+func copyONUInfo(onu *device.Onu) *api.ONUInfo {
+	onuData := &api.ONUInfo{
 		OnuId:     onu.OnuID,
 		PonPortId: onu.IntfID,
 		OnuSerial: stringifySerialNumber(onu.SerialNumber),
 		OnuState:  device.ONUState[onu.InternalState],
 		OperState: onu.OperState,
 	}
+
+	// update gemports
+	for _, gemPorts := range onu.GemPortMap {
+		onuData.Gemports = append(onuData.Gemports, gemPorts...)
+	}
+
+	// fill T-CONT data for ONU
+	if onu.Tconts != nil {
+		onuData.Tconts = &api.Tconts{
+			UniId:  onu.Tconts.UniId,
+			PortNo: onu.Tconts.PortNo,
+			Tconts: onu.Tconts.TrafficScheds,
+		}
+	}
+
 	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
+func (s *Server) fetchPortDetail(intfID uint32, portType string) (*api.PortInfo, error) {
+	logger.Trace("fetchPortDetail() invoked %s-%d", portType, intfID)
 
-	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")
+	portInfo := &api.PortInfo{}
+	var maxOnu, activeOnu uint32
+	var alarmState device.AlarmState
+	var state string
+
+	// Get info for specified port
+	if portType == device.IntfNni && s.isNniIntfPresentInOlt(intfID) {
+		state = s.Olt.NniIntfs[intfID].OperState
+		alarmState = s.Olt.NniIntfs[intfID].AlarmState
+
+	} else if portType == device.IntfPon && s.isPonIntfPresentInOlt(intfID) {
+		maxOnu = uint32(len(s.Onumap[intfID]))
+		activeOnu = s.getNoOfActiveOnuByPortID(intfID)
+		state = s.Olt.PonIntfs[intfID].OperState
+		alarmState = s.Olt.PonIntfs[intfID].AlarmState
+
+	} else {
+		return &api.PortInfo{}, errors.New(portType + "-" + strconv.Itoa(int(intfID)) + " not present in OLT-" +
+			strconv.Itoa(int(s.Olt.ID)))
 	}
+
+	// fill proto structure
+	portInfo = &api.PortInfo{
+		PortType:          portType,
+		PortId:            intfID,
+		PonPortMaxOnus:    maxOnu,
+		PonPortActiveOnus: activeOnu,
+		PortState:         state,
+	}
+
+	// update alarm state only when alarm is raised
+	if alarmState == device.NniLosRaised || alarmState == device.PonLosRaised {
+		portInfo.AlarmState = device.OLTAlarmStateToString[alarmState]
+	}
+
+	return portInfo, nil
 }
 
-func (s *Server) validateDeviceActionRequest(request *pb.DeviceAction) (*pb.DeviceAction, error) {
+func (s *Server) validateDeviceActionRequest(request *api.DeviceAction) (*api.DeviceAction, error) {
+	logger.Trace("validateDeviceActionRequest() invoked")
 	switch request.DeviceType {
 	case DeviceTypeOnu:
-		if request.DeviceSerialNumber == "" {
+		if request.SerialNumber == "" {
 			return request, errors.New("onu serial number can not be blank")
 		}
 
-		if len(request.DeviceSerialNumber) != SerialNumberLength {
+		if len(request.SerialNumber) != SerialNumberLength {
 			return request, errors.New("invalid serial number provided")
 		}
 
-		if request.DeviceAction != SoftReboot && request.DeviceAction != HardReboot {
+		_, exist := s.SNmap.Load(request.SerialNumber)
+		if !exist {
+			return &api.DeviceAction{}, errors.New(request.SerialNumber + " not present in OLT-" +
+				strconv.Itoa(int(s.Olt.ID)))
+		}
+
+		if request.Action != SoftReboot && request.Action != HardReboot {
 			return request, errors.New("invalid device action provided")
 		}
 		return request, nil
 	case DeviceTypeOlt:
 		request.DeviceType = DeviceTypeOlt
-		request.DeviceAction = HardReboot
+		request.Action = HardReboot
 		return request, nil
 	default:
 		return request, errors.New("invalid device type")
@@ -379,7 +446,7 @@
 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 {
+		if onu.InternalState >= device.OnuActive {
 			noOfActiveOnus++
 		}
 	}