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  }