Repository: kubernetes-sigs/cloud-provider-azure
Pull request #4268 (2023-07-12 06:48:31)

[aks pipeline] Refactor run-e2e.sh
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide/first-contribution.md#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/sig-release/release.md#issuepr-kind-label
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/sig-testing/testing.md
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
5. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

#### What type of PR is this?
/kind testing
<!--
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind design

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->

#### What this PR does / why we need it:
[aks pipeline] Refactor run-e2e.sh
    * It supports the local testing scenario when it is unnecessary
    to build kubetest2-aks, run tests, collect logs and gc.
    * Print custom config and cluster config path
    * Skip the e2e test "balance-node-groups" due to autoscaler bug
#### Which issue(s) this PR fixes:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->
```release-note
NONE
```

#### Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:

<!--
This section can be blank if this pull request does not require a release note.

When adding links which point to resources within git repositories, like
KEPs or supporting documentation, please reference a specific commit and avoid
linking directly to the master branch. This ensures that links reference a
specific point in time, rather than a document that may change over time.

See here for guidance on getting permanent links to files: https://help.github.com/en/articles/getting-permanent-links-to-files

Please use the following format for linking documentation:
- [KEP]: <link>
- [Usage]: <link>
- [Other doc]: <link>
-->
```docs

```


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/4268#" title="Author self-approved">lzhecheng</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcloud-provider-azure).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/cloud-provider-azure/blob/master/OWNERS)~~ [lzhecheng]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/.pipelines/scripts/collect-log.sh b/.pipelines/scripts/collect-log.sh
index 51caa9335..ed4da3f73 100755
--- a/.pipelines/scripts/collect-log.sh
+++ b/.pipelines/scripts/collect-log.sh
@@ -19,13 +19,13 @@ set -o nounset
 set -o pipefail
 
 echo "collecting logs of all pods in kube-system"
-mkdir "${ARTIFACT_DIR}/kube-system"
+mkdir -p "${ARTIFACT_DIR:-}/kube-system"
 kubectl get pod -A | grep "kube-system" | awk '{printf("%s\n",$2)}' | while read -r POD; do
-    kubectl logs ${POD} -n kube-system > "${ARTIFACT_DIR}/kube-system/${POD}.log" || echo "Cannot collect log from pod ${POD}"
+    kubectl logs ${POD} -n kube-system > "${ARTIFACT_DIR:-}/kube-system/${POD}.log" || echo "Cannot collect log from pod ${POD}"
 done
 
 echo "collecting logs of all nodes"
