cns/hnsclient/hnsclient_windows.go (554 lines of code) (raw):
package hnsclient
import (
"encoding/json"
"fmt"
"net"
"strconv"
"strings"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/networkcontainers"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/network/policy"
"github.com/Microsoft/hcsshim"
"github.com/Microsoft/hcsshim/hcn"
"github.com/pkg/errors"
)
// TODO redesign hnsclient on windows
const (
// Name of the external hns network
ExtHnsNetworkName = "ext"
// Address prefix for external hns network
ExtHnsNetworkAddressPrefix = "192.168.255.0/30"
// Gateway address for external hns network
ExtHnsNetworkGwAddress = "192.168.255.1"
// HNS network types
hnsL2Bridge = "l2bridge"
// hcnSchemaVersionMajor indicates major version number for hcn schema
hcnSchemaVersionMajor = 2
// hcnSchemaVersionMinor indicates minor version number for hcn schema
hcnSchemaVersionMinor = 0
// hcnIpamTypeStatic indicates the static type of ipam
hcnIpamTypeStatic = "Static"
// hostNCApipaNetworkName indicates the name of the apipa network used for host container connectivity
hostNCApipaNetworkName = "HostNCApipaNetwork"
// hostNCApipaNetworkType indicates the type of hns network set up for host NC connectivity
hostNCApipaNetworkType = hcn.L2Bridge
// hostNCApipaEndpointName indicates the prefix for the name of the apipa endpoint used for
// the host container connectivity
hostNCApipaEndpointNamePrefix = "HostNCApipaEndpoint"
// Name of the loopback adapter needed to create Host NC apipa network
hostNCLoopbackAdapterName = "LoopbackAdapterHostNCConnectivity"
// HNS rehydration issue requires this GW to be different than the loopback adapter ip, so we set it to .2
defaultHnsGwIPAddress = "169.254.128.2"
hnsLoopbackAdapterIPAddress = "169.254.128.1"
// protocolTCP indicates the TCP protocol identifier in HCN
protocolTCP = "6"
// protocolUDP indicates the UDP protocol identifier in HCN
protocolUDP = "17"
// protocolICMPv4 indicates the ICMPv4 protocol identifier in HCN
protocolICMPv4 = "1"
// aclPriority2000 indicates the ACL priority of 2000
aclPriority2000 = 2000
// aclPriority200 indicates the ACL priority of 200
aclPriority200 = 200
// aclPriority1000 indicates the ACL priority of 1000
aclPriority1000 = 1000
// aclPolicyType indicates a ACL policy
aclPolicyType = "ACLPolicy"
// signals a APIPA endpoint type
apipaEndpointType = "APIPA"
// default network name used by HNS
defaultNetworkName = "azure"
)
// Named Lock for network and endpoint creation/deletion
var namedLock = common.InitNamedLock()
// CreateHnsNetwork creates the HNS network with the provided configuration
func CreateHnsNetwork(nwConfig cns.CreateHnsNetworkRequest) error {
logger.Printf("[Azure CNS] CreateHnsNetwork")
// Initialize HNS network.
hnsNetwork := &hcsshim.HNSNetwork{
Name: nwConfig.NetworkName,
Type: nwConfig.NetworkType,
NetworkAdapterName: nwConfig.NetworkAdapterName,
SourceMac: nwConfig.SourceMac,
DNSSuffix: nwConfig.DNSSuffix,
DNSServerList: nwConfig.DNSServerList,
DNSServerCompartment: nwConfig.DNSServerCompartment,
ManagementIP: nwConfig.ManagementIP,
AutomaticDNS: nwConfig.AutomaticDNS,
}
for _, policy := range nwConfig.Policies {
hnsNetwork.Policies = append(hnsNetwork.Policies, policy)
}
for _, subnet := range nwConfig.Subnets {
hnsSubnet := hcsshim.Subnet{
AddressPrefix: subnet.AddressPrefix,
GatewayAddress: subnet.GatewayAddress,
}
hnsNetwork.Subnets = append(hnsNetwork.Subnets, hnsSubnet)
}
for _, macPool := range nwConfig.MacPools {
hnsMacPool := hcsshim.MacPool{
StartMacAddress: macPool.StartMacAddress,
EndMacAddress: macPool.EndMacAddress,
}
hnsNetwork.MacPools = append(hnsNetwork.MacPools, hnsMacPool)
}
return createHnsNetwork(hnsNetwork)
}
// DeleteHnsNetwork deletes the HNS network with the provided name
func DeleteHnsNetwork(networkName string) error {
logger.Printf("[Azure CNS] DeleteHnsNetwork")
return deleteHnsNetwork(networkName)
}
// CreateDefaultExtNetwork creates default HNS network named ext (if it doesn't exist already)
// to create external switch on windows platform.
// This allows orchestrators to start CNS which pre-provisions the network so that the
// VM network blip / disconnect is avoided when calling cni add for the very first time.
func CreateDefaultExtNetwork(networkType string) error {
networkType = strings.ToLower(strings.TrimSpace(networkType))
if len(networkType) == 0 {
return nil
}
if networkType != hnsL2Bridge {
return fmt.Errorf("Invalid hns network type %s", networkType)
}
logger.Printf("[Azure CNS] CreateDefaultExtNetwork")
extHnsNetwork, _ := hcsshim.GetHNSNetworkByName(ExtHnsNetworkName)
if extHnsNetwork != nil {
logger.Printf("[Azure CNS] Found existing DefaultExtNetwork with type: %s", extHnsNetwork.Type)
if !strings.EqualFold(networkType, extHnsNetwork.Type) {
return fmt.Errorf("Network type mismatch with existing network: %s", extHnsNetwork.Type)
}
return nil
}
// create new hns network
logger.Printf("[Azure CNS] Creating DefaultExtNetwork with type %s", networkType)
hnsNetwork := &hcsshim.HNSNetwork{
Name: ExtHnsNetworkName,
Type: networkType,
}
hnsSubnet := hcsshim.Subnet{
AddressPrefix: ExtHnsNetworkAddressPrefix,
GatewayAddress: ExtHnsNetworkGwAddress,
}
hnsNetwork.Subnets = append(hnsNetwork.Subnets, hnsSubnet)
return createHnsNetwork(hnsNetwork)
}
// DeleteDefaultExtNetwork deletes the default HNS network
func DeleteDefaultExtNetwork() error {
logger.Printf("[Azure CNS] DeleteDefaultExtNetwork")
return deleteHnsNetwork(ExtHnsNetworkName)
}
// createHnsNetwork calls the hcshim to create the hns network
func createHnsNetwork(hnsNetwork *hcsshim.HNSNetwork) error {
// Marshal the request.
buffer, err := json.Marshal(hnsNetwork)
if err != nil {
return err
}
hnsRequest := string(buffer)
// Create the HNS network.
logger.Printf("[Azure CNS] HNSNetworkRequest POST request:%+v", hnsRequest)
hnsResponse, err := hcsshim.HNSNetworkRequest("POST", "", hnsRequest)
logger.Printf("[Azure CNS] HNSNetworkRequest POST response:%+v err:%v.", hnsResponse, err)
return err
}
// deleteHnsNetwork calls HNS to delete the network with the provided name
func deleteHnsNetwork(networkName string) error {
hnsNetwork, err := hcsshim.GetHNSNetworkByName(networkName)
if err == nil {
// Delete the HNS network.
var hnsResponse *hcsshim.HNSNetwork
logger.Printf("[Azure CNS] HNSNetworkRequest DELETE id:%v", hnsNetwork.Id)
hnsResponse, err = hcsshim.HNSNetworkRequest("DELETE", hnsNetwork.Id, "")
logger.Printf("[Azure CNS] HNSNetworkRequest DELETE response:%+v err:%v.", hnsResponse, err)
}
return err
}
func configureHostNCApipaNetwork(localIPConfiguration cns.IPConfiguration) (*hcn.HostComputeNetwork, error) {
network := &hcn.HostComputeNetwork{
Name: hostNCApipaNetworkName,
Ipams: []hcn.Ipam{
{
Type: hcnIpamTypeStatic,
},
},
SchemaVersion: hcn.SchemaVersion{
Major: hcnSchemaVersionMajor,
Minor: hcnSchemaVersionMinor,
},
Type: hostNCApipaNetworkType,
Flags: hcn.EnableNonPersistent, // Set up the network in non-persistent mode
}
if netAdapterNamePolicy, err := policy.GetHcnNetAdapterPolicy(hostNCLoopbackAdapterName); err == nil {
network.Policies = append(network.Policies, netAdapterNamePolicy)
} else {
return nil, fmt.Errorf("Failed to serialize network adapter policy. Error: %v", err)
}
// Calculate subnet prefix
// Following code calculates the subnet prefix from localIPConfiguration IP
// e.g. IP: 169.254.128.7 Prefix length: 17 then resulting subnet prefix: 169.254.128.0/17
// subnetPrefix: ffff8000
// subnetPrefix.IP: 169.254.128.0
var (
subnetPrefix net.IPNet
subnetPrefixStr string
ipAddr net.IP
)
ipAddr = net.ParseIP(localIPConfiguration.IPSubnet.IPAddress)
if ipAddr.To4() != nil {
subnetPrefix = net.IPNet{Mask: net.CIDRMask(int(localIPConfiguration.IPSubnet.PrefixLength), 32)}
} else if ipAddr.To16() != nil {
subnetPrefix = net.IPNet{Mask: net.CIDRMask(int(localIPConfiguration.IPSubnet.PrefixLength), 128)}
} else {
return nil, fmt.Errorf("Failed get subnet prefix for localIPConfiguration: %+v", localIPConfiguration)
}
subnetPrefix.IP = ipAddr.Mask(subnetPrefix.Mask)
subnetPrefixStr = subnetPrefix.IP.String() + "/" + strconv.Itoa(int(localIPConfiguration.IPSubnet.PrefixLength))
subnet := hcn.Subnet{
IpAddressPrefix: subnetPrefixStr,
Routes: []hcn.Route{
{
NextHop: localIPConfiguration.GatewayIPAddress,
DestinationPrefix: "0.0.0.0/0",
},
},
}
network.Ipams[0].Subnets = append(network.Ipams[0].Subnets, subnet)
logger.Printf("[Azure CNS] Configured HostNCApipaNetwork: %+v", network)
return network, nil
}
func createHostNCApipaNetwork(
localIPConfiguration cns.IPConfiguration) (*hcn.HostComputeNetwork, error) {
var (
network *hcn.HostComputeNetwork
err error
)
namedLock.LockAcquire(hostNCApipaNetworkName)
defer namedLock.LockRelease(hostNCApipaNetworkName)
// Check if the network exists for Host NC connectivity
if network, err = hcn.GetNetworkByName(hostNCApipaNetworkName); err != nil {
// If error is anything other than networkNotFound, mark this as error
if _, networkNotFound := err.(hcn.NetworkNotFoundError); !networkNotFound {
return nil, fmt.Errorf("[Azure CNS] ERROR: createApipaNetwork failed. Error with GetNetworkByName: %v", err)
}
// Network doesn't exist. Create one.
if network, err = configureHostNCApipaNetwork(localIPConfiguration); err != nil {
return nil, fmt.Errorf("Failed to configure network. Error: %v", err)
}
// Create loopback adapter needed for this HNS network
if interfaceExists, _ := networkcontainers.InterfaceExists(hostNCLoopbackAdapterName); !interfaceExists {
ipconfig := cns.IPConfiguration{
IPSubnet: cns.IPSubnet{
IPAddress: hnsLoopbackAdapterIPAddress,
PrefixLength: localIPConfiguration.IPSubnet.PrefixLength,
},
GatewayIPAddress: localIPConfiguration.GatewayIPAddress,
}
logger.Printf("Print interfaces before creating loopback adapter")
LogNetworkInterfaces()
if err = networkcontainers.CreateLoopbackAdapter(
hostNCLoopbackAdapterName,
ipconfig,
false, /* Flag to setWeakHostOnInterface */
"" /* Empty primary Interface Identifier as setWeakHostOnInterface is not needed*/); err != nil {
return nil, fmt.Errorf("Failed to create loopback adapter. Error: %v", err)
}
logger.Printf("Print interfaces after creating loopback adapter")
LogNetworkInterfaces()
}
// Create the HNS network.
logger.Printf("[Azure CNS] Creating HostNCApipaNetwork: %+v", network)
if network, err = network.Create(); err != nil {
return nil, err
}
logger.Printf("[Azure CNS] Successfully created apipa network for host container connectivity: %+v", network)
} else {
logger.Printf("[Azure CNS] Found existing HostNCApipaNetwork: %+v", network)
}
return network, err
}
// LogNetworkInterfaces logs the host's network interfaces in the default namespace.
func LogNetworkInterfaces() {
interfaces, err := net.Interfaces()
if err != nil {
logger.Printf("Failed to query network interfaces, err:%v", err)
return
}
for _, iface := range interfaces {
addrs, _ := iface.Addrs()
logger.Printf("Network interface: %+v with IP: %+v", iface, addrs)
}
}
func addAclToEndpointPolicy(
aclPolicySetting hcn.AclPolicySetting,
endpointPolicies *[]hcn.EndpointPolicy) error {
var (
rawJSON []byte
err error
)
if rawJSON, err = json.Marshal(aclPolicySetting); err != nil {
return fmt.Errorf("Failed to marshal endpoint ACL: %+v", aclPolicySetting)
}
endpointPolicy := hcn.EndpointPolicy{
Type: hcn.ACL,
Settings: rawJSON,
}
*endpointPolicies = append(*endpointPolicies, endpointPolicy)
return nil
}
func configureAclSettingHostNCApipaEndpoint(
protocolList []string,
networkContainerApipaIP string,
hostApipaIP string,
allowNCToHostCommunication bool,
allowHostToNCCommunication bool,
ncRequestedPolicies []cns.NetworkContainerRequestPolicies) ([]hcn.EndpointPolicy, error) {
var (
err error
endpointPolicies []hcn.EndpointPolicy
)
if allowNCToHostCommunication {
logger.Printf("[Azure CNS] Allowing NC (%s) to Host (%s) connectivity", networkContainerApipaIP, hostApipaIP)
}
if allowHostToNCCommunication {
logger.Printf("[Azure CNS] Allowing Host (%s) to NC (%s) connectivity", hostApipaIP, networkContainerApipaIP)
}
// Iterate thru the protocol list and add ACL for each
for _, protocol := range protocolList {
// Endpoint ACL to block all outbound traffic from the Apipa IP of the container
outBlockAll := hcn.AclPolicySetting{
Protocols: protocol,
Action: hcn.ActionTypeBlock,
Direction: hcn.DirectionTypeOut,
LocalAddresses: networkContainerApipaIP,
RuleType: hcn.RuleTypeSwitch,
Priority: aclPriority2000,
}
if err = addAclToEndpointPolicy(outBlockAll, &endpointPolicies); err != nil {
return nil, err
}
if allowNCToHostCommunication {
// Endpoint ACL to allow the outbound traffic from the Apipa IP of the container to
// Apipa IP of the host only
outAllowToHostOnly := hcn.AclPolicySetting{
Protocols: protocol,
Action: hcn.ActionTypeAllow,
Direction: hcn.DirectionTypeOut,
LocalAddresses: networkContainerApipaIP,
RemoteAddresses: hostApipaIP,
RuleType: hcn.RuleTypeSwitch,
Priority: aclPriority1000,
}
if err = addAclToEndpointPolicy(outAllowToHostOnly, &endpointPolicies); err != nil {
return nil, err
}
}
// Endpoint ACL to block all inbound traffic to the Apipa IP of the container
inBlockAll := hcn.AclPolicySetting{
Protocols: protocol,
Action: hcn.ActionTypeBlock,
Direction: hcn.DirectionTypeIn,
LocalAddresses: networkContainerApipaIP,
RuleType: hcn.RuleTypeSwitch,
Priority: aclPriority2000,
}
if err = addAclToEndpointPolicy(inBlockAll, &endpointPolicies); err != nil {
return nil, err
}
if allowHostToNCCommunication {
// Endpoint ACL to allow the inbound traffic from the apipa IP of the host to
// the apipa IP of the container only
inAllowFromHostOnly := hcn.AclPolicySetting{
Protocols: protocol,
Action: hcn.ActionTypeAllow,
Direction: hcn.DirectionTypeIn,
LocalAddresses: networkContainerApipaIP,
RemoteAddresses: hostApipaIP,
RuleType: hcn.RuleTypeSwitch,
Priority: aclPriority1000,
}
if err = addAclToEndpointPolicy(inAllowFromHostOnly, &endpointPolicies); err != nil {
return nil, err
}
}
}
if ncRequestedPolicies != nil {
// Iterate thru the requested endpoint policies where policy type is ACL, endpoint type is APIPA
// include the raw json message in the endpoint policies
for _, requestedPolicy := range ncRequestedPolicies {
if strings.EqualFold(requestedPolicy.Type, aclPolicyType) && strings.EqualFold(requestedPolicy.EndpointType, apipaEndpointType) {
var requestedAclPolicy hcn.AclPolicySetting
if err = json.Unmarshal(requestedPolicy.Settings, &requestedAclPolicy); err != nil {
return nil, fmt.Errorf("Failed to Unmarshal requested ACL policy: %+v with error: %+v", requestedPolicy.Settings, err)
}
// Using {NetworkContainerIP} as a placeholder to signal using Network Container IP
if strings.EqualFold(requestedAclPolicy.LocalAddresses, "{NetworkContainerIP}") {
requestedAclPolicy.LocalAddresses = networkContainerApipaIP
}
// Using {HostApipaIP} as a placeholder to signal using Host Apipa IP
if strings.EqualFold(requestedAclPolicy.RemoteAddresses, "{HostApipaIP}") {
requestedAclPolicy.RemoteAddresses = hostApipaIP
}
logger.Printf("ACL Policy requested in NcGoalState %+v", requestedAclPolicy)
if err = addAclToEndpointPolicy(requestedAclPolicy, &endpointPolicies); err != nil {
return nil, err
}
}
}
}
return endpointPolicies, nil
}
func configureHostNCApipaEndpoint(
endpointName string,
networkID string,
localIPConfiguration cns.IPConfiguration,
allowNCToHostCommunication bool,
allowHostToNCCommunication bool,
ncPolicies []cns.NetworkContainerRequestPolicies) (*hcn.HostComputeEndpoint, error) {
endpoint := &hcn.HostComputeEndpoint{
Name: endpointName,
HostComputeNetwork: networkID,
SchemaVersion: hcn.SchemaVersion{
Major: hcnSchemaVersionMajor,
Minor: hcnSchemaVersionMinor,
},
}
networkContainerApipaIP := localIPConfiguration.IPSubnet.IPAddress
hostApipaIP := localIPConfiguration.GatewayIPAddress
protocolList := []string{protocolICMPv4, protocolTCP, protocolUDP}
endpointPolicies, err := configureAclSettingHostNCApipaEndpoint(
protocolList,
networkContainerApipaIP,
hnsLoopbackAdapterIPAddress,
allowNCToHostCommunication,
allowHostToNCCommunication,
ncPolicies)
if err != nil {
logger.Errorf("[Azure CNS] Failed to configure ACL for HostNCApipaEndpoint. Error: %v", err)
return nil, err
}
for _, endpointPolicy := range endpointPolicies {
endpoint.Policies = append(endpoint.Policies, endpointPolicy)
}
hcnRoute := hcn.Route{
NextHop: hostApipaIP,
DestinationPrefix: "0.0.0.0/0",
}
endpoint.Routes = append(endpoint.Routes, hcnRoute)
ipConfiguration := hcn.IpConfig{
IpAddress: networkContainerApipaIP,
PrefixLength: localIPConfiguration.IPSubnet.PrefixLength,
}
endpoint.IpConfigurations = append(endpoint.IpConfigurations, ipConfiguration)
logger.Printf("[Azure CNS] Configured HostNCApipaEndpoint: %+v", endpoint)
return endpoint, nil
}
// CreateHostNCApipaEndpoint creates the endpoint in the apipa network for host container connectivity
func CreateHostNCApipaEndpoint(
networkContainerID string,
localIPConfiguration cns.IPConfiguration,
allowNCToHostCommunication bool,
allowHostToNCCommunication bool,
ncPolicies []cns.NetworkContainerRequestPolicies) (string, error) {
var (
network *hcn.HostComputeNetwork
endpoint *hcn.HostComputeEndpoint
endpointName = getHostNCApipaEndpointName(networkContainerID)
err error
)
namedLock.LockAcquire(endpointName)
defer namedLock.LockRelease(endpointName)
// Return if the endpoint already exists
if endpoint, err = hcn.GetEndpointByName(endpointName); err != nil {
// If error is anything other than EndpointNotFoundError, return error.
if _, endpointNotFound := err.(hcn.EndpointNotFoundError); !endpointNotFound {
return "", fmt.Errorf("ERROR: Failed to query endpoint using GetEndpointByName "+
"due to error: %v", err)
}
}
if endpoint != nil {
logger.Debugf("[Azure CNS] Found existing endpoint: %+v", endpoint)
return endpoint.Id, nil
}
updateGwForLocalIPConfiguration(&localIPConfiguration)
if network, err = createHostNCApipaNetwork(localIPConfiguration); err != nil {
logger.Errorf("[Azure CNS] Failed to create HostNCApipaNetwork. Error: %v", err)
return "", err
}
logger.Printf("[Azure CNS] Configuring HostNCApipaEndpoint: %s, in network: %s with localIPConfig: %+v",
endpointName, network.Id, localIPConfiguration)
if endpoint, err = configureHostNCApipaEndpoint(
endpointName,
network.Id,
localIPConfiguration,
allowNCToHostCommunication,
allowHostToNCCommunication,
ncPolicies); err != nil {
logger.Errorf("[Azure CNS] Failed to configure HostNCApipaEndpoint: %s. Error: %v", endpointName, err)
return "", err
}
logger.Printf("[Azure CNS] Creating HostNCApipaEndpoint for host container connectivity: %+v", endpoint)
if endpoint, err = endpoint.Create(); err != nil {
err = fmt.Errorf("Failed to create HostNCApipaEndpoint: %s. Error: %v", endpointName, err)
logger.Errorf("[Azure CNS] %s", err.Error())
return "", err
}
logger.Printf("[Azure CNS] Successfully created HostNCApipaEndpoint: %+v", endpoint)
return endpoint.Id, nil
}
// updateGwForLocalIPConfiguration applies change on gw IP address for apipa NW and endpoint.
// Currently, cns using the same ip address "169.254.128.1" for both apipa gw and loopback adapter. This cause conflict issue when hns get restarted and not able to rehydrate the apipa endpoints.
// This func is to overwrite the address to 169.254.128.2 when the gateway address is 169.254.128.1
func updateGwForLocalIPConfiguration(localIPConfiguration *cns.IPConfiguration) {
// When gw address is 169.254.128.1, should use .2 instead. If gw address is not .1, that mean this value is
// configured from dnc, we should keep it
if localIPConfiguration.GatewayIPAddress == "169.254.128.1" {
localIPConfiguration.GatewayIPAddress = defaultHnsGwIPAddress
}
}
func getHostNCApipaEndpointName(
networkContainerID string) string {
return hostNCApipaEndpointNamePrefix + "-" + networkContainerID
}
func deleteNetworkByIDHnsV2(
networkID string) error {
var (
network *hcn.HostComputeNetwork
err error
)
if network, err = hcn.GetNetworkByID(networkID); err != nil {
// If error is anything other than NetworkNotFoundError, return error.
// else log the error but don't return error because network is already deleted.
if _, networkNotFound := err.(hcn.NetworkNotFoundError); !networkNotFound {
return fmt.Errorf("[Azure CNS] deleteNetworkByIDHnsV2 failed due to "+
"error with GetNetworkByID: %v", err)
}
logger.Errorf("[Azure CNS] Delete called on the Network: %s which doesn't exist. Error: %v",
networkID, err)
return nil
}
if err = network.Delete(); err != nil {
return fmt.Errorf("Failed to delete network: %+v. Error: %v", network, err)
}
logger.Errorf("[Azure CNS] Successfully deleted network: %+v", network)
return nil
}
func deleteEndpointByNameHnsV2(
endpointName string) error {
var (
endpoint *hcn.HostComputeEndpoint
err error
)
// Check if the endpoint exists
if endpoint, err = hcn.GetEndpointByName(endpointName); err != nil {
// If error is anything other than EndpointNotFoundError, return error.
// else log the error but don't return error because endpoint is already deleted.
if _, endpointNotFound := err.(hcn.EndpointNotFoundError); !endpointNotFound {
return fmt.Errorf("[Azure CNS] deleteEndpointByNameHnsV2 failed due to "+
"error with GetEndpointByName: %v", err)
}
logger.Errorf("[Azure CNS] Delete called on the Endpoint: %s which doesn't exist. Error: %v",
endpointName, err)
return nil
}
if err = endpoint.Delete(); err != nil {
return fmt.Errorf("Failed to delete endpoint: %+v. Error: %v", endpoint, err)
}
logger.Errorf("[Azure CNS] Successfully deleted endpoint: %+v", endpoint)
return nil
}
// DeleteHostNCApipaEndpoint deletes the endpoint in the apipa network created for host container connectivity
func DeleteHostNCApipaEndpoint(
networkContainerID string) error {
endpointName := getHostNCApipaEndpointName(networkContainerID)
namedLock.LockAcquire(endpointName)
defer namedLock.LockRelease(endpointName)
logger.Debugf("[Azure CNS] Deleting HostNCApipaEndpoint: %s", endpointName)
if err := deleteEndpointByNameHnsV2(endpointName); err != nil {
logger.Errorf("[Azure CNS] Failed to delete HostNCApipaEndpoint: %s. Error: %v", endpointName, err)
return err
}
logger.Debugf("[Azure CNS] Successfully deleted HostNCApipaEndpoint: %s", endpointName)
return nil
}
// DeleteHNSEndpointbyID deletes the HNS endpoint
func DeleteHNSEndpointbyID(hnsEndpointID string) error {
var (
hcnEndpoint *hcn.HostComputeEndpoint
err error
)
logger.Printf("Deleting hcn endpoint with id %v", hnsEndpointID)
hcnEndpoint, err = hcn.GetEndpointByID(hnsEndpointID)
if err != nil {
// If error is anything other than EndpointNotFoundError, return error.
// else log the error but don't return error because endpoint is already deleted.
var notFoundErr hcn.EndpointNotFoundError
if errors.As(err, ¬FoundErr) {
return fmt.Errorf("Failed to get hcn endpoint with id: %s due to err: %w", hnsEndpointID, err)
}
logger.Errorf("Delete called on the Endpoint which doesn't exist. Error:%v", err)
return nil
}
// Remove this endpoint from the namespace
if err = hcn.RemoveNamespaceEndpoint(hcnEndpoint.HostComputeNamespace, hcnEndpoint.Id); err != nil {
logger.Errorf("Failed to remove hcn endpoint %s from namespace %s due to err: %v", hcnEndpoint.Id, hcnEndpoint.HostComputeNamespace, err)
}
if err = hcnEndpoint.Delete(); err != nil {
return fmt.Errorf("Failed to delete endpoint: %s. Error: %w", hnsEndpointID, err)
}
logger.Errorf("[Azure CNS] Successfully deleted endpoint: %+v", hnsEndpointID)
return nil
}
// GetHNSEndpointbyIP returns an HNSEndpoint with the corrsponding HNS Endpoint ID that matches an specific IP Address.
func GetHNSEndpointbyIP(ipv4, ipv6 []net.IPNet) (string, error) {
logger.Printf("Fetching missing HNS endpoint id for endpoints in network with id %s", defaultNetworkName)
hnsResponse, err := hcn.GetNetworkByName(defaultNetworkName)
if err != nil || hnsResponse == nil {
return "", errors.Wrapf(err, "HNS Network or endpoints not found")
}
hcnEndpoints, err := hcn.ListEndpointsOfNetwork(hnsResponse.Id)
if err != nil {
return "", errors.Wrapf(err, "failed to fetch HNS endpoints for the given network")
}
for i := range hcnEndpoints {
for _, ipConfiguration := range hcnEndpoints[i].IpConfigurations {
for _, ip := range ipv4 {
if ipConfiguration.IpAddress == ip.IP.String() {
logger.Printf("Successfully found hcn endpoint id for endpoint %s with ip %s", hcnEndpoints[i].Id, ip.IP.String())
return hcnEndpoints[i].Id, nil
}
}
for _, ip := range ipv6 {
if ipConfiguration.IpAddress == ip.IP.String() {
logger.Printf("Successfully found hcn endpoint id for endpoint %s with ip %s", hcnEndpoints[i].Id, ip.IP.String())
return hcnEndpoints[i].Id, nil
}
}
}
}
return "", errors.Wrapf(err, "No HNSEndpointID matches the IPAddress")
}