diff --git a/Makefile b/Makefile index 946b459fd5..93823d4967 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ CNM_BUILD_DIR = $(BUILD_DIR)/cnm CNI_BUILD_DIR = $(BUILD_DIR)/cni ACNCLI_BUILD_DIR = $(BUILD_DIR)/acncli CNI_MULTITENANCY_BUILD_DIR = $(BUILD_DIR)/cni-multitenancy +CNI_MULTITENANCY_TRANSPARENT_VLAN_BUILD_DIR = $(BUILD_DIR)/cni-multitenancy-transparent-vlan CNI_SWIFT_BUILD_DIR = $(BUILD_DIR)/cni-swift CNI_OVERLAY_BUILD_DIR = $(BUILD_DIR)/cni-overlay CNI_BAREMETAL_BUILD_DIR = $(BUILD_DIR)/cni-baremetal @@ -77,6 +78,7 @@ CNM_ARCHIVE_NAME = azure-vnet-cnm-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT) CNI_ARCHIVE_NAME = azure-vnet-cni-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT) ACNCLI_ARCHIVE_NAME = acncli-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT) CNI_MULTITENANCY_ARCHIVE_NAME = azure-vnet-cni-multitenancy-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT) +CNI_MULTITENANCY_TRANSPARENT_VLAN_ARCHIVE_NAME = azure-vnet-cni-multitenancy-transparent-vlan-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT) CNI_SWIFT_ARCHIVE_NAME = azure-vnet-cni-swift-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT) CNI_OVERLAY_ARCHIVE_NAME = azure-vnet-cni-overlay-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT) CNI_BAREMETAL_ARCHIVE_NAME = azure-vnet-cni-baremetal-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT) @@ -439,6 +441,15 @@ ifeq ($(GOOS),linux) endif cd $(CNI_MULTITENANCY_BUILD_DIR) && $(ARCHIVE_CMD) $(CNI_MULTITENANCY_ARCHIVE_NAME) azure-vnet$(EXE_EXT) azure-vnet-ipam$(EXE_EXT) azure-vnet-telemetry$(EXE_EXT) 10-azure.conflist azure-vnet-telemetry.config + $(MKDIR) $(CNI_MULTITENANCY_TRANSPARENT_VLAN_BUILD_DIR) + cp cni/azure-$(GOOS)-multitenancy-transparent-vlan.conflist $(CNI_MULTITENANCY_TRANSPARENT_VLAN_BUILD_DIR)/10-azure.conflist + cp $(CNI_BUILD_DIR)/azure-vnet$(EXE_EXT) $(CNI_BUILD_DIR)/azure-vnet-ipam$(EXE_EXT) $(CNI_MULTITENANCY_TRANSPARENT_VLAN_BUILD_DIR) +ifeq ($(GOOS),linux) + cp telemetry/azure-vnet-telemetry.config $(CNI_MULTITENANCY_TRANSPARENT_VLAN_BUILD_DIR)/azure-vnet-telemetry.config + cp $(CNI_BUILD_DIR)/azure-vnet-telemetry$(EXE_EXT) $(CNI_MULTITENANCY_TRANSPARENT_VLAN_BUILD_DIR) +endif + cd $(CNI_MULTITENANCY_TRANSPARENT_VLAN_BUILD_DIR) && $(ARCHIVE_CMD) $(CNI_MULTITENANCY_TRANSPARENT_VLAN_ARCHIVE_NAME) azure-vnet$(EXE_EXT) azure-vnet-ipam$(EXE_EXT) azure-vnet-telemetry$(EXE_EXT) 10-azure.conflist azure-vnet-telemetry.config + $(MKDIR) $(CNI_SWIFT_BUILD_DIR) cp cni/azure-$(GOOS)-swift.conflist $(CNI_SWIFT_BUILD_DIR)/10-azure.conflist cp telemetry/azure-vnet-telemetry.config $(CNI_SWIFT_BUILD_DIR)/azure-vnet-telemetry.config diff --git a/cni/azure-linux-multitenancy-transparent-vlan.conflist b/cni/azure-linux-multitenancy-transparent-vlan.conflist new file mode 100644 index 0000000000..a997d1981f --- /dev/null +++ b/cni/azure-linux-multitenancy-transparent-vlan.conflist @@ -0,0 +1,29 @@ +{ + "cniVersion":"0.3.0", + "name":"azure", + "plugins":[ + { + "type":"azure-vnet", + "mode":"transparent-vlan", + "bridge":"azure0", + "multiTenancy":true, + "infraVnetAddressSpace":"", + "podNamespaceForDualNetwork":[], + "enableExactMatchForPodName": false, + "enableSnatOnHost":true, + "ipam":{ + "type":"azure-cns" + }, + "dns":{ + "nameservers":[] + } + }, + { + "type":"portmap", + "capabilities":{ + "portMappings":true + }, + "snat":true + } + ] +} diff --git a/cni/azure-windows-multitenancy-transparent-vlan.conflist b/cni/azure-windows-multitenancy-transparent-vlan.conflist new file mode 100644 index 0000000000..21031acab3 --- /dev/null +++ b/cni/azure-windows-multitenancy-transparent-vlan.conflist @@ -0,0 +1,52 @@ +{ + "cniVersion": "0.3.0", + "name": "azure", + "plugins": [ + { + "type": "azure-vnet", + "mode": "transparent-vlan", + "bridge": "azure0", + "multiTenancy":true, + "enableSnatOnHost":true, + "enableExactMatchForPodName": true, + "capabilities": { + "portMappings": true + }, + "ipam": { + "type": "azure-cns" + }, + "dns": { + "Nameservers": [ + "10.0.0.10", + "168.63.129.16" + ], + "Search": [ + "svc.cluster.local" + ] + }, + "AdditionalArgs": [ + { + "Name": "EndpointPolicy", + "Value": { + "Type": "OutBoundNAT", + "ExceptionList": [ + "10.240.0.0/16", + "10.0.0.0/8" + ] + } + }, + { + "Name": "EndpointPolicy", + "Value": { + "Type": "ROUTE", + "DestinationPrefix": "10.0.0.0/8", + "NeedEncap": true + } + } + ], + "windowsSettings": { + "hnsTimeoutDurationInSeconds" : 120 + } + } + ] +} \ No newline at end of file diff --git a/network/endpoint.go b/network/endpoint.go index ec51bea1bf..ae3d1008a9 100644 --- a/network/endpoint.go +++ b/network/endpoint.go @@ -93,6 +93,7 @@ type RouteInfo struct { DevName string Scope int Priority int + Table int } type apipaClient interface { diff --git a/network/endpoint_linux.go b/network/endpoint_linux.go index 0c21b6c0d5..92400ec8af 100644 --- a/network/endpoint_linux.go +++ b/network/endpoint_linux.go @@ -13,7 +13,6 @@ import ( "github.com/Azure/azure-container-networking/log" "github.com/Azure/azure-container-networking/netio" "github.com/Azure/azure-container-networking/netlink" - "github.com/Azure/azure-container-networking/netns" "github.com/Azure/azure-container-networking/network/networkutils" "github.com/Azure/azure-container-networking/ovsctl" "github.com/Azure/azure-container-networking/platform" @@ -90,25 +89,12 @@ func (nw *network) newEndpointImpl(_ apipaClient, nl netlink.NetlinkInterface, p } if vlanid != 0 { - if nw.Mode == opModeNative { - log.Printf("Native client") - vlanVethName := fmt.Sprintf("%s.%d", nw.extIf.Name, vlanid) - vnetNSName := fmt.Sprintf("az_ns_%d", vlanid) - - epClient = &NativeEndpointClient{ - primaryHostIfName: nw.extIf.Name, - vlanIfName: vlanVethName, - vnetVethName: hostIfName, - containerVethName: contIfName, - vnetNSName: vnetNSName, - nw: nw, - vlanID: vlanid, - netnsClient: netns.New(), - netlink: nl, - netioshim: &netio.NetIO{}, - plClient: plc, - netUtilsClient: networkutils.NewNetworkUtils(nl, plc), + if nw.Mode == opModeTransparentVlan { + log.Printf("Transparent vlan client") + if _, ok := epInfo.Data[SnatBridgeIPKey]; ok { + nw.SnatBridgeIP = epInfo.Data[SnatBridgeIPKey].(string) } + epClient = NewTransparentVlanEndpointClient(nw, epInfo, hostIfName, contIfName, vlanid, localIP, nl, plc) } else { log.Printf("OVS client") if _, ok := epInfo.Data[SnatBridgeIPKey]; ok { @@ -261,25 +247,10 @@ func (nw *network) deleteEndpointImpl(nl netlink.NetlinkInterface, plc platform. // entering the container netns and hence works both for CNI and CNM. if ep.VlanID != 0 { epInfo := ep.getInfo() - if nw.Mode == opModeNative { - log.Printf("Native client") - vlanVethName := fmt.Sprintf("%s.%d", nw.extIf.Name, ep.VlanID) - vnetNSName := fmt.Sprintf("az_ns_%d", ep.VlanID) - - epClient = &NativeEndpointClient{ - primaryHostIfName: nw.extIf.Name, - vlanIfName: vlanVethName, - vnetVethName: ep.HostIfName, - containerVethName: "", - vnetNSName: vnetNSName, - nw: nw, - vlanID: ep.VlanID, - netnsClient: netns.New(), - netlink: nl, - netioshim: &netio.NetIO{}, - plClient: plc, - netUtilsClient: networkutils.NewNetworkUtils(nl, plc), - } + if nw.Mode == opModeTransparentVlan { + log.Printf("Transparent vlan client") + epClient = NewTransparentVlanEndpointClient(nw, epInfo, ep.HostIfName, "", ep.VlanID, ep.LocalIP, nl, plc) + } else { epClient = NewOVSEndpointClient(nw, epInfo, ep.HostIfName, "", ep.VlanID, ep.LocalIP, nl, ovsctl.NewOvsctl(), plc) } @@ -330,6 +301,7 @@ func addRoutes(nl netlink.NetlinkInterface, netioshim netio.NetIOInterface, inte Priority: route.Priority, Protocol: route.Protocol, Scope: route.Scope, + Table: route.Table, } if err := nl.AddIPRoute(nlRoute); err != nil { diff --git a/network/endpoint_snatroute_linux.go b/network/endpoint_snatroute_linux.go new file mode 100644 index 0000000000..67f68d423a --- /dev/null +++ b/network/endpoint_snatroute_linux.go @@ -0,0 +1,100 @@ +package network + +import ( + "fmt" + + "github.com/Azure/azure-container-networking/log" + "github.com/Azure/azure-container-networking/netlink" + "github.com/Azure/azure-container-networking/network/networkutils" + "github.com/Azure/azure-container-networking/network/snat" + "github.com/Azure/azure-container-networking/platform" + "github.com/pkg/errors" +) + +func GetSnatHostIfName(epInfo *EndpointInfo) string { + return fmt.Sprintf("%s%s", snatVethInterfacePrefix, epInfo.Id[:7]) +} + +func GetSnatContIfName(epInfo *EndpointInfo) string { + return fmt.Sprintf("%s%s-2", snatVethInterfacePrefix, epInfo.Id[:7]) +} + +func AddSnatEndpoint(snatClient *snat.Client) error { + if err := snatClient.CreateSnatEndpoint(); err != nil { + return errors.Wrap(err, "failed to add snat endpoint") + } + return nil +} + +func AddSnatEndpointRules(snatClient *snat.Client, hostToNC, ncToHost bool, nl netlink.NetlinkInterface, plc platform.ExecClient) error { + // Allow specific Private IPs via Snat Bridge + if err := snatClient.AllowIPAddressesOnSnatBridge(); err != nil { + return errors.Wrap(err, "failed to allow ip addresses on snat bridge") + } + + // Block Private IPs via Snat Bridge + if err := snatClient.BlockIPAddressesOnSnatBridge(); err != nil { + return errors.Wrap(err, "failed to block ip addresses on snat bridge") + } + nuc := networkutils.NewNetworkUtils(nl, plc) + if err := nuc.EnableIPForwarding(snat.SnatBridgeName); err != nil { + return errors.Wrap(err, "failed to enable ip forwarding") + } + + if hostToNC { + if err := snatClient.AllowInboundFromHostToNC(); err != nil { + return errors.Wrap(err, "failed to allow inbound from host to nc") + } + } + + if ncToHost { + if err := snatClient.AllowInboundFromNCToHost(); err != nil { + return errors.Wrap(err, "failed to allow inbound from nc to host") + } + } + return nil +} + +func MoveSnatEndpointToContainerNS(snatClient *snat.Client, netnsPath string, nsID uintptr) error { + if err := snatClient.MoveSnatEndpointToContainerNS(netnsPath, nsID); err != nil { + return errors.Wrap(err, "failed to move snat endpoint to container ns") + } + return nil +} + +func SetupSnatContainerInterface(snatClient *snat.Client) error { + if err := snatClient.SetupSnatContainerInterface(); err != nil { + return errors.Wrap(err, "failed to setup snat container interface") + } + return nil +} + +func ConfigureSnatContainerInterface(snatClient *snat.Client) error { + if err := snatClient.ConfigureSnatContainerInterface(); err != nil { + return errors.Wrap(err, "failed to configure snat container interface") + } + return nil +} + +func DeleteSnatEndpoint(snatClient *snat.Client) error { + if err := snatClient.DeleteSnatEndpoint(); err != nil { + return errors.Wrap(err, "failed to delete snat endpoint") + } + return nil +} + +func DeleteSnatEndpointRules(snatClient *snat.Client, hostToNC, ncToHost bool) { + if hostToNC { + err := snatClient.DeleteInboundFromHostToNC() + if err != nil { + log.Errorf("failed to delete inbound from host to nc rules") + } + } + + if ncToHost { + err := snatClient.DeleteInboundFromNCToHost() + if err != nil { + log.Errorf("failed to delete inbound from nc to host rules") + } + } +} diff --git a/network/network.go b/network/network.go index a28d0a7244..bdcb80612b 100644 --- a/network/network.go +++ b/network/network.go @@ -15,11 +15,11 @@ import ( const ( // Operational modes. - opModeBridge = "bridge" - opModeTunnel = "tunnel" - opModeTransparent = "transparent" - opModeNative = "native" - opModeDefault = opModeTunnel + opModeBridge = "bridge" + opModeTunnel = "tunnel" + opModeTransparent = "transparent" + opModeTransparentVlan = "transparent-vlan" + opModeDefault = opModeTunnel ) const ( diff --git a/network/network_linux.go b/network/network_linux.go index 5ced57c8c2..50070e66ad 100644 --- a/network/network_linux.go +++ b/network/network_linux.go @@ -88,8 +88,8 @@ func (nm *networkManager) newNetworkImpl(nwInfo *NetworkInfo, extIf *externalInt return nil, fmt.Errorf("Ipv6 forwarding failed: %w", err) } } - case opModeNative: - log.Printf("Native mode") + case opModeTransparentVlan: + log.Printf("Transparent vlan mode") ifName = extIf.Name default: return nil, errNetworkModeInvalid diff --git a/network/ovs_endpoint_snatroute_linux.go b/network/ovs_endpoint_snatroute_linux.go index 5048bfc54a..9f43b2a6a2 100644 --- a/network/ovs_endpoint_snatroute_linux.go +++ b/network/ovs_endpoint_snatroute_linux.go @@ -1,114 +1,151 @@ package network import ( - "fmt" + "net" + "github.com/Azure/azure-container-networking/log" + "github.com/Azure/azure-container-networking/netlink" "github.com/Azure/azure-container-networking/network/networkutils" - "github.com/Azure/azure-container-networking/network/ovssnat" + "github.com/Azure/azure-container-networking/network/snat" + "github.com/pkg/errors" ) -func NewSnatClient(client *OVSEndpointClient, snatBridgeIP string, localIP string, epInfo *EndpointInfo) { - if client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDns { - hostIfName := fmt.Sprintf("%s%s", snatVethInterfacePrefix, epInfo.Id[:7]) - contIfName := fmt.Sprintf("%s%s-2", snatVethInterfacePrefix, epInfo.Id[:7]) +// Communication between ovs switch and snat bridge, master of azuresnatveth0 is snat bridge itself +const ( + azureSnatVeth0 = "azSnatveth0" + azureSnatVeth1 = "azSnatveth1" +) + +func (client *OVSEndpointClient) isSnatEnabled() bool { + return client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDns +} - client.snatClient = ovssnat.NewSnatClient(hostIfName, - contIfName, +func (client *OVSEndpointClient) NewSnatClient(snatBridgeIP, localIP string, epInfo *EndpointInfo) { + if client.isSnatEnabled() { + client.snatClient = snat.NewSnatClient( + GetSnatHostIfName(epInfo), + GetSnatContIfName(epInfo), localIP, snatBridgeIP, client.hostPrimaryMac, epInfo.DNS.Servers, client.netlink, - client.ovsctlClient, client.plClient, ) } } -func AddSnatEndpoint(client *OVSEndpointClient) error { - if client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDns { - if err := client.snatClient.CreateSnatEndpoint(client.bridgeName); err != nil { +func (client *OVSEndpointClient) AddSnatEndpoint() error { + if client.isSnatEnabled() { + if err := AddSnatEndpoint(&client.snatClient); err != nil { return err } - } + // A lot of this code was in createSnatBridge initially and moved here since it is for ovs only - return nil -} + snatClient := client.snatClient -func AddSnatEndpointRules(client *OVSEndpointClient) error { - if client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDns { - // Allow specific Private IPs via Snat Bridge - if err := client.snatClient.AllowIPAddressesOnSnatBridge(); err != nil { + log.Printf("Drop ARP for snat bridge ip: %s", snatClient.SnatBridgeIP) + if err := client.snatClient.DropArpForSnatBridgeApipaRange(snatClient.SnatBridgeIP, azureSnatVeth0); err != nil { return err } - // Block Private IPs via Snat Bridge - if err := client.snatClient.BlockIPAddressesOnSnatBridge(); err != nil { - return err + // Create a veth pair. One end of veth will be attached to ovs bridge and other end + // of veth will be attached to linux bridge + _, err := net.InterfaceByName(azureSnatVeth0) + if err == nil { + log.Printf("Azure snat veth already exists") + return nil } - // Add route for 169.254.169.54 in host via azure0, otherwise it will route via snat bridge - if err := AddStaticRoute(client.netlink, client.netioshim, ovssnat.ImdsIP, client.bridgeName); err != nil { - return err + vethLink := netlink.VEthLink{ + LinkInfo: netlink.LinkInfo{ + Type: netlink.LINK_TYPE_VETH, + Name: azureSnatVeth0, + }, + PeerName: azureSnatVeth1, } + err = client.netlink.AddLink(&vethLink) + if err != nil { + log.Printf("[net] Failed to create veth pair, err:%v.", err) + return errors.Wrap(err, "failed to create veth pair") + } nuc := networkutils.NewNetworkUtils(client.netlink, client.plClient) - if err := nuc.EnableIPForwarding(ovssnat.SnatBridgeName); err != nil { + //nolint + if err = nuc.DisableRAForInterface(azureSnatVeth0); err != nil { + return err + } + + //nolint + if err = nuc.DisableRAForInterface(azureSnatVeth1); err != nil { return err } - if client.allowInboundFromHostToNC { - if err := client.snatClient.AllowInboundFromHostToNC(); err != nil { - return err - } + if err := client.netlink.SetLinkState(azureSnatVeth0, true); err != nil { + return errors.Wrap(err, "failed to set azure snat veth 0 to up") } - if client.allowInboundFromNCToHost { - return client.snatClient.AllowInboundFromNCToHost() + if err := client.netlink.SetLinkMaster(azureSnatVeth0, snat.SnatBridgeName); err != nil { + return errors.Wrap(err, "failed to set snat veth 0 master to snat bridge") } - } + if err := client.netlink.SetLinkState(azureSnatVeth1, true); err != nil { + return errors.Wrap(err, "failed to set azure snat veth 1 to up") + } + + if err := client.ovsctlClient.AddPortOnOVSBridge(azureSnatVeth1, client.bridgeName, 0); err != nil { + return errors.Wrap(err, "failed to add port on OVS bridge") + } + } return nil } -func MoveSnatEndpointToContainerNS(client *OVSEndpointClient, netnsPath string, nsID uintptr) error { - if client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDns { - return client.snatClient.MoveSnatEndpointToContainerNS(netnsPath, nsID) +func (client *OVSEndpointClient) AddSnatEndpointRules() error { + if client.isSnatEnabled() { + // Add route for 169.254.169.254 in host via azure0, otherwise it will route via snat bridge + if err := AddSnatEndpointRules(&client.snatClient, client.allowInboundFromHostToNC, client.allowInboundFromNCToHost, client.netlink, client.plClient); err != nil { + return err + } + if err := AddStaticRoute(client.netlink, client.netioshim, snat.ImdsIP, client.bridgeName); err != nil { + return err + } } return nil } -func SetupSnatContainerInterface(client *OVSEndpointClient) error { - if client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDns { - return client.snatClient.SetupSnatContainerInterface() +func (client *OVSEndpointClient) MoveSnatEndpointToContainerNS(netnsPath string, nsID uintptr) error { + if client.isSnatEnabled() { + return MoveSnatEndpointToContainerNS(&client.snatClient, netnsPath, nsID) } return nil } -func ConfigureSnatContainerInterface(client *OVSEndpointClient) error { - if client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDns { - return client.snatClient.ConfigureSnatContainerInterface() +func (client *OVSEndpointClient) SetupSnatContainerInterface() error { + if client.isSnatEnabled() { + return SetupSnatContainerInterface(&client.snatClient) } return nil } -func DeleteSnatEndpoint(client *OVSEndpointClient) error { - if client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDns { - return client.snatClient.DeleteSnatEndpoint() +func (client *OVSEndpointClient) ConfigureSnatContainerInterface() error { + if client.isSnatEnabled() { + return ConfigureSnatContainerInterface(&client.snatClient) } return nil } -func DeleteSnatEndpointRules(client *OVSEndpointClient) { - if client.allowInboundFromHostToNC { - client.snatClient.DeleteInboundFromHostToNC() +func (client *OVSEndpointClient) DeleteSnatEndpoint() error { + if client.isSnatEnabled() { + return DeleteSnatEndpoint(&client.snatClient) } - if client.allowInboundFromNCToHost { - client.snatClient.DeleteInboundFromNCToHost() - } + return nil +} + +func (client *OVSEndpointClient) DeleteSnatEndpointRules() { + DeleteSnatEndpointRules(&client.snatClient, client.allowInboundFromHostToNC, client.allowInboundFromNCToHost) } diff --git a/network/ovs_endpointclient_linux.go b/network/ovs_endpointclient_linux.go index 54054f2572..dd9300a146 100644 --- a/network/ovs_endpointclient_linux.go +++ b/network/ovs_endpointclient_linux.go @@ -11,7 +11,7 @@ import ( "github.com/Azure/azure-container-networking/netlink" "github.com/Azure/azure-container-networking/network/networkutils" "github.com/Azure/azure-container-networking/network/ovsinfravnet" - "github.com/Azure/azure-container-networking/network/ovssnat" + "github.com/Azure/azure-container-networking/network/snat" "github.com/Azure/azure-container-networking/ovsctl" "github.com/Azure/azure-container-networking/platform" ) @@ -23,7 +23,7 @@ type OVSEndpointClient struct { hostPrimaryMac string containerVethName string containerMac string - snatClient ovssnat.OVSSnatClient + snatClient snat.Client infraVnetClient ovsinfravnet.OVSInfraVnetClient vlanID int enableSnatOnHost bool @@ -51,8 +51,8 @@ func NewOVSEndpointClient( localIP string, nl netlink.NetlinkInterface, ovs ovsctl.OvsInterface, - plc platform.ExecClient) *OVSEndpointClient { - + plc platform.ExecClient, +) *OVSEndpointClient { client := &OVSEndpointClient{ bridgeName: nw.extIf.BridgeName, hostPrimaryIfName: nw.extIf.Name, @@ -72,7 +72,7 @@ func NewOVSEndpointClient( } NewInfraVnetClient(client, epInfo.Id[:7]) - NewSnatClient(client, nw.SnatBridgeIP, localIP, epInfo) + client.NewSnatClient(nw.SnatBridgeIP, localIP, epInfo) return client } @@ -91,7 +91,7 @@ func (client *OVSEndpointClient) AddEndpoints(epInfo *EndpointInfo) error { client.containerMac = containerIf.HardwareAddr.String() - if err := AddSnatEndpoint(client); err != nil { + if err := client.AddSnatEndpoint(); err != nil { return err } @@ -149,7 +149,7 @@ func (client *OVSEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error { return err } - return AddSnatEndpointRules(client) + return client.AddSnatEndpointRules() } func (client *OVSEndpointClient) DeleteEndpointRules(ep *endpoint) { @@ -183,7 +183,7 @@ func (client *OVSEndpointClient) DeleteEndpointRules(ep *endpoint) { log.Printf("[ovs] Deletion of interface %v from bridge %v failed", client.hostVethName, client.bridgeName) } - DeleteSnatEndpointRules(client) + client.DeleteSnatEndpointRules() DeleteInfraVnetEndpointRules(client, ep, hostPort) } @@ -194,7 +194,7 @@ func (client *OVSEndpointClient) MoveEndpointsToContainerNS(epInfo *EndpointInfo return err } - if err := MoveSnatEndpointToContainerNS(client, epInfo.NetNsPath, nsID); err != nil { + if err := client.MoveSnatEndpointToContainerNS(epInfo.NetNsPath, nsID); err != nil { return err } @@ -209,7 +209,7 @@ func (client *OVSEndpointClient) SetupContainerInterfaces(epInfo *EndpointInfo) client.containerVethName = epInfo.IfName - if err := SetupSnatContainerInterface(client); err != nil { + if err := client.SetupSnatContainerInterface(); err != nil { return err } @@ -222,7 +222,7 @@ func (client *OVSEndpointClient) ConfigureContainerInterfacesAndRoutes(epInfo *E return err } - if err := ConfigureSnatContainerInterface(client); err != nil { + if err := client.ConfigureSnatContainerInterface(); err != nil { return err } @@ -241,6 +241,8 @@ func (client *OVSEndpointClient) DeleteEndpoints(ep *endpoint) error { return err } - DeleteSnatEndpoint(client) + if err := client.DeleteSnatEndpoint(); err != nil { + return err + } return DeleteInfraVnetEndpoint(client, ep.Id[:7]) } diff --git a/network/ovssnat/ovssnat_linux.go b/network/snat/snat_linux.go similarity index 73% rename from network/ovssnat/ovssnat_linux.go rename to network/snat/snat_linux.go index 60c531fc67..b11009baa3 100644 --- a/network/ovssnat/ovssnat_linux.go +++ b/network/snat/snat_linux.go @@ -1,7 +1,7 @@ // Copyright 2017 Microsoft. All rights reserved. // MIT License -package ovssnat +package snat import ( "errors" @@ -14,13 +14,10 @@ import ( "github.com/Azure/azure-container-networking/log" "github.com/Azure/azure-container-networking/netlink" "github.com/Azure/azure-container-networking/network/networkutils" - "github.com/Azure/azure-container-networking/ovsctl" "github.com/Azure/azure-container-networking/platform" ) const ( - azureSnatVeth0 = "azSnatveth0" - azureSnatVeth1 = "azSnatveth1" azureSnatIfName = "eth1" SnatBridgeName = "azSnatbr" ImdsIP = "169.254.169.254/32" @@ -30,22 +27,22 @@ const ( l2PreroutingEntries = "ebtables -t nat -L PREROUTING" ) -var errorOVSSnatClient = errors.New("OVSSnatClient Error") +var errorSnatClient = errors.New("SnatClient Error") -func newErrorOVSSnatClient(errStr string) error { - return fmt.Errorf("%w : %s", errorOVSSnatClient, errStr) +func newErrorSnatClient(errStr string) error { + return fmt.Errorf("%w : %s", errorSnatClient, errStr) } -type OVSSnatClient struct { +type Client struct { hostSnatVethName string hostPrimaryMac string containerSnatVethName string localIP string - snatBridgeIP string + SnatBridgeIP string SkipAddressesFromBlock []string netlink netlink.NetlinkInterface - ovsctlClient ovsctl.OvsInterface - plClient platform.ExecClient + + plClient platform.ExecClient } func NewSnatClient(hostIfName string, @@ -55,19 +52,19 @@ func NewSnatClient(hostIfName string, hostPrimaryMac string, skipAddressesFromBlock []string, nl netlink.NetlinkInterface, - ovsctlClient ovsctl.OvsInterface, + plClient platform.ExecClient, -) OVSSnatClient { +) Client { log.Printf("Initialize new snat client") - snatClient := OVSSnatClient{ + snatClient := Client{ hostSnatVethName: hostIfName, containerSnatVethName: contIfName, localIP: localIP, - snatBridgeIP: snatBridgeIP, + SnatBridgeIP: snatBridgeIP, hostPrimaryMac: hostPrimaryMac, netlink: nl, - ovsctlClient: ovsctlClient, - plClient: plClient, + + plClient: plClient, } snatClient.SkipAddressesFromBlock = append(snatClient.SkipAddressesFromBlock, skipAddressesFromBlock...) @@ -77,15 +74,15 @@ func NewSnatClient(hostIfName string, return snatClient } -func (client *OVSSnatClient) CreateSnatEndpoint(bridgeName string) error { +func (client *Client) CreateSnatEndpoint() error { // Create linux Bridge for outbound connectivity - if err := client.createSnatBridge(client.snatBridgeIP, client.hostPrimaryMac, bridgeName); err != nil { + if err := client.createSnatBridge(client.SnatBridgeIP, client.hostPrimaryMac); err != nil { log.Printf("creating snat bridge failed with error %v", err) return err } // SNAT Rule to masquerade packets destined to non-vnet ip - if err := client.addMasqueradeRule(client.snatBridgeIP); err != nil { + if err := client.addMasqueradeRule(client.SnatBridgeIP); err != nil { log.Printf("Adding snat rule failed with error %v", err) return err } @@ -100,31 +97,31 @@ func (client *OVSSnatClient) CreateSnatEndpoint(bridgeName string) error { // Create veth pair to tie one end to container and other end to linux bridge if err := epc.CreateEndpoint(client.hostSnatVethName, client.containerSnatVethName); err != nil { log.Printf("Creating Snat Endpoint failed with error %v", err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } err := client.netlink.SetLinkMaster(client.hostSnatVethName, SnatBridgeName) if err != nil { - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } return nil } // AllowIPAddressesOnSnatBridge adds iptables rules that allows only specific Private IPs via linux bridge -func (client *OVSSnatClient) AllowIPAddressesOnSnatBridge() error { +func (client *Client) AllowIPAddressesOnSnatBridge() error { if err := networkutils.AllowIPAddresses(SnatBridgeName, client.SkipAddressesFromBlock, iptables.Insert); err != nil { log.Printf("AllowIPAddresses failed with error %v", err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } return nil } // BlockIPAddressesOnSnatBridge adds iptables rules that blocks all private IPs flowing via linux bridge -func (client *OVSSnatClient) BlockIPAddressesOnSnatBridge() error { +func (client *Client) BlockIPAddressesOnSnatBridge() error { if err := networkutils.BlockIPAddresses(SnatBridgeName, iptables.Append); err != nil { log.Printf("AllowIPAddresses failed with error %v", err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } return nil @@ -133,11 +130,11 @@ func (client *OVSSnatClient) BlockIPAddressesOnSnatBridge() error { /** Move container veth inside container network namespace **/ -func (client *OVSSnatClient) MoveSnatEndpointToContainerNS(netnsPath string, nsID uintptr) error { - log.Printf("[ovs] Setting link %v netns %v.", client.containerSnatVethName, netnsPath) +func (client *Client) MoveSnatEndpointToContainerNS(netnsPath string, nsID uintptr) error { + log.Printf("[snat] Setting link %v netns %v.", client.containerSnatVethName, netnsPath) err := client.netlink.SetLinkNetNs(client.containerSnatVethName, nsID) if err != nil { - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } return nil } @@ -145,10 +142,10 @@ func (client *OVSSnatClient) MoveSnatEndpointToContainerNS(netnsPath string, nsI /** Configure Routes and setup name for container veth **/ -func (client *OVSSnatClient) SetupSnatContainerInterface() error { +func (client *Client) SetupSnatContainerInterface() error { epc := networkutils.NewNetworkUtils(client.netlink, client.plClient) if err := epc.SetupContainerInterface(client.containerSnatVethName, azureSnatIfName); err != nil { - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } client.containerSnatVethName = azureSnatIfName @@ -156,8 +153,8 @@ func (client *OVSSnatClient) SetupSnatContainerInterface() error { return nil } -func getNCLocalAndGatewayIP(client *OVSSnatClient) (net.IP, net.IP) { - bridgeIP, _, _ := net.ParseCIDR(client.snatBridgeIP) +func getNCLocalAndGatewayIP(client *Client) (brIP, contIP net.IP) { + bridgeIP, _, _ := net.ParseCIDR(client.SnatBridgeIP) containerIP, _, _ := net.ParseCIDR(client.localIP) return bridgeIP, containerIP } @@ -165,19 +162,19 @@ func getNCLocalAndGatewayIP(client *OVSSnatClient) (net.IP, net.IP) { /** This function adds iptables rules that allows only host to NC communication and not the other way **/ -func (client *OVSSnatClient) AllowInboundFromHostToNC() error { +func (client *Client) AllowInboundFromHostToNC() error { bridgeIP, containerIP := getNCLocalAndGatewayIP(client) - // Create CNI Ouptut chain + // Create CNI Output chain if err := iptables.CreateChain(iptables.V4, iptables.Filter, iptables.CNIOutputChain); err != nil { log.Printf("AllowInboundFromHostToNC: Creating %v failed with error: %v", iptables.CNIOutputChain, err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } // Forward traffic from Ouptut chain to CNI Output chain if err := iptables.InsertIptableRule(iptables.V4, iptables.Filter, iptables.Output, "", iptables.CNIOutputChain); err != nil { log.Printf("AllowInboundFromHostToNC: Inserting forward rule to %v failed with error: %v", iptables.CNIOutputChain, err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } // Allow connection from Host to NC @@ -185,19 +182,19 @@ func (client *OVSSnatClient) AllowInboundFromHostToNC() error { err := iptables.InsertIptableRule(iptables.V4, iptables.Filter, iptables.CNIOutputChain, matchCondition, iptables.Accept) if err != nil { log.Printf("AllowInboundFromHostToNC: Inserting output rule failed: %v", err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } // Create cniinput chain if err := iptables.CreateChain(iptables.V4, iptables.Filter, iptables.CNIInputChain); err != nil { log.Printf("AllowInboundFromHostToNC: Creating %v failed with error: %v", iptables.CNIInputChain, err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } // Forward from Input to cniinput chain if err := iptables.InsertIptableRule(iptables.V4, iptables.Filter, iptables.Input, "", iptables.CNIInputChain); err != nil { log.Printf("AllowInboundFromHostToNC: Inserting forward rule to %v failed with error: %v", iptables.CNIInputChain, err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } // Accept packets from NC only if established connection @@ -205,7 +202,7 @@ func (client *OVSSnatClient) AllowInboundFromHostToNC() error { err = iptables.InsertIptableRule(iptables.V4, iptables.Filter, iptables.CNIInputChain, matchCondition, iptables.Accept) if err != nil { log.Printf("AllowInboundFromHostToNC: Inserting input rule failed: %v", err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } snatContainerVeth, _ := net.InterfaceByName(client.containerSnatVethName) @@ -215,13 +212,13 @@ func (client *OVSSnatClient) AllowInboundFromHostToNC() error { err = client.netlink.AddOrRemoveStaticArp(netlink.ADD, SnatBridgeName, containerIP, snatContainerVeth.HardwareAddr, false) if err != nil { log.Printf("AllowInboundFromHostToNC: Error adding static arp entry for ip %s mac %s: %v", containerIP, snatContainerVeth.HardwareAddr.String(), err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } return nil } -func (client *OVSSnatClient) DeleteInboundFromHostToNC() error { +func (client *Client) DeleteInboundFromHostToNC() error { bridgeIP, containerIP := getNCLocalAndGatewayIP(client) // Delete allow connection from Host to NC @@ -244,7 +241,7 @@ func (client *OVSSnatClient) DeleteInboundFromHostToNC() error { /** This function adds iptables rules that allows only NC to Host communication and not the other way **/ -func (client *OVSSnatClient) AllowInboundFromNCToHost() error { +func (client *Client) AllowInboundFromNCToHost() error { bridgeIP, containerIP := getNCLocalAndGatewayIP(client) // Create CNI Input chain @@ -299,7 +296,7 @@ func (client *OVSSnatClient) AllowInboundFromNCToHost() error { return err } -func (client *OVSSnatClient) DeleteInboundFromNCToHost() error { +func (client *Client) DeleteInboundFromNCToHost() error { bridgeIP, containerIP := getNCLocalAndGatewayIP(client) // Delete allow NC to Host connection @@ -323,28 +320,28 @@ func (client *OVSSnatClient) DeleteInboundFromNCToHost() error { Configures Local IP Address for container Veth **/ -func (client *OVSSnatClient) ConfigureSnatContainerInterface() error { - log.Printf("[ovs] Adding IP address %v to link %v.", client.localIP, client.containerSnatVethName) +func (client *Client) ConfigureSnatContainerInterface() error { + log.Printf("[snat] Adding IP address %v to link %v.", client.localIP, client.containerSnatVethName) ip, intIpAddr, _ := net.ParseCIDR(client.localIP) err := client.netlink.AddIPAddress(client.containerSnatVethName, ip, intIpAddr) if err != nil { - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } return nil } -func (client *OVSSnatClient) DeleteSnatEndpoint() error { - log.Printf("[ovs] Deleting snat veth pair %v.", client.hostSnatVethName) +func (client *Client) DeleteSnatEndpoint() error { + log.Printf("[snat] Deleting snat veth pair %v.", client.hostSnatVethName) err := client.netlink.DeleteLink(client.hostSnatVethName) if err != nil { - log.Printf("[ovs] Failed to delete veth pair %v: %v.", client.hostSnatVethName, err) - return newErrorOVSSnatClient(err.Error()) + log.Printf("[snat] Failed to delete veth pair %v: %v.", client.hostSnatVethName, err) + return newErrorSnatClient(err.Error()) } return nil } -func (client *OVSSnatClient) setBridgeMac(hostPrimaryMac string) error { +func (client *Client) setBridgeMac(hostPrimaryMac string) error { hwAddr, err := net.ParseMAC(hostPrimaryMac) if err != nil { log.Errorf("Error while parsing host primary mac: %s error:%+v", hostPrimaryMac, err) @@ -357,7 +354,7 @@ func (client *OVSSnatClient) setBridgeMac(hostPrimaryMac string) error { return err } -func (client *OVSSnatClient) dropArpForSnatBridgeApipaRange(snatBridgeIP, azSnatVethIfName string) error { +func (client *Client) DropArpForSnatBridgeApipaRange(snatBridgeIP, azSnatVethIfName string) error { var err error _, ipCidr, _ := net.ParseCIDR(snatBridgeIP) if err = ebtables.SetArpDropRuleForIpCidr(ipCidr.String(), azSnatVethIfName); err != nil { @@ -370,7 +367,7 @@ func (client *OVSSnatClient) dropArpForSnatBridgeApipaRange(snatBridgeIP, azSnat /** This function creates linux bridge which will be used for outbound connectivity by NCs **/ -func (client *OVSSnatClient) createSnatBridge(snatBridgeIP string, hostPrimaryMac string, mainInterface string) error { +func (client *Client) createSnatBridge(snatBridgeIP, hostPrimaryMac string) error { _, err := net.InterfaceByName(SnatBridgeName) if err == nil { log.Printf("Snat Bridge already exists") @@ -385,7 +382,7 @@ func (client *OVSSnatClient) createSnatBridge(snatBridgeIP string, hostPrimaryMa } if err := client.netlink.AddLink(&link); err != nil { - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } } @@ -394,76 +391,23 @@ func (client *OVSSnatClient) createSnatBridge(snatBridgeIP string, hostPrimaryMa return err } - log.Printf("Drop ARP for snat bridge ip: %s", snatBridgeIP) - if err := client.dropArpForSnatBridgeApipaRange(snatBridgeIP, azureSnatVeth0); err != nil { - return err - } - - // Create a veth pair. One end of veth will be attached to ovs bridge and other end - // of veth will be attached to linux bridge - _, err = net.InterfaceByName(azureSnatVeth0) - if err == nil { - log.Printf("Azure snat veth already exists") - return nil - } - nuc := networkutils.NewNetworkUtils(client.netlink, client.plClient) //nolint if err = nuc.DisableRAForInterface(SnatBridgeName); err != nil { return err } - vethLink := netlink.VEthLink{ - LinkInfo: netlink.LinkInfo{ - Type: netlink.LINK_TYPE_VETH, - Name: azureSnatVeth0, - }, - PeerName: azureSnatVeth1, - } - - err = client.netlink.AddLink(&vethLink) - if err != nil { - log.Printf("[net] Failed to create veth pair, err:%v.", err) - return err - } - - //nolint - if err = nuc.DisableRAForInterface(azureSnatVeth0); err != nil { - return err - } - - //nolint - if err = nuc.DisableRAForInterface(azureSnatVeth1); err != nil { - return err - } - log.Printf("Assigning %v on snat bridge", snatBridgeIP) ip, addr, _ := net.ParseCIDR(snatBridgeIP) err = client.netlink.AddIPAddress(SnatBridgeName, ip, addr) if err != nil && !strings.Contains(strings.ToLower(err.Error()), "file exists") { log.Printf("[net] Failed to add IP address %v: %v.", addr, err) - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } if err = client.netlink.SetLinkState(SnatBridgeName, true); err != nil { - return newErrorOVSSnatClient(err.Error()) - } - - if err = client.netlink.SetLinkState(azureSnatVeth0, true); err != nil { - return newErrorOVSSnatClient(err.Error()) - } - - if err = client.netlink.SetLinkMaster(azureSnatVeth0, SnatBridgeName); err != nil { - return newErrorOVSSnatClient(err.Error()) - } - - if err = client.netlink.SetLinkState(azureSnatVeth1, true); err != nil { - return newErrorOVSSnatClient(err.Error()) - } - - if err = client.ovsctlClient.AddPortOnOVSBridge(azureSnatVeth1, mainInterface, 0); err != nil { - return newErrorOVSSnatClient(err.Error()) + return newErrorSnatClient(err.Error()) } return nil @@ -472,7 +416,7 @@ func (client *OVSSnatClient) createSnatBridge(snatBridgeIP string, hostPrimaryMa /** This function adds iptable rules that will snat all traffic that has source ip in apipa range and coming via linux bridge **/ -func (client *OVSSnatClient) addMasqueradeRule(snatBridgeIPWithPrefix string) error { +func (client *Client) addMasqueradeRule(snatBridgeIPWithPrefix string) error { _, ipNet, _ := net.ParseCIDR(snatBridgeIPWithPrefix) matchCondition := fmt.Sprintf("-s %s", ipNet.String()) return iptables.InsertIptableRule(iptables.V4, iptables.Nat, iptables.Postrouting, matchCondition, iptables.Masquerade) @@ -481,7 +425,7 @@ func (client *OVSSnatClient) addMasqueradeRule(snatBridgeIPWithPrefix string) er /** Drop all vlan traffic on linux bridge **/ -func (client *OVSSnatClient) addVlanDropRule() error { +func (client *Client) addVlanDropRule() error { out, err := client.plClient.ExecuteCommand(l2PreroutingEntries) if err != nil { log.Printf("Error while listing ebtable rules %v", err) diff --git a/network/ovssnat/ovssnat_linux_test.go b/network/snat/snat_linux_test.go similarity index 90% rename from network/ovssnat/ovssnat_linux_test.go rename to network/snat/snat_linux_test.go index 7717f06306..1838b6aab1 100644 --- a/network/ovssnat/ovssnat_linux_test.go +++ b/network/snat/snat_linux_test.go @@ -1,11 +1,10 @@ -package ovssnat +package snat import ( "os" "testing" "github.com/Azure/azure-container-networking/netlink" - "github.com/Azure/azure-container-networking/ovsctl" ) var anyInterface = "dummy" @@ -20,12 +19,11 @@ func TestMain(m *testing.M) { func TestAllowInboundFromHostToNC(t *testing.T) { nl := netlink.NewNetlink() - client := &OVSSnatClient{ - snatBridgeIP: "169.254.0.1/16", + client := &Client{ + SnatBridgeIP: "169.254.0.1/16", localIP: "169.254.0.4/16", containerSnatVethName: anyInterface, netlink: nl, - ovsctlClient: ovsctl.NewMockOvsctl(false, "", ""), } if err := nl.AddLink(&netlink.DummyLink{ @@ -68,8 +66,8 @@ func TestAllowInboundFromHostToNC(t *testing.T) { func TestAllowInboundFromNCToHost(t *testing.T) { nl := netlink.NewNetlink() - client := &OVSSnatClient{ - snatBridgeIP: "169.254.0.1/16", + client := &Client{ + SnatBridgeIP: "169.254.0.1/16", localIP: "169.254.0.4/16", containerSnatVethName: anyInterface, netlink: nl, diff --git a/network/transparent_vlan_endpoint_snatroute_linux.go b/network/transparent_vlan_endpoint_snatroute_linux.go new file mode 100644 index 0000000000..109f699b35 --- /dev/null +++ b/network/transparent_vlan_endpoint_snatroute_linux.go @@ -0,0 +1,80 @@ +package network + +import ( + "github.com/Azure/azure-container-networking/network/snat" +) + +func (client *TransparentVlanEndpointClient) isSnatEnabled() bool { + return client.enableSnatOnHost || client.allowInboundFromHostToNC || client.allowInboundFromNCToHost || client.enableSnatForDNS +} + +func (client *TransparentVlanEndpointClient) NewSnatClient(snatBridgeIP, localIP string, epInfo *EndpointInfo) { + if client.isSnatEnabled() { + client.snatClient = snat.NewSnatClient( + GetSnatHostIfName(epInfo), + GetSnatContIfName(epInfo), + localIP, + snatBridgeIP, + client.hostPrimaryMac.String(), + epInfo.DNS.Servers, + client.netlink, + client.plClient, + ) + } +} + +func (client *TransparentVlanEndpointClient) AddSnatEndpoint() error { + if client.isSnatEnabled() { + if err := AddSnatEndpoint(&client.snatClient); err != nil { + return err + } + } + return nil +} + +func (client *TransparentVlanEndpointClient) AddSnatEndpointRules() error { + if client.isSnatEnabled() { + // Add route for 169.254.169.54 in host via azure0, otherwise it will route via snat bridge + if err := AddSnatEndpointRules(&client.snatClient, client.allowInboundFromHostToNC, client.allowInboundFromNCToHost, client.netlink, client.plClient); err != nil { + return err + } + } + + return nil +} + +func (client *TransparentVlanEndpointClient) MoveSnatEndpointToContainerNS(netnsPath string, nsID uintptr) error { + if client.isSnatEnabled() { + return MoveSnatEndpointToContainerNS(&client.snatClient, netnsPath, nsID) + } + + return nil +} + +func (client *TransparentVlanEndpointClient) SetupSnatContainerInterface() error { + if client.isSnatEnabled() { + return SetupSnatContainerInterface(&client.snatClient) + } + + return nil +} + +func (client *TransparentVlanEndpointClient) ConfigureSnatContainerInterface() error { + if client.isSnatEnabled() { + return ConfigureSnatContainerInterface(&client.snatClient) + } + + return nil +} + +func (client *TransparentVlanEndpointClient) DeleteSnatEndpoint() error { + if client.isSnatEnabled() { + return DeleteSnatEndpoint(&client.snatClient) + } + + return nil +} + +func (client *TransparentVlanEndpointClient) DeleteSnatEndpointRules() { + DeleteSnatEndpointRules(&client.snatClient, client.allowInboundFromHostToNC, client.allowInboundFromNCToHost) +} diff --git a/network/native_endpointclient_linux.go b/network/transparent_vlan_endpointclient_linux.go similarity index 65% rename from network/native_endpointclient_linux.go rename to network/transparent_vlan_endpointclient_linux.go index 8ddd4b6bec..ba75d5f1ee 100644 --- a/network/native_endpointclient_linux.go +++ b/network/transparent_vlan_endpointclient_linux.go @@ -7,7 +7,9 @@ import ( "github.com/Azure/azure-container-networking/log" "github.com/Azure/azure-container-networking/netio" "github.com/Azure/azure-container-networking/netlink" + "github.com/Azure/azure-container-networking/netns" "github.com/Azure/azure-container-networking/network/networkutils" + "github.com/Azure/azure-container-networking/network/snat" "github.com/Azure/azure-container-networking/platform" "github.com/pkg/errors" vishnetlink "github.com/vishvananda/netlink" @@ -26,34 +28,79 @@ type netnsClient interface { NewNamed(name string) (fileDescriptor int, err error) DeleteNamed(name string) (err error) } -type NativeEndpointClient struct { +type TransparentVlanEndpointClient struct { primaryHostIfName string // So like eth0 vlanIfName string // So like eth0.1 vnetVethName string // Peer is containerVethName containerVethName string // Peer is vnetVethName - vnetMac net.HardwareAddr - containerMac net.HardwareAddr + vnetMac net.HardwareAddr + containerMac net.HardwareAddr + hostPrimaryMac net.HardwareAddr vnetNSName string vnetNSFileDescriptor int - nw *network - vlanID int - netnsClient netnsClient - netlink netlink.NetlinkInterface - netioshim netio.NetIOInterface - plClient platform.ExecClient - netUtilsClient networkutils.NetworkUtils + snatClient snat.Client + vlanID int + enableSnatOnHost bool + allowInboundFromHostToNC bool + allowInboundFromNCToHost bool + enableSnatForDNS bool + netnsClient netnsClient + netlink netlink.NetlinkInterface + netioshim netio.NetIOInterface + plClient platform.ExecClient + netUtilsClient networkutils.NetworkUtils +} + +func NewTransparentVlanEndpointClient( + nw *network, + ep *EndpointInfo, + vnetVethName string, + containerVethName string, + vlanid int, + localIP string, + nl netlink.NetlinkInterface, + plc platform.ExecClient, +) *TransparentVlanEndpointClient { + vlanVethName := fmt.Sprintf("%s_%d", nw.extIf.Name, vlanid) + vnetNSName := fmt.Sprintf("az_ns_%d", vlanid) + + client := &TransparentVlanEndpointClient{ + primaryHostIfName: nw.extIf.Name, + vlanIfName: vlanVethName, + vnetVethName: vnetVethName, + hostPrimaryMac: nw.extIf.MacAddress, + containerVethName: containerVethName, + vnetNSName: vnetNSName, + vlanID: vlanid, + enableSnatOnHost: ep.EnableSnatOnHost, + allowInboundFromHostToNC: ep.AllowInboundFromHostToNC, + allowInboundFromNCToHost: ep.AllowInboundFromNCToHost, + enableSnatForDNS: ep.EnableSnatForDns, + netnsClient: netns.New(), + netlink: nl, + netioshim: &netio.NetIO{}, + plClient: plc, + netUtilsClient: networkutils.NewNetworkUtils(nl, plc), + } + + client.NewSnatClient(nw.SnatBridgeIP, localIP, ep) + + return client } // Adds interfaces to the vnet (created if not existing) and vm namespace -func (client *NativeEndpointClient) AddEndpoints(epInfo *EndpointInfo) error { +func (client *TransparentVlanEndpointClient) AddEndpoints(epInfo *EndpointInfo) error { // VM Namespace err := client.PopulateVM(epInfo) if err != nil { return err } + if err := client.AddSnatEndpoint(); err != nil { + return errors.Wrap(err, "failed to add snat endpoint") + } // VNET Namespace return ExecuteInNS(client.vnetNSName, func() error { return client.PopulateVnet(epInfo) @@ -61,19 +108,19 @@ func (client *NativeEndpointClient) AddEndpoints(epInfo *EndpointInfo) error { } // Called from AddEndpoints, Namespace: VM -func (client *NativeEndpointClient) PopulateVM(epInfo *EndpointInfo) error { +func (client *TransparentVlanEndpointClient) PopulateVM(epInfo *EndpointInfo) error { vmNS, err := client.netnsClient.Get() if err != nil { return errors.Wrap(err, "failed to get vm ns handle") } - log.Printf("[native] Checking if NS exists...") + log.Printf("[transparent vlan] Checking if NS exists...") vnetNS, existingErr := client.netnsClient.GetFromName(client.vnetNSName) // If the ns does not exist, the below code will trigger to create it // This will also (we assume) mean the vlan veth does not exist if existingErr != nil { // We assume the only possible error is that the namespace doesn't exist - log.Printf("[native] No existing NS detected. Creating the vnet namespace and switching to it") + log.Printf("[transparent vlan] No existing NS detected. Creating the vnet namespace and switching to it") vnetNS, err = client.netnsClient.NewNamed(client.vnetNSName) if err != nil { return errors.Wrap(err, "failed to create vnet ns") @@ -83,7 +130,7 @@ func (client *NativeEndpointClient) PopulateVM(epInfo *EndpointInfo) error { // Any failure will trigger removing the namespace created defer func() { if deleteNSIfNotNilErr != nil { - log.Logf("[native] Removing vnet ns due to failure...") + log.Logf("[transparent vlan] removing vnet ns due to failure...") err = client.netnsClient.DeleteNamed(client.vnetNSName) if err != nil { log.Errorf("failed to cleanup/delete ns after failing to create vlan veth") @@ -95,7 +142,7 @@ func (client *NativeEndpointClient) PopulateVM(epInfo *EndpointInfo) error { } // Now create vlan veth - log.Printf("[native] Create the host vlan link after getting eth0: %s", client.primaryHostIfName) + log.Printf("[transparent vlan] Create the host vlan link after getting eth0: %s", client.primaryHostIfName) // Get parent interface index. Index is consistent across libraries. eth0, deleteNSIfNotNilErr := client.netioshim.GetNetworkInterfaceByName(client.primaryHostIfName) if deleteNSIfNotNilErr != nil { @@ -109,30 +156,52 @@ func (client *NativeEndpointClient) PopulateVM(epInfo *EndpointInfo) error { LinkAttrs: linkAttrs, VlanId: client.vlanID, } - log.Printf("[native] Attempting to create %s link in VM NS", client.vlanIfName) + log.Printf("[transparent vlan] Attempting to create %s link in VM NS", client.vlanIfName) // Create vlan veth deleteNSIfNotNilErr = vishnetlink.LinkAdd(link) if deleteNSIfNotNilErr != nil { // Any failure to add the link should error (auto delete NS) return errors.Wrap(deleteNSIfNotNilErr, "failed to create vlan vnet link after making new ns") } + defer func() { + if deleteNSIfNotNilErr != nil { + log.Logf("[transparent vlan] removing vlan veth due to failure...") + if delErr := client.netlink.DeleteLink(client.vlanIfName); delErr != nil { + log.Errorf("deleting vlan veth failed on addendpoint failure") + } + } + }() + deleteNSIfNotNilErr = client.netUtilsClient.DisableRAForInterface(client.vlanIfName) + if deleteNSIfNotNilErr != nil { + return errors.Wrap(deleteNSIfNotNilErr, "failed to disable router advertisements for vlan vnet link") + } // vlan veth was created successfully, so move the vlan veth you created - log.Printf("[native] Move vlan link (%s) to vnet NS: %d", client.vlanIfName, uintptr(client.vnetNSFileDescriptor)) + log.Printf("[transparent vlan] Move vlan link (%s) to vnet NS: %d", client.vlanIfName, uintptr(client.vnetNSFileDescriptor)) deleteNSIfNotNilErr = client.netlink.SetLinkNetNs(client.vlanIfName, uintptr(client.vnetNSFileDescriptor)) if deleteNSIfNotNilErr != nil { - if delErr := client.netlink.DeleteLink(client.vlanIfName); delErr != nil { - log.Errorf("deleting vlan veth failed on addendpoint failure") - } return errors.Wrap(deleteNSIfNotNilErr, "deleting vlan veth in vm ns due to addendpoint failure") } } else { - log.Printf("[native] Existing NS (%s) detected. Assuming %s exists too", client.vnetNSName, client.vlanIfName) + log.Printf("[transparent vlan] Existing NS (%s) detected. Assuming %s exists too", client.vnetNSName, client.vlanIfName) } client.vnetNSFileDescriptor = vnetNS if err = client.netUtilsClient.CreateEndpoint(client.vnetVethName, client.containerVethName); err != nil { return errors.Wrap(err, "failed to create veth pair") } + // Disable RA for veth pair, and delete if any failure + if err = client.netUtilsClient.DisableRAForInterface(client.vnetVethName); err != nil { + if delErr := client.netlink.DeleteLink(client.vnetVethName); delErr != nil { + log.Errorf("Deleting vnet veth failed on addendpoint failure:%v", delErr) + } + return errors.Wrap(err, "failed to disable RA on vnet veth, deleting") + } + if err = client.netUtilsClient.DisableRAForInterface(client.containerVethName); err != nil { + if delErr := client.netlink.DeleteLink(client.containerVethName); delErr != nil { + log.Errorf("Deleting container veth failed on addendpoint failure:%v", delErr) + } + return errors.Wrap(err, "failed to disable RA on container veth, deleting") + } if err = client.netlink.SetLinkNetNs(client.vnetVethName, uintptr(client.vnetNSFileDescriptor)); err != nil { if delErr := client.netlink.DeleteLink(client.vnetVethName); delErr != nil { @@ -150,7 +219,7 @@ func (client *NativeEndpointClient) PopulateVM(epInfo *EndpointInfo) error { } // Called from AddEndpoints, Namespace: Vnet -func (client *NativeEndpointClient) PopulateVnet(epInfo *EndpointInfo) error { +func (client *TransparentVlanEndpointClient) PopulateVnet(epInfo *EndpointInfo) error { _, err := client.netioshim.GetNetworkInterfaceByName(client.vlanIfName) if err != nil { return errors.Wrap(err, "vlan veth doesn't exist") @@ -163,35 +232,41 @@ func (client *NativeEndpointClient) PopulateVnet(epInfo *EndpointInfo) error { return nil } -func (client *NativeEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error { - // There are no rules to add here - // Described as rules on ip addresses on the container interface - +func (client *TransparentVlanEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error { + if err := client.AddSnatEndpointRules(); err != nil { + return errors.Wrap(err, "failed to add snat endpoint rules") + } return nil } -func (client *NativeEndpointClient) DeleteEndpointRules(ep *endpoint) { - // Never added any endpoint rules +func (client *TransparentVlanEndpointClient) DeleteEndpointRules(ep *endpoint) { + client.DeleteSnatEndpointRules() } -func (client *NativeEndpointClient) MoveEndpointsToContainerNS(epInfo *EndpointInfo, nsID uintptr) error { +func (client *TransparentVlanEndpointClient) MoveEndpointsToContainerNS(epInfo *EndpointInfo, nsID uintptr) error { if err := client.netlink.SetLinkNetNs(client.containerVethName, nsID); err != nil { return errors.Wrap(err, "failed to move endpoint to container ns") } + if err := client.MoveSnatEndpointToContainerNS(epInfo.NetNsPath, nsID); err != nil { + return errors.Wrap(err, "failed to move snat endpoint to container ns") + } return nil } -func (client *NativeEndpointClient) SetupContainerInterfaces(epInfo *EndpointInfo) error { +func (client *TransparentVlanEndpointClient) SetupContainerInterfaces(epInfo *EndpointInfo) error { if err := client.netUtilsClient.SetupContainerInterface(client.containerVethName, epInfo.IfName); err != nil { return errors.Wrap(err, "failed to setup container interface") } client.containerVethName = epInfo.IfName + if err := client.SetupSnatContainerInterface(); err != nil { + return errors.Wrap(err, "failed to setup snat container interface") + } return nil } // Adds routes, arp entries, etc. to the vnet and container namespaces -func (client *NativeEndpointClient) ConfigureContainerInterfacesAndRoutes(epInfo *EndpointInfo) error { +func (client *TransparentVlanEndpointClient) ConfigureContainerInterfacesAndRoutes(epInfo *EndpointInfo) error { // Container NS err := client.ConfigureContainerInterfacesAndRoutesImpl(epInfo) if err != nil { @@ -199,13 +274,22 @@ func (client *NativeEndpointClient) ConfigureContainerInterfacesAndRoutes(epInfo } // Switch to vnet NS and call ConfigureVnetInterfacesAndRoutes - return ExecuteInNS(client.vnetNSName, func() error { + err = ExecuteInNS(client.vnetNSName, func() error { return client.ConfigureVnetInterfacesAndRoutesImpl(epInfo) }) + if err != nil { + return err + } + + // Container NS + if err = client.ConfigureSnatContainerInterface(); err != nil { + return errors.Wrap(err, "failed to configure snat container interface") + } + return nil } // Called from ConfigureContainerInterfacesAndRoutes, Namespace: Container -func (client *NativeEndpointClient) ConfigureContainerInterfacesAndRoutesImpl(epInfo *EndpointInfo) error { +func (client *TransparentVlanEndpointClient) ConfigureContainerInterfacesAndRoutesImpl(epInfo *EndpointInfo) error { if err := client.netUtilsClient.AssignIPToInterface(client.containerVethName, epInfo.IPAddresses); err != nil { return errors.Wrap(err, "failed to assign ips to container veth interface") } @@ -232,7 +316,7 @@ func (client *NativeEndpointClient) ConfigureContainerInterfacesAndRoutesImpl(ep } // Called from ConfigureContainerInterfacesAndRoutes, Namespace: Vnet -func (client *NativeEndpointClient) ConfigureVnetInterfacesAndRoutesImpl(epInfo *EndpointInfo) error { +func (client *TransparentVlanEndpointClient) ConfigureVnetInterfacesAndRoutesImpl(epInfo *EndpointInfo) error { err := client.netlink.SetLinkState(loopbackIf, true) if err != nil { return errors.Wrap(err, "failed to set loopback link state to up") @@ -256,7 +340,7 @@ func (client *NativeEndpointClient) ConfigureVnetInterfacesAndRoutesImpl(epInfo // Helper that gets the routes in the vnet NS for a particular list of IP addresses // Example: 192.168.0.4 dev proto static -func (client *NativeEndpointClient) GetVnetRoutes(ipAddresses []net.IPNet) []RouteInfo { +func (client *TransparentVlanEndpointClient) GetVnetRoutes(ipAddresses []net.IPNet) []RouteInfo { routeInfoList := make([]RouteInfo, 0, len(ipAddresses)) // Add route specifying which device the pod ip(s) are on for _, ipAddr := range ipAddresses { @@ -270,7 +354,7 @@ func (client *NativeEndpointClient) GetVnetRoutes(ipAddresses []net.IPNet) []Rou } else { ipNet = net.IPNet{IP: ipAddr.IP, Mask: net.CIDRMask(ipv6FullMask, ipv6Bits)} } - log.Printf("[net] Native client adding route for the ip %v", ipNet.String()) + log.Printf("[net] transparent vlan client adding route for the ip %v", ipNet.String()) routeInfo.Dst = ipNet routeInfoList = append(routeInfoList, routeInfo) @@ -282,7 +366,7 @@ func (client *NativeEndpointClient) GetVnetRoutes(ipAddresses []net.IPNet) []Rou // to the virtual gateway ip on linkToName device interface // Route 1: 169.254.1.1 dev // Route 2: default via 169.254.1.1 dev -func (client *NativeEndpointClient) AddDefaultRoutes(linkToName string) error { +func (client *TransparentVlanEndpointClient) AddDefaultRoutes(linkToName string) error { // Add route for virtualgwip (ip route add 169.254.1.1/32 dev eth0) virtualGwIP, virtualGwNet, _ := net.ParseCIDR(virtualGwIPString) routeInfo := RouteInfo{ @@ -311,7 +395,7 @@ func (client *NativeEndpointClient) AddDefaultRoutes(linkToName string) error { // Helper that creates arp entry for the current NS which maps the virtual // gateway (169.254.1.1) to destMac on a particular interfaceName // Example: (169.254.1.1) at 12:34:56:78:9a:bc [ether] PERM on -func (client *NativeEndpointClient) AddDefaultArp(interfaceName, destMac string) error { +func (client *TransparentVlanEndpointClient) AddDefaultArp(interfaceName, destMac string) error { _, virtualGwNet, _ := net.ParseCIDR(virtualGwIPString) log.Printf("[net] Adding static arp for IP address %v and MAC %v in namespace", virtualGwNet.String(), destMac) @@ -325,8 +409,9 @@ func (client *NativeEndpointClient) AddDefaultArp(interfaceName, destMac string) return nil } -func (client *NativeEndpointClient) DeleteEndpoints(ep *endpoint) error { - return ExecuteInNS(client.vnetNSName, func() error { +func (client *TransparentVlanEndpointClient) DeleteEndpoints(ep *endpoint) error { + // Vnet NS + err := ExecuteInNS(client.vnetNSName, func() error { // Passing in functionality to get number of routes after deletion getNumRoutesLeft := func() (int, error) { routes, err := vishnetlink.RouteList(nil, vishnetlink.FAMILY_V4) @@ -338,10 +423,19 @@ func (client *NativeEndpointClient) DeleteEndpoints(ep *endpoint) error { return client.DeleteEndpointsImpl(ep, getNumRoutesLeft) }) + if err != nil { + return err + } + + // VM NS + if err := client.DeleteSnatEndpoint(); err != nil { + return errors.Wrap(err, "failed to delete snat endpoint") + } + return nil } // getNumRoutesLeft is a function which gets the current number of routes in the namespace. Namespace: Vnet -func (client *NativeEndpointClient) DeleteEndpointsImpl(ep *endpoint, getNumRoutesLeft func() (int, error)) error { +func (client *TransparentVlanEndpointClient) DeleteEndpointsImpl(ep *endpoint, getNumRoutesLeft func() (int, error)) error { routeInfoList := client.GetVnetRoutes(ep.IPAddresses) if err := deleteRoutes(client.netlink, client.netioshim, client.vnetVethName, routeInfoList); err != nil { return errors.Wrap(err, "failed to remove routes") @@ -352,12 +446,12 @@ func (client *NativeEndpointClient) DeleteEndpointsImpl(ep *endpoint, getNumRout return err } - log.Printf("[native] There are %d routes remaining after deletion", routesLeft) + log.Printf("[transparent vlan] There are %d routes remaining after deletion", routesLeft) if routesLeft <= numDefaultRoutes { // Deletes default arp, default routes, vlan veth; there are two default routes // so when we have <= numDefaultRoutes routes left, no containers use this namespace - log.Printf("[native] Deleting namespace %s as no containers occupy it", client.vnetNSName) + log.Printf("[transparent vlan] Deleting namespace %s as no containers occupy it", client.vnetNSName) delErr := client.netnsClient.DeleteNamed(client.vnetNSName) if delErr != nil { return errors.Wrap(delErr, "failed to delete namespace") diff --git a/network/native_endpointclient_linux_test.go b/network/transparent_vlan_endpointclient_linux_test.go similarity index 94% rename from network/native_endpointclient_linux_test.go rename to network/transparent_vlan_endpointclient_linux_test.go index ab81ca6041..61fbf8cc78 100644 --- a/network/native_endpointclient_linux_test.go +++ b/network/transparent_vlan_endpointclient_linux_test.go @@ -69,13 +69,13 @@ func defaultDeleteNamed(name string) error { return nil } -func TestNativeAddEndpoints(t *testing.T) { +func TestTransparentVlanAddEndpoints(t *testing.T) { nl := netlink.NewMockNetlink(false, "") plc := platform.NewMockExecClient(false) tests := []struct { name string - client *NativeEndpointClient + client *TransparentVlanEndpointClient epInfo *EndpointInfo wantErr bool wantErrMsg string @@ -83,7 +83,7 @@ func TestNativeAddEndpoints(t *testing.T) { // Populating VM with data and creating interfaces/links { name: "Add endpoints create vnet ns failure", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -109,7 +109,7 @@ func TestNativeAddEndpoints(t *testing.T) { }, { name: "Add endpoints with existing vnet ns", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -132,7 +132,7 @@ func TestNativeAddEndpoints(t *testing.T) { }, { name: "Add endpoints netlink fail", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -156,7 +156,7 @@ func TestNativeAddEndpoints(t *testing.T) { }, { name: "Add endpoints get interface fail for primary interface (eth0)", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -182,7 +182,7 @@ func TestNativeAddEndpoints(t *testing.T) { }, { name: "Add endpoints get interface fail for getting container veth", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -206,7 +206,7 @@ func TestNativeAddEndpoints(t *testing.T) { }, { name: "Add endpoints NetNS Get fail", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -228,7 +228,7 @@ func TestNativeAddEndpoints(t *testing.T) { }, { name: "Add endpoints NetNS Set fail", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -271,7 +271,7 @@ func TestNativeAddEndpoints(t *testing.T) { tests = []struct { name string - client *NativeEndpointClient + client *TransparentVlanEndpointClient epInfo *EndpointInfo wantErr bool wantErrMsg string @@ -279,7 +279,7 @@ func TestNativeAddEndpoints(t *testing.T) { // Populate the client with information from the vnet and set up vnet { name: "Add endpoints get vnet veth mac address", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -295,7 +295,7 @@ func TestNativeAddEndpoints(t *testing.T) { }, { name: "Add endpoints fail check vlan veth exists", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -312,7 +312,7 @@ func TestNativeAddEndpoints(t *testing.T) { }, { name: "Add endpoints fail check vnet veth exists", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -343,7 +343,7 @@ func TestNativeAddEndpoints(t *testing.T) { } } -func TestNativeDeleteEndpoints(t *testing.T) { +func TestTransparentVlanDeleteEndpoints(t *testing.T) { nl := netlink.NewMockNetlink(false, "") plc := platform.NewMockExecClient(false) IPAddresses := []net.IPNet{ @@ -359,7 +359,7 @@ func TestNativeDeleteEndpoints(t *testing.T) { tests := []struct { name string - client *NativeEndpointClient + client *TransparentVlanEndpointClient ep *endpoint wantErr bool wantErrMsg string @@ -367,7 +367,7 @@ func TestNativeDeleteEndpoints(t *testing.T) { }{ { name: "Delete endpoint delete vnet ns", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -391,7 +391,7 @@ func TestNativeDeleteEndpoints(t *testing.T) { }, { name: "Delete endpoint do not delete vnet ns it is still in use", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -417,7 +417,7 @@ func TestNativeDeleteEndpoints(t *testing.T) { }, { name: "Delete endpoint fail to delete namespace", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -458,7 +458,7 @@ func TestNativeDeleteEndpoints(t *testing.T) { } } -func TestNativeConfigureContainerInterfacesAndRoutes(t *testing.T) { +func TestTransparentVlanConfigureContainerInterfacesAndRoutes(t *testing.T) { nl := netlink.NewMockNetlink(false, "") plc := platform.NewMockExecClient(false) @@ -466,14 +466,14 @@ func TestNativeConfigureContainerInterfacesAndRoutes(t *testing.T) { tests := []struct { name string - client *NativeEndpointClient + client *TransparentVlanEndpointClient epInfo *EndpointInfo wantErr bool wantErrMsg string }{ { name: "Configure interface and routes good path for container", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -497,7 +497,7 @@ func TestNativeConfigureContainerInterfacesAndRoutes(t *testing.T) { }, { name: "Configure interface and routes multiple IPs", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -529,7 +529,7 @@ func TestNativeConfigureContainerInterfacesAndRoutes(t *testing.T) { }, { name: "Configure interface and routes assign ip fail", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -554,7 +554,7 @@ func TestNativeConfigureContainerInterfacesAndRoutes(t *testing.T) { }, { name: "Configure interface and routes container 2nd default route added fail", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -593,14 +593,14 @@ func TestNativeConfigureContainerInterfacesAndRoutes(t *testing.T) { } tests = []struct { name string - client *NativeEndpointClient + client *TransparentVlanEndpointClient epInfo *EndpointInfo wantErr bool wantErrMsg string }{ { name: "Configure interface and routes good path for vnet", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0", @@ -625,7 +625,7 @@ func TestNativeConfigureContainerInterfacesAndRoutes(t *testing.T) { { // fail route that tells which device container ip is on for vnet name: "Configure interface and routes fail final routes for vnet", - client: &NativeEndpointClient{ + client: &TransparentVlanEndpointClient{ primaryHostIfName: "eth0", vlanIfName: "eth0.1", vnetVethName: "A1veth0",