From b18b49081446be38f7c9ee4bd72542bd554871c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 23 Jul 2025 08:55:48 +0000 Subject: [PATCH 1/2] Initial plan From 4b2e2a8c70b7b2d14985053fa38cc3cb9e9937c9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 23 Jul 2025 09:05:26 +0000 Subject: [PATCH 2/2] Implement master interface support in CNI configuration Co-authored-by: mdebjit <5107473+mdebjit@users.noreply.github.com> --- cni/cni.go | 8 +++- cni/cni_master_test.go | 86 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 cni/cni_master_test.go diff --git a/cni/cni.go b/cni/cni.go index 92c29972..6fa5a0e0 100644 --- a/cni/cni.go +++ b/cni/cni.go @@ -88,6 +88,7 @@ type NetworkConfig struct { CniVersion string `json:"cniVersion"` Name string `json:"name"` // Name is the Network Name. Type hcn.NetworkType `json:"type"` // As per SPEC, Type is Name of the Binary + Master string `json:"master,omitempty"` // Host interface name to bind the network to Ipam IpamConfig `json:"ipam"` DNS cniTypes.DNS `json:"dns"` OptionalFlags OptionalFlags `json:"optionalFlags"` @@ -279,9 +280,14 @@ func (config *NetworkConfig) GetNetworkInfo(podNamespace string) (ninfo *network Name: config.Name, Type: config.Type, Subnets: subnets, - InterfaceName: "", + InterfaceName: config.Master, DNS: dnsSettings, } + + // Log when master interface is specified + if config.Master != "" { + logrus.Infof("[cni-net] Using master interface '%s' for network '%s'", config.Master, config.Name) + } if config.AdditionalArgs != nil { for _, kvp := range config.AdditionalArgs { if strings.Contains(kvp.Name, "Policy") { diff --git a/cni/cni_master_test.go b/cni/cni_master_test.go new file mode 100644 index 00000000..9f4918ae --- /dev/null +++ b/cni/cni_master_test.go @@ -0,0 +1,86 @@ +// Copyright Microsoft Corp. +// All rights reserved. + +//go:build windows +// +build windows + +package cni + +import ( + "testing" +) + +// TestParseMasterField tests that the master field is properly parsed from CNI config +func TestParseMasterField(t *testing.T) { + // Test with master field present + configWithMaster := `{ + "cniVersion": "0.3.0", + "name": "testNetwork", + "type": "nat", + "master": "Ethernet", + "ipam": { + "subnet": "192.168.100.0/24" + } + }` + + config, err := ParseNetworkConfig([]byte(configWithMaster)) + if err != nil { + t.Fatalf("Failed to parse config with master field: %v", err) + } + + if config.Master != "Ethernet" { + t.Errorf("Expected master to be 'Ethernet', got '%s'", config.Master) + } + + // Test with master field missing (should be empty string) + configWithoutMaster := `{ + "cniVersion": "0.3.0", + "name": "testNetwork", + "type": "nat", + "ipam": { + "subnet": "192.168.100.0/24" + } + }` + + config2, err := ParseNetworkConfig([]byte(configWithoutMaster)) + if err != nil { + t.Fatalf("Failed to parse config without master field: %v", err) + } + + if config2.Master != "" { + t.Errorf("Expected master to be empty when not specified, got '%s'", config2.Master) + } +} + +// TestMasterFieldInNetworkInfo tests that the master field is properly propagated to NetworkInfo +func TestMasterFieldInNetworkInfo(t *testing.T) { + config := &NetworkConfig{ + CniVersion: "0.3.0", + Name: "testNetwork", + Type: "nat", + Master: "Ethernet", + Ipam: IpamConfig{ + Subnet: "192.168.100.0/24", + }, + } + + networkInfo, err := config.GetNetworkInfo("") + if err != nil { + t.Fatalf("Failed to get network info: %v", err) + } + + if networkInfo.InterfaceName != "Ethernet" { + t.Errorf("Expected InterfaceName to be 'Ethernet', got '%s'", networkInfo.InterfaceName) + } + + // Test with empty master + config.Master = "" + networkInfo2, err := config.GetNetworkInfo("") + if err != nil { + t.Fatalf("Failed to get network info with empty master: %v", err) + } + + if networkInfo2.InterfaceName != "" { + t.Errorf("Expected InterfaceName to be empty when master is empty, got '%s'", networkInfo2.InterfaceName) + } +} \ No newline at end of file