go.ligato.io/vpp-agent/v3@v3.5.0/plugins/govppmux/vppcalls/vpp2202/vpe_vppcalls.go (about) 1 // Copyright (c) 2022 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 vpp2202 16 17 import ( 18 "context" 19 "fmt" 20 "strings" 21 22 "github.com/pkg/errors" 23 "go.fd.io/govpp/api" 24 25 "go.ligato.io/vpp-agent/v3/plugins/govppmux/vppcalls" 26 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/memclnt" 27 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/vlib" 28 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/vpe" 29 ) 30 31 // Ping sends VPP control ping. 32 func (h *VpeHandler) Ping(ctx context.Context) error { 33 _, err := h.memclnt.ControlPing(ctx, new(memclnt.ControlPing)) 34 return err 35 } 36 37 // GetVersion retrieves version info from VPP. 38 func (h *VpeHandler) GetVersion(ctx context.Context) (*vppcalls.VersionInfo, error) { 39 version, err := h.vpe.ShowVersion(ctx, new(vpe.ShowVersion)) 40 if err != nil { 41 return nil, err 42 } 43 info := &vppcalls.VersionInfo{ 44 Program: strings.TrimRight(version.Program, "\x00"), 45 Version: strings.TrimRight(version.Version, "\x00"), 46 BuildDate: strings.TrimRight(version.BuildDate, "\x00"), 47 BuildDirectory: strings.TrimRight(version.BuildDirectory, "\x00"), 48 } 49 return info, nil 50 } 51 52 // GetSession retrieves session info from VPP. 53 func (h *VpeHandler) GetSession(ctx context.Context) (*vppcalls.SessionInfo, error) { 54 pong, err := h.memclnt.ControlPing(ctx, new(memclnt.ControlPing)) 55 if err != nil { 56 return nil, err 57 } 58 info := &vppcalls.SessionInfo{ 59 PID: pong.VpePID, 60 ClientIdx: pong.ClientIndex, 61 } 62 63 systime, err := h.vpe.ShowVpeSystemTime(ctx, new(vpe.ShowVpeSystemTime)) 64 if err != nil { 65 // TODO: log returned error as warning? 66 } else { 67 info.Uptime = float64(systime.VpeSystemTime) 68 } 69 return info, nil 70 } 71 72 // GetModules retrieves module info from VPP. 73 func (h *VpeHandler) GetModules(ctx context.Context) ([]vppcalls.APIModule, error) { 74 versions, err := h.memclnt.APIVersions(ctx, new(memclnt.APIVersions)) 75 if err != nil { 76 return nil, err 77 } 78 var modules []vppcalls.APIModule 79 for _, v := range versions.APIVersions { 80 modules = append(modules, vppcalls.APIModule{ 81 Name: strings.TrimSuffix(strings.TrimRight(v.Name, "\x00"), ".api"), 82 Major: v.Major, 83 Minor: v.Minor, 84 Patch: v.Patch, 85 }) 86 } 87 return modules, nil 88 } 89 90 func (h *VpeHandler) GetPlugins(ctx context.Context) ([]vppcalls.PluginInfo, error) { 91 const ( 92 pluginPathPrefix = "Plugin path is:" 93 pluginNameSuffix = "_plugin.so" 94 ) 95 96 out, err := h.RunCli(ctx, "show plugins") 97 if err != nil { 98 return nil, err 99 } 100 101 lines := strings.Split(out, "\n") 102 if len(lines) == 0 { 103 return nil, fmt.Errorf("empty output for 'show plugins'") 104 } 105 pluginPathLine := strings.TrimSpace(lines[0]) 106 if !strings.HasPrefix(pluginPathLine, pluginPathPrefix) { 107 return nil, fmt.Errorf("unexpected output for 'show plugins'") 108 } 109 pluginPath := strings.TrimSpace(strings.TrimPrefix(pluginPathLine, pluginPathPrefix)) 110 if len(pluginPath) == 0 { 111 return nil, fmt.Errorf("plugin path not found in output for 'show plugins'") 112 } 113 114 var plugins []vppcalls.PluginInfo 115 for _, line := range lines { 116 fields := strings.Fields(line) 117 if len(fields) < 3 { 118 continue 119 } 120 var i int 121 if _, err := fmt.Sscanf(fields[0], "%d.", &i); err != nil { 122 continue 123 } 124 if i <= 0 { 125 continue 126 } 127 plugin := vppcalls.PluginInfo{ 128 Name: strings.TrimSuffix(fields[1], pluginNameSuffix), 129 Path: fields[1], 130 Version: fields[2], 131 Description: strings.Join(fields[3:], " "), 132 } 133 plugins = append(plugins, plugin) 134 } 135 136 return plugins, nil 137 } 138 139 func (h *VpeHandler) GetThreads(ctx context.Context) ([]vppcalls.ThreadInfo, error) { 140 resp, err := h.vlib.ShowThreads(ctx, &vlib.ShowThreads{}) 141 if err != nil { 142 return nil, err 143 } 144 threads := make([]vppcalls.ThreadInfo, len(resp.ThreadData)) 145 for i, thread := range resp.ThreadData { 146 threads[i] = vppcalls.ThreadInfo{ 147 Name: thread.Name, 148 ID: thread.ID, 149 Type: thread.Type, 150 PID: thread.PID, 151 Core: thread.Core, 152 CPUID: thread.CPUID, 153 CPUSocket: thread.CPUSocket, 154 } 155 } 156 return threads, nil 157 } 158 159 // RunCli sends CLI command to VPP and returns response. 160 func (h *VpeHandler) RunCli(ctx context.Context, cmd string) (string, error) { 161 reply, err := h.vlib.CliInband(ctx, &vlib.CliInband{ 162 Cmd: cmd, 163 }) 164 if err != nil { 165 return "", errors.Wrapf(err, "VPP CLI command '%s' failed", cmd) 166 } else if err = api.RetvalToVPPApiError(reply.Retval); err != nil { 167 return "", err 168 } 169 return reply.Reply, nil 170 }