First version of BBSim

Change-Id: I003b5cc4da090ba4631da65da2b513311648d667
VOL-813: gRPC server in BBSim (Broad Band Sim)
diff --git a/bbsim.go b/bbsim.go
new file mode 100755
index 0000000..2466dbb
--- /dev/null
+++ b/bbsim.go
@@ -0,0 +1,310 @@
+package main
+
+import (
+	"./openolt"
+	"log"
+	"net"
+	"google.golang.org/grpc"
+	"golang.org/x/net/context"
+	"fmt"
+	"flag"
+	"reflect"
+	"time"
+	"strings"
+	"strconv"
+	"sync"
+)
+
+type server struct{
+	olt olt
+	onus map[uint32][]onu
+}
+
+
+type oltState int
+
+const(
+	PRE_ENABLE oltState = iota
+	OLT_UP
+	PONIF_UP
+	ONU_DISCOVERED
+)
+
+
+//a
+type olt struct {
+	ID			         uint32
+	NumPonIntf           uint32
+	NumNniIntf           uint32
+	Mac                  string
+	SerialNumber         string
+	Manufacture          string
+	Name                 string
+	internalState        oltState
+	OperState            string
+	Intfs                []intf
+	HeartbeatSignature   uint32
+}
+
+type intf struct{
+	Type                string
+	IntfID              uint32
+	OperState           string
+}
+
+type onu struct{
+	IntfID              uint32
+	OperState           string
+	SerialNumber        *openolt.SerialNumber
+}
+
+func createOlt(oltid uint32, npon uint32, nnni uint32) olt{
+	olt := olt {}
+	olt.ID              = oltid
+	olt.NumPonIntf      = npon
+	olt.NumNniIntf      = nnni
+	olt.Name          = "BBSIM OLT"
+	olt.internalState = PRE_ENABLE
+	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 ++ {
+		olt.Intfs[i].IntfID = i
+		olt.Intfs[i].OperState = "up"
+		olt.Intfs[i].Type      = "nni"
+	}
+	return olt
+}
+
+func createSN(oltid uint32, intfid uint32, onuid uint32) string{
+	sn := fmt.Sprintf("%X%X%02X", oltid, intfid, onuid)
+	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
+	}
+	return onus
+}
+
+func validateONU(targetonu openolt.Onu, regonus map[uint32][]onu) bool{
+	for _, onus := range regonus{
+		for _, onu := range onus{
+			if validateSN(*targetonu.SerialNumber, *onu.SerialNumber){
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func validateSN(sn1 openolt.SerialNumber, sn2 openolt.SerialNumber) bool{
+	return reflect.DeepEqual(sn1.VendorId, sn2.VendorId) && reflect.DeepEqual(sn1.VendorSpecific, sn2.VendorSpecific)
+}
+
+
+func updateOnusOpStatus(ponif uint32, onus [] onu, opstatus string){
+	for i, onu := range onus{
+		onu.OperState = "up"
+		log.Printf("(PONIF:%d) ONU [%d] %v discovered.\n", ponif, i, onu.SerialNumber)
+	}
+}
+
+func activateOLT(s *server, stream openolt.Openolt_EnableIndicationServer) error{
+	// Activate OLT
+	olt  := &s.olt
+	onus := s.onus
+	if err := sendOltInd(stream, olt); err != nil {
+		return err
+	}
+	olt.OperState = "up"
+	olt.internalState = OLT_UP
+	log.Printf("OLT %s sent OltInd.\n", olt.Name)
+
+
+	// OLT sends Interface Indication to Adapter
+	if err := sendIntfInd(stream, olt); err != nil {
+		return err
+	}
+	log.Printf("OLT %s sent IntfInd.\n", olt.Name)
+
+	// OLT sends Operation Indication to Adapter after activating each interface
+	//time.Sleep(IF_UP_TIME * time.Second)
+	olt.internalState = PONIF_UP
+	if err := sendOperInd(stream, olt); err != nil {
+		return err
+	}
+	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 ++ {
+		updateOnusOpStatus(intfid, onus[intfid], "up")
+	}
+
+	for intfid := uint32(0); intfid < olt.NumPonIntf; intfid ++ {
+		sendOnuDiscInd(stream, onus[intfid])
+		log.Printf("OLT id:%d sent ONUDiscInd.\n", olt.ID)
+	}
+	olt.internalState = ONU_DISCOVERED
+	return nil
+}
+
+func sendOltInd(stream openolt.Openolt_EnableIndicationServer, olt *olt) error{
+	data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: "up"}}
+	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+		log.Printf("Failed to send OLT indication: %v\n", err)
+		return err
+	}
+	return nil
+}
+
+func sendIntfInd(stream openolt.Openolt_EnableIndicationServer, olt *olt) error{
+	for i := uint32(0); i < olt.NumPonIntf + olt.NumNniIntf; i ++ {
+		intf := olt.Intfs[i]
+		data := &openolt.Indication_IntfInd{&openolt.IntfIndication{IntfId: intf.IntfID, OperState: intf.OperState}}
+		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+			log.Printf("Failed to send Intf [id: %d] indication : %v\n", i, err)
+			return err
+		}
+	}
+	return nil
+}
+
+func sendOperInd(stream openolt.Openolt_EnableIndicationServer, olt *olt) error{
+	for i := uint32(0); i < olt.NumPonIntf + olt.NumNniIntf; i ++ {
+		intf := olt.Intfs[i]
+		data := &openolt.Indication_IntfOperInd{&openolt.IntfOperIndication{Type: intf.Type, IntfId: intf.IntfID, OperState: intf.OperState}}
+		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+			log.Printf("Failed to send IntfOper [id: %d] indication : %v\n", i, err)
+			return err
+		}
+	}
+	return nil
+}
+
+func sendOnuDiscInd(stream openolt.Openolt_EnableIndicationServer, onus [] 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)
+		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+			log.Printf("Failed to send ONUDiscInd [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)
+	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)
+	}
+	return s
+}
+
+func printBanner(){
+	log.Println("     ________    _______   ________                 ")
+	log.Println("    / ____   | / ____   | / ______/  __            ")
+	log.Println("   / /____/ / / /____/ / / /_____   /_/            ")
+	log.Println("  / _____  | / _____  | /______  | __  __________ ")
+	log.Println(" / /____/ / / /____/ / _______/ / / / / __  __  / ")
+	log.Println("/________/ /________/ /________/ /_/ /_/ /_/ /_/  ")
+}
+
+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")
+	)
+
+
+	flag.Parse()
+	//fmt.Println("nports:", *nports, "nonus:", *nonus)
+	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()
+	log.Printf("ip:%s, baseport:%d, nolts:%d, npon:%d, nonus:%d\n", ipaddress, baseport, nolts, npon, nonus)
+	servers := make([] *server, nolts)
+	grpcservers := make([] *grpc.Server, nolts)
+	lis         := make([] net.Listener, nolts)
+	var wg sync.WaitGroup
+	wg.Add(int(nolts))
+	for oltid := uint32(0); oltid < nolts; oltid ++ {
+		portnum := baseport + oltid
+		addressport := ipaddress + ":" + strconv.Itoa(int(portnum))
+		log.Printf("Listening %s ...", addressport)
+		lis[oltid], _ = net.Listen("tcp", addressport)
+		servers[oltid] = newServer(oltid, npon, nonus)
+		grpcservers[oltid] = grpc.NewServer()
+		openolt.RegisterOpenoltServer(grpcservers[oltid], servers[oltid])
+		go grpcservers[oltid].Serve(lis[oltid])
+	}
+	wg.Wait()
+}