-mkdir "${ARTIFACT_DIR}/node-log"
+mkdir "${ARTIFACT_DIR:-}/node-log"
 LOG_IMAGE="mcr.microsoft.com/dotnet/runtime-deps:6.0"
 NODE_CMDS=("journalctl --no-pager --output=short-precise" \
            "journalctl --no-pager --output=short-precise -k" \
@@ -36,7 +36,7 @@ NODE_CMDS=("journalctl --no-pager --output=short-precise" \
            "ls /run/cluster-api/")
 NODE_LOG_FILE_NAMES=("journal.log" "kern.log" "kubelet-version.txt" "kubelet.log" "containerd.log" "cloud-init.log" "cloud-init-output.log" "sentinel-file-dir.txt")
 kubectl get node | grep "aks-" | awk '{printf("%s\n",$1)}' | while read -r NODE; do
-    NODE_LOG_DIR="${ARTIFACT_DIR}/node-log/${NODE}"
+    NODE_LOG_DIR="${ARTIFACT_DIR:-}/node-log/${NODE}"
     mkdir "${NODE_LOG_DIR}"
     for i in "${!NODE_CMDS[@]}"; do
         kubectl debug node/${NODE} -it --image=${LOG_IMAGE} -- /bin/sh -c "chroot /host ${NODE_CMDS[$i]}" > "${NODE_LOG_DIR}/${NODE_LOG_FILE_NAMES[$i]}" || echo "Cannot collect ${NODE_LOG_FILE_NAMES[$i]} log from node ${NODE}"
diff --git a/pkg/provider/azure_loadbalancer.go b/pkg/provider/azure_loadbalancer.go
index c53f6348b..e592779b8 100644
--- a/pkg/provider/azure_loadbalancer.go
+++ b/pkg/provider/azure_loadbalancer.go
@@ -28,7 +28,6 @@ import (
 	"sort"
 	"strconv"
 	"strings"
-	"unicode"
 
 	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
 
@@ -810,7 +809,7 @@ func (az *Cloud) determinePublicIPName(clusterName string, service *v1.Service,
 
 	// For the services with loadBalancerIP set, an existing public IP is required, primary
 	// or secondary, or a public IP not found error would be reported.
-	pip, err := az.findMatchedPIP(loadBalancerIP, "", pipResourceGroup)
+	pip, err := az.findMatchedPIPByLoadBalancerIP(service, loadBalancerIP, pipResourceGroup)
 	if err != nil {
 		return "", false, err
 	}
@@ -822,6 +821,39 @@ func (az *Cloud) determinePublicIPName(clusterName string, service *v1.Service,
 	return "", false, fmt.Errorf("user supplied IP Address %s was not found in resource group %s", loadBalancerIP, pipResourceGroup)
 }
 
+func (az *Cloud) findMatchedPIPByLoadBalancerIP(service *v1.Service, loadBalancerIP, pipResourceGroup string) (*network.PublicIPAddress, error) {
+	pips, err := az.listPIP(pipResourceGroup, azcache.CacheReadTypeDefault)
+	if err != nil {
+		return nil, fmt.Errorf("findMatchedPIPByLoadBalancerIP: failed to listPIP: %w", err)
+	}
+
+	pip, err := getExpectedPIPFromListByIPAddress(pips, loadBalancerIP)
+	if err != nil {
+		pips, err = az.listPIP(pipResourceGroup, azcache.CacheReadTypeForceRefresh)
+		if err != nil {
+			return nil, fmt.Errorf("findMatchedPIPByLoadBalancerIP: failed to listPIP force refresh: %w", err)
+		}
+
+		pip, err = getExpectedPIPFromListByIPAddress(pips, loadBalancerIP)
+		if err != nil {
+			return nil, fmt.Errorf("findMatchedPIPByLoadBalancerIP: cannot find public IP with IP address %s in resource group %s", loadBalancerIP, pipResourceGroup)
+		}
+	}
+
+	return pip, nil
+}
+
+func getExpectedPIPFromListByIPAddress(pips []network.PublicIPAddress, ip string) (*network.PublicIPAddress, error) {
+	for _, pip := range pips {
+		if pip.PublicIPAddressPropertiesFormat.IPAddress != nil &&
+			*pip.PublicIPAddressPropertiesFormat.IPAddress == ip {
+			return &pip, nil
+		}
+	}
+
+	return nil, fmt.Errorf("getExpectedPIPFromListByIPAddress: cannot find public IP with IP address %s", ip)
+}
+
 func flipServiceInternalAnnotation(service *v1.Service) *v1.Service {
 	copyService := service.DeepCopy()
 	if copyService.Annotations == nil {
@@ -3484,7 +3516,7 @@ func serviceOwnsPublicIP(service *v1.Service, pip *network.PublicIPAddress, clus
 
 		// if there is no service tag on the pip, it is user-created pip
 		if serviceTag == "" {
-			return isServiceSelectPIP(service, pip, isIPv6), true
+			return isServiceLoadBalancerIPMatchesPIP(service, pip, isIPv6), true
 		}
 
 		// if there is service tag on the pip, it is system-created pip
@@ -3500,26 +3532,18 @@ func serviceOwnsPublicIP(service *v1.Service, pip *network.PublicIPAddress, clus
 		}
 
 		// if the service is not included in the tags of the system-created pip, check the ip address
-		// or pip name, this could happen for secondary services
-		return isServiceSelectPIP(service, pip, isIPv6), false
+		// this could happen for secondary services
+		return isServiceLoadBalancerIPMatchesPIP(service, pip, isIPv6), false
 	}
 
 	// if the pip has no tags, it should be user-created
-	return isServiceSelectPIP(service, pip, isIPv6), true
+	return isServiceLoadBalancerIPMatchesPIP(service, pip, isIPv6), true
 }
 
 func isServiceLoadBalancerIPMatchesPIP(service *v1.Service, pip *network.PublicIPAddress, isIPV6 bool) bool {
 	return strings.EqualFold(pointer.StringDeref(pip.IPAddress, ""), getServiceLoadBalancerIP(service, isIPV6))
 }
 
-func isServicePIPNameMatchesPIP(service *v1.Service, pip *network.PublicIPAddress, isIPV6 bool) bool {
-	return strings.EqualFold(pointer.StringDeref(pip.Name, ""), getServicePIPName(service, isIPV6))
-}
-
-func isServiceSelectPIP(service *v1.Service, pip *network.PublicIPAddress, isIPV6 bool) bool {
-	return isServiceLoadBalancerIPMatchesPIP(service, pip, isIPV6) || isServicePIPNameMatchesPIP(service, pip, isIPV6)
-}
-
 func isSVCNameInPIPTag(tag, svcName string) bool {
 	svcNames := parsePIPServiceTag(&tag)
 
@@ -3889,109 +3913,3 @@ func isLoadBalancerInUseByService(service *v1.Service, lbConfig MultipleStandard
 	}
 	return false
 }
-
-// There are two cases when a service owns the frontend IP config:
-// 1. The primary service, which means the frontend IP config is created after the creation of the service.
-// This means the name of the config can be tracked by the service UID.
-// 2. The secondary services must have their loadBalancer IP set if they want to share the same config as the primary
-// service. Hence, it can be tracked by the loadBalancer IP.
-// If the IP version is not empty, which means it is the secondary Service, it returns IP version of the Service FIP.
-func (az *Cloud) serviceOwnsFrontendIP(fip network.FrontendIPConfiguration, service *v1.Service) (bool, bool, network.IPVersion) {
-	var isPrimaryService bool
-	baseName := az.GetLoadBalancerName(context.TODO(), "", service)
-	if strings.HasPrefix(pointer.StringDeref(fip.Name, ""), baseName) {
-		klog.V(6).Infof("serviceOwnsFrontendIP: found primary service %s of the frontend IP config %s", service.Name, *fip.Name)
-		isPrimaryService = true
-		return true, isPrimaryService, ""
-	}
-
-	loadBalancerIPs := getServiceLoadBalancerIPs(service)
-	pipResourceGroup := az.getPublicIPAddressResourceGroup(service)
-	var pipNames []string
-	if len(loadBalancerIPs) == 0 {
-		if !requiresInternalLoadBalancer(service) {
-			pipNames = getServicePIPNames(service)
-			for _, pipName := range pipNames {
-				if pipName != "" {
-					pip, err := az.findMatchedPIP("", pipName, pipResourceGroup)
-					if err != nil {
-						klog.Warningf("serviceOwnsFrontendIP: unexpected error when finding match public IP of the service %s with name %s: %v", service.Name, pipName, err)
-						return false, isPrimaryService, ""
-					}
-					if publicIPOwnsFrontendIP(service, &fip, pip) {
-						return true, isPrimaryService, pip.PublicIPAddressPropertiesFormat.PublicIPAddressVersion
-					}
-				}
-			}
-		}
-		// it is a must that the secondary services set the loadBalancer IP or pip name
-		return false, isPrimaryService, ""
-	}
-
-	// for external secondary service the public IP address should be checked
-	if !requiresInternalLoadBalancer(service) {
-		for _, loadBalancerIP := range loadBalancerIPs {
-			pip, err := az.findMatchedPIP(loadBalancerIP, "", pipResourceGroup)
-			if err != nil {
-				klog.Warningf("serviceOwnsFrontendIP: unexpected error when finding match public IP of the service %s with loadBalancerIP %s: %v", service.Name, loadBalancerIP, err)
-				return false, isPrimaryService, ""
-			}
-
-			if publicIPOwnsFrontendIP(service, &fip, pip) {
-				return true, isPrimaryService, pip.PublicIPAddressPropertiesFormat.PublicIPAddressVersion
-			}
-			klog.V(6).Infof("serviceOwnsFrontendIP: the public IP with ID %s is being referenced by other service with public IP address %s "+
-				"OR it is of incorrect IP version", *pip.ID, *pip.IPAddress)
-		}
-
-		return false, isPrimaryService, ""
-	}
-
-	// for internal secondary service the private IP address on the frontend IP config should be checked
-	if fip.PrivateIPAddress == nil {
-		return false, isPrimaryService, ""
-	}
-	privateIPAddrVersion := network.IPv4
-	if net.ParseIP(*fip.PrivateIPAddress).To4() == nil {
-		privateIPAddrVersion = network.IPv6
-	}
-
-	privateIPEquals := false
-	for _, loadBalancerIP := range loadBalancerIPs {
-		if strings.EqualFold(*fip.PrivateIPAddress, loadBalancerIP) {
-			privateIPEquals = true
-			break
-		}
-	}
-	return privateIPEquals, isPrimaryService, privateIPAddrVersion
-}
-
-func (az *Cloud) getFrontendIPConfigNames(service *v1.Service) map[bool]string {
-	isDualStack := isServiceDualStack(service)
-	defaultLBFrontendIPConfigName := az.getDefaultFrontendIPConfigName(service)
-	return map[bool]string{
-		consts.IPVersionIPv4: getResourceByIPFamily(defaultLBFrontendIPConfigName, isDualStack, consts.IPVersionIPv4),
-		consts.IPVersionIPv6: getResourceByIPFamily(defaultLBFrontendIPConfigName, isDualStack, consts.IPVersionIPv6),
-	}
-}
-
-func (az *Cloud) getDefaultFrontendIPConfigName(service *v1.Service) string {
-	baseName := az.GetLoadBalancerName(context.TODO(), "", service)
-	subnetName := getInternalSubnet(service)
-	if subnetName != nil {
-		ipcName := fmt.Sprintf("%s-%s", baseName, *subnetName)
-
-		// Azure lb front end configuration name must not exceed 80 characters
-		maxLength := consts.FrontendIPConfigNameMaxLength - consts.IPFamilySuffixLength
-		if len(ipcName) > maxLength {
-			ipcName = ipcName[:maxLength]
-			// Cutting the string may result in char like "-" as the string end.
-			// If the last char is not a letter or '_', replace it with "_".
-			if !unicode.IsLetter(rune(ipcName[len(ipcName)-1:][0])) && ipcName[len(ipcName)-1:] != "_" {
-				ipcName = ipcName[:len(ipcName)-1] + "_"
-			}
-		}
-		return ipcName
-	}
-	return baseName
-}
diff --git a/pkg/provider/azure_publicip_repo.go b/pkg/provider/azure_publicip_repo.go
index 2ace3b992..536d48abd 100644
--- a/pkg/provider/azure_publicip_repo.go
+++ b/pkg/provider/azure_publicip_repo.go
@@ -18,14 +18,12 @@ package provider
 
 import (
 	"encoding/json"
-	"fmt"
 	"net/http"
 	"strings"
 	"sync"
 	"time"
 
 	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
 	v1 "k8s.io/api/core/v1"
 	"k8s.io/klog/v2"
 	"k8s.io/utils/pointer"
@@ -154,74 +152,3 @@ func (az *Cloud) listPIP(pipResourceGroup string, crt azcache.AzureCacheReadType
 	})
 	return ret, nil
 }
-
-func (az *Cloud) findMatchedPIP(loadBalancerIP, pipName, pipResourceGroup string) (pip *network.PublicIPAddress, err error) {
-	pips, err := az.listPIP(pipResourceGroup, azcache.CacheReadTypeDefault)
-	if err != nil {
-		return nil, fmt.Errorf("findMatchedPIPByLoadBalancerIP: failed to listPIP: %w", err)
-	}
-
-	if loadBalancerIP != "" {
-		pip, err = az.findMatchedPIPByLoadBalancerIP(&pips, loadBalancerIP, pipResourceGroup)
-		if err != nil {
-			return nil, err
-		}
-		return pip, nil
-	}
-
-	if pipResourceGroup != "" {
-		pip, err = az.findMatchedPIPByName(&pips, pipName, pipResourceGroup)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return pip, nil
-}
-
-func (az *Cloud) findMatchedPIPByName(pips *[]network.PublicIPAddress, pipName, pipResourceGroup string) (*network.PublicIPAddress, error) {
-	for _, pip := range *pips {
-		if strings.EqualFold(pointer.StringDeref(pip.Name, ""), pipName) {
-			return &pip, nil
-		}
-	}
-
-	pipList, err := az.listPIP(pipResourceGroup, azcache.CacheReadTypeForceRefresh)
-	if err != nil {
-		return nil, fmt.Errorf("findMatchedPIPByName: failed to listPIP force refresh: %w", err)
-	}
-	for _, pip := range pipList {
-		if strings.EqualFold(pointer.StringDeref(pip.Name, ""), pipName) {
-			return &pip, nil
-		}
-	}
-
-	return nil, fmt.Errorf("findMatchedPIPByName: failed to find PIP %s in resource group %s", pipName, pipResourceGroup)
-}
-
-func (az *Cloud) findMatchedPIPByLoadBalancerIP(pips *[]network.PublicIPAddress, loadBalancerIP, pipResourceGroup string) (*network.PublicIPAddress, error) {
-	pip, err := getExpectedPIPFromListByIPAddress(*pips, loadBalancerIP)
-	if err != nil {
-		pipList, err := az.listPIP(pipResourceGroup, azcache.CacheReadTypeForceRefresh)
-		if err != nil {
-			return nil, fmt.Errorf("findMatchedPIPByLoadBalancerIP: failed to listPIP force refresh: %w", err)
-		}
-
-		pip, err = getExpectedPIPFromListByIPAddress(pipList, loadBalancerIP)
-		if err != nil {
-			return nil, fmt.Errorf("findMatchedPIPByLoadBalancerIP: cannot find public IP with IP address %s in resource group %s", loadBalancerIP, pipResourceGroup)
-		}
-	}
-
-	return pip, nil
-}
-
-func getExpectedPIPFromListByIPAddress(pips []network.PublicIPAddress, ip string) (*network.PublicIPAddress, error) {
-	for _, pip := range pips {
-		if pip.PublicIPAddressPropertiesFormat.IPAddress != nil &&
-			*pip.PublicIPAddressPropertiesFormat.IPAddress == ip {
-			return &pip, nil
-		}
-	}
-
-	return nil, fmt.Errorf("getExpectedPIPFromListByIPAddress: cannot find public IP with IP address %s", ip)
-}
diff --git a/pkg/provider/azure_standard.go b/pkg/provider/azure_standard.go
index 2b4a7a362..8482a82e0 100644
--- a/pkg/provider/azure_standard.go
+++ b/pkg/provider/azure_standard.go
@@ -21,12 +21,16 @@ import (
 	"errors"
 	"fmt"
 	"hash/crc32"
+	"net"
 	"regexp"
 	"strconv"
 	"strings"
 	"sync"
 	"sync/atomic"
 	"time"
+	"unicode"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 
 	"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2022-08-01/compute"
 	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
@@ -40,7 +44,6 @@ import (
 	"k8s.io/utils/pointer"
 
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
-	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
 )
 
@@ -359,20 +362,102 @@ func (az *Cloud) serviceOwnsRule(service *v1.Service, rule string) bool {
 	return strings.HasPrefix(strings.ToUpper(rule), strings.ToUpper(prefix))
 }
 
-func publicIPOwnsFrontendIP(service *v1.Service, fip *network.FrontendIPConfiguration, pip *network.PublicIPAddress) bool {
-	if pip != nil &&
-		pip.ID != nil &&
-		pip.PublicIPAddressPropertiesFormat != nil &&
-		pip.PublicIPAddressPropertiesFormat.IPAddress != nil &&
-		fip != nil &&
-		fip.FrontendIPConfigurationPropertiesFormat != nil &&
-		fip.FrontendIPConfigurationPropertiesFormat.PublicIPAddress != nil {
-		if strings.EqualFold(pointer.StringDeref(pip.ID, ""), pointer.StringDeref(fip.PublicIPAddress.ID, "")) {
-			klog.V(6).Infof("publicIPOwnsFrontendIP:found secondary service %s of the frontend IP config %s", service.Name, *fip.Name)
-			return true
+// There are two cases when a service owns the frontend IP config:
+// 1. The primary service, which means the frontend IP config is created after the creation of the service.
+// This means the name of the config can be tracked by the service UID.
+// 2. The secondary services must have their loadBalancer IP set if they want to share the same config as the primary
+// service. Hence, it can be tracked by the loadBalancer IP.
+// If the IP version is not empty, which means it is the secondary Service, it returns IP version of the Service FIP.
+func (az *Cloud) serviceOwnsFrontendIP(fip network.FrontendIPConfiguration, service *v1.Service) (bool, bool, network.IPVersion) {
+	var isPrimaryService bool
+	baseName := az.GetLoadBalancerName(context.TODO(), "", service)
+	if strings.HasPrefix(pointer.StringDeref(fip.Name, ""), baseName) {
+		klog.V(6).Infof("serviceOwnsFrontendIP: found primary service %s of the frontend IP config %s", service.Name, *fip.Name)
+		isPrimaryService = true
+		return true, isPrimaryService, ""
+	}
+
+	loadBalancerIPs := getServiceLoadBalancerIPs(service)
+	if len(loadBalancerIPs) == 0 {
+		// it is a must that the secondary services set the loadBalancer IP
+		return false, isPrimaryService, ""
+	}
+
+	// for external secondary service the public IP address should be checked
+	if !requiresInternalLoadBalancer(service) {
+		pipResourceGroup := az.getPublicIPAddressResourceGroup(service)
+		for _, loadBalancerIP := range loadBalancerIPs {
+			pip, err := az.findMatchedPIPByLoadBalancerIP(service, loadBalancerIP, pipResourceGroup)
+			if err != nil {
+				klog.Warningf("serviceOwnsFrontendIP: unexpected error when finding match public IP of the service %s with loadBalancerIP %s: %v", service.Name, loadBalancerIP, err)
+				return false, isPrimaryService, ""
+			}
+
+			if pip != nil &&
+				pip.ID != nil &&
+				pip.PublicIPAddressPropertiesFormat != nil &&
+				pip.PublicIPAddressPropertiesFormat.IPAddress != nil &&
+				fip.FrontendIPConfigurationPropertiesFormat != nil &&
+				fip.FrontendIPConfigurationPropertiesFormat.PublicIPAddress != nil {
+				if strings.EqualFold(pointer.StringDeref(pip.ID, ""), pointer.StringDeref(fip.PublicIPAddress.ID, "")) {
+					klog.V(6).Infof("serviceOwnsFrontendIP:found secondary service %s of the frontend IP config %s", service.Name, *fip.Name)
+					return true, isPrimaryService, pip.PublicIPAddressPropertiesFormat.PublicIPAddressVersion
+				}
+			}
+			klog.V(6).Infof("serviceOwnsFrontendIP: the public IP with ID %s is being referenced by other service with public IP address %s "+
+				"OR it is of incorrect IP version", *pip.ID, *pip.IPAddress)
 		}
+
+		return false, isPrimaryService, ""
 	}
-	return false
+
+	// for internal secondary service the private IP address on the frontend IP config should be checked
+	if fip.PrivateIPAddress == nil {
+		return false, isPrimaryService, ""
+	}
+	privateIPAddrVersion := network.IPv4
+	if net.ParseIP(*fip.PrivateIPAddress).To4() == nil {
+		privateIPAddrVersion = network.IPv6
+	}
+
+	privateIPEquals := false
+	for _, loadBalancerIP := range loadBalancerIPs {
+		if strings.EqualFold(*fip.PrivateIPAddress, loadBalancerIP) {
+			privateIPEquals = true
+			break
+		}
+	}
+	return privateIPEquals, isPrimaryService, privateIPAddrVersion
+}
+
+func (az *Cloud) getFrontendIPConfigNames(service *v1.Service) map[bool]string {
+	isDualStack := isServiceDualStack(service)
+	defaultLBFrontendIPConfigName := az.getDefaultFrontendIPConfigName(service)
+	return map[bool]string{
+		consts.IPVersionIPv4: getResourceByIPFamily(defaultLBFrontendIPConfigName, isDualStack, consts.IPVersionIPv4),
+		consts.IPVersionIPv6: getResourceByIPFamily(defaultLBFrontendIPConfigName, isDualStack, consts.IPVersionIPv6),
+	}
+}
+
+func (az *Cloud) getDefaultFrontendIPConfigName(service *v1.Service) string {
+	baseName := az.GetLoadBalancerName(context.TODO(), "", service)
+	subnetName := getInternalSubnet(service)
+	if subnetName != nil {
+		ipcName := fmt.Sprintf("%s-%s", baseName, *subnetName)
+
+		// Azure lb front end configuration name must not exceed 80 characters
+		maxLength := consts.FrontendIPConfigNameMaxLength - consts.IPFamilySuffixLength
+		if len(ipcName) > maxLength {
+			ipcName = ipcName[:maxLength]
+			// Cutting the string may result in char like "-" as the string end.
+			// If the last char is not a letter or '_', replace it with "_".
+			if !unicode.IsLetter(rune(ipcName[len(ipcName)-1:][0])) && ipcName[len(ipcName)-1:] != "_" {
+				ipcName = ipcName[:len(ipcName)-1] + "_"
+			}
+		}
+		return ipcName
+	}
+	return baseName
 }
 
 // This returns the next available rule priority level for a given set of security rules.
diff --git a/pkg/provider/azure_utils.go b/pkg/provider/azure_utils.go
index d038fc4ce..610cd83b4 100644
--- a/pkg/provider/azure_utils.go
+++ b/pkg/provider/azure_utils.go
@@ -426,14 +426,6 @@ func getServicePIPName(service *v1.Service, isIPv6 bool) string {
 	return service.Annotations[consts.ServiceAnnotationPIPNameDualStack[isIPv6]]
 }
 
-func getServicePIPNames(service *v1.Service) []string {
-	var ips []string
-	for _, ipVersion := range []bool{IPVersionIPv4, IPVersionIPv6} {
-		ips = append(ips, getServicePIPName(service, ipVersion))
-	}
-	return ips
-}
-
 func getServicePIPPrefixID(service *v1.Service, isIPv6 bool) string {
 	if service == nil {
 		return ""


Test patch:
diff --git a/.pipelines/scripts/run-e2e.sh b/.pipelines/scripts/run-e2e.sh
index 1bb767283..1b2a4dca9 100755
--- a/.pipelines/scripts/run-e2e.sh
+++ b/.pipelines/scripts/run-e2e.sh
@@ -59,6 +59,10 @@ get_k8s_version() {
 }
 
 cleanup() {
+  if [[ "${SKIP_COLLECT_LOG_AND_CLEAN_UP:-}" == "true" ]]; then
+    return
+  fi
+
   if [[ -n ${KUBECONFIG:-} ]]; then
       kubectl get node -owide || echo "Unable to get nodes"
       kubectl get pod --all-namespaces=true -owide || echo "Unable to get pods"
@@ -92,43 +96,51 @@ if [[ -z "${CLUSTER_CONFIG_PATH:-}" ]]; then
     export AZURE_LOADBALANCER_SKU=standard
   fi
 fi
+echo "Choose cluster config file: ${CLUSTER_CONFIG_PATH:-}"
 
-# basic-lb and vmas
-CUSTOM_CONFIG_PATH="${CUSTOM_CONFIG_PATH:-${REPO_ROOT}/.pipelines/templates/customconfiguration.json}"
-if [[ "${CLUSTER_TYPE:-}" == "autoscaling" ]]; then
-  CUSTOM_CONFIG_PATH="${CUSTOM_CONFIG_PATH:-${REPO_ROOT}/.pipelines/templates/customconfiguration-autoscaling.json}"
-elif [[ "${CLUSTER_TYPE:-}" == "autoscaling-multipool" ]]; then
-  CUSTOM_CONFIG_PATH="${CUSTOM_CONFIG_PATH:-${REPO_ROOT}/.pipelines/templates/customconfiguration-autoscaling-multipool.json}"
+if [[ -z "${CUSTOM_CONFIG_PATH:-}" ]]; then
+  # basic-lb and vmas
+  CUSTOM_CONFIG_PATH="${REPO_ROOT}/.pipelines/templates/customconfiguration.json"
+  if [[ "${CLUSTER_TYPE:-}" == "autoscaling" ]]; then
+    CUSTOM_CONFIG_PATH="${REPO_ROOT}/.pipelines/templates/customconfiguration-autoscaling.json"
+  elif [[ "${CLUSTER_TYPE:-}" == "autoscaling-multipool" ]]; then
+    CUSTOM_CONFIG_PATH="${REPO_ROOT}/.pipelines/templates/customconfiguration-autoscaling-multipool.json"
+  fi
 fi
+echo "Choose custom config file: ${CUSTOM_CONFIG_PATH:-}"
 
-rm -rf kubetest2-aks
-git clone https://github.com/kubernetes-sigs/cloud-provider-azure.git
-cp -r cloud-provider-azure/kubetest2-aks .
-rm -rf cloud-provider-azure
-git config --global --add safe.directory "$(pwd)" || true
-pushd kubetest2-aks
-go get -d sigs.k8s.io/kubetest2@latest
-go install sigs.k8s.io/kubetest2@latest
-go mod tidy
-make deployer
-if [[ -n "${RELEASE_PIPELINE:-}" ]]; then
-  make install
-else
-  sudo GOPATH="/home/vsts/go" make install
+if [[ "${SKIP_BUILD_KUBETEST2_AKS:-}" != "true" ]]; then
+  rm -rf kubetest2-aks
+  git clone https://github.com/kubernetes-sigs/cloud-provider-azure.git
+  cp -r cloud-provider-azure/kubetest2-aks .
+  rm -rf cloud-provider-azure
+  git config --global --add safe.directory "$(pwd)" || true
+  pushd kubetest2-aks
+  go get -d sigs.k8s.io/kubetest2@latest
+  go install sigs.k8s.io/kubetest2@latest
+  go mod tidy
+  make deployer
+  if [[ -n "${RELEASE_PIPELINE:-}" ]]; then
+    make install
+  else
+    sudo GOPATH="/home/vsts/go" make install
+  fi
+  popd
 fi
-popd
 
 get_k8s_version
 echo "AKS Kubernetes version is: ${AKS_KUBERNETES_VERSION:-}"
 
-if [[ -n "${RELEASE_PIPELINE:-}" ]]; then
-  rm -rf kubetest2-aks
-  if [[ "${AKS_KUBERNETES_VERSION:-}" < "1.24" ]]; then
-    go mod tidy -compat=1.17
-  else
-    go mod tidy
+if [[ "${SKIP_BUILD_KUBETEST2_AKS:-}" != "true" ]]; then
+  if [[ -n "${RELEASE_PIPELINE:-}" ]]; then
+    rm -rf kubetest2-aks
+    if [[ "${AKS_KUBERNETES_VERSION:-}" < "1.24" ]]; then
+      go mod tidy -compat=1.17
+    else
+      go mod tidy
+    fi
+    go mod vendor
   fi
-  go mod vendor
 fi
 
 kubetest2 aks --up --rgName "${RESOURCE_GROUP:-}" \
@@ -157,11 +169,21 @@ done
 kubectl wait --for=condition=Ready node --all --timeout=5m
 kubectl get node -owide
 
-echo "Running e2e"
-
-export E2E_ON_AKS_CLUSTER=true
 if [[ "${CLUSTER_TYPE:-}" =~ "autoscaling" ]]; then
-  export LABEL_FILTER=${LABEL_FILTER:-Feature:Autoscaling || !Serial && !Slow}
-  export SKIP_ARGS=${SKIP_ARGS:-""}
+  az aks update --subscription ${AZURE_SUBSCRIPTION_ID:-} --resource-group "${RESOURCE_GROUP:-}" --name "${CLUSTER_NAME:-}" \
+    --cluster-autoscaler-profile skip-nodes-with-system-pods=false scale-down-delay-after-add=1m scale-down-unneeded-time=1m scale-down-unready-time=2m
+  if [[ "${CLUSTER_TYPE:-}" == "autoscaling-multipool" ]]; then
+    az aks update --subscription ${AZURE_SUBSCRIPTION_ID:-} --resource-group "${RESOURCE_GROUP:-}" --name "${CLUSTER_NAME:-}" \
+      --cluster-autoscaler-profile balance-similar-node-groups=true
+  fi
+fi
+
+if [[ "${SKIP_E2E:-}" != "true" ]]; then
+  echo "Running e2e"
+  export E2E_ON_AKS_CLUSTER=true
+  if [[ "${CLUSTER_TYPE:-}" =~ "autoscaling" ]]; then
+    export LABEL_FILTER=${LABEL_FILTER:-Feature:Autoscaling || !Serial && !Slow}
+    export SKIP_ARGS=${SKIP_ARGS:-""}
+  fi
+  make test-ccm-e2e
 fi
-make test-ccm-e2e
diff --git a/pkg/provider/azure_loadbalancer_test.go b/pkg/provider/azure_loadbalancer_test.go
index 925f570cb..8a8e0c1d2 100644
--- a/pkg/provider/azure_loadbalancer_test.go
+++ b/pkg/provider/azure_loadbalancer_test.go
@@ -791,7 +791,6 @@ func TestServiceOwnsPublicIP(t *testing.T) {
 		clusterName             string
 		serviceName             string
 		serviceLBIP             string
-		serviceLBName           string
 		expectedOwns            bool
 		expectedUserAssignedPIP bool
 	}{
@@ -804,7 +803,6 @@ func TestServiceOwnsPublicIP(t *testing.T) {
 		{
 			desc: "false should be returned when service name tag doesn't match",
 			pip: &network.PublicIPAddress{
-				Name: pointer.String("pip1"),
 				Tags: map[string]*string{
 					consts.ServiceTagKey: pointer.String("default/nginx"),
 				},
@@ -847,7 +845,6 @@ func TestServiceOwnsPublicIP(t *testing.T) {
 		{
 			desc: "false should be returned when cluster name matches while service name doesn't match",
 			pip: &network.PublicIPAddress{
-				Name: pointer.String("pip1"),
 				Tags: map[string]*string{
 					consts.ServiceTagKey:  pointer.String("default/web"),
 					consts.ClusterNameKey: pointer.String("kubernetes"),
@@ -878,7 +875,6 @@ func TestServiceOwnsPublicIP(t *testing.T) {
 		{
 			desc: "false should be returned when the tag is empty and load balancer IP does not match",
 			pip: &network.PublicIPAddress{
-				Name: pointer.String("pip1"),
 				Tags: map[string]*string{
 					consts.ServiceTagKey:  pointer.String(""),
 					consts.ClusterNameKey: pointer.String("kubernetes"),
@@ -910,7 +906,6 @@ func TestServiceOwnsPublicIP(t *testing.T) {
 		{
 			desc: "false should be returned if there is not a match among a multi-service tag",
 			pip: &network.PublicIPAddress{
-				Name: pointer.String("pip1"),
 				Tags: map[string]*string{
 					consts.ServiceTagKey:  pointer.String("default/nginx1,default/nginx2"),
 					consts.ClusterNameKey: pointer.String("kubernetes"),
@@ -967,45 +962,6 @@ func TestServiceOwnsPublicIP(t *testing.T) {
 			expectedOwns:            true,
 			expectedUserAssignedPIP: true,
 		},
-		{
-			desc: "should be true if the pip name matches",
-			pip: &network.PublicIPAddress{
-				Name: pointer.String("pip1"),
-				PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-					IPAddress: pointer.String("1.2.3.4"),
-				},
-			},
-			serviceLBName:           "pip1",
-			expectedOwns:            true,
-			expectedUserAssignedPIP: true,
-		},
-		{
-			desc: "should be true if the pip with tag matches the pip name",
-			pip: &network.PublicIPAddress{
-				Name: pointer.String("pip1"),
-				Tags: map[string]*string{},
-				PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-					IPAddress: pointer.String("1.2.3.4"),
-				},
-			},
-			serviceLBName:           "pip1",
-			expectedOwns:            true,
-			expectedUserAssignedPIP: true,
-		},
-		{
-			desc: "should be true if the pip with service tag matches the pip name",
-			pip: &network.PublicIPAddress{
-				Name: pointer.String("pip1"),
-				Tags: map[string]*string{
-					consts.ServiceTagKey: pointer.String("default/web"),
-				},
-				PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-					IPAddress: pointer.String("1.2.3.4"),
-				},
-			},
-			serviceLBName: "pip1",
-			expectedOwns:  true,
-		},
 	}
 
 	for i, c := range tests {
@@ -1014,13 +970,6 @@ func TestServiceOwnsPublicIP(t *testing.T) {
 			if c.serviceLBIP != "" {
 				setServiceLoadBalancerIP(&service, c.serviceLBIP)
 			}
-			if c.serviceLBName != "" {
-				if service.ObjectMeta.Annotations == nil {
-					service.ObjectMeta.Annotations = map[string]string{consts.ServiceAnnotationPIPNameDualStack[false]: "pip1"}
-				} else {
-					service.ObjectMeta.Annotations[consts.ServiceAnnotationPIPNameDualStack[false]] = "pip1"
-				}
-			}
 			owns, isUserAssignedPIP := serviceOwnsPublicIP(&service, c.pip, c.clusterName)
 			assert.Equal(t, c.expectedOwns, owns, "TestCase[%d]: %s", i, c.desc)
 			assert.Equal(t, c.expectedUserAssignedPIP, isUserAssignedPIP, "TestCase[%d]: %s", i, c.desc)
@@ -2094,6 +2043,59 @@ func TestIsFrontendIPChanged(t *testing.T) {
 	}
 }
 
+func TestFindMatchedPIPByLoadBalancerIP(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	testPIP := network.PublicIPAddress{
+		Name: pointer.String("pipName"),
+		PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+			IPAddress: pointer.String("1.2.3.4"),
+		},
+	}
+	testCases := []struct {
+		desc               string
+		pips               []network.PublicIPAddress
+		shouldRefreshCache bool
+		expectedPIP        *network.PublicIPAddress
+		expectedError      bool
+	}{
+		{
+			desc:        "findMatchedPIPByLoadBalancerIP shall return the matched ip",
+			pips:        []network.PublicIPAddress{testPIP},
+			expectedPIP: &testPIP,
+		},
+		{
+			desc:               "findMatchedPIPByLoadBalancerIP shall return error if ip is not found",
+			pips:               []network.PublicIPAddress{},
+			shouldRefreshCache: true,
+			expectedError:      true,
+		},
+		{
+			desc:               "findMatchedPIPByLoadBalancerIP should refresh cache if no matched ip is found",
+			pips:               []network.PublicIPAddress{testPIP},
+			shouldRefreshCache: true,
+			expectedPIP:        &testPIP,
+		},
+	}
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			az := GetTestCloud(ctrl)
+			service := getTestService("test1", v1.ProtocolTCP, nil, false, 80)
+			setServiceLoadBalancerIP(&service, "1.2.3.4")
+
+			mockPIPsClient := az.PublicIPAddressesClient.(*mockpublicipclient.MockInterface)
+			if test.shouldRefreshCache {
+				mockPIPsClient.EXPECT().List(gomock.Any(), "rg").Return([]network.PublicIPAddress{}, nil)
+			}
+			mockPIPsClient.EXPECT().List(gomock.Any(), "rg").Return(test.pips, nil)
+			pip, err := az.findMatchedPIPByLoadBalancerIP(&service, "1.2.3.4", "rg")
+			assert.Equal(t, test.expectedPIP, pip)
+			assert.Equal(t, test.expectedError, err != nil)
+		})
+	}
+}
+
 func TestDeterminePublicIPName(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
@@ -7775,446 +7777,3 @@ func TestReconcileMultipleStandardLoadBalancerConfigurations(t *testing.T) {
 		})
 	}
 }
-
-func TestGetFrontendIPConfigName(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-	az := GetTestCloud(ctrl)
-	az.PrimaryAvailabilitySetName = primary
-
-	svc := &v1.Service{
-		ObjectMeta: metav1.ObjectMeta{
-			Annotations: map[string]string{
-				consts.ServiceAnnotationLoadBalancerInternalSubnet: "subnet",
-				consts.ServiceAnnotationLoadBalancerInternal:       "true",
-			},
-			UID: "257b9655-5137-4ad2-b091-ef3f07043ad3",
-		},
-	}
-
-	cases := []struct {
-		description   string
-		subnetName    string
-		isInternal    bool
-		useStandardLB bool
-		expected      string
-	}{
-		{
-			description:   "internal lb should have subnet name on the frontend ip configuration name",
-			subnetName:    "shortsubnet",
-			isInternal:    true,
-			useStandardLB: true,
-			expected:      "a257b965551374ad2b091ef3f07043ad-shortsubnet",
-		},
-		{
-			description:   "internal lb should have subnet name on the frontend ip configuration name but truncated to 80 characters, also not end with char like '-'",
-			subnetName:    "a--------------------------------------------------z",
-			isInternal:    true,
-			useStandardLB: true,
-			expected:      "a257b965551374ad2b091ef3f07043ad-a----------------------------------------_",
-		},
-		{
-			description:   "internal standard lb should have subnet name on the frontend ip configuration name but truncated to 80 characters",
-			subnetName:    "averylonnnngggnnnnnnnnnnnnnnnnnnnnnngggggggggggggggggggggggggggggggggggggsubet",
-			isInternal:    true,
-			useStandardLB: true,
-			expected:      "a257b965551374ad2b091ef3f07043ad-averylonnnngggnnnnnnnnnnnnnnnnnnnnnngggggg",
-		},
-		{
-			description:   "internal basic lb should have subnet name on the frontend ip configuration name but truncated to 80 characters",
-			subnetName:    "averylonnnngggnnnnnnnnnnnnnnnnnnnnnngggggggggggggggggggggggggggggggggggggsubet",
-			isInternal:    true,
-			useStandardLB: false,
-			expected:      "a257b965551374ad2b091ef3f07043ad-averylonnnngggnnnnnnnnnnnnnnnnnnnnnngggggg",
-		},
-		{
-			description:   "external standard lb should not have subnet name on the frontend ip configuration name",
-			subnetName:    "shortsubnet",
-			isInternal:    false,
-			useStandardLB: true,
-			expected:      "a257b965551374ad2b091ef3f07043ad",
-		},
-		{
-			description:   "external basic lb should not have subnet name on the frontend ip configuration name",
-			subnetName:    "shortsubnet",
-			isInternal:    false,
-			useStandardLB: false,
-			expected:      "a257b965551374ad2b091ef3f07043ad",
-		},
-	}
-
-	for _, c := range cases {
-		t.Run(c.description, func(t *testing.T) {
-			if c.useStandardLB {
-				az.Config.LoadBalancerSku = consts.LoadBalancerSkuStandard
-			} else {
-				az.Config.LoadBalancerSku = consts.LoadBalancerSkuBasic
-			}
-			svc.Annotations[consts.ServiceAnnotationLoadBalancerInternalSubnet] = c.subnetName
-			svc.Annotations[consts.ServiceAnnotationLoadBalancerInternal] = strconv.FormatBool(c.isInternal)
-
-			ipconfigName := az.getDefaultFrontendIPConfigName(svc)
-			assert.Equal(t, c.expected, ipconfigName)
-		})
-	}
-}
-
-func TestGetFrontendIPConfigNames(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-	az := GetTestCloud(ctrl)
-	az.PrimaryAvailabilitySetName = primary
-
-	svc := &v1.Service{
-		ObjectMeta: metav1.ObjectMeta{
-			Annotations: map[string]string{
-				consts.ServiceAnnotationLoadBalancerInternalSubnet: "subnet",
-				consts.ServiceAnnotationLoadBalancerInternal:       "true",
-			},
-			UID: "257b9655-5137-4ad2-b091-ef3f07043ad3",
-		},
-		Spec: v1.ServiceSpec{
-			IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
-		},
-	}
-
-	cases := []struct {
-		description   string
-		subnetName    string
-		isInternal    bool
-		useStandardLB bool
-		expectedV4    string
-		expectedV6    string
-	}{
-		{
-			description:   "internal lb should have subnet name on the frontend ip configuration name",
-			subnetName:    "shortsubnet",
-			isInternal:    true,
-			useStandardLB: true,
-			expectedV4:    "a257b965551374ad2b091ef3f07043ad-shortsubnet",
-			expectedV6:    "a257b965551374ad2b091ef3f07043ad-shortsubnet-IPv6",
-		},
-	}
-
-	for _, c := range cases {
-		t.Run(c.description, func(t *testing.T) {
-			if c.useStandardLB {
-				az.Config.LoadBalancerSku = consts.LoadBalancerSkuStandard
-			} else {
-				az.Config.LoadBalancerSku = consts.LoadBalancerSkuBasic
-			}
-			svc.Annotations[consts.ServiceAnnotationLoadBalancerInternalSubnet] = c.subnetName
-			svc.Annotations[consts.ServiceAnnotationLoadBalancerInternal] = strconv.FormatBool(c.isInternal)
-
-			ipconfigNames := az.getFrontendIPConfigNames(svc)
-			assert.Equal(t, c.expectedV4, ipconfigNames[false])
-			assert.Equal(t, c.expectedV6, ipconfigNames[true])
-		})
-	}
-}
-
-func TestServiceOwnsFrontendIP(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	testCases := []struct {
-		desc                 string
-		existingPIPs         []network.PublicIPAddress
-		fip                  network.FrontendIPConfiguration
-		service              *v1.Service
-		isOwned              bool
-		isPrimary            bool
-		expectedFIPIPVersion network.IPVersion
-		listError            *retry.Error
-	}{
-		{
-			desc: "serviceOwnsFrontendIP should detect the primary service",
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID: types.UID("uid"),
-				},
-			},
-			isOwned:   true,
-			isPrimary: true,
-		},
-		{
-			desc: "serviceOwnsFrontendIP should return false if the secondary external service doesn't set it's loadBalancer IP",
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID: types.UID("secondary"),
-				},
-			},
-		},
-		{
-			desc: "serviceOwnsFrontendIP should report a not found error if there is no public IP " +
-				"found according to the external service's loadBalancer IP but do not return the error",
-			existingPIPs: []network.PublicIPAddress{
-				{
-					ID: pointer.String("pip"),
-					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-						IPAddress: pointer.String("4.3.2.1"),
-					},
-				},
-			},
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PublicIPAddress: &network.PublicIPAddress{
-						ID: pointer.String("pip"),
-					},
-				},
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID:         types.UID("secondary"),
-					Annotations: map[string]string{consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "1.2.3.4"},
-				},
-			},
-		},
-		{
-			desc: "serviceOwnsFrontendIP should return correct FIP IP version",
-			existingPIPs: []network.PublicIPAddress{
-				{
-					ID: pointer.String("pip"),
-					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-						IPAddress:              pointer.String("4.3.2.1"),
-						PublicIPAddressVersion: network.IPv4,
-					},
-				},
-			},
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PublicIPAddress: &network.PublicIPAddress{
-						ID: pointer.String("pip"),
-					},
-				},
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID:         types.UID("secondary"),
-					Annotations: map[string]string{consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1"},
-				},
-			},
-			expectedFIPIPVersion: network.IPv4,
-			isOwned:              true,
-		},
-		{
-			desc: "serviceOwnsFrontendIP should return false if there is a mismatch between the PIP's ID and " +
-				"the counterpart on the frontend IP config",
-			existingPIPs: []network.PublicIPAddress{
-				{
-					ID: pointer.String("pip"),
-					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-						IPAddress: pointer.String("4.3.2.1"),
-					},
-				},
-			},
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PublicIPAddress: &network.PublicIPAddress{
-						ID: pointer.String("pip1"),
-					},
-				},
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID:         types.UID("secondary"),
-					Annotations: map[string]string{consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1"},
-				},
-			},
-		},
-		{
-			desc: "serviceOwnsFrontendIP should return false if there is no public IP address in the frontend IP config",
-			existingPIPs: []network.PublicIPAddress{
-				{
-					ID: pointer.String("pip"),
-					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-						IPAddress: pointer.String("4.3.2.1"),
-					},
-				},
-			},
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PublicIPPrefix: &network.SubResource{
-						ID: pointer.String("pip1"),
-					},
-				},
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID: types.UID("secondary"),
-					Annotations: map[string]string{
-						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
-					},
-				},
-			},
-		},
-		{
-			desc: "serviceOwnsFrontendIP should detect the secondary external service",
-			existingPIPs: []network.PublicIPAddress{
-				{
-					ID: pointer.String("pip"),
-					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-						IPAddress: pointer.String("4.3.2.1"),
-					},
-				},
-			},
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PublicIPAddress: &network.PublicIPAddress{
-						ID: pointer.String("pip"),
-					},
-				},
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID: types.UID("secondary"),
-					Annotations: map[string]string{
-						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
-						consts.ServiceAnnotationLoadBalancerIPDualStack[true]:  "fd00::eef0",
-					},
-				},
-			},
-			isOwned: true,
-		},
-		{
-			desc: "serviceOwnsFrontendIP should detect the secondary external service dual-stack",
-			existingPIPs: []network.PublicIPAddress{
-				{
-					Name: pointer.String("pip"),
-					ID:   pointer.String("pip"),
-					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-						PublicIPAddressVersion: network.IPv4,
-						IPAddress:              pointer.String("4.3.2.1"),
-					},
-				},
-				{
-					Name: pointer.String("pip1"),
-					ID:   pointer.String("pip1"),
-					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-						PublicIPAddressVersion: network.IPv6,
-						IPAddress:              pointer.String("fd00::eef0"),
-					},
-				},
-			},
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PublicIPAddress: &network.PublicIPAddress{
-						PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-							PublicIPAddressVersion: network.IPv6,
-						},
-						ID: pointer.String("pip1"),
-					},
-				},
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID: types.UID("secondary"),
-					Annotations: map[string]string{
-						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
-						consts.ServiceAnnotationLoadBalancerIPDualStack[true]:  "fd00::eef0",
-					},
-				},
-			},
-			isOwned:   true,
-			isPrimary: false,
-		},
-		{
-			desc: "serviceOwnsFrontendIP should detect the secondary internal service",
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PrivateIPAddress: pointer.String("4.3.2.1"),
-				},
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID: types.UID("secondary"),
-					Annotations: map[string]string{
-						consts.ServiceAnnotationLoadBalancerInternal:           "true",
-						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
-					},
-				},
-			},
-			isOwned: true,
-		},
-		{
-			desc: "serviceOwnsFrontendIP should detect the secondary internal service - dualstack",
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("auid"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PrivateIPAddress: pointer.String("fd00::eef0"),
-				},
-			},
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					UID: types.UID("secondary"),
-					Annotations: map[string]string{
-						consts.ServiceAnnotationLoadBalancerInternal:           "true",
-						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
-						consts.ServiceAnnotationLoadBalancerIPDualStack[true]:  "fd00::eef0",
-					},
-				},
-			},
-			isOwned: true,
-		},
-		{
-			desc:      "serviceOwnsFrontendIP should return false if failed to find matched pip by name",
-			service:   &v1.Service{},
-			listError: retry.NewError(false, errors.New("error")),
-		},
-		{
-			desc: "serviceOwnsFrontnedIP should support search pip by name",
-			service: &v1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{consts.ServiceAnnotationPIPNameDualStack[false]: "pip1"},
-				},
-			},
-			existingPIPs: []network.PublicIPAddress{
-				{
-					Name: pointer.String("pip1"),
-					ID:   pointer.String("pip1"),
-					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-						IPAddress: pointer.String("1.2.3.4"),
-					},
-				},
-			},
-			fip: network.FrontendIPConfiguration{
-				Name: pointer.String("test"),
-				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
-					PublicIPAddress: &network.PublicIPAddress{
-						ID: pointer.String("pip1"),
-					},
-				},
-			},
-			isOwned: true,
-		},
-	}
-
-	for _, test := range testCases {
-		t.Run(test.desc, func(t *testing.T) {
-			cloud := GetTestCloud(ctrl)
-			if test.existingPIPs != nil {
-				mockPIPsClient := cloud.PublicIPAddressesClient.(*mockpublicipclient.MockInterface)
-				mockPIPsClient.EXPECT().List(gomock.Any(), "rg").Return(test.existingPIPs, test.listError).MaxTimes(2)
-			}
-			isOwned, isPrimary, fipIPVersion := cloud.serviceOwnsFrontendIP(test.fip, test.service)
-			if test.expectedFIPIPVersion != "" {
-				assert.Equal(t, test.expectedFIPIPVersion, fipIPVersion)
-			}
-			assert.Equal(t, test.isOwned, isOwned)
-			assert.Equal(t, test.isPrimary, isPrimary)
-		})
-	}
-}
diff --git a/pkg/provider/azure_publicip_repo_test.go b/pkg/provider/azure_publicip_repo_test.go
index 7daa41acb..cbe272328 100644
--- a/pkg/provider/azure_publicip_repo_test.go
+++ b/pkg/provider/azure_publicip_repo_test.go
@@ -17,7 +17,6 @@ limitations under the License.
 package provider
 
 import (
-	"errors"
 	"fmt"
 	"net/http"
 	"sync"
@@ -206,130 +205,3 @@ func TestGetPublicIPAddress(t *testing.T) {
 		})
 	}
 }
