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  }