Skip to content

Commit

Permalink
Add UTs to test findMasterInterface (#2941)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
paulyufan2 authored Aug 28, 2024
1 parent 6cfc50f commit 6f3fcdb
Show file tree
Hide file tree
Showing 2 changed files with 252 additions and 3 deletions.
3 changes: 2 additions & 1 deletion cni/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
252 changes: 250 additions & 2 deletions cni/network/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net"
"os"
"runtime"
"strconv"
"testing"

"github.com/Azure/azure-container-networking/cni"
Expand Down Expand Up @@ -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) {
Expand All @@ -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")

Expand Down Expand Up @@ -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{
Expand Down

0 comments on commit 6f3fcdb

Please sign in to comment.