summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorZeling Feng <zeling@google.com>2021-03-05 11:53:18 -0800
committergVisor bot <gvisor-bot@google.com>2021-03-05 11:56:31 -0800
commit2f0b82a8028019d4c996cf64341f84bb1d1c65b7 (patch)
treed69937f5cbd2296803d140cf6ad6a1c57fdd269a
parent3e8e2cad881978674737ee3f9ac58b780d172187 (diff)
Gather uname information from DUT
Some OSs behave slightly differently, but still within the RFC. It can be useful to have access to uname information from the testbench. PiperOrigin-RevId: 361193766
-rw-r--r--test/packetimpact/runner/dut.go71
-rw-r--r--test/packetimpact/testbench/BUILD2
-rw-r--r--test/packetimpact/testbench/dut.go11
-rw-r--r--test/packetimpact/testbench/testbench.go62
4 files changed, 104 insertions, 42 deletions
diff --git a/test/packetimpact/runner/dut.go b/test/packetimpact/runner/dut.go
index 3da265b78..2e8ffe883 100644
--- a/test/packetimpact/runner/dut.go
+++ b/test/packetimpact/runner/dut.go
@@ -109,6 +109,7 @@ type dutInfo struct {
dut DUT
ctrlNet, testNet *dockerutil.Network
netInfo *testbench.DUTTestNet
+ uname *testbench.DUTUname
}
// setUpDUT will set up one DUT and return information for setting up the
@@ -182,6 +183,10 @@ func setUpDUT(ctx context.Context, t *testing.T, id int, mkDevice func(*dockerut
POSIXServerIP: AddressInSubnet(DUTAddr, *ctrlNet.Subnet),
POSIXServerPort: CtrlPort,
}
+ info.uname, err = dut.Uname(ctx)
+ if err != nil {
+ return dutInfo{}, fmt.Errorf("failed to get uname information on DUT: %w", err)
+ }
return info, nil
}
@@ -195,7 +200,7 @@ func TestWithDUT(ctx context.Context, t *testing.T, mkDevice func(*dockerutil.Co
dutInfoChan := make(chan dutInfo, numDUTs)
errChan := make(chan error, numDUTs)
var dockerNetworks []*dockerutil.Network
- var dutTestNets []*testbench.DUTTestNet
+ var dutInfos []*testbench.DUTInfo
var duts []DUT
setUpCtx, cancelSetup := context.WithCancel(ctx)
@@ -214,7 +219,10 @@ func TestWithDUT(ctx context.Context, t *testing.T, mkDevice func(*dockerutil.Co
select {
case info := <-dutInfoChan:
dockerNetworks = append(dockerNetworks, info.ctrlNet, info.testNet)
- dutTestNets = append(dutTestNets, info.netInfo)
+ dutInfos = append(dutInfos, &testbench.DUTInfo{
+ Net: info.netInfo,
+ Uname: info.uname,
+ })
duts = append(duts, info.dut)
case err := <-errChan:
t.Fatal(err)
@@ -246,23 +254,23 @@ func TestWithDUT(ctx context.Context, t *testing.T, mkDevice func(*dockerutil.Co
t.Fatalf("cannot start testbench container: %s", err)
}
- for i := range dutTestNets {
- name, info, err := deviceByIP(ctx, testbenchContainer, dutTestNets[i].LocalIPv4)
+ for i := range dutInfos {
+ name, info, err := deviceByIP(ctx, testbenchContainer, dutInfos[i].Net.LocalIPv4)
if err != nil {
- t.Fatalf("failed to get the device name associated with %s: %s", dutTestNets[i].LocalIPv4, err)
+ t.Fatalf("failed to get the device name associated with %s: %s", dutInfos[i].Net.LocalIPv4, err)
}
- dutTestNets[i].LocalDevName = name
- dutTestNets[i].LocalDevID = info.ID
- dutTestNets[i].LocalMAC = info.MAC
+ dutInfos[i].Net.LocalDevName = name
+ dutInfos[i].Net.LocalDevID = info.ID
+ dutInfos[i].Net.LocalMAC = info.MAC
localIPv6, err := getOrAssignIPv6Addr(ctx, testbenchContainer, name)
if err != nil {
t.Fatalf("failed to get IPV6 address on %s: %s", testbenchContainer.Name, err)
}
- dutTestNets[i].LocalIPv6 = localIPv6
+ dutInfos[i].Net.LocalIPv6 = localIPv6
}
- dutTestNetsBytes, err := json.Marshal(dutTestNets)
+ dutInfosBytes, err := json.Marshal(dutInfos)
if err != nil {
- t.Fatalf("failed to marshal %v into json: %s", dutTestNets, err)
+ t.Fatalf("failed to marshal %v into json: %s", dutInfos, err)
}
baseSnifferArgs := []string{
@@ -296,7 +304,8 @@ func TestWithDUT(ctx context.Context, t *testing.T, mkDevice func(*dockerutil.Co
"-n",
}
}
- for _, n := range dutTestNets {
+ for _, info := range dutInfos {
+ n := info.Net
snifferArgs := append(baseSnifferArgs, "-i", n.LocalDevName)
if !tshark {
snifferArgs = append(
@@ -351,7 +360,7 @@ func TestWithDUT(ctx context.Context, t *testing.T, mkDevice func(*dockerutil.Co
testArgs = append(testArgs, extraTestArgs...)
testArgs = append(testArgs,
fmt.Sprintf("--native=%t", native),
- "--dut_test_nets_json", string(dutTestNetsBytes),
+ "--dut_infos_json", string(dutInfosBytes),
)
testbenchLogs, err := testbenchContainer.Exec(ctx, dockerutil.ExecOpts{}, testArgs...)
if (err != nil) != expectFailure {
@@ -388,6 +397,10 @@ type DUT interface {
// The t parameter is supposed to be used for t.Cleanup. Don't use it for
// t.Fatal/FailNow functions.
Prepare(ctx context.Context, t *testing.T, runOpts dockerutil.RunOpts, ctrlNet, testNet *dockerutil.Network) (net.IP, net.HardwareAddr, uint32, string, error)
+
+ // Uname gathers information of DUT using command uname.
+ Uname(ctx context.Context) (*testbench.DUTUname, error)
+
// Logs retrieves the logs from the dut.
Logs(ctx context.Context) (string, error)
}
@@ -440,6 +453,38 @@ func (dut *DockerDUT) Prepare(ctx context.Context, _ *testing.T, runOpts dockeru
return remoteIPv6, dutDeviceInfo.MAC, dutDeviceInfo.ID, testNetDev, nil
}
+// Uname implements DUT.Uname.
+func (dut *DockerDUT) Uname(ctx context.Context) (*testbench.DUTUname, error) {
+ machine, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-m")
+ if err != nil {
+ return nil, err
+ }
+ kernelRelease, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-r")
+ if err != nil {
+ return nil, err
+ }
+ kernelVersion, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-v")
+ if err != nil {
+ return nil, err
+ }
+ kernelName, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-s")
+ if err != nil {
+ return nil, err
+ }
+ // TODO(gvisor.dev/issues/5586): -o is not supported on macOS.
+ operatingSystem, err := dut.c.Exec(ctx, dockerutil.ExecOpts{}, "uname", "-o")
+ if err != nil {
+ return nil, err
+ }
+ return &testbench.DUTUname{
+ Machine: strings.TrimRight(machine, "\n"),
+ KernelName: strings.TrimRight(kernelName, "\n"),
+ KernelRelease: strings.TrimRight(kernelRelease, "\n"),
+ KernelVersion: strings.TrimRight(kernelVersion, "\n"),
+ OperatingSystem: strings.TrimRight(operatingSystem, "\n"),
+ }, nil
+}
+
// Logs implements DUT.Logs.
func (dut *DockerDUT) Logs(ctx context.Context) (string, error) {
logs, err := dut.c.Logs(ctx)
diff --git a/test/packetimpact/testbench/BUILD b/test/packetimpact/testbench/BUILD
index 983c2c030..43b4c7ca1 100644
--- a/test/packetimpact/testbench/BUILD
+++ b/test/packetimpact/testbench/BUILD
@@ -1,7 +1,6 @@
load("//tools:defs.bzl", "go_library", "go_test")
package(
- default_visibility = ["//test/packetimpact:__subpackages__"],
licenses = ["notice"],
)
@@ -15,6 +14,7 @@ go_library(
"rawsockets.go",
"testbench.go",
],
+ visibility = ["//test/packetimpact:__subpackages__"],
deps = [
"//pkg/tcpip",
"//pkg/tcpip/buffer",
diff --git a/test/packetimpact/testbench/dut.go b/test/packetimpact/testbench/dut.go
index be5121d98..aeae5e5d3 100644
--- a/test/packetimpact/testbench/dut.go
+++ b/test/packetimpact/testbench/dut.go
@@ -35,24 +35,26 @@ type DUT struct {
conn *grpc.ClientConn
posixServer POSIXClient
Net *DUTTestNet
+ Uname *DUTUname
}
// NewDUT creates a new connection with the DUT over gRPC.
func NewDUT(t *testing.T) DUT {
t.Helper()
- n := GetDUTTestNet()
- dut := n.ConnectToDUT(t)
+ info := getDUTInfo()
+ dut := info.ConnectToDUT(t)
t.Cleanup(func() {
dut.TearDownConnection()
- dut.Net.Release()
+ info.release()
})
return dut
}
// ConnectToDUT connects to DUT through gRPC.
-func (n *DUTTestNet) ConnectToDUT(t *testing.T) DUT {
+func (info *DUTInfo) ConnectToDUT(t *testing.T) DUT {
t.Helper()
+ n := info.Net
posixServerAddress := net.JoinHostPort(n.POSIXServerIP.String(), fmt.Sprintf("%d", n.POSIXServerPort))
conn, err := grpc.Dial(posixServerAddress, grpc.WithInsecure(), grpc.WithKeepaliveParams(keepalive.ClientParameters{Timeout: RPCKeepalive}))
if err != nil {
@@ -63,6 +65,7 @@ func (n *DUTTestNet) ConnectToDUT(t *testing.T) DUT {
conn: conn,
posixServer: posixServer,
Net: n,
+ Uname: info.Uname,
}
}
diff --git a/test/packetimpact/testbench/testbench.go b/test/packetimpact/testbench/testbench.go
index 891897d55..a73c07e64 100644
--- a/test/packetimpact/testbench/testbench.go
+++ b/test/packetimpact/testbench/testbench.go
@@ -34,14 +34,29 @@ var (
// RPCTimeout is the gRPC timeout.
RPCTimeout = 100 * time.Millisecond
- // dutTestNetsJSON is the json string that describes all the test networks to
+ // dutInfosJSON is the json string that describes information about all the
// duts available to use.
- dutTestNetsJSON string
- // dutTestNets is the pool among which the testbench can choose a DUT to work
+ dutInfosJSON string
+ // dutInfo is the pool among which the testbench can choose a DUT to work
// with.
- dutTestNets chan *DUTTestNet
+ dutInfo chan *DUTInfo
)
+// DUTInfo has both network and uname information about the DUT.
+type DUTInfo struct {
+ Uname *DUTUname
+ Net *DUTTestNet
+}
+
+// DUTUname contains information about the DUT from uname.
+type DUTUname struct {
+ Machine string
+ KernelName string
+ KernelRelease string
+ KernelVersion string
+ OperatingSystem string
+}
+
// DUTTestNet describes the test network setup on dut and how the testbench
// should connect with an existing DUT.
type DUTTestNet struct {
@@ -86,7 +101,7 @@ func registerFlags(fs *flag.FlagSet) {
fs.BoolVar(&Native, "native", Native, "whether the test is running natively")
fs.DurationVar(&RPCTimeout, "rpc_timeout", RPCTimeout, "gRPC timeout")
fs.DurationVar(&RPCKeepalive, "rpc_keepalive", RPCKeepalive, "gRPC keepalive")
- fs.StringVar(&dutTestNetsJSON, "dut_test_nets_json", dutTestNetsJSON, "path to the dut test nets json file")
+ fs.StringVar(&dutInfosJSON, "dut_infos_json", dutInfosJSON, "json that describes the DUTs")
}
// Initialize initializes the testbench, it parse the flags and sets up the
@@ -94,27 +109,27 @@ func registerFlags(fs *flag.FlagSet) {
func Initialize(fs *flag.FlagSet) {
registerFlags(fs)
flag.Parse()
- if err := loadDUTTestNets(); err != nil {
+ if err := loadDUTInfos(); err != nil {
panic(err)
}
}
-// loadDUTTestNets loads available DUT test networks from the json file, it
+// loadDUTInfos loads available DUT test infos from the json file, it
// must be called after flag.Parse().
-func loadDUTTestNets() error {
- var parsedTestNets []DUTTestNet
- if err := json.Unmarshal([]byte(dutTestNetsJSON), &parsedTestNets); err != nil {
+func loadDUTInfos() error {
+ var dutInfos []DUTInfo
+ if err := json.Unmarshal([]byte(dutInfosJSON), &dutInfos); err != nil {
return fmt.Errorf("failed to unmarshal JSON: %w", err)
}
- if got, want := len(parsedTestNets), 1; got < want {
+ if got, want := len(dutInfos), 1; got < want {
return fmt.Errorf("got %d DUTs, the test requires at least %d DUTs", got, want)
}
// Using a buffered channel as semaphore
- dutTestNets = make(chan *DUTTestNet, len(parsedTestNets))
- for i := range parsedTestNets {
- parsedTestNets[i].LocalIPv4 = parsedTestNets[i].LocalIPv4.To4()
- parsedTestNets[i].RemoteIPv4 = parsedTestNets[i].RemoteIPv4.To4()
- dutTestNets <- &parsedTestNets[i]
+ dutInfo = make(chan *DUTInfo, len(dutInfos))
+ for i := range dutInfos {
+ dutInfos[i].Net.LocalIPv4 = dutInfos[i].Net.LocalIPv4.To4()
+ dutInfos[i].Net.RemoteIPv4 = dutInfos[i].Net.RemoteIPv4.To4()
+ dutInfo <- &dutInfos[i]
}
return nil
}
@@ -130,14 +145,13 @@ func GenerateRandomPayload(t *testing.T, n int) []byte {
return buf
}
-// GetDUTTestNet gets a usable DUTTestNet, the function will block until any
-// becomes available.
-func GetDUTTestNet() *DUTTestNet {
- return <-dutTestNets
+// getDUTInfo returns information about an available DUT from the pool. If no
+// DUT is readily available, getDUTInfo blocks until one becomes available.
+func getDUTInfo() *DUTInfo {
+ return <-dutInfo
}
-// Release releases the DUTTestNet back to the pool so that some other test
-// can use.
-func (n *DUTTestNet) Release() {
- dutTestNets <- n
+// release returns the DUTInfo back to the pool.
+func (info *DUTInfo) release() {
+ dutInfo <- info
}