Skip to content
Open
1 change: 1 addition & 0 deletions cni/network/multitenancy.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ func (m *Multitenancy) GetAllNetworkContainers(
ifInfo.IPConfigs = append(ifInfo.IPConfigs, ipconfig)
ifInfo.Routes = routes
ifInfo.NICType = cns.InfraNIC
ifInfo.SkipDefaultRoutes = ncResponses[i].SkipDefaultRoutes

// assuming we only assign infra nics in this function
ipamResult.interfaceInfo[m.getInterfaceInfoKey(ifInfo.NICType, i)] = ifInfo
Expand Down
2 changes: 1 addition & 1 deletion cni/network/network_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func platformInit(cniConfig *cni.NetworkConfig) {}

// isDualNicFeatureSupported returns if the dual nic feature is supported. Currently it's only supported for windows hnsv2 path
func (plugin *NetPlugin) isDualNicFeatureSupported(netNs string) bool {
return false
return true
}

func getOverlayGateway(_ *net.IPNet) (net.IP, error) {
Expand Down
6 changes: 4 additions & 2 deletions cns/NetworkContainerContract.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ type CreateNetworkContainerRequest struct {
Routes []Route
AllowHostToNCCommunication bool
AllowNCToHostCommunication bool
SkipDefaultRoutes bool
EndpointPolicies []NetworkContainerRequestPolicies
NCStatus v1alpha.NCStatus
NetworkInterfaceInfo NetworkInterfaceInfo //nolint // introducing new field for backendnic, to be used later by cni code
Expand Down Expand Up @@ -161,10 +162,10 @@ func (req *CreateNetworkContainerRequest) String() string {
return fmt.Sprintf("CreateNetworkContainerRequest"+
"{Version: %s, NetworkContainerType: %s, NetworkContainerid: %s, PrimaryInterfaceIdentifier: %s, "+
"LocalIPConfiguration: %+v, IPConfiguration: %+v, SecondaryIPConfigs: %+v, MultitenancyInfo: %+v, "+
"AllowHostToNCCommunication: %t, AllowNCToHostCommunication: %t, NCStatus: %s, NetworkInterfaceInfo: %+v}",
"AllowHostToNCCommunication: %t, AllowNCToHostCommunication: %t, SkipDefaultRoutes: %t, NCStatus: %s, NetworkInterfaceInfo: %+v}",
req.Version, req.NetworkContainerType, req.NetworkContainerid, req.PrimaryInterfaceIdentifier, req.LocalIPConfiguration,
req.IPConfiguration, req.SecondaryIPConfigs, req.MultiTenancyInfo, req.AllowHostToNCCommunication, req.AllowNCToHostCommunication,
string(req.NCStatus), req.NetworkInterfaceInfo)
req.SkipDefaultRoutes, string(req.NCStatus), req.NetworkInterfaceInfo)
}

// NetworkContainerRequestPolicies - specifies policies associated with create network request
Expand Down Expand Up @@ -497,6 +498,7 @@ type GetNetworkContainerResponse struct {
Response Response
AllowHostToNCCommunication bool
AllowNCToHostCommunication bool
SkipDefaultRoutes bool
NetworkInterfaceInfo NetworkInterfaceInfo
}

Expand Down
37 changes: 37 additions & 0 deletions cns/NetworkContainerContract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,40 @@ func TestPostNetworkContainersRequest_Validate(t *testing.T) {
})
}
}

func TestCreateNetworkContainerRequest_SkipDefaultRoutes(t *testing.T) {
tests := []struct {
name string
req CreateNetworkContainerRequest
expected bool
}{
{
name: "SkipDefaultRoutesTrue",
req: CreateNetworkContainerRequest{
NetworkContainerid: "f47ac10b-58cc-0372-8567-0e02b2c3d479",
SkipDefaultRoutes: true,
},
expected: true,
},
{
name: "SkipDefaultRoutesFalse",
req: CreateNetworkContainerRequest{
NetworkContainerid: "f47ac10b-58cc-0372-8567-0e02b2c3d479",
SkipDefaultRoutes: false,
},
expected: false,
},
{
name: "SkipDefaultRoutesIgnored",
req: CreateNetworkContainerRequest{
NetworkContainerid: "f47ac10b-58cc-0372-8567-0e02b2c3d479",
},
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, tt.req.SkipDefaultRoutes, "SkipDefaultRoutes value should match expected")
})
}
}
4 changes: 4 additions & 0 deletions cns/restserver/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ func (service *HTTPRestService) getAllNetworkContainerResponses(
LocalIPConfiguration: savedReq.LocalIPConfiguration,
AllowHostToNCCommunication: savedReq.AllowHostToNCCommunication,
AllowNCToHostCommunication: savedReq.AllowNCToHostCommunication,
SkipDefaultRoutes: savedReq.SkipDefaultRoutes,
NetworkInterfaceInfo: savedReq.NetworkInterfaceInfo,
}

