Code Monkey home page Code Monkey logo

govpp's Introduction

logo
GoVPP

Latest PkgGoDev CI Test

The GoVPP repository contains Go client libraries, code bindings generator and other toolings for VPP.


Features

  • πŸ†• CLI app for interacting with VPP instance and development of VPP API (see GoVPP CLI)
  • πŸ†• Extendable code generator supporting custom plugins (see Enhanced Generator)
  • πŸ†• Generated RPC client code that handles all boilerplate (see RPC Services)
  • Simple VPP client API that is not dependent on any VPP API semantics (see Stream API)
  • Generator of Go bindings for VPP API schema (see Binapi Generator)
  • Go client library for VPP binary API & Stats API (see VPP API calls)
  • Pure Go implementation of VPP binary API protocol (see socketclient)
  • Efficient reader of VPP Stats data from shared memory (see stats client example)

Quick Start

Here is a code sample of an effortless way for calling the VPP API services by using a generated RPC client.

Note For extensive info about using generated RPC client , see RPC Services

// Connect to VPP API socket
conn, err := govpp.Connect("/run/vpp/api.sock")
if err != nil {
  // handle err
}
defer conn.Disconnect()

// Initialize VPP API service client
client := vpe.NewServiceClient(conn)

// Call VPP API service method
reply, err := client.ShowVersion(context.Background(), &vpe.ShowVersion{})
if err != nil {
  // handle err
}
log.Print("Version: ", reply.Version)

See complete code for the example above: examples/rpc-service.

Examples

For complete code examples demonstrating vrious GoVPP features, please refer to the examples directory.

Documentation

Refer to User Guide document for info about how to use GoVPP. If you run into any issues or need some help with debugging GoVPP, read our Troubleshooting document.

Go reference docs are available at pkg.go.dev.

For other documentation refer to docs directory.

How to contribute?

Anyone insterested in GoVPP development is welcome to join our bi-weekly πŸ“£ GoVPP Community Meeting, where we accept inputs from projects using GoVPP and have technical discussions about actual development.

Repository Structure

Here is a brief overview of the repository structure.

  • govpp - the entry point for the GoVPP client
    • adapter - VPP binary & stats API interface
      • mock - Mock adapter used for testing
      • socketclient - Go implementation of VPP API client for unix socket
      • statsclient - Go implementation of VPP Stats client for shared memory
    • api - GoVPP client API
    • binapi - generated Go bindings for the latest VPP release
    • binapigen - library for generating code from VPP API
    • cmd
    • codec - handles encoding/decoding of generated messages into binary form
    • core - implementation of the GoVPP client
    • docs - user & developer documentation
    • examples - examples demonstrating GoVPP functionality
    • proxy - contains client/server implementation for proxy
    • test - integration tests, benchmarks and performance tests

govpp's People

Contributors

aloysaugustin avatar bayrinat avatar brecode avatar deathbeam avatar dependabot[bot] avatar dvalter avatar edwarnicke avatar giluerre avatar glazychev-art avatar grosa1 avatar hurd54 avatar lukasmacko avatar lukedirtwalker avatar matus-mrekaj avatar mhalaj1 avatar nikhil-agarwal-git avatar nplanel avatar ondrej-fabry avatar rastislavs avatar rubasov avatar sbezverk avatar serejkus avatar sknat avatar themiron avatar toravir avatar vladolavor avatar vvalderrv avatar xcxinng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

govpp's Issues

no server example?

there is no server example?

rpc-service i've tried but maybe there's no server example that's why i find it strange the application of vpp or how to test request/s over simple echo service etc.

not sure where i can apply vpp or where it really shines?

Function WaitReady does not wait if socket dir does not exist

