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