Expand Down Expand Up @@ -831,6 +832,8 @@ func (service *HTTPRestService) populateIPConfigInfoUntransacted(ipConfigStatus

primaryIPCfg := ncStatus.CreateNetworkContainerRequest.IPConfiguration

podIPInfo.SkipDefaultRoutes = ncStatus.CreateNetworkContainerRequest.SkipDefaultRoutes

podIPInfo.PodIPConfig = cns.IPSubnet{
IPAddress: ipConfigStatus.IPAddress,
PrefixLength: primaryIPCfg.IPSubnet.PrefixLength,
Expand Down Expand Up @@ -933,6 +936,7 @@ func (service *HTTPRestService) handleGetNetworkContainers(w http.ResponseWriter
LocalIPConfiguration: ncDetails.CreateNetworkContainerRequest.LocalIPConfiguration,
AllowHostToNCCommunication: ncDetails.CreateNetworkContainerRequest.AllowHostToNCCommunication,
AllowNCToHostCommunication: ncDetails.CreateNetworkContainerRequest.AllowNCToHostCommunication,
SkipDefaultRoutes: ncDetails.CreateNetworkContainerRequest.SkipDefaultRoutes,
}
networkContainers[i] = getNcResp
i++
Expand Down
27 changes: 25 additions & 2 deletions network/transparent_vlan_endpointclient_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,6 @@ func (client *TransparentVlanEndpointClient) PopulateVM(epInfo *EndpointInfo) er
_, err = client.netioshim.GetNetworkInterfaceByName(client.vlanIfName)
return errors.Wrap(err, "failed to get vlan interface")
}, numRetries, sleepInMs)

if err != nil {
deleteNSIfNotNilErr = errors.Wrapf(err, "failed to get vlan interface: %s", client.vlanIfName)
return deleteNSIfNotNilErr
Expand Down Expand Up @@ -400,14 +399,32 @@ func (client *TransparentVlanEndpointClient) PopulateVnet(epInfo *EndpointInfo)
return nil
}

// Set ARP proxy on the vlan interface to respond to ARP requests for the gateway IP
func (client *TransparentVlanEndpointClient) setArpProxy(ifName string) error {
cmd := fmt.Sprintf("echo 1 > /proc/sys/net/ipv4/conf/%v/proxy_arp", ifName)
_, err := client.plClient.ExecuteRawCommand(cmd)
Comment on lines +404 to +405
Copy link
Preview

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using shell command execution with string formatting could be vulnerable to command injection if ifName contains malicious characters. Consider using a safer approach or validating the interface name against a whitelist of allowed characters.

Copilot uses AI. Check for mistakes.

if err != nil {
logger.Error("Failed to set ARP proxy", zap.String("interface", ifName), zap.Error(err))
return errors.Wrap(err, "failed to set arp proxy")
}
return nil
}

func (client *TransparentVlanEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error {
if err := client.AddSnatEndpointRules(); err != nil {
return errors.Wrap(err, "failed to add snat endpoint rules")
}
logger.Info("[transparent-vlan] Adding tunneling rules in vnet namespace")
err := ExecuteInNS(client.nsClient, client.vnetNSName, func() error {
return client.AddVnetRules(epInfo)
if err := client.AddVnetRules(epInfo); err != nil {
return err
}

// Set ARP proxy on vnet veth (inside vnet namespace)
logger.Info("calling setArpProxy for", zap.String("vnetVethName", client.vnetVethName))
return client.setArpProxy(client.vnetVethName)
})

return err
}

Expand Down Expand Up @@ -519,9 +536,15 @@ func (client *TransparentVlanEndpointClient) ConfigureContainerInterfacesAndRout
}
}

if epInfo.SkipDefaultRoutes {
logger.Info("Skipping adding routes in container ns as requested")
return nil
}
logger.Info("Adding default routes in container ns")
if err := client.addDefaultRoutes(client.containerVethName, 0); err != nil {
return errors.Wrap(err, "failed container ns add default routes")
}

if err := client.AddDefaultArp(client.containerVethName, client.vnetMac.String()); err != nil {
return errors.Wrap(err, "failed container ns add default arp")
}
Expand Down
68 changes: 68 additions & 0 deletions network/transparent_vlan_endpointclient_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,74 @@ func TestTransparentVlanConfigureContainerInterfacesAndRoutes(t *testing.T) {
wantErr: true,
wantErrMsg: "failed container ns add default routes: addRoutes failed: " + netio.ErrMockNetIOFail.Error() + ":B1veth0",
},
{
name: "Configure interface and routes good path with SkipDefaultRoutes set to true for container",
client: &TransparentVlanEndpointClient{
primaryHostIfName: "eth0",
vlanIfName: "eth0.1",
vnetVethName: "A1veth0",
containerVethName: "B1veth0",
vnetNSName: "az_ns_1",
vnetMac: vnetMac,
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
},
epInfo: &EndpointInfo{
SkipDefaultRoutes: true,
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("192.168.0.4"),
Mask: net.CIDRMask(subnetv4Mask, ipv4Bits),
},
},
Subnets: []SubnetInfo{
{
Gateway: net.ParseIP("192.168.0.1"),
Prefix: net.IPNet{
IP: net.ParseIP("192.168.0.0"),
Mask: net.CIDRMask(subnetv4Mask, ipv4Bits),
},
},
},
},
wantErr: false,
},
{
name: "Configure interface and routes good path with SkipDefaultRoutes set to false for container",
client: &TransparentVlanEndpointClient{
primaryHostIfName: "eth0",
vlanIfName: "eth0.1",
vnetVethName: "A1veth0",
containerVethName: "B1veth0",
vnetNSName: "az_ns_1",
vnetMac: vnetMac,
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
},
epInfo: &EndpointInfo{
SkipDefaultRoutes: true,
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("192.168.0.4"),
Mask: net.CIDRMask(subnetv4Mask, ipv4Bits),
},
},
Subnets: []SubnetInfo{
{
Gateway: net.ParseIP("192.168.0.1"),
Prefix: net.IPNet{
IP: net.ParseIP("192.168.0.0"),
Mask: net.CIDRMask(subnetv4Mask, ipv4Bits),
},
},
},
},
wantErr: false,
},
}

for _, tt := range tests {
Expand Down
Loading