Description: The function WaitReady (https://github.com/FDio/govpp/blob/master/adapter/socketclient/socketclient.go#L141) should wait until socket exists. If the directory for the socket already exists, it works correctly. But if the directory does not exist, it throws error and does not wait.
How to reproduce: Make sure that VPP is not running and the directory /run/vpp does not exist. If it exists, delete it. Then run the example examples/simple_client.go.
Observed behaviour: GoVPP waits 0.5 seconds between reconnects (reconnect interval).
Expected behaviour: It should wait 10.5 seconds between reconnects (variable MaxWaitReady + reconnect interval).

Fix failing build for integration tests due removed version of package

Problem

It seems the version specified for the ca-certificates package has been removed and is no longer available, which causes builds to fail.

#5 [2/8] RUN apt-get update && apt-get install -y --no-install-recommends         apt-transport-https=2.0.*         ca-certificates=20211016ubuntu0.20.*         curl=7.68.*         git=1:2.25.*         gnupg=2.2.*         iproute2=5.5.*         iputils-ping=3:20190709-3         make=4.2.*         nano=4.8-*         sudo=1.8.*         wget=1.20.*  	&& rm -rf /var/lib/apt/lists/*
#5 sha256:a961ed24ce65943d20eb5eeb6c4632d26787a3931ecf282faaf16f19f7f02398
#5 2.213 Get:1 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB]
#5 2.213 Get:2 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]
#5 3.015 Get:3 http://archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]
#5 3.202 Get:4 http://archive.ubuntu.com/ubuntu focal-backports InRelease [108 kB]
#5 3.299 Get:5 http://security.ubuntu.com/ubuntu focal-security/multiverse amd64 Packages [28.5 kB]
#5 3.402 Get:6 http://archive.ubuntu.com/ubuntu focal/main amd64 Packages [1275 kB]
#5 3.484 Get:7 http://security.ubuntu.com/ubuntu focal-security/restricted amd64 Packages [2270 kB]
#5 3.913 Get:8 http://archive.ubuntu.com/ubuntu focal/restricted amd64 Packages [33.4 kB]
#5 3.914 Get:9 http://archive.ubuntu.com/ubuntu focal/universe amd64 Packages [11.3 MB]
#5 4.136 Get:10 http://security.ubuntu.com/ubuntu focal-security/universe amd64 Packages [1051 kB]
#5 4.213 Get:11 http://security.ubuntu.com/ubuntu focal-security/main amd64 Packages [2726 kB]
#5 4.550 Get:12 http://archive.ubuntu.com/ubuntu focal/multiverse amd64 Packages [177 kB]
#5 4.552 Get:13 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages [3202 kB]
#5 4.700 Get:14 http://archive.ubuntu.com/ubuntu focal-updates/multiverse amd64 Packages [31.2 kB]
#5 4.701 Get:15 http://archive.ubuntu.com/ubuntu focal-updates/universe amd64 Packages [1346 kB]
#5 4.792 Get:16 http://archive.ubuntu.com/ubuntu focal-updates/restricted amd64 Packages [2408 kB]
#5 5.212 Get:17 http://archive.ubuntu.com/ubuntu focal-backports/main amd64 Packages [55.2 kB]
#5 5.668 Get:18 http://archive.ubuntu.com/ubuntu focal-backports/universe amd64 Packages [28.6 kB]
#5 5.767 Fetched 26.6 MB in 4s (6644 kB/s)
#5 5.767 Reading package lists...
#5 6.941 Reading package lists...
#5 8.019 Building dependency tree...
#5 8.208 Reading state information...
#5 8.229 E: Version '20211016ubuntu0.20.*' for 'ca-certificates' was not found
#5 ERROR: executor failed running [/bin/sh -c apt-get update && apt-get install -y --no-install-recommends         apt-transport-https=2.0.*         ca-certificates=20211016ubuntu0.20.*         curl=7.68.*         git=1:2.25.*         gnupg=2.2.*         iproute2=5.5.*         iputils-ping=3:20190709-3         make=4.2.*         nano=4.8-*         sudo=1.8.*         wget=1.20.*  	&& rm -rf /var/lib/apt/lists/*]: exit code: 100
------
 > [2/8] RUN apt-get update && apt-get install -y --no-install-recommends         apt-transport-https=2.0.*         ca-certificates=20211016ubuntu0.20.*         curl=7.68.*         git=1:2.25.*         gnupg=2.2.*         iproute2=5.5.*         iputils-ping=3:20190709-3         make=4.2.*         nano=4.8-*         sudo=1.8.*         wget=1.20.*  	&& rm -rf /var/lib/apt/lists/*:
------
executor failed running [/bin/sh -c apt-get update && apt-get install -y --no-install-recommends         apt-transport-https=2.0.*         ca-certificates=20211016ubuntu0.20.*         curl=7.68.*         git=1:2.25.*         gnupg=2.2.*         iproute2=5.5.*         iputils-ping=3:20190709-3         make=4.2.*         nano=4.8-*         sudo=1.8.*         wget=1.20.*  	&& rm -rf /var/lib/apt/lists/*]: exit code: 100
make: *** [Makefile:87: test-integration] Error 1
Error: Process completed with exit code 2.

https://github.com/FDio/govpp/actions/runs/5087800421/jobs/9143515162

Originally posted by @ondrej-fabry in #123 (comment)

Solutions

From quick glance, I see following alternative solutions for this.

  1. Remove the specified version for this particular package
    This might still break sometime in the future due other package version being removed

  2. Pick a different base image that contains all or at least most of the packages that we are installing.
    I believe there are some official ubuntu images that have these already installed, which would make it faster to build and more secure.

Investigate intermittent failure of TestTraceEnabled

The test case TestTraceEnabled seems to be failing at random occurrences.

Here is a log output from recent failure that occurred in CI Workflow:

2023-02-20T20:59:37.3608367Z === RUN   TestTraceEnabled
2023-02-20T20:59:37.3609424Z     trace_test.go:46: 
2023-02-20T20:59:37.3610020Z         Expected
2023-02-20T20:59:37.3610822Z             <[]*api.Record | len:7, cap:8>: [
2023-02-20T20:59:37.3611331Z                 {
2023-02-20T20:59:37.3612307Z                     Message: <*interfaces.CreateLoopback | 0xc00225222a>{
2023-02-20T20:59:37.3613298Z                         MacAddress: [0, 0, 0, 0, 0, 0],
2023-02-20T20:59:37.3613754Z                     },
2023-02-20T20:59:37.3614748Z                     Timestamp: 2023-02-20T20:59:37.355402739Z,
2023-02-20T20:59:37.3615331Z                     IsReceived: false,
2023-02-20T20:59:37.3615852Z                     ChannelID: 1,
2023-02-20T20:59:37.3616265Z                 },
2023-02-20T20:59:37.3616619Z                 {
2023-02-20T20:59:37.3617622Z                     Message: <*interfaces.CreateLoopbackReply | 0xc002252298>{Retval: 0, SwIfIndex: 0},
2023-02-20T20:59:37.3618529Z                     Timestamp: 2023-02-20T20:59:37.35542454Z,
2023-02-20T20:59:37.3619089Z                     IsReceived: true,
2023-02-20T20:59:37.3619599Z                     ChannelID: 1,
2023-02-20T20:59:37.3620004Z                 },
2023-02-20T20:59:37.3620379Z                 {
2023-02-20T20:59:37.3621083Z                     Message: <*memif.MemifCreate | 0xc00224f200>{
2023-02-20T20:59:37.3621654Z                         Role: 0,
2023-02-20T20:59:37.3622160Z                         Mode: 0,
2023-02-20T20:59:37.3622694Z                         RxQueues: 0,
2023-02-20T20:59:37.3623227Z                         TxQueues: 0,
2023-02-20T20:59:37.3623704Z                         ID: 0,
2023-02-20T20:59:37.3624226Z                         SocketID: 0,
2023-02-20T20:59:37.3624901Z                         RingSize: 0,
2023-02-20T20:59:37.3625461Z                         BufferSize: 0,
2023-02-20T20:59:37.3626050Z                         NoZeroCopy: false,
2023-02-20T20:59:37.3626722Z                         HwAddr: [0, 0, 0, 0, 0, 0],
2023-02-20T20:59:37.3628285Z                         Secret: "",
2023-02-20T20:59:37.3628768Z                     },
2023-02-20T20:59:37.3629619Z                     Timestamp: 2023-02-20T20:59:37.355516946Z,
2023-02-20T20:59:37.3630204Z                     IsReceived: false,
2023-02-20T20:59:37.3630740Z                     ChannelID: 1,
2023-02-20T20:59:37.3631145Z                 },
2023-02-20T20:59:37.3631521Z                 {
2023-02-20T20:59:37.3632439Z                     Message: <*memif.MemifCreateReply | 0xc0022522c8>{Retval: 0, SwIfIndex: 0},
2023-02-20T20:59:37.3633317Z                     Timestamp: 2023-02-20T20:59:37.355526447Z,
2023-02-20T20:59:37.3633888Z                     IsReceived: true,
2023-02-20T20:59:37.3634395Z                     ChannelID: 1,
2023-02-20T20:59:37.3634778Z                 },
2023-02-20T20:59:37.3635156Z                 {
2023-02-20T20:59:37.3641241Z                     Message: <*l2.BridgeDomainAddDel | 0xc001c56f00>{BdID: 0, Flood: false, UuFlood: false, Forward: false, Learn: false, ArpTerm: false, ArpUfwd: false, MacAge: 0, BdTag: "", IsAdd: false},
2023-02-20T20:59:37.3642204Z                     Timestamp: 2023-02-20T20:59:37.355608052Z,
2023-02-20T20:59:37.3643344Z                     IsReceived: false,
2023-02-20T20:59:37.3643806Z                     ChannelID: 1,
2023-02-20T20:59:37.3644106Z                 },
2023-02-20T20:59:37.3644392Z                 {
2023-02-20T20:59:37.3645178Z                     Message: <*l2.BridgeDomainAddDelReply | 0xc00225230c>{Retval: 0},
2023-02-20T20:59:37.3645972Z                     Timestamp: 2023-02-20T20:59:37.355629753Z,
2023-02-20T20:59:37.3646441Z                     IsReceived: true,
2023-02-20T20:59:37.3646861Z                     ChannelID: 1,
2023-02-20T20:59:37.3647167Z                 },
2023-02-20T20:59:37.3647450Z                 {
2023-02-20T20:59:37.3648179Z                     Message: <*ip.IPTableAddDelReply | 0xc00225233c>{Retval: 0},
2023-02-20T20:59:37.3648928Z                     Timestamp: 2023-02-20T20:59:37.35574826Z,
2023-02-20T20:59:37.3649402Z                     IsReceived: true,
2023-02-20T20:59:37.3649818Z                     ChannelID: 1,
2023-02-20T20:59:37.3650108Z                 },
2023-02-20T20:59:37.3650378Z             ]
2023-02-20T20:59:37.3650679Z         to have length 8
2023-02-20T20:59:37.3651028Z --- FAIL: TestTraceEnabled (0.00s)
2023-02-20T20:59:37.3651445Z οΏ½[31mFAILοΏ½[0m core.TestTraceEnabled (0.00s)
2023-02-20T20:59:37.3656156Z οΏ½[32mPASSοΏ½[0m core.TestMultiRequestTraceEnabled (0.00s)
2023-02-20T20:59:37.3656938Z οΏ½[32mPASSοΏ½[0m core.TestTraceDisabled (0.00s)
2023-02-20T20:59:37.3678066Z οΏ½[32mPASSοΏ½[0m core.TestTracePerChannel (0.00s)
2023-02-20T20:59:37.3757584Z οΏ½[32mPASSοΏ½[0m core.TestTraceClear (0.00s)
2023-02-20T20:59:37.3845354Z οΏ½[31mFAILοΏ½[0m core
2023-02-20T20:59:37.3864616Z οΏ½[33mEMPTYοΏ½[0m core/genericpool
2023-02-20T20:59:37.3903496Z οΏ½[33mEMPTYοΏ½[0m examples/api-trace
2023-02-20T20:59:37.3904257Z οΏ½[33mEMPTYοΏ½[0m examples/binapi-types
2023-02-20T20:59:37.3904922Z οΏ½[33mEMPTYοΏ½[0m examples/multi-vpp
2023-02-20T20:59:37.3905468Z οΏ½[33mEMPTYοΏ½[0m examples/perf-bench
2023-02-20T20:59:37.3906066Z οΏ½[33mEMPTYοΏ½[0m examples/rpc-service
2023-02-20T20:59:37.3906646Z οΏ½[33mEMPTYοΏ½[0m examples/simple-client
2023-02-20T20:59:37.3907253Z οΏ½[33mEMPTYοΏ½[0m examples/stats-client
2023-02-20T20:59:37.3907797Z οΏ½[33mEMPTYοΏ½[0m examples/stream-client
2023-02-20T20:59:37.3908346Z οΏ½[33mEMPTYοΏ½[0m proxy
2023-02-20T20:59:37.3908855Z οΏ½[33mEMPTYοΏ½[0m test/vpptesting
2023-02-20T20:59:37.3909472Z οΏ½[33mEMPTYοΏ½[0m test/vpptesting/vpplauncher
2023-02-20T20:59:37.3909966Z οΏ½[33mEMPTYοΏ½[0m version
2023-02-20T20:59:37.4423300Z 
2023-02-20T20:59:37.4423989Z === οΏ½[33mSkippedοΏ½[0m
2023-02-20T20:59:37.4424657Z === οΏ½[33mSKIPοΏ½[0m: core TestReceiveReplyAfterTimeoutMultiRequest (0.00s)
2023-02-20T20:59:37.4425487Z     channel_test.go:435: 
2023-02-20T20:59:37.4425663Z 
2023-02-20T20:59:37.4425825Z === οΏ½[31mFailedοΏ½[0m
2023-02-20T20:59:37.4426222Z === οΏ½[31mFAILοΏ½[0m: core TestTraceEnabled (0.00s)
2023-02-20T20:59:37.4426574Z     trace_test.go:46: 
2023-02-20T20:59:37.4426868Z         Expected
2023-02-20T20:59:37.4427301Z             <[]*api.Record | len:7, cap:8>: [
2023-02-20T20:59:37.4427622Z                 {
2023-02-20T20:59:37.4428322Z                     Message: <*interfaces.CreateLoopback | 0xc00225222a>{
2023-02-20T20:59:37.4428993Z                         MacAddress: [0, 0, 0, 0, 0, 0],
2023-02-20T20:59:37.4429358Z                     },
2023-02-20T20:59:37.4430046Z                     Timestamp: 2023-02-20T20:59:37.355402739Z,
2023-02-20T20:59:37.4430526Z                     IsReceived: false,
2023-02-20T20:59:37.4430952Z                     ChannelID: 1,
2023-02-20T20:59:37.4431249Z                 },
2023-02-20T20:59:37.4431541Z                 {
2023-02-20T20:59:37.4432440Z                     Message: <*interfaces.CreateLoopbackReply | 0xc002252298>{Retval: 0, SwIfIndex: 0},
2023-02-20T20:59:37.4433241Z                     Timestamp: 2023-02-20T20:59:37.35542454Z,
2023-02-20T20:59:37.4433715Z                     IsReceived: true,
2023-02-20T20:59:37.4434137Z                     ChannelID: 1,
2023-02-20T20:59:37.4434435Z                 },
2023-02-20T20:59:37.4434722Z                 {
2023-02-20T20:59:37.4435356Z                     Message: <*memif.MemifCreate | 0xc00224f200>{
2023-02-20T20:59:37.4435836Z                         Role: 0,
2023-02-20T20:59:37.4437305Z                         Mode: 0,
2023-02-20T20:59:37.4437780Z                         RxQueues: 0,
2023-02-20T20:59:37.4438251Z                         TxQueues: 0,
2023-02-20T20:59:37.4438710Z                         ID: 0,
2023-02-20T20:59:37.4439162Z                         SocketID: 0,
2023-02-20T20:59:37.4439613Z                         RingSize: 0,
2023-02-20T20:59:37.4440068Z                         BufferSize: 0,
2023-02-20T20:59:37.4440604Z                         NoZeroCopy: false,
2023-02-20T20:59:37.4441174Z                         HwAddr: [0, 0, 0, 0, 0, 0],
2023-02-20T20:59:37.4441620Z                         Secret: "",
2023-02-20T20:59:37.4441960Z                     },
2023-02-20T20:59:37.4442677Z                     Timestamp: 2023-02-20T20:59:37.355516946Z,
2023-02-20T20:59:37.4443149Z                     IsReceived: false,
2023-02-20T20:59:37.4443584Z                     ChannelID: 1,
2023-02-20T20:59:37.4443899Z                 },
2023-02-20T20:59:37.4444177Z                 {
2023-02-20T20:59:37.4445178Z                     Message: <*memif.MemifCreateReply | 0xc0022522c8>{Retval: 0, SwIfIndex: 0},
2023-02-20T20:59:37.4445986Z                     Timestamp: 2023-02-20T20:59:37.355526447Z,
2023-02-20T20:59:37.4446463Z                     IsReceived: true,
2023-02-20T20:59:37.4446878Z                     ChannelID: 1,
2023-02-20T20:59:37.4447193Z                 },
2023-02-20T20:59:37.4447483Z                 {
2023-02-20T20:59:37.4449035Z                     Message: <*l2.BridgeDomainAddDel | 0xc001c56f00>{BdID: 0, Flood: false, UuFlood: false, Forward: false, Learn: false, ArpTerm: false, ArpUfwd: false, MacAge: 0, BdTag: "", IsAdd: false},
2023-02-20T20:59:37.4449958Z                     Timestamp: 2023-02-20T20:59:37.355608052Z,
2023-02-20T20:59:37.4450431Z                     IsReceived: false,
2023-02-20T20:59:37.4450862Z                     ChannelID: 1,
2023-02-20T20:59:37.4451159Z                 },
2023-02-20T20:59:37.4451442Z                 {
2023-02-20T20:59:37.4452215Z                     Message: <*l2.BridgeDomainAddDelReply | 0xc00225230c>{Retval: 0},
2023-02-20T20:59:37.4452980Z                     Timestamp: 2023-02-20T20:59:37.355629753Z,
2023-02-20T20:59:37.4453451Z                     IsReceived: true,
2023-02-20T20:59:37.4453876Z                     ChannelID: 1,
2023-02-20T20:59:37.4454171Z                 },
2023-02-20T20:59:37.4454455Z                 {
2023-02-20T20:59:37.4455290Z                     Message: <*ip.IPTableAddDelReply | 0xc00225233c>{Retval: 0},
2023-02-20T20:59:37.4456044Z                     Timestamp: 2023-02-20T20:59:37.35574826Z,
2023-02-20T20:59:37.4456520Z                     IsReceived: true,
2023-02-20T20:59:37.4456943Z                     ChannelID: 1,
2023-02-20T20:59:37.4457242Z                 },
2023-02-20T20:59:37.4457512Z             ]
2023-02-20T20:59:37.4457827Z         to have length 8
2023-02-20T20:59:37.4457998Z 
2023-02-20T20:59:37.4458167Z DONE 90 tests, 1 skipped, 1 failure in 37.514s
2023-02-20T20:59:37.4467380Z ##[error]Process completed with exit code 1.

Update GoVPP info on FD.io & VPP docs websites

This issue tracks progress of updating info about GoVPP project on official FD.io web sites.

Description

The official web for the FD.io project (https://fd.io/) is lacking any info about the GoVPP sub-project and web for the VPP documentation (https://s3-docs.fd.io/vpp/master/developer/build-run-debug/) contains limited or outdated info.

TODO

Here are few places to start with:

LDFLAG gets redefined in the code, though if it is set in the Makefile

Sometimes the libmemif.so can be generated at a custom path rather than in the standard path /usr/lib.

extras/libmemif/adapter.go
extras/libmemif/error.go

Has the definition of LDFLAGS in the code which redefines the one which is set from Makefile
#cgo LDFLAGS: -lmemif

Could you please make this flexible so that it can be set via Makefile

cannot parse high u64 default values in the API files

As Govpp doesn't know in advance the exact template of the json it parses, it uses a generic parsing with json.Unmarshal here
However, when unmarshalling generic json in Go, numbers are casted in float64. Now, if the Json contain uint64 numbers, we lose precision casting them as float64.

As we allow u64 types in the VPP API, we may end up with a wrong value after parsing the API. And casting float64 into uint64 depends on the hardware implementation.
In Govpp, the conversion happens here
Let's take a VPP API exmaple:

 [
    "u64",
    "value",
    {
        "default": 18446744073709551615
    }
],

If we generate Go bindings with this Json, we get:

  • u64,name=value,default=9223372036854775808 if we run it on x86 devices
  • u64,name=value,default=18446744073709551615 if we run it on arm devices

Memory leak prevention proposal

The thread servers for discussion on how to properly implement an automatic process checking the memory consumption of GoVPP, mainly the API processing.

The process should measure the memory footprint of the transport library regularly and compare it with reference numbers. This would help us to identify code changes with improper memory management.

  • Test proposal: PR#186
  • The test may run in the same manner as integration tests (although it is not needed to run it against multiple VPP versions)

Create Troubleshooting Guide document

Create a Troubleshooting guide docs with common problems that users often run into.

  • info about how to increase log verbosity and enable debugging of various GoVPP components
  • send/receive error unknown message: ... - occurs when running VPP version with incompatible messages
  • connection errors - possibly missing socket? perhaps incorrect path or wrong VPP config?
  • add more..

Improve compatibility checking

The current implementation of the compatibility checking does not make distinction between a missing message and message with different CRC.

This has recently caused issue in the last VPP release 23.06 where new messages where added to interface API which caused the compatibility check in examples fail. As a quick workaround the examples now only log warning message on failing this check for interface API.

The proper solution for this is to fail only if the messages that are being checked actually exist in the connected VPP and are truly incompatible - have different CRC.

Add support of VPP events to Stream API

Opening this issue to track progress of design and implementation of event support in new Stream API which is one of the remaining features required to make this new API complete.

@edwarnicke has already opened a PR #42 with initial implementation:

type Connection interface {
  // ...
  SubscribeNotification(ctx context.Context, event Message, bufferSize int) (chan Message, error)
}

Ed included some comments on design decisions.

However, before merging this as is, I would like to go over some concerns and possible improvements.
Here is summary of what should be taken into consideration when designing this.

  1. Generated RPC services should provide simple way to watching events without required boilerplate.
  • subsribing/unsubscring to event would need to match value of EnableDisable field
  • starting multiple watchers for same event would need to keep reference count to work properly for all
  1. Instead of using a go channel for events we should look into re-using the Stream itself as it already has RecvMsg() (Message, error) method for receiving messages.
  • stream would be added to subscribers of specific event type to get the event message (because context is 0)
  • this could easily handle multiple event types using RecvMsg() with type switch
  1. Consider if it makes sense to allow users to consume multiple events on same go channel/Stream.

Proposal for generated code

Currently the generated method for enable events has nothing to do with the actual event message:

// Current implementation of generated RPC method that enables events
func (c *serviceClient) WantWireguardPeerEvents(ctx context.Context, in *WantWireguardPeerEvents) (*WantWireguardPeerEventsReply, error) {
	out := new(WantWireguardPeerEventsReply)
	err := c.conn.Invoke(ctx, in, out)
	if err != nil {
		return nil, err
	}
	return out, api.RetvalToVPPApiError(out.Retval)
}

Instead, RPC method that enables events could work in a similar way that dump requests do:

// Proposed implementation of generated RPC method that handles events
func (c *serviceClient) WantWireguardPeerEvents(ctx context.Context, in *WantWireguardPeerEvents) (RPCService_WireguardPeersEventsClient, error) {
	stream, err := c.conn.NewStream(ctx)
	if err != nil {
		return nil, err
	}
	x := &serviceClient_WireguardPeersEventsClient{stream}
    // this should check the value of `EnableDisable` field or ??
	if err := x.Stream.SendMsg(in); err != nil {
		return nil, err
	}
	msg, err := x.Stream.RecvMsg()
	if err != nil {
		return nil, err
	}
	out, ok := msg.(*WantWireguardPeerEventsReply)
	if !ok {
		return nil, fmt.Errorf("unexpected message: %T %v", msg, msg)
	}
	if err := api.RetvalToVPPApiError(out.Retval); err != nil {
		return nil, err
	}
	// until here it is pretty much same, just creates stream instead of calling Invoke
	// here we subscribe to specific event that is handled by this RPC methoid
	c.conn.SubscribeEvent(ctx, (*WireguardPeerEvent)(nil), stream)
    
	go func() {
		<-ctx.Done()
		c.conn.UnsubscribeEvent(ctx, (*WireguardPeerEvent)(nil), stream)
	}()
	return x, nil
}

type RPCService_WireguardPeersEventsClient interface {
	Recv() (*WireguardPeerEvent, error)
	// Perhaps Stop() or Unsubscribe() method ??
	api.Stream
}

type serviceClient_WireguardPeersEventsClient struct {
	api.Stream
}

// this would work in
func (c *serviceClient_WireguardPeersEventsClient) Recv() (*WireguardPeerEvent, error) {
	msg, err := c.Stream.RecvMsg()
	if err != nil {
		return nil, err
	}
	switch m := msg.(type) {
	case *WireguardPeerEvent:
		return m, nil
	default:
		return nil, fmt.Errorf("unexpected message: %T %v", m, m)
	}
}

however this example above does not check EnableDisable field and perhaps should not even accept request message WantWireguardPeerEvents from user, but handle it in way that enables events at beginning and disables them when ending.

Fix: memory leak in receiveReplyInternal function

Function receiveReplyInternal uses 2 control timers: timeoutTimer and slowTimer.

Need to stop these timers before exit from the function (using defer) to avoid memory leak:

	timeoutTimer := time.NewTimer(timeout)
	slowTimer := time.NewTimer(slowReplyDur)
	defer func() {
		timeoutTimer.Stop()
		slowTimer.Stop()
	}()

I met the problem in our production environment while using very repeatetive dumping IP routes. My temp solution fixed the memory leak.

Add a dev and release VPP container

It would be good to maintain per-release containers for VPP, both

  • a dev container containing build & run dependencies so that a user can clone or mount a VPP git tree and run make build within.
  • a release container with compiled VPP images, and a minimal set of runtime dependancies

gomemif: Packet sent on Tx queue is received back on Rx queue of sender

Hi,

I am hitting an issue where in Tx packet send is received back in sender's Rx queue intermittently. And this behavior is observed both on govpp as well as vpp side.

Setup details : Gomemif in slave mode and vpp in master mode with single pair of queues. Gomemif is latest and VPP release is 21.10.1

Packets are being pumped from both master(from vpp side) and slaves(from gomemif) simultaneously and rate is roughly 100/s each side.

On further digging in the gomemif code, I see that Rx descriptor's buffers offset are set to Tx descriptors buffer offset instead of seperate buffers even though region(shared memory) for sepearte Tx and Rx rings,descriptors and buffers is allocated.
This also leads to use of only half of the total descriptors allocated.

I tried with a minor fix(attached-gomemif-descriptor-fix.txt) with which I was able use separate buffers for Tx and Rx and get around this issue. After this fix, no such issue was observed on even 1000/s rate for longer runs(more than 12 hrs)
I can push this fix for review incase required or can wait for fix from contributors. Either way is fine.

gomemif-descriptor-fix.txt

GoVPP CLI: worker to main thread when using api : communication problem ?

Intro

This issue tracks a potential bug or misbehaviour when using several worker on VPP (tested on VPP 23.06).

Problem

We are facing an issue when using several worker in the VPP startup config when sending a basic ping command through GoVPP CLI.
Here are the logs (1 main thread + 2 workers):

vpp# sh threads
ID     Name                Type        LWP     Sched Policy (Priority)  lcore  Core   Socket State
0      vpp_main                        160368  other (0)                1      0      0
1      vpp_wk_0            workers     160371  other (0)                2      0      0
2      vpp_wk_1            workers     160372  other (0)                3      0      0

vpp# sh hardware-interfaces
              Name                Idx   Link  Hardware
eth4                               1     up   eth4
  Link speed: unknown
  RX Queues:
    queue thread         mode
    0     vpp_wk_0 (1)   polling
  TX Queues:
    TX Hash: [name: hash-eth-l34 priority: 50 description: Hash ethernet L34 headers]
    queue shared thread(s)
    0     yes    0-2
  Ethernet address fa:16:3e:67:61:ef
  Red Hat Virtio

root@ddd:/home/lab# ./govpp -L trace cli ping 192.168.200.1
TRAC[0000]options.go:74 main.InitOptions() log level set to: trace
TRAC[0000]options.go:84 main.InitOptions() init global options: &{Debug:false LogLevel:trace Color:}
DEBU[0000]cmd_cli.go:127 main.newCliCommand.func1() provided 2 args
TRAC[0000]cmd_cli.go:227 main.newBinapiVppCli() connecting to VPP API socket "/run/vpp/api.sock"
vpp# ping 192.168.200.1
DEBU[0000]cmd_cli.go:192 main.runCliCmd() executing CLI command: ping 192.168.200.1
TRAC[0000]cmd_cli.go:255 main.(*vppcliBinapi).Execute() sending CLI command: "ping 192.168.200.1"

Statistics: 5 sent, 0 received, 100% packet loss

DEBU[0005]cmd_cli.go:269 main.(*vppcliBinapi).Close() disconnecting VPP API connection

We made some dpdk- input trace, and the icmp packets are well received but it seems it does not communicate properly the result. Is this because API is running on main thread ?

Here are the logs (1 main thread):

vpp# sh threads
ID     Name                Type        LWP     Sched Policy (Priority)  lcore  Core   Socket State
0      vpp_main                        160396  other (0)                1      0      0

vpp# sh hardware-interfaces
              Name                Idx   Link  Hardware
eth4                               1     up   eth4
  Link speed: unknown
  RX Queues:
    queue thread         mode
    0     main (0)       polling
  TX Queues:
    TX Hash: [name: hash-eth-l34 priority: 50 description: Hash ethernet L34 headers]
    queue shared thread(s)
    0     no     0
  Ethernet address fa:16:3e:67:61:ef

root@ddd:/home/lab# ./govpp -L trace cli ping 192.168.200.1
TRAC[0000]options.go:74 main.InitOptions() log level set to: trace
TRAC[0000]options.go:84 main.InitOptions() init global options: &{Debug:false LogLevel:trace Color:}
DEBU[0000]cmd_cli.go:127 main.newCliCommand.func1() provided 2 args
TRAC[0000]cmd_cli.go:227 main.newBinapiVppCli() connecting to VPP API socket "/run/vpp/api.sock"
vpp# ping 192.168.200.1
DEBU[0000]cmd_cli.go:192 main.runCliCmd() executing CLI command: ping 192.168.200.1
TRAC[0000]cmd_cli.go:255 main.(*vppcliBinapi).Execute() sending CLI command: "ping 192.168.200.1"
116 bytes from 192.168.200.1: icmp_seq=1 ttl=64 time=10.8021 ms
116 bytes from 192.168.200.1: icmp_seq=2 ttl=64 time=.3975 ms
116 bytes from 192.168.200.1: icmp_seq=3 ttl=64 time=.3383 ms
116 bytes from 192.168.200.1: icmp_seq=4 ttl=64 time=.2925 ms
116 bytes from 192.168.200.1: icmp_seq=5 ttl=64 time=.2718 ms

Statistics: 5 sent, 5 received, 0% packet loss

DEBU[0005]cmd_cli.go:269 main.(*vppcliBinapi).Close() disconnecting VPP API connection

Solution

This problem can be solved by using only one main thread. Or by setting rx-placement on main queue : set interface rx-placement eth4 queue0 main

Fix memory leak

Hi govpp team:

I've used govpp on the production environment for more than 1 year, and it is very stable, and thank you for your hard work.

But I once got a memory leak when it failed to check the stat version in the test environment, and the problem was solved after I make this patch: #34

Isn't it better to call munmap() before the return statement, What do you guys think?

[extras] The gomemif library struggles with high throughput when using interrupt mode.

When using the interrupt mode from the (example) code this error is returned over the memifErrChan:
EpollWait: %!(EXTRA syscall.Errno=interrupted system call)
This only happens when the traffic goes up (like 1Gbps), and even then its not very frequent. Still, this causes the StartPolling() to quit, and the channel dies.

As a quick fix I have changed the return to a continue and it seems to work without any issues. In addition my code changed the return nil in the example to only return if if pktLen > 0 is false so the loop keeps processing packets.

Ps. the handleEvent() should probably return the error from the interrupt function like this: return intf.onInterrupt(intf)

go.fd.io/govpp/extras cannot be imported

extras directory is declared as its own module:

module go.fd.io/govpp/extras

However, the HTTP server at go.fd.io/govpp/extras is not returning the necessary <meta name="go-import"> tag, so that the module cannot be imported.

$ go get go.fd.io/govpp/extras@latest
go: module go.fd.io/govpp@latest found (v0.7.0), but does not contain package go.fd.io/govpp/extras

⚠️ Please, read the following comment with update: ➑️ #111 (comment)

Close connection event channel on disconnect

Intro

This issue tracks progress for fixing issue with connection even channel on disconnect.

Problem

With the current implementation the core.AsyncConnect will return channel for core.ConnectionEvent which allows user to receive events about the connection state. However there might be cases where the reconnection loop with terminate and no more reconnect attempts will be done. If the user for some reason misses the event (full buffer) or accidentally calls Disconnect somewhere in the code he might run into situation where the receiving of next event will block forever.

Solution

This problem can be solved by closing the connection event channel after termination of reconnect loop.

Fix import for extras in go.mod file

When I attempt to add the two references to a go.mod file

go.fd.io/govpp.git v0.8.0
go.fd.io/govpp.git/extras v0.1.0

and then I run go mod tidy, I get this error a lot:

git.fd.io/govpp.git: go.fd.io/[email protected]: no secure protocol found for repository
git.fd.io/govpp.git/binapi/memif: go.fd.io/[email protected]: no secure protocol found for repository

What should I be adding to go.mod so that I can use libmemif and govpp.
I also tried to use github.com/FDio/govpp but go mod hates that even more.


Originally posted by @Sophrinix in #122 (comment)

Using Log2RingSize custom set to more than 10 causes crash in packet writer for gomemif

When we are using custom memory config in gomemif, with Log2RingSize set to more than 10, the packet writer after writing some packets panics with index out of range error:

panic: runtime error: index out of range [770] with length 1

The packet buffersize doesn't matter. I have tried 2048 to 9128. It doesn't affect the outcome, only the Log2RingSize. I have set it to 11, 12 it panics.

I see that the default Log2RingSize is set to 10.

Support new VPP API objects: counters & paths

The VPP has added support for a data model in VPP API for counters.

Gerrit change which introduced this feature: https://gerrit.fd.io/r/c/vpp/+/29296

Here is a part of ip.api.json file extracted from VPP master branch:

{
	"counters": [
	  {
	    "name": "ip_frag",
	    "elements": [
	      {
	        "name": "none",
	        "severity": "info",
	        "type": "counter64",
	        "units": "packets",
	        "description": "packet fragmented"
	      },
	      {
	        "name": "small_packet",
	        "severity": "error",
	        "type": "counter64",
	        "units": "packets",
	        "description": "packet smaller than MTU"
	      },
	      // ...
	    ]
	  }
	],
	"paths": [
	    [
	      {
	        "path": "/err/ip-frag",
	        "counter": "ip_frag"
	      },
	      {
	        "path": "/err/mpls-frag",
	        "counter": "ip_frag"
	      },
		  // ...
		]
	]
}

We should consider adding support for this in the GoVPP. At the minimum we can add support to vppapi parser package so it is properly extracted from VPP API file.

Then, just brainstorming here, we could generate special file for this which could be used by the VPP Stats client in GoVPP for retrieving the stats data using defined paths and then structuring them according counters definition.

Disconnect Stats panic

your func:

func (c *StatsConnection) Disconnect() {
	if c == nil {
		return
	}
	if c.statsClient != nil {
		if err := c.statsClient.Disconnect(); err != nil {
			log.Debugf("disconnecting stats client failed: %v", err)
		}
	}
	close(c.connChan)
	close(c.done)
}

in another fiber:

case <-c.done:
	log.Debugf("health check watcher closed")
	c.sendStatsConnEvent(ConnectionEvent{Timestamp: time.Now(), State: Disconnected, Error: nil})
	return
}

func sendStatsConnEvent:

func (c *StatsConnection) sendStatsConnEvent(event ConnectionEvent) {
	select {
	case c.connChan <- event:
	default:
		log.Warn("Stats connection state channel is full, discarding value.")
	}
}

note this: case c.connChan <- event:
now the c.connChan is cloed,then panic

Fix generated RPC client for Dump+Reply requests

Intro

There are two types of dump requests in VPP API:

  1. Simple dump - send [dump] and receive [details, details, ..]
  2. Dump+Reply - send [dump] and received [details, details, .., reply]

Below is a code sample of generated code for Recv() method of RPC client for dumping output interfaces in nat44_ed VPP API:

func (c *serviceClient_Nat44EdOutputInterfaceGetClient) Recv() (*Nat44EdOutputInterfaceDetails, error) {
msg, err := c.Stream.RecvMsg()
if err != nil {
return nil, err
}
switch m := msg.(type) {
case *Nat44EdOutputInterfaceDetails:
return m, nil
case *Nat44EdOutputInterfaceGetReply:
err = c.Stream.Close()
if err != nil {
return nil, err
}
return nil, io.EOF
default:
return nil, fmt.Errorf("unexpected message: %T %v", m, m)
}
}

Current problems

The generated code for the RPC client for Dump+Reply requests does not provide access to the *Reply message that is received as last message. This practically makes the generated code unusable for users that need the *Reply message values, e.g. reply message often contains a Cursor field where its value is used in the next request.

Another problem is that the Retval field from the *Reply is not converted to error.

Possible solutions

There are at least three alternative solutions that could be implemented to fix this.

1. SOLUTION

Add another method RecvReply() to dump client

When calling Recv() and receiving io.EOF error, the actual *Reply message received would be stored to a field of dump client and user would call RecvReply() (placeholder name) to receive it.

type RPCService_Nat44EdOutputInterfaceGetClient interface {
	Recv() (*Nat44EdOutputInterfaceDetails, error)
	RecvReply() *Nat44EdOutputInterfaceGetReply
	api.Stream
}

CONS:

  • requires user to do extra call after receiving io.EOF

2. SOLUTION

Define union-like type and return it instead of *Details

When calling Recv() and receiving io.EOF error, the return value would only have *Reply message set otherwise only *Details message would be set.

type Nat44EdOutputInterfaceGetX struct {
	Details *Nat44EdOutputInterfaceDetails
	Reply *Nat44EdOutputInterfaceGetReply
}

type RPCService_Nat44EdOutputInterfaceGetClient interface {
	Recv() (*Nat44EdOutputInterfaceGetX, error)
	api.Stream
}

CONS:

  • requires definition of special helper type

3. SOLUTION

Return 3 values from Recv()

When calling Recv() and receiving io.EOF error, the actual *Reply message received would be returned as second return value, otherwise only *Details or error would be non-nil.

type RPCService_Nat44EdOutputInterfaceGetClient interface {
	Recv() (*Nat44EdOutputInterfaceDetails, *Nat44EdOutputInterfaceGetReply, error)
	api.Stream
}

CONS:

  • ??

I am personally for solution 3 as I do not see any disadvantages for it.


CC @edwarnicke @sknat

panic in the stats element

Hello,
We are facing a panic issue in the stats element:

panic: runtime error: index out of range [9] with length 9

goroutine 11380 [running]:
go.fd.io/govpp/adapter/statsclient.(*statSegmentV2).UpdateEntryData(0x430?, 0x7f62c4c3aa60, 0xc000cfdff8)
	/root/go/pkg/mod/go.fd.io/[email protected]/adapter/statsclient/statseg_v2.go:354 +0x77c
go.fd.io/govpp/adapter/statsclient.(*StatsClient).updateStatOnIndex(0xc000200690, 0xc000cfdfc8, 0xc000fde3e8?)
	/root/go/pkg/mod/go.fd.io/[email protected]/adapter/statsclient/statsclient.go:633 +0x171
go.fd.io/govpp/adapter/statsclient.(*StatsClient).UpdateDir(0xc000200690, 0xc0008ecba0)
	/root/go/pkg/mod/go.fd.io/[email protected]/adapter/statsclient/statsclient.go:294 +0x1e7
go.fd.io/govpp/core.(*StatsConnection).updateStats.func1()
	/root/go/pkg/mod/go.fd.io/[email protected]/core/stats.go:220 +0x5b
go.fd.io/govpp/core.(*StatsConnection).updateStats(0xc000fde638?, 0x6dce3e?, {0xc00096b1a0?, 0xc00036c3f0?, 0x1488630?})
	/root/go/pkg/mod/go.fd.io/[email protected]/core/stats.go:231 +0xc4
go.fd.io/govpp/core.(*StatsConnection).GetInterfaceStats(0xc000912c60, 0xc000fde818)
	/root/go/pkg/mod/go.fd.io/[email protected]/core/stats.go:385 +0x7e

Most likely, interfaces are created in parallel. Or probably GetInterfaceStats is called from different goroutines.

Do you have any ideas how to fix this?

Create User Guide document

This issue tracks progress of creating User Guide document for using GoVPP.

Here are few ideas for topics to cover:

  • How to use Binary API generator (some of this already covered in docs/GENERATOR.md but might need updating)
  • How to call VPP API - Channel vs Stream
  • How to use generated RPC client
  • How to use Stats interfaces - StatsAPI vs StatsProvider (posted by @VladoLavor in #60)
  • πŸ€” ... add more ideas ...

Verify auto release process works

This issues tracks progress for testing the recently added CI pipeline (GitHub Workflow) - Release. It is expected to automatically run all steps defined in .goreleaser.yml file and generate GitHub release and publish docker images to GitHub Container Registry.

Move generated binapi

This issue tracks progress for moving the generated Go bindings located currently in binapi directory outside of the main module.

List of tasks related to this:

  • remove all dependency on binapi packages from the GoVPP client code

Considering these approaches:

  1. move the binapi folder under examples and make examples a Go sub-module
  • this way we still keep the generated code for the purpose of comparing changes to generator
  • allows examples to still use the generated code for the usage demonstration
  • will require examples to depend on main module (go.fd.io/govpp) - specific version or local replace
  1. remove the binapi folder from master branch and use dedicated branch(es) containing only the generated code
  • this way we could generated binapi code for multiple VPP versions, either separate branches for each version: binapi/2202, binapi/2210.. or single branch binapi with directory for each VPP version

Stream API & RPC services

This issue tracks progress of design & implementation of new Stream API & generated RPC services.
This post will be updated over time to provide all the relevant info.


Stream API

The GoVPP originally came with Channels for sending and receiving messages, which supported normal requests (request/reply) types, multi-request (dump/details) and subscriptions (want/event). Internally it came with buffered channels (100 capacity by default).

Old Channel API

Code
// ChannelProvider provides the communication channel with govpp core.
type ChannelProvider interface {
	// NewAPIChannel returns a new channel for communication with VPP via govpp core.
	// It uses default buffer sizes for the request and reply Go channels.
	NewAPIChannel() (Channel, error)

	// NewAPIChannelBuffered returns a new channel for communication with VPP via govpp core.
	// It allows to specify custom buffer sizes for the request and reply Go channels.
	NewAPIChannelBuffered(reqChanBufSize, replyChanBufSize int) (Channel, error)
}

// Channel provides methods for direct communication with VPP channel.
type Channel interface {
	// SendRequest asynchronously sends a request to VPP. Returns a request context, that can be used to call ReceiveReply.
	// In case of any errors by sending, the error will be delivered to ReplyChan (and returned by ReceiveReply).
	SendRequest(msg Message) RequestCtx

	// SendMultiRequest asynchronously sends a multipart request (request to which multiple responses are expected) to VPP.
	// Returns a multipart request context, that can be used to call ReceiveReply.
	// In case of any errors by sending, the error will be delivered to ReplyChan (and returned by ReceiveReply).
	SendMultiRequest(msg Message) MultiRequestCtx

	// SubscribeNotification subscribes for receiving of the specified notification messages via provided Go channel.
	// Note that the caller is responsible for creating the Go channel with preferred buffer size. If the channel's
	// buffer is full, the notifications will not be delivered into it.
	SubscribeNotification(notifChan chan Message, event Message) (SubscriptionCtx, error)

	// SetReplyTimeout sets the timeout for replies from VPP. It represents the maximum time the API waits for a reply
	// from VPP before returning an error.
	SetReplyTimeout(timeout time.Duration)

	// CheckCompatibility checks the compatiblity for the given messages.
	// It will return an error if any of the given messages are not compatible.
	CheckCompatiblity(msgs ...Message) error

	// Close closes the API channel and releases all API channel-related resources
	// in the ChannelProvider.
	Close()
}

// RequestCtx is helper interface which allows to receive reply on request.
type RequestCtx interface {
	// ReceiveReply receives a reply from VPP (blocks until a reply is delivered
	// from VPP, or until an error occurs). The reply will be decoded into the msg
	// argument. Error will be returned if the response cannot be received or decoded.
	ReceiveReply(msg Message) error
}

// MultiRequestCtx is helper interface which allows to receive reply on multi-request.
type MultiRequestCtx interface {
	// ReceiveReply receives a reply from VPP (blocks until a reply is delivered
	// from VPP, or until an error occurs).The reply will be decoded into the msg
	// argument. If the last reply has been already consumed, lastReplyReceived is
	// set to true. Do not use the message itself if lastReplyReceived is
	// true - it won't be filled with actual data.Error will be returned if the
	// response cannot be received or decoded.
	ReceiveReply(msg Message) (lastReplyReceived bool, err error)
}

// SubscriptionCtx is helper interface which allows to control subscription for
// notification events.
type SubscriptionCtx interface {
	// Unsubscribe unsubscribes from receiving the notifications tied to the
	// subscription context.
	Unsubscribe() error
}

However this Channel API could not be used for some new types of multi-requests (dump/details+reply) that VPP later introduced. This new type of requests could not work with the old Channel API since it was not possible to receive message without knowing exactly what type of message comes (receiving message was a parameter not a return value). The implementation of Channels also does several stuff behind the scenes which were either not very controllable by user (sending ControlPing for multi-requests) or just plain inefficient (using reflect to get Retval field).

For this reasons we introduced new API for sending and receiving messages: Stream.

New Stream API

Code
// Connection represents the client connection to VPP API.
//
// NOTE: This API is EXPERIMENTAL.
type Connection interface {
	// NewStream creates a new stream for sending and receiving messages.
	// Context can be used to close the stream using cancel or timeout.
	NewStream(ctx context.Context, options ...StreamOption) (Stream, error)

	// Invoke can be used for a simple request-reply RPC.
	// It creates stream and calls SendMsg with req and RecvMsg which returns
	// reply.
	Invoke(ctx context.Context, req Message, reply Message) error
}

// Stream provides low-level access for sending and receiving messages.
// Users should handle correct type and ordering of messages.
//
// It is not safe to call these methods on the same stream in different
// goroutines.
//
// NOTE: This API is EXPERIMENTAL.
type Stream interface {
	// SendMsg sends a message to the client.
	// It blocks until message is sent to the transport.
	SendMsg(Message) error

	// RecvMsg blocks until a message is received or error occurs.
	RecvMsg() (Message, error)

	// Close closes the stream. Calling SendMsg and RecvMsg will return error
	// after closing stream.
	Close() error
}

// StreamOption allows customizing a Stream. Available options are:
// - WithRequestSize
// - WithReplySize
// - WithReplyTimeout
type StreamOption func(Stream)

This new API is supposed to be less restrictive and much simpler. This means it does not try to do any assumptions about the semantics of the VPP API requests. It only has two methods for messages: SendMsg(Message) error and RecvMsg() (Message, error).

However, the new Stream API does not currently come with completely new implementation and for time/cycles reasons it still uses the channel implementation under the hood. This means it creates a new channel for each stream which brings some extra overhead which is not even necessary or even used.

The plan is to switch the Stream to a new implementation which would get rid of the channels and provide much more efficient way.

TBD

RPC services

With the new Stream API, being so low-level, users would have to do much of the things done by Channels before themselves; e.g. send ControlPings after each dump manually. For this reasons we also introduced generated RPC methods, where each generate binapi package came with a service interface and also client implementation of this interface where all of the boilerplate was automatically generated.

Here is example code using raw sending (Channel): https://github.com/FDio/govpp/blob/master/examples/simple-client/simple_client.go
Here is example code using RPCs (Stream): https://github.com/FDio/govpp/blob/master/examples/rpc-service/rpc_service.go

The generated RPCs have made it possible to get rid of the boilerplate and allow users to use simple methods. For those who are familiar with Protobuf and gRPC, this has been very similar in that way.

The generated code for RPC takes care of:

  • matching correct Request/Response message pairs of the particular service
  • handling the Retval value and returning error in case it's non-zero
  • sending extra ControlPing request after dumps
  • handling correct message type for special dump requests (dump/details/reply)
  • allowing to pass the context.Context value from the user to the actual requests processing

TBD

ubuntu 22.04 apt update issue after adding the repo

followed here but doesnt work on ubuntu 22.04

https://fd.io/gettingstarted/installing/

W: https://packagecloud.io/fdio/release/ubuntu/dists/bionic/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
W: https://packagecloud.io/fdio/master/ubuntu/dists/bionic/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.

Support VPP API comments

Comments in VPP API

The VPP API source files (*.api) have always contained comments. These comments contain helpful information for the users of VPP API and for some requests they are often necessary to understand what some fields do. However, until recently, these comments have not been included in the generated VPP API JSON files (*.api.json).

Here is a sample of vpe.show_vpe_system_time_reply in vpe.api:

/** \brief Reply for show vpe system time.
    @param context - sender context which was passed in the request
    @param retval - return value
    @param vpe_system_time - the time in seconds since epoch of the host system.
*/
define show_vpe_system_time_reply
{
  u32 context;
  i32 retval;
  vl_api_timestamp_t vpe_system_time;
};

Now, with the upcoming release of VPP 23.02 (or latest VPP from master branch), the comments are now part of message metadata for all messages that have comments.

Gerrit change: vppapigen: include comments in json

Here is a sample for vpe.show_vpe_system_time_reply message in vpe.api.json:

	[
	  "show_vpe_system_time_reply",
	  [
	      "u16",
	      "_vl_msg_id"
	  ],
	  [
	      "u32",
	      "context"
	  ],
	  [
	      "i32",
	      "retval"
	  ],
	  [
	      "vl_api_timestamp_t",
	      "vpe_system_time"
	  ],
	  {
	      "crc": "0x7ffd8193",
	      "options": {},
	      "comment": "/** \\brief Reply for show vpe system time.\n    @param context - sender context which was passed in the request\n    @param retval - return value\n    @param vpe_system_time - the time in seconds since epoch of the host system.\n*/"
	  }
	]
Full content of vpe.api.json:
{
    "types": [
        [
            "version",
            [
                "u32",
                "major"
            ],
            [
                "u32",
                "minor"
            ],
            [
                "u32",
                "patch"
            ],
            [
                "u8",
                "pre_release",
                17
            ],
            [
                "u8",
                "build_metadata",
                17
            ]
        ]
    ],
    "messages": [
        [
            "show_version",
            [
                "u16",
                "_vl_msg_id"
            ],
            [
                "u32",
                "client_index"
            ],
            [
                "u32",
                "context"
            ],
            {
                "crc": "0x51077d14",
                "options": {},
                "comment": "/** \\brief show version\n    @param client_index - opaque cookie to identify the sender\n    @param context - sender context, to match reply w/ request\n*/"
            }
        ],
        [
            "show_version_reply",
            [
                "u16",
                "_vl_msg_id"
            ],
            [
                "u32",
                "context"
            ],
            [
                "i32",
                "retval"
            ],
            [
                "string",
                "program",
                32
            ],
            [
                "string",
                "version",
                32
            ],
            [
                "string",
                "build_date",
                32
            ],
            [
                "string",
                "build_directory",
                256
            ],
            {
                "crc": "0xc919bde1",
                "options": {},
                "comment": "/** \\brief show version response\n    @param context - sender context, to match reply w/ request\n    @param retval - return code for the request\n    @param program - name of the program (vpe)\n    @param version  - version of the program\n    @param build_directory - root of the workspace where the program was built\n*/"
            }
        ],
        [
            "show_vpe_system_time",
            [
                "u16",
                "_vl_msg_id"
            ],
            [
                "u32",
                "client_index"
            ],
            [
                "u32",
                "context"
            ],
            {
                "crc": "0x51077d14",
                "options": {},
                "comment": "/** \\brief Show the current system timestamp.\n    @param client_index - opaque cookie to identify the sender\n    @param context - sender context, to match reply w/ request\n*/"
            }
        ],
        [
            "show_vpe_system_time_reply",
            [
                "u16",
                "_vl_msg_id"
            ],
            [
                "u32",
                "context"
            ],
            [
                "i32",
                "retval"
            ],
            [
                "vl_api_timestamp_t",
                "vpe_system_time"
            ],
            {
                "crc": "0x7ffd8193",
                "options": {},
                "comment": "/** \\brief Reply for show vpe system time.\n    @param context - sender context which was passed in the request\n    @param retval - return value\n    @param vpe_system_time - the time in seconds since epoch of the host system.\n*/"
            }
        ],
        [
            "log_dump",
            [
                "u16",
                "_vl_msg_id"
            ],
            [
                "u32",
                "client_index"
            ],
            [
                "u32",
                "context"
            ],
            [
                "vl_api_timestamp_t",
                "start_timestamp"
            ],
            {
                "crc": "0x6ab31753",
                "options": {},
                "comment": "/** \\brief Reply for show vpe system time.\n    @param context - sender context which was passed in the request\n    @param retval - return value\n    @param vpe_system_time - the time in seconds since epoch of the host system.\n*/"
            }
        ],
        [
            "log_details",
            [
                "u16",
                "_vl_msg_id"
            ],
            [
                "u32",
                "context"
            ],
            [
                "vl_api_timestamp_t",
                "timestamp"
            ],
            [
                "vl_api_log_level_t",
                "level"
            ],
            [
                "string",
                "msg_class",
                32
            ],
            [
                "string",
                "message",
                256
            ],
            {
                "crc": "0x03d61cc0",
                "options": {},
                "comment": "/** \\brief Reply for show vpe system time.\n    @param context - sender context which was passed in the request\n    @param retval - return value\n    @param vpe_system_time - the time in seconds since epoch of the host system.\n*/"
            }
        ]
    ],
    "unions": [],
    "enums": [
        [
            "log_level",
            [
                "VPE_API_LOG_LEVEL_EMERG",
                0
            ],
            [
                "VPE_API_LOG_LEVEL_ALERT",
                1
            ],
            [
                "VPE_API_LOG_LEVEL_CRIT",
                2
            ],
            [
                "VPE_API_LOG_LEVEL_ERR",
                3
            ],
            [
                "VPE_API_LOG_LEVEL_WARNING",
                4
            ],
            [
                "VPE_API_LOG_LEVEL_NOTICE",
                5
            ],
            [
                "VPE_API_LOG_LEVEL_INFO",
                6
            ],
            [
                "VPE_API_LOG_LEVEL_DEBUG",
                7
            ],
            [
                "VPE_API_LOG_LEVEL_DISABLED",
                8
            ],
            {
                "enumtype": "u32"
            }
        ]
    ],
    "enumflags": [],
    "services": {
        "show_version": {
            "reply": "show_version_reply"
        },
        "show_vpe_system_time": {
            "reply": "show_vpe_system_time_reply"
        },
        "log_dump": {
            "reply": "log_details",
            "stream": true
        }
    },
    "options": {
        "version": "1.7.0"
    },
    "aliases": {
        "timestamp": {
            "type": "f64"
        },
        "timedelta": {
            "type": "f64"
        }
    },
    "vl_api_version": "0xbbfa7484",
    "imports": [
        "vpp/api/vpe_types.api"
    ],
    "counters": [],
    "paths": []
}

Possible Implementation Alternatives in GoVPP

Alternative 1

At the very least, the generated binapi should add comment to each generate VPP API message, that has the comment defined, as-is.

Here is an example of generated message vpe.ShowVpeSystemTimeReply:

// ShowVpeSystemTimeReply defines message 'show_vpe_system_time_reply'.
//
//  Reply for show vpe system time.
//  - retval - return value
//  - vpe_system_time - the time in seconds since epoch of the host system.
//
type ShowVpeSystemTimeReply struct {
	Retval        int32               `binapi:"i32,name=retval" json:"retval,omitempty"`
	VpeSystemTime vpe_types.Timestamp `binapi:"timestamp,name=vpe_system_time" json:"vpe_system_time,omitempty"`
Show as diff
diff --git a/binapi/vpe/vpe.ba.go b/binapi/vpe/vpe.ba.go
--- a/binapi/vpe/vpe.ba.go	(revision 36a21f52113a896330b25a8426153f3ff132a152)
+++ b/binapi/vpe/vpe.ba.go	(date 1675073172453)
@@ -210,6 +210,11 @@
 }
 
 // ShowVpeSystemTimeReply defines message 'show_vpe_system_time_reply'.
+//
+//  Reply for show vpe system time.
+//  - retval - return value
+//  - vpe_system_time - the time in seconds since epoch of the host system.
+//
 type ShowVpeSystemTimeReply struct {
 	Retval        int32               `binapi:"i32,name=retval" json:"retval,omitempty"`
 	VpeSystemTime vpe_types.Timestamp `binapi:"timestamp,name=vpe_system_time" json:"vpe_system_time,omitempty"`
}

Alternative 2

However, ideally it would be much better if the comment would be processed and split into parts:

  • comment for message describing what the message does
  • comment for each field describing what the field does

Here is an example of generated message vpe.ShowVpeSystemTimeReply:

// ShowVpeSystemTimeReply defines message 'show_vpe_system_time_reply'.
//
//  Reply for show vpe system time.
//
type ShowVpeSystemTimeReply struct {
	// Retval - return value
	Retval        int32               `binapi:"i32,name=retval" json:"retval,omitempty"`
	// VpeSystemTime - the time in seconds since epoch of the host system.
	VpeSystemTime vpe_types.Timestamp `binapi:"timestamp,name=vpe_system_time" json:"vpe_system_time,omitempty"`
}
Show as diff
===================================================================
diff --git a/binapi/vpe/vpe.ba.go b/binapi/vpe/vpe.ba.go
--- a/binapi/vpe/vpe.ba.go	(revision 36a21f52113a896330b25a8426153f3ff132a152)
+++ b/binapi/vpe/vpe.ba.go	(date 1675073172453)
@@ -210,8 +210,13 @@
 }
 
 // ShowVpeSystemTimeReply defines message 'show_vpe_system_time_reply'.
