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 }