[VOL-5378]-voltctl implementation to fetch PPPoe IA and DHCP RA stats
Change-Id: I617531684bfcf8cbac7846d5b21b63c03b6a7086
Signed-off-by: Akash Soni <akash.soni@radisys.com>
diff --git a/internal/pkg/commands/devices.go b/internal/pkg/commands/devices.go
index c9410d2..d45d663 100644
--- a/internal/pkg/commands/devices.go
+++ b/internal/pkg/commands/devices.go
@@ -413,6 +413,28 @@
} `positional-args:"yes"`
}
+type GetOffloadAppStats struct {
+ ListOutputOptions
+ Args struct {
+ OltId DeviceId `positional-arg-name:"OLT_DEVICE_ID" required:"yes"`
+ StatsFor extension.GetOffloadedAppsStatisticsRequest_OffloadedApp `positional-arg-name:"OFFLOADED_APP" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type SetOffloadAppState struct {
+ Args struct {
+ OltId DeviceId `positional-arg-name:"OLT_DEVICE_ID" required:"yes"`
+ Config extension.AppOffloadConfig `json:"config" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type SetOnuOffloadState struct {
+ Args struct {
+ OnuDeviceId string `positional-arg-name:"ONU_DEVICE_ID" required:"yes"`
+ PerUniInfo []extension.AppOffloadOnuConfig_PerUniConfig `json:"per_uni_info" required:"yes"`
+ } `positional-args:"yes"`
+}
+
type GetOnuEthernetFrameExtendedPmCounters struct {
ListOutputOptions
Reset bool `long:"reset" description:"Reset the counters"`
@@ -527,7 +549,12 @@
OnuOmciActiveAlarms GetOnuOmciActiveAlarms `command:"onu_omci_active_alarms"`
PonRxPower PonRxPower `command:"pon_rx_power"`
OnuDistance GetOnuDistance `command:"onu_distance"`
+ OffloadAppStats GetOffloadAppStats `command:"offload_app_stats"`
} `command:"getextval"`
+ SetExtVal struct {
+ OffloadAppStatsSet SetOffloadAppState `command:"set_offload_app_stats"`
+ OnuOffloadStatsSet SetOnuOffloadState `command:"set_onu_offload_stats"`
+ } `command:"setextval"`
}
var deviceOpts = DeviceOpts{}
@@ -2119,6 +2146,149 @@
return nil
}
+func (options *GetOffloadAppStats) Execute(args []string) error {
+ // Establish a connection to the gRPC server
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := extension.NewExtensionClient(conn)
+
+ // Build the request
+ singleGetValReq := &extension.SingleGetValueRequest{
+ TargetId: string(options.Args.OltId),
+ Request: &extension.GetValueRequest{
+ Request: &extension.GetValueRequest_OffloadedAppsStats{
+ OffloadedAppsStats: &extension.GetOffloadedAppsStatisticsRequest{
+ StatsFor: options.Args.StatsFor,
+ },
+ },
+ },
+ }
+
+ // Set a context with timeout
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
+ defer cancel()
+
+ // Perform the gRPC call
+ rv, err := client.GetExtValue(ctx, singleGetValReq)
+ if err != nil {
+ Error.Printf("Error getting value for device ID %s, err=%s\n", options.Args.OltId, ErrorToString(err))
+ return err
+ }
+
+ // Check response status
+ if rv.GetResponse().GetStatus() != extension.GetValueResponse_OK {
+ return fmt.Errorf("failed to get offloaded app stats: %v", rv.GetResponse().GetErrReason().String())
+ }
+
+ // Process the response data
+ stats, formatStr := buildOffloadAppStatsOutputFormat(rv.GetResponse().GetOffloadedAppsStats())
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = GetCommandOptionWithDefault("device-get-offload-app-stats", "format", formatStr)
+ }
+
+ // Generate and display the output
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ OutputAs: toOutputType(options.OutputAs),
+ NameLimit: options.NameLimit,
+ Data: stats,
+ }
+ GenerateOutput(&result)
+
+ return nil
+}
+
+func (options *SetOffloadAppState) Execute(args []string) error {
+ conn, err := NewConnection()
+ if err != nil {
+ return fmt.Errorf("failed to establish gRPC connection: %v", err)
+ }
+ defer conn.Close()
+
+ client := extension.NewExtensionClient(conn)
+
+ // Build the AppOffloadConfig request
+ setValueRequest := &extension.SetValueRequest{
+ Request: &extension.SetValueRequest_AppOffloadConfig{
+ AppOffloadConfig: &options.Args.Config,
+ },
+ }
+
+ singleSetValReq := &extension.SingleSetValueRequest{
+ TargetId: string(options.Args.OltId),
+ Request: setValueRequest,
+ }
+
+ // Make gRPC call
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
+ defer cancel()
+
+ resp, err := client.SetExtValue(ctx, singleSetValReq)
+ if err != nil {
+ return fmt.Errorf("failed to set AppOffloadConfig: %v", err)
+ }
+
+ if resp.Response.Status != extension.SetValueResponse_OK {
+ return fmt.Errorf("failed with status %v: %s", resp.Response.Status, resp.Response.ErrReason)
+ }
+
+ fmt.Printf("AppOffloadConfig successfully set for OLT ID: %s\n", options.Args.OltId)
+ return nil
+}
+
+func (options *SetOnuOffloadState) Execute(args []string) error {
+ conn, err := NewConnection()
+ if err != nil {
+ return fmt.Errorf("failed to establish gRPC connection: %v", err)
+ }
+ defer conn.Close()
+
+ client := extension.NewExtensionClient(conn)
+
+ // Convert PerUniInfo to []*extension.AppOffloadOnuConfig_PerUniConfig
+ var perUniInfo []*extension.AppOffloadOnuConfig_PerUniConfig
+ for i := range options.Args.PerUniInfo {
+ perUniInfo = append(perUniInfo, &options.Args.PerUniInfo[i])
+ }
+ // Build the AppOffloadOnuConfig request
+ onuConfig := &extension.AppOffloadOnuConfig{
+ OnuDeviceId: options.Args.OnuDeviceId,
+ PerUniInfo: perUniInfo,
+ }
+
+ setValueRequest := &extension.SetValueRequest{
+ Request: &extension.SetValueRequest_AppOffloadOnuConfig{
+ AppOffloadOnuConfig: onuConfig,
+ },
+ }
+
+ singleSetValReq := &extension.SingleSetValueRequest{
+ TargetId: options.Args.OnuDeviceId,
+ Request: setValueRequest,
+ }
+
+ // Make gRPC call
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
+ defer cancel()
+
+ resp, err := client.SetExtValue(ctx, singleSetValReq)
+ if err != nil {
+ return fmt.Errorf("failed to set AppOffloadOnuConfig: %v", err)
+ }
+
+ if resp.Response.Status != extension.SetValueResponse_OK {
+ return fmt.Errorf("failed with status %v: %s", resp.Response.Status, resp.Response.ErrReason)
+ }
+
+ fmt.Printf("AppOffloadOnuConfig successfully set for ONU ID: %s\n", options.Args.OnuDeviceId)
+ return nil
+}
+
func (options *GetOnuEthernetFrameExtendedPmCounters) Execute(args []string) error {
conn, err := NewConnection()
if err != nil {
diff --git a/internal/pkg/commands/stats.go b/internal/pkg/commands/stats.go
index 1fe9c4c..26697ac 100644
--- a/internal/pkg/commands/stats.go
+++ b/internal/pkg/commands/stats.go
@@ -17,9 +17,10 @@
import (
"fmt"
+ "strings"
+
"github.com/opencord/voltctl/pkg/model"
"github.com/opencord/voltha-protos/v5/go/extension"
- "strings"
)
type tagBuilder struct {
@@ -193,6 +194,73 @@
return onuStats, tagBuilder.buildOutputString()
}
+func buildOffloadAppStatsOutputFormat(stats *extension.GetOffloadedAppsStatisticsResponse) (map[string]interface{}, string) {
+ formatStr := "table" // Default format
+
+ if stats == nil {
+ return map[string]interface{}{
+ "error": "No stats available in response",
+ }, formatStr
+ }
+
+ switch data := stats.GetStats().(type) {
+ case *extension.GetOffloadedAppsStatisticsResponse_Dhcpv4RaStats:
+ return map[string]interface{}{
+ "in_bad_packets_from_client": data.Dhcpv4RaStats.InBadPacketsFromClient,
+ "in_bad_packets_from_server": data.Dhcpv4RaStats.InBadPacketsFromServer,
+ "in_packets_from_client": data.Dhcpv4RaStats.InPacketsFromClient,
+ "in_packets_from_server": data.Dhcpv4RaStats.InPacketsFromServer,
+ "out_packets_to_server": data.Dhcpv4RaStats.OutPacketsToServer,
+ "out_packets_to_client": data.Dhcpv4RaStats.OutPacketsToClient,
+ "option_82_inserted_packets_to_server": data.Dhcpv4RaStats.Option_82InsertedPacketsToServer,
+ "option_82_removed_packets_to_client": data.Dhcpv4RaStats.Option_82RemovedPacketsToClient,
+ "option_82_not_inserted_to_server": data.Dhcpv4RaStats.Option_82NotInsertedToServer,
+ "additional_stats": convertMapStringToInterface(data.Dhcpv4RaStats.AdditionalStats),
+ }, formatStr
+
+ case *extension.GetOffloadedAppsStatisticsResponse_Dhcpv6RaStats:
+ return map[string]interface{}{
+ "in_bad_packets_from_client": data.Dhcpv6RaStats.InBadPacketsFromClient,
+ "in_bad_packets_from_server": data.Dhcpv6RaStats.InBadPacketsFromServer,
+ "option_17_inserted_packets_to_server": data.Dhcpv6RaStats.Option_17InsertedPacketsToServer,
+ "option_17_removed_packets_to_client": data.Dhcpv6RaStats.Option_17RemovedPacketsToClient,
+ "option_18_inserted_packets_to_server": data.Dhcpv6RaStats.Option_18InsertedPacketsToServer,
+ "option_18_removed_packets_to_client": data.Dhcpv6RaStats.Option_18RemovedPacketsToClient,
+ "option_37_inserted_packets_to_server": data.Dhcpv6RaStats.Option_18InsertedPacketsToServer,
+ "option_37_removed_packets_to_client": data.Dhcpv6RaStats.Option_18RemovedPacketsToClient,
+ "outgoing_mtu_exceeded_packets_from_client": data.Dhcpv6RaStats.OutgoingMtuExceededPacketsFromClient,
+ "additional_stats": convertMapStringToInterface(data.Dhcpv6RaStats.AdditionalStats),
+ }, formatStr
+
+ case *extension.GetOffloadedAppsStatisticsResponse_PppoeIaStats:
+ return map[string]interface{}{
+ "in_error_packets_from_client": data.PppoeIaStats.InErrorPacketsFromClient,
+ "in_error_packets_from_server": data.PppoeIaStats.InErrorPacketsFromServer,
+ "in_packets_from_client": data.PppoeIaStats.InPacketsFromClient,
+ "in_packets_from_server": data.PppoeIaStats.InPacketsFromServer,
+ "out_packets_to_server": data.PppoeIaStats.OutPacketsToServer,
+ "out_packets_to_client": data.PppoeIaStats.OutPacketsToClient,
+ "vendor_specific_tag_inserted_packets_to_server": data.PppoeIaStats.VendorSpecificTagInsertedPacketsToServer,
+ "vendor_specific_tag_removed_packets_to_client": data.PppoeIaStats.VendorSpecificTagRemovedPacketsToClient,
+ "outgoing_mtu_exceeded_packets_from_client": data.PppoeIaStats.OutgoingMtuExceededPacketsFromClient,
+ "additional_stats": convertMapStringToInterface(data.PppoeIaStats.AdditionalStats),
+ }, formatStr
+
+ default:
+ return map[string]interface{}{
+ "error": "Unsupported or unknown stats type",
+ }, formatStr
+ }
+}
+
+func convertMapStringToInterface(input map[string]string) map[string]interface{} {
+ result := make(map[string]interface{}, len(input))
+ for key, value := range input {
+ result[key] = value
+ }
+ return result
+}
+
/*
* Construct a template format string based on the fields required by the
* results.