From 6f3fcdb432d46870e46ea5cbb5ee525836a36005 Mon Sep 17 00:00:00 2001 From: Paul Yu <129891899+paulyufan2@users.noreply.github.com> Date: Tue, 27 Aug 2024 22:29:24 -0400 Subject: [PATCH] Add UTs to test findMasterInterface (#2941) * add UTs to test findMasterInterface * fix comments * fix an UT * fix UTs * remove a fmt print * fix linter issue * add new IT * fix linter issue * fix comment * fix comment * add parser for multiple interfaces * remove print * add net.IPNet to net.addr array * fix comment --- cni/network/network.go | 3 +- cni/network/network_test.go | 252 +++++++++++++++++++++++++++++++++++- 2 files changed, 252 insertions(+), 3 deletions(-) diff --git a/cni/network/network.go b/cni/network/network.go index acfd5897dd..4b484a541b 100644 --- a/cni/network/network.go +++ b/cni/network/network.go @@ -107,6 +107,7 @@ type NnsClient interface { // client for getting interface type InterfaceGetter interface { GetNetworkInterfaces() ([]net.Interface, error) + GetNetworkInterfaceAddrs(iface *net.Interface) ([]net.Addr, error) } // snatConfiguration contains a bool that determines whether CNI enables snat on host and snat for dns @@ -255,7 +256,7 @@ func (plugin *NetPlugin) findMasterInterfaceBySubnet(nwCfg *cni.NetworkConfig, s } var ipnets []string for _, iface := range interfaces { - addrs, _ := iface.Addrs() + addrs, _ := plugin.netClient.GetNetworkInterfaceAddrs(&iface) //nolint for _, addr := range addrs { _, ipnet, err := net.ParseCIDR(addr.String()) if err != nil { diff --git a/cni/network/network_test.go b/cni/network/network_test.go index f6341375a3..632c1a0414 100644 --- a/cni/network/network_test.go +++ b/cni/network/network_test.go @@ -5,6 +5,7 @@ import ( "net" "os" "runtime" + "strconv" "testing" "github.com/Azure/azure-container-networking/cni" @@ -1235,8 +1236,9 @@ func TestGetPodSubnetNatInfo(t *testing.T) { } type InterfaceGetterMock struct { - interfaces []net.Interface - err error + interfaces []net.Interface + interfaceAddrs map[string][]net.Addr // key is interfaceName, value is one interface's CIDRs(IPs+Masks) + err error } func (n *InterfaceGetterMock) GetNetworkInterfaces() ([]net.Interface, error) { @@ -1246,6 +1248,21 @@ func (n *InterfaceGetterMock) GetNetworkInterfaces() ([]net.Interface, error) { return n.interfaces, nil } +func (n *InterfaceGetterMock) GetNetworkInterfaceAddrs(iface *net.Interface) ([]net.Addr, error) { + if n.err != nil { + return nil, n.err + } + + // actual net.Addr invokes syscall; here just create a mocked net.Addr{} + netAddrs := []net.Addr{} + for _, intf := range n.interfaces { + if iface.Name == intf.Name { + return n.interfaceAddrs[iface.Name], nil + } + } + return netAddrs, nil +} + func TestPluginSwiftV2Add(t *testing.T) { plugin, _ := cni.NewPlugin("name", "0.3.0") @@ -1746,6 +1763,237 @@ func TestPluginSwiftV2MultipleAddDelete(t *testing.T) { } } +// test findMasterInterface with different NIC types +func TestFindMasterInterface(t *testing.T) { + plugin, _ := cni.NewPlugin("name", "0.3.0") + endpointIndex := 1 + macAddress := "12:34:56:78:90:ab" + + tests := []struct { + name string + endpointOpt createEpInfoOpt + plugin *NetPlugin + nwCfg *cni.NetworkConfig + want string // expected master interface name + wantErr bool + }{ + { + name: "Find master interface by infraNIC with a master interfaceName in swiftv1 path", + plugin: &NetPlugin{ + Plugin: plugin, + report: &telemetry.CNIReport{}, + tb: &telemetry.TelemetryBuffer{}, + netClient: &InterfaceGetterMock{ + interfaces: []net.Interface{ + { + Name: "eth0", + }, + }, + }, + }, + endpointOpt: createEpInfoOpt{ + ipamAddConfig: &IPAMAddConfig{ + nwCfg: &cni.NetworkConfig{ + Master: "eth0", // return this master interface name + }, + }, + ifInfo: &acnnetwork.InterfaceInfo{ + NICType: cns.InfraNIC, + HostSubnetPrefix: net.IPNet{ + IP: net.ParseIP("10.255.0.0"), + Mask: net.CIDRMask(24, 32), + }, + }, + }, + want: "eth0", + wantErr: false, + }, + { + name: "Find master interface by one infraNIC", + plugin: &NetPlugin{ + Plugin: plugin, + report: &telemetry.CNIReport{}, + tb: &telemetry.TelemetryBuffer{}, + netClient: &InterfaceGetterMock{ + interfaces: []net.Interface{ + { + Index: 0, + Name: "eth0", + }, + }, + interfaceAddrs: map[string][]net.Addr{ + "eth0": { + &net.IPNet{ + IP: net.IPv4(10, 255, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + }, + }, + }, + }, + endpointOpt: createEpInfoOpt{ + ipamAddConfig: &IPAMAddConfig{ + nwCfg: &cni.NetworkConfig{ + Master: "", + }, + }, + ifInfo: &acnnetwork.InterfaceInfo{ + NICType: cns.InfraNIC, + HostSubnetPrefix: net.IPNet{ + IP: net.ParseIP("10.255.0.0"), + Mask: net.CIDRMask(24, 32), + }, + }, + }, + want: "eth0", + wantErr: false, + }, + { + name: "Find master interface from multiple infraNIC interfaces", + plugin: &NetPlugin{ + Plugin: plugin, + report: &telemetry.CNIReport{}, + tb: &telemetry.TelemetryBuffer{}, + netClient: &InterfaceGetterMock{ + interfaces: []net.Interface{ + { + Index: 0, + Name: "eth0", + }, + { + Index: 1, + Name: "eth1", + }, + }, + interfaceAddrs: map[string][]net.Addr{ + "eth0": { + &net.IPNet{ + IP: net.IPv4(10, 255, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + &net.IPNet{ + IP: net.IPv4(192, 168, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + }, + "eth1": { + &net.IPNet{ + IP: net.IPv4(20, 255, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + &net.IPNet{ + IP: net.IPv4(30, 255, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 0), + }, + }, + }, + }, + }, + endpointOpt: createEpInfoOpt{ + ipamAddConfig: &IPAMAddConfig{ + nwCfg: &cni.NetworkConfig{ + Master: "", + }, + }, + ifInfo: &acnnetwork.InterfaceInfo{ + NICType: cns.InfraNIC, + HostSubnetPrefix: net.IPNet{ + IP: net.ParseIP("20.255.0.0"), + Mask: net.CIDRMask(24, 32), + }, + }, + }, + want: "eth1", + wantErr: false, + }, + { + name: "Find master interface by delegatedVMNIC", + plugin: &NetPlugin{ + Plugin: plugin, + report: &telemetry.CNIReport{}, + tb: &telemetry.TelemetryBuffer{}, + netClient: &InterfaceGetterMock{ + interfaces: []net.Interface{ + { + Name: "eth1", + HardwareAddr: net.HardwareAddr(macAddress), + }, + }, + }, + }, + endpointOpt: createEpInfoOpt{ + ifInfo: &acnnetwork.InterfaceInfo{ + NICType: cns.NodeNetworkInterfaceFrontendNIC, + MacAddress: net.HardwareAddr(macAddress), + }, + }, + want: "eth1", + wantErr: false, + }, + { + name: "Find master interface by accelnetNIC", + plugin: &NetPlugin{ + Plugin: plugin, + report: &telemetry.CNIReport{}, + tb: &telemetry.TelemetryBuffer{}, + netClient: &InterfaceGetterMock{ + interfaces: []net.Interface{ + { + Name: "eth1", + HardwareAddr: net.HardwareAddr(macAddress), + }, + }, + }, + }, + endpointOpt: createEpInfoOpt{ + ifInfo: &acnnetwork.InterfaceInfo{ + NICType: cns.NodeNetworkInterfaceAccelnetFrontendNIC, + MacAddress: net.HardwareAddr(macAddress), + }, + }, + want: "eth1", + wantErr: false, + }, + { + name: "Find master interface by backend NIC", + endpointOpt: createEpInfoOpt{ + endpointIndex: endpointIndex, + ifInfo: &acnnetwork.InterfaceInfo{ + NICType: cns.BackendNIC, + MacAddress: net.HardwareAddr(macAddress), + }, + }, + want: ibInterfacePrefix + strconv.Itoa(endpointIndex), + wantErr: false, + }, + { + name: "Find master interface by invalid NIC type", + endpointOpt: createEpInfoOpt{ + endpointIndex: endpointIndex, + ifInfo: &acnnetwork.InterfaceInfo{ + NICType: "invalidType", + MacAddress: net.HardwareAddr(macAddress), + }, + }, + want: "", // default interface name is "" + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + masterInterface := tt.plugin.findMasterInterface(&tt.endpointOpt) + t.Logf("masterInterface is %s\n", masterInterface) + require.Equal(t, tt.want, masterInterface) + }) + } +} + func TestValidateArgs(t *testing.T) { p, _ := cni.NewPlugin("name", "0.3.0") plugin := &NetPlugin{