blob: 20837b59d280dd56e8ee6930035e97d8f108ec5b [file] [log] [blame]
/*
* Portions copyright 2019-present Open Networking Foundation
* Original copyright 2019-present Ciena Corporation
*
* 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 commands
import (
"context"
"fmt"
"os"
"strconv"
"strings"
"github.com/jessevdk/go-flags"
"github.com/olekukonko/tablewriter"
pb "github.com/opencord/bbsim/api/bbsim"
"github.com/opencord/bbsim/internal/bbsimctl/config"
"github.com/opencord/cordctl/pkg/format"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
)
const (
DEFAULT_ONU_DEVICE_HEADER_FORMAT = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}"
DEFAULT_ONU_DEVICE_HEADER_FORMAT_WITH_SERVICES = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .Services }}"
)
type OnuSnString string
type IgmpSubAction string
const IgmpJoinKey string = "join"
const IgmpLeaveKey string = "leave"
const IgmpJoinKeyV3 string = "joinv3"
type ONUList struct {
Verbose bool `short:"v" long:"verbose" description:"Print all the informations we have about ONUs"`
}
type ONUGet struct {
Verbose bool `short:"v" long:"verbose" description:"Print all the informations we have about ONUs"`
Args struct {
OnuSn OnuSnString
} `positional-args:"yes" required:"yes"`
}
type ONUServices struct {
Args struct {
OnuSn OnuSnString
} `positional-args:"yes" required:"yes"`
}
type ONUShutDown struct {
Args struct {
OnuSn OnuSnString
} `positional-args:"yes" required:"yes"`
}
type ONUPowerOn struct {
Args struct {
OnuSn OnuSnString
} `positional-args:"yes" required:"yes"`
}
type ONUEapolRestart struct {
Args struct {
OnuSn OnuSnString
} `positional-args:"yes" required:"yes"`
}
type ONUDhcpRestart struct {
Args struct {
OnuSn OnuSnString
} `positional-args:"yes" required:"yes"`
}
type ONUIgmp struct {
Args struct {
OnuSn OnuSnString
SubAction IgmpSubAction
} `positional-args:"yes" required:"yes"`
}
type ONUTrafficSchedulers struct {
Args struct {
OnuSn OnuSnString
} `positional-args:"yes" required:"yes"`
}
type ONUFlows struct {
Args struct {
OnuSn OnuSnString
} `positional-args:"yes" required:"yes"`
}
type ONUOptions struct {
List ONUList `command:"list"`
Get ONUGet `command:"get"`
Services ONUServices `command:"services"`
ShutDown ONUShutDown `command:"shutdown"`
PowerOn ONUPowerOn `command:"poweron"`
RestartEapol ONUEapolRestart `command:"auth_restart"`
RestartDchp ONUDhcpRestart `command:"dhcp_restart"`
Igmp ONUIgmp `command:"igmp"`
TrafficSchedulers ONUTrafficSchedulers `command:"traffic_schedulers"`
Alarms AlarmOptions `command:"alarms"`
Flows ONUFlows `command:"flows"`
}
func RegisterONUCommands(parser *flags.Parser) {
_, _ = parser.AddCommand("onu", "ONU Commands", "Commands to query and manipulate ONU devices", &ONUOptions{})
}
func connect() (pb.BBSimClient, *grpc.ClientConn) {
conn, err := grpc.Dial(config.GlobalConfig.Server, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
return nil, conn
}
return pb.NewBBSimClient(conn), conn
}
func getONUs() *pb.ONUs {
client, conn := connect()
defer conn.Close()
// Contact the server and print out its response.
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
onus, err := client.GetONUs(ctx, &pb.Empty{})
if err != nil {
log.Fatalf("could not get OLT: %v", err)
return nil
}
return onus
}
func (options *ONUList) Execute(args []string) error {
onus := getONUs()
// print out
var tableFormat format.Format
if options.Verbose {
tableFormat = format.Format(DEFAULT_ONU_DEVICE_HEADER_FORMAT_WITH_SERVICES)
} else {
tableFormat = format.Format(DEFAULT_ONU_DEVICE_HEADER_FORMAT)
}
if err := tableFormat.Execute(os.Stdout, true, onus.Items); err != nil {
log.Fatalf("Error while formatting ONUs table: %s", err)
}
return nil
}
func (options *ONUGet) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
res, err := client.GetONU(ctx, &req)
if err != nil {
log.Fatalf("Cannot not get ONU %s: %v", options.Args.OnuSn, err)
return err
}
var tableFormat format.Format
if options.Verbose {
tableFormat = format.Format(DEFAULT_ONU_DEVICE_HEADER_FORMAT_WITH_SERVICES)
} else {
tableFormat = format.Format(DEFAULT_ONU_DEVICE_HEADER_FORMAT)
}
if err := tableFormat.Execute(os.Stdout, true, []*pb.ONU{res}); err != nil {
log.Fatalf("Error while formatting ONUs table: %s", err)
}
return nil
}
func (options *ONUServices) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
res, err := client.GetOnuServices(ctx, &req)
if err != nil {
log.Fatalf("Cannot not get services for ONU %s: %v", options.Args.OnuSn, err)
return err
}
tableFormat := format.Format(DEFAULT_SERVICE_HEADER_FORMAT)
if err := tableFormat.Execute(os.Stdout, true, res.Items); err != nil {
log.Fatalf("Error while formatting Services table: %s", err)
}
return nil
}
func (options *ONUShutDown) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
res, err := client.ShutdownONU(ctx, &req)
if err != nil {
log.Fatalf("Cannot shutdown ONU %s: %v", options.Args.OnuSn, err)
return err
}
fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
return nil
}
func (options *ONUPowerOn) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
res, err := client.PoweronONU(ctx, &req)
if err != nil {
log.Fatalf("Cannot power on ONU %s: %v", options.Args.OnuSn, err)
return err
}
fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
return nil
}
func (options *ONUEapolRestart) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
res, err := client.RestartEapol(ctx, &req)
if err != nil {
log.Fatalf("Cannot restart EAPOL for ONU %s: %v", options.Args.OnuSn, err)
return err
}
fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
return nil
}
func (options *ONUDhcpRestart) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
res, err := client.RestartDhcp(ctx, &req)
if err != nil {
log.Fatalf("Cannot restart DHCP for ONU %s: %v", options.Args.OnuSn, err)
return err
}
fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
return nil
}
func (options *ONUIgmp) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
var subActionVal pb.SubActionTypes
if string(options.Args.SubAction) == IgmpJoinKey {
subActionVal = pb.SubActionTypes_JOIN
} else if string(options.Args.SubAction) == IgmpLeaveKey {
subActionVal = pb.SubActionTypes_LEAVE
} else if string(options.Args.SubAction) == IgmpJoinKeyV3 {
subActionVal = pb.SubActionTypes_JOINV3
}
igmpReq := pb.IgmpRequest{
OnuReq: &req,
SubActionVal: subActionVal,
}
res, err := client.GetONU(ctx, igmpReq.OnuReq)
if err != nil {
log.WithFields(log.Fields{
"SerialNumber": options.Args.OnuSn,
}).Errorf("Cannot not get details on ONU error: %v", err)
}
log.WithFields(log.Fields{
"SerialNumber": igmpReq.OnuReq.SerialNumber,
}).Debugf("ONU has indentified : %s", res)
igmpRes, igmpErr := client.ChangeIgmpState(ctx, &igmpReq)
if igmpErr != nil {
log.WithFields(log.Fields{
"SubAction": options.Args.SubAction,
}).Errorf("Could not process Action: error: %v", igmpErr)
} else {
log.WithFields(log.Fields{
"SubAction": options.Args.SubAction,
}).Debugf("igmp state has been changed with response: %s",
igmpRes.Message)
}
return nil
}
func (options *ONUFlows) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
res, err := client.GetFlows(ctx, &req)
if err != nil {
log.Errorf("Cannot get flows for ONU %s: %v", options.Args.OnuSn, err)
return err
}
if res.Flows == nil {
fmt.Println(fmt.Sprintf("ONU %s has no flows", options.Args.OnuSn))
return nil
}
flowHeader := []string{
"access_intf_id",
"onu_id",
"uni_id",
"flow_id",
"flow_type",
"eth_type",
"alloc_id",
"network_intf_id",
"gemport_id",
"classifier",
"action",
"priority",
"cookie",
"port_no",
}
tableFlow := tablewriter.NewWriter(os.Stdout)
tableFlow.SetRowLine(true)
fmt.Fprintf(os.Stdout, "ONU Flows:\n")
tableFlow.SetHeader(flowHeader)
for _, flow := range res.Flows {
flowInfo := []string{}
flowInfo = append(flowInfo,
strconv.Itoa(int(flow.AccessIntfId)),
strconv.Itoa(int(flow.OnuId)),
strconv.Itoa(int(flow.UniId)),
strconv.Itoa(int(flow.FlowId)),
flow.FlowType,
fmt.Sprintf("%x", flow.Classifier.EthType),
strconv.Itoa(int(flow.AllocId)),
strconv.Itoa(int(flow.NetworkIntfId)),
strconv.Itoa(int(flow.GemportId)),
flow.Classifier.String(),
flow.Action.String(),
strconv.Itoa(int(flow.Priority)),
strconv.Itoa(int(flow.Cookie)),
strconv.Itoa(int(flow.PortNo)),
)
tableFlow.Append(flowInfo)
}
tableFlow.Render()
tableFlow.SetNewLine("")
return nil
}
func (onuSn *OnuSnString) Complete(match string) []flags.Completion {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
onus, err := client.GetONUs(ctx, &pb.Empty{})
if err != nil {
log.Fatalf("could not get ONUs: %v", err)
return nil
}
list := make([]flags.Completion, 0)
for _, k := range onus.Items {
if strings.HasPrefix(k.SerialNumber, match) {
list = append(list, flags.Completion{Item: k.SerialNumber})
}
}
return list
}
func (options *ONUTrafficSchedulers) Execute(args []string) error {
client, conn := connect()
defer conn.Close()
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
defer cancel()
req := pb.ONURequest{
SerialNumber: string(options.Args.OnuSn),
}
res, err := client.GetOnuTrafficSchedulers(ctx, &req)
if err != nil {
log.Fatalf("Cannot get traffic schedulers for ONU %s: %v", options.Args.OnuSn, err)
return err
}
if res.TraffSchedulers == nil {
log.Fatalf("Cannot get traffic schedulers for ONU: %s (unavailable)", options.Args.OnuSn)
return nil
}
SchedulerHeader := []string{"Direction",
"AllocId",
"Scheduler.Direction",
"Scheduler.AdditionalBw",
"Scheduler.Priority",
"Scheduler.Weight",
"Scheduler.SchedPolicy",
}
ShapingInfoHeader := []string{"InferredAdditionBwIndication",
"Cbs",
"Cir",
"Gir",
"Pbs",
"Pir",
}
SchedulerVals := []string{}
ShapingInfoVals := []string{}
for _, v := range res.TraffSchedulers.TrafficScheds {
SchedulerVals = append(SchedulerVals,
v.GetDirection().String(),
strconv.Itoa(int(v.GetAllocId())),
v.Scheduler.GetDirection().String(),
v.Scheduler.GetAdditionalBw().String(),
strconv.Itoa(int(v.Scheduler.GetPriority())),
strconv.Itoa(int(v.Scheduler.GetWeight())),
v.GetScheduler().GetSchedPolicy().String(),
)
ShapingInfoVals = append(ShapingInfoVals,
v.TrafficShapingInfo.GetAddBwInd().String(),
strconv.Itoa(int(v.TrafficShapingInfo.GetCbs())),
strconv.Itoa(int(v.TrafficShapingInfo.GetCir())),
strconv.Itoa(int(v.TrafficShapingInfo.GetGir())),
strconv.Itoa(int(v.TrafficShapingInfo.GetPbs())),
strconv.Itoa(int(v.TrafficShapingInfo.GetPir())),
)
}
fmt.Fprintf(os.Stdout, "OnuId: %d \n", int(res.TraffSchedulers.OnuId))
fmt.Fprintf(os.Stdout, "IntfId: %d \n", int(res.TraffSchedulers.IntfId))
fmt.Fprintf(os.Stdout, "UniId: %d \n", int(res.TraffSchedulers.UniId))
fmt.Fprintf(os.Stdout, "OnuPortNo: %d \n", int(res.TraffSchedulers.PortNo))
tableSched := tablewriter.NewWriter(os.Stdout)
tableSched.SetRowLine(true)
fmt.Fprintf(os.Stdout, "Traffic Schedulers Info:\n")
tableSched.SetHeader(SchedulerHeader)
tableSched.Append(SchedulerVals)
tableSched.Render()
tableSched.SetNewLine("")
tableShap := tablewriter.NewWriter(os.Stdout)
tableShap.SetRowLine(true)
fmt.Fprintf(os.Stdout, "Traffic Shaping Info:\n")
tableShap.SetHeader(ShapingInfoHeader)
tableShap.Append(ShapingInfoVals)
tableShap.Render()
return nil
}