summaryrefslogtreecommitdiffhomepage
path: root/test/packetimpact/testbench
diff options
context:
space:
mode:
Diffstat (limited to 'test/packetimpact/testbench')
-rw-r--r--test/packetimpact/testbench/connections.go118
-rw-r--r--test/packetimpact/testbench/dut.go36
-rw-r--r--test/packetimpact/testbench/rawsockets.go22
-rw-r--r--test/packetimpact/testbench/testbench.go165
4 files changed, 211 insertions, 130 deletions
diff --git a/test/packetimpact/testbench/connections.go b/test/packetimpact/testbench/connections.go
index 919b4fd25..266a8601c 100644
--- a/test/packetimpact/testbench/connections.go
+++ b/test/packetimpact/testbench/connections.go
@@ -17,7 +17,6 @@ package testbench
import (
"fmt"
"math/rand"
- "net"
"testing"
"time"
@@ -42,7 +41,7 @@ func portFromSockaddr(sa unix.Sockaddr) (uint16, error) {
// pickPort makes a new socket and returns the socket FD and port. The domain
// should be AF_INET or AF_INET6. The caller must close the FD when done with
// the port if there is no error.
-func pickPort(domain, typ int) (fd int, port uint16, err error) {
+func (n *DUTTestNet) pickPort(domain, typ int) (fd int, port uint16, err error) {
fd, err = unix.Socket(domain, typ, 0)
if err != nil {
return -1, 0, fmt.Errorf("creating socket: %w", err)
@@ -58,11 +57,11 @@ func pickPort(domain, typ int) (fd int, port uint16, err error) {
switch domain {
case unix.AF_INET:
var sa4 unix.SockaddrInet4
- copy(sa4.Addr[:], net.ParseIP(LocalIPv4).To4())
+ copy(sa4.Addr[:], n.LocalIPv4)
sa = &sa4
case unix.AF_INET6:
- sa6 := unix.SockaddrInet6{ZoneId: uint32(LocalInterfaceID)}
- copy(sa6.Addr[:], net.ParseIP(LocalIPv6).To16())
+ sa6 := unix.SockaddrInet6{ZoneId: n.LocalDevID}
+ copy(sa6.Addr[:], n.LocalIPv6)
sa = &sa6
default:
return -1, 0, fmt.Errorf("invalid domain %d, it should be one of unix.AF_INET or unix.AF_INET6", domain)
@@ -117,19 +116,12 @@ type etherState struct {
var _ layerState = (*etherState)(nil)
// newEtherState creates a new etherState.
-func newEtherState(out, in Ether) (*etherState, error) {
- lMAC, err := tcpip.ParseMACAddress(LocalMAC)
- if err != nil {
- return nil, fmt.Errorf("parsing local MAC: %q: %w", LocalMAC, err)
- }
-
- rMAC, err := tcpip.ParseMACAddress(RemoteMAC)
- if err != nil {
- return nil, fmt.Errorf("parsing remote MAC: %q: %w", RemoteMAC, err)
- }
+func (n *DUTTestNet) newEtherState(out, in Ether) (*etherState, error) {
+ lmac := tcpip.LinkAddress(n.LocalMAC)
+ rmac := tcpip.LinkAddress(n.RemoteMAC)
s := etherState{
- out: Ether{SrcAddr: &lMAC, DstAddr: &rMAC},
- in: Ether{SrcAddr: &rMAC, DstAddr: &lMAC},
+ out: Ether{SrcAddr: &lmac, DstAddr: &rmac},
+ in: Ether{SrcAddr: &rmac, DstAddr: &lmac},
}
if err := s.out.merge(&out); err != nil {
return nil, err
@@ -169,9 +161,9 @@ type ipv4State struct {
var _ layerState = (*ipv4State)(nil)
// newIPv4State creates a new ipv4State.
-func newIPv4State(out, in IPv4) (*ipv4State, error) {
- lIP := tcpip.Address(net.ParseIP(LocalIPv4).To4())
- rIP := tcpip.Address(net.ParseIP(RemoteIPv4).To4())
+func (n *DUTTestNet) newIPv4State(out, in IPv4) (*ipv4State, error) {
+ lIP := tcpip.Address(n.LocalIPv4)
+ rIP := tcpip.Address(n.RemoteIPv4)
s := ipv4State{
out: IPv4{SrcAddr: &lIP, DstAddr: &rIP},
in: IPv4{SrcAddr: &rIP, DstAddr: &lIP},
@@ -214,9 +206,9 @@ type ipv6State struct {
var _ layerState = (*ipv6State)(nil)
// newIPv6State creates a new ipv6State.
-func newIPv6State(out, in IPv6) (*ipv6State, error) {
- lIP := tcpip.Address(net.ParseIP(LocalIPv6).To16())
- rIP := tcpip.Address(net.ParseIP(RemoteIPv6).To16())
+func (n *DUTTestNet) newIPv6State(out, in IPv6) (*ipv6State, error) {
+ lIP := tcpip.Address(n.LocalIPv6)
+ rIP := tcpip.Address(n.RemoteIPv6)
s := ipv6State{
out: IPv6{SrcAddr: &lIP, DstAddr: &rIP},
in: IPv6{SrcAddr: &rIP, DstAddr: &lIP},
@@ -272,8 +264,8 @@ func SeqNumValue(v seqnum.Value) *seqnum.Value {
}
// newTCPState creates a new TCPState.
-func newTCPState(domain int, out, in TCP) (*tcpState, error) {
- portPickerFD, localPort, err := pickPort(domain, unix.SOCK_STREAM)
+func (n *DUTTestNet) newTCPState(domain int, out, in TCP) (*tcpState, error) {
+ portPickerFD, localPort, err := n.pickPort(domain, unix.SOCK_STREAM)
if err != nil {
return nil, err
}
@@ -376,8 +368,8 @@ type udpState struct {
var _ layerState = (*udpState)(nil)
// newUDPState creates a new udpState.
-func newUDPState(domain int, out, in UDP) (*udpState, error) {
- portPickerFD, localPort, err := pickPort(domain, unix.SOCK_DGRAM)
+func (n *DUTTestNet) newUDPState(domain int, out, in UDP) (*udpState, error) {
+ portPickerFD, localPort, err := n.pickPort(domain, unix.SOCK_DGRAM)
if err != nil {
return nil, fmt.Errorf("picking port: %w", err)
}
@@ -639,26 +631,26 @@ func (conn *Connection) Drain(t *testing.T) {
type TCPIPv4 Connection
// NewTCPIPv4 creates a new TCPIPv4 connection with reasonable defaults.
-func NewTCPIPv4(t *testing.T, outgoingTCP, incomingTCP TCP) TCPIPv4 {
+func (n *DUTTestNet) NewTCPIPv4(t *testing.T, outgoingTCP, incomingTCP TCP) TCPIPv4 {
t.Helper()
- etherState, err := newEtherState(Ether{}, Ether{})
+ etherState, err := n.newEtherState(Ether{}, Ether{})
if err != nil {
t.Fatalf("can't make etherState: %s", err)
}
- ipv4State, err := newIPv4State(IPv4{}, IPv4{})
+ ipv4State, err := n.newIPv4State(IPv4{}, IPv4{})
if err != nil {
t.Fatalf("can't make ipv4State: %s", err)
}
- tcpState, err := newTCPState(unix.AF_INET, outgoingTCP, incomingTCP)
+ tcpState, err := n.newTCPState(unix.AF_INET, outgoingTCP, incomingTCP)
if err != nil {
t.Fatalf("can't make tcpState: %s", err)
}
- injector, err := NewInjector(t)
+ injector, err := n.NewInjector(t)
if err != nil {
t.Fatalf("can't make injector: %s", err)
}
- sniffer, err := NewSniffer(t)
+ sniffer, err := n.NewSniffer(t)
if err != nil {
t.Fatalf("can't make sniffer: %s", err)
}
@@ -841,23 +833,23 @@ func (conn *TCPIPv4) Drain(t *testing.T) {
type IPv4Conn Connection
// NewIPv4Conn creates a new IPv4Conn connection with reasonable defaults.
-func NewIPv4Conn(t *testing.T, outgoingIPv4, incomingIPv4 IPv4) IPv4Conn {
+func (n *DUTTestNet) NewIPv4Conn(t *testing.T, outgoingIPv4, incomingIPv4 IPv4) IPv4Conn {
t.Helper()
- etherState, err := newEtherState(Ether{}, Ether{})
+ etherState, err := n.newEtherState(Ether{}, Ether{})
if err != nil {
t.Fatalf("can't make EtherState: %s", err)
}
- ipv4State, err := newIPv4State(outgoingIPv4, incomingIPv4)
+ ipv4State, err := n.newIPv4State(outgoingIPv4, incomingIPv4)
if err != nil {
t.Fatalf("can't make IPv4State: %s", err)
}
- injector, err := NewInjector(t)
+ injector, err := n.NewInjector(t)
if err != nil {
t.Fatalf("can't make injector: %s", err)
}
- sniffer, err := NewSniffer(t)
+ sniffer, err := n.NewSniffer(t)
if err != nil {
t.Fatalf("can't make sniffer: %s", err)
}
@@ -896,23 +888,23 @@ func (c *IPv4Conn) ExpectFrame(t *testing.T, frame Layers, timeout time.Duration
type IPv6Conn Connection
// NewIPv6Conn creates a new IPv6Conn connection with reasonable defaults.
-func NewIPv6Conn(t *testing.T, outgoingIPv6, incomingIPv6 IPv6) IPv6Conn {
+func (n *DUTTestNet) NewIPv6Conn(t *testing.T, outgoingIPv6, incomingIPv6 IPv6) IPv6Conn {
t.Helper()
- etherState, err := newEtherState(Ether{}, Ether{})
+ etherState, err := n.newEtherState(Ether{}, Ether{})
if err != nil {
t.Fatalf("can't make EtherState: %s", err)
}
- ipv6State, err := newIPv6State(outgoingIPv6, incomingIPv6)
+ ipv6State, err := n.newIPv6State(outgoingIPv6, incomingIPv6)
if err != nil {
t.Fatalf("can't make IPv6State: %s", err)
}
- injector, err := NewInjector(t)
+ injector, err := n.NewInjector(t)
if err != nil {
t.Fatalf("can't make injector: %s", err)
}
- sniffer, err := NewSniffer(t)
+ sniffer, err := n.NewSniffer(t)
if err != nil {
t.Fatalf("can't make sniffer: %s", err)
}
@@ -951,26 +943,26 @@ func (conn *IPv6Conn) ExpectFrame(t *testing.T, frame Layers, timeout time.Durat
type UDPIPv4 Connection
// NewUDPIPv4 creates a new UDPIPv4 connection with reasonable defaults.
-func NewUDPIPv4(t *testing.T, outgoingUDP, incomingUDP UDP) UDPIPv4 {
+func (n *DUTTestNet) NewUDPIPv4(t *testing.T, outgoingUDP, incomingUDP UDP) UDPIPv4 {
t.Helper()
- etherState, err := newEtherState(Ether{}, Ether{})
+ etherState, err := n.newEtherState(Ether{}, Ether{})
if err != nil {
t.Fatalf("can't make etherState: %s", err)
}
- ipv4State, err := newIPv4State(IPv4{}, IPv4{})
+ ipv4State, err := n.newIPv4State(IPv4{}, IPv4{})
if err != nil {
t.Fatalf("can't make ipv4State: %s", err)
}
- udpState, err := newUDPState(unix.AF_INET, outgoingUDP, incomingUDP)
+ udpState, err := n.newUDPState(unix.AF_INET, outgoingUDP, incomingUDP)
if err != nil {
t.Fatalf("can't make udpState: %s", err)
}
- injector, err := NewInjector(t)
+ injector, err := n.NewInjector(t)
if err != nil {
t.Fatalf("can't make injector: %s", err)
}
- sniffer, err := NewSniffer(t)
+ sniffer, err := n.NewSniffer(t)
if err != nil {
t.Fatalf("can't make sniffer: %s", err)
}
@@ -1075,26 +1067,26 @@ func (conn *UDPIPv4) Drain(t *testing.T) {
type UDPIPv6 Connection
// NewUDPIPv6 creates a new UDPIPv6 connection with reasonable defaults.
-func NewUDPIPv6(t *testing.T, outgoingUDP, incomingUDP UDP) UDPIPv6 {
+func (n *DUTTestNet) NewUDPIPv6(t *testing.T, outgoingUDP, incomingUDP UDP) UDPIPv6 {
t.Helper()
- etherState, err := newEtherState(Ether{}, Ether{})
+ etherState, err := n.newEtherState(Ether{}, Ether{})
if err != nil {
t.Fatalf("can't make etherState: %s", err)
}
- ipv6State, err := newIPv6State(IPv6{}, IPv6{})
+ ipv6State, err := n.newIPv6State(IPv6{}, IPv6{})
if err != nil {
t.Fatalf("can't make IPv6State: %s", err)
}
- udpState, err := newUDPState(unix.AF_INET6, outgoingUDP, incomingUDP)
+ udpState, err := n.newUDPState(unix.AF_INET6, outgoingUDP, incomingUDP)
if err != nil {
t.Fatalf("can't make udpState: %s", err)
}
- injector, err := NewInjector(t)
+ injector, err := n.NewInjector(t)
if err != nil {
t.Fatalf("can't make injector: %s", err)
}
- sniffer, err := NewSniffer(t)
+ sniffer, err := n.NewSniffer(t)
if err != nil {
t.Fatalf("can't make sniffer: %s", err)
}
@@ -1126,14 +1118,14 @@ func (conn *UDPIPv6) ipv6State(t *testing.T) *ipv6State {
}
// LocalAddr gets the local socket address of this connection.
-func (conn *UDPIPv6) LocalAddr(t *testing.T) *unix.SockaddrInet6 {
+func (conn *UDPIPv6) LocalAddr(t *testing.T, zoneID uint32) *unix.SockaddrInet6 {
t.Helper()
sa := &unix.SockaddrInet6{
Port: int(*conn.udpState(t).out.SrcPort),
// Local address is in perspective to the remote host, so it's scoped to the
// ID of the remote interface.
- ZoneId: uint32(RemoteInterfaceID),
+ ZoneId: zoneID,
}
copy(sa.Addr[:], *conn.ipv6State(t).out.SrcAddr)
return sa
@@ -1203,24 +1195,24 @@ func (conn *UDPIPv6) Drain(t *testing.T) {
type TCPIPv6 Connection
// NewTCPIPv6 creates a new TCPIPv6 connection with reasonable defaults.
-func NewTCPIPv6(t *testing.T, outgoingTCP, incomingTCP TCP) TCPIPv6 {
- etherState, err := newEtherState(Ether{}, Ether{})
+func (n *DUTTestNet) NewTCPIPv6(t *testing.T, outgoingTCP, incomingTCP TCP) TCPIPv6 {
+ etherState, err := n.newEtherState(Ether{}, Ether{})
if err != nil {
t.Fatalf("can't make etherState: %s", err)
}
- ipv6State, err := newIPv6State(IPv6{}, IPv6{})
+ ipv6State, err := n.newIPv6State(IPv6{}, IPv6{})
if err != nil {
t.Fatalf("can't make ipv6State: %s", err)
}
- tcpState, err := newTCPState(unix.AF_INET6, outgoingTCP, incomingTCP)
+ tcpState, err := n.newTCPState(unix.AF_INET6, outgoingTCP, incomingTCP)
if err != nil {
t.Fatalf("can't make tcpState: %s", err)
}
- injector, err := NewInjector(t)
+ injector, err := n.NewInjector(t)
if err != nil {
t.Fatalf("can't make injector: %s", err)
}
- sniffer, err := NewSniffer(t)
+ sniffer, err := n.NewSniffer(t)
if err != nil {
t.Fatalf("can't make sniffer: %s", err)
}
diff --git a/test/packetimpact/testbench/dut.go b/test/packetimpact/testbench/dut.go
index 6165ab293..66a0255b8 100644
--- a/test/packetimpact/testbench/dut.go
+++ b/test/packetimpact/testbench/dut.go
@@ -17,9 +17,8 @@ package testbench
import (
"context"
"encoding/binary"
- "flag"
+ "fmt"
"net"
- "strconv"
"syscall"
"testing"
"time"
@@ -35,18 +34,26 @@ import (
type DUT struct {
conn *grpc.ClientConn
posixServer POSIXClient
+ Net *DUTTestNet
}
// NewDUT creates a new connection with the DUT over gRPC.
func NewDUT(t *testing.T) DUT {
t.Helper()
+ n := GetDUTTestNet()
+ dut := n.ConnectToDUT(t)
+ t.Cleanup(func() {
+ dut.TearDownConnection()
+ dut.Net.Release()
+ })
+ return dut
+}
- flag.Parse()
- if err := genPseudoFlags(); err != nil {
- t.Fatal("generating psuedo flags:", err)
- }
+// ConnectToDUT connects to DUT through gRPC.
+func (n *DUTTestNet) ConnectToDUT(t *testing.T) DUT {
+ t.Helper()
- posixServerAddress := POSIXServerIP + ":" + strconv.Itoa(POSIXServerPort)
+ 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 {
t.Fatalf("failed to grpc.Dial(%s): %s", posixServerAddress, err)
@@ -55,11 +62,12 @@ func NewDUT(t *testing.T) DUT {
return DUT{
conn: conn,
posixServer: posixServer,
+ Net: n,
}
}
-// TearDown closes the underlying connection.
-func (dut *DUT) TearDown() {
+// TearDownConnection closes the underlying connection.
+func (dut *DUT) TearDownConnection() {
dut.conn.Close()
}
@@ -132,7 +140,7 @@ func (dut *DUT) CreateBoundSocket(t *testing.T, typ, proto int32, addr net.IP) (
fd = dut.Socket(t, unix.AF_INET6, typ, proto)
sa := unix.SockaddrInet6{}
copy(sa.Addr[:], addr.To16())
- sa.ZoneId = uint32(RemoteInterfaceID)
+ sa.ZoneId = dut.Net.RemoteDevID
dut.Bind(t, fd, &sa)
} else {
t.Fatalf("invalid IP address: %s", addr)
@@ -154,7 +162,7 @@ func (dut *DUT) CreateBoundSocket(t *testing.T, typ, proto int32, addr net.IP) (
func (dut *DUT) CreateListener(t *testing.T, typ, proto, backlog int32) (int32, uint16) {
t.Helper()
- fd, remotePort := dut.CreateBoundSocket(t, typ, proto, net.ParseIP(RemoteIPv4))
+ fd, remotePort := dut.CreateBoundSocket(t, typ, proto, dut.Net.RemoteIPv4)
dut.Listen(t, fd, backlog)
return fd, remotePort
}
@@ -717,9 +725,9 @@ func (dut *DUT) SetSockLingerOption(t *testing.T, sockfd int32, timeout time.Dur
dut.SetSockOpt(t, sockfd, unix.SOL_SOCKET, unix.SO_LINGER, buf)
}
-// Shutdown calls shutdown on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over the timeout or error handling is needed, use
-// ShutdownWithErrno.
+// Shutdown calls shutdown on the DUT and causes a fatal test failure if it
+// doesn't succeed. If more control over the timeout or error handling is
+// needed, use ShutdownWithErrno.
func (dut *DUT) Shutdown(t *testing.T, fd, how int32) error {
t.Helper()
diff --git a/test/packetimpact/testbench/rawsockets.go b/test/packetimpact/testbench/rawsockets.go
index 193bb2dc8..fd8015ce2 100644
--- a/test/packetimpact/testbench/rawsockets.go
+++ b/test/packetimpact/testbench/rawsockets.go
@@ -38,13 +38,27 @@ func htons(x uint16) uint16 {
}
// NewSniffer creates a Sniffer connected to *device.
-func NewSniffer(t *testing.T) (Sniffer, error) {
+func (n *DUTTestNet) NewSniffer(t *testing.T) (Sniffer, error) {
t.Helper()
+ ifInfo, err := net.InterfaceByName(n.LocalDevName)
+ if err != nil {
+ return Sniffer{}, err
+ }
+
+ var haddr [8]byte
+ copy(haddr[:], ifInfo.HardwareAddr)
+ sa := unix.SockaddrLinklayer{
+ Protocol: htons(unix.ETH_P_ALL),
+ Ifindex: ifInfo.Index,
+ }
snifferFd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW, int(htons(unix.ETH_P_ALL)))
if err != nil {
return Sniffer{}, err
}
+ if err := unix.Bind(snifferFd, &sa); err != nil {
+ return Sniffer{}, err
+ }
if err := unix.SetsockoptInt(snifferFd, unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, 1); err != nil {
t.Fatalf("can't set sockopt SO_RCVBUFFORCE to 1: %s", err)
}
@@ -136,10 +150,10 @@ type Injector struct {
}
// NewInjector creates a new injector on *device.
-func NewInjector(t *testing.T) (Injector, error) {
+func (n *DUTTestNet) NewInjector(t *testing.T) (Injector, error) {
t.Helper()
- ifInfo, err := net.InterfaceByName(LocalDevice)
+ ifInfo, err := net.InterfaceByName(n.LocalDevName)
if err != nil {
return Injector{}, err
}
@@ -147,7 +161,7 @@ func NewInjector(t *testing.T) (Injector, error) {
var haddr [8]byte
copy(haddr[:], ifInfo.HardwareAddr)
sa := unix.SockaddrLinklayer{
- Protocol: unix.ETH_P_IP,
+ Protocol: htons(unix.ETH_P_IP),
Ifindex: ifInfo.Index,
Halen: uint8(len(ifInfo.HardwareAddr)),
Addr: haddr,
diff --git a/test/packetimpact/testbench/testbench.go b/test/packetimpact/testbench/testbench.go
index c1db95d8c..92200add9 100644
--- a/test/packetimpact/testbench/testbench.go
+++ b/test/packetimpact/testbench/testbench.go
@@ -31,64 +31,120 @@ import (
var (
// Native indicates that the test is being run natively.
Native = false
- // LocalDevice is the device that testbench uses to inject traffic.
- LocalDevice = ""
- // RemoteDevice is the device name on the DUT, individual tests can
- // use the name to construct tests.
- RemoteDevice = ""
+ // RPCKeepalive is the gRPC keepalive.
+ RPCKeepalive = 10 * time.Second
+ // RPCTimeout is the gRPC timeout.
+ RPCTimeout = 100 * time.Millisecond
+ // dutTestNets is the pool among which the testbench can choose a DUT to work
+ // with.
+ dutTestNets chan *DUTTestNet
+
+ // TODO(zeling): Remove the following variables once the test runner side is
+ // ready.
+ localDevice = ""
+ remoteDevice = ""
+ localIPv4 = ""
+ remoteIPv4 = ""
+ ipv4PrefixLength = 0
+ localIPv6 = ""
+ remoteIPv6 = ""
+ localInterfaceID uint32
+ remoteInterfaceID uint64
+ localMAC = ""
+ remoteMAC = ""
+ posixServerIP = ""
+ posixServerPort = 40000
+)
+
+// DUTTestNet describes the test network setup on dut and how the testbench
+// should connect with an existing DUT.
+type DUTTestNet struct {
+ // LocalMAC is the local MAC address on the test network.
+ LocalMAC net.HardwareAddr
+ // RemoteMAC is the DUT's MAC address on the test network.
+ RemoteMAC net.HardwareAddr
// LocalIPv4 is the local IPv4 address on the test network.
- LocalIPv4 = ""
+ LocalIPv4 net.IP
// RemoteIPv4 is the DUT's IPv4 address on the test network.
- RemoteIPv4 = ""
+ RemoteIPv4 net.IP
// IPv4PrefixLength is the network prefix length of the IPv4 test network.
- IPv4PrefixLength = 0
-
+ IPv4PrefixLength int
// LocalIPv6 is the local IPv6 address on the test network.
- LocalIPv6 = ""
+ LocalIPv6 net.IP
// RemoteIPv6 is the DUT's IPv6 address on the test network.
- RemoteIPv6 = ""
-
- // LocalInterfaceID is the ID of the local interface on the test network.
- LocalInterfaceID uint32
- // RemoteInterfaceID is the ID of the remote interface on the test network.
- //
- // Not using uint32 because package flag does not support uint32.
- RemoteInterfaceID uint64
+ RemoteIPv6 net.IP
+ // LocalDevID is the ID of the local interface on the test network.
+ LocalDevID uint32
+ // RemoteDevID is the ID of the remote interface on the test network.
+ RemoteDevID uint32
+ // LocalDevName is the device that testbench uses to inject traffic.
+ LocalDevName string
+ // RemoteDevName is the device name on the DUT, individual tests can
+ // use the name to construct tests.
+ RemoteDevName string
- // LocalMAC is the local MAC address on the test network.
- LocalMAC = ""
- // RemoteMAC is the DUT's MAC address on the test network.
- RemoteMAC = ""
+ // The following two fields on actually on the control network instead
+ // of the test network, including them for convenience.
// POSIXServerIP is the POSIX server's IP address on the control network.
- POSIXServerIP = ""
+ POSIXServerIP net.IP
// POSIXServerPort is the UDP port the POSIX server is bound to on the
// control network.
- POSIXServerPort = 40000
-
- // RPCKeepalive is the gRPC keepalive.
- RPCKeepalive = 10 * time.Second
- // RPCTimeout is the gRPC timeout.
- RPCTimeout = 100 * time.Millisecond
-)
+ POSIXServerPort uint16
+}
-// RegisterFlags defines flags and associates them with the package-level
+// registerFlags defines flags and associates them with the package-level
// exported variables above. It should be called by tests in their init
// functions.
-func RegisterFlags(fs *flag.FlagSet) {
- fs.StringVar(&POSIXServerIP, "posix_server_ip", POSIXServerIP, "ip address to listen to for UDP commands")
- fs.IntVar(&POSIXServerPort, "posix_server_port", POSIXServerPort, "port to listen to for UDP commands")
+func registerFlags(fs *flag.FlagSet) {
+ fs.StringVar(&posixServerIP, "posix_server_ip", posixServerIP, "ip address to listen to for UDP commands")
+ fs.IntVar(&posixServerPort, "posix_server_port", posixServerPort, "port to listen to for UDP commands")
+ fs.StringVar(&localIPv4, "local_ipv4", localIPv4, "local IPv4 address for test packets")
+ fs.StringVar(&remoteIPv4, "remote_ipv4", remoteIPv4, "remote IPv4 address for test packets")
+ fs.StringVar(&remoteIPv6, "remote_ipv6", remoteIPv6, "remote IPv6 address for test packets")
+ fs.StringVar(&remoteMAC, "remote_mac", remoteMAC, "remote mac address for test packets")
+ fs.StringVar(&localDevice, "local_device", localDevice, "local device to inject traffic")
+ fs.StringVar(&remoteDevice, "remote_device", remoteDevice, "remote device on the DUT")
+ fs.Uint64Var(&remoteInterfaceID, "remote_interface_id", remoteInterfaceID, "remote interface ID for test packets")
+
+ 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(&LocalIPv4, "local_ipv4", LocalIPv4, "local IPv4 address for test packets")
- fs.StringVar(&RemoteIPv4, "remote_ipv4", RemoteIPv4, "remote IPv4 address for test packets")
- fs.StringVar(&RemoteIPv6, "remote_ipv6", RemoteIPv6, "remote IPv6 address for test packets")
- fs.StringVar(&RemoteMAC, "remote_mac", RemoteMAC, "remote mac address for test packets")
- fs.StringVar(&LocalDevice, "local_device", LocalDevice, "local device to inject traffic")
- fs.StringVar(&RemoteDevice, "remote_device", RemoteDevice, "remote device on the DUT")
- fs.BoolVar(&Native, "native", Native, "whether the test is running natively")
- fs.Uint64Var(&RemoteInterfaceID, "remote_interface_id", RemoteInterfaceID, "remote interface ID for test packets")
+}
+
+// Initialize initializes the testbench, it parse the flags and sets up the
+// pool of test networks for testbench's later use.
+func Initialize(fs *flag.FlagSet) {
+ registerFlags(fs)
+ flag.Parse()
+ if err := genPseudoFlags(); err != nil {
+ panic(err)
+ }
+ var dut DUTTestNet
+ var err error
+ dut.LocalMAC, err = net.ParseMAC(localMAC)
+ if err != nil {
+ panic(err)
+ }
+ dut.RemoteMAC, err = net.ParseMAC(remoteMAC)
+ if err != nil {
+ panic(err)
+ }
+ dut.LocalIPv4 = net.ParseIP(localIPv4).To4()
+ dut.LocalIPv6 = net.ParseIP(localIPv6).To16()
+ dut.RemoteIPv4 = net.ParseIP(remoteIPv4).To4()
+ dut.RemoteIPv6 = net.ParseIP(remoteIPv6).To16()
+ dut.LocalDevID = uint32(localInterfaceID)
+ dut.RemoteDevID = uint32(remoteInterfaceID)
+ dut.LocalDevName = localDevice
+ dut.RemoteDevName = remoteDevice
+ dut.POSIXServerIP = net.ParseIP(posixServerIP)
+ dut.POSIXServerPort = uint16(posixServerPort)
+ dut.IPv4PrefixLength = ipv4PrefixLength
+
+ dutTestNets = make(chan *DUTTestNet, 1)
+ dutTestNets <- &dut
}
// genPseudoFlags populates flag-like global config based on real flags.
@@ -104,21 +160,20 @@ func genPseudoFlags() error {
return fmt.Errorf("parsing devices: %w", err)
}
- _, deviceInfo, err := netdevs.FindDeviceByIP(net.ParseIP(LocalIPv4), devs)
+ _, deviceInfo, err := netdevs.FindDeviceByIP(net.ParseIP(localIPv4), devs)
if err != nil {
return fmt.Errorf("can't find deviceInfo: %w", err)
}
- LocalMAC = deviceInfo.MAC.String()
- LocalIPv6 = deviceInfo.IPv6Addr.String()
- LocalInterfaceID = deviceInfo.ID
+ localMAC = deviceInfo.MAC.String()
+ localIPv6 = deviceInfo.IPv6Addr.String()
+ localInterfaceID = deviceInfo.ID
if deviceInfo.IPv4Net != nil {
- IPv4PrefixLength, _ = deviceInfo.IPv4Net.Mask.Size()
+ ipv4PrefixLength, _ = deviceInfo.IPv4Net.Mask.Size()
} else {
- IPv4PrefixLength, _ = net.ParseIP(LocalIPv4).DefaultMask().Size()
+ ipv4PrefixLength, _ = net.ParseIP(localIPv4).DefaultMask().Size()
}
-
return nil
}
@@ -132,3 +187,15 @@ 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
+}
+
+// Release releases the DUTTestNet back to the pool so that some other test
+// can use.
+func (n *DUTTestNet) Release() {
+ dutTestNets <- n
+}