blob: 66f55e532bb83b0616c8383122f55bff5e23f662 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package netstack
import (
"reflect"
"sort"
"strconv"
"syscall/zx"
"testing"
"netstack/link/eth"
"fidl/fuchsia/hardware/ethernet"
inspect "fidl/fuchsia/inspect/deprecated"
ethernetext "fidlext/fuchsia/hardware/ethernet"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"gvisor.dev/gvisor/pkg/waiter"
)
func TestStatCounterInspectImpl(t *testing.T) {
s := tcpip.Stats{}.FillIn()
v := statCounterInspectImpl{
name: "doesn't matter",
value: reflect.ValueOf(s),
}
children := v.ListChildren()
if diff := cmp.Diff([]string{
"ICMP",
"IP",
"TCP",
"UDP",
}, children); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
for _, childName := range children {
if child := v.GetChild(childName); child == nil {
t.Errorf("got GetChild(%s) = %v, want non-nil", childName, child)
} else if _, ok := child.(*statCounterInspectImpl); !ok {
t.Errorf("got GetChild(%s) = %T, want %T", childName, child, &statCounterInspectImpl{})
}
}
childName := "not a real child"
if child := v.GetChild(childName); child != nil {
t.Errorf("got GetChild(%s) = %s, want = %v", childName, child, nil)
}
s.UnknownProtocolRcvdPackets.IncrementBy(1)
s.MalformedRcvdPackets.IncrementBy(2)
s.DroppedPackets.IncrementBy(3)
if diff := cmp.Diff(inspect.Object{
Name: v.name,
Metrics: []inspect.Metric{
{Key: "UnknownProtocolRcvdPackets", Value: inspect.MetricValueWithUintValue(s.UnknownProtocolRcvdPackets.Value())},
{Key: "MalformedRcvdPackets", Value: inspect.MetricValueWithUintValue(s.MalformedRcvdPackets.Value())},
{Key: "DroppedPackets", Value: inspect.MetricValueWithUintValue(s.DroppedPackets.Value())},
},
}, v.ReadData(), cmpopts.IgnoreUnexported(inspect.Object{}, inspect.Metric{})); diff != "" {
t.Errorf("ReadData() mismatch (-want +got):\n%s", diff)
}
}
func TestSocketStatCounterInspectImpl(t *testing.T) {
// Create a new netstack and add TCP and UDP endpoints.
ns := newNetstack(t)
wq := new(waiter.Queue)
tcpEP, err := ns.stack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, wq)
if err != nil {
t.Fatal(err)
}
udpEP, err := ns.stack.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, wq)
if err != nil {
t.Fatal(err)
}
v := socketInfoMapInspectImpl{
value: &ns.endpoints,
}
children := v.ListChildren()
if diff := cmp.Diff([]string(nil), children); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
// Add the 2 endpoints to endpoints with key being the transport protocol
// number.
const key1 = 1
const key2 = 2
ns.endpoints.Store(key1, tcpEP)
ns.endpoints.Store(key2, udpEP)
children = v.ListChildren()
sort.Strings(children)
if diff := cmp.Diff([]string{strconv.Itoa(key1), strconv.Itoa(key2)}, children); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
childName := "not a real child"
if child := v.GetChild(childName); child != nil {
t.Errorf("got GetChild(%s) = %s, want = %v", childName, child, nil)
}
for _, name := range children {
child := v.GetChild(name)
if child == nil {
t.Fatalf("got GetChild(%s) = %v, want non-nil", name, child)
}
var protoName string
var expectInspectObj inspect.Object
// Update protocol specific expected values.
val, err := strconv.ParseUint(name, 10, 64)
if err != nil {
t.Fatalf("string parsing error %s", err)
}
switch val {
case key1:
protoName = "TCP"
expectInspectObj = inspect.Object{
Name: "Stats",
Metrics: []inspect.Metric{
{Key: "SegmentsReceived", Value: inspect.MetricValueWithUintValue(0)},
{Key: "SegmentsSent", Value: inspect.MetricValueWithUintValue(0)},
{Key: "FailedConnectionAttempts", Value: inspect.MetricValueWithUintValue(0)},
},
}
case key2:
protoName = "UDP"
expectInspectObj = inspect.Object{
Name: "Stats",
Metrics: []inspect.Metric{
{Key: "PacketsReceived", Value: inspect.MetricValueWithUintValue(0)},
{Key: "PacketsSent", Value: inspect.MetricValueWithUintValue(0)},
},
}
}
epChildren := child.ListChildren()
if diff := cmp.Diff([]string{
"Stats",
}, epChildren); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
for _, c := range epChildren {
if c == "Stats" {
statsChild := child.GetChild(c)
if diff := cmp.Diff([]string{
"ReceiveErrors",
"ReadErrors",
"SendErrors",
"WriteErrors",
}, statsChild.ListChildren()); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
// Compare against the expected inspect objects.
if diff := cmp.Diff(expectInspectObj, statsChild.ReadData(), cmpopts.IgnoreUnexported(inspect.Object{}, inspect.Metric{}, inspect.Property{})); diff != "" {
t.Errorf("ReadData() mismatch (-want +got):\n%s", diff)
}
}
}
if diff := cmp.Diff(inspect.Object{
Name: name,
Properties: []inspect.Property{
{Key: "NetworkProtocol", Value: inspect.PropertyValueWithStr("IPv4")},
{Key: "TransportProtocol", Value: inspect.PropertyValueWithStr(protoName)},
{Key: "State", Value: inspect.PropertyValueWithStr("INITIAL")},
{Key: "LocalAddress", Value: inspect.PropertyValueWithStr(":0")},
{Key: "RemoteAddress", Value: inspect.PropertyValueWithStr(":0")},
{Key: "BindAddress", Value: inspect.PropertyValueWithStr("")},
{Key: "BindNICID", Value: inspect.PropertyValueWithStr("0")},
{Key: "RegisterNICID", Value: inspect.PropertyValueWithStr("0")},
},
}, child.ReadData(), cmpopts.IgnoreUnexported(inspect.Object{}, inspect.Metric{}, inspect.Property{})); diff != "" {
t.Errorf("ReadData() mismatch (-want +got):\n%s", diff)
}
}
// Empty the endpoints.
ns.endpoints.Range(func(handle zx.Handle, _ tcpip.Endpoint) bool {
ns.endpoints.Delete(handle)
return true
})
children = v.ListChildren()
if diff := cmp.Diff([]string(nil), children); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
}
func TestNicInfoMapInspectImpl(t *testing.T) {
v := nicInfoMapInspectImpl{
value: map[tcpip.NICID]ifStateInfo{
1: {},
2: {},
},
}
children := v.ListChildren()
if diff := cmp.Diff([]string{
"1", "2",
}, children); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
for _, childName := range children {
if child := v.GetChild(childName); child == nil {
t.Errorf("got GetChild(%s) = %v, want non-nil", childName, child)
} else if _, ok := child.(*nicInfoInspectImpl); !ok {
t.Errorf("got GetChild(%s) = %T, want %T", childName, child, &nicInfoInspectImpl{})
}
}
childName := "not a real child"
if child := v.GetChild(childName); child != nil {
t.Errorf("got GetChild(%s) = %s, want = %v", childName, child, nil)
}
if diff := cmp.Diff(inspect.Object{
Name: "NICs",
}, v.ReadData(), cmpopts.IgnoreUnexported(inspect.Object{})); diff != "" {
t.Errorf("ReadData() mismatch (-want +got):\n%s", diff)
}
}
func TestNicInfoInspectImpl(t *testing.T) {
v := nicInfoInspectImpl{
name: "doesn't matter",
}
children := v.ListChildren()
if diff := cmp.Diff([]string{
"Stats",
}, children); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
for _, childName := range children {
if child := v.GetChild(childName); child == nil {
t.Errorf("got GetChild(%s) = %v, want non-nil", childName, child)
} else if _, ok := child.(*statCounterInspectImpl); !ok {
t.Errorf("got GetChild(%s) = %T, want %T", childName, child, &statCounterInspectImpl{})
}
}
childName := "not a real child"
if child := v.GetChild(childName); child != nil {
t.Errorf("got GetChild(%s) = %s, want = %v", childName, child, nil)
}
v.value.Flags.Up = true
v.value.Flags.Loopback = true
v.value.dnsServers = []tcpip.Address{"\x01\x02\x03\x04"}
if diff := cmp.Diff(inspect.Object{
Name: v.name,
Properties: []inspect.Property{
{Key: "Name", Value: inspect.PropertyValueWithStr(v.value.Name)},
{Key: "Up", Value: inspect.PropertyValueWithStr(strconv.FormatBool(v.value.Flags.Up))},
{Key: "Running", Value: inspect.PropertyValueWithStr(strconv.FormatBool(v.value.Flags.Running))},
{Key: "Loopback", Value: inspect.PropertyValueWithStr(strconv.FormatBool(v.value.Flags.Loopback))},
{Key: "Promiscuous", Value: inspect.PropertyValueWithStr(strconv.FormatBool(v.value.Flags.Promiscuous))},
{Key: "DNS server0", Value: inspect.PropertyValueWithStr(v.value.dnsServers[0].String())},
{Key: "DHCP enabled", Value: inspect.PropertyValueWithStr(strconv.FormatBool(v.value.dhcpEnabled))},
},
Metrics: []inspect.Metric{
{Key: "MTU", Value: inspect.MetricValueWithUintValue(uint64(v.value.MTU))},
},
}, v.ReadData(), cmpopts.IgnoreUnexported(inspect.Object{}, inspect.Property{}, inspect.Metric{})); diff != "" {
t.Errorf("ReadData() mismatch (-want +got):\n%s", diff)
}
}
func TestDHCPInfoInspectImpl(t *testing.T) {
v := dhcpInfoInspectImpl{
name: "doesn't matter",
}
children := v.ListChildren()
if diff := cmp.Diff([]string{
"Stats",
}, children); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
for _, childName := range children {
if child := v.GetChild(childName); child == nil {
t.Errorf("got GetChild(%s) = %v, want non-nil", childName, child)
} else if _, ok := child.(*statCounterInspectImpl); !ok {
t.Errorf("got GetChild(%s) = %T, want %T", childName, child, &statCounterInspectImpl{})
}
}
childName := "not a real child"
if child := v.GetChild(childName); child != nil {
t.Errorf("got GetChild(%s) = %s, want = %v", childName, child, nil)
}
if diff := cmp.Diff(inspect.Object{
Name: v.name,
Properties: []inspect.Property{
{Key: "State", Value: inspect.PropertyValueWithStr(v.info.State.String())},
{Key: "AcquiredAddress", Value: inspect.PropertyValueWithStr("[none]")},
{Key: "ServerAddress", Value: inspect.PropertyValueWithStr("[none]")},
{Key: "OldAddress", Value: inspect.PropertyValueWithStr("[none]")},
{Key: "Acquisition", Value: inspect.PropertyValueWithStr(v.info.Acquisition.String())},
{Key: "Backoff", Value: inspect.PropertyValueWithStr(v.info.Backoff.String())},
{Key: "Retransmission", Value: inspect.PropertyValueWithStr(v.info.Retransmission.String())},
},
}, v.ReadData(), cmpopts.IgnoreUnexported(inspect.Object{}, inspect.Property{}, inspect.Metric{})); diff != "" {
t.Errorf("ReadData() mismatch (-want +got):\n%s", diff)
}
}
func TestEthInfoInspectImpl(t *testing.T) {
const topopath, filepath = "topopath", "filepath"
const features = ethernet.InfoFeatureWlan | ethernet.InfoFeatureSynth | ethernet.InfoFeatureLoopback
device := ethernetext.Device{
TB: t,
GetInfoImpl: func() (ethernet.Info, error) {
return ethernet.Info{
Features: features,
}, nil
},
GetFifosImpl: func() (int32, *ethernet.Fifos, error) {
return int32(zx.ErrOk), &ethernet.Fifos{
RxDepth: 1,
TxDepth: 1,
}, nil
},
SetIoBufferImpl: func(zx.VMO) (int32, error) {
return int32(zx.ErrOk), nil
},
StopImpl: func() error {
return nil
},
SetClientNameImpl: func(string) (int32, error) {
return int32(zx.ErrOk), nil
},
ConfigMulticastSetPromiscuousModeImpl: func(bool) (int32, error) {
return int32(zx.ErrOk), nil
},
}
client, err := eth.NewClient("client", topopath, filepath, &device)
if err != nil {
t.Fatal(err)
}
defer func() {
_ = client.Close()
client.Wait()
}()
v := ethInfoInspectImpl{
name: "doesn't matter",
value: client,
}
children := v.ListChildren()
if diff := cmp.Diff([]string{
"RxReads",
"RxWrites",
"TxReads",
"TxWrites",
}, children); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
for _, childName := range children {
if child := v.GetChild(childName); child == nil {
t.Errorf("got GetChild(%s) = %v, want non-nil", childName, child)
} else if _, ok := child.(*fifoStatsInspectImpl); !ok {
t.Errorf("got GetChild(%s) = %T, want %T", childName, child, &fifoStatsInspectImpl{})
}
}
childName := "not a real child"
if child := v.GetChild(childName); child != nil {
t.Errorf("got GetChild(%s) = %s, want = %v", childName, child, nil)
}
if diff := cmp.Diff(inspect.Object{
Name: v.name,
Properties: []inspect.Property{
{Key: "Topopath", Value: inspect.PropertyValueWithStr(topopath)},
{Key: "Filepath", Value: inspect.PropertyValueWithStr(filepath)},
{Key: "Features", Value: inspect.PropertyValueWithStr(featuresString(features))},
},
}, v.ReadData(), cmpopts.IgnoreUnexported(inspect.Object{}, inspect.Property{}, inspect.Metric{})); diff != "" {
t.Errorf("ReadData() mismatch (-want +got):\n%s", diff)
}
}
func TestFifoStatsInfoInspectImpl(t *testing.T) {
var zeroCounter, nonZeroCounter tcpip.StatCounter
nonZeroCounter.IncrementBy(5)
v := fifoStatsInspectImpl{
name: "doesn't matter",
value: func(depth uint32) *tcpip.StatCounter {
if depth%2 == 0 {
return &zeroCounter
}
return &nonZeroCounter
},
size: 2,
}
children := v.ListChildren()
if diff := cmp.Diff(children, []string(nil)); diff != "" {
t.Errorf("ListChildren() mismatch (-want +got):\n%s", diff)
}
childName := "not a real child"
if child := v.GetChild(childName); child != nil {
t.Errorf("got GetChild(%s) = %s, want = %v", childName, child, nil)
}
if diff := cmp.Diff(inspect.Object{
Name: v.name,
Metrics: []inspect.Metric{
{Key: "1", Value: inspect.MetricValueWithUintValue(5)},
},
}, v.ReadData(), cmpopts.IgnoreUnexported(inspect.Object{}, inspect.Property{}, inspect.Metric{})); diff != "" {
t.Errorf("ReadData() mismatch (-want +got):\n%s", diff)
}
}