summaryrefslogtreecommitdiffhomepage
path: root/test/packetimpact/netdevs
diff options
context:
space:
mode:
Diffstat (limited to 'test/packetimpact/netdevs')
-rw-r--r--test/packetimpact/netdevs/BUILD10
-rw-r--r--test/packetimpact/netdevs/netdevs.go17
-rw-r--r--test/packetimpact/netdevs/netdevs_test.go227
3 files changed, 250 insertions, 4 deletions
diff --git a/test/packetimpact/netdevs/BUILD b/test/packetimpact/netdevs/BUILD
index 422bb9b0c..8d1193fed 100644
--- a/test/packetimpact/netdevs/BUILD
+++ b/test/packetimpact/netdevs/BUILD
@@ -1,4 +1,4 @@
-load("//tools:defs.bzl", "go_library")
+load("//tools:defs.bzl", "go_library", "go_test")
package(
licenses = ["notice"],
@@ -13,3 +13,11 @@ go_library(
"//pkg/tcpip/header",
],
)
+
+go_test(
+ name = "netdevs_test",
+ size = "small",
+ srcs = ["netdevs_test.go"],
+ library = ":netdevs",
+ deps = ["@com_github_google_go_cmp//cmp:go_default_library"],
+)
diff --git a/test/packetimpact/netdevs/netdevs.go b/test/packetimpact/netdevs/netdevs.go
index d2c9cfeaf..eecfe0730 100644
--- a/test/packetimpact/netdevs/netdevs.go
+++ b/test/packetimpact/netdevs/netdevs.go
@@ -19,6 +19,7 @@ import (
"fmt"
"net"
"regexp"
+ "strconv"
"strings"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -27,6 +28,7 @@ import (
// A DeviceInfo represents a network device.
type DeviceInfo struct {
+ ID uint32
MAC net.HardwareAddr
IPv4Addr net.IP
IPv4Net *net.IPNet
@@ -35,7 +37,7 @@ type DeviceInfo struct {
}
var (
- deviceLine = regexp.MustCompile(`^\s*\d+: (\w+)`)
+ deviceLine = regexp.MustCompile(`^\s*(\d+): (\w+)`)
linkLine = regexp.MustCompile(`^\s*link/\w+ ([0-9a-fA-F:]+)`)
inetLine = regexp.MustCompile(`^\s*inet ([0-9./]+)`)
inet6Line = regexp.MustCompile(`^\s*inet6 ([0-9a-fA-Z:/]+)`)
@@ -43,6 +45,11 @@ var (
// ParseDevices parses the output from `ip addr show` into a map from device
// name to information about the device.
+//
+// Note: if multiple IPv6 addresses are assigned to a device, the last address
+// displayed by `ip addr show` will be used. This is fine for packetimpact
+// because we will always only have at most one IPv6 address assigned to each
+// device.
func ParseDevices(cmdOutput string) (map[string]DeviceInfo, error) {
var currentDevice string
var currentInfo DeviceInfo
@@ -52,8 +59,12 @@ func ParseDevices(cmdOutput string) (map[string]DeviceInfo, error) {
if currentDevice != "" {
deviceInfos[currentDevice] = currentInfo
}
- currentInfo = DeviceInfo{}
- currentDevice = m[1]
+ id, err := strconv.ParseUint(m[1], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("parsing device ID %s: %w", m[1], err)
+ }
+ currentInfo = DeviceInfo{ID: uint32(id)}
+ currentDevice = m[2]
} else if m := linkLine.FindStringSubmatch(line); m != nil {
mac, err := net.ParseMAC(m[1])
if err != nil {
diff --git a/test/packetimpact/netdevs/netdevs_test.go b/test/packetimpact/netdevs/netdevs_test.go
new file mode 100644
index 000000000..24ad12198
--- /dev/null
+++ b/test/packetimpact/netdevs/netdevs_test.go
@@ -0,0 +1,227 @@
+// Copyright 2020 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package netdevs
+
+import (
+ "fmt"
+ "net"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+)
+
+func mustParseMAC(s string) net.HardwareAddr {
+ mac, err := net.ParseMAC(s)
+ if err != nil {
+ panic(fmt.Sprintf("failed to parse test MAC %q: %s", s, err))
+ }
+ return mac
+}
+
+func TestParseDevices(t *testing.T) {
+ for _, v := range []struct {
+ desc string
+ cmdOutput string
+ want map[string]DeviceInfo
+ }{
+ {
+ desc: "v4 and v6",
+ cmdOutput: `
+1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+ link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+ inet 127.0.0.1/8 scope host lo
+ valid_lft forever preferred_lft forever
+ inet6 ::1/128 scope host
+ valid_lft forever preferred_lft forever
+2613: eth0@if2614: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:c0:a8:09:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet 192.168.9.2/24 brd 192.168.9.255 scope global eth0
+ valid_lft forever preferred_lft forever
+ inet6 fe80::42:c0ff:fea8:902/64 scope link tentative
+ valid_lft forever preferred_lft forever
+2615: eth2@if2616: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:df:f5:e1:0a brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet 223.245.225.10/24 brd 223.245.225.255 scope global eth2
+ valid_lft forever preferred_lft forever
+ inet6 fe80::42:dfff:fef5:e10a/64 scope link tentative
+ valid_lft forever preferred_lft forever
+2617: eth1@if2618: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:da:33:13:0a brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet 218.51.19.10/24 brd 218.51.19.255 scope global eth1
+ valid_lft forever preferred_lft forever
+ inet6 fe80::42:daff:fe33:130a/64 scope link tentative
+ valid_lft forever preferred_lft forever`,
+ want: map[string]DeviceInfo{
+ "lo": DeviceInfo{
+ ID: 1,
+ MAC: mustParseMAC("00:00:00:00:00:00"),
+ IPv4Addr: net.IPv4(127, 0, 0, 1),
+ IPv4Net: &net.IPNet{
+ IP: net.IPv4(127, 0, 0, 0),
+ Mask: net.CIDRMask(8, 32),
+ },
+ IPv6Addr: net.ParseIP("::1"),
+ IPv6Net: &net.IPNet{
+ IP: net.ParseIP("::1"),
+ Mask: net.CIDRMask(128, 128),
+ },
+ },
+ "eth0": DeviceInfo{
+ ID: 2613,
+ MAC: mustParseMAC("02:42:c0:a8:09:02"),
+ IPv4Addr: net.IPv4(192, 168, 9, 2),
+ IPv4Net: &net.IPNet{
+ IP: net.IPv4(192, 168, 9, 0),
+ Mask: net.CIDRMask(24, 32),
+ },
+ IPv6Addr: net.ParseIP("fe80::42:c0ff:fea8:902"),
+ IPv6Net: &net.IPNet{
+ IP: net.ParseIP("fe80::"),
+ Mask: net.CIDRMask(64, 128),
+ },
+ },
+ "eth1": DeviceInfo{
+ ID: 2617,
+ MAC: mustParseMAC("02:42:da:33:13:0a"),
+ IPv4Addr: net.IPv4(218, 51, 19, 10),
+ IPv4Net: &net.IPNet{
+ IP: net.IPv4(218, 51, 19, 0),
+ Mask: net.CIDRMask(24, 32),
+ },
+ IPv6Addr: net.ParseIP("fe80::42:daff:fe33:130a"),
+ IPv6Net: &net.IPNet{
+ IP: net.ParseIP("fe80::"),
+ Mask: net.CIDRMask(64, 128),
+ },
+ },
+ "eth2": DeviceInfo{
+ ID: 2615,
+ MAC: mustParseMAC("02:42:df:f5:e1:0a"),
+ IPv4Addr: net.IPv4(223, 245, 225, 10),
+ IPv4Net: &net.IPNet{
+ IP: net.IPv4(223, 245, 225, 0),
+ Mask: net.CIDRMask(24, 32),
+ },
+ IPv6Addr: net.ParseIP("fe80::42:dfff:fef5:e10a"),
+ IPv6Net: &net.IPNet{
+ IP: net.ParseIP("fe80::"),
+ Mask: net.CIDRMask(64, 128),
+ },
+ },
+ },
+ },
+ {
+ desc: "v4 only",
+ cmdOutput: `
+2613: eth0@if2614: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:c0:a8:09:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet 192.168.9.2/24 brd 192.168.9.255 scope global eth0
+ valid_lft forever preferred_lft forever`,
+ want: map[string]DeviceInfo{
+ "eth0": DeviceInfo{
+ ID: 2613,
+ MAC: mustParseMAC("02:42:c0:a8:09:02"),
+ IPv4Addr: net.IPv4(192, 168, 9, 2),
+ IPv4Net: &net.IPNet{
+ IP: net.IPv4(192, 168, 9, 0),
+ Mask: net.CIDRMask(24, 32),
+ },
+ },
+ },
+ },
+ {
+ desc: "v6 only",
+ cmdOutput: `
+2615: eth2@if2616: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:df:f5:e1:0a brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet6 fe80::42:dfff:fef5:e10a/64 scope link tentative
+ valid_lft forever preferred_lft forever`,
+ want: map[string]DeviceInfo{
+ "eth2": DeviceInfo{
+ ID: 2615,
+ MAC: mustParseMAC("02:42:df:f5:e1:0a"),
+ IPv6Addr: net.ParseIP("fe80::42:dfff:fef5:e10a"),
+ IPv6Net: &net.IPNet{
+ IP: net.ParseIP("fe80::"),
+ Mask: net.CIDRMask(64, 128),
+ },
+ },
+ },
+ },
+ } {
+ t.Run(v.desc, func(t *testing.T) {
+ got, err := ParseDevices(v.cmdOutput)
+ if err != nil {
+ t.Errorf("ParseDevices(\n%s\n) got unexpected error: %s", v.cmdOutput, err)
+ }
+ if diff := cmp.Diff(v.want, got); diff != "" {
+ t.Errorf("ParseDevices(\n%s\n) got output diff (-want, +got):\n%s", v.cmdOutput, diff)
+ }
+ })
+ }
+}
+
+func TestParseDevicesErrors(t *testing.T) {
+ for _, v := range []struct {
+ desc string
+ cmdOutput string
+ }{
+ {
+ desc: "invalid MAC addr",
+ cmdOutput: `
+2617: eth1@if2618: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:da:33:13:0a:ffffffff brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet 218.51.19.10/24 brd 218.51.19.255 scope global eth1
+ valid_lft forever preferred_lft forever
+ inet6 fe80::42:daff:fe33:130a/64 scope link tentative
+ valid_lft forever preferred_lft forever`,
+ },
+ {
+ desc: "invalid v4 addr",
+ cmdOutput: `
+2617: eth1@if2618: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:da:33:13:0a brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet 1234.4321.424242.0/24 brd 218.51.19.255 scope global eth1
+ valid_lft forever preferred_lft forever
+ inet6 fe80::42:daff:fe33:130a/64 scope link tentative
+ valid_lft forever preferred_lft forever`,
+ },
+ {
+ desc: "invalid v6 addr",
+ cmdOutput: `
+2617: eth1@if2618: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:da:33:13:0a brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet 218.51.19.10/24 brd 218.51.19.255 scope global eth1
+ valid_lft forever preferred_lft forever
+ inet6 fe80:ffffffff::42:daff:fe33:130a/64 scope link tentative
+ valid_lft forever preferred_lft forever`,
+ },
+ {
+ desc: "invalid CIDR missing prefixlen",
+ cmdOutput: `
+2617: eth1@if2618: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+ link/ether 02:42:da:33:13:0a brd ff:ff:ff:ff:ff:ff link-netnsid 0
+ inet 218.51.19.10 brd 218.51.19.255 scope global eth1
+ valid_lft forever preferred_lft forever
+ inet6 fe80::42:daff:fe33:130a scope link tentative
+ valid_lft forever preferred_lft forever`,
+ },
+ } {
+ t.Run(v.desc, func(t *testing.T) {
+ if _, err := ParseDevices(v.cmdOutput); err == nil {
+ t.Errorf("ParseDevices(\n%s\n) succeeded unexpectedly, want error", v.cmdOutput)
+ }
+ })
+ }
+}