blob: 2c3a15da92ce112ab8245fdbded80dae5a55657f [file] [log] [blame]
/*
* 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 (
"./openolt"
"log"
"net"
"google.golang.org/grpc"
"fmt"
"flag"
"reflect"
"strings"
"strconv"
"sync"
)
type server struct{
olt olt
onus map[uint32]map[uint32]*onu
}
type oltState int
type onuState int
const(
PRE_ENABLE oltState = iota
OLT_UP
PONIF_UP
ONU_DISCOVERED
)
const(
ONU_PRE_ACTIVATED onuState = iota
ONU_ACTIVATED
)
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{
internalState onuState
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.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
}
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, 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]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 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 map[uint32] *onu, opstatus string){
for i, onu := range onus{
onu.OperState = "up"
log.Printf("(PONIF:%d) ONU [%d] discovered.\n", ponif, i)
}
}
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(olt.NumNniIntf); intfid < olt.NumNniIntf + olt.NumPonIntf; intfid ++ {
updateOnusOpStatus(intfid, onus[intfid], "up")
}
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)
}
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
}
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
}
log.Printf("SendIntfInd olt:%d intf:%d (%s)\n", olt.ID, intf.IntfID, intf.Type)
}
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
}
log.Printf("SendOperInd olt:%d intf:%d (%s)\n", olt.ID, intf.IntfID, intf.Type)
}
return nil
}
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)
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 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]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
}
func printBanner(){
log.Println(" ________ _______ ________ ")
log.Println(" / ____ | / ____ | / ______/ __ ")
log.Println(" / /____/ / / /____/ / / /_____ /_/ ")
log.Println(" / _____ | / _____ | /______ | __ __________ ")
log.Println(" / /____/ / / /____/ / _______/ / / / / __ __ / ")
log.Println("/________/ /________/ /________/ /_/ /_/ /_/ /_/ ")
}
func getOptions()(string, uint32, uint32, uint32, uint32){
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)
}
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()
}