SEBA-432
SEBA-565
SEBA-654 (alarms)
implemented
fix Jenkins make errors
fix merge conflicts
address review comments
Change-Id: Ia2e95afb33ce55054afa1fcbd9beb6ada62dd764
diff --git a/.gitignore b/.gitignore
index 203f81b..32fcb27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
-bbsim
+api/swagger/bbsim.swagger.json
+/bbsim
protos/openolt.pb.go
coverage.txt
diff --git a/Makefile b/Makefile
index d73ab70..e2c0242 100644
--- a/Makefile
+++ b/Makefile
@@ -19,16 +19,17 @@
.PHONY: dep test clean docker
prereq:
- go get -u google.golang.org/grpc
+ go get -v google.golang.org/grpc
go get -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -v github.com/golang/protobuf/protoc-gen-go
+ go get -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
go get -v github.com/google/gopacket
go get -v github.com/opencord/omci-sim
-bbsim: prereq protos/openolt.pb.go dep
+bbsim: prereq protos/openolt.pb.go bbsimapi dep
go build -i -v -o $@
-dep: protos/openolt.pb.go
+dep: protos/openolt.pb.go bbsimapi
go get -v -d ./...
protos/openolt.pb.go: openolt.proto
@@ -38,6 +39,23 @@
--go_out=plugins=grpc:protos/ \
$<
+bbsimapi: api/bbsim.proto
+ @protoc -I ./api \
+ -I${GOPATH}/src \
+ -I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
+ -I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway \
+ --go_out=plugins=grpc:api/ \
+ --grpc-gateway_out=logtostderr=true,allow_delete_body=true:api/ \
+ bbsim.proto
+
+swagger: ## Generate swagger documentation for BBsim API
+ @protoc -I ./api \
+ -I${GOPATH}/src \
+ -I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
+ -I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway \
+ --swagger_out=logtostderr=true,allow_delete_body=true:api/swagger/ \
+ bbsim.proto
+
test:
go test -v ./...
go test -v ./... -cover
@@ -52,7 +70,12 @@
gometalinter --vendor --exclude ../../golang.org --skip protos --sort path --sort line ./...
clean:
- rm -f bbsim openolt/openolt.pb.go
+ @rm -vf bbsim \
+ protos/openolt.pb.go \
+ api/bbsim.pb.go \
+ api/bbsim.pb.gw.go \
+ api/swagger/*.json
docker:
docker build -t ${REGISTRY}voltha/voltha-bbsim:${DOCKERTAG} .
+ docker save voltha/voltha-bbsim:${DOCKERTAG} -o voltha-bbsim_${DOCKERTAG}.tgz
diff --git a/README.md b/README.md
index 45ece4c..a3f3fd7 100644
--- a/README.md
+++ b/README.md
@@ -113,4 +113,10 @@
DHCP Server IP Address (default "182.21.0.128")
-v int
Interval each ONU Discovery Indication (ms) (default 1000)
+ -ia bool
+ Interactive activation of ONUs: if true ONUs must be activated explicitly using the management API (no ONUs are activated at startup) (default false)
+ -grpc int
+ Management API gRPC port (default 50061)
+ -rest int
+ Management API rest port (default 50062)
```
diff --git a/api/README.md b/api/README.md
new file mode 100644
index 0000000..02f9125
--- /dev/null
+++ b/api/README.md
@@ -0,0 +1,65 @@
+This directory contains protobuf files for the BBSim control API.
+
+# Examples
+
+```
+# start BBSim
+
+ ./bbsim -i 8 -n 16 -ia false
+
+# get OLT status
+
+ curl -X GET http://127.0.0.1:50062/v1/olt | jq
+
+# get status of the OLT's PON ports
+
+ curl -X GET http://127.0.0.1:50062/v1/olt/ports/pon | jq
+
+# get status of all active ONUs
+
+ curl -X GET http://127.0.0.1:50062/v1/olt/onus | jq
+
+# get the status of the ONU with ONU-ID 2 (on PON port 1)
+
+ curl -X GET "http://127.0.0.1:50062/v1/olt/onus?onu_id=2&pon_port_id=1" | jq
+
+# activate single ONU with a given serial number:
+
+ curl -X POST http://127.0.0.1:50062/v1/olt/ports/1/onus/BBSM00000201 | jq
+
+# get the status of an ONU using its serial number:
+
+ curl -X GET http://127.0.0.1:50062/v1/olt/onus/BBSM00000201 | jq
+
+# deactivate ONU using its serial number:
+
+ curl -X DELETE http://127.0.0.1:50062/v1/olt/onus/BBSM00000201 | jq
+
+# or
+
+ curl -X DELETE http://127.0.0.1:50062/v1/olt/onus?onu_serial=BBSM00000201 | jq
+```
+
+
+# Activate multiple ONUs
+```
+cat <<EOF > onus_request.json
+{
+ "onus": [
+ {
+ "pon_port_id": 1,
+ "onu_serial": "BBSIMONU0001"
+ },
+ {
+ "pon_port_id": 2,
+ "onu_serial": "BBSIMONU0002"
+ }
+ ]
+}
+EOF
+
+
+ curl -H "Content-Type: application/json" -X POST "http://127.0.0.1:50062/v1/olt/onus" -d @onus_request.json
+
+
+```
diff --git a/api/bbsim.proto b/api/bbsim.proto
new file mode 100644
index 0000000..494f947
--- /dev/null
+++ b/api/bbsim.proto
@@ -0,0 +1,196 @@
+// Copyright (c) 2018 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.
+
+syntax = "proto3";
+package bbsim.api.v1;
+
+import "google/api/annotations.proto";
+import "protoc-gen-swagger/options/annotations.proto";
+
+option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+ info: {
+ title: "BBSim API";
+ version: "1.0";
+ };
+ schemes: HTTP;
+ consumes: "application/json";
+ produces: "application/json";
+ responses: {
+ key: "404";
+ value: {
+ description: "Returned when the resource does not exist.";
+ schema: {
+ json_schema: {
+ type: STRING;
+ }
+ }
+ }
+ }
+};
+
+// OLT information
+message OLTInfo {
+ int64 olt_id = 1;
+ string olt_serial = 2;
+ string olt_ip = 3;
+ string olt_state = 4;
+ string olt_vendor = 5;
+}
+
+// ONU information
+message ONUInfo {
+ uint32 onu_id = 1;
+ uint32 pon_port_id = 2;
+ // ONU serial number
+ string onu_serial = 3;
+ // ONU oper state
+ string oper_state = 4;
+ // ONU internal state
+ string onu_state = 5;
+}
+
+// Bulk ONU operations
+message ONUs {
+ repeated ONUInfo onus = 1;
+}
+
+message ONURequest {
+ ONUInfo onu = 1;
+ ONUs onus_batch = 2;
+}
+
+// Port information
+message PortInfo {
+ string port_type = 1;
+ uint32 port_id = 2;
+ int32 pon_port_max_onus = 3;
+ uint32 pon_port_active_onus = 4;
+ string port_state = 5;
+ string alarm_state = 6;
+}
+
+// Bulk port information
+message Ports {
+ repeated PortInfo ports = 1;
+}
+
+// BBSim status
+message OLTStatusResponse {
+ OLTInfo olt = 1;
+ repeated PortInfo ports = 2;
+}
+
+// BBSim response message
+message BBSimResponse {
+ string status_msg = 1;
+}
+
+// ONU alarm request
+message ONUAlarmRequest {
+ // ONU serial number
+ string onu_serial = 1;
+ // Alarm types are:
+ // "signaldegrade"
+ // "lossofomcichannel"
+ // "lossofploam"
+ string alarm_type = 2;
+ // "on"/"off" indicates raised or cleared alarm
+ string status = 3; }
+
+// OLT alarm request
+message OLTAlarmRequest {
+ uint32 port_id = 1;
+ string port_type = 2;
+ string status = 3;
+}
+
+// Device action
+message DeviceAction {
+ string device_type = 1; // ONU or OLT
+ string device_serial_number = 2; // Device serial number
+ string device_action = 3; // soft or hard reboot
+}
+
+message Empty {}
+
+service BBSimService {
+
+ // Get current status of OLT
+ rpc OLTStatus(Empty) returns (OLTStatusResponse) {
+ option (google.api.http) = {
+ get : "/v1/olt"
+ additional_bindings {get : "/v1/olt/status"}
+ };
+ }
+
+ // Get status of a PON/NNI port
+ rpc PortStatus(PortInfo) returns (Ports) {
+ option (google.api.http) = {
+ get : "/v1/olt/ports/{port_type}"
+ };
+ }
+
+ // Get status of all or specific ONUs
+ rpc ONUStatus(ONURequest) returns (ONUs) {
+ option (google.api.http) = {
+ get : "/v1/olt/onus"
+ additional_bindings { get : "/v1/olt/ports/{onu.pon_port_id}/onus" }
+ additional_bindings { get : "/v1/olt/onus/{onu.onu_serial}" }
+ };
+ }
+
+ // Single/bulk activate ONU(s) for specific PON port(s)
+ rpc ONUActivate(ONURequest) returns (BBSimResponse) {
+ option (google.api.http) = {
+ post : "/v1/olt/onus"
+ body: "onus_batch"
+ additional_bindings { post : "/v1/olt/ports/{onu.pon_port_id}/onus" }
+ additional_bindings { post : "/v1/olt/ports/{onu.pon_port_id}/onus/{onu.onu_serial}" }
+ };
+ }
+
+ // Deactivate ONU(s) for specific PON port(s) specified by
+ // a given onu_serial, onu_id, or pon_port_id
+ rpc ONUDeactivate(ONURequest) returns (BBSimResponse) {
+ option (google.api.http) = {
+ delete : "/v1/olt/onus"
+ body: "onus_batch"
+ additional_bindings { delete: "/v1/olt/onus/{onu.onu_serial}" }
+ additional_bindings { delete: "/v1/olt/ports/{onu.pon_port_id}/onus" }
+ additional_bindings { delete: "/v1/olt/ports/{onu.pon_port_id}/onus/{onu.onu_id}" }
+ };
+ }
+
+ // Generate ONU related alarms
+ rpc GenerateONUAlarm(ONUAlarmRequest) returns (BBSimResponse) {
+ option (google.api.http) = {
+ post : "/v1/olt/onus/{onu_serial}/alarms/{alarm_type}/{status}"
+ };
+ }
+
+ // Generate OLT related alarms
+ rpc GenerateOLTAlarm(OLTAlarmRequest) returns (BBSimResponse) {
+ option (google.api.http) = {
+ post : "/v1/olt/ports/{port_type}/{port_id}/alarms/los/{status}"
+ };
+ }
+
+ // Perform actions on OLT/ONU devices (e.g. reboot)
+ rpc PerformDeviceAction(DeviceAction) returns (BBSimResponse) {
+ option (google.api.http) = {
+ patch: "/v1/{device_type}/reboot"
+ additional_bindings { patch : "/v1/olt/{device_type}/{device_serial_number}/reboot/{device_action}"}
+ };
+ }
+}
diff --git a/api/swagger/.gitignore b/api/swagger/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/api/swagger/.gitignore
diff --git a/common/logger/logger.go b/common/logger/logger.go
index e3d1e90..cb7229f 100644
--- a/common/logger/logger.go
+++ b/common/logger/logger.go
@@ -26,13 +26,14 @@
myLogger *log.Entry
)
+// Setup logger
func Setup(kafkaBroker string, level string) {
logger := log.New()
//logger.SetReportCaller(true)
myLogger = logger.WithField("topics", []string{"bbsim.log"})
- var logLevel log.Level = log.DebugLevel
+ var logLevel = log.DebugLevel
switch level{
case "TRACE":
logLevel = log.TraceLevel
@@ -75,38 +76,47 @@
myLogger.WithField("kafkaBroker", kafkaBroker).Debug("Logger setup done")
}
+// GetLogger return logger instance
func GetLogger() *log.Entry {
return myLogger
}
+// WithField logs message with specified field
func WithField(key string, value interface{}) *log.Entry {
return myLogger.WithField(key, value)
}
+// WithFields logs message with multiple fields
func WithFields(fields log.Fields) *log.Entry {
return myLogger.WithFields(fields)
}
+// Panic logs with log level panic
func Panic(msg string, args ...interface{}) {
myLogger.Panicf(msg, args...)
}
+// Fatal logs woth loge level fatal
func Fatal(msg string, args ...interface{}) {
myLogger.Fatalf(msg, args...)
}
+// Error logs with log level error
func Error(msg string, args ...interface{}) {
myLogger.Errorf(msg, args...)
}
+// Warn logs with log level warn
func Warn(msg string, args ...interface{}) {
myLogger.Warnf(msg, args...)
}
+// Info logs with log level info
func Info(msg string, args ...interface{}) {
myLogger.Infof(msg, args...)
}
+// Debug logs with log level debug
func Debug(msg string, args ...interface{}) {
myLogger.Debugf(msg, args...)
}
diff --git a/common/utils/utils.go b/common/utils/utils.go
index f36cae4..3bfd0de 100644
--- a/common/utils/utils.go
+++ b/common/utils/utils.go
@@ -17,20 +17,28 @@
package utils
import (
- "fmt"
+ "strconv"
"gerrit.opencord.org/voltha-bbsim/common/logger"
-
"gerrit.opencord.org/voltha-bbsim/device"
log "github.com/sirupsen/logrus"
)
-func OnuToSn(onu *device.Onu) string {
- // FIXME
- // see https://github.com/opencord/voltha/blob/master/voltha/adapters/openolt/openolt_device.py#L929-L943
- return string(onu.SerialNumber.VendorId) + "00000" + fmt.Sprint(onu.IntfID) + "0" + fmt.Sprintf("%x", onu.OnuID-1)
+// ConvB2S converts byte array to string
+func ConvB2S(b []byte) string {
+ s := ""
+ for _, i := range b {
+ s = s + strconv.FormatInt(int64(i/16), 16) + strconv.FormatInt(int64(i%16), 16)
+ }
+ return s
}
+// OnuToSn returns serial number in string format for given ONU
+func OnuToSn(onu *device.Onu) string {
+ return string(onu.SerialNumber.VendorId) + ConvB2S(onu.SerialNumber.VendorSpecific)
+}
+
+// LoggerWithOnu method logs ONU fields
func LoggerWithOnu(onu *device.Onu) *log.Entry {
if onu == nil {
@@ -40,8 +48,8 @@
return logger.GetLogger().WithFields(log.Fields{
"serial_number": OnuToSn(onu),
- "interfaceId": onu.IntfID,
- "onuId": onu.OnuID,
- "oltId": onu.OltID,
+ "interfaceID": onu.IntfID,
+ "onuID": onu.OnuID,
+ "oltID": onu.OltID,
})
}
diff --git a/core/alarms.go b/core/alarms.go
new file mode 100644
index 0000000..5c7d287
--- /dev/null
+++ b/core/alarms.go
@@ -0,0 +1,291 @@
+/*
+ * 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 core
+
+import (
+ "strconv"
+
+ pb "gerrit.opencord.org/voltha-bbsim/api"
+ "gerrit.opencord.org/voltha-bbsim/common/logger"
+ "gerrit.opencord.org/voltha-bbsim/device"
+ openolt "gerrit.opencord.org/voltha-bbsim/protos"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+const (
+ // OnuLossOfPloam is state on onu los
+ OnuLossOfPloam = "lossofploam"
+ // OnuLossOfOmciChannel is the state on omci channel loss alarm
+ OnuLossOfOmciChannel = "lossofomcichannel"
+ // OnuSignalDegrade is the state on signal degrade alarm
+ OnuSignalDegrade = "signaldegrade"
+ // AlarmOn is for raising the alarm
+ AlarmOn = "on"
+ // AlarmOff is for clearing the alarm
+ AlarmOff = "off"
+)
+
+func (s *Server) handleOnuAlarm(in *pb.ONUAlarmRequest) (*pb.BBSimResponse, error) {
+ value, ok := s.SNmap.Load(in.OnuSerial)
+ onu := value.(*device.Onu)
+ if !ok {
+ return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, "no active or discovered onu found with serial number "+in.OnuSerial)
+ }
+
+ if (onu.InternalState == device.ONU_LOS_RAISED || onu.InternalState == device.ONU_LOS_ON_OLT_PON_LOS) &&
+ (in.AlarmType != OnuLossOfPloam) {
+ return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, in.OnuSerial+" is not reachable, can not send onu alarm")
+ }
+
+ if s.Olt.PonIntfs[onu.IntfID].AlarmState == device.PonLosRaised && (in.AlarmType != OnuLossOfPloam) {
+ // Don't send onu alarm as OLT-PON is down
+ return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, "pon-port down, can not send onu alarm")
+ }
+ switch in.AlarmType {
+ case OnuLossOfOmciChannel:
+ Ind := formulateLossOfOmciChannelAlarm(in.Status, onu)
+ if in.Status == AlarmOn {
+ onu.UpdateIntState(device.ONU_OMCI_CHANNEL_LOS_RAISED)
+ } else {
+ onu.UpdateIntState(device.ONU_ACTIVE)
+ }
+ s.alarmCh <- Ind
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+
+ case OnuSignalDegrade:
+ Ind := formulateSignalDegradeAlarm(in.Status, onu)
+ s.alarmCh <- Ind
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+
+ case OnuLossOfPloam:
+ if in.Status == AlarmOn {
+ onu.UpdateIntState(device.ONU_LOS_RAISED)
+ device.UpdateOnusOpStatus(onu.IntfID, onu, "down")
+ } else {
+ onu.UpdateIntState(device.ONU_ACTIVE)
+ device.UpdateOnusOpStatus(onu.IntfID, onu, "up")
+ // TODO is it required to check onu state?
+ err := sendOnuDiscInd(*s.EnableServer, onu)
+ if err != nil {
+ logger.Error("Error: %v", err.Error())
+ }
+ }
+ Ind := formulateLossOfPLOAM(in.Status, onu)
+ s.alarmCh <- Ind
+ er := sendOnuInd(*s.EnableServer, onu, 0, onu.OperState, "up")
+ if er != nil {
+ logger.Debug(er.Error())
+ }
+
+ resp, err := s.checkAndSendOltPonLos(in.OnuSerial, in.Status, device.IntfPon) // Send olt los if all the onus attached to a pon-port shows los
+ if err != nil {
+ return resp, err
+ }
+ return resp, nil
+
+ default:
+ logger.Debug("Unhandled alarm type")
+ return &pb.BBSimResponse{}, status.Errorf(codes.Unimplemented, "Unhandled alarm type")
+ }
+
+}
+
+func (s *Server) handleOltAlarm(in *pb.OLTAlarmRequest) (*pb.BBSimResponse, error) {
+ switch in.PortType {
+ case device.IntfNni:
+
+ if !s.isNniIntfPresentInOlt(in.PortId) {
+ return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, strconv.Itoa(int(in.PortId))+" NNI not present in olt")
+ }
+
+ Ind := formulateOLTLOSAlarm(in.Status, in.PortId, device.IntfNni)
+ s.alarmCh <- Ind
+ s.setNNIPortState(in.PortId, in.Status)
+
+ case device.IntfPon:
+ if !s.isPonIntfPresentInOlt(in.PortId) {
+ return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, strconv.Itoa(int(in.PortId))+" PON not present in olt")
+ }
+ Ind := formulateOLTLOSAlarm(in.Status, in.PortId, in.PortType)
+ s.alarmCh <- Ind
+ onusOperstat := s.setPONPortState(in.PortId, in.Status)
+ for _, onu := range s.Onumap[in.PortId] {
+ if onu.InternalState == device.ONU_LOS_RAISED || onu.InternalState == device.ONU_FREE {
+ continue // Skip for onus which have independently raised onu los
+ }
+
+ er := sendOnuInd(*s.EnableServer, onu, 0, onusOperstat, "up")
+ if er != nil {
+ logger.Debug(er.Error())
+ }
+ s.sendOnuLosOnOltPonLos(onu, in.Status)
+ }
+ default:
+ return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "invalid interface type provided")
+ }
+
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+}
+
+func (s *Server) setNNIPortState(portID uint32, alarmstatus string) {
+ switch alarmstatus {
+ case AlarmOn:
+ s.Olt.UpdateNniPortState(portID, device.NniLosRaised, "down")
+
+ case AlarmOff:
+ s.Olt.UpdateNniPortState(portID, device.NniLosCleared, "up")
+ }
+}
+
+func (s *Server) setPONPortState(portID uint32, alarmstatus string) string {
+ switch alarmstatus {
+ case AlarmOn:
+ s.Olt.UpdatePonPortState(portID, device.PonLosRaised, "down")
+ return "down"
+
+ case AlarmOff:
+ s.Olt.UpdatePonPortState(portID, device.PonLosCleared, "up")
+ return "up"
+ }
+ return ""
+}
+
+func (s *Server) sendOnuLosOnOltPonLos(onu *device.Onu, status string) {
+ var internalState device.DeviceState
+
+ if status == AlarmOn {
+ internalState = device.ONU_LOS_ON_OLT_PON_LOS
+ } else if status == AlarmOff {
+ internalState = device.ONU_ACTIVE
+ }
+
+ Ind := formulateLossOfPLOAM(status, onu)
+ onu.UpdateIntState(internalState)
+
+ // update onus slice on alarm off
+ if status == "off" {
+ err := sendOnuDiscInd(*s.EnableServer, onu)
+ if err != nil {
+ logger.Error(err.Error())
+ }
+ }
+
+ s.alarmCh <- Ind
+}
+
+func formulateLossOfOmciChannelAlarm(status string, onu *device.Onu) *openolt.Indication {
+ logger.Debug("formulateLossofOmciChannelAlarm() invoked")
+
+ alarmIndication := &openolt.AlarmIndication_OnuLossOmciInd{
+ OnuLossOmciInd: &openolt.OnuLossOfOmciChannelIndication{
+ IntfId: onu.IntfID,
+ OnuId: onu.OnuID,
+ Status: status,
+ },
+ }
+
+ alarmind := &openolt.AlarmIndication{
+ Data: alarmIndication,
+ }
+
+ msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind}
+ Ind := &openolt.Indication{Data: msg}
+ return Ind
+}
+
+func formulateSignalDegradeAlarm(status string, onu *device.Onu) *openolt.Indication {
+ logger.Debug("formulateSignalDegrade() invoked")
+ alarmIndication := &openolt.AlarmIndication_OnuSignalDegradeInd{
+ OnuSignalDegradeInd: &openolt.OnuSignalDegradeIndication{
+ IntfId: onu.IntfID,
+ OnuId: onu.OnuID,
+ Status: status,
+ InverseBitErrorRate: 0,
+ },
+ }
+ alarmind := &openolt.AlarmIndication{
+ Data: alarmIndication,
+ }
+ msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind}
+ Ind := &openolt.Indication{Data: msg}
+ return Ind
+}
+
+func formulateLossOfPLOAM(status string, onu *device.Onu) *openolt.Indication {
+ logger.Debug("formulateLossOfPLOAM() invoked")
+
+ alarmIndication := &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
+ IntfId: onu.IntfID,
+ OnuId: onu.OnuID,
+ LosStatus: status,
+ LobStatus: status,
+ LopcMissStatus: status,
+ LopcMicErrorStatus: status,
+ }}
+
+ alarmind := &openolt.AlarmIndication{Data: alarmIndication}
+ msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind}
+ Ind := &openolt.Indication{Data: msg}
+ return Ind
+}
+
+func formulateOLTLOSAlarm(status string, PortID uint32, intfType string) *openolt.Indication {
+ intfID := interfaceIDToPortNo(PortID, intfType)
+
+ alarmIndication := &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{
+ IntfId: intfID,
+ Status: status,
+ }}
+
+ alarmind := &openolt.AlarmIndication{Data: alarmIndication}
+ msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind}
+ Ind := &openolt.Indication{Data: msg}
+ return Ind
+}
+
+func (s *Server) checkAndSendOltPonLos(serial string, status string, intfType string) (*pb.BBSimResponse, error) {
+ value, _ := s.SNmap.Load(serial)
+ onu := value.(*device.Onu)
+ if s.getNoOfActiveOnuByPortID(onu.IntfID) == 0 {
+ logger.Warn("Warning: Sending OLT-LOS, as all onus on pon-port %v raised los", onu.IntfID)
+ request := &pb.OLTAlarmRequest{PortId: onu.IntfID, Status: AlarmOn, PortType: device.IntfPon}
+ resp, err := s.handleOltAlarm(request)
+ return resp, err
+ }
+ if s.Olt.PonIntfs[onu.IntfID].AlarmState == device.PonLosRaised && status == AlarmOff {
+ s.setPONPortState(onu.IntfID, status)
+ Ind := formulateOLTLOSAlarm(status, onu.IntfID, intfType)
+ s.alarmCh <- Ind
+ }
+
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+}
+
+func interfaceIDToPortNo(intfid uint32, intfType string) uint32 {
+ // Converts interface-id to port-numbers that can be understood by the voltha
+ if intfType == device.IntfNni {
+ // nni at voltha starts with 65536
+ // nni = 65536 + interface_id
+ return 0x1<<16 + intfid
+ } else if intfType == device.IntfPon {
+ // pon = 536,870,912 + interface_id
+ return (0x2 << 28) + intfid // In openolt code, stats_collection.cc line number 196, pon starts from 0
+ // In bbsim, pon starts from 1
+ }
+ return 0
+}
diff --git a/core/api_handler.go b/core/api_handler.go
new file mode 100644
index 0000000..eb52977
--- /dev/null
+++ b/core/api_handler.go
@@ -0,0 +1,424 @@
+/*
+ * 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 core
+
+import (
+ "errors"
+ "net"
+ "strconv"
+ "time"
+
+ pb "gerrit.opencord.org/voltha-bbsim/api"
+ "gerrit.opencord.org/voltha-bbsim/common/logger"
+ "gerrit.opencord.org/voltha-bbsim/device"
+ "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{}
+ if in.OnuSerial != "" { // Get status of single ONU by SerialNumber
+ // Get OpenOlt serial number from string
+ sn, err := getOpenoltSerialNumber(in.OnuSerial)
+ if err != nil {
+ logger.Error("Invalid serial number %s", in.OnuSerial)
+ return onuInfo, status.Errorf(codes.InvalidArgument, "serial: "+in.OnuSerial+" is invalid")
+ }
+ // Get ONU by serial number
+ onu, err := getOnuBySN(s.Onumap, sn)
+ if err != nil {
+ logger.Error("ONU with serial number %v not found", sn)
+ return onuInfo, status.Errorf(codes.NotFound, "serial: "+in.OnuSerial+" not found")
+ }
+ onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
+ } else {
+ // Return error if specified PON port does not exist
+ if _, exist := s.Onumap[in.PonPortId]; !exist {
+ logger.Error("PON port %d not found", in.PonPortId)
+ return onuInfo, status.Errorf(codes.NotFound, "PON Port: "+strconv.Itoa(int(in.PonPortId))+" not found")
+ }
+
+ if in.OnuId != 0 { // Get status of single ONU by ONU-ID
+ for intfid := range s.Onumap {
+ for _, onu := range s.Onumap[intfid] {
+ if in.OnuId == onu.OnuID {
+ onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
+ }
+ }
+ }
+ } else {
+ // Append ONU data
+ for _, onu := range s.Onumap[in.PonPortId] {
+ onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
+ }
+ }
+ }
+
+ return onuInfo, nil
+}
+
+// handleONUActivate method handles ONU activate requests from user.
+func (s *Server) handleONUActivate(in []*pb.ONUInfo) (*pb.BBSimResponse, error) {
+ logger.Info("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)
+ }
+
+ onuaddmap := make(map[uint32][]*device.Onu)
+ var newSerialNums []string
+
+ //Iterate request for each PON port specified
+ for _, onu := range in {
+ intfid := onu.PonPortId
+
+ // 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())
+ }
+
+ // Check if Serial number is provided by user
+ if onu.OnuSerial != "" {
+ // Get OpenOlt serial number from string
+ sn, err := getOpenoltSerialNumber(onu.OnuSerial)
+ if err != nil {
+ logger.Error("Failed to get OpenOlt serial number %v", err)
+ Onu.InternalState = device.ONU_FREE
+ markONUsFree(onuaddmap)
+ return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "serial number: "+onu.OnuSerial+" is invalid")
+ }
+
+ // Check if serial number is not duplicate in requested ONUs
+ for _, sn := range newSerialNums {
+ if onu.OnuSerial == sn {
+ 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")
+ }
+ }
+ newSerialNums = append(newSerialNums, onu.OnuSerial)
+
+ // Check if serial number already exist
+ _, exist := s.getOnuFromSNmap(sn)
+ if exist {
+ 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")
+ }
+
+ // Store user provided serial number in ONU object
+ Onu.SerialNumber = sn
+ }
+ // Store onu object in map for particular intfid
+ onuaddmap[intfid] = append(onuaddmap[intfid], Onu)
+ }
+
+ if len(onuaddmap) >= 1 {
+ //Pass onumap to activateONU to handle indication to VOLTHA
+ s.activateONUs(*s.EnableServer, onuaddmap)
+ }
+
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+}
+
+// handleONUDeactivate deactivates ONU described by a single ONUInfo object
+func (s *Server) handleONUDeactivate(in *pb.ONUInfo) error {
+
+ if s.EnableServer == nil {
+ logger.Error(OLTNotEnabled)
+ return status.Errorf(codes.FailedPrecondition, OLTNotEnabled)
+ }
+
+ if in.OnuSerial != "" {
+ // Get OpenOlt serial number from string
+ serialNumber, err := getOpenoltSerialNumber(in.OnuSerial)
+ if err != nil {
+ logger.Error("Invalid serial number %s", in.OnuSerial)
+ return status.Errorf(codes.InvalidArgument, "serial: "+in.OnuSerial+" is invalid")
+ }
+ // Get ONU by serial number
+ onu, exist := s.getOnuFromSNmap(serialNumber)
+ if !exist {
+ logger.Error("ONU with serial number %s not found", in.OnuSerial)
+ return status.Errorf(codes.NotFound, "serial: "+in.OnuSerial+" not found")
+ }
+
+ if err := s.HandleOnuDeactivate(onu); err != nil {
+ return err
+ }
+ } else {
+ if in.OnuId != 0 { // if provided, delete ONU by ONU ID
+ onu, err := getOnuByID(s.Onumap, in.OnuId, in.PonPortId)
+ if err != nil {
+ return err
+ }
+ if err := s.HandleOnuDeactivate(onu); err != nil {
+ return err
+ }
+ } else { // delete all ONUs on provided port
+ if err := s.DeactivateAllOnuByIntfID(in.PonPortId); err != nil {
+ logger.Error("Failed in handleONUDeactivate: %v", err)
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (s *Server) handleOLTReboot() {
+ logger.Debug("HandleOLTReboot() invoked")
+ logger.Debug("Sending stop to serverActionCh")
+ s.serverActionCh <- OpenOltStop
+ time.Sleep(40 * time.Second)
+
+ logger.Debug("Sending start to serverActionCh")
+ s.serverActionCh <- OpenOltStart
+ for {
+ if s.Olt.GetIntState() == device.OLT_ACTIVE {
+ logger.Info("Info: OLT reactivated")
+ break
+ }
+ time.Sleep(2 * time.Second)
+ }
+ s.sendOnuIndicationsOnOltReboot()
+}
+
+func (s *Server) handleONUHardReboot(onu *device.Onu) {
+ logger.Debug("handleONUHardReboot() invoked")
+ _ = sendDyingGaspInd(*s.EnableServer, onu.IntfID, onu.OnuID)
+ device.UpdateOnusOpStatus(onu.IntfID, onu, "down")
+ // send operstat down to voltha
+ _ = sendOnuInd(*s.EnableServer, onu, s.IndInterval, "down", "up")
+ // Give OEH some time to perform cleanup
+ time.Sleep(30 * time.Second)
+ s.activateOnu(onu)
+}
+
+func (s *Server) handleONUSoftReboot(IntfID uint32, OnuID uint32) {
+ logger.Debug("handleONUSoftReboot() invoked")
+ onu, err := s.GetOnuByID(OnuID, IntfID)
+ if err != nil {
+ logger.Error("No onu found with given OnuID on interface %v", IntfID)
+ }
+ OnuAlarmRequest := &pb.ONUAlarmRequest{
+ OnuSerial: stringifySerialNumber(onu.SerialNumber),
+ AlarmType: OnuLossOfPloam,
+ Status: "on",
+ }
+ // Raise alarm
+ _, err = s.handleOnuAlarm(OnuAlarmRequest)
+ if err != nil {
+ logger.Error(err.Error())
+ }
+ // Clear alarm
+ time.Sleep(10 * time.Second)
+ OnuAlarmRequest.Status = "off"
+ _, err = s.handleOnuAlarm(OnuAlarmRequest)
+ if err != nil {
+ logger.Error(err.Error())
+ }
+}
+
+// GetNextFreeOnu returns free onu object for specified interface ID
+func (s *Server) GetNextFreeOnu(intfid uint32) (*device.Onu, error) {
+ 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 auto generated serial number is already used by some other ONU,
+ // continue to find for other free object
+ snkey := stringifySerialNumber(onu.SerialNumber)
+ if _, exist := s.SNmap.Load(snkey); exist {
+ continue
+ }
+ // Update Onu Internal State
+ onu.InternalState = device.ONU_INACTIVE
+ return onu, nil
+ }
+ }
+ return nil, errors.New("no free ONU found for pon port: " + strconv.Itoa(int(intfid)))
+}
+
+// DeactivateAllOnuByIntfID deletes all ONUs for given PON port ID
+func (s *Server) DeactivateAllOnuByIntfID(intfid uint32) error {
+ for _, onu := range s.Onumap[intfid] {
+ if onu.InternalState == device.ONU_FREE || onu.InternalState == device.ONU_INACTIVE {
+ continue
+ }
+ if err := s.HandleOnuDeactivate(onu); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// 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)
+
+ // Update ONU internal state to ONU_INACTIVE
+ s.updateDevIntState(onu, device.ONU_INACTIVE)
+
+ // Update ONU operstate to down
+ onu.OperState = "down"
+
+ // Send DyingGasp Alarm to VOLTHA
+ _ = sendDyingGaspInd(*s.EnableServer, onu.IntfID, onu.OnuID)
+ _ = sendOnuInd(*s.EnableServer, onu, s.IndInterval, onu.OperState, "down")
+ return nil
+}
+
+func markONUsFree(onumap map[uint32][]*device.Onu) {
+ for intfid := range onumap {
+ for _, onu := range onumap[intfid] {
+ onu.UpdateIntState(device.ONU_FREE)
+ }
+ }
+}
+
+func copyONUInfo(onu *device.Onu) *pb.ONUInfo {
+ onuData := &pb.ONUInfo{
+ OnuId: onu.OnuID,
+ PonPortId: onu.IntfID,
+ OnuSerial: stringifySerialNumber(onu.SerialNumber),
+ OnuState: device.ONUState[onu.InternalState],
+ OperState: onu.OperState,
+ }
+ 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
+
+ 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")
+ }
+}
+
+func (s *Server) validateDeviceActionRequest(request *pb.DeviceAction) (*pb.DeviceAction, error) {
+ switch request.DeviceType {
+ case DeviceTypeOnu:
+ if request.DeviceSerialNumber == "" {
+ return request, errors.New("onu serial number can not be blank")
+ }
+
+ if len(request.DeviceSerialNumber) != SerialNumberLength {
+ return request, errors.New("invalid serial number provided")
+ }
+
+ if request.DeviceAction != SoftReboot && request.DeviceAction != HardReboot {
+ return request, errors.New("invalid device action provided")
+ }
+ return request, nil
+ case DeviceTypeOlt:
+ request.DeviceType = DeviceTypeOlt
+ request.DeviceAction = HardReboot
+ return request, nil
+ default:
+ return request, errors.New("invalid device type")
+ }
+}
+
+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 {
+ noOfActiveOnus++
+ }
+ }
+ return noOfActiveOnus
+}
+
+func (s *Server) isPonIntfPresentInOlt(intfID uint32) bool {
+ for _, intf := range s.Olt.PonIntfs {
+ if intf.IntfID == intfID {
+ return true
+ }
+ }
+ return false
+}
+
+func (s *Server) isNniIntfPresentInOlt(intfID uint32) bool {
+ for _, intf := range s.Olt.NniIntfs {
+ if intf.IntfID == intfID {
+ return true
+ }
+ }
+ return false
+}
+
+func getOltIP() net.IP {
+ // TODO make this better
+ conn, err := net.Dial("udp", "8.8.8.8:80")
+ if err != nil {
+ logger.Error(err.Error())
+ return net.IP{}
+ }
+ defer func() {
+ err := conn.Close()
+ if err != nil {
+ logger.Error(err.Error())
+ }
+ }()
+
+ localAddr := conn.LocalAddr().(*net.UDPAddr)
+
+ return localAddr.IP
+}
diff --git a/core/api_service.go b/core/api_service.go
new file mode 100644
index 0000000..a826594
--- /dev/null
+++ b/core/api_service.go
@@ -0,0 +1,247 @@
+/*
+ * 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 core
+
+import (
+ "context"
+ "net"
+ "net/http"
+ "sync"
+
+ "gerrit.opencord.org/voltha-bbsim/device"
+
+ pb "gerrit.opencord.org/voltha-bbsim/api"
+ "github.com/grpc-ecosystem/grpc-gateway/runtime"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+
+ "gerrit.opencord.org/voltha-bbsim/common/logger"
+)
+
+// Response Constants
+const (
+ RequestAccepted = "API request accepted"
+ OLTNotEnabled = "OLT not enabled"
+ RequestFailed = "API request failed"
+ SoftReboot = "soft-reboot"
+ HardReboot = "hard-reboot"
+ DeviceTypeOlt = "olt"
+ DeviceTypeOnu = "onu"
+)
+
+// OLTStatus method returns OLT status.
+func (s *Server) OLTStatus(ctx context.Context, in *pb.Empty) (*pb.OLTStatusResponse, error) {
+ logger.Debug("OLTStatus request received")
+ oltInfo := &pb.OLTStatusResponse{
+ Olt: &pb.OLTInfo{
+ OltId: int64(s.Olt.ID),
+ OltSerial: s.Olt.SerialNumber,
+ OltIp: getOltIP().String(),
+ OltState: s.Olt.OperState,
+ OltVendor: s.Olt.Manufacture,
+ },
+ }
+
+ for _, nniPort := range s.Olt.NniIntfs {
+ nniPortInfo, _ := s.fetchPortDetail(nniPort.IntfID, nniPort.Type)
+ oltInfo.Ports = append(oltInfo.Ports, nniPortInfo)
+ }
+ for _, ponPort := range s.Olt.PonIntfs {
+ ponPortInfo, _ := s.fetchPortDetail(ponPort.IntfID, ponPort.Type)
+ oltInfo.Ports = append(oltInfo.Ports, ponPortInfo)
+ }
+
+ logger.Info("OLT Info: %v\n", oltInfo)
+ return oltInfo, nil
+}
+
+// PortStatus method returns Port status.
+func (s *Server) PortStatus(ctx context.Context, in *pb.PortInfo) (*pb.Ports, error) {
+ portInfo := &pb.Ports{}
+ logger.Debug("PortStatus() invoked")
+ if in.PortType == device.IntfNni {
+ for _, nniPort := range s.Olt.NniIntfs {
+ nniPortInfo, _ := s.fetchPortDetail(nniPort.IntfID, nniPort.Type)
+ portInfo.Ports = append(portInfo.Ports, nniPortInfo)
+ }
+ } else if in.PortType == device.IntfPon {
+ for _, ponPort := range s.Olt.PonIntfs {
+ ponPortInfo, _ := s.fetchPortDetail(ponPort.IntfID, ponPort.Type)
+ portInfo.Ports = append(portInfo.Ports, ponPortInfo)
+ }
+ } else {
+ return &pb.Ports{}, status.Errorf(codes.InvalidArgument, "Invalid port type")
+
+ }
+ return portInfo, nil
+}
+
+// ONUStatus method returns ONU status.
+func (s *Server) ONUStatus(ctx context.Context, in *pb.ONURequest) (*pb.ONUs, error) {
+ logger.Debug("ONUStatus request received")
+ if in.GetOnu() != nil {
+ logger.Debug("Received single ONU: %+v, %d\n", in.GetOnu(), in.GetOnu().PonPortId)
+ return s.handleONUStatusRequest(in.GetOnu())
+ }
+ logger.Debug("Received bulk ONUs status request")
+ onuInfo := &pb.ONUs{}
+ for intfid := range s.Onumap {
+ for _, onu := range s.Onumap[intfid] {
+ if onu.InternalState != device.ONU_FREE {
+ onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
+ }
+ }
+ }
+ return onuInfo, nil
+}
+
+// ONUActivate method handles ONU activate requests from user.
+func (s *Server) ONUActivate(ctx context.Context, in *pb.ONURequest) (*pb.BBSimResponse, error) {
+ logger.Info("ONUActivate request received")
+ logger.Debug("Received values: %+v\n", in)
+
+ var onuInfo = []*pb.ONUInfo{}
+ // Activate single ONU
+ if in.GetOnu() != nil {
+ logger.Debug("Received single ONU: %+v\n", in.GetOnu())
+ onuInfo = append(onuInfo, in.GetOnu())
+ } else if len(in.GetOnusBatch().GetOnus()) != 0 { // Activate multiple ONUs
+ logger.Debug("Received multiple ONUs")
+ onuInfo = in.GetOnusBatch().GetOnus()
+ } else {
+ logger.Debug("Received empty request body")
+ return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, RequestFailed)
+ }
+ resp, err := s.handleONUActivate(onuInfo)
+ return resp, err
+}
+
+// ONUDeactivate method handles ONU deactivation request.
+func (s *Server) ONUDeactivate(ctx context.Context, in *pb.ONURequest) (*pb.BBSimResponse, error) {
+ logger.Info("ONUDeactivate request received")
+
+ // deactivate single ONU
+ if in.GetOnu() != nil {
+ logger.Debug("Received single ONU: %+v\n", in.GetOnu())
+ err := s.handleONUDeactivate(in.GetOnu())
+ if err != nil {
+ return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, RequestFailed)
+ }
+ } else if len(in.GetOnusBatch().GetOnus()) != 0 { // bulk deactivate
+ logger.Debug("Received multiple ONUs")
+ for _, onuinfo := range in.GetOnusBatch().GetOnus() {
+ logger.Debug("ONU values: %+v\n", onuinfo)
+ err := s.handleONUDeactivate(onuinfo)
+ if err != nil {
+ return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, RequestFailed)
+ }
+ }
+ } else {
+ // Empty request body is passed, delete all ONUs from all PON ports
+ for intfID := range s.Onumap {
+ if err := s.DeactivateAllOnuByIntfID(intfID); err != nil {
+ logger.Error("Failed in ONUDeactivate: %v", err)
+ return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, RequestFailed)
+ }
+ }
+ }
+
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+}
+
+// GenerateONUAlarm RPC generates alarm for the onu
+func (s *Server) GenerateONUAlarm(ctx context.Context, in *pb.ONUAlarmRequest) (*pb.BBSimResponse, error) {
+ logger.Debug("GenerateONUAlarms() invoked")
+ if in.OnuSerial == "" {
+ return &pb.BBSimResponse{}, status.Errorf(codes.FailedPrecondition, "serial number can not be blank")
+ }
+ if len(in.OnuSerial) != SerialNumberLength {
+ return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "invalid serial number given (length mismatch)")
+ }
+ if in.Status != "on" && in.Status != "off" {
+ return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "invalid alarm status provided")
+ }
+ if s.alarmCh == nil {
+ return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "alarm-channel not created, can not send alarm")
+ }
+ // TODO put these checks inside handleOnuAlarm for modularity
+ resp, err := s.handleOnuAlarm(in)
+ return resp, err
+}
+
+// GenerateOLTAlarm RPC generates alarm for the OLT
+func (s *Server) GenerateOLTAlarm(ctx context.Context, in *pb.OLTAlarmRequest) (*pb.BBSimResponse, error) {
+ logger.Debug("GenerateOLTAlarm() invoked")
+ if in.Status != "on" && in.Status != "off" {
+ return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "invalid alarm status provided")
+ }
+ if s.alarmCh == nil {
+ return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "alarm-channel not created, can not send alarm")
+ }
+ resp, err := s.handleOltAlarm(in)
+ if err != nil {
+ return resp, err
+ }
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+}
+
+// PerformDeviceAction rpc take the device request and performs OLT and ONU hard and soft reboot
+func (s *Server) PerformDeviceAction(ctx context.Context, in *pb.DeviceAction) (*pb.BBSimResponse, error) {
+ logger.Debug("PerformDeviceAction() invoked")
+ if s.deviceActionCh == nil {
+ return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "device action channel not created, can not entertain request")
+ }
+ in, err := s.validateDeviceActionRequest(in)
+ if err != nil {
+ return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, err.Error())
+ }
+ s.deviceActionCh <- in
+ return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
+}
+
+// NewMgmtAPIServer method starts BBSim gRPC server.
+func NewMgmtAPIServer(addrport string) (l net.Listener, g *grpc.Server, e error) {
+ logger.Info("BBSim gRPC server listening %s ...", addrport)
+ g = grpc.NewServer()
+ l, e = net.Listen("tcp", addrport)
+ return
+}
+
+// StartRestGatewayService method starts REST server for BBSim.
+func StartRestGatewayService(grpcAddress string, hostandport string, wg *sync.WaitGroup) {
+ ctx := context.Background()
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+
+ mux := runtime.NewServeMux()
+ opts := []grpc.DialOption{grpc.WithInsecure()}
+ // Register REST endpoints
+ err := pb.RegisterBBSimServiceHandlerFromEndpoint(ctx, mux, grpcAddress, opts)
+ if err != nil {
+ logger.Error("%v", err)
+ return
+ }
+
+ logger.Info("BBSim REST server listening %s ...", hostandport)
+ err = http.ListenAndServe(hostandport, mux)
+ if err != nil {
+ logger.Error("%v", err)
+ return
+ }
+ return
+}
diff --git a/core/core_server.go b/core/core_server.go
index ba0727a..4c4fcab 100644
--- a/core/core_server.go
+++ b/core/core_server.go
@@ -18,54 +18,73 @@
import (
"context"
+ "encoding/hex"
"errors"
+ "reflect"
"strconv"
"sync"
- "reflect"
- omci "github.com/opencord/omci-sim"
+ pb "gerrit.opencord.org/voltha-bbsim/api"
"gerrit.opencord.org/voltha-bbsim/common/logger"
"gerrit.opencord.org/voltha-bbsim/common/utils"
"gerrit.opencord.org/voltha-bbsim/device"
+ flowHandler "gerrit.opencord.org/voltha-bbsim/flow"
openolt "gerrit.opencord.org/voltha-bbsim/protos"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
+ omci "github.com/opencord/omci-sim"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
)
+// Constants
const (
- NNI_VETH_NORTH_PFX = "nni_north"
- NNI_VETH_SOUTH_PFX = "nni_south"
- MAX_ONUS_PER_PON = 64 // This value should be the same with the value in AdapterPlatrorm class
+ NniVethNorthPfx = "nni_north"
+ NniVethSouthPfx = "nni_south"
+ MaxPonPorts = 64
+ MaxOnusPerPon = 64 // This value should be the same with the value in AdapterPlatform class
+ VendorIDLength = 4
+ SerialNumberLength = 12
+ OpenOltStart = "start"
+ OpenOltStop = "stop"
)
// Server structure consists of all the params required for BBsim.
type Server struct {
- wg *sync.WaitGroup
- Olt *device.Olt
- Onumap map[uint32][]*device.Onu
- Ioinfos []*Ioinfo
- gRPCserver *grpc.Server
- gRPCAddress string
- gRPCPort uint32
- Vethnames []string
- IndInterval int
- Processes []string
- EnableServer *openolt.Openolt_EnableIndicationServer
- CtagMap map[string]uint32
- cancel context.CancelFunc
- stateRepCh chan stateReport
- omciIn chan openolt.OmciIndication
- omciOut chan openolt.OmciMsg
- eapolIn chan *byteMsg
- eapolOut chan *byteMsg
- dhcpIn chan *byteMsg
- dhcpOut chan *byteMsg
+ wg *sync.WaitGroup
+ Olt *device.Olt
+ Onumap map[uint32][]*device.Onu
+ SNmap sync.Map
+ AutoONUActivate bool
+ Ioinfos []*Ioinfo
+ gRPCserver *grpc.Server
+ gRPCAddress string
+ gRPCPort uint32
+ mgmtServer *grpc.Server
+ mgmtGrpcPort uint32
+ mgmtRestPort uint32
+ Vethnames []string
+ IndInterval int
+ Processes []string
+ EnableServer *openolt.Openolt_EnableIndicationServer
+ CtagMap map[string]uint32
+ cancel context.CancelFunc
+ stateRepCh chan stateReport
+ omciIn chan openolt.OmciIndication
+ omciOut chan openolt.OmciMsg
+ eapolIn chan *byteMsg
+ eapolOut chan *byteMsg
+ dhcpIn chan *byteMsg
+ dhcpOut chan *byteMsg
+ FlowMap map[FlowKey]*openolt.Flow
+ alarmCh chan *openolt.Indication
+ deviceActionCh chan *pb.DeviceAction
+ serverActionCh chan string
}
+// Packet structure
type Packet struct {
Info *Ioinfo
Pkt gopacket.Packet
@@ -83,56 +102,89 @@
next device.DeviceState
}
+// FlowKey used for FlowMap key
+type FlowKey struct {
+ FlowID uint32
+ FlowDirection string
+}
+
// NewCore initialize OLT and ONU objects
func NewCore(opt *option) *Server {
// TODO: make it decent
oltid := opt.oltid
npon := opt.npon
- nonus := opt.nonus
- s := Server{
- Olt: device.NewOlt(oltid, npon, 1),
- Onumap: make(map[uint32][]*device.Onu),
- Ioinfos: []*Ioinfo{},
- gRPCAddress: opt.address,
- gRPCPort: opt.port,
- Vethnames: []string{},
- IndInterval: opt.intvl,
- Processes: []string{},
- EnableServer: nil,
- stateRepCh: make(chan stateReport, 8),
- omciIn: make(chan openolt.OmciIndication, 1024),
- omciOut: make(chan openolt.OmciMsg, 1024),
- eapolIn: make(chan *byteMsg, 1024),
- eapolOut: make(chan *byteMsg, 1024),
- dhcpIn: make(chan *byteMsg, 1024),
- dhcpOut: make(chan *byteMsg, 1024),
+ if npon > MaxPonPorts {
+ logger.Warn("Provided number of PON ports exceeds limit of %d", MaxPonPorts)
+ logger.Info("Setting number of PON ports to %d", MaxPonPorts)
+ npon = MaxPonPorts
}
+ nonus := opt.nonus
+ if nonus > MaxOnusPerPon {
+ logger.Warn("Provided number of ONUs per PON port exceeds limit of %d", MaxOnusPerPon)
+ logger.Info("Setting number of ONUs per PON port to %d", MaxOnusPerPon)
+ nonus = MaxOnusPerPon
+ }
+ s := Server{
+ Olt: device.NewOlt(oltid, npon, 1), // TODO nnni is to be taken from options
+ Onumap: make(map[uint32][]*device.Onu),
+ Ioinfos: []*Ioinfo{},
+ gRPCAddress: opt.address,
+ gRPCPort: opt.port,
+ Vethnames: []string{},
+ IndInterval: opt.intvl,
+ AutoONUActivate: !opt.interactiveOnuActivation,
+ Processes: []string{},
+ mgmtGrpcPort: opt.mgmtGrpcPort,
+ mgmtRestPort: opt.mgmtRestPort,
+ EnableServer: nil,
+ stateRepCh: make(chan stateReport, 8),
+ omciIn: make(chan openolt.OmciIndication, 1024),
+ omciOut: make(chan openolt.OmciMsg, 1024),
+ eapolIn: make(chan *byteMsg, 1024),
+ eapolOut: make(chan *byteMsg, 1024),
+ dhcpIn: make(chan *byteMsg, 1024),
+ dhcpOut: make(chan *byteMsg, 1024),
+ FlowMap: make(map[FlowKey]*openolt.Flow),
+ serverActionCh: make(chan string),
+ }
+ logger.Info("OLT %d created: %v", s.Olt.ID, s.Olt)
nnni := s.Olt.NumNniIntf
logger.Info("OLT ID: %d was retrieved.", s.Olt.ID)
- for intfid := nnni; intfid < npon+nnni; intfid++ {
+ logger.Info("OLT Serial-Number: %v", s.Olt.SerialNumber)
+ // Creating Onu Map
+ for intfid := uint32(0); intfid < npon; intfid++ {
s.Onumap[intfid] = device.NewOnus(oltid, intfid, nonus, nnni)
}
- //TODO: To be fixed because it is hardcoded
+ logger.Debug("Onu Map:")
+ for _, onus := range s.Onumap {
+ for _, onu := range onus {
+ logger.Debug("%+v", *onu)
+ }
+ }
+
+ // TODO: To be fixed because it is hardcoded
s.CtagMap = make(map[string]uint32)
- for i := 0; i < MAX_ONUS_PER_PON; i++ {
+ for i := 0; i < MaxOnusPerPon; i++ {
oltid := s.Olt.ID
intfid := uint32(1)
- sn := convB2S(device.NewSN(oltid, intfid, uint32(i)))
+ sn := utils.ConvB2S(device.NewSN(oltid, intfid, uint32(i)))
s.CtagMap[sn] = uint32(900 + i) // This is hard coded for BBWF
}
+
+ flowHandler.InitializeFlowManager(s.Olt.ID)
return &s
}
-// Start starts the BBSim and openolt gRPC servers (blocking)
+// Start starts the openolt gRPC server (blocking)
func (s *Server) Start() error {
- s.wg = &sync.WaitGroup{}
- logger.Debug("Start() Start")
+ logger.Debug("Starting OpenOLT gRPC Server")
defer func() {
- close(s.stateRepCh)
- logger.Debug("Start() Done")
+ logger.Debug("OpenOLT gRPC Server Stopped")
}()
+
+ // Start Openolt gRPC server
addressport := s.gRPCAddress + ":" + strconv.Itoa(int(s.gRPCPort))
listener, gserver, err := NewGrpcServer(addressport)
if err != nil {
@@ -145,32 +197,67 @@
logger.Error("Failed to run gRPC server: %v", err)
return err
}
- s.wg.Wait()
return nil
}
-// Stop stops the BBSim and openolt gRPC servers (non-blocking).
+// Stop stops the openolt gRPC servers (non-blocking).
func (s *Server) Stop() {
- logger.Debug("Stop() Start")
- defer logger.Debug("Stop() Done")
+ logger.Debug("Stopping OpenOLT gRPC Server & PktLoops")
+ defer logger.Debug("OpenOLT gRPC Server & PktLoops Stopped")
+
if s.gRPCserver != nil {
s.gRPCserver.Stop()
logger.Debug("gRPCserver.Stop()")
}
+
s.StopPktLoops()
return
}
+func (s *Server) startMgmtServer(wg *sync.WaitGroup) {
+ defer logger.Debug("Management api server exited")
+
+ grpcAddressPort := s.gRPCAddress + ":" + strconv.Itoa(int(s.mgmtGrpcPort))
+ restAddressPort := s.gRPCAddress + ":" + strconv.Itoa(int(s.mgmtRestPort))
+ // Start rest gateway for BBSim server
+ go StartRestGatewayService(grpcAddressPort, restAddressPort, wg)
+ addressPort := s.gRPCAddress + ":" + strconv.Itoa(int(s.mgmtGrpcPort))
+
+ listener, apiserver, err := NewMgmtAPIServer(addressPort)
+ if err != nil {
+ logger.Error("Unable to create management api server %v", err)
+ return
+ }
+
+ s.mgmtServer = apiserver
+ pb.RegisterBBSimServiceServer(apiserver, s)
+ if e := apiserver.Serve(listener); e != nil {
+ logger.Error("Failed to run management api server %v", e)
+ return
+ }
+
+}
+
+func (s *Server) stopMgmtServer() error {
+ if s.mgmtServer != nil {
+ s.mgmtServer.GracefulStop()
+ logger.Debug("Management server stopped")
+ return nil
+ }
+ return errors.New("can not stop management server, server not created")
+}
+
// Enable invokes methods for activation of OLT and ONU (blocking)
func (s *Server) Enable(sv *openolt.Openolt_EnableIndicationServer) error {
olt := s.Olt
defer func() {
olt.Initialize()
- for intfid := range s.Onumap {
- for _, onu := range s.Onumap[intfid] {
- onu.Initialize()
- }
- }
+ // Below lines commented as we dont want to change the onu state on restart
+ // for intfid := range s.Onumap {
+ // for _, onu := range s.Onumap[intfid] {
+ // onu.Initialize()
+ // }
+ // }
s.updateDevIntState(olt, device.OLT_INACTIVE)
logger.Debug("Enable() Done")
}()
@@ -185,11 +272,29 @@
coreCtx := context.Background()
coreCtx, corecancel := context.WithCancel(coreCtx)
s.cancel = corecancel
- go s.sendDiscovertoONUs(*sv)
- if err := s.StartPktLoops(coreCtx, *sv); err != nil {
- return err
+ errorchan := make(chan error, 5)
+ go s.StartPktLoops(coreCtx, *sv, errorchan)
+
+ if s.AutoONUActivate == true {
+ // Initialize all ONUs
+ for intfid := range s.Onumap {
+ for _, onu := range s.Onumap[intfid] {
+ onu.Initialize()
+ }
+ }
+ // Activate all ONUs
+ s.activateONUs(*sv, s.Onumap)
}
+
+ select {
+ case err := <-errorchan:
+ if err != nil {
+ logger.Debug("Error: %v", err)
+ return err
+ }
+ }
+
return nil
}
@@ -224,10 +329,28 @@
s.updateDevIntState(onu, state)
return nil
}
-func (s *Server) Activate(onu *device.Onu) error {
- utils.LoggerWithOnu(onu).Info("sending ONUInd Onuid")
- go sendOnuIndtoONU(*s.EnableServer, onu)
- return nil
+
+func (s *Server) activateOnu(onu *device.Onu) {
+ snKey := stringifySerialNumber(onu.SerialNumber)
+ s.SNmap.Store(snKey, onu)
+ device.UpdateOnusOpStatus(onu.IntfID, onu, "up")
+
+ err := sendOnuDiscInd(*s.EnableServer, onu)
+ if err != nil {
+ logger.Error(err.Error())
+ return
+ }
+ logger.Info("OLT id:%d sent ONUDiscInd.", s.Olt.ID)
+ logger.Debug("activateONUs Entry in SNmap %v", snKey)
+}
+
+func (s *Server) activateONUs(stream openolt.Openolt_EnableIndicationServer, Onumap map[uint32][]*device.Onu) {
+ // Add all ONUs to SerialNumber Map
+ for intfid := range Onumap {
+ for _, onu := range Onumap[intfid] {
+ s.activateOnu(onu)
+ }
+ }
}
func (s *Server) activateOLT(stream openolt.Openolt_EnableIndicationServer) error {
@@ -249,37 +372,16 @@
logger.Info("OLT %s sent IntfInd.", olt.Name)
// OLT sends Operation Indication to Adapter after activating each interface
- //time.Sleep(IF_UP_TIME * time.Second)
if err := sendOperInd(stream, olt); err != nil {
logger.Error("Fail to sendOperInd: %v", err)
return err
}
logger.Info("OLT %s sent OperInd.", olt.Name)
-
return nil
}
-func (s *Server) sendDiscovertoONUs(stream openolt.Openolt_EnableIndicationServer) {
- // OLT sends ONU Discover Indication to Adapter after ONU discovery
- for intfid := range s.Onumap {
- device.UpdateOnusOpStatus(intfid, s.Onumap[intfid], "up")
- }
-
- // Initialize all ONUs
- for intfid := range s.Onumap {
- for _, onu := range s.Onumap[intfid] {
- onu.Initialize()
- }
- }
-
- // Send discovery indication for all ONUs
- for intfid, _ := range s.Onumap {
- sendOnuDiscInd(stream, s.Onumap[intfid], s.IndInterval)
- logger.Info("OLT sent ONUDiscInd for intfId:%d.", intfid)
- }
-}
// StartPktLoops creates veth pairs and invokes runPktLoops (blocking)
-func (s *Server) StartPktLoops(ctx context.Context, stream openolt.Openolt_EnableIndicationServer) error {
+func (s *Server) StartPktLoops(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, errorchan chan error) {
logger.Debug("StartPktLoops () Start")
defer func() {
RemoveVeths(s.Vethnames)
@@ -289,11 +391,14 @@
s.updateDevIntState(s.Olt, device.OLT_PREACTIVE)
logger.Debug("StartPktLoops () Done")
}()
+ s.alarmCh = make(chan *openolt.Indication, 10)
+ go startAlarmLoop(stream, s.alarmCh)
+ go s.startDeviceActionLoop()
s.wg.Add(1)
ioinfos, veths, err := createIoinfos(s.Olt.ID, s.Vethnames)
if err != nil {
logger.Error("createIoinfos failed: %v", err)
- return err
+ errorchan <- err
}
s.Ioinfos = ioinfos
s.Vethnames = veths
@@ -305,9 +410,9 @@
if err = s.runPktLoops(child, stream); err != nil {
logger.Error("runPktLoops failed: %v", err)
- return err
+ errorchan <- err
}
- return nil
+ errorchan <- nil
}
// StopPktLoops (non-blocking)
@@ -335,13 +440,13 @@
return ioinfos, Vethnames, nil
}
-//Blocking
+// Blocking
func (s *Server) runPktLoops(ctx context.Context, stream openolt.Openolt_EnableIndicationServer) error {
logger.Debug("runPacketPktLoops Start")
defer logger.Debug("runPacketLoops Done")
errchOmci := make(chan error)
- RunOmciResponder(ctx, s.omciOut, s.omciIn, errchOmci)
+ s.RunOmciResponder(ctx, s.omciOut, s.omciIn, errchOmci)
eg, child := errgroup.WithContext(ctx)
child, cancel := context.WithCancel(child)
@@ -356,7 +461,7 @@
defer logger.Debug("runOMCIResponder Done")
select {
case v, ok := <-errchOmci: // Wait for OmciInitialization
- if ok { //Error
+ if ok { // Error
logger.Error("Error happend in Omci: %s", v)
return v
}
@@ -371,7 +476,7 @@
defer logger.Debug("runEapolResponder Done")
select {
case v, ok := <-errchEapol:
- if ok { //Error
+ if ok { // Error
logger.Error("Error happend in Eapol:%s", v)
return v
}
@@ -386,7 +491,7 @@
defer logger.Debug("runDhcpResponder Done")
select {
case v, ok := <-errchDhcp:
- if ok { //Error
+ if ok { // Error
logger.Error("Error happend in Dhcp:%s", v)
return v
}
@@ -451,7 +556,7 @@
logger.Error("Fail to send EAPOL PktInd indication. %v", err)
return err
}
- case msg := <-s.dhcpIn: //TODO: We should put omciIn, eapolIn, dhcpIn toghether
+ case msg := <-s.dhcpIn: // TODO: We should put omciIn, eapolIn, dhcpIn toghether
intfid := msg.IntfId
onuid := msg.OnuId
gemid, err := s.getGemPortID(intfid, onuid)
@@ -468,7 +573,7 @@
logger.Error("Failed to GetOnuByID:%d", onuid)
continue
}
- sn := convB2S(onu.SerialNumber.VendorSpecific)
+ sn := utils.ConvB2S(onu.SerialNumber.VendorSpecific)
if ctag, ok := s.CtagMap[sn]; ok == true {
tagpkt, err := PushVLAN(pkt, uint16(ctag), onu)
if err != nil {
@@ -499,7 +604,12 @@
logger.Debug("WARNING: This packet does not come from NNI ")
continue
}
+
+ onuid := nnipkt.Info.onuid
intfid := nnipkt.Info.intfid
+ onu, _ := s.GetOnuByID(onuid, intfid)
+
+ utils.LoggerWithOnu(onu).Info("Received packet from NNI in grpc Server.")
pkt := nnipkt.Pkt
data = &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{IntfType: "nni", IntfId: intfid, Pkt: pkt.Data()}}
@@ -513,7 +623,6 @@
return nil
}
}
- return nil
}
func (s *Server) onuPacketOut(intfid uint32, onuid uint32, rawpkt gopacket.Packet) error {
@@ -622,7 +731,7 @@
}
}
}
- err := errors.New("No mathced SN is found ")
+ err := errors.New("no matching serial number found")
logger.Error("%s", err)
return nil, err
}
@@ -638,7 +747,7 @@
return onu, nil
}
}
- err := errors.New("No matched OnuID is found ")
+ err := errors.New("no matching OnuID found")
logger.WithFields(log.Fields{
"onumap": onumap,
"onuid": onuid,
@@ -647,10 +756,111 @@
return nil, err
}
-func convB2S(b []byte) string {
- s := ""
- for _, i := range b {
- s = s + strconv.FormatInt(int64(i/16), 16) + strconv.FormatInt(int64(i%16), 16)
+// getOnuFromSNmap method returns onu object from SNmap if found
+func (s *Server) getOnuFromSNmap(serialNumber *openolt.SerialNumber) (*device.Onu, bool) {
+ snkey := stringifySerialNumber(serialNumber)
+
+ logger.Debug("getOnuFromSNmap received serial number %s", snkey)
+
+ if onu, exist := s.SNmap.Load(snkey); exist {
+ logger.Info("Serial number found in map")
+ return onu.(*device.Onu), true
}
- return s
+ logger.Info("Serial number not found in map")
+ return nil, false
+}
+
+func stringifySerialNumber(serialNum *openolt.SerialNumber) string {
+ return string(serialNum.VendorId) + utils.ConvB2S(serialNum.VendorSpecific)
+}
+
+func getOpenoltSerialNumber(SerialNumber string) (*openolt.SerialNumber, error) {
+ if len(SerialNumber) != SerialNumberLength {
+ logger.Error("Invalid serial number %s", SerialNumber)
+ return nil, errors.New("invalid serial number")
+ }
+ // First four characters are vendorId
+ vendorID := SerialNumber[:VendorIDLength]
+ vendorSpecific := SerialNumber[VendorIDLength:]
+
+ vsbyte, _ := hex.DecodeString(vendorSpecific)
+
+ // Convert to Openolt serial number
+ serialNum := new(openolt.SerialNumber)
+ serialNum.VendorId = []byte(vendorID)
+ serialNum.VendorSpecific = vsbyte
+
+ return serialNum, nil
+}
+
+// TODO move to device_onu.go
+func (s *Server) sendOnuIndicationsOnOltReboot() {
+ if AutoONUActivate == 1 {
+ // For auto activate mode, onu indications is sent in Enable()
+ return
+ }
+
+ s.SNmap.Range(
+ func(key, value interface{}) bool {
+ onu := value.(*device.Onu)
+ if onu.InternalState == device.ONU_LOS_RAISED {
+ return true
+ }
+
+ err := sendOnuDiscInd(*s.EnableServer, onu)
+ if err != nil {
+ logger.Error(err.Error())
+ }
+
+ return true
+ })
+}
+
+// StartServerActionLoop reads on server-action channel, and starts and stops the server as per the value received
+func (s *Server) StartServerActionLoop(wg *sync.WaitGroup) {
+ for {
+ select {
+ case Req := <-s.serverActionCh:
+ logger.Debug("Request Received On serverActionCh: %+v", Req)
+ switch Req {
+ case "start":
+ logger.Debug("Server Start Request Received On ServerActionChannel")
+ go s.Start() // blocking
+ case "stop":
+ logger.Debug("Server Stop Request Received On ServerActionChannel")
+ s.Stop()
+ default:
+ logger.Error("Invalid value received in deviceActionCh")
+ }
+ }
+ }
+}
+
+// startDeviceActionLoop reads on the action-channel, and performs onu and olt reboot related actions
+// TODO all onu and olt related actions (like alarms) should be handled using this function
+func (s *Server) startDeviceActionLoop() {
+ logger.Debug("startDeviceActionLoop invoked")
+ s.deviceActionCh = make(chan *pb.DeviceAction, 10)
+ for {
+ logger.Debug("Action channel loop started")
+ select {
+ case Req := <-s.deviceActionCh:
+ logger.Debug("Reboot Action Type: %+v", Req.DeviceAction)
+ switch Req.DeviceType {
+ case DeviceTypeOnu:
+ value, _ := s.SNmap.Load(Req.DeviceSerialNumber)
+ onu := value.(*device.Onu)
+ if Req.DeviceAction == SoftReboot {
+ s.handleONUSoftReboot(onu.IntfID, onu.OnuID)
+ } else if Req.DeviceAction == HardReboot {
+ s.handleONUHardReboot(onu)
+ }
+ case DeviceTypeOlt:
+ logger.Debug("Reboot For OLT Received")
+ s.handleOLTReboot()
+ default:
+ logger.Error("Invalid value received in deviceActionCh")
+ }
+ }
+ }
}
diff --git a/core/dhcp.go b/core/dhcp.go
index 6aa5753..ae890ba 100644
--- a/core/dhcp.go
+++ b/core/dhcp.go
@@ -21,15 +21,17 @@
"encoding/hex"
"errors"
"fmt"
- "gerrit.opencord.org/voltha-bbsim/common/logger"
- "github.com/google/gopacket"
- "github.com/google/gopacket/layers"
"math/rand"
"net"
"reflect"
"sync"
+
+ "gerrit.opencord.org/voltha-bbsim/common/logger"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
)
+// Constants for DHCP states
const (
DHCP_INIT clientState = iota + 1
DHCP_SELECTING
@@ -78,6 +80,7 @@
layers.DHCPOptNTPServers,
}
+// RunDhcpResponder responds to the DHCP client messages
func RunDhcpResponder(ctx context.Context, dhcpOut chan *byteMsg, dhcpIn chan *byteMsg, errch chan error) {
responder := getDHCPResponder()
responder.dhcpIn = dhcpIn
@@ -310,7 +313,7 @@
// Send our packet
msg := byteMsg{IntfId: c.key.intfid,
OnuId: c.key.onuid,
- Byte: bytes}
+ Byte: bytes}
dhcpIn <- &msg
logger.Debug("sendBytes intfid:%d onuid:%d", c.key.intfid, c.key.onuid)
logger.Debug(hex.Dump(msg.Byte))
diff --git a/core/eapol.go b/core/eapol.go
index 85a9f07..cc9f24c 100644
--- a/core/eapol.go
+++ b/core/eapol.go
@@ -22,17 +22,19 @@
"encoding/hex"
"errors"
"fmt"
+ "net"
+ "sync"
+
"gerrit.opencord.org/voltha-bbsim/common/logger"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
- "net"
- "sync"
)
type clientState int
+// Constants for eapol states
const (
- EAP_START clientState = iota + 1 //TODO: This state definition should support 802.1X
+ EAP_START clientState = iota + 1 // TODO: This state definition should support 802.1X
EAP_RESPID
EAP_RESPCHA
EAP_SUCCESS
@@ -72,7 +74,7 @@
return resp
}
-//RunEapolResponder starts go routine which processes and responds for received eapol messages
+// RunEapolResponder starts go routine which processes and responds for received eapol messages
func RunEapolResponder(ctx context.Context, eapolOut chan *byteMsg, eapolIn chan *byteMsg, errch chan error) {
responder := getEAPResponder()
responder.eapolIn = eapolIn
@@ -82,7 +84,7 @@
defer logger.Debug("EAPOL response process was done")
for {
select {
- case msg := <- eapolOut:
+ case msg := <-eapolOut:
logger.Debug("Received eapol from eapolOut intfid:%d onuid:%d", msg.IntfId, msg.OnuId)
responder := getEAPResponder()
clients := responder.clients
@@ -136,7 +138,7 @@
return errors.New("Failed to send EAPStart")
}
logger.Debug("Sending EAPStart")
- //clients[key{intfid: intfid, onuid: onuid}] = &client
+ // clients[key{intfid: intfid, onuid: onuid}] = &client
resp.clients[clientKey{intfid: intfid, onuid: onuid}] = &client
return nil
}
@@ -254,10 +256,10 @@
return &eap
}
-func getMD5Data (id uint8, eap *layers.EAP) []byte {
+func getMD5Data(id uint8, eap *layers.EAP) []byte {
i := byte(id)
C := []byte(eap.BaseLayer.Contents)[6:]
- P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} //"password"
+ P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} // "password"
data := md5.Sum(append(P, C...))
ret := make([]byte, 16)
for j := 0; j < 16; j++ {
diff --git a/core/grpc_service.go b/core/grpc_service.go
index cb1ee95..2d216d8 100644
--- a/core/grpc_service.go
+++ b/core/grpc_service.go
@@ -22,7 +22,8 @@
"gerrit.opencord.org/voltha-bbsim/common/logger"
"gerrit.opencord.org/voltha-bbsim/common/utils"
"gerrit.opencord.org/voltha-bbsim/device"
- "gerrit.opencord.org/voltha-bbsim/protos"
+ flowHandler "gerrit.opencord.org/voltha-bbsim/flow"
+ openolt "gerrit.opencord.org/voltha-bbsim/protos"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
omci "github.com/opencord/omci-sim"
@@ -36,6 +37,12 @@
// DisableOlt method sends OLT down indication
func (s *Server) DisableOlt(c context.Context, empty *openolt.Empty) (*openolt.Empty, error) {
logger.Debug("OLT receives DisableOLT()")
+
+ err := flowHandler.PortDown(0)
+ if err != nil {
+ logger.Error("Failed in port down %v", err)
+ }
+
if s.EnableServer != nil {
if err := sendOltIndDown(*s.EnableServer); err != nil {
return new(openolt.Empty), err
@@ -48,6 +55,12 @@
// ReenableOlt method sends OLT up indication for re-enabling OLT
func (s *Server) ReenableOlt(c context.Context, empty *openolt.Empty) (*openolt.Empty, error) {
logger.Debug("OLT receives Reenable()")
+
+ err := flowHandler.PortUp(0)
+ if err != nil {
+ logger.Error("Failed in port up %v", err)
+ }
+
if s.EnableServer != nil {
if err := sendOltIndUp(*s.EnableServer, s.Olt); err != nil {
logger.Error("Failed to send OLT UP indication for reenable OLT: %v", err)
@@ -91,16 +104,19 @@
func (s *Server) ActivateOnu(c context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
logger.Debug("OLT receives ActivateONU()")
- matched, err := getOnuBySN(s.Onumap, onu.SerialNumber)
- if err != nil {
- logger.Fatal("%s", err)
+ matched, exist := s.getOnuFromSNmap(onu.SerialNumber)
+ if !exist {
+ logger.Fatal("ONU not found with serial nnumber %v", onu.SerialNumber)
return new(openolt.Empty), status.Errorf(codes.NotFound, "ONU not found with serial number %v", onu.SerialNumber)
}
onuid := onu.OnuId
matched.OnuID = onuid
s.updateDevIntState(matched, device.ONU_ACTIVE)
- s.Activate(matched)
logger.Debug("ONU IntfID: %d OnuID: %d activated succesufully.", onu.IntfId, onu.OnuId)
+ if err := sendOnuInd(*s.EnableServer, matched, s.IndInterval, "up", "up"); err != nil {
+ logger.Error("Failed to send ONU Indication intfID %d, onuID %d", matched.IntfID, matched.OnuID)
+ return new(openolt.Empty), err
+ }
return new(openolt.Empty), nil
}
@@ -125,7 +141,7 @@
// DeleteOnu handles ONU deletion request from VOLTHA
func (s *Server) DeleteOnu(c context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
- logger.Debug("OLT receives DeleteONU()")
+ logger.Debug("OLT receives DeleteONU() intfID: %d, onuID: %d", onu.IntfId, onu.OnuId)
Onu, err := s.GetOnuByID(onu.OnuId, onu.IntfId)
if err != nil {
return new(openolt.Empty), err
@@ -135,6 +151,12 @@
Onu.InternalState = device.ONU_FREE
Onu.OnuID = 0
+ // Get snMap key for the ONU serial number
+ snkey := stringifySerialNumber(Onu.SerialNumber)
+
+ // Delete Serial number entry from SNmap
+ logger.Info("Deleting serial number %s from SNmap", snkey)
+ s.SNmap.Delete(snkey)
return new(openolt.Empty), nil
}
@@ -150,8 +172,8 @@
state := onu.GetIntState()
logger.Debug("ONU-ID: %v, ONU state: %d", msg.OnuId, state)
- // If ONU is ONU_INACTIVE or ONU_FREE do not send omci response
- if state == device.ONU_INACTIVE || state == device.ONU_FREE {
+ // If ONU is ONU_INACTIVE, ONU_FREE or ONU_OMCI_CHANNEL_LOS_RAISED drop
+ if state != device.ONU_ACTIVE && state != device.ONU_OMCIACTIVE {
logger.Info("ONU (IF %v ONU-ID: %v) is not ACTIVE, so not processing OmciMsg", msg.IntfId, msg.OnuId)
return new(openolt.Empty), nil
}
@@ -187,12 +209,29 @@
// FlowAdd method should handle flows addition to datapath for OLT and ONU
func (s *Server) FlowAdd(c context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
- logger.Debug("OLT %d receives FlowAdd() IntfID:%d OnuID:%d EType:%x GemPortID:%d", s.Olt.ID, flow.AccessIntfId, flow.OnuId, flow.Classifier.EthType, flow.GemportId)
- onu, err := s.GetOnuByID(uint32(flow.OnuId), uint32(flow.AccessIntfId))
+ logger.Debug("OLT %d receives FlowAdd() %v", s.Olt.ID, flow)
+ // Check if flow already present
+ flowKey := FlowKey{
+ FlowID: flow.FlowId,
+ FlowDirection: flow.FlowType,
+ }
+ if _, exist := s.FlowMap[flowKey]; exist {
+ logger.Error("Flow already exists %v", flow)
+ return new(openolt.Empty), status.Errorf(codes.AlreadyExists, "Flow already exists")
+ }
+ // Send flow to flowHandler
+ err := flowHandler.AddFlow(flow)
+ if err != nil {
+ logger.Error("Error in pushing flow to datapath")
+ return new(openolt.Empty), err
+ }
+
+ // Update flowMap
+ s.FlowMap[flowKey] = flow
+
+ onu, err := s.GetOnuByID(uint32(flow.OnuId), uint32(flow.AccessIntfId))
if err == nil {
- intfid := onu.IntfID
- onuid := onu.OnuID
onu.GemportID = uint16(flow.GemportId)
utils.LoggerWithOnu(onu).WithFields(log.Fields{
@@ -200,14 +239,13 @@
"c_tag": flow.Action.IVid,
}).Debug("OLT receives FlowAdd().")
-
// EAPOL flow
if flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) {
omcistate := omci.GetOnuOmciState(onu.IntfID, onu.OnuID)
if omcistate != omci.DONE {
logger.Warn("FlowAdd() OMCI state %d is not \"DONE\"", omci.GetOnuOmciState(onu.OnuID, onu.IntfID))
}
- s.updateOnuIntState(intfid, onuid, device.ONU_OMCIACTIVE)
+ _ = s.updateOnuIntState(onu.IntfID, onu.OnuID, device.ONU_OMCIACTIVE)
}
// DHCP flow
@@ -219,23 +257,52 @@
if omcistate != omci.DONE {
logger.Warn("FlowAdd() OMCI state %d is not \"DONE\"", omci.GetOnuOmciState(onu.OnuID, onu.IntfID))
}
- s.updateOnuIntState(intfid, onuid, device.ONU_AUTHENTICATED)
+ _ = s.updateOnuIntState(onu.IntfID, onu.OnuID, device.ONU_AUTHENTICATED)
}
}
+ // Update flow ID in ONU object
+ onu.FlowIDs = append(onu.FlowIDs, flow.FlowId)
}
return new(openolt.Empty), nil
}
-// FlowRemove should handle flow deletion from datapath
+// FlowRemove handles flow deletion from datapath
func (s *Server) FlowRemove(c context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
- logger.Debug("OLT %d receives FlowRemove()", s.Olt.ID)
+ logger.Debug("OLT %d receives FlowRemove(): %v", s.Olt.ID, flow)
+
+ // Check if flow exists
+ flowKey := FlowKey{
+ FlowID: flow.FlowId,
+ FlowDirection: flow.FlowType,
+ }
+ if _, exist := s.FlowMap[flowKey]; !exist {
+ logger.Error("Flow %v not found", flow)
+ return new(openolt.Empty), status.Errorf(codes.NotFound, "Flow not found")
+ }
+
+ flow = s.FlowMap[flowKey]
+ // Send delete flow to flowHandler
+ err := flowHandler.DeleteFlow(flow)
+ if err != nil {
+ return new(openolt.Empty), err
+ }
+
onu, err := s.GetOnuByID(uint32(flow.OnuId), uint32(flow.AccessIntfId))
- if err == nil {
+ if err != nil {
+ logger.Warn("Failed flow remove %v", err)
+ } else {
+ // Delete flowID from onu
+ onu.DeleteFlowID(flow.FlowId)
utils.LoggerWithOnu(onu).WithFields(log.Fields{
"olt": s.Olt.ID,
"c_tag": flow.Action.IVid,
}).Debug("OLT receives FlowRemove().")
+ logger.Debug("Flows %v in ONU %d", onu.FlowIDs, onu.OnuID)
}
+
+ // Delete flow from flowMap
+ delete(s.FlowMap, flowKey)
+
return new(openolt.Empty), nil
}
@@ -261,7 +328,7 @@
logger.Debug("OLT %d receives Reboot ().", s.Olt.ID)
// Initialize OLT & Env
logger.Debug("Initialized by Reboot")
- s.Disable()
+ s.handleOLTReboot()
return new(openolt.Empty), nil
}
@@ -280,7 +347,7 @@
// NewGrpcServer starts openolt gRPC server
func NewGrpcServer(addrport string) (l net.Listener, g *grpc.Server, e error) {
- logger.Debug("Listening %s ...", addrport)
+ logger.Debug("OpenOLT gRPC server listening %s ...", addrport)
g = grpc.NewServer()
l, e = net.Listen("tcp", addrport)
return
diff --git a/core/io_info.go b/core/io_info.go
index e56d4b6..36eb67f 100644
--- a/core/io_info.go
+++ b/core/io_info.go
@@ -25,10 +25,11 @@
log "github.com/sirupsen/logrus"
)
+// Ioinfo represents the input/output
type Ioinfo struct {
Name string
- iotype string //nni or uni
- ioloc string //inside or outsode
+ iotype string // nni or uni
+ ioloc string // inside or outside
intfid uint32
onuid uint32
handler *pcap.Handle
@@ -45,6 +46,7 @@
return nil, err
}
+// IdentifyNniIoinfo returns matched ioinfo
func (s *Server) IdentifyNniIoinfo(ioloc string) (*Ioinfo, error) {
for _, ioinfo := range s.Ioinfos {
if ioinfo.iotype == "nni" && ioinfo.ioloc == ioloc {
@@ -56,6 +58,7 @@
return nil, err
}
+// CreateVethPairs creates veth pairs with given names
func CreateVethPairs(veth1 string, veth2 string) (err error) {
err = exec.Command("ip", "link", "add", veth1, "type", "veth", "peer", "name", veth2).Run()
if err != nil {
@@ -80,6 +83,7 @@
return
}
+// RemoveVeth deletes veth by given name
func RemoveVeth(name string) error {
err := exec.Command("ip", "link", "del", name).Run()
if err != nil {
@@ -89,6 +93,7 @@
return err
}
+// RemoveVeths deletes veth
func RemoveVeths(names []string) {
for _, name := range names {
RemoveVeth(name)
diff --git a/core/io_worker.go b/core/io_worker.go
index 0496b9c..c59b903 100644
--- a/core/io_worker.go
+++ b/core/io_worker.go
@@ -18,24 +18,23 @@
import (
"errors"
- "net"
- "strconv"
- "time"
-
"gerrit.opencord.org/voltha-bbsim/common/logger"
+ "gerrit.opencord.org/voltha-bbsim/common/utils"
+ "gerrit.opencord.org/voltha-bbsim/device"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
- "gerrit.opencord.org/voltha-bbsim/device"
- "gerrit.opencord.org/voltha-bbsim/common/utils"
+ "net"
+ "strconv"
)
+// RecvWorker receives the packet and forwards to the channel
func RecvWorker(io *Ioinfo, handler *pcap.Handle, r chan Packet) {
logger.Debug("recvWorker runs. handler: %v", *handler)
packetSource := gopacket.NewPacketSource(handler, handler.LinkType())
for packet := range packetSource.Packets() {
logger.Debug("recv packet from IF: %v ", *handler)
- //logger.Println(packet.Dump())
+ // logger.Println(packet.Dump())
pkt := Packet{}
pkt.Info = io
pkt.Pkt = packet
@@ -43,6 +42,7 @@
}
}
+// SendUni sends packet to UNI interface
func SendUni(handle *pcap.Handle, packet gopacket.Packet, onu *device.Onu) {
err := handle.WritePacketData(packet.Data())
if err != nil {
@@ -51,15 +51,17 @@
utils.LoggerWithOnu(onu).Debugf("Successfully send packet to UNI-IF: %v", *handle)
}
+// SendNni sends packaet to NNI interface
func SendNni(handle *pcap.Handle, packet gopacket.Packet) {
err := handle.WritePacketData(packet.Data())
if err != nil {
logger.Error("Error in send packet to NNI e:%s", err)
}
logger.Debug("send packet to NNI-IF: %v ", *handle)
- //logger.Println(packet.Dump())
+ // logger.Println(packet.Dump())
}
+// PopVLAN pops the vlan ans return packet
func PopVLAN(pkt gopacket.Packet) (gopacket.Packet, uint16, error) {
if layer := getDot1QLayer(pkt); layer != nil {
if eth := getEthernetLayer(pkt); eth != nil {
@@ -84,9 +86,10 @@
}
}
return pkt, 0, nil
- //return nil, 0, errors.New("failed to pop vlan")
+ // return nil, 0, errors.New("failed to pop vlan")
}
+// PushVLAN pushes the vlan header to the packet and returns tha packet
func PushVLAN(pkt gopacket.Packet, vid uint16, onu *device.Onu) (gopacket.Packet, error) {
if eth := getEthernetLayer(pkt); eth != nil {
ethernetLayer := &layers.Ethernet{
@@ -145,8 +148,8 @@
}
func makeNniName(oltid uint32) (upif string, dwif string) {
- upif = NNI_VETH_NORTH_PFX + strconv.Itoa(int(oltid))
- dwif = NNI_VETH_SOUTH_PFX + strconv.Itoa(int(oltid))
+ upif = NniVethNorthPfx + strconv.Itoa(int(oltid))
+ dwif = NniVethSouthPfx + strconv.Itoa(int(oltid))
return
}
@@ -170,13 +173,13 @@
func getVethHandler(vethname string) (*pcap.Handle, error) {
var (
- device string = vethname
- snapshot_len int32 = 1518
- promiscuous bool = false
- err error
- timeout time.Duration = pcap.BlockForever
+ device = vethname
+ snapshotLen int32 = 1518
+ promiscuous = false
+ err error
+ timeout = pcap.BlockForever
)
- handle, err := pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
+ handle, err := pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
if err != nil {
return nil, err
}
diff --git a/core/mediator.go b/core/mediator.go
index b1d098d..c4cdc21 100644
--- a/core/mediator.go
+++ b/core/mediator.go
@@ -18,17 +18,16 @@
import (
"flag"
- "fmt"
"os"
"os/signal"
+ "reflect"
"strconv"
"strings"
"sync"
"gerrit.opencord.org/voltha-bbsim/common/logger"
- log "github.com/sirupsen/logrus"
"gerrit.opencord.org/voltha-bbsim/device"
- "reflect"
+ log "github.com/sirupsen/logrus"
)
const (
@@ -37,21 +36,28 @@
BOTH
)
+// Store emulation mode
type Mode int
+// AutoONUActivate is flag for Auto ONU Add on/off.
+var AutoONUActivate int
+
type option struct {
- address string
- port uint32
- oltid uint32
- npon uint32
- nonus uint32
- aaawait int
- dhcpwait int
- dhcpservip string
- intvl int
- Mode Mode
- KafkaBroker string
- Debuglvl string
+ address string
+ port uint32
+ mgmtGrpcPort uint32
+ mgmtRestPort uint32
+ oltid uint32
+ npon uint32
+ nonus uint32
+ aaawait int
+ dhcpwait int
+ dhcpservip string
+ intvl int
+ interactiveOnuActivation bool
+ Mode Mode
+ KafkaBroker string
+ Debuglvl string
}
// GetOptions receives command line options and stores them in option structure
@@ -67,6 +73,9 @@
dhcpservip := flag.String("s", "182.21.0.128", "DHCP Server IP Address")
intvl := flag.Int("v", 1000, "Interval each Indication (ms)")
kafkaBroker := flag.String("k", "", "Kafka broker")
+ interactiveOnuActivation := flag.Bool("ia", false, "Enable interactive activation of ONUs")
+ mgmtGrpcPort := flag.Int("grpc", 50061, "BBSim API server gRPC port")
+ mgmtRestPort := flag.Int("rest", 50062, "BBSim API server REST port")
o.Mode = DEFAULT
debg := flag.String("d", "DEBUG", "Debug Level(TRACE DEBUG INFO WARN ERROR)")
flag.Parse()
@@ -83,10 +92,18 @@
o.dhcpwait = *dhcpwait
o.dhcpservip = *dhcpservip
o.intvl = *intvl
+ o.interactiveOnuActivation = *interactiveOnuActivation
o.KafkaBroker = *kafkaBroker
- o.address = (strings.Split(*addressport, ":")[0])
+ o.address = strings.Split(*addressport, ":")[0]
tmp, _ := strconv.Atoi(strings.Split(*addressport, ":")[1])
o.port = uint32(tmp)
+ o.mgmtGrpcPort = uint32(*mgmtGrpcPort)
+ o.mgmtRestPort = uint32(*mgmtRestPort)
+
+ if o.interactiveOnuActivation == true {
+ log.Info("Automatic ONU activation disabled: use BBSim API to activate ONUs")
+ }
+
return o
}
@@ -115,14 +132,11 @@
var wg sync.WaitGroup
opt := m.opt
server := NewCore(opt)
- wg.Add(1)
- go func() {
- if err := server.Start(); err != nil { //Blocking
- logger.Error("Start %s", err)
- }
- wg.Done()
- return
- }()
+ server.wg = &sync.WaitGroup{}
+ server.wg.Add(1)
+ go server.StartServerActionLoop(&wg)
+ server.serverActionCh <- "start"
+ go server.startMgmtServer(&wg)
tm := NewTestManager(opt)
m.server = server
@@ -140,15 +154,17 @@
}()
for sig := range c {
wg.Add(1)
- fmt.Println("SIGINT", sig)
+ logger.Debug("SIGINT %v", sig)
close(c)
- server.Stop() //Non-blocking
- tm.Stop() //Non-blocking
+ server.Stop() // Non-blocking
+ tm.Stop() // Non-blocking
+ server.stopMgmtServer()
+ server.wg.Done()
return
}
}()
wg.Wait()
- logger.Debug("Reach to the end line")
+ server.wg.Wait()
}
// Mediate method is invoked on OLT and ONU state change
@@ -158,7 +174,7 @@
next := sr.next
current := sr.current
dev := sr.device
- if reflect.TypeOf(dev) == reflect.TypeOf(&device.Olt{}){
+ if reflect.TypeOf(dev) == reflect.TypeOf(&device.Olt{}) {
logger.Debug("Received OLT Device %v Current: %d Next: %d", dev, current, next)
if err := transitOlt(current, next, m.testmanager, m.opt); err != nil {
logger.Error("%v", err)
@@ -173,19 +189,22 @@
}
}
-func transitOlt (current device.DeviceState, next device.DeviceState, tm *TestManager, o *option) error {
+func transitOlt(current device.DeviceState, next device.DeviceState, tm *TestManager, o *option) error {
logger.Debug("trnsitOlt called current:%d , next:%d", current, next)
if current == device.OLT_PREACTIVE && next == device.OLT_ACTIVE {
tm.Start()
nniup, _ := makeNniName(o.oltid)
activateDHCPServer(nniup, o.dhcpservip)
- } else if current == device.OLT_ACTIVE && next == device.OLT_PREACTIVE{
+ } else if current == device.OLT_ACTIVE && next == device.OLT_PREACTIVE {
tm.Stop()
+ } else if current == device.OLT_ACTIVE && next == device.OLT_INACTIVE {
+ // Reboot case
+ // TODO Point of discussion
}
return nil
}
-func transitOnu (key device.Devkey, current device.DeviceState, next device.DeviceState, tm *TestManager, o *option) error {
+func transitOnu(key device.Devkey, current device.DeviceState, next device.DeviceState, tm *TestManager, o *option) error {
logger.Debug("trnsitOnu called with key: %v, current: %d, next: %d", key, current, next)
if o.Mode == AAA || o.Mode == BOTH {
if current == device.ONU_ACTIVE && next == device.ONU_OMCIACTIVE {
@@ -200,7 +219,7 @@
}
}
- if o.Mode == BOTH{
+ if o.Mode == BOTH {
if current == device.ONU_OMCIACTIVE && next == device.ONU_AUTHENTICATED {
t := tm.CreateTester("DHCP", o, key, activateDHCPClient, o.dhcpwait)
if err := tm.StartTester(t); err != nil {
diff --git a/core/omci.go b/core/omci.go
index 711bbc7..a83c07a 100644
--- a/core/omci.go
+++ b/core/omci.go
@@ -18,14 +18,13 @@
import (
"context"
-
"gerrit.opencord.org/voltha-bbsim/common/logger"
- "gerrit.opencord.org/voltha-bbsim/protos"
+ openolt "gerrit.opencord.org/voltha-bbsim/protos"
omci "github.com/opencord/omci-sim"
)
// RunOmciResponder starts a go routine to process/respond to OMCI messages from VOLTHA
-func RunOmciResponder(ctx context.Context, omciOut chan openolt.OmciMsg, omciIn chan openolt.OmciIndication, errch chan error) {
+func (s *Server) RunOmciResponder(ctx context.Context, omciOut chan openolt.OmciMsg, omciIn chan openolt.OmciIndication, errch chan error) {
go func() {
defer logger.Debug("Omci response process was done")
@@ -34,14 +33,17 @@
for {
select {
case m := <-omciOut:
- resp_pkt, err := omci.OmciSim(m.IntfId, m.OnuId, HexDecode(m.Pkt))
+ respPkt, err := omci.OmciSim(m.IntfId, m.OnuId, HexDecode(m.Pkt))
switch err := err.(type) {
case nil:
// Success
resp.IntfId = m.IntfId
resp.OnuId = m.OnuId
- resp.Pkt = resp_pkt
+ resp.Pkt = respPkt
omciIn <- resp
+ s.handleOmciAction(resp.Pkt, resp.IntfId, resp.OnuId)
+
+
case *omci.OmciError:
// Error in processing omci message. Log and carry on.
logger.Debug("%s", err.Msg)
@@ -72,3 +74,17 @@
return p
}
+func (s *Server) handleOmciAction(pkt []byte, IntfID uint32, OnuID uint32) {
+ logger.Debug("handleOmciAction invoked")
+ MEClass := omci.OmciClass(uint16(pkt[5]) | uint16(pkt[4])<<8)
+ msgType := omci.OmciMsgType(pkt[2] & 0x1F)
+ logger.Debug("ME Class %d, msgType %d", MEClass, msgType)
+
+ if MEClass == omci.ONUG {
+ switch msgType {
+ case omci.Reboot:
+ logger.Info("ONU reboot recieved")
+ s.handleONUSoftReboot(IntfID, OnuID)
+ }
+ }
+}
diff --git a/core/openolt_service.go b/core/openolt_service.go
index c34468a..dc48577 100644
--- a/core/openolt_service.go
+++ b/core/openolt_service.go
@@ -17,11 +17,12 @@
package core
import (
+ "time"
+
"gerrit.opencord.org/voltha-bbsim/common/logger"
"gerrit.opencord.org/voltha-bbsim/common/utils"
"gerrit.opencord.org/voltha-bbsim/device"
- "gerrit.opencord.org/voltha-bbsim/protos"
- "time"
+ openolt "gerrit.opencord.org/voltha-bbsim/protos"
)
func sendOltIndUp(stream openolt.Openolt_EnableIndicationServer, olt *device.Olt) error {
@@ -43,65 +44,95 @@
}
func sendIntfInd(stream openolt.Openolt_EnableIndicationServer, olt *device.Olt) error {
- for i := uint32(0); i < olt.NumPonIntf+olt.NumNniIntf; i++ {
- intf := olt.Intfs[i]
- if intf.Type == "pon" { // There is no need to send IntfInd for NNI
- data := &openolt.Indication_IntfInd{&openolt.IntfIndication{IntfId: intf.IntfID, OperState: intf.OperState}}
- if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
- logger.Error("Failed to send Intf [id: %d] indication : %v", i, err)
- return err
- }
- logger.Info("SendIntfInd olt:%d intf:%d (%s)", olt.ID, intf.IntfID, intf.Type)
+ // There is no need to send IntfInd for NNI
+ for i := uint32(0); i < olt.NumPonIntf; i++ {
+ intf := olt.PonIntfs[i]
+ data := &openolt.Indication_IntfInd{&openolt.IntfIndication{IntfId: intf.IntfID, OperState: intf.OperState}}
+ if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+ logger.Error("Failed to send Intf [id: %d] indication : %v", i, err)
+ return err
}
+ logger.Info("SendIntfInd olt:%d intf:%d (%s)", olt.ID, intf.IntfID, intf.Type)
}
return nil
}
func sendOperInd(stream openolt.Openolt_EnableIndicationServer, olt *device.Olt) error {
- for i := uint32(0); i < olt.NumPonIntf+olt.NumNniIntf; i++ {
- intf := olt.Intfs[i]
+ // Send OperInd for Nni
+ for i := uint32(0); i < olt.NumNniIntf; i++ {
+ intf := olt.NniIntfs[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 {
- logger.Error("Failed to send IntfOper [id: %d] indication : %v", i, err)
+ logger.Error("Failed to send NNI IntfOper [id: %d] indication : %v", i, err)
return err
}
- logger.Info("SendOperInd olt:%d intf:%d (%s)", olt.ID, intf.IntfID, intf.Type)
+ logger.Info("SendOperInd NNI olt:%d intf:%d (%s)", olt.ID, intf.IntfID, intf.Type)
}
- return nil
-}
-func sendOnuDiscInd(stream openolt.Openolt_EnableIndicationServer, onus []*device.Onu, delay int) error {
- for i, onu := range onus {
- data := &openolt.Indication_OnuDiscInd{&openolt.OnuDiscIndication{IntfId: onu.IntfID, SerialNumber: onu.SerialNumber}}
- time.Sleep(time.Duration(delay) * time.Millisecond)
+ // Send OperInd for Pon
+ for i := uint32(0); i < olt.NumPonIntf; i++ {
+ intf := olt.PonIntfs[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 {
- logger.Error("Failed to send ONUDiscInd [id: %d]: %v", i, err)
+ logger.Error("Failed to send PON IntfOper [id: %d] indication : %v", i, err)
return err
}
- utils.LoggerWithOnu(onu).Info("sendONUDiscInd Onuid")
+ logger.Info("SendOperInd PON olt:%d intf:%d (%s)", olt.ID, intf.IntfID, intf.Type)
}
return nil
}
-func sendOnuInd(stream openolt.Openolt_EnableIndicationServer, onus []*device.Onu, delay int) error {
- for i, onu := range onus {
-// time.Sleep(time.Duration(delay) * time.Millisecond)
- data := &openolt.Indication_OnuInd{&openolt.OnuIndication{IntfId: onu.IntfID, OnuId: onu.OnuID, OperState: "up", AdminState: "up", SerialNumber: onu.SerialNumber}}
- if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
- logger.Error("Failed to send ONUInd [id: %d]: %v", i, err)
- return err
- }
- utils.LoggerWithOnu(onu).Info("sendONUInd Onuid")
- }
- return nil
-}
-
-func sendOnuIndtoONU(stream openolt.Openolt_EnableIndicationServer, onu *device.Onu ) {
- time.Sleep(time.Duration(10000) * time.Millisecond) //TODO:This sleep added because of a known race condition in VOLTHA. Can be removed after fix.
- data := &openolt.Indication_OnuInd{&openolt.OnuIndication{IntfId: onu.IntfID, OnuId: onu.OnuID, OperState: "up", AdminState: "up", SerialNumber: onu.SerialNumber}}
+func sendOnuDiscInd(stream openolt.Openolt_EnableIndicationServer, onu *device.Onu) error {
+ data := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{IntfId: onu.IntfID, SerialNumber: onu.SerialNumber}}
if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
- logger.Error("Failed to send ONUInd [id: %d]: %v", onu.OnuID, err)
+ logger.Error("Failed to send ONUDiscInd [id: %d]: %v", onu.OnuID, err)
+ return err
+ }
+ utils.LoggerWithOnu(onu).Info("sendONUDiscInd Onuid")
+ return nil
+}
+
+func sendOnuInd(stream openolt.Openolt_EnableIndicationServer, onu *device.Onu, delay int, operState string, adminState string) error {
+ time.Sleep(time.Duration(delay) * time.Millisecond)
+ data := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
+ IntfId: onu.IntfID,
+ OnuId: onu.OnuID,
+ OperState: operState,
+ AdminState: adminState,
+ SerialNumber: onu.SerialNumber,
+ }}
+ if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+ logger.Error("Failed to send ONUInd [id: %d]: %v", onu.OnuID, err)
+ return err
}
utils.LoggerWithOnu(onu).Info("sendONUInd Onuid")
+ return nil
+}
+func sendDyingGaspInd(stream openolt.Openolt_EnableIndicationServer, intfID uint32, onuID uint32) error {
+ // Form DyingGasp Indication with ONU-ID and Intf-ID
+ alarmData := &openolt.AlarmIndication_DyingGaspInd{DyingGaspInd: &openolt.DyingGaspIndication{IntfId: intfID, OnuId: onuID, Status: "on"}}
+ data := &openolt.Indication_AlarmInd{AlarmInd: &openolt.AlarmIndication{Data: alarmData}}
+
+ // Send Indication to VOLTHA
+ if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+ logger.Error("Failed to send DyingGaspInd : %v", err)
+ return err
+ }
+ logger.Info("sendDyingGaspInd Intf-ID:%d ONU-ID:%d", intfID, onuID)
+ return nil
+}
+
+func startAlarmLoop(stream openolt.Openolt_EnableIndicationServer, alarmchan chan *openolt.Indication) {
+ logger.Debug("SendAlarm() Invoked")
+ for {
+ select {
+ case ind := <-alarmchan:
+ logger.Debug("Alarm recieved at alarm-channel to send to voltha %+v", ind)
+ err := stream.Send(ind)
+ if err != nil {
+ logger.Debug("Error occured while sending alarm indication %v", err)
+ }
+ }
+ }
}
diff --git a/core/tester.go b/core/tester.go
index 4d1118e..fe2aa39 100644
--- a/core/tester.go
+++ b/core/tester.go
@@ -18,14 +18,16 @@
import (
"context"
- "os/exec"
- "gerrit.opencord.org/voltha-bbsim/common/logger"
- "time"
- "strconv"
- "gerrit.opencord.org/voltha-bbsim/device"
"fmt"
+ "os/exec"
+ "strconv"
+ "time"
+
+ "gerrit.opencord.org/voltha-bbsim/common/logger"
+ "gerrit.opencord.org/voltha-bbsim/device"
)
+// TestManager is the structure for test manager
type TestManager struct {
DhcpServerIP string
Pid []int
@@ -34,22 +36,25 @@
cancel context.CancelFunc
}
+// Tester is the structure for Test
type Tester struct {
- Type string
- Key device.Devkey
+ Type string
+ Key device.Devkey
Testfunc func(device.Devkey) error
Waitsec int
- ctx context.Context
- cancel context.CancelFunc
+ ctx context.Context
+ cancel context.CancelFunc
}
+// NewTestManager returns new TestManager
func NewTestManager(opt *option) *TestManager {
t := new(TestManager)
t.DhcpServerIP = opt.dhcpservip
return t
}
-func (*TestManager) CreateTester(testtype string, opt *option, key device.Devkey, fn func(device.Devkey) error, waitsec int) *Tester{
+// CreateTester creates instance of Tester
+func (*TestManager) CreateTester(testtype string, opt *option, key device.Devkey, fn func(device.Devkey) error, waitsec int) *Tester {
logger.Debug("CreateTester() called")
t := new(Tester)
t.Type = testtype
@@ -59,7 +64,7 @@
return t
}
-//Blocking
+// Start does starting action - Blocking Call
func (tm *TestManager) Start() error {
ctx, cancel := context.WithCancel(context.Background())
tm.ctx = ctx
@@ -71,6 +76,7 @@
return nil
}
+// Stop does stopping action
func (tm *TestManager) Stop() error {
if tm.cancel != nil {
tm.cancel()
@@ -80,7 +86,7 @@
return nil
}
-func (tm *TestManager) StartTester (t *Tester) error {
+func (tm *TestManager) StartTester(t *Tester) error {
testtype := t.Type
key := t.Key
waitsec := t.Waitsec
@@ -99,10 +105,10 @@
L:
for counter < waitsec {
- select{
+ select {
case <-tick.C:
- counter ++
- if counter == waitsec { // TODO: This should be fixed
+ counter++
+ if counter == waitsec { // TODO: This should be fixed
break L
}
case <-child.Done():
@@ -120,22 +126,25 @@
return nil
}
-func (tm *TestManager) StopTester (testtype string, key device.Devkey) error {
+// StopTester stops the test
+func (tm *TestManager) StopTester(testtype string, key device.Devkey) error {
ts := tm.testers[testtype][key]
ts.cancel()
delete(tm.testers[testtype], key)
return nil
}
+// Initialize test manager
func (tm *TestManager) Initialize() {
logger.Info("TestManager Initialize () called")
pids := tm.Pid
logger.Debug("Runnig Process: %v", pids)
KillProcesses(pids)
- exec.Command("rm", "/var/run/dhcpd.pid").Run() //This is for DHCP server activation
- exec.Command("touch", "/var/run/dhcpd.pid").Run() //This is for DHCP server activation
+ exec.Command("rm", "/var/run/dhcpd.pid").Run() // This is for DHCP server activation
+ exec.Command("touch", "/var/run/dhcpd.pid").Run() // This is for DHCP server activation
}
+// KillProcesses kill process by specified pid
func KillProcesses(pids []int) error {
for _, pname := range pids {
killProcess(pname)
@@ -170,7 +179,7 @@
return nil
}
-func activateDHCPServer (veth string, serverip string) error {
+func activateDHCPServer(veth string, serverip string) error {
err := exec.Command("ip", "addr", "add", serverip, "dev", veth).Run()
if err != nil {
logger.Error("Fail to add ip to %s address: %s", veth, err)
@@ -191,4 +200,4 @@
}
logger.Info("DHCP Server is successfully activated !")
return err
-}
\ No newline at end of file
+}
diff --git a/device/device_olt.go b/device/device_olt.go
index daffcec..5f34a03 100644
--- a/device/device_olt.go
+++ b/device/device_olt.go
@@ -31,8 +31,9 @@
GetDevkey() Devkey
}
+// Devkey key for OLT/ONU devices
type Devkey struct {
- ID uint32
+ ID uint32
Intfid uint32
}
@@ -47,30 +48,68 @@
Name string
InternalState DeviceState
OperState string
- Intfs []intf
+ NniIntfs []nniIntf
+ PonIntfs []ponIntf
HeartbeatSignature uint32
- mu *sync.Mutex
+ mu *sync.Mutex
}
-type intf struct {
- Type string
- IntfID uint32
- OperState string
+// AlarmState informs about the present state of the supported alarms
+type AlarmState uint32
+
+const (
+ // PonLosCleared alarm state for PON-LOS
+ PonLosCleared AlarmState = iota
+ // NniLosCleared alarm state for NNI-LOS
+ NniLosCleared
+ // PonLosRaised alarm state for PON-LOS
+ PonLosRaised
+ // NniLosRaised for NNI-LOS
+ NniLosRaised
+)
+
+type ponIntf struct {
+ Type string
+ IntfID uint32
+ OperState string
+ AlarmState AlarmState
}
+type nniIntf struct {
+ Type string
+ IntfID uint32
+ OperState string
+ AlarmState AlarmState
+}
+
+// Constants for port types
+const (
+ IntfPon = "pon"
+ IntfNni = "nni"
+)
+
/* OltState
OLT_INACTIVE -> OLT_PREACTIVE -> ACTIVE
- (ActivateOLT) (Enable)
+ (ActivateOLT) (Enable)
<- <-
*/
+// Constants for OLT states
const (
- OLT_INACTIVE DeviceState = iota // OLT/ONUs are not instantiated
- OLT_PREACTIVE // Before PacketInDaemon Running
- OLT_ACTIVE // After PacketInDaemon Running
+ OLT_INACTIVE DeviceState = iota // OLT/ONUs are not instantiated
+ OLT_PREACTIVE // Before PacketInDaemon Running
+ OLT_ACTIVE // After PacketInDaemon Running
)
-// NewOlt creates and return new Olt object
+// OLTAlarmStateToString is used to get alarm state as string
+var OLTAlarmStateToString = map[AlarmState]string{
+ PonLosCleared: "PonLosCleared",
+ NniLosCleared: "NniLosCleared",
+ PonLosRaised: "PonLosRaised",
+ NniLosRaised: "NniLosRaised",
+}
+
+// NewOlt initialises the new olt variable with the given values
func NewOlt(oltid uint32, npon uint32, nnni uint32) *Olt {
olt := Olt{}
olt.ID = oltid
@@ -81,18 +120,21 @@
olt.OperState = "up"
olt.Manufacture = "BBSIM"
olt.SerialNumber = "BBSIMOLT00" + strconv.FormatInt(int64(oltid), 10)
- olt.Intfs = make([]intf, olt.NumPonIntf+olt.NumNniIntf)
+ olt.NniIntfs = make([]nniIntf, olt.NumNniIntf)
+ olt.PonIntfs = make([]ponIntf, olt.NumPonIntf)
olt.HeartbeatSignature = oltid
olt.mu = &sync.Mutex{}
for i := uint32(0); i < olt.NumNniIntf; i++ {
- olt.Intfs[i].IntfID = i
- olt.Intfs[i].OperState = "up"
- olt.Intfs[i].Type = "nni"
+ olt.NniIntfs[i].IntfID = i
+ olt.NniIntfs[i].OperState = "up"
+ olt.NniIntfs[i].Type = IntfNni
+ olt.NniIntfs[i].AlarmState = NniLosCleared
}
- 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"
+ for i := uint32(0); i < olt.NumPonIntf; i++ {
+ olt.PonIntfs[i].IntfID = i
+ olt.PonIntfs[i].OperState = "up"
+ olt.PonIntfs[i].Type = IntfPon
+ olt.PonIntfs[i].AlarmState = PonLosCleared
}
return &olt
}
@@ -102,14 +144,16 @@
olt.InternalState = OLT_INACTIVE
olt.OperState = "up"
for i := uint32(0); i < olt.NumNniIntf; i++ {
- olt.Intfs[i].IntfID = i
- olt.Intfs[i].OperState = "up"
- olt.Intfs[i].Type = "nni"
+ olt.NniIntfs[i].IntfID = i
+ olt.NniIntfs[i].OperState = "up"
+ olt.NniIntfs[i].Type = IntfNni
+ olt.NniIntfs[i].AlarmState = NniLosCleared
}
- 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"
+ for i := uint32(olt.NumNniIntf); i < olt.NumPonIntf; i++ {
+ olt.PonIntfs[i].IntfID = i
+ olt.PonIntfs[i].OperState = "up"
+ olt.PonIntfs[i].Type = IntfPon
+ olt.PonIntfs[i].AlarmState = PonLosCleared
}
}
@@ -121,7 +165,7 @@
}
// GetDevkey returns device key of OLT
-func (olt *Olt) GetDevkey () Devkey {
+func (olt *Olt) GetDevkey() Devkey {
return Devkey{ID: olt.ID}
}
@@ -130,4 +174,16 @@
olt.mu.Lock()
defer olt.mu.Unlock()
olt.InternalState = intstate
+}
+
+// UpdateNniPortState updates the status of the nni-port
+func (olt *Olt) UpdateNniPortState(portID uint32, alarmState AlarmState, operState string) {
+ olt.NniIntfs[portID].AlarmState = alarmState
+ olt.NniIntfs[portID].OperState = operState
+}
+
+// UpdatePonPortState updates the status of the pon-port
+func (olt *Olt) UpdatePonPortState(portID uint32, alarmState AlarmState, operState string) {
+ olt.PonIntfs[portID].AlarmState = alarmState
+ olt.PonIntfs[portID].OperState = operState
}
\ No newline at end of file
diff --git a/device/device_onu.go b/device/device_onu.go
index f2338d7..0add821 100644
--- a/device/device_onu.go
+++ b/device/device_onu.go
@@ -21,18 +21,33 @@
"sync"
"gerrit.opencord.org/voltha-bbsim/common/logger"
- "gerrit.opencord.org/voltha-bbsim/protos"
+ openolt "gerrit.opencord.org/voltha-bbsim/protos"
log "github.com/sirupsen/logrus"
)
+// Constants for the ONU states
const (
- ONU_INACTIVE DeviceState = iota //TODO: Each stage name should be more accurate
+ ONU_INACTIVE DeviceState = iota // TODO: Each stage name should be more accurate
ONU_ACTIVE
ONU_OMCIACTIVE
ONU_AUTHENTICATED
+ ONU_LOS_RAISED
+ ONU_OMCI_CHANNEL_LOS_RAISED
+ ONU_LOS_ON_OLT_PON_LOS // TODO give more suitable and crisp name
ONU_FREE
)
+// ONUState maps int value of device state to string
+var ONUState = map[DeviceState]string{
+ ONU_INACTIVE: "ONU_INACTIVE",
+ ONU_ACTIVE: "ONU_ACTIVE",
+ ONU_OMCIACTIVE: "ONU_OMCIACTIVE",
+ ONU_FREE: "ONU_FREE",
+ ONU_LOS_RAISED: "ONU_LOS_RAISED",
+ ONU_OMCI_CHANNEL_LOS_RAISED: "ONU_OMCI_CHANNEL_LOS_RAISED",
+ ONU_LOS_ON_OLT_PON_LOS: "ONU_LOS_ON_OLT_PON_LOS",
+}
+
// Onu structure stores information of ONUs
type Onu struct {
InternalState DeviceState
@@ -42,6 +57,7 @@
SerialNumber *openolt.SerialNumber
OnuID uint32
GemportID uint16
+ FlowIDs []uint32
mu *sync.Mutex
}
@@ -54,9 +70,9 @@
// NewOnus initializes and returns slice of Onu objects
func NewOnus(oltid uint32, intfid uint32, nonus uint32, nnni uint32) []*Onu {
onus := []*Onu{}
- for i := 0; i < int(nonus); i++ {
+ for i := 1; i <= int(nonus); i++ {
onu := Onu{}
- onu.InternalState = ONU_FREE
+ onu.InternalState = ONU_FREE // New Onu Initialised with state ONU_FREE
onu.mu = &sync.Mutex{}
onu.IntfID = intfid
onu.OltID = oltid
@@ -94,14 +110,12 @@
}
// UpdateOnusOpStatus method updates ONU oper status
-func UpdateOnusOpStatus(ponif uint32, onus []*Onu, opstatus string) {
- for _, onu := range onus {
- onu.OperState = opstatus
- logger.WithFields(log.Fields{
- "onu": onu.SerialNumber,
- "pon_interface": ponif,
- }).Info("ONU discovered.")
- }
+func UpdateOnusOpStatus(ponif uint32, onu *Onu, opstatus string) {
+ onu.OperState = opstatus
+ logger.WithFields(log.Fields{
+ "onu": onu.SerialNumber,
+ "pon_interface": ponif,
+ }).Info("ONU OperState Updated")
}
// UpdateIntState method updates ONU internal state
@@ -112,8 +126,8 @@
}
// GetDevkey returns ONU device key
-func (onu *Onu) GetDevkey () Devkey {
- return Devkey{ID: onu.OnuID, Intfid:onu.IntfID}
+func (onu *Onu) GetDevkey() Devkey {
+ return Devkey{ID: onu.OnuID, Intfid: onu.IntfID}
}
// GetIntState returns ONU internal state
@@ -122,3 +136,17 @@
defer onu.mu.Unlock()
return onu.InternalState
}
+
+// DeleteFlowID method search and delete flowID from the onu flowIDs slice
+func (onu *Onu) DeleteFlowID(flowID uint32) {
+ for pos, id := range onu.FlowIDs {
+ if id == flowID {
+ // delete the flowID by shifting all flowIDs by one
+ onu.FlowIDs = append(onu.FlowIDs[:pos], onu.FlowIDs[pos+1:]...)
+ t := make([]uint32, len(onu.FlowIDs))
+ copy(t, onu.FlowIDs)
+ onu.FlowIDs = t
+ break
+ }
+ }
+}
diff --git a/flow/flow.go b/flow/flow.go
new file mode 100644
index 0000000..f32e048
--- /dev/null
+++ b/flow/flow.go
@@ -0,0 +1,100 @@
+/*
+ * 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 flow
+
+import (
+ "gerrit.opencord.org/voltha-bbsim/common/logger"
+ openolt "gerrit.opencord.org/voltha-bbsim/protos"
+)
+
+var flowManager FlowManager
+
+// FlowManager interface for common methods of controller
+type FlowManager interface {
+ AddFlow(flow *openolt.Flow) error
+ DeleteFlow(flow *openolt.Flow) error
+ PortUp(portID uint32) error
+ PortDown(portID uint32) error
+ GetFlow(onuID uint32) ([]*openolt.Flow, error)
+}
+
+// DefaultFlowController empty struct
+type DefaultFlowController struct {
+}
+
+// InitializeFlowManager starts godc controller
+func InitializeFlowManager(OltID uint32) {
+ // Initialize flow controller as per custom implementation
+ logger.Debug("InitializeFlowManager for OLT %d", OltID)
+ flowManager = InitializeDefaultFlowController()
+ return
+}
+
+// AddFlow abstracts actual implementation of flow addition
+func AddFlow(flow *openolt.Flow) error {
+ return flowManager.AddFlow(flow)
+}
+
+// DeleteFlow abstracts actual implementation of flow deletion
+func DeleteFlow(flow *openolt.Flow) error {
+ return flowManager.DeleteFlow(flow)
+}
+
+// PortUp abstracts actual implementation of port up
+func PortUp(portID uint32) error {
+ return flowManager.PortUp(portID)
+}
+
+// PortDown abstracts actual implementation of port down
+func PortDown(portID uint32) error {
+ return flowManager.PortDown(portID)
+}
+
+// InitializeDefaultFlowController method to initialize default controller
+func InitializeDefaultFlowController() FlowManager {
+ logger.Debug("Default controller initialized")
+ return new(DefaultFlowController)
+}
+
+// AddFlow method implemented for DefaultFlowController
+func (fc *DefaultFlowController) AddFlow(flow *openolt.Flow) error {
+ logger.Debug("AddFlow invoked %v", flow)
+ return nil
+}
+
+// DeleteFlow implemented for DefaultFlowController
+func (fc *DefaultFlowController) DeleteFlow(flow *openolt.Flow) error {
+ logger.Debug("DeleteFlow invoked %v", flow)
+ return nil
+}
+
+// GetFlow implemented for DefaultFlowController
+func (fc *DefaultFlowController) GetFlow(onuID uint32) ([]*openolt.Flow, error) {
+ return nil, nil
+}
+
+// PortUp implemented for DefaultFlowController
+func (fc *DefaultFlowController) PortUp(portID uint32) error {
+ logger.Debug("PortUp invoked %d", portID)
+ return nil
+}
+
+// PortDown implemented for DefaultFlowController
+func (fc *DefaultFlowController) PortDown(portID uint32) error {
+ logger.Debug("PortDown invoked %d", portID)
+ return nil
+}