-
-func TestFindMatchedPIP(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	testPIP := network.PublicIPAddress{
-		Name: pointer.String("pipName"),
-		PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-			IPAddress: pointer.String("1.2.3.4"),
-		},
-	}
-
-	for _, tc := range []struct {
-		description         string
-		pips                []network.PublicIPAddress
-		pipsSecondTime      []network.PublicIPAddress
-		pipName             string
-		loadBalancerIP      string
-		shouldRefreshCache  bool
-		listError           *retry.Error
-		listErrorSecondTime *retry.Error
-		expectedPIP         *network.PublicIPAddress
-		expectedError       error
-	}{
-		{
-			description:        "should ignore pipName if loadBalancerIP is specified",
-			pips:               []network.PublicIPAddress{testPIP},
-			pipsSecondTime:     []network.PublicIPAddress{testPIP},
-			shouldRefreshCache: true,
-			loadBalancerIP:     "2.3.4.5",
-			pipName:            "pipName",
-			expectedError:      errors.New("findMatchedPIPByLoadBalancerIP: cannot find public IP with IP address 2.3.4.5 in resource group rg"),
-		},
-		{
-			description:   "should report an error if failed to list pip",
-			listError:     retry.NewError(false, errors.New("list error")),
-			expectedError: errors.New("findMatchedPIPByLoadBalancerIP: failed to listPIP: Retriable: false, RetryAfter: 0s, HTTPStatusCode: 0, RawError: list error"),
-		},
-		{
-			description:        "should refresh the cache if failed to search by name",
-			pips:               []network.PublicIPAddress{},
-			pipsSecondTime:     []network.PublicIPAddress{testPIP},
-			shouldRefreshCache: true,
-			pipName:            "pipName",
-			expectedPIP:        &testPIP,
-		},
-		{
-			description: "should return the expected pip by name",
-			pips:        []network.PublicIPAddress{testPIP},
-			pipName:     "pipName",
-			expectedPIP: &testPIP,
-		},
-		{
-			description:         "should report an error if failed to list pip second time",
-			pips:                []network.PublicIPAddress{},
-			listErrorSecondTime: retry.NewError(false, errors.New("list error")),
-			shouldRefreshCache:  true,
-			expectedError:       errors.New("findMatchedPIPByName: failed to listPIP force refresh: Retriable: false, RetryAfter: 0s, HTTPStatusCode: 0, RawError: list error"),
-		},
-	} {
-		t.Run(tc.description, func(t *testing.T) {
-			az := GetTestCloud(ctrl)
-			mockPIPsClient := az.PublicIPAddressesClient.(*mockpublicipclient.MockInterface)
-			mockPIPsClient.EXPECT().List(gomock.Any(), "rg").Return(tc.pips, tc.listError)
-			if tc.shouldRefreshCache {
-				mockPIPsClient.EXPECT().List(gomock.Any(), "rg").Return(tc.pipsSecondTime, tc.listErrorSecondTime)
-			}
-
-			pip, err := az.findMatchedPIP(tc.loadBalancerIP, tc.pipName, "rg")
-			assert.Equal(t, tc.expectedPIP, pip)
-			if tc.expectedError != nil {
-				assert.Equal(t, tc.expectedError.Error(), err.Error())
-			}
-		})
-	}
-}
-
-func TestFindMatchedPIPByLoadBalancerIP(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	testPIP := network.PublicIPAddress{
-		Name: pointer.String("pipName"),
-		PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
-			IPAddress: pointer.String("1.2.3.4"),
-		},
-	}
-	testCases := []struct {
-		desc               string
-		pips               []network.PublicIPAddress
-		pipsSecondTime     []network.PublicIPAddress
-		shouldRefreshCache bool
-		expectedPIP        *network.PublicIPAddress
-		expectedError      bool
-	}{
-		{
-			desc:        "findMatchedPIPByLoadBalancerIP shall return the matched ip",
-			pips:        []network.PublicIPAddress{testPIP},
-			expectedPIP: &testPIP,
-		},
-		{
-			desc:               "findMatchedPIPByLoadBalancerIP shall return error if ip is not found",
-			pips:               []network.PublicIPAddress{},
-			shouldRefreshCache: true,
-			expectedError:      true,
-		},
-		{
-			desc:               "findMatchedPIPByLoadBalancerIP should refresh cache if no matched ip is found",
-			pipsSecondTime:     []network.PublicIPAddress{testPIP},
-			shouldRefreshCache: true,
-			expectedPIP:        &testPIP,
-		},
-	}
-	for _, test := range testCases {
-		t.Run(test.desc, func(t *testing.T) {
-			az := GetTestCloud(ctrl)
-
-			mockPIPsClient := az.PublicIPAddressesClient.(*mockpublicipclient.MockInterface)
-			if test.shouldRefreshCache {
-				mockPIPsClient.EXPECT().List(gomock.Any(), "rg").Return(test.pipsSecondTime, nil)
-			}
-			pip, err := az.findMatchedPIPByLoadBalancerIP(&test.pips, "1.2.3.4", "rg")
-			assert.Equal(t, test.expectedPIP, pip)
-			assert.Equal(t, test.expectedError, err != nil)
-		})
-	}
-}
diff --git a/pkg/provider/azure_standard_test.go b/pkg/provider/azure_standard_test.go
index b6c6dba3c..29c8db003 100644
--- a/pkg/provider/azure_standard_test.go
+++ b/pkg/provider/azure_standard_test.go
@@ -36,6 +36,7 @@ import (
 	"k8s.io/utils/pointer"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/interfaceclient/mockinterfaceclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/publicipclient/mockpublicipclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmasclient/mockvmasclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmclient/mockvmclient"
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
@@ -415,6 +416,143 @@ func TestGetloadbalancerHAmodeRuleName(t *testing.T) {
 	}
 }
 
