summaryrefslogtreecommitdiffhomepage
path: root/test/packetimpact/testbench
diff options
context:
space:
mode:
authorSam Balana <sbalana@google.com>2021-05-27 16:16:29 -0700
committergVisor bot <gvisor-bot@google.com>2021-05-27 16:19:00 -0700
commit121af37738525a629ecc11863b7454b67c0f4117 (patch)
tree16ab7bc5c0d2528482264f15f3daf524a38af866 /test/packetimpact/testbench
parent17df2df75ca092342a29694739d6fbe3bf95b770 (diff)
Support SO_BINDTODEVICE in ICMP sockets
Adds support for the SO_BINDTODEVICE socket option in ICMP sockets with an accompanying packetimpact test to exercise use of this socket option. Adds a unit test to exercise the NIC selection logic introduced by this change. The remaining unit tests for ICMP sockets need to be added in a subsequent CL. See https://gvisor.dev/issues/5623 for the list of remaining unit tests. Adds a "timeout" field to PacketimpactTestInfo, necessary due to the long runtime of the newly added packetimpact test. Fixes #5678 Fixes #4896 Updates #5623 Updates #5681 Updates #5763 Updates #5956 Updates #5966 Updates #5967 PiperOrigin-RevId: 376271581
Diffstat (limited to 'test/packetimpact/testbench')
-rw-r--r--test/packetimpact/testbench/connections.go54
-rw-r--r--test/packetimpact/testbench/layers.go7
-rw-r--r--test/packetimpact/testbench/testbench.go22
3 files changed, 65 insertions, 18 deletions
diff --git a/test/packetimpact/testbench/connections.go b/test/packetimpact/testbench/connections.go
index 8ad9040ff..ed56f9ac7 100644
--- a/test/packetimpact/testbench/connections.go
+++ b/test/packetimpact/testbench/connections.go
@@ -594,32 +594,50 @@ func (conn *Connection) Expect(t *testing.T, layer Layer, timeout time.Duration)
func (conn *Connection) ExpectFrame(t *testing.T, layers Layers, timeout time.Duration) (Layers, error) {
t.Helper()
- deadline := time.Now().Add(timeout)
+ frames, ok := conn.ListenForFrame(t, layers, timeout)
+ if ok {
+ return frames[len(frames)-1], nil
+ }
+ if len(frames) == 0 {
+ return nil, fmt.Errorf("got no frames matching %s during %s", layers, timeout)
+ }
+
var errs error
+ for _, got := range frames {
+ want := conn.incoming(layers)
+ if err := want.merge(layers); err != nil {
+ errs = multierr.Combine(errs, err)
+ } else {
+ errs = multierr.Combine(errs, &layersError{got: got, want: want})
+ }
+ }
+ return nil, fmt.Errorf("got frames:\n%w want %s during %s", errs, layers, timeout)
+}
+
+// ListenForFrame captures all frames until a frame matches the provided Layers,
+// or until the timeout specified. Returns all captured frames, including the
+// matched frame, and true if the desired frame was found.
+func (conn *Connection) ListenForFrame(t *testing.T, layers Layers, timeout time.Duration) ([]Layers, bool) {
+ t.Helper()
+
+ deadline := time.Now().Add(timeout)
+ var frames []Layers
for {
- var gotLayers Layers
+ var got Layers
if timeout := time.Until(deadline); timeout > 0 {
- gotLayers = conn.recvFrame(t, timeout)
+ got = conn.recvFrame(t, timeout)
}
- if gotLayers == nil {
- if errs == nil {
- return nil, fmt.Errorf("got no frames matching %s during %s", layers, timeout)
- }
- return nil, fmt.Errorf("got frames:\n%w want %s during %s", errs, layers, timeout)
+ if got == nil {
+ return frames, false
}
- if conn.match(layers, gotLayers) {
+ frames = append(frames, got)
+ if conn.match(layers, got) {
for i, s := range conn.layerStates {
- if err := s.received(gotLayers[i]); err != nil {
+ if err := s.received(got[i]); err != nil {
t.Fatalf("failed to update test connection's layer states based on received frame: %s", err)
}
}
- return gotLayers, nil
- }
- want := conn.incoming(layers)
- if err := want.merge(layers); err != nil {
- errs = multierr.Combine(errs, err)
- } else {
- errs = multierr.Combine(errs, &layersError{got: gotLayers, want: want})
+ return frames, true
}
}
}
@@ -1025,6 +1043,8 @@ func (conn *UDPIPv4) SendIP(t *testing.T, ip IPv4, udp UDP, additionalLayers ...
// SendFrame sends a frame on the wire and updates the state of all layers.
func (conn *UDPIPv4) SendFrame(t *testing.T, overrideLayers Layers, additionalLayers ...Layer) {
+ t.Helper()
+
conn.send(t, overrideLayers, additionalLayers...)
}
diff --git a/test/packetimpact/testbench/layers.go b/test/packetimpact/testbench/layers.go
index ef8b63db4..078f500e4 100644
--- a/test/packetimpact/testbench/layers.go
+++ b/test/packetimpact/testbench/layers.go
@@ -824,6 +824,7 @@ type ICMPv6 struct {
Type *header.ICMPv6Type
Code *header.ICMPv6Code
Checksum *uint16
+ Ident *uint16 // Only in Echo Request/Reply.
Pointer *uint32 // Only in Parameter Problem.
Payload []byte
}
@@ -849,6 +850,10 @@ func (l *ICMPv6) ToBytes() ([]byte, error) {
}
typ := h.Type()
switch typ {
+ case header.ICMPv6EchoRequest, header.ICMPv6EchoReply:
+ if l.Ident != nil {
+ h.SetIdent(*l.Ident)
+ }
case header.ICMPv6ParamProblem:
if l.Pointer != nil {
h.SetTypeSpecific(*l.Pointer)
@@ -899,6 +904,8 @@ func parseICMPv6(b []byte) (Layer, layerParser) {
Payload: h.Payload(),
}
switch msgType {
+ case header.ICMPv6EchoRequest, header.ICMPv6EchoReply:
+ icmpv6.Ident = Uint16(h.Ident())
case header.ICMPv6ParamProblem:
icmpv6.Pointer = Uint32(h.TypeSpecific())
}
diff --git a/test/packetimpact/testbench/testbench.go b/test/packetimpact/testbench/testbench.go
index 37d02365a..d0efbcc08 100644
--- a/test/packetimpact/testbench/testbench.go
+++ b/test/packetimpact/testbench/testbench.go
@@ -57,11 +57,21 @@ type DUTUname struct {
OperatingSystem string
}
-// IsLinux returns true if we are running natively on Linux.
+// IsLinux returns true if the DUT is running Linux.
func (n *DUTUname) IsLinux() bool {
return Native && n.OperatingSystem == "GNU/Linux"
}
+// IsGvisor returns true if the DUT is running gVisor.
+func (*DUTUname) IsGvisor() bool {
+ return !Native
+}
+
+// IsFuchsia returns true if the DUT is running Fuchsia.
+func (n *DUTUname) IsFuchsia() bool {
+ return Native && n.OperatingSystem == "Fuchsia"
+}
+
// DUTTestNet describes the test network setup on dut and how the testbench
// should connect with an existing DUT.
type DUTTestNet struct {
@@ -99,6 +109,16 @@ type DUTTestNet struct {
POSIXServerPort uint16
}
+// SubnetBroadcast returns the test network's subnet broadcast address.
+func (n *DUTTestNet) SubnetBroadcast() net.IP {
+ addr := append([]byte(nil), n.RemoteIPv4...)
+ mask := net.CIDRMask(n.IPv4PrefixLength, net.IPv4len*8)
+ for i := range addr {
+ addr[i] |= ^mask[i]
+ }
+ return addr
+}
+
// registerFlags defines flags and associates them with the package-level
// exported variables above. It should be called by tests in their init
// functions.