+//
+//  Reply for show vpe system time.
+//
 type ShowVpeSystemTimeReply struct {
+	// Retval - return value
 	Retval        int32               `binapi:"i32,name=retval" json:"retval,omitempty"`
+	// VpeSystemTime - the time in seconds since epoch of the host system.
 	VpeSystemTime vpe_types.Timestamp `binapi:"timestamp,name=vpe_system_time" json:"vpe_system_time,omitempty"`
 }

Implementation steps

  • Parse - vppapi package
    • update the definition of vppapi.Message type to include Comment field
    • add parsing of the comment from options in messages
  • Process - binapigen package
    • define an exported func NormalizeComment(string)(string?) which processes a string value representing message comment
      • exclude comments for header fields (context, client_index..)
      • strip special syntax (\\brief, @param)
    • store the returned normalized value in binapigen.Message type as Comment
  • Generate
    • generate comment value as part of comment for generated message type

[vpp repo] Update make go-api-files procedure in VPP repo

In the VPP repository there is a make target go-api-files for generating Go bindings for VPP binary API from the local API files in the source code. The make target simply executes a Python script generate_go.py that runs go install to get the GoVPP binapi-generator. However it uses some arbitrary commit of GoVPP with the old import path git.fd.io/govpp.git that used before migration to GitHub.

