hs-test: add support for running vpp in gdb
[vpp.git] / extras / hs-test / vppinstance.go
index dfaf405..1c28ec9 100644 (file)
@@ -3,7 +3,11 @@ package main
 import (
        "fmt"
        "github.com/edwarnicke/exechelper"
+       "os"
+       "os/exec"
+       "os/signal"
        "strings"
+       "syscall"
        "time"
 
        "go.fd.io/govpp"
@@ -19,7 +23,7 @@ import (
 
 const vppConfigTemplate = `unix {
   nodaemon
-  log %[1]s/var/log/vpp/vpp.log
+  log %[1]s%[4]s
   full-coredump
   cli-listen %[1]s%[2]s
   runtime-dir %[1]s/var/run
@@ -52,18 +56,24 @@ plugins {
   plugin http_plugin.so { enable }
 }
 
+logging {
+  default-log-level debug
+  default-syslog-log-level debug
+}
+
 `
 
 const (
        defaultCliSocketFilePath = "/var/run/vpp/cli.sock"
        defaultApiSocketFilePath = "/var/run/vpp/api.sock"
+       defaultLogFilePath       = "/var/log/vpp/vpp.log"
 )
 
 type VppInstance struct {
-       container      *Container
-       additionalConfig  Stanza
-       connection     *core.Connection
-       apiChannel     api.Channel
+       container        *Container
+       additionalConfig Stanza
+       connection       *core.Connection
+       apiChannel       api.Channel
 }
 
 func (vpp *VppInstance) Suite() *HstSuite {
@@ -96,17 +106,37 @@ func (vpp *VppInstance) start() error {
 
        // Create startup.conf inside the container
        configContent := fmt.Sprintf(
-                vppConfigTemplate,
-                containerWorkDir,
-                defaultCliSocketFilePath,
-                defaultApiSocketFilePath,
-        )
+               vppConfigTemplate,
+               containerWorkDir,
+               defaultCliSocketFilePath,
+               defaultApiSocketFilePath,
+               defaultLogFilePath,
+       )
        configContent += vpp.additionalConfig.ToString()
        startupFileName := vpp.getEtcDir() + "/startup.conf"
        vpp.container.createFile(startupFileName, configContent)
 
-       // Start VPP
-       vpp.container.execServer("vpp -c " + startupFileName)
+       if *IsVppDebug {
+               sig := make(chan os.Signal, 1)
+               signal.Notify(sig, syscall.SIGINT)
+               cont := make(chan bool, 1)
+               go func() {
+                       sig := <-sig
+                       fmt.Println(sig)
+                       cont <- true
+               }()
+
+               // Start VPP in GDB and wait for user to attach it
+               vpp.container.execServer("su -c \"gdb -ex run --args vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
+               fmt.Println("run following command in different terminal:")
+               fmt.Println("docker exec -it " + vpp.container.name + " gdb -ex \"attach $(docker exec " + vpp.container.name + " pidof gdb)\"")
+               fmt.Println("Afterwards press CTRL+C to continue")
+               <-cont
+               fmt.Println("continuing...")
+       } else {
+               // Start VPP
+               vpp.container.execServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
+       }
 
        // Connect to VPP and store the connection
        sockAddress := vpp.container.GetHostWorkDir() + defaultApiSocketFilePath
@@ -152,22 +182,21 @@ func (vpp *VppInstance) vppctl(command string, arguments ...any) string {
        return string(output)
 }
 
-func (vpp *VppInstance) waitForApp(appName string, timeout int) error {
+func (vpp *VppInstance) waitForApp(appName string, timeout int) {
        for i := 0; i < timeout; i++ {
                o := vpp.vppctl("show app")
                if strings.Contains(o, appName) {
-                       return nil
+                       return
                }
                time.Sleep(1 * time.Second)
        }
-       return fmt.Errorf("timeout while waiting for app '%s'", appName)
+       vpp.Suite().assertNil(1, "Timeout while waiting for app '%s'", appName)
+       return
 }
 
 func (vpp *VppInstance) createAfPacket(
-       netInterface NetInterface,
+       veth *NetInterface,
 ) (interface_types.InterfaceIndex, error) {
-        veth := netInterface.(*NetworkInterfaceVeth)
-
        createReq := &af_packet.AfPacketCreateV2{
                UseRandomHwAddr: true,
                HostIfName:      veth.Name(),
@@ -198,14 +227,7 @@ func (vpp *VppInstance) createAfPacket(
        if veth.AddressWithPrefix() == (AddressWithPrefix{}) {
                var err error
                var ip4Address string
-               if veth.peerNetworkNamespace != "" {
-                       ip4Address, err = veth.addresser.
-                               NewIp4AddressWithNamespace(veth.peerNetworkNamespace)
-               } else {
-                       ip4Address, err = veth.addresser.
-                               NewIp4Address()
-               }
-               if err == nil {
+               if ip4Address, err = veth.addresser.NewIp4Address(veth.Peer().networkNumber); err == nil {
                        veth.SetAddress(ip4Address)
                } else {
                        return 0, err
@@ -254,15 +276,19 @@ func (vpp *VppInstance) addAppNamespace(
 }
 
 func (vpp *VppInstance) createTap(
-       hostInterfaceName string,
-       hostIp4Address IP4AddressWithPrefix,
-       vppIp4Address AddressWithPrefix,
+       tap *NetInterface,
+       tapId ...uint32,
 ) error {
+       var id uint32 = 1
+       if len(tapId) > 0 {
+               id = tapId[0]
+       }
        createTapReq := &tapv2.TapCreateV2{
+               ID:               id,
                HostIfNameSet:    true,
-               HostIfName:       hostInterfaceName,
+               HostIfName:       tap.Name(),
                HostIP4PrefixSet: true,
-               HostIP4Prefix:    hostIp4Address,
+               HostIP4Prefix:    tap.IP4AddressWithPrefix(),
        }
        createTapReply := &tapv2.TapCreateV2Reply{}
 
@@ -275,7 +301,7 @@ func (vpp *VppInstance) createTap(
        addAddressReq := &interfaces.SwInterfaceAddDelAddress{
                IsAdd:     true,
                SwIfIndex: createTapReply.SwIfIndex,
-               Prefix:    vppIp4Address,
+               Prefix:    tap.Peer().AddressWithPrefix(),
        }
        addAddressReply := &interfaces.SwInterfaceAddDelAddressReply{}
 
@@ -297,6 +323,15 @@ func (vpp *VppInstance) createTap(
        return nil
 }
 
+func (vpp *VppInstance) saveLogs() {
+       logTarget := vpp.container.getLogDirPath() + "vppinstance-" + vpp.container.name + ".log"
+       logSource := vpp.container.GetHostWorkDir() + defaultLogFilePath
+       cmd := exec.Command("cp", logSource, logTarget)
+       vpp.Suite().T().Helper()
+       vpp.Suite().log(cmd.String())
+       cmd.Run()
+}
+
 func (vpp *VppInstance) disconnect() {
        vpp.connection.Disconnect()
        vpp.apiChannel.Close()