Add ONU Ind-related features

Change-Id: Ib6dd74efc0893b2d56275ecf5a1c56c5958fddbd
VOL-1118
diff --git a/bbsim.go b/bbsim.go
index 2466dbb..2c3a15d 100755
--- a/bbsim.go
+++ b/bbsim.go
@@ -1,3 +1,19 @@
+/*
+ * 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 main
 
 import (
@@ -5,11 +21,9 @@
 	"log"
 	"net"
 	"google.golang.org/grpc"
-	"golang.org/x/net/context"
 	"fmt"
 	"flag"
 	"reflect"
-	"time"
 	"strings"
 	"strconv"
 	"sync"
@@ -17,11 +31,12 @@
 
 type server struct{
 	olt olt
-	onus map[uint32][]onu
+	onus map[uint32]map[uint32]*onu
 }
 
 
 type oltState int
+type onuState int
 
 const(
 	PRE_ENABLE oltState = iota
@@ -30,8 +45,11 @@
 	ONU_DISCOVERED
 )
 
+const(
+	ONU_PRE_ACTIVATED onuState = iota
+	ONU_ACTIVATED
+)
 
-//a
 type olt struct {
 	ID			         uint32
 	NumPonIntf           uint32
@@ -53,6 +71,7 @@
 }
 
 type onu struct{
+	internalState       onuState
 	IntfID              uint32
 	OperState           string
 	SerialNumber        *openolt.SerialNumber
@@ -68,16 +87,16 @@
 	olt.OperState     = "up"
 	olt.Intfs = make([]intf, olt.NumPonIntf + olt.NumNniIntf)
 	olt.HeartbeatSignature = oltid
-	for i := uint32(0); i < olt.NumPonIntf; i ++ {
-		olt.Intfs[i].IntfID = i
-		olt.Intfs[i].OperState = "up"
-		olt.Intfs[i].Type      = "pon"
-	}
-	for i := uint32(olt.NumPonIntf); i <  olt.NumPonIntf + olt.NumNniIntf; i ++ {
+	for i := uint32(0); i < olt.NumNniIntf; i ++ {
 		olt.Intfs[i].IntfID = i
 		olt.Intfs[i].OperState = "up"
 		olt.Intfs[i].Type      = "nni"
 	}
+	for i := uint32(olt.NumNniIntf); i <  olt.NumPonIntf + olt.NumNniIntf; i ++ {
+		olt.Intfs[i].IntfID = i
+		olt.Intfs[i].OperState = "up"
+		olt.Intfs[i].Type      = "pon"
+	}
 	return olt
 }
 
@@ -86,19 +105,22 @@
 	return sn
 }
 
-func createOnus(oltid uint32, intfid uint32, nonus uint32) [] onu {
-	onus := make([]onu ,nonus)
-	for onuid := uint32(0); onuid < nonus; onuid ++ {
-		onus[onuid].IntfID       = intfid
-		onus[onuid].OperState    = "down"
-		onus[onuid].SerialNumber = new(openolt.SerialNumber)
-		onus[onuid].SerialNumber.VendorId = []byte("BRCM")
-		onus[onuid].SerialNumber.VendorSpecific = []byte(createSN(oltid, intfid, uint32(onuid))) //FIX
+func createOnus(oltid uint32, intfid uint32, nonus uint32, nnni uint32) map[uint32] *onu {
+	onus := make(map[uint32] *onu ,nonus)
+	for onuid := uint32(1 + (intfid - nnni) * nonus); onuid <= (intfid - nnni + 1) * nonus; onuid ++ {
+		onu := onu{}
+		onu.internalState = ONU_PRE_ACTIVATED
+		onu.IntfID        = intfid
+		onu.OperState     = "up"
+		onu.SerialNumber  = new(openolt.SerialNumber)
+		onu.SerialNumber.VendorId = []byte("BRCM")
+		onu.SerialNumber.VendorSpecific = []byte(createSN(oltid, intfid, uint32(onuid))) //FIX
+		onus[onuid] = &onu
 	}
 	return onus
 }
 
-func validateONU(targetonu openolt.Onu, regonus map[uint32][]onu) bool{
+func validateONU(targetonu openolt.Onu, regonus map[uint32]map[uint32] *onu) bool{
 	for _, onus := range regonus{
 		for _, onu := range onus{
 			if validateSN(*targetonu.SerialNumber, *onu.SerialNumber){
@@ -113,11 +135,21 @@
 	return reflect.DeepEqual(sn1.VendorId, sn2.VendorId) && reflect.DeepEqual(sn1.VendorSpecific, sn2.VendorSpecific)
 }
 
+func isAllONUActive(regonus map[uint32]map[uint32] *onu ) bool{
+	for _, onus := range regonus{
+		for _, onu := range onus{
+			if onu.internalState != ONU_ACTIVATED{
+				return false
+			}
+		}
+	}
+	return true
+}
 
-func updateOnusOpStatus(ponif uint32, onus [] onu, opstatus string){
+func updateOnusOpStatus(ponif uint32, onus map[uint32] *onu, opstatus string){
 	for i, onu := range onus{
 		onu.OperState = "up"
-		log.Printf("(PONIF:%d) ONU [%d] %v discovered.\n", ponif, i, onu.SerialNumber)
+		log.Printf("(PONIF:%d) ONU [%d] discovered.\n", ponif, i)
 	}
 }
 
@@ -148,15 +180,26 @@
 	log.Printf("OLT %s sent OperInd.\n", olt.Name)
 
 	// OLT sends ONU Discover Indication to Adapter after ONU discovery
-	for intfid := uint32(0); intfid < olt.NumPonIntf; intfid ++ {
+	for intfid := uint32(olt.NumNniIntf); intfid < olt.NumNniIntf + olt.NumPonIntf; intfid ++ {
 		updateOnusOpStatus(intfid, onus[intfid], "up")
 	}
 
-	for intfid := uint32(0); intfid < olt.NumPonIntf; intfid ++ {
+	for intfid := uint32(olt.NumNniIntf); intfid < olt.NumNniIntf + olt.NumPonIntf; intfid ++ {
 		sendOnuDiscInd(stream, onus[intfid])
 		log.Printf("OLT id:%d sent ONUDiscInd.\n", olt.ID)
 	}
-	olt.internalState = ONU_DISCOVERED
+
+	for{
+		//log.Printf("stop %v\n", s.onus)
+		if isAllONUActive(s.onus){
+			//log.Printf("break! %v\n", s.onus)
+			break
+		}
+	}
+	for intfid := uint32(olt.NumNniIntf); intfid < olt.NumNniIntf + olt.NumPonIntf; intfid ++ {
+		sendOnuInd(stream, onus[intfid])
+		log.Printf("OLT id:%d sent ONUInd.\n", olt.ID)
+	}
 	return nil
 }
 
@@ -177,6 +220,7 @@
 			log.Printf("Failed to send Intf [id: %d] indication : %v\n", i, err)
 			return err
 		}
+		log.Printf("SendIntfInd olt:%d intf:%d (%s)\n", olt.ID, intf.IntfID, intf.Type)
 	}
 	return nil
 }
@@ -189,11 +233,12 @@
 			log.Printf("Failed to send IntfOper [id: %d] indication : %v\n", i, err)
 			return err
 		}
+		log.Printf("SendOperInd olt:%d intf:%d (%s)\n", olt.ID, intf.IntfID, intf.Type)
 	}
 	return nil
 }
 
-func sendOnuDiscInd(stream openolt.Openolt_EnableIndicationServer, onus [] onu) error{
+func sendOnuDiscInd(stream openolt.Openolt_EnableIndicationServer, onus map[uint32] *onu) error{
 	for i, onu := range onus {
 		data := &openolt.Indication_OnuDiscInd{&openolt.OnuDiscIndication{IntfId: onu.IntfID, SerialNumber:onu.SerialNumber}}
 		log.Printf("sendONUDiscInd Onuid: %d\n", i)
@@ -205,15 +250,29 @@
 	return nil
 }
 
+func sendOnuInd(stream openolt.Openolt_EnableIndicationServer, onus map[uint32] *onu) error{
+	for i, onu := range onus {
+		data := &openolt.Indication_OnuInd{&openolt.OnuIndication{IntfId: onu.IntfID, OnuId: uint32(i), OperState: "up", AdminState: "up", SerialNumber:onu.SerialNumber}}
+		log.Printf("sendONUInd Onuid: %d\n", i)
+		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+			log.Printf("Failed to send ONUInd [id: %d]: %v\n", i, err)
+			return err
+		}
+	}
+	return nil
+}
+
 func newServer(oltid uint32, npon uint32, nonus uint32) *server{
 	s := new(server)
 	s.olt  = createOlt(oltid, npon, 1)
+	nnni := s.olt.NumNniIntf
 	log.Printf("OLT ID: %d was retrieved.\n", s.olt.ID)
 
-	s.onus = make(map[uint32][]onu)
-	for intfid := uint32(0); intfid < npon; intfid ++ {
-		s.onus[intfid] = createOnus(oltid, intfid, nonus)
+	s.onus = make(map[uint32]map[uint32] *onu)
+	for intfid := nnni; intfid < npon + nnni; intfid ++ {
+		s.onus[intfid] = createOnus(oltid, intfid, nonus, nnni)
 	}
+	//log.Printf("s.onus: %v\n", s.onus)
 	return s
 }
 
@@ -227,66 +286,19 @@
 }
 
 func getOptions()(string, uint32, uint32, uint32, uint32){
-	var(
-		addressport = flag.String("H","172.17.0.1:50060","IP address:port")
-		address  = strings.Split(*addressport, ":")[0]
-		port,_ = strconv.Atoi(strings.Split(*addressport, ":")[1])
-		nolts    = flag.Int("N", 1, "Number of OLTs")
-		nports   = flag.Int("i", 1, "Number of PON-IF ports")
-		nonus    = flag.Int("n", 1, "Number of ONUs per PON-IF port")
-	)
-
-
+	addressport := flag.String("H","127.0.0.1:50060","IP address:port")
+	nolts    := flag.Int("N", 1, "Number of OLTs")
+	nports   := flag.Int("i", 1, "Number of PON-IF ports")
+	nonus    := flag.Int("n", 1, "Number of ONUs per PON-IF port")
 	flag.Parse()
+	fmt.Printf("%v\n", *addressport)
 	//fmt.Println("nports:", *nports, "nonus:", *nonus)
+	address  := strings.Split(*addressport, ":")[0]
+	port,_ := strconv.Atoi(strings.Split(*addressport, ":")[1])
 	return address, uint32(port), uint32(*nolts), uint32(*nports), uint32(*nonus)
 }
 
 
-// gRPC Service
-func (s *server) ActivateOnu(c context.Context, onu *openolt.Onu) (*openolt.Empty, error){
-	log.Printf("OLT receives ActivateONU()")
-	result := validateONU(*onu, s.onus)
-	if result == true {
-		log.Printf("ONU %d activated succesufully.\n", onu.OnuId)
-	}
-	return new(openolt.Empty), nil
-}
-
-func (s *server)OmciMsgOut(c context.Context, msg *openolt.OmciMsg)(*openolt.Empty, error){
-	return new(openolt.Empty), nil
-}
-
-func (s *server) OnuPacketOut(c context.Context, packet *openolt.OnuPacket)(*openolt.Empty, error){
-	return new(openolt.Empty), nil
-}
-
-func (s *server) FlowAdd(c context.Context, flow *openolt.Flow)(*openolt.Empty, error){
-	return new(openolt.Empty), nil
-}
-
-func (s *server) EnableIndication(empty *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
-	log.Printf("OLT receives EnableInd.\n")
-	if err := activateOLT(s, stream); err != nil {
-		log.Printf("Failed to activate OLT: %v\n", err)
-		return err
-	}
-	for ;;{
-		//if err := sendIntfInd(stream, &s.olt); err != nil{
-		//	return err
-		//}
-		time.Sleep(1 * time.Second)
-	}
-	return nil
-}
-
-func (s *server) HeartbeatCheck(c context.Context, empty *openolt.Empty) (*openolt.Heartbeat, error){
-	log.Printf("OLT receives HeartbeatCheck.\n")
-	signature := new(openolt.Heartbeat)
-	signature.HeartbeatSignature = s.olt.HeartbeatSignature
-	return signature, nil
-}
-
 func main() {
 	printBanner()
 	ipaddress, baseport, nolts, npon, nonus := getOptions()