From b2f7430b6751e4a8177ee0088ea8e09675703828 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Mon, 1 Nov 2021 18:17:39 +0100 Subject: Add more netavark tests Signed-off-by: Paul Holzinger --- libpod/network/netavark/netavark_suite_test.go | 37 +++ libpod/network/netavark/run_test.go | 309 ++++++++++++++++++++++++- 2 files changed, 343 insertions(+), 3 deletions(-) (limited to 'libpod/network/netavark') diff --git a/libpod/network/netavark/netavark_suite_test.go b/libpod/network/netavark/netavark_suite_test.go index 4d0c04634..6063a54e3 100644 --- a/libpod/network/netavark/netavark_suite_test.go +++ b/libpod/network/netavark/netavark_suite_test.go @@ -3,14 +3,19 @@ package netavark_test import ( + "fmt" + "net" "os" "path/filepath" + "reflect" "testing" "github.com/containers/podman/v3/libpod/network/netavark" "github.com/containers/podman/v3/libpod/network/types" + "github.com/containers/podman/v3/libpod/network/util" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + gomegaTypes "github.com/onsi/gomega/types" ) func TestNetavark(t *testing.T) { @@ -36,3 +41,35 @@ func getNetworkInterface(confDir string, machine bool) (types.ContainerNetwork, LockFile: filepath.Join(confDir, "netavark.lock"), }) } + +// EqualSubnet is a custom GomegaMatcher to match a subnet +// This makes sure to not use the 16 bytes ip representation. +func EqualSubnet(subnet *net.IPNet) gomegaTypes.GomegaMatcher { + return &equalSubnetMatcher{ + expected: subnet, + } +} + +type equalSubnetMatcher struct { + expected *net.IPNet +} + +func (m *equalSubnetMatcher) Match(actual interface{}) (bool, error) { + util.NormalizeIP(&m.expected.IP) + + subnet, ok := actual.(*net.IPNet) + if !ok { + return false, fmt.Errorf("EqualSubnet expects a *net.IPNet") + } + util.NormalizeIP(&subnet.IP) + + return reflect.DeepEqual(subnet, m.expected), nil +} + +func (m *equalSubnetMatcher) FailureMessage(actual interface{}) string { + return fmt.Sprintf("Expected subnet %#v to equal subnet %#v", actual, m.expected) +} + +func (m *equalSubnetMatcher) NegatedFailureMessage(actual interface{}) string { + return fmt.Sprintf("Expected subnet %#v not to equal subnet %#v", actual, m.expected) +} diff --git a/libpod/network/netavark/run_test.go b/libpod/network/netavark/run_test.go index 84db89b49..e44828496 100644 --- a/libpod/network/netavark/run_test.go +++ b/libpod/network/netavark/run_test.go @@ -28,6 +28,7 @@ import ( "github.com/vishvananda/netlink" "github.com/containers/podman/v3/libpod/network/types" + "github.com/containers/podman/v3/libpod/network/util" "github.com/containers/podman/v3/pkg/netns" "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/storage/pkg/stringid" @@ -57,6 +58,10 @@ var _ = Describe("run netavark", func() { } BeforeEach(func() { + if _, ok := os.LookupEnv("NETAVARK_BINARY"); !ok { + Skip("NETAVARK_BINARY not set skip run tests") + } + // set the logrus settings logrus.SetLevel(logrus.TraceLevel) // disable extra quotes so we can easily copy the netavark command @@ -130,6 +135,7 @@ var _ = Describe("run netavark", func() { ip := res[defNet].Interfaces[intName].Networks[0].Subnet.IP Expect(ip.String()).To(ContainSubstring("10.88.0.")) gw := res[defNet].Interfaces[intName].Networks[0].Gateway + util.NormalizeIP(&gw) Expect(gw.String()).To(Equal("10.88.0.1")) macAddress := res[defNet].Interfaces[intName].MacAddress Expect(macAddress).To(HaveLen(6)) @@ -143,14 +149,14 @@ var _ = Describe("run netavark", func() { i, err := net.InterfaceByName(intName) Expect(err).To(BeNil()) Expect(i.Name).To(Equal(intName)) - Expect(i.HardwareAddr).To(Equal(macAddress)) + Expect(i.HardwareAddr).To(Equal(net.HardwareAddr(macAddress))) addrs, err := i.Addrs() Expect(err).To(BeNil()) subnet := &net.IPNet{ IP: ip, Mask: net.CIDRMask(16, 32), } - Expect(addrs).To(ContainElements(subnet)) + Expect(addrs).To(ContainElements(EqualSubnet(subnet))) // check loopback adapter i, err = net.InterfaceByName("lo") @@ -175,12 +181,13 @@ var _ = Describe("run netavark", func() { IP: gw, Mask: net.CIDRMask(16, 32), } - Expect(addrs).To(ContainElements(subnet)) + Expect(addrs).To(ContainElements(EqualSubnet(subnet))) wg := &sync.WaitGroup{} expected := stringid.GenerateNonCryptoID() // now check ip connectivity err = netNSContainer.Do(func(_ ns.NetNS) error { + wg.Add(1) runNetListener(wg, "tcp", "0.0.0.0", 5000, expected) return nil }) @@ -194,6 +201,256 @@ var _ = Describe("run netavark", func() { err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(opts)) Expect(err).ToNot(HaveOccurred()) + wg.Wait() + }) + }) + + It("setup two containers", func() { + runTest(func() { + defNet := types.DefaultNetworkName + intName := "eth0" + setupOpts1 := types.SetupOptions{ + NetworkOptions: types.NetworkOptions{ + ContainerID: stringid.GenerateNonCryptoID(), + Networks: map[string]types.PerNetworkOptions{ + defNet: {InterfaceName: intName}, + }, + }, + } + res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts1) + Expect(err).ToNot(HaveOccurred()) + Expect(res).To(HaveLen(1)) + Expect(res).To(HaveKey(defNet)) + Expect(res[defNet].Interfaces).To(HaveKey(intName)) + Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1)) + ip1 := res[defNet].Interfaces[intName].Networks[0].Subnet.IP + Expect(ip1.String()).To(ContainSubstring("10.88.0.")) + Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6)) + + setupOpts2 := types.SetupOptions{ + NetworkOptions: types.NetworkOptions{ + ContainerID: stringid.GenerateNonCryptoID(), + Networks: map[string]types.PerNetworkOptions{ + defNet: {InterfaceName: intName}, + }, + }, + } + + netNSContainer2, err := netns.NewNS() + Expect(err).ToNot(HaveOccurred()) + defer netns.UnmountNS(netNSContainer2) + defer netNSContainer2.Close() + + res, err = libpodNet.Setup(netNSContainer2.Path(), setupOpts2) + Expect(err).ToNot(HaveOccurred()) + Expect(res).To(HaveLen(1)) + Expect(res).To(HaveKey(defNet)) + Expect(res[defNet].Interfaces).To(HaveKey(intName)) + Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1)) + ip2 := res[defNet].Interfaces[intName].Networks[0].Subnet.IP + Expect(ip2.String()).To(ContainSubstring("10.88.0.")) + Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6)) + Expect(ip1.Equal(ip2)).To(BeFalse(), "IP1 %s should not be equal to IP2 %s", ip1.String(), ip2.String()) + + err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts1)) + Expect(err).ToNot(HaveOccurred()) + err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts2)) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + It("setup dualstack network", func() { + runTest(func() { + s1, _ := types.ParseCIDR("10.0.0.1/24") + s2, _ := types.ParseCIDR("fd10:88:a::/64") + network, err := libpodNet.NetworkCreate(types.Network{ + Subnets: []types.Subnet{ + {Subnet: s1}, {Subnet: s2}, + }, + }) + Expect(err).ToNot(HaveOccurred()) + + netName := network.Name + intName := "eth0" + + setupOpts := types.SetupOptions{ + NetworkOptions: types.NetworkOptions{ + ContainerID: stringid.GenerateNonCryptoID(), + Networks: map[string]types.PerNetworkOptions{ + netName: {InterfaceName: intName}, + }, + }, + } + res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts) + Expect(err).ToNot(HaveOccurred()) + Expect(res).To(HaveLen(1)) + Expect(res).To(HaveKey(netName)) + Expect(res[netName].Interfaces).To(HaveKey(intName)) + Expect(res[netName].Interfaces[intName].Networks).To(HaveLen(2)) + ip1 := res[netName].Interfaces[intName].Networks[0].Subnet.IP + Expect(ip1.String()).To(ContainSubstring("10.0.0.")) + gw1 := res[netName].Interfaces[intName].Networks[0].Gateway + Expect(gw1.String()).To(Equal("10.0.0.1")) + ip2 := res[netName].Interfaces[intName].Networks[1].Subnet.IP + Expect(ip2.String()).To(ContainSubstring("fd10:88:a::")) + gw2 := res[netName].Interfaces[intName].Networks[0].Gateway + Expect(gw2.String()).To(Equal("fd10:88:a::1")) + Expect(res[netName].Interfaces[intName].MacAddress).To(HaveLen(6)) + + // check in the container namespace if the settings are applied + err = netNSContainer.Do(func(_ ns.NetNS) error { + defer GinkgoRecover() + i, err := net.InterfaceByName(intName) + Expect(err).ToNot(HaveOccurred()) + Expect(i.Name).To(Equal(intName)) + addrs, err := i.Addrs() + Expect(err).ToNot(HaveOccurred()) + subnet1 := s1.IPNet + subnet1.IP = ip1 + subnet2 := s2.IPNet + subnet2.IP = ip2 + Expect(addrs).To(ContainElements(EqualSubnet(&subnet1), EqualSubnet(&subnet2))) + + // check loopback adapter + i, err = net.InterfaceByName("lo") + Expect(err).ToNot(HaveOccurred()) + Expect(i.Name).To(Equal("lo")) + Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback)) + Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up") + return nil + }) + Expect(err).ToNot(HaveOccurred()) + + bridgeName := network.NetworkInterface + // check settings on the host side + i, err := net.InterfaceByName(bridgeName) + Expect(err).ToNot(HaveOccurred()) + Expect(i.Name).To(Equal(bridgeName)) + addrs, err := i.Addrs() + Expect(err).ToNot(HaveOccurred()) + // test that the gateway ip is assigned to the interface + subnet1 := s1.IPNet + subnet1.IP = gw1 + subnet2 := s2.IPNet + subnet2.IP = gw2 + Expect(addrs).To(ContainElements(EqualSubnet(&subnet1), EqualSubnet(&subnet2))) + + err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts)) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + It("setup two networks", func() { + runTest(func() { + s1, _ := types.ParseCIDR("10.0.0.1/24") + network1, err := libpodNet.NetworkCreate(types.Network{ + Subnets: []types.Subnet{ + {Subnet: s1}, + }, + }) + Expect(err).ToNot(HaveOccurred()) + + netName1 := network1.Name + intName1 := "eth0" + + s2, _ := types.ParseCIDR("10.1.0.0/24") + network2, err := libpodNet.NetworkCreate(types.Network{ + Subnets: []types.Subnet{ + {Subnet: s2}, + }, + }) + Expect(err).ToNot(HaveOccurred()) + + netName2 := network2.Name + intName2 := "eth1" + + setupOpts := types.SetupOptions{ + NetworkOptions: types.NetworkOptions{ + ContainerID: stringid.GenerateNonCryptoID(), + Networks: map[string]types.PerNetworkOptions{ + netName1: {InterfaceName: intName1}, + netName2: {InterfaceName: intName2}, + }, + }, + } + res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts) + Expect(err).ToNot(HaveOccurred()) + Expect(res).To(HaveLen(2)) + Expect(res).To(HaveKey(netName1)) + Expect(res).To(HaveKey(netName2)) + Expect(res[netName1].Interfaces).To(HaveKey(intName1)) + Expect(res[netName2].Interfaces).To(HaveKey(intName2)) + Expect(res[netName1].Interfaces[intName1].Networks).To(HaveLen(1)) + ip1 := res[netName1].Interfaces[intName1].Networks[0].Subnet.IP + Expect(ip1.String()).To(ContainSubstring("10.0.0.")) + gw1 := res[netName1].Interfaces[intName1].Networks[0].Gateway + Expect(gw1.String()).To(Equal("10.0.0.1")) + ip2 := res[netName2].Interfaces[intName2].Networks[0].Subnet.IP + Expect(ip2.String()).To(ContainSubstring("10.1.0.")) + gw2 := res[netName2].Interfaces[intName2].Networks[0].Gateway + Expect(gw2.String()).To(Equal("10.1.0.1")) + mac1 := res[netName1].Interfaces[intName1].MacAddress + Expect(mac1).To(HaveLen(6)) + mac2 := res[netName2].Interfaces[intName2].MacAddress + Expect(mac2).To(HaveLen(6)) + + // check in the container namespace if the settings are applied + err = netNSContainer.Do(func(_ ns.NetNS) error { + defer GinkgoRecover() + i, err := net.InterfaceByName(intName1) + Expect(err).ToNot(HaveOccurred()) + Expect(i.Name).To(Equal(intName1)) + addrs, err := i.Addrs() + Expect(err).ToNot(HaveOccurred()) + subnet1 := s1.IPNet + subnet1.IP = ip1 + Expect(addrs).To(ContainElements(EqualSubnet(&subnet1))) + + i, err = net.InterfaceByName(intName2) + Expect(err).ToNot(HaveOccurred()) + Expect(i.Name).To(Equal(intName2)) + addrs, err = i.Addrs() + Expect(err).ToNot(HaveOccurred()) + subnet2 := s2.IPNet + subnet2.IP = ip2 + Expect(addrs).To(ContainElements(EqualSubnet(&subnet2))) + + // check loopback adapter + i, err = net.InterfaceByName("lo") + Expect(err).ToNot(HaveOccurred()) + Expect(i.Name).To(Equal("lo")) + Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback)) + Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up") + return nil + }) + Expect(err).ToNot(HaveOccurred()) + + bridgeName1 := network1.NetworkInterface + // check settings on the host side + i, err := net.InterfaceByName(bridgeName1) + Expect(err).ToNot(HaveOccurred()) + Expect(i.Name).To(Equal(bridgeName1)) + addrs, err := i.Addrs() + Expect(err).ToNot(HaveOccurred()) + // test that the gateway ip is assigned to the interface + subnet1 := s1.IPNet + subnet1.IP = gw1 + Expect(addrs).To(ContainElements(EqualSubnet(&subnet1))) + + bridgeName2 := network2.NetworkInterface + // check settings on the host side + i, err = net.InterfaceByName(bridgeName2) + Expect(err).ToNot(HaveOccurred()) + Expect(i.Name).To(Equal(bridgeName2)) + addrs, err = i.Addrs() + Expect(err).ToNot(HaveOccurred()) + // test that the gateway ip is assigned to the interface + subnet2 := s2.IPNet + subnet2.IP = gw2 + Expect(addrs).To(ContainElements(EqualSubnet(&subnet2))) + + err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts)) + Expect(err).ToNot(HaveOccurred()) }) }) @@ -316,6 +573,52 @@ var _ = Describe("run netavark", func() { }) } + It("simple teardown", func() { + runTest(func() { + defNet := types.DefaultNetworkName + intName := "eth0" + opts := types.SetupOptions{ + NetworkOptions: types.NetworkOptions{ + ContainerID: "someID", + ContainerName: "someName", + Networks: map[string]types.PerNetworkOptions{ + defNet: { + InterfaceName: intName, + }, + }, + }, + } + res, err := libpodNet.Setup(netNSContainer.Path(), opts) + Expect(err).ToNot(HaveOccurred()) + Expect(res).To(HaveLen(1)) + Expect(res).To(HaveKey(defNet)) + Expect(res[defNet].Interfaces).To(HaveKey(intName)) + Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1)) + ip := res[defNet].Interfaces[intName].Networks[0].Subnet.IP + Expect(ip.String()).To(ContainSubstring("10.88.0.")) + gw := res[defNet].Interfaces[intName].Networks[0].Gateway + Expect(gw.String()).To(Equal("10.88.0.1")) + macAddress := res[defNet].Interfaces[intName].MacAddress + Expect(macAddress).To(HaveLen(6)) + + err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(opts)) + Expect(err).ToNot(HaveOccurred()) + err = netNSContainer.Do(func(_ ns.NetNS) error { + defer GinkgoRecover() + // check that the container interface is removed + _, err := net.InterfaceByName(intName) + Expect(err).To(HaveOccurred()) + return nil + }) + Expect(err).ToNot(HaveOccurred()) + + // default bridge name + bridgeName := "podman0" + // check that bridge interface was removed + _, err = net.InterfaceByName(bridgeName) + Expect(err).To(HaveOccurred()) + }) + }) }) func runNetListener(wg *sync.WaitGroup, protocol, ip string, port int, expectedData string) { -- cgit v1.2.3-54-g00ecf