From 49d2cde1e2bb7d2dc245a30cfe7564183b8f909a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz <s.ortiz@apple.com> Date: Tue, 9 Nov 2021 01:28:23 +0000 Subject: [PATCH] virtcontainers: Split network tests into generic and OS specific parts Some unit tests are generic while others, mostly because they depend on netlink, are Linux specific. Signed-off-by: Samuel Ortiz <s.ortiz@apple.com> --- .../virtcontainers/network_linux_test.go | 329 ++++++++++++++++++ src/runtime/virtcontainers/network_test.go | 316 ----------------- 2 files changed, 329 insertions(+), 316 deletions(-) create mode 100644 src/runtime/virtcontainers/network_linux_test.go diff --git a/src/runtime/virtcontainers/network_linux_test.go b/src/runtime/virtcontainers/network_linux_test.go new file mode 100644 index 0000000000..8aa2e44b23 --- /dev/null +++ b/src/runtime/virtcontainers/network_linux_test.go @@ -0,0 +1,329 @@ +// Copyright (c) 2016 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +package virtcontainers + +import ( + "context" + "fmt" + "net" + "reflect" + "testing" + + "github.com/containernetworking/plugins/pkg/ns" + ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" + pbTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols" + "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils" + "github.com/stretchr/testify/assert" + "github.com/vishvananda/netlink" +) + +func TestGenerateInterfacesAndRoutes(t *testing.T) { + // + //Create a couple of addresses + // + address1 := &net.IPNet{IP: net.IPv4(172, 17, 0, 2), Mask: net.CIDRMask(16, 32)} + address2 := &net.IPNet{IP: net.IPv4(182, 17, 0, 2), Mask: net.CIDRMask(16, 32)} + address3 := &net.IPNet{IP: net.ParseIP("2001:db8:1::242:ac11:2"), Mask: net.CIDRMask(64, 128)} + + addrs := []netlink.Addr{ + {IPNet: address1, Label: "phyaddr1"}, + {IPNet: address2, Label: "phyaddr2"}, + {IPNet: address3, Label: "phyaddr3"}, + } + + // Create a couple of routes: + dst2 := &net.IPNet{IP: net.IPv4(172, 17, 0, 0), Mask: net.CIDRMask(16, 32)} + src2 := net.IPv4(172, 17, 0, 2) + gw2 := net.IPv4(172, 17, 0, 1) + + dstV6 := &net.IPNet{IP: net.ParseIP("2001:db8:1::"), Mask: net.CIDRMask(64, 128)} + gatewayV6 := net.ParseIP("2001:db8:1::1") + + routes := []netlink.Route{ + {LinkIndex: 329, Dst: nil, Src: nil, Gw: net.IPv4(172, 17, 0, 1), Scope: netlink.Scope(254)}, + {LinkIndex: 329, Dst: dst2, Src: src2, Gw: gw2}, + {LinkIndex: 329, Dst: dstV6, Src: nil, Gw: nil}, + {LinkIndex: 329, Dst: nil, Src: nil, Gw: gatewayV6}, + } + + arpMAC, _ := net.ParseMAC("6a:92:3a:59:70:aa") + + neighs := []netlink.Neigh{ + {LinkIndex: 329, IP: net.IPv4(192, 168, 0, 101), State: netlink.NUD_PERMANENT, HardwareAddr: arpMAC}, + } + + networkInfo := NetworkInfo{ + Iface: NetlinkIface{ + LinkAttrs: netlink.LinkAttrs{MTU: 1500}, + Type: "", + }, + Addrs: addrs, + Routes: routes, + Neighbors: neighs, + } + + ep0 := &PhysicalEndpoint{ + IfaceName: "eth0", + HardAddr: net.HardwareAddr{0x02, 0x00, 0xca, 0xfe, 0x00, 0x04}.String(), + EndpointProperties: networkInfo, + } + + endpoints := []Endpoint{ep0} + + nns, err := NewNetwork(&NetworkConfig{NetworkID: "foobar", NetworkCreated: true}) + assert.Nil(t, err) + nns.SetEndpoints(endpoints) + + resInterfaces, resRoutes, resNeighs, err := generateVCNetworkStructures(context.Background(), nns) + + // + // Build expected results: + // + expectedAddresses := []*pbTypes.IPAddress{ + {Family: utils.ConvertAddressFamily(netlink.FAMILY_V4), Address: "172.17.0.2", Mask: "16"}, + {Family: utils.ConvertAddressFamily(netlink.FAMILY_V4), Address: "182.17.0.2", Mask: "16"}, + {Family: utils.ConvertAddressFamily(netlink.FAMILY_V6), Address: "2001:db8:1::242:ac11:2", Mask: "64"}, + } + + expectedInterfaces := []*pbTypes.Interface{ + {Device: "eth0", Name: "eth0", IPAddresses: expectedAddresses, Mtu: 1500, HwAddr: "02:00:ca:fe:00:04"}, + } + + expectedRoutes := []*pbTypes.Route{ + {Dest: "", Gateway: "172.17.0.1", Device: "eth0", Source: "", Scope: uint32(254)}, + {Dest: "172.17.0.0/16", Gateway: "172.17.0.1", Device: "eth0", Source: "172.17.0.2"}, + {Dest: "2001:db8:1::/64", Gateway: "", Device: "eth0", Source: ""}, + {Dest: "", Gateway: "2001:db8:1::1", Device: "eth0", Source: ""}, + } + + expectedNeighs := []*pbTypes.ARPNeighbor{ + { + Device: "eth0", + State: netlink.NUD_PERMANENT, + Lladdr: "6a:92:3a:59:70:aa", + ToIPAddress: &pbTypes.IPAddress{Address: "192.168.0.101", Family: utils.ConvertAddressFamily(netlink.FAMILY_V4)}, + }, + } + + for _, r := range resRoutes { + fmt.Printf("resRoute: %+v\n", r) + } + + assert.Nil(t, err, "unexpected failure when calling generateKataInterfacesAndRoutes") + assert.True(t, reflect.DeepEqual(resInterfaces, expectedInterfaces), + "Interfaces returned didn't match: got %+v, expecting %+v", resInterfaces, expectedInterfaces) + assert.True(t, reflect.DeepEqual(resRoutes, expectedRoutes), + "Routes returned didn't match: got %+v, expecting %+v", resRoutes, expectedRoutes) + assert.True(t, reflect.DeepEqual(resNeighs, expectedNeighs), + "ARP Neighbors returned didn't match: got %+v, expecting %+v", resNeighs, expectedNeighs) +} + +func TestCreateGetTunTapLink(t *testing.T) { + if tc.NotValid(ktu.NeedRoot()) { + t.Skip(testDisabledAsNonRoot) + } + + assert := assert.New(t) + + netHandle, err := netlink.NewHandle() + assert.NoError(err) + defer netHandle.Close() + + assert.NoError(err) + + tapName := "testtap0" + tapLink, fds, err := createLink(netHandle, tapName, &netlink.Tuntap{}, 1) + assert.NoError(err) + assert.NotNil(tapLink) + assert.NotZero(len(fds)) + + tapLink, err = getLinkByName(netHandle, tapName, &netlink.Tuntap{}) + assert.NoError(err) + + err = netHandle.LinkDel(tapLink) + assert.NoError(err) +} + +func TestCreateMacVtap(t *testing.T) { + if tc.NotValid(ktu.NeedRoot()) { + t.Skip(testDisabledAsNonRoot) + } + + assert := assert.New(t) + + netHandle, err := netlink.NewHandle() + assert.NoError(err) + defer netHandle.Close() + + assert.NoError(err) + + tapName := "testtap0" + tapLink, _, err := createLink(netHandle, tapName, &netlink.Tuntap{}, 1) + assert.NoError(err) + + attrs := tapLink.Attrs() + + mcLink := &netlink.Macvtap{ + Macvlan: netlink.Macvlan{ + LinkAttrs: netlink.LinkAttrs{ + TxQLen: attrs.TxQLen, + ParentIndex: attrs.Index, + }, + }, + } + + macvtapName := "testmc0" + _, err = createMacVtap(netHandle, macvtapName, mcLink, 1) + assert.NoError(err) + + macvtapLink, err := getLinkByName(netHandle, macvtapName, &netlink.Macvtap{}) + assert.NoError(err) + + err = netHandle.LinkDel(macvtapLink) + assert.NoError(err) + + tapLink, err = getLinkByName(netHandle, tapName, &netlink.Tuntap{}) + assert.NoError(err) + + err = netHandle.LinkDel(tapLink) + assert.NoError(err) +} + +func TestTcRedirectNetwork(t *testing.T) { + if tc.NotValid(ktu.NeedRoot()) { + t.Skip(testDisabledAsNonRoot) + } + + assert := assert.New(t) + + netHandle, err := netlink.NewHandle() + assert.NoError(err) + defer netHandle.Close() + + // Create a test veth interface. + vethName := "foo" + veth := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: vethName, TxQLen: 200, MTU: 1400}, PeerName: "bar"} + + err = netlink.LinkAdd(veth) + assert.NoError(err) + + endpoint, err := createVethNetworkEndpoint(1, vethName, NetXConnectTCFilterModel) + assert.NoError(err) + + link, err := netlink.LinkByName(vethName) + assert.NoError(err) + + err = netHandle.LinkSetUp(link) + assert.NoError(err) + + err = setupTCFiltering(context.Background(), endpoint, 1, true) + assert.NoError(err) + + err = removeTCFiltering(context.Background(), endpoint) + assert.NoError(err) + + // Remove the veth created for testing. + err = netHandle.LinkDel(link) + assert.NoError(err) +} + +func TestRxRateLimiter(t *testing.T) { + if tc.NotValid(ktu.NeedRoot()) { + t.Skip(testDisabledAsNonRoot) + } + + assert := assert.New(t) + + netHandle, err := netlink.NewHandle() + assert.NoError(err) + defer netHandle.Close() + + // Create a test veth interface. + vethName := "foo" + veth := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: vethName, TxQLen: 200, MTU: 1400}, PeerName: "bar"} + + err = netlink.LinkAdd(veth) + assert.NoError(err) + + endpoint, err := createVethNetworkEndpoint(1, vethName, NetXConnectTCFilterModel) + assert.NoError(err) + + link, err := netlink.LinkByName(vethName) + assert.NoError(err) + + err = netHandle.LinkSetUp(link) + assert.NoError(err) + + err = setupTCFiltering(context.Background(), endpoint, 1, true) + assert.NoError(err) + + // 10Mb + maxRate := uint64(10000000) + err = addRxRateLimiter(endpoint, maxRate) + assert.NoError(err) + + currentNS, err := ns.GetCurrentNS() + assert.NoError(err) + + err = removeRxRateLimiter(endpoint, currentNS.Path()) + assert.NoError(err) + + err = removeTCFiltering(context.Background(), endpoint) + assert.NoError(err) + + // Remove the veth created for testing. + err = netHandle.LinkDel(link) + assert.NoError(err) +} + +func TestTxRateLimiter(t *testing.T) { + if tc.NotValid(ktu.NeedRoot()) { + t.Skip(testDisabledAsNonRoot) + } + + assert := assert.New(t) + + netHandle, err := netlink.NewHandle() + assert.NoError(err) + defer netHandle.Close() + + // Create a test veth interface. + vethName := "foo" + veth := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: vethName, TxQLen: 200, MTU: 1400}, PeerName: "bar"} + + err = netlink.LinkAdd(veth) + assert.NoError(err) + + endpoint, err := createVethNetworkEndpoint(1, vethName, NetXConnectTCFilterModel) + assert.NoError(err) + + link, err := netlink.LinkByName(vethName) + assert.NoError(err) + + err = netHandle.LinkSetUp(link) + assert.NoError(err) + + err = setupTCFiltering(context.Background(), endpoint, 1, true) + assert.NoError(err) + + // 10Mb + maxRate := uint64(10000000) + err = addTxRateLimiter(endpoint, maxRate) + assert.NoError(err) + + currentNS, err := ns.GetCurrentNS() + assert.NoError(err) + + err = removeTxRateLimiter(endpoint, currentNS.Path()) + assert.NoError(err) + + err = removeTCFiltering(context.Background(), endpoint) + assert.NoError(err) + + // Remove the veth created for testing. + err = netHandle.LinkDel(link) + assert.NoError(err) +} diff --git a/src/runtime/virtcontainers/network_test.go b/src/runtime/virtcontainers/network_test.go index bff91a0626..be980ec168 100644 --- a/src/runtime/virtcontainers/network_test.go +++ b/src/runtime/virtcontainers/network_test.go @@ -6,121 +6,12 @@ package virtcontainers import ( - "context" - "fmt" "net" - "reflect" "testing" - "github.com/containernetworking/plugins/pkg/ns" - ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" - pbTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols" - "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils" "github.com/stretchr/testify/assert" - "github.com/vishvananda/netlink" ) -func TestGenerateInterfacesAndRoutes(t *testing.T) { - // - //Create a couple of addresses - // - address1 := &net.IPNet{IP: net.IPv4(172, 17, 0, 2), Mask: net.CIDRMask(16, 32)} - address2 := &net.IPNet{IP: net.IPv4(182, 17, 0, 2), Mask: net.CIDRMask(16, 32)} - address3 := &net.IPNet{IP: net.ParseIP("2001:db8:1::242:ac11:2"), Mask: net.CIDRMask(64, 128)} - - addrs := []netlink.Addr{ - {IPNet: address1, Label: "phyaddr1"}, - {IPNet: address2, Label: "phyaddr2"}, - {IPNet: address3, Label: "phyaddr3"}, - } - - // Create a couple of routes: - dst2 := &net.IPNet{IP: net.IPv4(172, 17, 0, 0), Mask: net.CIDRMask(16, 32)} - src2 := net.IPv4(172, 17, 0, 2) - gw2 := net.IPv4(172, 17, 0, 1) - - dstV6 := &net.IPNet{IP: net.ParseIP("2001:db8:1::"), Mask: net.CIDRMask(64, 128)} - gatewayV6 := net.ParseIP("2001:db8:1::1") - - routes := []netlink.Route{ - {LinkIndex: 329, Dst: nil, Src: nil, Gw: net.IPv4(172, 17, 0, 1), Scope: netlink.Scope(254)}, - {LinkIndex: 329, Dst: dst2, Src: src2, Gw: gw2}, - {LinkIndex: 329, Dst: dstV6, Src: nil, Gw: nil}, - {LinkIndex: 329, Dst: nil, Src: nil, Gw: gatewayV6}, - } - - arpMAC, _ := net.ParseMAC("6a:92:3a:59:70:aa") - - neighs := []netlink.Neigh{ - {LinkIndex: 329, IP: net.IPv4(192, 168, 0, 101), State: netlink.NUD_PERMANENT, HardwareAddr: arpMAC}, - } - - networkInfo := NetworkInfo{ - Iface: NetlinkIface{ - LinkAttrs: netlink.LinkAttrs{MTU: 1500}, - Type: "", - }, - Addrs: addrs, - Routes: routes, - Neighbors: neighs, - } - - ep0 := &PhysicalEndpoint{ - IfaceName: "eth0", - HardAddr: net.HardwareAddr{0x02, 0x00, 0xca, 0xfe, 0x00, 0x04}.String(), - EndpointProperties: networkInfo, - } - - endpoints := []Endpoint{ep0} - - nns, err := NewNetwork(&NetworkConfig{NetworkID: "foobar", NetworkCreated: true}) - assert.Nil(t, err) - nns.SetEndpoints(endpoints) - - resInterfaces, resRoutes, resNeighs, err := generateVCNetworkStructures(context.Background(), nns) - - // - // Build expected results: - // - expectedAddresses := []*pbTypes.IPAddress{ - {Family: utils.ConvertAddressFamily(netlink.FAMILY_V4), Address: "172.17.0.2", Mask: "16"}, - {Family: utils.ConvertAddressFamily(netlink.FAMILY_V4), Address: "182.17.0.2", Mask: "16"}, - {Family: utils.ConvertAddressFamily(netlink.FAMILY_V6), Address: "2001:db8:1::242:ac11:2", Mask: "64"}, - } - - expectedInterfaces := []*pbTypes.Interface{ - {Device: "eth0", Name: "eth0", IPAddresses: expectedAddresses, Mtu: 1500, HwAddr: "02:00:ca:fe:00:04"}, - } - - expectedRoutes := []*pbTypes.Route{ - {Dest: "", Gateway: "172.17.0.1", Device: "eth0", Source: "", Scope: uint32(254)}, - {Dest: "172.17.0.0/16", Gateway: "172.17.0.1", Device: "eth0", Source: "172.17.0.2"}, - {Dest: "2001:db8:1::/64", Gateway: "", Device: "eth0", Source: ""}, - {Dest: "", Gateway: "2001:db8:1::1", Device: "eth0", Source: ""}, - } - - expectedNeighs := []*pbTypes.ARPNeighbor{ - { - Device: "eth0", - State: netlink.NUD_PERMANENT, - Lladdr: "6a:92:3a:59:70:aa", - ToIPAddress: &pbTypes.IPAddress{Address: "192.168.0.101", Family: utils.ConvertAddressFamily(netlink.FAMILY_V4)}, - }, - } - - for _, r := range resRoutes { - fmt.Printf("resRoute: %+v\n", r) - } - - assert.Nil(t, err, "unexpected failure when calling generateKataInterfacesAndRoutes") - assert.True(t, reflect.DeepEqual(resInterfaces, expectedInterfaces), - "Interfaces returned didn't match: got %+v, expecting %+v", resInterfaces, expectedInterfaces) - assert.True(t, reflect.DeepEqual(resRoutes, expectedRoutes), - "Routes returned didn't match: got %+v, expecting %+v", resRoutes, expectedRoutes) - assert.True(t, reflect.DeepEqual(resNeighs, expectedNeighs), - "ARP Neighbors returned didn't match: got %+v, expecting %+v", resNeighs, expectedNeighs) -} - func TestNetInterworkingModelIsValid(t *testing.T) { tests := []struct { name string @@ -181,210 +72,3 @@ func TestGenerateRandomPrivateMacAdd(t *testing.T) { assert.NotEqual(addr1, addr2) } - -func TestCreateGetTunTapLink(t *testing.T) { - if tc.NotValid(ktu.NeedRoot()) { - t.Skip(testDisabledAsNonRoot) - } - - assert := assert.New(t) - - netHandle, err := netlink.NewHandle() - assert.NoError(err) - defer netHandle.Close() - - assert.NoError(err) - - tapName := "testtap0" - tapLink, fds, err := createLink(netHandle, tapName, &netlink.Tuntap{}, 1) - assert.NoError(err) - assert.NotNil(tapLink) - assert.NotZero(len(fds)) - - tapLink, err = getLinkByName(netHandle, tapName, &netlink.Tuntap{}) - assert.NoError(err) - - err = netHandle.LinkDel(tapLink) - assert.NoError(err) -} - -func TestCreateMacVtap(t *testing.T) { - if tc.NotValid(ktu.NeedRoot()) { - t.Skip(testDisabledAsNonRoot) - } - - assert := assert.New(t) - - netHandle, err := netlink.NewHandle() - assert.NoError(err) - defer netHandle.Close() - - assert.NoError(err) - - tapName := "testtap0" - tapLink, _, err := createLink(netHandle, tapName, &netlink.Tuntap{}, 1) - assert.NoError(err) - - attrs := tapLink.Attrs() - - mcLink := &netlink.Macvtap{ - Macvlan: netlink.Macvlan{ - LinkAttrs: netlink.LinkAttrs{ - TxQLen: attrs.TxQLen, - ParentIndex: attrs.Index, - }, - }, - } - - macvtapName := "testmc0" - _, err = createMacVtap(netHandle, macvtapName, mcLink, 1) - assert.NoError(err) - - macvtapLink, err := getLinkByName(netHandle, macvtapName, &netlink.Macvtap{}) - assert.NoError(err) - - err = netHandle.LinkDel(macvtapLink) - assert.NoError(err) - - tapLink, err = getLinkByName(netHandle, tapName, &netlink.Tuntap{}) - assert.NoError(err) - - err = netHandle.LinkDel(tapLink) - assert.NoError(err) -} - -func TestTcRedirectNetwork(t *testing.T) { - if tc.NotValid(ktu.NeedRoot()) { - t.Skip(testDisabledAsNonRoot) - } - - assert := assert.New(t) - - netHandle, err := netlink.NewHandle() - assert.NoError(err) - defer netHandle.Close() - - // Create a test veth interface. - vethName := "foo" - veth := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: vethName, TxQLen: 200, MTU: 1400}, PeerName: "bar"} - - err = netlink.LinkAdd(veth) - assert.NoError(err) - - endpoint, err := createVethNetworkEndpoint(1, vethName, NetXConnectTCFilterModel) - assert.NoError(err) - - link, err := netlink.LinkByName(vethName) - assert.NoError(err) - - err = netHandle.LinkSetUp(link) - assert.NoError(err) - - err = setupTCFiltering(context.Background(), endpoint, 1, true) - assert.NoError(err) - - err = removeTCFiltering(context.Background(), endpoint) - assert.NoError(err) - - // Remove the veth created for testing. - err = netHandle.LinkDel(link) - assert.NoError(err) -} - -func TestRxRateLimiter(t *testing.T) { - if tc.NotValid(ktu.NeedRoot()) { - t.Skip(testDisabledAsNonRoot) - } - - assert := assert.New(t) - - netHandle, err := netlink.NewHandle() - assert.NoError(err) - defer netHandle.Close() - - // Create a test veth interface. - vethName := "foo" - veth := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: vethName, TxQLen: 200, MTU: 1400}, PeerName: "bar"} - - err = netlink.LinkAdd(veth) - assert.NoError(err) - - endpoint, err := createVethNetworkEndpoint(1, vethName, NetXConnectTCFilterModel) - assert.NoError(err) - - link, err := netlink.LinkByName(vethName) - assert.NoError(err) - - err = netHandle.LinkSetUp(link) - assert.NoError(err) - - err = setupTCFiltering(context.Background(), endpoint, 1, true) - assert.NoError(err) - - // 10Mb - maxRate := uint64(10000000) - err = addRxRateLimiter(endpoint, maxRate) - assert.NoError(err) - - currentNS, err := ns.GetCurrentNS() - assert.NoError(err) - - err = removeRxRateLimiter(endpoint, currentNS.Path()) - assert.NoError(err) - - err = removeTCFiltering(context.Background(), endpoint) - assert.NoError(err) - - // Remove the veth created for testing. - err = netHandle.LinkDel(link) - assert.NoError(err) -} - -func TestTxRateLimiter(t *testing.T) { - if tc.NotValid(ktu.NeedRoot()) { - t.Skip(testDisabledAsNonRoot) - } - - assert := assert.New(t) - - netHandle, err := netlink.NewHandle() - assert.NoError(err) - defer netHandle.Close() - - // Create a test veth interface. - vethName := "foo" - veth := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: vethName, TxQLen: 200, MTU: 1400}, PeerName: "bar"} - - err = netlink.LinkAdd(veth) - assert.NoError(err) - - endpoint, err := createVethNetworkEndpoint(1, vethName, NetXConnectTCFilterModel) - assert.NoError(err) - - link, err := netlink.LinkByName(vethName) - assert.NoError(err) - - err = netHandle.LinkSetUp(link) - assert.NoError(err) - - err = setupTCFiltering(context.Background(), endpoint, 1, true) - assert.NoError(err) - - // 10Mb - maxRate := uint64(10000000) - err = addTxRateLimiter(endpoint, maxRate) - assert.NoError(err) - - currentNS, err := ns.GetCurrentNS() - assert.NoError(err) - - err = removeTxRateLimiter(endpoint, currentNS.Path()) - assert.NoError(err) - - err = removeTCFiltering(context.Background(), endpoint) - assert.NoError(err) - - // Remove the veth created for testing. - err = netHandle.LinkDel(link) - assert.NoError(err) -}