blob: dfb236b6725772bff218bd2c2e46b82cfa6e831f [file] [log] [blame]
Adrian Villin4677d922024-06-14 09:32:39 +02001package hst
Maros Ondrejicka11a03e92022-12-01 09:56:37 +01002
3import (
Adrian Villin46d66002024-05-15 04:33:41 -04004 "context"
Matus Fabiane99d2662024-07-19 16:04:09 +02005 "encoding/json"
Filip Tehlarf3ee2b62023-01-09 12:07:09 +01006 "fmt"
Matus Fabian82ad9662024-06-04 19:00:00 +02007 "go.fd.io/govpp/binapi/ethernet_types"
Adrian Villin637edda2024-05-06 06:55:34 -04008 "io"
Matus Fabian82ad9662024-06-04 19:00:00 +02009 "net"
Filip Tehlarec5c40b2023-02-28 18:59:15 +010010 "os"
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010011 "os/exec"
Filip Tehlarec5c40b2023-02-28 18:59:15 +010012 "os/signal"
Filip Tehlar543cd572023-06-27 10:01:37 +020013 "strconv"
Maros Ondrejicka7550dd22023-02-07 20:40:27 +010014 "strings"
Filip Tehlarec5c40b2023-02-28 18:59:15 +010015 "syscall"
Maros Ondrejicka7550dd22023-02-07 20:40:27 +010016 "time"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010017
Filip Tehlar9abba112023-03-07 10:13:19 +010018 "github.com/edwarnicke/exechelper"
Adrian Villincee15aa2024-03-14 11:42:55 -040019 . "github.com/onsi/ginkgo/v2"
Adrian Villin46d66002024-05-15 04:33:41 -040020 "github.com/sirupsen/logrus"
Filip Tehlar9abba112023-03-07 10:13:19 +010021
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010022 "go.fd.io/govpp"
23 "go.fd.io/govpp/api"
24 "go.fd.io/govpp/binapi/af_packet"
25 interfaces "go.fd.io/govpp/binapi/interface"
26 "go.fd.io/govpp/binapi/interface_types"
27 "go.fd.io/govpp/binapi/session"
Maros Ondrejicka7550dd22023-02-07 20:40:27 +010028 "go.fd.io/govpp/binapi/tapv2"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010029 "go.fd.io/govpp/core"
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010030)
31
32const vppConfigTemplate = `unix {
33 nodaemon
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010034 log %[1]s%[4]s
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010035 full-coredump
36 cli-listen %[1]s%[2]s
37 runtime-dir %[1]s/var/run
38 gid vpp
39}
40
41api-trace {
42 on
43}
44
45api-segment {
46 gid vpp
47}
48
49socksvr {
Maros Ondrejicka7d7ab102023-02-14 12:56:49 +010050 socket-name %[1]s%[3]s
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010051}
52
53statseg {
54 socket-name %[1]s/var/run/vpp/stats.sock
55}
56
57plugins {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010058 plugin default { disable }
59
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010060 plugin unittest_plugin.so { enable }
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010061 plugin quic_plugin.so { enable }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010062 plugin af_packet_plugin.so { enable }
63 plugin hs_apps_plugin.so { enable }
64 plugin http_plugin.so { enable }
Filip Tehlarcc1475c2023-11-29 12:59:05 +010065 plugin http_static_plugin.so { enable }
66 plugin prom_plugin.so { enable }
Filip Tehlar3336eef2023-11-29 07:40:18 +010067 plugin tlsopenssl_plugin.so { enable }
Adrian Villincee15aa2024-03-14 11:42:55 -040068 plugin ping_plugin.so { enable }
Matus Fabianc899ab42024-04-22 13:42:00 +020069 plugin nsim_plugin.so { enable }
Matus Fabian82ad9662024-06-04 19:00:00 +020070 plugin mactime_plugin.so { enable }
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010071}
72
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010073logging {
74 default-log-level debug
75 default-syslog-log-level debug
76}
77
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010078`
79
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010080const (
81 defaultCliSocketFilePath = "/var/run/vpp/cli.sock"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010082 defaultApiSocketFilePath = "/var/run/vpp/api.sock"
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010083 defaultLogFilePath = "/var/log/vpp/vpp.log"
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010084)
85
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010086type VppInstance struct {
Adrian Villin4677d922024-06-14 09:32:39 +020087 Container *Container
88 AdditionalConfig []Stanza
89 Connection *core.Connection
90 ApiStream api.Stream
91 Cpus []int
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +020092 CpuConfig VppCpuConfig
93}
94
95type VppCpuConfig struct {
96 PinMainCpu bool
97 PinWorkersCorelist bool
98 SkipCores int
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010099}
100
Matus Fabiane99d2662024-07-19 16:04:09 +0200101type VppMemTrace struct {
102 Count int `json:"count"`
103 Size int `json:"bytes"`
104 Sample string `json:"sample"`
105 Traceback []string `json:"traceback"`
106}
107
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100108func (vpp *VppInstance) getSuite() *HstSuite {
Adrian Villin4677d922024-06-14 09:32:39 +0200109 return vpp.Container.Suite
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100110}
111
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100112func (vpp *VppInstance) getCliSocket() string {
Adrian Villin4677d922024-06-14 09:32:39 +0200113 return fmt.Sprintf("%s%s", vpp.Container.GetContainerWorkDir(), defaultCliSocketFilePath)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100114}
115
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100116func (vpp *VppInstance) getRunDir() string {
Adrian Villin4677d922024-06-14 09:32:39 +0200117 return vpp.Container.GetContainerWorkDir() + "/var/run/vpp"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100118}
119
120func (vpp *VppInstance) getLogDir() string {
Adrian Villin4677d922024-06-14 09:32:39 +0200121 return vpp.Container.GetContainerWorkDir() + "/var/log/vpp"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100122}
123
124func (vpp *VppInstance) getEtcDir() string {
Adrian Villin4677d922024-06-14 09:32:39 +0200125 return vpp.Container.GetContainerWorkDir() + "/etc/vpp"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100126}
127
Adrian Villin4677d922024-06-14 09:32:39 +0200128func (vpp *VppInstance) Start() error {
Adrian Villin93974e22024-05-30 06:10:59 -0400129 maxReconnectAttempts := 3
Adrian Villin637edda2024-05-06 06:55:34 -0400130 // Replace default logger in govpp with our own
131 govppLogger := logrus.New()
Adrian Villin4677d922024-06-14 09:32:39 +0200132 govppLogger.SetOutput(io.MultiWriter(vpp.getSuite().Logger.Writer(), GinkgoWriter))
Adrian Villin637edda2024-05-06 06:55:34 -0400133 core.SetLogger(govppLogger)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100134 // Create folders
Adrian Villin4677d922024-06-14 09:32:39 +0200135 containerWorkDir := vpp.Container.GetContainerWorkDir()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100136
Adrian Villin4677d922024-06-14 09:32:39 +0200137 vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getRunDir())
138 vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getLogDir())
139 vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getEtcDir())
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100140
141 // Create startup.conf inside the container
Maros Ondrejicka7d7ab102023-02-14 12:56:49 +0100142 configContent := fmt.Sprintf(
Maros Ondrejicka300f70d2023-02-21 10:53:20 +0100143 vppConfigTemplate,
144 containerWorkDir,
145 defaultCliSocketFilePath,
146 defaultApiSocketFilePath,
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100147 defaultLogFilePath,
Maros Ondrejicka300f70d2023-02-21 10:53:20 +0100148 )
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200149 configContent += vpp.generateVPPCpuConfig()
Adrian Villin4677d922024-06-14 09:32:39 +0200150 for _, c := range vpp.AdditionalConfig {
151 configContent += c.ToString()
Filip Tehlar608d0062023-04-28 10:29:47 +0200152 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100153 startupFileName := vpp.getEtcDir() + "/startup.conf"
Adrian Villin4677d922024-06-14 09:32:39 +0200154 vpp.Container.CreateFile(startupFileName, configContent)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100155
Filip Tehlar1a661502023-03-08 11:55:50 +0100156 // create wrapper script for vppctl with proper CLI socket path
157 cliContent := "#!/usr/bin/bash\nvppctl -s " + vpp.getRunDir() + "/cli.sock"
158 vppcliFileName := "/usr/bin/vppcli"
Adrian Villin4677d922024-06-14 09:32:39 +0200159 vpp.Container.CreateFile(vppcliFileName, cliContent)
160 vpp.Container.Exec("chmod 0755 " + vppcliFileName)
Filip Tehlar1a661502023-03-08 11:55:50 +0100161
Adrian Villin4677d922024-06-14 09:32:39 +0200162 vpp.getSuite().Log("starting vpp")
163 if *IsVppDebug {
Adrian Villin93974e22024-05-30 06:10:59 -0400164 // default = 3; VPP will timeout while debugging if there are not enough attempts
165 maxReconnectAttempts = 5000
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100166 sig := make(chan os.Signal, 1)
Adrian Villincee15aa2024-03-14 11:42:55 -0400167 signal.Notify(sig, syscall.SIGQUIT)
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100168 cont := make(chan bool, 1)
169 go func() {
Filip Tehlar9abba112023-03-07 10:13:19 +0100170 <-sig
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100171 cont <- true
172 }()
173
Adrian Villin4677d922024-06-14 09:32:39 +0200174 vpp.Container.ExecServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100175 fmt.Println("run following command in different terminal:")
Adrian Villin4677d922024-06-14 09:32:39 +0200176 fmt.Println("docker exec -it " + vpp.Container.Name + " gdb -ex \"attach $(docker exec " + vpp.Container.Name + " pidof vpp)\"")
Adrian Villincee15aa2024-03-14 11:42:55 -0400177 fmt.Println("Afterwards press CTRL+\\ to continue")
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100178 <-cont
179 fmt.Println("continuing...")
180 } else {
181 // Start VPP
Adrian Villin4677d922024-06-14 09:32:39 +0200182 vpp.Container.ExecServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100183 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100184
Adrian Villin4677d922024-06-14 09:32:39 +0200185 vpp.getSuite().Log("connecting to vpp")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100186 // Connect to VPP and store the connection
Adrian Villin4677d922024-06-14 09:32:39 +0200187 sockAddress := vpp.Container.GetHostWorkDir() + defaultApiSocketFilePath
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100188 conn, connEv, err := govpp.AsyncConnect(
189 sockAddress,
Adrian Villin93974e22024-05-30 06:10:59 -0400190 maxReconnectAttempts,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100191 core.DefaultReconnectInterval)
192 if err != nil {
Adrian Villin4677d922024-06-14 09:32:39 +0200193 vpp.getSuite().Log("async connect error: " + fmt.Sprint(err))
Filip Tehlar56e17cf2024-01-11 17:17:33 +0100194 return err
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100195 }
Adrian Villin4677d922024-06-14 09:32:39 +0200196 vpp.Connection = conn
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100197
198 // ... wait for Connected event
199 e := <-connEv
200 if e.State != core.Connected {
Adrian Villin4677d922024-06-14 09:32:39 +0200201 vpp.getSuite().Log("connecting to VPP failed: " + fmt.Sprint(e.Error))
Hadi Rayan Al-Sandid0eccf452024-06-24 10:48:54 +0200202 return e.Error
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100203 }
204
Adrian Villin46d66002024-05-15 04:33:41 -0400205 ch, err := conn.NewStream(
206 context.Background(),
207 core.WithRequestSize(50),
208 core.WithReplySize(50),
Adrian Villin93974e22024-05-30 06:10:59 -0400209 core.WithReplyTimeout(time.Second*5))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100210 if err != nil {
Adrian Villin4677d922024-06-14 09:32:39 +0200211 vpp.getSuite().Log("creating stream failed: " + fmt.Sprint(err))
Filip Tehlar56e17cf2024-01-11 17:17:33 +0100212 return err
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100213 }
Adrian Villin4677d922024-06-14 09:32:39 +0200214 vpp.ApiStream = ch
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100215
216 return nil
217}
218
Adrian Villin4677d922024-06-14 09:32:39 +0200219func (vpp *VppInstance) Vppctl(command string, arguments ...any) string {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100220 vppCliCommand := fmt.Sprintf(command, arguments...)
221 containerExecCommand := fmt.Sprintf("docker exec --detach=false %[1]s vppctl -s %[2]s %[3]s",
Adrian Villin4677d922024-06-14 09:32:39 +0200222 vpp.Container.Name, vpp.getCliSocket(), vppCliCommand)
223 vpp.getSuite().Log(containerExecCommand)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100224 output, err := exechelper.CombinedOutput(containerExecCommand)
Adrian Villin4677d922024-06-14 09:32:39 +0200225 vpp.getSuite().AssertNil(err)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100226
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100227 return string(output)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100228}
229
Filip Tehlar543cd572023-06-27 10:01:37 +0200230func (vpp *VppInstance) GetSessionStat(stat string) int {
Adrian Villin4677d922024-06-14 09:32:39 +0200231 o := vpp.Vppctl("show session stats")
232 vpp.getSuite().Log(o)
Filip Tehlar543cd572023-06-27 10:01:37 +0200233 for _, line := range strings.Split(o, "\n") {
234 if strings.Contains(line, stat) {
235 tokens := strings.Split(strings.TrimSpace(line), " ")
236 val, err := strconv.Atoi(tokens[0])
237 if err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -0400238 Fail("failed to parse stat value %s" + fmt.Sprint(err))
Filip Tehlar543cd572023-06-27 10:01:37 +0200239 return 0
240 }
241 return val
242 }
243 }
244 return 0
245}
246
Adrian Villin4677d922024-06-14 09:32:39 +0200247func (vpp *VppInstance) WaitForApp(appName string, timeout int) {
248 vpp.getSuite().Log("waiting for app " + appName)
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100249 for i := 0; i < timeout; i++ {
Adrian Villin4677d922024-06-14 09:32:39 +0200250 o := vpp.Vppctl("show app")
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100251 if strings.Contains(o, appName) {
Maros Ondrejickac2f76f42023-02-27 13:22:45 +0100252 return
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100253 }
254 time.Sleep(1 * time.Second)
Maros Ondrejickadb823ed2022-12-14 16:30:04 +0100255 }
Adrian Villin4677d922024-06-14 09:32:39 +0200256 vpp.getSuite().AssertNil(1, "Timeout while waiting for app '%s'", appName)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100257}
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100258
259func (vpp *VppInstance) createAfPacket(
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100260 veth *NetInterface,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100261) (interface_types.InterfaceIndex, error) {
Adrian Villin46d66002024-05-15 04:33:41 -0400262 createReq := &af_packet.AfPacketCreateV3{
263 Mode: 1,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100264 UseRandomHwAddr: true,
265 HostIfName: veth.Name(),
Adrian Villin46d66002024-05-15 04:33:41 -0400266 Flags: af_packet.AfPacketFlags(11),
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100267 }
Adrian Villin4677d922024-06-14 09:32:39 +0200268 if veth.HwAddress != (MacAddress{}) {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100269 createReq.UseRandomHwAddr = false
Adrian Villin4677d922024-06-14 09:32:39 +0200270 createReq.HwAddr = veth.HwAddress
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100271 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100272
Adrian Villin4677d922024-06-14 09:32:39 +0200273 vpp.getSuite().Log("create af-packet interface " + veth.Name())
274 if err := vpp.ApiStream.SendMsg(createReq); err != nil {
275 vpp.getSuite().HstFail()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100276 return 0, err
277 }
Adrian Villin4677d922024-06-14 09:32:39 +0200278 replymsg, err := vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400279 if err != nil {
280 return 0, err
281 }
282 reply := replymsg.(*af_packet.AfPacketCreateV3Reply)
283 err = api.RetvalToVPPApiError(reply.Retval)
284 if err != nil {
285 return 0, err
286 }
287
Adrian Villin4677d922024-06-14 09:32:39 +0200288 veth.Index = reply.SwIfIndex
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100289
290 // Set to up
291 upReq := &interfaces.SwInterfaceSetFlags{
Adrian Villin4677d922024-06-14 09:32:39 +0200292 SwIfIndex: veth.Index,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100293 Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
294 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100295
Adrian Villin4677d922024-06-14 09:32:39 +0200296 vpp.getSuite().Log("set af-packet interface " + veth.Name() + " up")
297 if err := vpp.ApiStream.SendMsg(upReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400298 return 0, err
299 }
Adrian Villin4677d922024-06-14 09:32:39 +0200300 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400301 if err != nil {
302 return 0, err
303 }
304 reply2 := replymsg.(*interfaces.SwInterfaceSetFlagsReply)
305 if err = api.RetvalToVPPApiError(reply2.Retval); err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100306 return 0, err
307 }
308
309 // Add address
Adrian Villin4677d922024-06-14 09:32:39 +0200310 if veth.AddressWithPrefix() == (AddressWithPrefix{}) {
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100311 var err error
312 var ip4Address string
Adrian Villin4677d922024-06-14 09:32:39 +0200313 if ip4Address, err = veth.Ip4AddrAllocator.NewIp4InterfaceAddress(veth.Peer.NetworkNumber); err == nil {
314 veth.Ip4Address = ip4Address
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100315 } else {
316 return 0, err
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100317 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100318 }
319 addressReq := &interfaces.SwInterfaceAddDelAddress{
320 IsAdd: true,
Adrian Villin4677d922024-06-14 09:32:39 +0200321 SwIfIndex: veth.Index,
322 Prefix: veth.AddressWithPrefix(),
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100323 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100324
Adrian Villin4677d922024-06-14 09:32:39 +0200325 vpp.getSuite().Log("af-packet interface " + veth.Name() + " add address " + veth.Ip4Address)
326 if err := vpp.ApiStream.SendMsg(addressReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400327 return 0, err
328 }
Adrian Villin4677d922024-06-14 09:32:39 +0200329 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400330 if err != nil {
331 return 0, err
332 }
333 reply3 := replymsg.(*interfaces.SwInterfaceAddDelAddressReply)
334 err = api.RetvalToVPPApiError(reply3.Retval)
335 if err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100336 return 0, err
337 }
338
Adrian Villin4677d922024-06-14 09:32:39 +0200339 return veth.Index, nil
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100340}
341
342func (vpp *VppInstance) addAppNamespace(
343 secret uint64,
344 ifx interface_types.InterfaceIndex,
345 namespaceId string,
346) error {
Adrian Villin46d66002024-05-15 04:33:41 -0400347 req := &session.AppNamespaceAddDelV4{
348 IsAdd: true,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100349 Secret: secret,
350 SwIfIndex: ifx,
351 NamespaceID: namespaceId,
Adrian Villin46d66002024-05-15 04:33:41 -0400352 SockName: defaultApiSocketFilePath,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100353 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100354
Adrian Villin4677d922024-06-14 09:32:39 +0200355 vpp.getSuite().Log("add app namespace " + namespaceId)
356 if err := vpp.ApiStream.SendMsg(req); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400357 return err
358 }
Adrian Villin4677d922024-06-14 09:32:39 +0200359 replymsg, err := vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400360 if err != nil {
361 return err
362 }
363 reply := replymsg.(*session.AppNamespaceAddDelV4Reply)
364 if err = api.RetvalToVPPApiError(reply.Retval); err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100365 return err
366 }
367
368 sessionReq := &session.SessionEnableDisable{
369 IsEnable: true,
370 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100371
Adrian Villin4677d922024-06-14 09:32:39 +0200372 vpp.getSuite().Log("enable app namespace " + namespaceId)
373 if err := vpp.ApiStream.SendMsg(sessionReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400374 return err
375 }
Adrian Villin4677d922024-06-14 09:32:39 +0200376 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400377 if err != nil {
378 return err
379 }
380 reply2 := replymsg.(*session.SessionEnableDisableReply)
381 if err = api.RetvalToVPPApiError(reply2.Retval); err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100382 return err
383 }
384
385 return nil
386}
387
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100388func (vpp *VppInstance) createTap(
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100389 tap *NetInterface,
Maros Ondrejickac2f76f42023-02-27 13:22:45 +0100390 tapId ...uint32,
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100391) error {
Maros Ondrejickac2f76f42023-02-27 13:22:45 +0100392 var id uint32 = 1
393 if len(tapId) > 0 {
394 id = tapId[0]
395 }
Adrian Villin46d66002024-05-15 04:33:41 -0400396 createTapReq := &tapv2.TapCreateV3{
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100397 ID: id,
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100398 HostIfNameSet: true,
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100399 HostIfName: tap.Name(),
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100400 HostIP4PrefixSet: true,
Adrian Villin4677d922024-06-14 09:32:39 +0200401 HostIP4Prefix: tap.Ip4AddressWithPrefix(),
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100402 }
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100403
Adrian Villin4677d922024-06-14 09:32:39 +0200404 vpp.getSuite().Log("create tap interface " + tap.Name())
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100405 // Create tap interface
Adrian Villin4677d922024-06-14 09:32:39 +0200406 if err := vpp.ApiStream.SendMsg(createTapReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400407 return err
408 }
Adrian Villin4677d922024-06-14 09:32:39 +0200409 replymsg, err := vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400410 if err != nil {
411 return err
412 }
413 reply := replymsg.(*tapv2.TapCreateV3Reply)
414 if err = api.RetvalToVPPApiError(reply.Retval); err != nil {
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100415 return err
416 }
Adrian Villin4677d922024-06-14 09:32:39 +0200417 tap.Peer.Index = reply.SwIfIndex
Matus Fabian82ad9662024-06-04 19:00:00 +0200418
419 // Get name and mac
Adrian Villin4677d922024-06-14 09:32:39 +0200420 if err := vpp.ApiStream.SendMsg(&interfaces.SwInterfaceDump{
Matus Fabian82ad9662024-06-04 19:00:00 +0200421 SwIfIndex: reply.SwIfIndex,
422 }); err != nil {
423 return err
424 }
Adrian Villin4677d922024-06-14 09:32:39 +0200425 replymsg, err = vpp.ApiStream.RecvMsg()
Matus Fabian82ad9662024-06-04 19:00:00 +0200426 if err != nil {
427 return err
428 }
429 ifDetails := replymsg.(*interfaces.SwInterfaceDetails)
Adrian Villin4677d922024-06-14 09:32:39 +0200430 tap.Peer.name = ifDetails.InterfaceName
431 tap.Peer.HwAddress = ifDetails.L2Address
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100432
433 // Add address
434 addAddressReq := &interfaces.SwInterfaceAddDelAddress{
435 IsAdd: true,
Adrian Villin46d66002024-05-15 04:33:41 -0400436 SwIfIndex: reply.SwIfIndex,
Adrian Villin4677d922024-06-14 09:32:39 +0200437 Prefix: tap.Peer.AddressWithPrefix(),
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100438 }
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100439
Adrian Villin4677d922024-06-14 09:32:39 +0200440 vpp.getSuite().Log("tap interface " + tap.Name() + " add address " + tap.Peer.Ip4Address)
441 if err := vpp.ApiStream.SendMsg(addAddressReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400442 return err
443 }
Adrian Villin4677d922024-06-14 09:32:39 +0200444 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400445 if err != nil {
446 return err
447 }
448 reply2 := replymsg.(*interfaces.SwInterfaceAddDelAddressReply)
449 if err = api.RetvalToVPPApiError(reply2.Retval); err != nil {
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100450 return err
451 }
452
453 // Set interface to up
454 upReq := &interfaces.SwInterfaceSetFlags{
Adrian Villin46d66002024-05-15 04:33:41 -0400455 SwIfIndex: reply.SwIfIndex,
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100456 Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
457 }
Adrian Villin4677d922024-06-14 09:32:39 +0200458
459 vpp.getSuite().Log("set tap interface " + tap.Name() + " up")
460 if err := vpp.ApiStream.SendMsg(upReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400461 return err
462 }
Adrian Villin4677d922024-06-14 09:32:39 +0200463 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400464 if err != nil {
465 return err
466 }
467 reply3 := replymsg.(*interfaces.SwInterfaceSetFlagsReply)
468 if err = api.RetvalToVPPApiError(reply3.Retval); err != nil {
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100469 return err
470 }
471
Matus Fabian82ad9662024-06-04 19:00:00 +0200472 // Get host mac
473 netIntf, err := net.InterfaceByName(tap.Name())
474 if err == nil {
Adrian Villin4677d922024-06-14 09:32:39 +0200475 tap.HwAddress, _ = ethernet_types.ParseMacAddress(netIntf.HardwareAddr.String())
Matus Fabian82ad9662024-06-04 19:00:00 +0200476 }
477
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100478 return nil
479}
480
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100481func (vpp *VppInstance) saveLogs() {
Adrian Villin4677d922024-06-14 09:32:39 +0200482 logTarget := vpp.Container.getLogDirPath() + "vppinstance-" + vpp.Container.Name + ".log"
483 logSource := vpp.Container.GetHostWorkDir() + defaultLogFilePath
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100484 cmd := exec.Command("cp", logSource, logTarget)
Adrian Villin4677d922024-06-14 09:32:39 +0200485 vpp.getSuite().Log(cmd.String())
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100486 cmd.Run()
487}
488
Adrian Villin4677d922024-06-14 09:32:39 +0200489func (vpp *VppInstance) Disconnect() {
490 vpp.Connection.Disconnect()
491 vpp.ApiStream.Close()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100492}
Filip Tehlar608d0062023-04-28 10:29:47 +0200493
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200494func (vpp *VppInstance) setDefaultCpuConfig() {
495 vpp.CpuConfig.PinMainCpu = true
496 vpp.CpuConfig.PinWorkersCorelist = true
497 vpp.CpuConfig.SkipCores = 0
498}
499
500func (vpp *VppInstance) generateVPPCpuConfig() string {
Filip Tehlar608d0062023-04-28 10:29:47 +0200501 var c Stanza
502 var s string
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200503 startCpu := 0
Adrian Villin4677d922024-06-14 09:32:39 +0200504 if len(vpp.Cpus) < 1 {
Filip Tehlar608d0062023-04-28 10:29:47 +0200505 return ""
506 }
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200507
508 c.NewStanza("cpu")
509
510 // If skip-cores is valid, use as start value to assign main/workers CPUs
511 if vpp.CpuConfig.SkipCores != 0 {
512 c.Append(fmt.Sprintf("skip-cores %d", vpp.CpuConfig.SkipCores))
513 vpp.getSuite().Log(fmt.Sprintf("skip-cores %d", vpp.CpuConfig.SkipCores))
514 }
515
516 if len(vpp.Cpus) > vpp.CpuConfig.SkipCores {
517 startCpu = vpp.CpuConfig.SkipCores
518 }
519
520 if vpp.CpuConfig.PinMainCpu {
521 c.Append(fmt.Sprintf("main-core %d", vpp.Cpus[startCpu]))
522 vpp.getSuite().Log(fmt.Sprintf("main-core %d", vpp.Cpus[startCpu]))
523 }
524
525 workers := vpp.Cpus[startCpu+1:]
Filip Tehlar608d0062023-04-28 10:29:47 +0200526
527 if len(workers) > 0 {
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200528 if vpp.CpuConfig.PinWorkersCorelist {
529 for i := 0; i < len(workers); i++ {
530 if i != 0 {
531 s = s + ", "
532 }
533 s = s + fmt.Sprintf("%d", workers[i])
Filip Tehlar608d0062023-04-28 10:29:47 +0200534 }
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200535 c.Append(fmt.Sprintf("corelist-workers %s", s))
536 vpp.getSuite().Log("corelist-workers " + s)
537 } else {
538 s = fmt.Sprintf("%d", len(workers))
539 c.Append(fmt.Sprintf("workers %s", s))
540 vpp.getSuite().Log("workers " + s)
Filip Tehlar608d0062023-04-28 10:29:47 +0200541 }
Filip Tehlar608d0062023-04-28 10:29:47 +0200542 }
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200543
Adrian Villin4677d922024-06-14 09:32:39 +0200544 return c.Close().ToString()
Filip Tehlar608d0062023-04-28 10:29:47 +0200545}
Matus Fabiane99d2662024-07-19 16:04:09 +0200546
547// EnableMemoryTrace enables memory traces of VPP main-heap
548func (vpp *VppInstance) EnableMemoryTrace() {
549 vpp.getSuite().Log(vpp.Vppctl("memory-trace on main-heap"))
550}
551
552// GetMemoryTrace dumps memory traces for analysis
553func (vpp *VppInstance) GetMemoryTrace() ([]VppMemTrace, error) {
554 var trace []VppMemTrace
555 vpp.getSuite().Log(vpp.Vppctl("save memory-trace trace.json"))
556 err := vpp.Container.GetFile("/tmp/trace.json", "/tmp/trace.json")
557 if err != nil {
558 return nil, err
559 }
560 fileBytes, err := os.ReadFile("/tmp/trace.json")
561 if err != nil {
562 return nil, err
563 }
564 err = json.Unmarshal(fileBytes, &trace)
565 if err != nil {
566 return nil, err
567 }
568 return trace, nil
569}
570
571// memTracesSuppressCli filter out CLI related samples
572func memTracesSuppressCli(traces []VppMemTrace) []VppMemTrace {
573 var filtered []VppMemTrace
574 for i := 0; i < len(traces); i++ {
575 isCli := false
576 for j := 0; j < len(traces[i].Traceback); j++ {
577 if strings.Contains(traces[i].Traceback[j], "unix_cli") {
578 isCli = true
579 break
580 }
581 }
582 if !isCli {
583 filtered = append(filtered, traces[i])
584 }
585 }
586 return filtered
587}
588
589// MemLeakCheck compares memory traces at different point in time, analyzes if memory leaks happen and produces report
590func (vpp *VppInstance) MemLeakCheck(first, second []VppMemTrace) {
591 totalBytes := 0
592 totalCounts := 0
593 trace1 := memTracesSuppressCli(first)
594 trace2 := memTracesSuppressCli(second)
595 report := ""
596 for i := 0; i < len(trace2); i++ {
597 match := false
598 for j := 0; j < len(trace1); j++ {
599 if trace1[j].Sample == trace2[i].Sample {
600 if trace2[i].Size > trace1[j].Size {
601 deltaBytes := trace2[i].Size - trace1[j].Size
602 deltaCounts := trace2[i].Count - trace1[j].Count
603 report += fmt.Sprintf("grow %d byte(s) in %d allocation(s) from:\n", deltaBytes, deltaCounts)
604 for j := 0; j < len(trace2[i].Traceback); j++ {
605 report += fmt.Sprintf("\t#%d %s\n", j, trace2[i].Traceback[j])
606 }
607 totalBytes += deltaBytes
608 totalCounts += deltaCounts
609 }
610 match = true
611 break
612 }
613 }
614 if !match {
615 report += fmt.Sprintf("\nleak of %d byte(s) in %d allocation(s) from:\n", trace2[i].Size, trace2[i].Count)
616 for j := 0; j < len(trace2[i].Traceback); j++ {
617 report += fmt.Sprintf("\t#%d %s\n", j, trace2[i].Traceback[j])
618 }
619 totalBytes += trace2[i].Size
620 totalCounts += trace2[i].Count
621 }
622 }
623 summary := fmt.Sprintf("\nSUMMARY: %d byte(s) leaked in %d allocation(s)\n", totalBytes, totalCounts)
624 AddReportEntry(summary, report)
625}