blob: a1f2ce46ed3180027cc51f50d553d9e3c7d30677 [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"
Adrian Villin637edda2024-05-06 06:55:34 -04007 "io"
Matus Fabian82ad9662024-06-04 19:00:00 +02008 "net"
Filip Tehlarec5c40b2023-02-28 18:59:15 +01009 "os"
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010010 "os/exec"
Filip Tehlarec5c40b2023-02-28 18:59:15 +010011 "os/signal"
Filip Tehlar543cd572023-06-27 10:01:37 +020012 "strconv"
Maros Ondrejicka7550dd22023-02-07 20:40:27 +010013 "strings"
Filip Tehlarec5c40b2023-02-28 18:59:15 +010014 "syscall"
Maros Ondrejicka7550dd22023-02-07 20:40:27 +010015 "time"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010016
Adrian Villin5a4c7a92024-09-26 11:24:34 +020017 "go.fd.io/govpp/binapi/ethernet_types"
18
Filip Tehlar9abba112023-03-07 10:13:19 +010019 "github.com/edwarnicke/exechelper"
Adrian Villincee15aa2024-03-14 11:42:55 -040020 . "github.com/onsi/ginkgo/v2"
Adrian Villin46d66002024-05-15 04:33:41 -040021 "github.com/sirupsen/logrus"
Filip Tehlar9abba112023-03-07 10:13:19 +010022
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010023 "go.fd.io/govpp"
24 "go.fd.io/govpp/api"
25 "go.fd.io/govpp/binapi/af_packet"
26 interfaces "go.fd.io/govpp/binapi/interface"
27 "go.fd.io/govpp/binapi/interface_types"
28 "go.fd.io/govpp/binapi/session"
Maros Ondrejicka7550dd22023-02-07 20:40:27 +010029 "go.fd.io/govpp/binapi/tapv2"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010030 "go.fd.io/govpp/core"
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010031)
32
33const vppConfigTemplate = `unix {
34 nodaemon
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010035 log %[1]s%[4]s
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010036 full-coredump
Adrian Villin4995d0d2024-07-29 17:54:58 +020037 coredump-size unlimited
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010038 cli-listen %[1]s%[2]s
39 runtime-dir %[1]s/var/run
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010040}
41
42api-trace {
43 on
44}
45
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010046socksvr {
Maros Ondrejicka7d7ab102023-02-14 12:56:49 +010047 socket-name %[1]s%[3]s
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010048}
49
50statseg {
51 socket-name %[1]s/var/run/vpp/stats.sock
52}
53
54plugins {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010055 plugin default { disable }
56
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010057 plugin unittest_plugin.so { enable }
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010058 plugin quic_plugin.so { enable }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010059 plugin af_packet_plugin.so { enable }
60 plugin hs_apps_plugin.so { enable }
61 plugin http_plugin.so { enable }
Filip Tehlarcc1475c2023-11-29 12:59:05 +010062 plugin http_static_plugin.so { enable }
63 plugin prom_plugin.so { enable }
Filip Tehlar3336eef2023-11-29 07:40:18 +010064 plugin tlsopenssl_plugin.so { enable }
Adrian Villincee15aa2024-03-14 11:42:55 -040065 plugin ping_plugin.so { enable }
Matus Fabianc899ab42024-04-22 13:42:00 +020066 plugin nsim_plugin.so { enable }
Matus Fabian82ad9662024-06-04 19:00:00 +020067 plugin mactime_plugin.so { enable }
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010068}
69
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010070logging {
71 default-log-level debug
72 default-syslog-log-level debug
73}
74
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010075`
76
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010077const (
78 defaultCliSocketFilePath = "/var/run/vpp/cli.sock"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010079 defaultApiSocketFilePath = "/var/run/vpp/api.sock"
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010080 defaultLogFilePath = "/var/log/vpp/vpp.log"
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010081)
82
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010083type VppInstance struct {
Adrian Villin4677d922024-06-14 09:32:39 +020084 Container *Container
85 AdditionalConfig []Stanza
86 Connection *core.Connection
87 ApiStream api.Stream
88 Cpus []int
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +020089 CpuConfig VppCpuConfig
90}
91
92type VppCpuConfig struct {
93 PinMainCpu bool
94 PinWorkersCorelist bool
95 SkipCores int
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010096}
97
Matus Fabiane99d2662024-07-19 16:04:09 +020098type VppMemTrace struct {
99 Count int `json:"count"`
100 Size int `json:"bytes"`
101 Sample string `json:"sample"`
102 Traceback []string `json:"traceback"`
103}
104
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100105func (vpp *VppInstance) getSuite() *HstSuite {
Adrian Villin4677d922024-06-14 09:32:39 +0200106 return vpp.Container.Suite
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100107}
108
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100109func (vpp *VppInstance) getCliSocket() string {
Adrian Villin4677d922024-06-14 09:32:39 +0200110 return fmt.Sprintf("%s%s", vpp.Container.GetContainerWorkDir(), defaultCliSocketFilePath)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100111}
112
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100113func (vpp *VppInstance) getRunDir() string {
Adrian Villin4677d922024-06-14 09:32:39 +0200114 return vpp.Container.GetContainerWorkDir() + "/var/run/vpp"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100115}
116
117func (vpp *VppInstance) getLogDir() string {
Adrian Villin4677d922024-06-14 09:32:39 +0200118 return vpp.Container.GetContainerWorkDir() + "/var/log/vpp"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100119}
120
121func (vpp *VppInstance) getEtcDir() string {
Adrian Villin4677d922024-06-14 09:32:39 +0200122 return vpp.Container.GetContainerWorkDir() + "/etc/vpp"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100123}
124
Adrian Villin4677d922024-06-14 09:32:39 +0200125func (vpp *VppInstance) Start() error {
Adrian Villin93974e22024-05-30 06:10:59 -0400126 maxReconnectAttempts := 3
Adrian Villin637edda2024-05-06 06:55:34 -0400127 // Replace default logger in govpp with our own
128 govppLogger := logrus.New()
Adrian Villin4677d922024-06-14 09:32:39 +0200129 govppLogger.SetOutput(io.MultiWriter(vpp.getSuite().Logger.Writer(), GinkgoWriter))
Adrian Villin637edda2024-05-06 06:55:34 -0400130 core.SetLogger(govppLogger)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100131 // Create folders
Adrian Villin4677d922024-06-14 09:32:39 +0200132 containerWorkDir := vpp.Container.GetContainerWorkDir()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100133
Adrian Villin4677d922024-06-14 09:32:39 +0200134 vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getRunDir())
135 vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getLogDir())
136 vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getEtcDir())
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100137
138 // Create startup.conf inside the container
Maros Ondrejicka7d7ab102023-02-14 12:56:49 +0100139 configContent := fmt.Sprintf(
Maros Ondrejicka300f70d2023-02-21 10:53:20 +0100140 vppConfigTemplate,
141 containerWorkDir,
142 defaultCliSocketFilePath,
143 defaultApiSocketFilePath,
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100144 defaultLogFilePath,
Maros Ondrejicka300f70d2023-02-21 10:53:20 +0100145 )
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200146 configContent += vpp.generateVPPCpuConfig()
Adrian Villin4677d922024-06-14 09:32:39 +0200147 for _, c := range vpp.AdditionalConfig {
148 configContent += c.ToString()
Filip Tehlar608d0062023-04-28 10:29:47 +0200149 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100150 startupFileName := vpp.getEtcDir() + "/startup.conf"
Adrian Villin4677d922024-06-14 09:32:39 +0200151 vpp.Container.CreateFile(startupFileName, configContent)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100152
Filip Tehlar1a661502023-03-08 11:55:50 +0100153 // create wrapper script for vppctl with proper CLI socket path
154 cliContent := "#!/usr/bin/bash\nvppctl -s " + vpp.getRunDir() + "/cli.sock"
155 vppcliFileName := "/usr/bin/vppcli"
Adrian Villin4677d922024-06-14 09:32:39 +0200156 vpp.Container.CreateFile(vppcliFileName, cliContent)
157 vpp.Container.Exec("chmod 0755 " + vppcliFileName)
Filip Tehlar1a661502023-03-08 11:55:50 +0100158
Adrian Villin4677d922024-06-14 09:32:39 +0200159 vpp.getSuite().Log("starting vpp")
160 if *IsVppDebug {
Adrian Villin93974e22024-05-30 06:10:59 -0400161 // default = 3; VPP will timeout while debugging if there are not enough attempts
162 maxReconnectAttempts = 5000
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100163 sig := make(chan os.Signal, 1)
Adrian Villincee15aa2024-03-14 11:42:55 -0400164 signal.Notify(sig, syscall.SIGQUIT)
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100165 cont := make(chan bool, 1)
166 go func() {
Filip Tehlar9abba112023-03-07 10:13:19 +0100167 <-sig
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100168 cont <- true
169 }()
170
Adrian Villin4677d922024-06-14 09:32:39 +0200171 vpp.Container.ExecServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100172 fmt.Println("run following command in different terminal:")
Adrian Villin4677d922024-06-14 09:32:39 +0200173 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 -0400174 fmt.Println("Afterwards press CTRL+\\ to continue")
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100175 <-cont
176 fmt.Println("continuing...")
177 } else {
178 // Start VPP
Adrian Villin4677d922024-06-14 09:32:39 +0200179 vpp.Container.ExecServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
Filip Tehlarec5c40b2023-02-28 18:59:15 +0100180 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100181
Adrian Villin4677d922024-06-14 09:32:39 +0200182 vpp.getSuite().Log("connecting to vpp")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100183 // Connect to VPP and store the connection
Adrian Villin4677d922024-06-14 09:32:39 +0200184 sockAddress := vpp.Container.GetHostWorkDir() + defaultApiSocketFilePath
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100185 conn, connEv, err := govpp.AsyncConnect(
186 sockAddress,
Adrian Villin93974e22024-05-30 06:10:59 -0400187 maxReconnectAttempts,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100188 core.DefaultReconnectInterval)
189 if err != nil {
Adrian Villin4677d922024-06-14 09:32:39 +0200190 vpp.getSuite().Log("async connect error: " + fmt.Sprint(err))
Filip Tehlar56e17cf2024-01-11 17:17:33 +0100191 return err
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100192 }
Adrian Villin4677d922024-06-14 09:32:39 +0200193 vpp.Connection = conn
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100194
195 // ... wait for Connected event
196 e := <-connEv
197 if e.State != core.Connected {
Adrian Villin4677d922024-06-14 09:32:39 +0200198 vpp.getSuite().Log("connecting to VPP failed: " + fmt.Sprint(e.Error))
Hadi Rayan Al-Sandid0eccf452024-06-24 10:48:54 +0200199 return e.Error
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100200 }
201
Adrian Villin46d66002024-05-15 04:33:41 -0400202 ch, err := conn.NewStream(
203 context.Background(),
204 core.WithRequestSize(50),
205 core.WithReplySize(50),
Adrian Villin93974e22024-05-30 06:10:59 -0400206 core.WithReplyTimeout(time.Second*5))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100207 if err != nil {
Adrian Villin4677d922024-06-14 09:32:39 +0200208 vpp.getSuite().Log("creating stream failed: " + fmt.Sprint(err))
Filip Tehlar56e17cf2024-01-11 17:17:33 +0100209 return err
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100210 }
Adrian Villin4677d922024-06-14 09:32:39 +0200211 vpp.ApiStream = ch
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100212
213 return nil
214}
215
Adrian Villin4677d922024-06-14 09:32:39 +0200216func (vpp *VppInstance) Vppctl(command string, arguments ...any) string {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100217 vppCliCommand := fmt.Sprintf(command, arguments...)
218 containerExecCommand := fmt.Sprintf("docker exec --detach=false %[1]s vppctl -s %[2]s %[3]s",
Adrian Villin4677d922024-06-14 09:32:39 +0200219 vpp.Container.Name, vpp.getCliSocket(), vppCliCommand)
220 vpp.getSuite().Log(containerExecCommand)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100221 output, err := exechelper.CombinedOutput(containerExecCommand)
Adrian Villin4677d922024-06-14 09:32:39 +0200222 vpp.getSuite().AssertNil(err)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100223
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100224 return string(output)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100225}
226
Filip Tehlar543cd572023-06-27 10:01:37 +0200227func (vpp *VppInstance) GetSessionStat(stat string) int {
Adrian Villin4677d922024-06-14 09:32:39 +0200228 o := vpp.Vppctl("show session stats")
229 vpp.getSuite().Log(o)
Filip Tehlar543cd572023-06-27 10:01:37 +0200230 for _, line := range strings.Split(o, "\n") {
231 if strings.Contains(line, stat) {
232 tokens := strings.Split(strings.TrimSpace(line), " ")
233 val, err := strconv.Atoi(tokens[0])
234 if err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -0400235 Fail("failed to parse stat value %s" + fmt.Sprint(err))
Filip Tehlar543cd572023-06-27 10:01:37 +0200236 return 0
237 }
238 return val
239 }
240 }
241 return 0
242}
243
Adrian Villin4677d922024-06-14 09:32:39 +0200244func (vpp *VppInstance) WaitForApp(appName string, timeout int) {
245 vpp.getSuite().Log("waiting for app " + appName)
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100246 for i := 0; i < timeout; i++ {
Adrian Villin4677d922024-06-14 09:32:39 +0200247 o := vpp.Vppctl("show app")
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100248 if strings.Contains(o, appName) {
Maros Ondrejickac2f76f42023-02-27 13:22:45 +0100249 return
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100250 }
251 time.Sleep(1 * time.Second)
Maros Ondrejickadb823ed2022-12-14 16:30:04 +0100252 }
Adrian Villin4677d922024-06-14 09:32:39 +0200253 vpp.getSuite().AssertNil(1, "Timeout while waiting for app '%s'", appName)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +0100254}
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100255
256func (vpp *VppInstance) createAfPacket(
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100257 veth *NetInterface,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100258) (interface_types.InterfaceIndex, error) {
Adrian Villin46d66002024-05-15 04:33:41 -0400259 createReq := &af_packet.AfPacketCreateV3{
260 Mode: 1,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100261 UseRandomHwAddr: true,
262 HostIfName: veth.Name(),
Adrian Villin46d66002024-05-15 04:33:41 -0400263 Flags: af_packet.AfPacketFlags(11),
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100264 }
Adrian Villin4677d922024-06-14 09:32:39 +0200265 if veth.HwAddress != (MacAddress{}) {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100266 createReq.UseRandomHwAddr = false
Adrian Villin4677d922024-06-14 09:32:39 +0200267 createReq.HwAddr = veth.HwAddress
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100268 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100269
Adrian Villin4677d922024-06-14 09:32:39 +0200270 vpp.getSuite().Log("create af-packet interface " + veth.Name())
271 if err := vpp.ApiStream.SendMsg(createReq); err != nil {
272 vpp.getSuite().HstFail()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100273 return 0, err
274 }
Adrian Villin4677d922024-06-14 09:32:39 +0200275 replymsg, err := vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400276 if err != nil {
277 return 0, err
278 }
279 reply := replymsg.(*af_packet.AfPacketCreateV3Reply)
280 err = api.RetvalToVPPApiError(reply.Retval)
281 if err != nil {
282 return 0, err
283 }
284
Adrian Villin4677d922024-06-14 09:32:39 +0200285 veth.Index = reply.SwIfIndex
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100286
287 // Set to up
288 upReq := &interfaces.SwInterfaceSetFlags{
Adrian Villin4677d922024-06-14 09:32:39 +0200289 SwIfIndex: veth.Index,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100290 Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
291 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100292
Adrian Villin4677d922024-06-14 09:32:39 +0200293 vpp.getSuite().Log("set af-packet interface " + veth.Name() + " up")
294 if err := vpp.ApiStream.SendMsg(upReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400295 return 0, err
296 }
Adrian Villin4677d922024-06-14 09:32:39 +0200297 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400298 if err != nil {
299 return 0, err
300 }
301 reply2 := replymsg.(*interfaces.SwInterfaceSetFlagsReply)
302 if err = api.RetvalToVPPApiError(reply2.Retval); err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100303 return 0, err
304 }
305
306 // Add address
Adrian Villin4677d922024-06-14 09:32:39 +0200307 if veth.AddressWithPrefix() == (AddressWithPrefix{}) {
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100308 var err error
309 var ip4Address string
Adrian Villin4677d922024-06-14 09:32:39 +0200310 if ip4Address, err = veth.Ip4AddrAllocator.NewIp4InterfaceAddress(veth.Peer.NetworkNumber); err == nil {
311 veth.Ip4Address = ip4Address
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100312 } else {
313 return 0, err
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100314 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100315 }
316 addressReq := &interfaces.SwInterfaceAddDelAddress{
317 IsAdd: true,
Adrian Villin4677d922024-06-14 09:32:39 +0200318 SwIfIndex: veth.Index,
319 Prefix: veth.AddressWithPrefix(),
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100320 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100321
Adrian Villin4677d922024-06-14 09:32:39 +0200322 vpp.getSuite().Log("af-packet interface " + veth.Name() + " add address " + veth.Ip4Address)
323 if err := vpp.ApiStream.SendMsg(addressReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400324 return 0, err
325 }
Adrian Villin4677d922024-06-14 09:32:39 +0200326 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400327 if err != nil {
328 return 0, err
329 }
330 reply3 := replymsg.(*interfaces.SwInterfaceAddDelAddressReply)
331 err = api.RetvalToVPPApiError(reply3.Retval)
332 if err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100333 return 0, err
334 }
335
Adrian Villin4677d922024-06-14 09:32:39 +0200336 return veth.Index, nil
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100337}
338
339func (vpp *VppInstance) addAppNamespace(
340 secret uint64,
341 ifx interface_types.InterfaceIndex,
342 namespaceId string,
343) error {
Adrian Villin46d66002024-05-15 04:33:41 -0400344 req := &session.AppNamespaceAddDelV4{
345 IsAdd: true,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100346 Secret: secret,
347 SwIfIndex: ifx,
348 NamespaceID: namespaceId,
Adrian Villin46d66002024-05-15 04:33:41 -0400349 SockName: defaultApiSocketFilePath,
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100350 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100351
Adrian Villin4677d922024-06-14 09:32:39 +0200352 vpp.getSuite().Log("add app namespace " + namespaceId)
353 if err := vpp.ApiStream.SendMsg(req); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400354 return err
355 }
Adrian Villin4677d922024-06-14 09:32:39 +0200356 replymsg, err := vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400357 if err != nil {
358 return err
359 }
360 reply := replymsg.(*session.AppNamespaceAddDelV4Reply)
361 if err = api.RetvalToVPPApiError(reply.Retval); err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100362 return err
363 }
364
365 sessionReq := &session.SessionEnableDisable{
366 IsEnable: true,
367 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100368
Adrian Villin4677d922024-06-14 09:32:39 +0200369 vpp.getSuite().Log("enable app namespace " + namespaceId)
370 if err := vpp.ApiStream.SendMsg(sessionReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400371 return err
372 }
Adrian Villin4677d922024-06-14 09:32:39 +0200373 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400374 if err != nil {
375 return err
376 }
377 reply2 := replymsg.(*session.SessionEnableDisableReply)
378 if err = api.RetvalToVPPApiError(reply2.Retval); err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100379 return err
380 }
381
382 return nil
383}
384
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100385func (vpp *VppInstance) createTap(
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100386 tap *NetInterface,
Maros Ondrejickac2f76f42023-02-27 13:22:45 +0100387 tapId ...uint32,
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100388) error {
Maros Ondrejickac2f76f42023-02-27 13:22:45 +0100389 var id uint32 = 1
390 if len(tapId) > 0 {
391 id = tapId[0]
392 }
Adrian Villin46d66002024-05-15 04:33:41 -0400393 createTapReq := &tapv2.TapCreateV3{
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100394 ID: id,
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100395 HostIfNameSet: true,
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100396 HostIfName: tap.Name(),
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100397 HostIP4PrefixSet: true,
Adrian Villin4677d922024-06-14 09:32:39 +0200398 HostIP4Prefix: tap.Ip4AddressWithPrefix(),
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100399 }
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100400
Adrian Villin4677d922024-06-14 09:32:39 +0200401 vpp.getSuite().Log("create tap interface " + tap.Name())
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100402 // Create tap interface
Adrian Villin4677d922024-06-14 09:32:39 +0200403 if err := vpp.ApiStream.SendMsg(createTapReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400404 return err
405 }
Adrian Villin4677d922024-06-14 09:32:39 +0200406 replymsg, err := vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400407 if err != nil {
408 return err
409 }
410 reply := replymsg.(*tapv2.TapCreateV3Reply)
411 if err = api.RetvalToVPPApiError(reply.Retval); err != nil {
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100412 return err
413 }
Adrian Villin4677d922024-06-14 09:32:39 +0200414 tap.Peer.Index = reply.SwIfIndex
Matus Fabian82ad9662024-06-04 19:00:00 +0200415
416 // Get name and mac
Adrian Villin4677d922024-06-14 09:32:39 +0200417 if err := vpp.ApiStream.SendMsg(&interfaces.SwInterfaceDump{
Matus Fabian82ad9662024-06-04 19:00:00 +0200418 SwIfIndex: reply.SwIfIndex,
419 }); err != nil {
420 return err
421 }
Adrian Villin4677d922024-06-14 09:32:39 +0200422 replymsg, err = vpp.ApiStream.RecvMsg()
Matus Fabian82ad9662024-06-04 19:00:00 +0200423 if err != nil {
424 return err
425 }
426 ifDetails := replymsg.(*interfaces.SwInterfaceDetails)
Adrian Villin4677d922024-06-14 09:32:39 +0200427 tap.Peer.name = ifDetails.InterfaceName
428 tap.Peer.HwAddress = ifDetails.L2Address
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100429
430 // Add address
431 addAddressReq := &interfaces.SwInterfaceAddDelAddress{
432 IsAdd: true,
Adrian Villin46d66002024-05-15 04:33:41 -0400433 SwIfIndex: reply.SwIfIndex,
Adrian Villin4677d922024-06-14 09:32:39 +0200434 Prefix: tap.Peer.AddressWithPrefix(),
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100435 }
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100436
Adrian Villin4677d922024-06-14 09:32:39 +0200437 vpp.getSuite().Log("tap interface " + tap.Name() + " add address " + tap.Peer.Ip4Address)
438 if err := vpp.ApiStream.SendMsg(addAddressReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400439 return err
440 }
Adrian Villin4677d922024-06-14 09:32:39 +0200441 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400442 if err != nil {
443 return err
444 }
445 reply2 := replymsg.(*interfaces.SwInterfaceAddDelAddressReply)
446 if err = api.RetvalToVPPApiError(reply2.Retval); err != nil {
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100447 return err
448 }
449
450 // Set interface to up
451 upReq := &interfaces.SwInterfaceSetFlags{
Adrian Villin46d66002024-05-15 04:33:41 -0400452 SwIfIndex: reply.SwIfIndex,
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100453 Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
454 }
Adrian Villin4677d922024-06-14 09:32:39 +0200455
456 vpp.getSuite().Log("set tap interface " + tap.Name() + " up")
457 if err := vpp.ApiStream.SendMsg(upReq); err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400458 return err
459 }
Adrian Villin4677d922024-06-14 09:32:39 +0200460 replymsg, err = vpp.ApiStream.RecvMsg()
Adrian Villin46d66002024-05-15 04:33:41 -0400461 if err != nil {
462 return err
463 }
464 reply3 := replymsg.(*interfaces.SwInterfaceSetFlagsReply)
465 if err = api.RetvalToVPPApiError(reply3.Retval); err != nil {
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100466 return err
467 }
468
Matus Fabian82ad9662024-06-04 19:00:00 +0200469 // Get host mac
470 netIntf, err := net.InterfaceByName(tap.Name())
471 if err == nil {
Adrian Villin4677d922024-06-14 09:32:39 +0200472 tap.HwAddress, _ = ethernet_types.ParseMacAddress(netIntf.HardwareAddr.String())
Matus Fabian82ad9662024-06-04 19:00:00 +0200473 }
474
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100475 return nil
476}
477
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100478func (vpp *VppInstance) saveLogs() {
Adrian Villin4995d0d2024-07-29 17:54:58 +0200479 logTarget := vpp.getSuite().getLogDirPath() + "vppinstance-" + vpp.Container.Name + ".log"
Adrian Villin4677d922024-06-14 09:32:39 +0200480 logSource := vpp.Container.GetHostWorkDir() + defaultLogFilePath
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100481 cmd := exec.Command("cp", logSource, logTarget)
Adrian Villin4677d922024-06-14 09:32:39 +0200482 vpp.getSuite().Log(cmd.String())
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100483 cmd.Run()
484}
485
Adrian Villin4677d922024-06-14 09:32:39 +0200486func (vpp *VppInstance) Disconnect() {
487 vpp.Connection.Disconnect()
488 vpp.ApiStream.Close()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100489}
Filip Tehlar608d0062023-04-28 10:29:47 +0200490
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200491func (vpp *VppInstance) setDefaultCpuConfig() {
492 vpp.CpuConfig.PinMainCpu = true
493 vpp.CpuConfig.PinWorkersCorelist = true
494 vpp.CpuConfig.SkipCores = 0
495}
496
497func (vpp *VppInstance) generateVPPCpuConfig() string {
Filip Tehlar608d0062023-04-28 10:29:47 +0200498 var c Stanza
499 var s string
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200500 startCpu := 0
Adrian Villin4677d922024-06-14 09:32:39 +0200501 if len(vpp.Cpus) < 1 {
Filip Tehlar608d0062023-04-28 10:29:47 +0200502 return ""
503 }
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200504
505 c.NewStanza("cpu")
506
507 // If skip-cores is valid, use as start value to assign main/workers CPUs
508 if vpp.CpuConfig.SkipCores != 0 {
509 c.Append(fmt.Sprintf("skip-cores %d", vpp.CpuConfig.SkipCores))
510 vpp.getSuite().Log(fmt.Sprintf("skip-cores %d", vpp.CpuConfig.SkipCores))
511 }
512
513 if len(vpp.Cpus) > vpp.CpuConfig.SkipCores {
514 startCpu = vpp.CpuConfig.SkipCores
515 }
516
517 if vpp.CpuConfig.PinMainCpu {
518 c.Append(fmt.Sprintf("main-core %d", vpp.Cpus[startCpu]))
519 vpp.getSuite().Log(fmt.Sprintf("main-core %d", vpp.Cpus[startCpu]))
520 }
521
522 workers := vpp.Cpus[startCpu+1:]
Filip Tehlar608d0062023-04-28 10:29:47 +0200523
524 if len(workers) > 0 {
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200525 if vpp.CpuConfig.PinWorkersCorelist {
526 for i := 0; i < len(workers); i++ {
527 if i != 0 {
528 s = s + ", "
529 }
530 s = s + fmt.Sprintf("%d", workers[i])
Filip Tehlar608d0062023-04-28 10:29:47 +0200531 }
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200532 c.Append(fmt.Sprintf("corelist-workers %s", s))
533 vpp.getSuite().Log("corelist-workers " + s)
534 } else {
535 s = fmt.Sprintf("%d", len(workers))
536 c.Append(fmt.Sprintf("workers %s", s))
537 vpp.getSuite().Log("workers " + s)
Filip Tehlar608d0062023-04-28 10:29:47 +0200538 }
Filip Tehlar608d0062023-04-28 10:29:47 +0200539 }
Hadi Rayan Al-Sandide0e85132024-06-24 10:28:58 +0200540
Adrian Villin4677d922024-06-14 09:32:39 +0200541 return c.Close().ToString()
Filip Tehlar608d0062023-04-28 10:29:47 +0200542}
Matus Fabiane99d2662024-07-19 16:04:09 +0200543
544// EnableMemoryTrace enables memory traces of VPP main-heap
545func (vpp *VppInstance) EnableMemoryTrace() {
546 vpp.getSuite().Log(vpp.Vppctl("memory-trace on main-heap"))
547}
548
549// GetMemoryTrace dumps memory traces for analysis
550func (vpp *VppInstance) GetMemoryTrace() ([]VppMemTrace, error) {
551 var trace []VppMemTrace
552 vpp.getSuite().Log(vpp.Vppctl("save memory-trace trace.json"))
553 err := vpp.Container.GetFile("/tmp/trace.json", "/tmp/trace.json")
554 if err != nil {
555 return nil, err
556 }
557 fileBytes, err := os.ReadFile("/tmp/trace.json")
558 if err != nil {
559 return nil, err
560 }
561 err = json.Unmarshal(fileBytes, &trace)
562 if err != nil {
563 return nil, err
564 }
565 return trace, nil
566}
567
568// memTracesSuppressCli filter out CLI related samples
569func memTracesSuppressCli(traces []VppMemTrace) []VppMemTrace {
570 var filtered []VppMemTrace
571 for i := 0; i < len(traces); i++ {
572 isCli := false
573 for j := 0; j < len(traces[i].Traceback); j++ {
574 if strings.Contains(traces[i].Traceback[j], "unix_cli") {
575 isCli = true
576 break
577 }
578 }
579 if !isCli {
580 filtered = append(filtered, traces[i])
581 }
582 }
583 return filtered
584}
585
586// MemLeakCheck compares memory traces at different point in time, analyzes if memory leaks happen and produces report
587func (vpp *VppInstance) MemLeakCheck(first, second []VppMemTrace) {
588 totalBytes := 0
589 totalCounts := 0
590 trace1 := memTracesSuppressCli(first)
591 trace2 := memTracesSuppressCli(second)
592 report := ""
593 for i := 0; i < len(trace2); i++ {
594 match := false
595 for j := 0; j < len(trace1); j++ {
596 if trace1[j].Sample == trace2[i].Sample {
597 if trace2[i].Size > trace1[j].Size {
598 deltaBytes := trace2[i].Size - trace1[j].Size
599 deltaCounts := trace2[i].Count - trace1[j].Count
600 report += fmt.Sprintf("grow %d byte(s) in %d allocation(s) from:\n", deltaBytes, deltaCounts)
601 for j := 0; j < len(trace2[i].Traceback); j++ {
602 report += fmt.Sprintf("\t#%d %s\n", j, trace2[i].Traceback[j])
603 }
604 totalBytes += deltaBytes
605 totalCounts += deltaCounts
606 }
607 match = true
608 break
609 }
610 }
611 if !match {
612 report += fmt.Sprintf("\nleak of %d byte(s) in %d allocation(s) from:\n", trace2[i].Size, trace2[i].Count)
613 for j := 0; j < len(trace2[i].Traceback); j++ {
614 report += fmt.Sprintf("\t#%d %s\n", j, trace2[i].Traceback[j])
615 }
616 totalBytes += trace2[i].Size
617 totalCounts += trace2[i].Count
618 }
619 }
620 summary := fmt.Sprintf("\nSUMMARY: %d byte(s) leaked in %d allocation(s)\n", totalBytes, totalCounts)
621 AddReportEntry(summary, report)
622}
Matus Fabian147585e2024-09-20 10:44:08 +0200623
624// CollectEventLogs saves event logs to the test execution directory
625func (vpp *VppInstance) CollectEventLogs() {
626 vpp.getSuite().Log(vpp.Vppctl("event-logger save event_log"))
627 targetDir := vpp.Container.Suite.getLogDirPath()
628 err := vpp.Container.GetFile("/tmp/event_log", targetDir+"/"+vpp.Container.Name+"-event_log")
629 if err != nil {
630 vpp.getSuite().Log(fmt.Sprint(err))
631 }
632}
633
634// EnablePcapTrace enables packet capture on all interfaces and maximum 10000 packets
635func (vpp *VppInstance) EnablePcapTrace() {
636 vpp.getSuite().Log(vpp.Vppctl("pcap trace rx tx max 10000 intfc any file vppTest.pcap"))
637}
638
639// CollectPcapTrace saves pcap trace to the test execution directory
640func (vpp *VppInstance) CollectPcapTrace() {
641 vpp.getSuite().Log(vpp.Vppctl("pcap trace off"))
642 targetDir := vpp.Container.Suite.getLogDirPath()
643 err := vpp.Container.GetFile("/tmp/vppTest.pcap", targetDir+"/"+vpp.Container.Name+".pcap")
644 if err != nil {
645 vpp.getSuite().Log(fmt.Sprint(err))
646 }
647}