go.ligato.io/vpp-agent/v3@v3.5.0/plugins/telemetry/vppcalls/telemetry_handler_api.go (about)

     1  //  Copyright (c) 2019 Cisco and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  package vppcalls
    16  
    17  import (
    18  	"context"
    19  
    20  	govppapi "go.fd.io/govpp/api"
    21  	log "go.ligato.io/cn-infra/v2/logging"
    22  
    23  	"go.ligato.io/vpp-agent/v3/plugins/vpp"
    24  )
    25  
    26  var (
    27  	// FallbackToCli defines whether should telemetry handler
    28  	// fallback to parsing stats from CLI output.
    29  	FallbackToCli = false
    30  )
    31  
    32  // TelemetryVppAPI provides API for retrieving telemetry data from VPP.
    33  type TelemetryVppAPI interface {
    34  	GetSystemStats(context.Context) (*govppapi.SystemStats, error)
    35  	GetMemory(context.Context) (*MemoryInfo, error)
    36  	GetNodeCounters(context.Context) (*NodeCounterInfo, error)
    37  	GetRuntimeInfo(context.Context) (*RuntimeInfo, error)
    38  	GetBuffersInfo(context.Context) (*BuffersInfo, error)
    39  	GetInterfaceStats(context.Context) (*govppapi.InterfaceStats, error)
    40  	GetThreads(ctx context.Context) (*ThreadsInfo, error)
    41  }
    42  
    43  // MemoryInfo contains memory thread info.
    44  type MemoryInfo struct {
    45  	Threads []MemoryThread `json:"threads"`
    46  }
    47  
    48  // GetThreads is safe getter for threads,
    49  func (i *MemoryInfo) GetThreads() []MemoryThread {
    50  	if i == nil {
    51  		return nil
    52  	}
    53  	return i.Threads
    54  }
    55  
    56  // MemoryThread represents single thread memory counters
    57  type MemoryThread struct {
    58  	ID              uint   `json:"id"`
    59  	Name            string `json:"name"`
    60  	Size            uint64 `json:"size"`
    61  	Pages           uint64 `json:"pages"`
    62  	PageSize        uint64 `json:"page_size"`
    63  	Total           uint64 `json:"total"`
    64  	Used            uint64 `json:"used"`
    65  	Free            uint64 `json:"free"`
    66  	Trimmable       uint64 `json:"trimmable"`
    67  	FreeChunks      uint64 `json:"free_chunks"`
    68  	FreeFastbinBlks uint64 `json:"free_fastbin_blks"`
    69  	MaxTotalAlloc   uint64 `json:"max_total_allocated"`
    70  }
    71  
    72  // NodeCounterInfo contains node counters info.
    73  type NodeCounterInfo struct {
    74  	Counters []NodeCounter `json:"counters"`
    75  }
    76  
    77  // GetCounters is safe getter for counters,
    78  func (i *NodeCounterInfo) GetCounters() []NodeCounter {
    79  	if i == nil {
    80  		return nil
    81  	}
    82  	return i.Counters
    83  }
    84  
    85  // NodeCounter represents single node counter
    86  type NodeCounter struct {
    87  	Value uint64 `json:"value"`
    88  	Node  string `json:"node"`
    89  	Name  string `json:"name"`
    90  }
    91  
    92  // RuntimeInfo contains values returned from 'show runtime'
    93  type RuntimeInfo struct {
    94  	Threads []RuntimeThread `json:"threads"`
    95  }
    96  
    97  // GetThreads is safe getter for threads.
    98  func (i *RuntimeInfo) GetThreads() []RuntimeThread {
    99  	if i == nil {
   100  		return nil
   101  	}
   102  	return i.Threads
   103  }
   104  
   105  // RuntimeThread represents single runtime thread
   106  type RuntimeThread struct {
   107  	ID                  uint          `json:"id"`
   108  	Name                string        `json:"name"`
   109  	Time                float64       `json:"time"`
   110  	AvgVectorsPerNode   float64       `json:"avg_vectors_per_node"`
   111  	LastMainLoops       uint64        `json:"last_main_loops"`
   112  	VectorsPerMainLoop  float64       `json:"vectors_per_main_loop"`
   113  	VectorLengthPerNode float64       `json:"vector_length_per_node"`
   114  	VectorRatesIn       float64       `json:"vector_rates_in"`
   115  	VectorRatesOut      float64       `json:"vector_rates_out"`
   116  	VectorRatesDrop     float64       `json:"vector_rates_drop"`
   117  	VectorRatesPunt     float64       `json:"vector_rates_punt"`
   118  	Items               []RuntimeItem `json:"items"`
   119  }
   120  
   121  // RuntimeItem represents single runtime item
   122  type RuntimeItem struct {
   123  	Index          uint    `json:"index"`
   124  	Name           string  `json:"name"`
   125  	State          string  `json:"state"`
   126  	Calls          uint64  `json:"calls"`
   127  	Vectors        uint64  `json:"vectors"`
   128  	Suspends       uint64  `json:"suspends"`
   129  	Clocks         float64 `json:"clocks"`
   130  	VectorsPerCall float64 `json:"vectors_per_call"`
   131  }
   132  
   133  // BuffersInfo contains values returned from 'show buffers'
   134  type BuffersInfo struct {
   135  	Items []BuffersItem `json:"items"`
   136  }
   137  
   138  // GetItems is safe getter for items,
   139  func (i *BuffersInfo) GetItems() []BuffersItem {
   140  	if i == nil {
   141  		return nil
   142  	}
   143  	return i.Items
   144  }
   145  
   146  // BuffersItem represents single buffers item
   147  type BuffersItem struct {
   148  	ThreadID uint   `json:"thread_id"`
   149  	Name     string `json:"name"`
   150  	Index    uint   `json:"index"`
   151  	Size     uint64 `json:"size"`
   152  	Alloc    uint64 `json:"alloc"`
   153  	Free     uint64 `json:"free"`
   154  	NumAlloc uint64 `json:"num_alloc"`
   155  	NumFree  uint64 `json:"num_free"`
   156  }
   157  
   158  // ThreadsInfo contains values returned form `show threads`
   159  type ThreadsInfo struct {
   160  	Items []ThreadsItem
   161  }
   162  
   163  // GetItems is safe getter for thread items
   164  func (i *ThreadsInfo) GetItems() []ThreadsItem {
   165  	if i == nil {
   166  		return nil
   167  	}
   168  	return i.Items
   169  }
   170  
   171  // ThreadsItem represents single threads item
   172  type ThreadsItem struct {
   173  	Name      string `json:"name"`
   174  	ID        uint32 `json:"id"`
   175  	Type      string `json:"type"`
   176  	PID       uint32 `json:"pid"`
   177  	CPUID     uint32 `json:"cpuid"`
   178  	Core      uint32 `json:"core"`
   179  	CPUSocket uint32 `json:"cpu_socket"`
   180  }
   181  
   182  var Handler = vpp.RegisterHandler(vpp.HandlerDesc{
   183  	Name:       "telemetry",
   184  	HandlerAPI: (*TelemetryVppAPI)(nil),
   185  })
   186  
   187  type NewHandlerFunc func(vpp.Client) TelemetryVppAPI
   188  
   189  // AddHandlerVersion registers vppcalls Handler for the given version.
   190  func AddHandlerVersion(version vpp.Version, msgs []govppapi.Message, h NewHandlerFunc) {
   191  	Handler.AddVersion(vpp.HandlerVersion{
   192  		Version: version,
   193  		Check: func(c vpp.Client) error {
   194  			return c.CheckCompatiblity(msgs...)
   195  		},
   196  		NewHandler: func(c vpp.Client, a ...interface{}) vpp.HandlerAPI {
   197  			return h(c)
   198  		},
   199  	})
   200  }
   201  
   202  // NewHandler returns the telemetry handler preferring the VPP stats API
   203  // with CLI/binary API handler injected to retrieve data not included in
   204  // stats. In case the stats API is not available, CLI handler is returned.
   205  func NewHandler(c vpp.Client) (TelemetryVppAPI, error) {
   206  	var compatibleHandler TelemetryVppAPI = nil
   207  	v, err := Handler.GetCompatibleVersion(c)
   208  	if err != nil {
   209  		log.Warnf("compatible handler unavailable: %v", err)
   210  	} else {
   211  		compatibleHandler = v.NewHandler(c).(TelemetryVppAPI)
   212  	}
   213  	// Prefer the VPP stats API (even without the handler)
   214  	if stats := c.Stats(); stats != nil {
   215  		return NewTelemetryVppStats(stats, compatibleHandler), nil
   216  	}
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  	return compatibleHandler, nil
   221  }
   222  
   223  // CompatibleTelemetryHandler returns the telemetry handler respecting
   224  // VPP version. It returns the stats API handler when available, or
   225  // fallbacks to the CLI when requested.
   226  func CompatibleTelemetryHandler(c vpp.Client) TelemetryVppAPI {
   227  	var compatibleHandler TelemetryVppAPI = nil
   228  	v := Handler.FindCompatibleVersion(c)
   229  	if v != nil {
   230  		compatibleHandler = v.NewHandler(c).(TelemetryVppAPI)
   231  	}
   232  	if FallbackToCli && v != nil {
   233  		log.Info("falling back to parsing CLI output for telemetry")
   234  		return v.NewHandler(c).(TelemetryVppAPI)
   235  	}
   236  	if stats := c.Stats(); stats != nil {
   237  		if v == nil {
   238  			log.Warn("handler unavailable, functionality limited")
   239  		}
   240  		return NewTelemetryVppStats(stats, compatibleHandler)
   241  	}
   242  	// no compatible version found
   243  	log.Warnf("stats connection not available for telemetry")
   244  	return nil
   245  }