Move multicounter testutil functions out of network/ip

This is in preparation of having aggregated NIC stats at the stack
level. These validation functions will be needed outside of the
network layer packages to test aggregated NIC stats.

PiperOrigin-RevId: 373180565
This commit is contained in:
Arthur Sfez
2021-05-11 10:25:33 -07:00
committed by gVisor bot
parent 1daabac237
commit 60bdf7ed31
11 changed files with 88 additions and 86 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ go_test(
library = ":arp",
deps = [
"//pkg/tcpip",
"//pkg/tcpip/network/internal/testutil",
"//pkg/tcpip/stack",
"//pkg/tcpip/testutil",
],
)
+1 -1
View File
@@ -19,8 +19,8 @@ import (
"testing"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/testutil"
)
var _ stack.NetworkInterface = (*testInterface)(nil)
+1 -4
View File
@@ -4,10 +4,7 @@ package(licenses = ["notice"])
go_library(
name = "testutil",
srcs = [
"testutil.go",
"testutil_unsafe.go",
],
srcs = ["testutil.go"],
visibility = [
"//pkg/tcpip/network/arp:__pkg__",
"//pkg/tcpip/network/internal/fragmentation:__pkg__",
@@ -19,8 +19,6 @@ package testutil
import (
"fmt"
"math/rand"
"reflect"
"strings"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
@@ -129,69 +127,3 @@ func MakeRandPkt(transportHeaderLength int, extraHeaderReserveLength int, viewSi
}
return pkt
}
func checkFieldCounts(ref, multi reflect.Value) error {
refTypeName := ref.Type().Name()
multiTypeName := multi.Type().Name()
refNumField := ref.NumField()
multiNumField := multi.NumField()
if refNumField != multiNumField {
return fmt.Errorf("type %s has an incorrect number of fields: got = %d, want = %d (same as type %s)", multiTypeName, multiNumField, refNumField, refTypeName)
}
return nil
}
func validateField(ref reflect.Value, refName string, m tcpip.MultiCounterStat, multiName string) error {
s, ok := ref.Addr().Interface().(**tcpip.StatCounter)
if !ok {
return fmt.Errorf("expected ref type's to be *StatCounter, but its type is %s", ref.Type().Elem().Name())
}
// The field names are expected to match (case insensitive).
if !strings.EqualFold(refName, multiName) {
return fmt.Errorf("wrong field name: got = %s, want = %s", multiName, refName)
}
base := (*s).Value()
m.Increment()
if (*s).Value() != base+1 {
return fmt.Errorf("updates to the '%s MultiCounterStat' counters are not reflected in the '%s CounterStat'", multiName, refName)
}
return nil
}
// ValidateMultiCounterStats verifies that every counter stored in multi is
// correctly tracking its counterpart in the given counters.
func ValidateMultiCounterStats(multi reflect.Value, counters []reflect.Value) error {
for _, c := range counters {
if err := checkFieldCounts(c, multi); err != nil {
return err
}
}
for i := 0; i < multi.NumField(); i++ {
multiName := multi.Type().Field(i).Name
multiUnsafe := unsafeExposeUnexportedFields(multi.Field(i))
if m, ok := multiUnsafe.Addr().Interface().(*tcpip.MultiCounterStat); ok {
for _, c := range counters {
if err := validateField(unsafeExposeUnexportedFields(c.Field(i)), c.Type().Field(i).Name, *m, multiName); err != nil {
return err
}
}
} else {
var countersNextField []reflect.Value
for _, c := range counters {
countersNextField = append(countersNextField, c.Field(i))
}
if err := ValidateMultiCounterStats(multi.Field(i), countersNextField); err != nil {
return err
}
}
}
return nil
}
+1 -1
View File
@@ -62,7 +62,7 @@ go_test(
library = ":ipv4",
deps = [
"//pkg/tcpip",
"//pkg/tcpip/network/internal/testutil",
"//pkg/tcpip/stack",
"//pkg/tcpip/testutil",
],
)
+1 -1
View File
@@ -19,8 +19,8 @@ import (
"testing"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/testutil"
)
var _ stack.NetworkInterface = (*testInterface)(nil)
+1
View File
@@ -45,6 +45,7 @@ go_test(
"//pkg/tcpip/link/sniffer",
"//pkg/tcpip/network/internal/testutil",
"//pkg/tcpip/stack",
"//pkg/tcpip/testutil",
"//pkg/tcpip/transport/icmp",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/udp",
+10 -9
View File
@@ -31,8 +31,9 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/faketime"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil"
iptestutil "gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/testutil"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
@@ -2603,7 +2604,7 @@ func TestWriteStats(t *testing.T) {
t.Run(writer.name, func(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ep := testutil.NewMockLinkEndpoint(header.IPv6MinimumMTU, &tcpip.ErrInvalidEndpointState{}, test.allowPackets)
ep := iptestutil.NewMockLinkEndpoint(header.IPv6MinimumMTU, &tcpip.ErrInvalidEndpointState{}, test.allowPackets)
rt := buildRoute(t, ep)
var pkts stack.PacketBufferList
for i := 0; i < nPackets; i++ {
@@ -2802,9 +2803,9 @@ func TestFragmentationWritePacket(t *testing.T) {
for _, ft := range fragmentationTests {
t.Run(ft.description, func(t *testing.T) {
pkt := testutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber)
pkt := iptestutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber)
source := pkt.Clone()
ep := testutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32)
ep := iptestutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32)
r := buildRoute(t, ep)
err := r.WritePacket(stack.NetworkHeaderParams{
Protocol: tcp.ProtocolNumber,
@@ -2858,7 +2859,7 @@ func TestFragmentationWritePackets(t *testing.T) {
insertAfter: 1,
},
}
tinyPacket := testutil.MakeRandPkt(header.TCPMinimumSize, extraHeaderReserve+header.IPv6MinimumSize, []int{1}, header.IPv6ProtocolNumber)
tinyPacket := iptestutil.MakeRandPkt(header.TCPMinimumSize, extraHeaderReserve+header.IPv6MinimumSize, []int{1}, header.IPv6ProtocolNumber)
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
@@ -2868,14 +2869,14 @@ func TestFragmentationWritePackets(t *testing.T) {
for i := 0; i < test.insertBefore; i++ {
pkts.PushBack(tinyPacket.Clone())
}
pkt := testutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber)
pkt := iptestutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber)
source := pkt
pkts.PushBack(pkt.Clone())
for i := 0; i < test.insertAfter; i++ {
pkts.PushBack(tinyPacket.Clone())
}
ep := testutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32)
ep := iptestutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32)
r := buildRoute(t, ep)
wantTotalPackets := len(ft.wantFragments) + test.insertBefore + test.insertAfter
@@ -2980,8 +2981,8 @@ func TestFragmentationErrors(t *testing.T) {
for _, ft := range tests {
t.Run(ft.description, func(t *testing.T) {
pkt := testutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber)
ep := testutil.NewMockLinkEndpoint(ft.mtu, ft.mockError, ft.allowPackets)
pkt := iptestutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber)
ep := iptestutil.NewMockLinkEndpoint(ft.mtu, ft.mockError, ft.allowPackets)
r := buildRoute(t, ep)
err := r.WritePacket(stack.NetworkHeaderParams{
Protocol: tcp.ProtocolNumber,
+4 -1
View File
@@ -5,7 +5,10 @@ package(licenses = ["notice"])
go_library(
name = "testutil",
testonly = True,
srcs = ["testutil.go"],
srcs = [
"testutil.go",
"testutil_unsafe.go",
],
visibility = ["//visibility:public"],
deps = ["//pkg/tcpip"],
)
+68
View File
@@ -18,6 +18,8 @@ package testutil
import (
"fmt"
"net"
"reflect"
"strings"
"gvisor.dev/gvisor/pkg/tcpip"
)
@@ -41,3 +43,69 @@ func MustParse6(addr string) tcpip.Address {
}
return tcpip.Address(ip)
}
func checkFieldCounts(ref, multi reflect.Value) error {
refTypeName := ref.Type().Name()
multiTypeName := multi.Type().Name()
refNumField := ref.NumField()
multiNumField := multi.NumField()
if refNumField != multiNumField {
return fmt.Errorf("type %s has an incorrect number of fields: got = %d, want = %d (same as type %s)", multiTypeName, multiNumField, refNumField, refTypeName)
}
return nil
}
func validateField(ref reflect.Value, refName string, m tcpip.MultiCounterStat, multiName string) error {
s, ok := ref.Addr().Interface().(**tcpip.StatCounter)
if !ok {
return fmt.Errorf("expected ref type's to be *StatCounter, but its type is %s", ref.Type().Elem().Name())
}
// The field names are expected to match (case insensitive).
if !strings.EqualFold(refName, multiName) {
return fmt.Errorf("wrong field name: got = %s, want = %s", multiName, refName)
}
base := (*s).Value()
m.Increment()
if (*s).Value() != base+1 {
return fmt.Errorf("updates to the '%s MultiCounterStat' counters are not reflected in the '%s CounterStat'", multiName, refName)
}
return nil
}
// ValidateMultiCounterStats verifies that every counter stored in multi is
// correctly tracking its counterpart in the given counters.
func ValidateMultiCounterStats(multi reflect.Value, counters []reflect.Value) error {
for _, c := range counters {
if err := checkFieldCounts(c, multi); err != nil {
return err
}
}
for i := 0; i < multi.NumField(); i++ {
multiName := multi.Type().Field(i).Name
multiUnsafe := unsafeExposeUnexportedFields(multi.Field(i))
if m, ok := multiUnsafe.Addr().Interface().(*tcpip.MultiCounterStat); ok {
for _, c := range counters {
if err := validateField(unsafeExposeUnexportedFields(c.Field(i)), c.Type().Field(i).Name, *m, multiName); err != nil {
return err
}
}
} else {
var countersNextField []reflect.Value
for _, c := range counters {
countersNextField = append(countersNextField, c.Field(i))
}
if err := ValidateMultiCounterStats(multi.Field(i), countersNextField); err != nil {
return err
}
}
}
return nil
}