+func TestGetFrontendIPConfigName(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	az := GetTestCloud(ctrl)
+	az.PrimaryAvailabilitySetName = primary
+
+	svc := &v1.Service{
+		ObjectMeta: meta.ObjectMeta{
+			Annotations: map[string]string{
+				consts.ServiceAnnotationLoadBalancerInternalSubnet: "subnet",
+				consts.ServiceAnnotationLoadBalancerInternal:       "true",
+			},
+			UID: "257b9655-5137-4ad2-b091-ef3f07043ad3",
+		},
+	}
+
+	cases := []struct {
+		description   string
+		subnetName    string
+		isInternal    bool
+		useStandardLB bool
+		expected      string
+	}{
+		{
+			description:   "internal lb should have subnet name on the frontend ip configuration name",
+			subnetName:    "shortsubnet",
+			isInternal:    true,
+			useStandardLB: true,
+			expected:      "a257b965551374ad2b091ef3f07043ad-shortsubnet",
+		},
+		{
+			description:   "internal lb should have subnet name on the frontend ip configuration name but truncated to 80 characters, also not end with char like '-'",
+			subnetName:    "a--------------------------------------------------z",
+			isInternal:    true,
+			useStandardLB: true,
+			expected:      "a257b965551374ad2b091ef3f07043ad-a----------------------------------------_",
+		},
+		{
+			description:   "internal standard lb should have subnet name on the frontend ip configuration name but truncated to 80 characters",
+			subnetName:    "averylonnnngggnnnnnnnnnnnnnnnnnnnnnngggggggggggggggggggggggggggggggggggggsubet",
+			isInternal:    true,
+			useStandardLB: true,
+			expected:      "a257b965551374ad2b091ef3f07043ad-averylonnnngggnnnnnnnnnnnnnnnnnnnnnngggggg",
+		},
+		{
+			description:   "internal basic lb should have subnet name on the frontend ip configuration name but truncated to 80 characters",
+			subnetName:    "averylonnnngggnnnnnnnnnnnnnnnnnnnnnngggggggggggggggggggggggggggggggggggggsubet",
+			isInternal:    true,
+			useStandardLB: false,
+			expected:      "a257b965551374ad2b091ef3f07043ad-averylonnnngggnnnnnnnnnnnnnnnnnnnnnngggggg",
+		},
+		{
+			description:   "external standard lb should not have subnet name on the frontend ip configuration name",
+			subnetName:    "shortsubnet",
+			isInternal:    false,
+			useStandardLB: true,
+			expected:      "a257b965551374ad2b091ef3f07043ad",
+		},
+		{
+			description:   "external basic lb should not have subnet name on the frontend ip configuration name",
+			subnetName:    "shortsubnet",
+			isInternal:    false,
+			useStandardLB: false,
+			expected:      "a257b965551374ad2b091ef3f07043ad",
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.description, func(t *testing.T) {
+			if c.useStandardLB {
+				az.Config.LoadBalancerSku = consts.LoadBalancerSkuStandard
+			} else {
+				az.Config.LoadBalancerSku = consts.LoadBalancerSkuBasic
+			}
+			svc.Annotations[consts.ServiceAnnotationLoadBalancerInternalSubnet] = c.subnetName
+			svc.Annotations[consts.ServiceAnnotationLoadBalancerInternal] = strconv.FormatBool(c.isInternal)
+
+			ipconfigName := az.getDefaultFrontendIPConfigName(svc)
+			assert.Equal(t, c.expected, ipconfigName)
+		})
+	}
+}
+
+func TestGetFrontendIPConfigNames(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	az := GetTestCloud(ctrl)
+	az.PrimaryAvailabilitySetName = primary
+
+	svc := &v1.Service{
+		ObjectMeta: meta.ObjectMeta{
+			Annotations: map[string]string{
+				consts.ServiceAnnotationLoadBalancerInternalSubnet: "subnet",
+				consts.ServiceAnnotationLoadBalancerInternal:       "true",
+			},
+			UID: "257b9655-5137-4ad2-b091-ef3f07043ad3",
+		},
+		Spec: v1.ServiceSpec{
+			IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
+		},
+	}
+
+	cases := []struct {
+		description   string
+		subnetName    string
+		isInternal    bool
+		useStandardLB bool
+		expectedV4    string
+		expectedV6    string
+	}{
+		{
+			description:   "internal lb should have subnet name on the frontend ip configuration name",
+			subnetName:    "shortsubnet",
+			isInternal:    true,
+			useStandardLB: true,
+			expectedV4:    "a257b965551374ad2b091ef3f07043ad-shortsubnet",
+			expectedV6:    "a257b965551374ad2b091ef3f07043ad-shortsubnet-IPv6",
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.description, func(t *testing.T) {
+			if c.useStandardLB {
+				az.Config.LoadBalancerSku = consts.LoadBalancerSkuStandard
+			} else {
+				az.Config.LoadBalancerSku = consts.LoadBalancerSkuBasic
+			}
+			svc.Annotations[consts.ServiceAnnotationLoadBalancerInternalSubnet] = c.subnetName
+			svc.Annotations[consts.ServiceAnnotationLoadBalancerInternal] = strconv.FormatBool(c.isInternal)
+
+			ipconfigNames := az.getFrontendIPConfigNames(svc)
+			assert.Equal(t, c.expectedV4, ipconfigNames[false])
+			assert.Equal(t, c.expectedV6, ipconfigNames[true])
+		})
+	}
+}
+
 func TestGetFrontendIPConfigID(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
@@ -1596,6 +1734,280 @@ func TestStandardEnsureHostsInPool(t *testing.T) {
 	}
 }
 
