Add more netavark tests

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger
2021-11-01 18:17:39 +01:00
parent 1c88f741a7
commit b2f7430b67
2 changed files with 343 additions and 3 deletions

View File

@ -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)
}

View File

@ -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) {