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()
+}