+func TestServiceOwnsFrontendIP(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	testCases := []struct {
+		desc                 string
+		existingPIPs         []network.PublicIPAddress
+		fip                  network.FrontendIPConfiguration
+		service              *v1.Service
+		isOwned              bool
+		isPrimary            bool
+		expectedFIPIPVersion network.IPVersion
+	}{
+		{
+			desc: "serviceOwnsFrontendIP should detect the primary service",
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID: types.UID("uid"),
+				},
+			},
+			isOwned:   true,
+			isPrimary: true,
+		},
+		{
+			desc: "serviceOwnsFrontendIP should return false if the secondary external service doesn't set it's loadBalancer IP",
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID: types.UID("secondary"),
+				},
+			},
+		},
+		{
+			desc: "serviceOwnsFrontendIP should report a not found error if there is no public IP " +
+				"found according to the external service's loadBalancer IP but do not return the error",
+			existingPIPs: []network.PublicIPAddress{
+				{
+					ID: pointer.String("pip"),
+					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+						IPAddress: pointer.String("4.3.2.1"),
+					},
+				},
+			},
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
+					PublicIPAddress: &network.PublicIPAddress{
+						ID: pointer.String("pip"),
+					},
+				},
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID:         types.UID("secondary"),
+					Annotations: map[string]string{consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "1.2.3.4"},
+				},
+			},
+		},
+		{
+			desc: "serviceOwnsFrontendIP should return correct FIP IP version",
+			existingPIPs: []network.PublicIPAddress{
+				{
+					ID: pointer.String("pip"),
+					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+						IPAddress:              pointer.String("4.3.2.1"),
+						PublicIPAddressVersion: network.IPv4,
+					},
+				},
+			},
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
+					PublicIPAddress: &network.PublicIPAddress{
+						ID: pointer.String("pip"),
+					},
+				},
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID:         types.UID("secondary"),
+					Annotations: map[string]string{consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1"},
+				},
+			},
+			expectedFIPIPVersion: network.IPv4,
+			isOwned:              true,
+		},
+		{
+			desc: "serviceOwnsFrontendIP should return false if there is a mismatch between the PIP's ID and " +
+				"the counterpart on the frontend IP config",
+			existingPIPs: []network.PublicIPAddress{
+				{
+					ID: pointer.String("pip"),
+					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+						IPAddress: pointer.String("4.3.2.1"),
+					},
+				},
+			},
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
+					PublicIPAddress: &network.PublicIPAddress{
+						ID: pointer.String("pip1"),
+					},
+				},
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID:         types.UID("secondary"),
+					Annotations: map[string]string{consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1"},
+				},
+			},
+		},
+		{
+			desc: "serviceOwnsFrontendIP should return false if there is no public IP address in the frontend IP config",
+			existingPIPs: []network.PublicIPAddress{
+				{
+					ID: pointer.String("pip"),
+					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+						IPAddress: pointer.String("4.3.2.1"),
+					},
+				},
+			},
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
+					PublicIPPrefix: &network.SubResource{
+						ID: pointer.String("pip1"),
+					},
+				},
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID: types.UID("secondary"),
+					Annotations: map[string]string{
+						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
+					},
+				},
+			},
+		},
+		{
+			desc: "serviceOwnsFrontendIP should detect the secondary external service",
+			existingPIPs: []network.PublicIPAddress{
+				{
+					ID: pointer.String("pip"),
+					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+						IPAddress: pointer.String("4.3.2.1"),
+					},
+				},
+			},
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
+					PublicIPAddress: &network.PublicIPAddress{
+						ID: pointer.String("pip"),
+					},
+				},
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID: types.UID("secondary"),
+					Annotations: map[string]string{
+						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
+						consts.ServiceAnnotationLoadBalancerIPDualStack[true]:  "fd00::eef0",
+					},
+				},
+			},
+			isOwned: true,
+		},
+		{
+			desc: "serviceOwnsFrontendIP should detect the secondary external service dual-stack",
+			existingPIPs: []network.PublicIPAddress{
+				{
+					Name: pointer.String("pip"),
+					ID:   pointer.String("pip"),
+					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+						PublicIPAddressVersion: network.IPv4,
+						IPAddress:              pointer.String("4.3.2.1"),
+					},
+				},
+				{
+					Name: pointer.String("pip1"),
+					ID:   pointer.String("pip1"),
+					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+						PublicIPAddressVersion: network.IPv6,
+						IPAddress:              pointer.String("fd00::eef0"),
+					},
+				},
+			},
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
+					PublicIPAddress: &network.PublicIPAddress{
+						PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
+							PublicIPAddressVersion: network.IPv6,
+						},
+						ID: pointer.String("pip1"),
+					},
+				},
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID: types.UID("secondary"),
+					Annotations: map[string]string{
+						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
+						consts.ServiceAnnotationLoadBalancerIPDualStack[true]:  "fd00::eef0",
+					},
+				},
+			},
+			isOwned:   true,
+			isPrimary: false,
+		},
+		{
+			desc: "serviceOwnsFrontendIP should detect the secondary internal service",
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
+					PrivateIPAddress: pointer.String("4.3.2.1"),
+				},
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID: types.UID("secondary"),
+					Annotations: map[string]string{
+						consts.ServiceAnnotationLoadBalancerInternal:           "true",
+						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
+					},
+				},
+			},
+			isOwned: true,
+		},
+		{
+			desc: "serviceOwnsFrontendIP should detect the secondary internal service - dualstack",
+			fip: network.FrontendIPConfiguration{
+				Name: pointer.String("auid"),
+				FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{
+					PrivateIPAddress: pointer.String("fd00::eef0"),
+				},
+			},
+			service: &v1.Service{
+				ObjectMeta: meta.ObjectMeta{
+					UID: types.UID("secondary"),
+					Annotations: map[string]string{
+						consts.ServiceAnnotationLoadBalancerInternal:           "true",
+						consts.ServiceAnnotationLoadBalancerIPDualStack[false]: "4.3.2.1",
+						consts.ServiceAnnotationLoadBalancerIPDualStack[true]:  "fd00::eef0",
+					},
+				},
+			},
+			isOwned: true,
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			cloud := GetTestCloud(ctrl)
+			if test.existingPIPs != nil {
+				mockPIPsClient := cloud.PublicIPAddressesClient.(*mockpublicipclient.MockInterface)
+				mockPIPsClient.EXPECT().List(gomock.Any(), "rg").Return(test.existingPIPs, nil).MaxTimes(2)
+			}
+			isOwned, isPrimary, fipIPVersion := cloud.serviceOwnsFrontendIP(test.fip, test.service)
+			if test.expectedFIPIPVersion != "" {
+				assert.Equal(t, test.expectedFIPIPVersion, fipIPVersion)
+			}
+			assert.Equal(t, test.isOwned, isOwned)
+			assert.Equal(t, test.isPrimary, isPrimary)
+		})
+	}
+}
+
 func TestStandardEnsureBackendPoolDeleted(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
diff --git a/tests/e2e/autoscaling/autoscaler.go b/tests/e2e/autoscaling/autoscaler.go
index d4fce903a..4560e9264 100644
--- a/tests/e2e/autoscaling/autoscaler.go
+++ b/tests/e2e/autoscaling/autoscaler.go
@@ -204,6 +204,8 @@ var _ = Describe("Cluster size autoscaler", Label(utils.TestSuiteLabelFeatureAut
 	})
 
 	It("should balance the sizes of multiple node group if the `--balance-node-groups` is set to true", Label(utils.TestSuiteLabelMultiNodePools), func() {
+		Skip("--balance-node-groups is not supported due to autoscaler bug. This label should be ignored: kubernetes.azure.com/consolidated-additional-properties")
+
 		By("Checking the number of node pools")
 		if len(initNodepoolNodeMap) < 2 {
 			Skip("multiple node pools are needed in this scenario")
diff --git a/tests/e2e/network/ensureloadbalancer.go b/tests/e2e/network/ensureloadbalancer.go
index 252ea9447..5114b4623 100644
--- a/tests/e2e/network/ensureloadbalancer.go
+++ b/tests/e2e/network/ensureloadbalancer.go
@@ -459,7 +459,7 @@ var _ = Describe("Ensure LoadBalancer", Label(utils.TestSuiteLabelLB), func() {
 		}
 
 		serviceNames := []string{}
-		for i := 0; i < 3; i++ {
+		for i := 0; i < 2; i++ {
 			serviceLabels := labels
 			deploymentName := testDeploymentName
 			tcpPort := int32(80 + i)
@@ -478,7 +478,6 @@ var _ = Describe("Ensure LoadBalancer", Label(utils.TestSuiteLabelLB), func() {
 				Expect(err).NotTo(HaveOccurred())
 			}
 
-			var service *v1.Service
 			serviceName := fmt.Sprintf("%s-%d", testServiceName, i)
 			utils.Logf("Creating Service %q", serviceName)
 			serviceNames = append(serviceNames, serviceName)
@@ -486,20 +485,8 @@ var _ = Describe("Ensure LoadBalancer", Label(utils.TestSuiteLabelLB), func() {
 				Port:       tcpPort,
 				TargetPort: intstr.FromInt(int(tcpPort)),
 			}}
-			service = utils.CreateLoadBalancerServiceManifest(serviceName, nil, serviceLabels, ns.Name, servicePort)
-			if i < 2 {
-				service = updateServiceLBIPs(service, false, targetIPs)
-			} else {
-				var pipNames []string
-				if v4Enabled {
-					pipNames = append(pipNames, utils.GetNameWithSuffix(ipNameBase, utils.Suffixes[consts.IPVersionIPv4]))
-				}
-				if v6Enabled {
-					pipNames = append(pipNames, utils.GetNameWithSuffix(ipNameBase, utils.Suffixes[consts.IPVersionIPv6]))
-				}
-				utils.Logf("update pip names %s", strings.Join(pipNames, ","))
-				service = updateServicePIPNames(service, pipNames)
-			}
+			service := utils.CreateLoadBalancerServiceManifest(serviceName, nil, serviceLabels, ns.Name, servicePort)
+			service = updateServiceLBIPs(service, false, targetIPs)
 			_, err := cs.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{})
 			defer func() {
 				err = utils.DeleteService(cs, ns.Name, serviceName)
@@ -516,7 +503,7 @@ var _ = Describe("Ensure LoadBalancer", Label(utils.TestSuiteLabelLB), func() {
 	})
 
 	It("should support multiple external services sharing one newly created public IP addresses", func() {
-		serviceCount := 3
+		serviceCount := 2
 		sharedIPs := []string{}
 		serviceNames := []string{}
 		var serviceLabels map[string]string
@@ -546,16 +533,8 @@ var _ = Describe("Ensure LoadBalancer", Label(utils.TestSuiteLabelLB), func() {
 				TargetPort: intstr.FromInt(int(tcpPort)),
 			}}
 			service := utils.CreateLoadBalancerServiceManifest(serviceName, nil, serviceLabels, ns.Name, servicePort)
-			if i < 2 {
-				if len(sharedIPs) != 0 {
-					service = updateServiceLBIPs(service, false, sharedIPs)
-				}
-			} else {
-				pip, err := tc.GetPublicIPFromAddress(tc.GetResourceGroup(), sharedIPs[0])
-				Expect(err).NotTo(HaveOccurred())
-				pipNames := []string{pointer.StringDeref(pip.Name, "")}
-				utils.Logf("update pip names %s", strings.Join(pipNames, ","))
-				service = updateServicePIPNames(service, pipNames)
+			if len(sharedIPs) != 0 {
+				service = updateServiceLBIPs(service, false, sharedIPs)
 			}
 			_, err := cs.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{})
 			Expect(err).NotTo(HaveOccurred())
@@ -1282,22 +1261,6 @@ func updateServiceLBIPs(service *v1.Service, isInternal bool, ips []string) (res
 	return
 }
 
-func updateServicePIPNames(service *v1.Service, pipNames []string) *v1.Service {
-	if service.Annotations == nil {
-		service.Annotations = map[string]string{}
-	}
-
-	for _, pipName := range pipNames {
-		if strings.HasSuffix(pipName, "-IPv6") {
-			service.Annotations[consts.ServiceAnnotationPIPNameDualStack[consts.IPVersionIPv6]] = pipName
-		} else {
-			service.Annotations[consts.ServiceAnnotationPIPNameDualStack[consts.IPVersionIPv4]] = pipName
-		}
-	}
-
-	return service
-}
-
 func defaultPublicIPAddress(ipName string, isIPv6 bool) aznetwork.PublicIPAddress {
 	// The default sku for LoadBalancer and PublicIP is basic.
 	skuName := aznetwork.PublicIPAddressSkuNameBasic