The VPP repository should only use released versions of GoVPP.

Tasks:

  • update to new import path go.fd.io/govpp
  • replace global variable DefaultGoVppCommit=xxx with DefaultGoVppVersion=v0.6.0
  • replace the install procedure for GoVPP for Go older than 1.18 (which is the minimum version) with error "unsupported Go version, please install Go 1.18 or newer"

support for .tar.gz archives as input of govpp apigen

It would be nice to be able to pass an archive as an input to the apigen cli, i.e. :

//go:generate go run go.fd.io/govpp/cmd/binapi-generator --gen rpc -o ./bindings --input ./somefile.tar.gz

Where ./somefile.tar.gz contains

core/
  ip_types.api.json
  ip.api.json
  ...
plugins/
  abf.api.json
  acl.api.json
  ...

In some cases, the api specification is exchanged as a compressed bundle,
having this feature would spare the caller the hassle to (decompress ; pass the temporary directory as input ; cleanup)

Fix random failure of TestSetReplyTimeout

I have noticed that the test for setting reply timeout fails occasionally. Have not looked much deeper yet into the code, I suspect some timing issue or perhaps improper test procedure in the test case.

--- FAIL: TestSetReplyTimeout (0.02s)
    channel_test.go:199: 
        Unexpected error:
            <*errors.errorString | 0xc0003d4370>: {
                s: "no reply received within the timeout period 1ms",
            }
            no reply received within the timeout period 1ms
        occurred
FAIL
FAIL	go.fd.io/govpp/core	0.102s

You can reproduce this by running the tests 100 times:

go test -count 100 -failfast -race ./...

Run more steps in CI

To improve the quality of the code that is merged to master, the CI pipeline should perform more tests or checks for common things developers forget to update.

  • verify contents of go.mod file are up-to-date and go.sum is not missing any entry
  • add golangci-lint for linting and code checks
  • add base for integration/e2e tests against real VPP instances
  • run examples against master version of VPP and 2-3 recent VPP releases

Request for a tag

Hello, govpp folks!

We're interested in tagging the main branch with the fix: #172

Could you please provide an ETA for the next release that will include the fix?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.