Repository: kubernetes-sigs/cloud-provider-azure
Pull request #7571 (2024-11-13 15:44:20)

[release-1.31] Migrate RouteTableClient to SDK track v2
This is an automated cherry-pick of #7517

/assign MartinForReal

```release-note
NONE
```

MartinForReal: /kind feature
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/7571#" title="Author self-approved">k8s-infra-cherrypick-robot</a>*, *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/7571#issuecomment-2473994783" title="Approved">MartinForReal</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/release-1.31/OWNERS)~~ [MartinForReal]

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":[]} -->
coveralls: 
[![Coverage Status](https://coveralls.io/builds/70849909/badge)](https://coveralls.io/builds/70849909)

coverage: 75.895% (-0.3%) from 76.182%
when pulling **b0f6b198dee88b0aa54a76bddabe4e6ed8489e07 on k8s-infra-cherrypick-robot:cherry-pick-7517-to-release-1.31**
into **bac7d1f23b3c280466462bb2bcf37ce46cc4e29b on kubernetes-sigs:release-1.31**.

k8s-ci-robot: @k8s-infra-cherrypick-robot: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz-1-31 | b0f6b198dee88b0aa54a76bddabe4e6ed8489e07 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/7571/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz-1-31/1856724846134693888) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz-1-31`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=7571). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ak8s-infra-cherrypick-robot). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->

Patch:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index df04a78c3..9e1395b45 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -70,7 +70,7 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@9278e421667d5d90a2839487a482448c4ec7df4d # v3.27.2
+      uses: github/codeql-action/init@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
       with:
         languages: ${{ matrix.language }}
         # If you wish to specify custom queries, you can do so here or in a config file.
@@ -93,4 +93,4 @@ jobs:
         $(go env GOPATH)/bin/goveralls -coverprofile=profile.cov -service=github
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@9278e421667d5d90a2839487a482448c4ec7df4d # v3.27.2
+      uses: github/codeql-action/analyze@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index ac0168cb8..2e3a1066f 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -72,6 +72,6 @@ jobs:
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@9278e421667d5d90a2839487a482448c4ec7df4d # v3.27.2
+        uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
         with:
           sarif_file: results.sarif
diff --git a/.github/workflows/trivy.yaml b/.github/workflows/trivy.yaml
index 1ec784962..1658abdb5 100644
--- a/.github/workflows/trivy.yaml
+++ b/.github/workflows/trivy.yaml
@@ -67,7 +67,7 @@ jobs:
           vuln-type: 'os,library'
           severity: 'CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN'
       - name: Upload Trivy scan results to GitHub Security tab
-        uses: github/codeql-action/upload-sarif@9278e421667d5d90a2839487a482448c4ec7df4d # v3.27.2
+        uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
         with:
           sarif_file: 'trivy-ccm-results.sarif'
           category: azure-cloud-controller-manager-image
@@ -82,7 +82,7 @@ jobs:
           severity: 'CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN'
           skip-setup-trivy: true
       - name: Upload Trivy scan results to GitHub Security tab
-        uses: github/codeql-action/upload-sarif@9278e421667d5d90a2839487a482448c4ec7df4d # v3.27.2
+        uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
         with:
           sarif_file: 'trivy-cnm-linux-results.sarif'
           category: azure-cloud-node-manager-linux-image
@@ -97,7 +97,7 @@ jobs:
           severity: 'CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN'
           skip-setup-trivy: true
       - name: Upload Trivy scan results to GitHub Security tab
-        uses: github/codeql-action/upload-sarif@9278e421667d5d90a2839487a482448c4ec7df4d # v3.27.2
+        uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
         if: ${{ github.ref == 'refs/heads/main' }}
         with:
           sarif_file: 'trivy-health-probe-proxy-linux-results.sarif'
diff --git a/Dockerfile b/Dockerfile
index 9c34c4835..9e73ee082 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,7 +14,7 @@
 
 # syntax=docker/dockerfile:1
 
-FROM --platform=linux/amd64 golang:1.23-bullseye@sha256:1002103155eb5802f6876dceb8cb8bf965cc6d3deeb34f11e4774926aca6a1fd AS builder
+FROM --platform=linux/amd64 golang:1.23-bullseye@sha256:d4387d8b2ee5b78a199fae168a761d0fb0f33f172642d20856f29a67204af16b AS builder
 
 ARG ENABLE_GIT_COMMAND=true
 ARG ARCH=amd64
diff --git a/cloud-node-manager.Dockerfile b/cloud-node-manager.Dockerfile
index be185d9f5..c4fc398b7 100644
--- a/cloud-node-manager.Dockerfile
+++ b/cloud-node-manager.Dockerfile
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM --platform=linux/amd64 golang:1.23-bullseye@sha256:1002103155eb5802f6876dceb8cb8bf965cc6d3deeb34f11e4774926aca6a1fd AS builder
+FROM --platform=linux/amd64 golang:1.23-bullseye@sha256:d4387d8b2ee5b78a199fae168a761d0fb0f33f172642d20856f29a67204af16b AS builder
 
 ARG ENABLE_GIT_COMMAND=true
 ARG ARCH=amd64
diff --git a/go.mod b/go.mod
index d80675293..cac324685 100644
--- a/go.mod
+++ b/go.mod
@@ -28,16 +28,16 @@ require (
 	github.com/spf13/cobra v1.8.1
 	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.9.0
-	go.opentelemetry.io/otel v1.31.0
+	go.opentelemetry.io/otel v1.32.0
 	go.opentelemetry.io/otel/exporters/prometheus v0.53.0
-	go.opentelemetry.io/otel/metric v1.31.0
+	go.opentelemetry.io/otel/metric v1.32.0
 	go.opentelemetry.io/otel/sdk v1.31.0
 	go.opentelemetry.io/otel/sdk/metric v1.31.0
-	go.opentelemetry.io/otel/trace v1.31.0
+	go.opentelemetry.io/otel/trace v1.32.0
 	go.uber.org/mock v0.5.0
-	golang.org/x/sync v0.8.0
-	golang.org/x/sys v0.26.0
-	golang.org/x/text v0.19.0
+	golang.org/x/sync v0.9.0
+	golang.org/x/sys v0.27.0
+	golang.org/x/text v0.20.0
 	k8s.io/api v0.31.2
 	k8s.io/apimachinery v0.31.2
 	k8s.io/apiserver v0.31.2
@@ -49,7 +49,7 @@ require (
 	k8s.io/klog/v2 v2.130.1
 	k8s.io/kubelet v0.31.2
 	k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
-	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.11
+	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.18
 	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.4
 	sigs.k8s.io/yaml v1.4.0
 )
@@ -61,7 +61,7 @@ require (
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.2.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.4.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 // indirect
-	github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.2.0 // indirect
+	github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 // indirect
 	github.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe // indirect
@@ -70,7 +70,7 @@ require (
 	github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
 	github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
 	github.com/Azure/go-autorest/logger v0.2.1 // indirect
-	github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
+	github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 // indirect
 	github.com/NYTimes/gziphandler v1.1.1 // indirect
 	github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
 	github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
@@ -135,12 +135,12 @@ require (
 	go.opentelemetry.io/proto/otlp v1.3.1 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.26.0 // indirect
-	golang.org/x/crypto v0.28.0 // indirect
+	golang.org/x/crypto v0.29.0 // indirect
 	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
 	golang.org/x/net v0.30.0 // indirect
 	golang.org/x/oauth2 v0.23.0 // indirect
-	golang.org/x/term v0.25.0 // indirect
-	golang.org/x/time v0.7.0 // indirect
+	golang.org/x/term v0.26.0 // indirect
+	golang.org/x/time v0.8.0 // indirect
 	golang.org/x/tools v0.26.0 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f // indirect
diff --git a/go.sum b/go.sum
index a131e1888..aac08074e 100644
--- a/go.sum
+++ b/go.sum
@@ -43,8 +43,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc=
-github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.2.0 h1:TkNl6WlpHdZSMt0Zngw8y0c9ZMi3GwmYl0kKNbW9PvU=
-github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.2.0/go.mod h1:ukmL56lWl275SgNFijuwx0Wv6n6HmzzpPWW4kMoy/wY=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 h1:WLUIpeyv04H0RCcQHaA4TNoyrQ39Ox7V+re+iaqzTe0=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0/go.mod h1:hd8hTTIY3VmUVPRHNH7GVCHO3SHgXkJKZHReby/bnUQ=
 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 h1:eXnN9kaS8TiDwXjoie3hMRLuwdUBUMW9KRgOqB3mCaw=
 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0/go.mod h1:XIpam8wumeZ5rVMuhdDQLMfIPDf1WO3IzrCRO3e3e3o=
 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 h1:nVocQV40OQne5613EeLayJiRAJuKlBGy+m22qWG+WRg=
@@ -75,8 +75,8 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM
 github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
 github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
 github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 h1:gUDtaZk8heteyfdmv+pcfHvhR9llnh7c7GMwZ8RVG04=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
 github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
 github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
@@ -288,22 +288,22 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.5
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
-go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
-go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
+go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
+go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
 go.opentelemetry.io/otel/exporters/prometheus v0.53.0 h1:QXobPHrwiGLM4ufrY3EOmDPJpo2P90UuFau4CDPJA/I=
 go.opentelemetry.io/otel/exporters/prometheus v0.53.0/go.mod h1:WOAXGr3D00CfzmFxtTV1eR0GpoHuPEu+HJT8UWW2SIU=
-go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
-go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
+go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
+go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
 go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
 go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
 go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
 go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
-go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
-go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
+go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
+go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
 go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
 go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -321,8 +321,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
-golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
-golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
+golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
+golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -348,8 +348,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
+golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -364,15 +364,15 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
+golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
-golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
-golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
+golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
+golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -381,10 +381,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
-golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
-golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
+golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
+golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
+golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -454,8 +454,8 @@ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1
 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.11 h1:j2/A1mR1IK7JaUcyFQMwSyNOLOadyEd4filsHniqmO8=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.11/go.mod h1:l3tX2uxSjXo5BkD0rUUoS1cMbk9pZDejByfb7d9qZc0=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.18 h1:IWQ4QGFRFBg5qs3PqaQOMiBeL03piicaOhE42MNusIY=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.18/go.mod h1:TBCLfYApPcLBc0AG0inEFyEtD3jk+hq097H6dXlFTnk=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.4 h1:78nKI0bjXCXLKGccr2aITi0mJ1YScqMeoCiYSrzi3Ag=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.1.4/go.mod h1:qpPLf/GsTSQV8pGzInA07hYT7OgwN5AqLoYf0i5qI2I=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
diff --git a/pkg/azureclients/routetableclient/azure_routetableclient.go b/pkg/azureclients/routetableclient/azure_routetableclient.go
deleted file mode 100644
index 1eea86106..000000000
--- a/pkg/azureclients/routetableclient/azure_routetableclient.go
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package routetableclient
-
-import (
-	"context"
-	"net/http"
-	"strings"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-	"github.com/Azure/go-autorest/autorest"
-	"github.com/Azure/go-autorest/autorest/azure"
-
-	"k8s.io/client-go/util/flowcontrol"
-	"k8s.io/klog/v2"
-
-	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-var _ Interface = &Client{}
-
-const routeTablesResourceType = "Microsoft.Network/routeTables"
-
-// Client implements RouteTable client Interface.
-type Client struct {
-	armClient      armclient.Interface
-	subscriptionID string
-	cloudName      string
-
-	// Rate limiting configures.
-	rateLimiterReader flowcontrol.RateLimiter
-	rateLimiterWriter flowcontrol.RateLimiter
-
-	// ARM throttling configures.
-	RetryAfterReader time.Time
-	RetryAfterWriter time.Time
-}
-
-// New creates a new RouteTable client with ratelimiting.
-func New(config *azclients.ClientConfig) *Client {
-	baseURI := config.ResourceManagerEndpoint
-	authorizer := config.Authorizer
-	apiVersion := APIVersion
-	if strings.EqualFold(config.CloudName, AzureStackCloudName) && !config.DisableAzureStackCloud {
-		apiVersion = AzureStackCloudAPIVersion
-	}
-	armClient := armclient.New(authorizer, *config, baseURI, apiVersion)
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig)
-
-	if azclients.RateLimitEnabled(config.RateLimitConfig) {
-		klog.V(2).Infof("Azure RouteTablesClient (read ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPS,
-			config.RateLimitConfig.CloudProviderRateLimitBucket)
-		klog.V(2).Infof("Azure RouteTablesClient (write ops) using rate limit config: QPS=%g, bucket=%d",
-			config.RateLimitConfig.CloudProviderRateLimitQPSWrite,
-			config.RateLimitConfig.CloudProviderRateLimitBucketWrite)
-	}
-
-	client := &Client{
-		armClient:         armClient,
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-		subscriptionID:    config.SubscriptionID,
-		cloudName:         config.CloudName,
-	}
-
-	return client
-}
-
-// Get gets a RouteTable.
-func (c *Client) Get(ctx context.Context, resourceGroupName string, routeTableName string, expand string) (network.RouteTable, *retry.Error) {
-	mc := metrics.NewMetricContext("route_tables", "get", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterReader.TryAccept() {
-		mc.RateLimitedCount()
-		return network.RouteTable{}, retry.GetRateLimitError(false, "RouteTableGet")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterReader.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("RouteTableGet", "client throttled", c.RetryAfterReader)
-		return network.RouteTable{}, rerr
-	}
-
-	result, rerr := c.getRouteTable(ctx, resourceGroupName, routeTableName, expand)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterReader = rerr.RetryAfter
-		}
-
-		return result, rerr
-	}
-
-	return result, nil
-}
-
-// getRouteTable gets a RouteTable.
-func (c *Client) getRouteTable(ctx context.Context, resourceGroupName string, routeTableName string, expand string) (network.RouteTable, *retry.Error) {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		routeTablesResourceType,
-		routeTableName,
-	)
-	result := network.RouteTable{}
-
-	response, rerr := c.armClient.GetResourceWithExpandQuery(ctx, resourceID, expand)
-	defer c.armClient.CloseResponse(ctx, response)
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "routetable.get.request", resourceID, rerr.Error())
-		return result, rerr
-	}
-
-	err := autorest.Respond(
-		response,
-		azure.WithErrorUnlessStatusCode(http.StatusOK),
-		autorest.ByUnmarshallingJSON(&result))
-	if err != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "routetable.get.respond", resourceID, err)
-		return result, retry.GetError(response, err)
-	}
-
-	result.Response = autorest.Response{Response: response}
-	return result, nil
-}
-
-// CreateOrUpdate creates or updates a RouteTable.
-func (c *Client) CreateOrUpdate(ctx context.Context, resourceGroupName string, routeTableName string, parameters network.RouteTable, etag string) *retry.Error {
-	mc := metrics.NewMetricContext("route_tables", "create_or_update", resourceGroupName, c.subscriptionID, "")
-
-	// Report errors if the client is rate limited.
-	if !c.rateLimiterWriter.TryAccept() {
-		mc.RateLimitedCount()
-		return retry.GetRateLimitError(true, "RouteTableCreateOrUpdate")
-	}
-
-	// Report errors if the client is throttled.
-	if c.RetryAfterWriter.After(time.Now()) {
-		mc.ThrottledCount()
-		rerr := retry.GetThrottlingError("RouteTableCreateOrUpdate", "client throttled", c.RetryAfterWriter)
-		return rerr
-	}
-
-	rerr := c.createOrUpdateRouteTable(ctx, resourceGroupName, routeTableName, parameters, etag)
-	mc.Observe(rerr)
-	if rerr != nil {
-		if rerr.IsThrottled() {
-			// Update RetryAfterReader so that no more requests would be sent until RetryAfter expires.
-			c.RetryAfterWriter = rerr.RetryAfter
-		}
-
-		return rerr
-	}
-
-	return nil
-}
-
-// createOrUpdateRouteTable creates or updates a RouteTable.
-func (c *Client) createOrUpdateRouteTable(ctx context.Context, resourceGroupName string, routeTableName string, parameters network.RouteTable, etag string) *retry.Error {
-	resourceID := armclient.GetResourceID(
-		c.subscriptionID,
-		resourceGroupName,
-		routeTablesResourceType,
-		routeTableName,
-	)
-	decorators := []autorest.PrepareDecorator{}
-	if etag != "" {
-		decorators = append(decorators, autorest.WithHeader("If-Match", autorest.String(etag)))
-	}
-
-	response, rerr := c.armClient.PutResource(ctx, resourceID, parameters, decorators...)
-	defer c.armClient.CloseResponse(ctx, response)
-	if rerr != nil {
-		klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "routetable.put.request", resourceID, rerr.Error())
-		return rerr
-	}
-
-	if response != nil && response.StatusCode != http.StatusNoContent {
-		_, rerr = c.createOrUpdateResponder(response)
-		if rerr != nil {
-			klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "routetable.put.respond", resourceID, rerr.Error())
-			return rerr
-		}
-	}
-
-	return nil
-}
-
-func (c *Client) createOrUpdateResponder(resp *http.Response) (*network.RouteTable, *retry.Error) {
-	result := &network.RouteTable{}
-	err := autorest.Respond(
-		resp,
-		azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
-		autorest.ByUnmarshallingJSON(&result))
-	result.Response = autorest.Response{Response: resp}
-	return result, retry.GetError(resp, err)
-}
diff --git a/pkg/azureclients/routetableclient/doc.go b/pkg/azureclients/routetableclient/doc.go
deleted file mode 100644
index 49d8ed616..000000000
--- a/pkg/azureclients/routetableclient/doc.go
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package routetableclient implements the client for RouteTable.
-package routetableclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient"
diff --git a/pkg/azureclients/routetableclient/interface.go b/pkg/azureclients/routetableclient/interface.go
deleted file mode 100644
index 1ef8cfc08..000000000
--- a/pkg/azureclients/routetableclient/interface.go
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package routetableclient
-
-import (
-	"context"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-const (
-	// APIVersion is the API version for network.
-	APIVersion = "2022-07-01"
-	// AzureStackCloudAPIVersion is the API version for Azure Stack
-	AzureStackCloudAPIVersion = "2018-11-01"
-	// AzureStackCloudName is the cloud name of Azure Stack
-	AzureStackCloudName = "AZURESTACKCLOUD"
-)
-
-// Interface is the client interface for RouteTable.
-// Don't forget to run "hack/update-mock-clients.sh" command to generate the mock client.
-type Interface interface {
-	// Get gets a RouteTable.
-	Get(ctx context.Context, resourceGroupName string, routeTableName string, expand string) (result network.RouteTable, rerr *retry.Error)
-
-	// CreateOrUpdate creates or updates a RouteTable.
-	CreateOrUpdate(ctx context.Context, resourceGroupName string, routeTableName string, parameters network.RouteTable, etag string) *retry.Error
-}
diff --git a/pkg/azureclients/routetableclient/mockroutetableclient/doc.go b/pkg/azureclients/routetableclient/mockroutetableclient/doc.go
deleted file mode 100644
index c2aa4cc39..000000000
--- a/pkg/azureclients/routetableclient/mockroutetableclient/doc.go
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package mockroutetableclient implements the mock client for RouteTable.
-package mockroutetableclient // import "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient/mockroutetableclient"
diff --git a/pkg/provider/azure.go b/pkg/provider/azure.go
index 725b6cdce..7d027adfc 100644
--- a/pkg/provider/azure.go
+++ b/pkg/provider/azure.go
@@ -48,6 +48,7 @@ import (
 	cloudnodeutil "k8s.io/cloud-provider/node/helpers"
 	nodeutil "k8s.io/component-helpers/node/util"
 	"k8s.io/klog/v2"
+	"sigs.k8s.io/yaml"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/azclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader"
@@ -60,7 +61,6 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/privatednszonegroupclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/privateendpointclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/publicipclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/storageaccountclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/subnetclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmasclient"
@@ -69,15 +69,14 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmssclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmssvmclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/privatelinkservice"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/routetable"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/subnet"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/zone"
 
-	"sigs.k8s.io/yaml"
-
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	ratelimitconfig "sigs.k8s.io/cloud-provider-azure/pkg/provider/config"
-	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
 	"sigs.k8s.io/cloud-provider-azure/pkg/util/taints"
@@ -358,7 +357,6 @@ type Cloud struct {
 
 	SubnetsClient                   subnetclient.Interface
 	InterfacesClient                interfaceclient.Interface
-	RouteTablesClient               routetableclient.Interface
 	LoadBalancerClient              loadbalancerclient.Interface
 	PublicIPAddressesClient         publicipclient.Interface
 	VirtualMachinesClient           vmclient.Interface
@@ -415,13 +413,13 @@ type Cloud struct {
 	routeUpdater       batchProcessor
 	backendPoolUpdater batchProcessor
 
-	vmCache    azcache.Resource
-	lbCache    azcache.Resource
-	nsgRepo    securitygroup.Repository
-	zoneRepo   zone.Repository
-	plsRepo    privatelinkservice.Repository
-	subnetRepo subnet.Repository
-	rtCache    azcache.Resource
+	vmCache        azcache.Resource
+	lbCache        azcache.Resource
+	nsgRepo        securitygroup.Repository
+	zoneRepo       zone.Repository
+	plsRepo        privatelinkservice.Repository
+	subnetRepo     subnet.Repository
+	routeTableRepo routetable.Repository
 	// public ip cache
 	// key: [resourceGroupName]
 	// Value: sync.Map of [pipName]*PublicIPAddress
@@ -752,10 +750,16 @@ func (az *Cloud) InitializeCloudFromConfig(ctx context.Context, config *Config,
 		if err != nil {
 			return err
 		}
+
 		az.subnetRepo, err = subnet.NewRepo(networkClientFactory.GetSubnetClient())
 		if err != nil {
 			return err
 		}
+
+		az.routeTableRepo, err = routetable.NewRepo(networkClientFactory.GetRouteTableClient(), az.RouteTableResourceGroup, time.Duration(az.RouteTableCacheTTLInSeconds)*time.Second, az.DisableAPICallCache)
+		if err != nil {
+			return err
+		}
 	}
 	err = az.initCaches()
 	if err != nil {
@@ -869,11 +873,6 @@ func (az *Cloud) initCaches() (err error) {
 		return err
 	}
 
-	az.rtCache, err = az.newRouteTableCache()
-	if err != nil {
-		return err
-	}
-
 	az.pipCache, err = az.newPIPCache()
 	if err != nil {
 		return err
@@ -1036,7 +1035,6 @@ func (az *Cloud) configAzureClients(
 	az.VirtualMachineScaleSetsClient = vmssclient.New(vmssClientConfig)
 	az.VirtualMachineScaleSetVMsClient = vmssvmclient.New(vmssVMClientConfig)
 	az.SubnetsClient = subnetclient.New(subnetClientConfig)
-	az.RouteTablesClient = routetableclient.New(routeTableClientConfig)
 	az.LoadBalancerClient = loadbalancerclient.New(loadBalancerClientConfig)
 	az.PublicIPAddressesClient = publicipclient.New(publicIPClientConfig)
 	az.FileClient = fileclient.New(fileClientConfig)
diff --git a/pkg/provider/azure_fakes.go b/pkg/provider/azure_fakes.go
index 030128a85..0b1db9dfd 100644
--- a/pkg/provider/azure_fakes.go
+++ b/pkg/provider/azure_fakes.go
@@ -36,7 +36,6 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/interfaceclient/mockinterfaceclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/loadbalancerclient/mockloadbalancerclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/publicipclient/mockpublicipclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient/mockroutetableclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/subnetclient/mocksubnetclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmclient/mockvmclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/vmssclient/mockvmssclient"
@@ -45,6 +44,7 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/config"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/privatelinkservice"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/routetable"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/securitygroup"
 	"sigs.k8s.io/cloud-provider-azure/pkg/provider/subnet"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
@@ -116,7 +116,6 @@ func GetTestCloud(ctrl *gomock.Controller) (az *Cloud) {
 	az.InterfacesClient = mockinterfaceclient.NewMockInterface(ctrl)
 	az.LoadBalancerClient = mockloadbalancerclient.NewMockInterface(ctrl)
 	az.PublicIPAddressesClient = mockpublicipclient.NewMockInterface(ctrl)
-	az.RouteTablesClient = mockroutetableclient.NewMockInterface(ctrl)
 	az.SubnetsClient = mocksubnetclient.NewMockInterface(ctrl)
 	az.VirtualMachineScaleSetsClient = mockvmssclient.NewMockInterface(ctrl)
 	az.VirtualMachineScaleSetVMsClient = mockvmssvmclient.NewMockInterface(ctrl)
@@ -140,11 +139,11 @@ func GetTestCloud(ctrl *gomock.Controller) (az *Cloud) {
 	az.lbCache, _ = az.newLBCache()
 	az.nsgRepo, _ = securitygroup.NewSecurityGroupRepo(az.SecurityGroupResourceGroup, az.SecurityGroupName, az.NsgCacheTTLInSeconds, az.Config.DisableAPICallCache, securtyGrouptrack2Client)
 	az.subnetRepo = subnet.NewMockRepository(ctrl)
-	az.rtCache, _ = az.newRouteTableCache()
 	az.pipCache, _ = az.newPIPCache()
 	az.LoadBalancerBackendPool = NewMockBackendPool(ctrl)
 
 	az.plsRepo = privatelinkservice.NewMockRepository(ctrl)
+	az.routeTableRepo = routetable.NewMockRepository(ctrl)
 
 	getter := func(_ context.Context, _ string) (interface{}, error) { return nil, nil }
 	az.storageAccountCache, _ = azcache.NewTimedCache(time.Minute, getter, az.Config.DisableAPICallCache)
diff --git a/pkg/provider/azure_loadbalancer.go b/pkg/provider/azure_loadbalancer.go
index c846ff178..7a369a4e3 100644
--- a/pkg/provider/azure_loadbalancer.go
+++ b/pkg/provider/azure_loadbalancer.go
@@ -711,15 +711,12 @@ func (az *Cloud) cleanOrphanedLoadBalancer(ctx context.Context, lb *network.Load
 }
 
 // safeDeleteLoadBalancer deletes the load balancer after decoupling it from the vmSet
-func (az *Cloud) safeDeleteLoadBalancer(ctx context.Context, lb network.LoadBalancer, clusterName, vmSetName string, service *v1.Service) *retry.Error {
-	lbBackendPoolIDs := az.getBackendPoolIDs(clusterName, ptr.Deref(lb.Name, ""))
+func (az *Cloud) safeDeleteLoadBalancer(ctx context.Context, lb network.LoadBalancer, _, vmSetName string, service *v1.Service) *retry.Error {
 	lbBackendPoolIDsToDelete := []string{}
-	v4Enabled, v6Enabled := getIPFamiliesEnabled(service)
-	if v4Enabled {
-		lbBackendPoolIDsToDelete = append(lbBackendPoolIDsToDelete, lbBackendPoolIDs[consts.IPVersionIPv4])
-	}
-	if v6Enabled {
-		lbBackendPoolIDsToDelete = append(lbBackendPoolIDsToDelete, lbBackendPoolIDs[consts.IPVersionIPv6])
+	if lb.LoadBalancerPropertiesFormat != nil && lb.BackendAddressPools != nil {
+		for _, bp := range *lb.BackendAddressPools {
+			lbBackendPoolIDsToDelete = append(lbBackendPoolIDsToDelete, ptr.Deref(bp.ID, ""))
+		}
 	}
 	if _, err := az.VMSet.EnsureBackendPoolDeleted(ctx, service, lbBackendPoolIDsToDelete, vmSetName, lb.BackendAddressPools, true); err != nil {
 		return retry.NewError(false, fmt.Errorf("safeDeleteLoadBalancer: failed to EnsureBackendPoolDeleted: %w", err))
@@ -1507,7 +1504,7 @@ func (az *Cloud) isFrontendIPChanged(
 	if fipIPVersion != "" {
 		isIPv6 = fipIPVersion == network.IPv6
 	} else {
-		if isIPv6, err = az.isFIPIPv6(service, pipRG, &config); err != nil {
+		if isIPv6, err = az.isFIPIPv6(service, &config); err != nil {
 			return false, err
 		}
 	}
@@ -1657,7 +1654,6 @@ func (az *Cloud) findFrontendIPConfigsOfService(
 	service *v1.Service,
 ) (map[bool]*network.FrontendIPConfiguration, error) {
 	fipsOfServiceMap := map[bool]*network.FrontendIPConfiguration{}
-	pipRG := az.getPublicIPAddressResourceGroup(service)
 	for _, config := range *fipConfigs {
 		config := config
 		owns, _, fipIPVersion := az.serviceOwnsFrontendIP(ctx, config, service)
@@ -1667,7 +1663,7 @@ func (az *Cloud) findFrontendIPConfigsOfService(
 			if fipIPVersion != "" {
 				fipIsIPv6 = fipIPVersion == network.IPv6
 			} else {
-				if fipIsIPv6, err = az.isFIPIPv6(service, pipRG, &config); err != nil {
+				if fipIsIPv6, err = az.isFIPIPv6(service, &config); err != nil {
 					return nil, err
 				}
 			}
@@ -1843,7 +1839,6 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 	}
 
 	// update probes/rules
-	pipRG := az.getPublicIPAddressResourceGroup(service)
 	for _, ownedFIPConfig := range ownedFIPConfigs {
 		if ownedFIPConfig == nil {
 			continue
@@ -1858,7 +1853,7 @@ func (az *Cloud) reconcileLoadBalancer(ctx context.Context, clusterName string,
 		if fipIPVersion != "" {
 			isIPv6 = fipIPVersion == network.IPv6
 		} else {
-			if isIPv6, err = az.isFIPIPv6(service, pipRG, ownedFIPConfig); err != nil {
+			if isIPv6, err = az.isFIPIPv6(service, ownedFIPConfig); err != nil {
 				return nil, err
 			}
 		}
@@ -2519,8 +2514,6 @@ func (az *Cloud) reconcileFrontendIPConfigs(
 			}
 		}
 
-		pipRG := az.getPublicIPAddressResourceGroup(service)
-
 		for i := len(newConfigs) - 1; i >= 0; i-- {
 			config := newConfigs[i]
 			isServiceOwnsFrontendIP, _, fipIPVersion := az.serviceOwnsFrontendIP(ctx, config, service)
@@ -2534,7 +2527,7 @@ func (az *Cloud) reconcileFrontendIPConfigs(
 			if fipIPVersion != "" {
 				isIPv6 = fipIPVersion == network.IPv6
 			} else {
-				if isIPv6, err = az.isFIPIPv6(service, pipRG, &config); err != nil {
+				if isIPv6, err = az.isFIPIPv6(service, &config); err != nil {
 					return nil, toDeleteConfigs, false, err
 				}
 			}
diff --git a/pkg/provider/azure_privatelinkservice.go b/pkg/provider/azure_privatelinkservice.go
index bc9a58607..a4c386268 100644
--- a/pkg/provider/azure_privatelinkservice.go
+++ b/pkg/provider/azure_privatelinkservice.go
@@ -49,7 +49,6 @@ func (az *Cloud) reconcilePrivateLinkService(
 	wantPLS bool,
 ) error {
 	isinternal := requiresInternalLoadBalancer(service)
-	pipRG := az.getPublicIPAddressResourceGroup(service)
 	_, _, fipIPVersion := az.serviceOwnsFrontendIP(ctx, *fipConfig, service)
 	serviceName := getServiceName(service)
 	var isIPv6 bool
@@ -57,7 +56,7 @@ func (az *Cloud) reconcilePrivateLinkService(
 	if fipIPVersion != "" {
 		isIPv6 = fipIPVersion == network.IPv6
 	} else {
-		if isIPv6, err = az.isFIPIPv6(service, pipRG, fipConfig); err != nil {
+		if isIPv6, err = az.isFIPIPv6(service, fipConfig); err != nil {
 			klog.Errorf("reconcilePrivateLinkService for service(%s): failed to get FIP IP family: %v", serviceName, err)
 			return err
 		}
diff --git a/pkg/provider/azure_routes.go b/pkg/provider/azure_routes.go
index c32c7a3cc..4527908ef 100644
--- a/pkg/provider/azure_routes.go
+++ b/pkg/provider/azure_routes.go
@@ -23,8 +23,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
 	cloudprovider "k8s.io/cloud-provider"
@@ -53,7 +52,7 @@ const (
 
 // delayedRouteOperation defines a delayed route operation which is used in delayedRouteUpdater.
 type delayedRouteOperation struct {
-	route          network.Route
+	route          *armnetwork.Route
 	routeTableTags map[string]*string
 	operation      routeOperation
 	result         chan batchOperationResult
@@ -119,24 +118,23 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 	}()
 
 	var (
-		routeTable       network.RouteTable
-		existsRouteTable bool
+		routeTable *armnetwork.RouteTable
 	)
-	routeTable, existsRouteTable, err = d.az.getRouteTable(ctx, azcache.CacheReadTypeDefault)
+	routeTable, err = d.az.routeTableRepo.Get(ctx, d.az.RouteTableName, azcache.CacheReadTypeDefault)
 	if err != nil {
 		klog.Errorf("getRouteTable() failed with error: %v", err)
 		return
 	}
 
 	// create route table if it doesn't exists yet.
-	if !existsRouteTable {
-		err = d.az.createRouteTable()
+	if routeTable == nil {
+		err = d.az.createRouteTable(ctx)
 		if err != nil {
 			klog.Errorf("createRouteTable() failed with error: %v", err)
 			return
 		}
 
-		routeTable, _, err = d.az.getRouteTable(ctx, azcache.CacheReadTypeDefault)
+		routeTable, err = d.az.routeTableRepo.Get(ctx, d.az.RouteTableName, azcache.CacheReadTypeDefault)
 		if err != nil {
 			klog.Errorf("getRouteTable() failed with error: %v", err)
 			return
@@ -145,9 +143,9 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 
 	// reconcile routes.
 	dirty, onlyUpdateTags := false, true
-	routes := []network.Route{}
-	if routeTable.RouteTablePropertiesFormat != nil && routeTable.RouteTablePropertiesFormat.Routes != nil {
-		routes = *routeTable.Routes
+	var routes []*armnetwork.Route
+	if routeTable.Properties != nil {
+		routes = routeTable.Properties.Routes
 	}
 
 	routes, dirty = d.cleanupOutdatedRoutes(routes)
@@ -169,10 +167,10 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 			if strings.EqualFold(ptr.Deref(existingRoute.Name, ""), ptr.Deref(rt.route.Name, "")) {
 				// delete the name-matched routes here (missing routes would be added later if the operation is add).
 				routes = append(routes[:i], routes[i+1:]...)
-				if existingRoute.RoutePropertiesFormat != nil &&
-					rt.route.RoutePropertiesFormat != nil &&
-					strings.EqualFold(ptr.Deref(existingRoute.AddressPrefix, ""), ptr.Deref(rt.route.AddressPrefix, "")) &&
-					strings.EqualFold(ptr.Deref(existingRoute.NextHopIPAddress, ""), ptr.Deref(rt.route.NextHopIPAddress, "")) {
+				if existingRoute.Properties != nil &&
+					rt.route.Properties != nil &&
+					strings.EqualFold(ptr.Deref(existingRoute.Properties.AddressPrefix, ""), ptr.Deref(rt.route.Properties.AddressPrefix, "")) &&
+					strings.EqualFold(ptr.Deref(existingRoute.Properties.NextHopIPAddress, ""), ptr.Deref(rt.route.Properties.NextHopIPAddress, "")) {
 					routeMatch = true
 				}
 				if rt.operation == routeOperationDelete {
@@ -198,9 +196,9 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 	if dirty {
 		if !onlyUpdateTags {
 			klog.V(2).Infof("updateRoutes: updating routes")
-			routeTable.Routes = &routes
+			routeTable.Properties.Routes = routes
 		}
-		err = d.az.CreateOrUpdateRouteTable(routeTable)
+		_, err := d.az.routeTableRepo.CreateOrUpdate(ctx, *routeTable)
 		if err != nil {
 			klog.Errorf("CreateOrUpdateRouteTable() failed with error: %v", err)
 			return
@@ -213,7 +211,7 @@ func (d *delayedRouteUpdater) updateRoutes(ctx context.Context) {
 
 // cleanupOutdatedRoutes deletes all non-dualstack routes when dualstack is enabled,
 // and deletes all dualstack routes when dualstack is not enabled.
-func (d *delayedRouteUpdater) cleanupOutdatedRoutes(existingRoutes []network.Route) (routes []network.Route, changed bool) {
+func (d *delayedRouteUpdater) cleanupOutdatedRoutes(existingRoutes []*armnetwork.Route) (routes []*armnetwork.Route, changed bool) {
 	for i := len(existingRoutes) - 1; i >= 0; i-- {
 		existingRouteName := ptr.Deref(existingRoutes[i].Name, "")
 		split := strings.Split(existingRouteName, consts.RouteNameSeparator)
@@ -241,7 +239,7 @@ func (d *delayedRouteUpdater) cleanupOutdatedRoutes(existingRoutes []network.Rou
 	return existingRoutes, changed
 }
 
-func getAddRouteOperation(route network.Route) batchOperation {
+func getAddRouteOperation(route *armnetwork.Route) batchOperation {
 	return &delayedRouteOperation{
 		route:     route,
 		operation: routeOperationAdd,
@@ -249,7 +247,7 @@ func getAddRouteOperation(route network.Route) batchOperation {
 	}
 }
 
-func getDeleteRouteOperation(route network.Route) batchOperation {
+func getDeleteRouteOperation(route *armnetwork.Route) batchOperation {
 	return &delayedRouteOperation{
 		route:     route,
 		operation: routeOperationDelete,
@@ -280,8 +278,8 @@ func (d *delayedRouteUpdater) removeOperation(_ string) {}
 // implements cloudprovider.Routes.ListRoutes
 func (az *Cloud) ListRoutes(ctx context.Context, clusterName string) ([]*cloudprovider.Route, error) {
 	klog.V(10).Infof("ListRoutes: START clusterName=%q", clusterName)
-	routeTable, existsRouteTable, err := az.getRouteTable(ctx, azcache.CacheReadTypeDefault)
-	routes, err := processRoutes(az.ipv6DualStackEnabled, routeTable, existsRouteTable, err)
+	routeTable, err := az.routeTableRepo.Get(ctx, az.RouteTableName, azcache.CacheReadTypeDefault)
+	routes, err := processRoutes(az.ipv6DualStackEnabled, routeTable, err)
 	if err != nil {
 		return nil, err
 	}
@@ -304,7 +302,7 @@ func (az *Cloud) ListRoutes(ctx context.Context, clusterName string) ([]*cloudpr
 	}
 
 	// ensure the route table is tagged as configured
-	tags, changed := az.ensureRouteTableTagged(&routeTable)
+	tags, changed := az.ensureRouteTableTagged(routeTable)
 	if changed {
 		klog.V(2).Infof("ListRoutes: updating tags on route table %s", ptr.Deref(routeTable.Name, ""))
 		op := az.routeUpdater.addOperation(getUpdateRouteTableTagsOperation(tags))
@@ -321,20 +319,20 @@ func (az *Cloud) ListRoutes(ctx context.Context, clusterName string) ([]*cloudpr
 }
 
 // Injectable for testing
-func processRoutes(ipv6DualStackEnabled bool, routeTable network.RouteTable, exists bool, err error) ([]*cloudprovider.Route, error) {
+func processRoutes(ipv6DualStackEnabled bool, routeTable *armnetwork.RouteTable, err error) ([]*cloudprovider.Route, error) {
 	if err != nil {
 		return nil, err
 	}
-	if !exists {
+	if routeTable == nil {
 		return []*cloudprovider.Route{}, nil
 	}
 
 	var kubeRoutes []*cloudprovider.Route
-	if routeTable.RouteTablePropertiesFormat != nil && routeTable.Routes != nil {
-		kubeRoutes = make([]*cloudprovider.Route, len(*routeTable.Routes))
-		for i, route := range *routeTable.Routes {
+	if routeTable.Properties != nil {
+		kubeRoutes = make([]*cloudprovider.Route, len(routeTable.Properties.Routes))
+		for i, route := range routeTable.Properties.Routes {
 			instance := MapRouteNameToNodeName(ipv6DualStackEnabled, *route.Name)
-			cidr := *route.AddressPrefix
+			cidr := *route.Properties.AddressPrefix
 			klog.V(10).Infof("ListRoutes: * instance=%q, cidr=%q", instance, cidr)
 
 			kubeRoutes[i] = &cloudprovider.Route{
@@ -349,22 +347,16 @@ func processRoutes(ipv6DualStackEnabled bool, routeTable network.RouteTable, exi
 	return kubeRoutes, nil
 }
 
-func (az *Cloud) createRouteTable() error {
-	routeTable := network.RouteTable{
-		Name:                       ptr.To(az.RouteTableName),
-		Location:                   ptr.To(az.Location),
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{},
+func (az *Cloud) createRouteTable(ctx context.Context) error {
+	routeTable := armnetwork.RouteTable{
+		Name:       ptr.To(az.RouteTableName),
+		Location:   ptr.To(az.Location),
+		Properties: &armnetwork.RouteTablePropertiesFormat{},
 	}
 
 	klog.V(3).Infof("createRouteTableIfNotExists: creating routetable. routeTableName=%q", az.RouteTableName)
-	err := az.CreateOrUpdateRouteTable(routeTable)
-	if err != nil {
-		return err
-	}
-
-	// Invalidate the cache right after updating
-	_ = az.rtCache.Delete(az.RouteTableName)
-	return nil
+	_, err := az.routeTableRepo.CreateOrUpdate(ctx, routeTable)
+	return err
 }
 
 // CreateRoute creates the described managed route
@@ -419,11 +411,11 @@ func (az *Cloud) CreateRoute(ctx context.Context, clusterName string, _ string,
 		}
 	}
 	routeName := mapNodeNameToRouteName(az.ipv6DualStackEnabled, kubeRoute.TargetNode, kubeRoute.DestinationCIDR)
-	route := network.Route{
+	route := &armnetwork.Route{
 		Name: ptr.To(routeName),
-		RoutePropertiesFormat: &network.RoutePropertiesFormat{
+		Properties: &armnetwork.RoutePropertiesFormat{
 			AddressPrefix:    ptr.To(kubeRoute.DestinationCIDR),
-			NextHopType:      network.RouteNextHopTypeVirtualAppliance,
+			NextHopType:      ptr.To(armnetwork.RouteNextHopTypeVirtualAppliance),
 			NextHopIPAddress: ptr.To(targetIP),
 		},
 	}
@@ -470,9 +462,9 @@ func (az *Cloud) DeleteRoute(_ context.Context, clusterName string, kubeRoute *c
 
 	routeName := mapNodeNameToRouteName(az.ipv6DualStackEnabled, kubeRoute.TargetNode, kubeRoute.DestinationCIDR)
 	klog.V(2).Infof("DeleteRoute: deleting route. clusterName=%q instance=%q cidr=%q routeName=%q", clusterName, kubeRoute.TargetNode, kubeRoute.DestinationCIDR, routeName)
-	route := network.Route{
-		Name:                  ptr.To(routeName),
-		RoutePropertiesFormat: &network.RoutePropertiesFormat{},
+	route := &armnetwork.Route{
+		Name:       ptr.To(routeName),
+		Properties: &armnetwork.RoutePropertiesFormat{},
 	}
 	op := az.routeUpdater.addOperation(getDeleteRouteOperation(route))
 
@@ -487,9 +479,9 @@ func (az *Cloud) DeleteRoute(_ context.Context, clusterName string, kubeRoute *c
 	if az.ipv6DualStackEnabled {
 		routeNameWithoutIPV6Suffix := strings.Split(routeName, consts.RouteNameSeparator)[0]
 		klog.V(2).Infof("DeleteRoute: deleting route. clusterName=%q instance=%q cidr=%q routeName=%q", clusterName, kubeRoute.TargetNode, kubeRoute.DestinationCIDR, routeNameWithoutIPV6Suffix)
-		route := network.Route{
-			Name:                  ptr.To(routeNameWithoutIPV6Suffix),
-			RoutePropertiesFormat: &network.RoutePropertiesFormat{},
+		route := &armnetwork.Route{
+			Name:       ptr.To(routeNameWithoutIPV6Suffix),
+			Properties: &armnetwork.RoutePropertiesFormat{},
 		}
 		op := az.routeUpdater.addOperation(getDeleteRouteOperation(route))
 
@@ -553,7 +545,7 @@ func cidrtoRfc1035(cidr string) string {
 }
 
 // ensureRouteTableTagged ensures the route table is tagged as configured
-func (az *Cloud) ensureRouteTableTagged(rt *network.RouteTable) (map[string]*string, bool) {
+func (az *Cloud) ensureRouteTableTagged(rt *armnetwork.RouteTable) (map[string]*string, bool) {
 	if !strings.EqualFold(az.RouteTableResourceGroup, az.ResourceGroup) {
 		return nil, false
 	}
diff --git a/pkg/provider/azure_routetable_repo.go b/pkg/provider/azure_routetable_repo.go
deleted file mode 100644
index 116c9138f..000000000
--- a/pkg/provider/azure_routetable_repo.go
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package provider
-
-import (
-	"context"
-	"encoding/json"
-	"net/http"
-	"strings"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-
-	"k8s.io/klog/v2"
-	"k8s.io/utils/ptr"
-
-	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
-	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
-)
-
-// CreateOrUpdateRouteTable invokes az.RouteTablesClient.CreateOrUpdate with exponential backoff retry
-func (az *Cloud) CreateOrUpdateRouteTable(routeTable network.RouteTable) error {
-	ctx, cancel := getContextWithCancel()
-	defer cancel()
-
-	rerr := az.RouteTablesClient.CreateOrUpdate(ctx, az.RouteTableResourceGroup, az.RouteTableName, routeTable, ptr.Deref(routeTable.Etag, ""))
-	if rerr == nil {
-		// Invalidate the cache right after updating
-		_ = az.rtCache.Delete(*routeTable.Name)
-		return nil
-	}
-
-	rtJSON, _ := json.Marshal(routeTable)
-	klog.Warningf("RouteTablesClient.CreateOrUpdate(%s) failed: %v, RouteTable request: %s", ptr.Deref(routeTable.Name, ""), rerr.Error(), string(rtJSON))
-
-	// Invalidate the cache because etag mismatch.
-	if rerr.HTTPStatusCode == http.StatusPreconditionFailed {
-		klog.V(3).Infof("Route table cache for %s is cleanup because of http.StatusPreconditionFailed", *routeTable.Name)
-		_ = az.rtCache.Delete(*routeTable.Name)
-	}
-	// Invalidate the cache because another new operation has canceled the current request.
-	if strings.Contains(strings.ToLower(rerr.Error().Error()), consts.OperationCanceledErrorMessage) {
-		klog.V(3).Infof("Route table cache for %s is cleanup because CreateOrUpdateRouteTable is canceled by another operation", *routeTable.Name)
-		_ = az.rtCache.Delete(*routeTable.Name)
-	}
-	klog.Errorf("RouteTablesClient.CreateOrUpdate(%s) failed: %v", az.RouteTableName, rerr.Error())
-	return rerr.Error()
-}
-
-func (az *Cloud) newRouteTableCache() (azcache.Resource, error) {
-	getter := func(ctx context.Context, key string) (interface{}, error) {
-		rt, err := az.RouteTablesClient.Get(ctx, az.RouteTableResourceGroup, key, "")
-		exists, rerr := checkResourceExistsFromError(err)
-		if rerr != nil {
-			return nil, rerr.Error()
-		}
-
-		if !exists {
-			klog.V(2).Infof("Route table %q not found", key)
-			return nil, nil
-		}
-
-		return &rt, nil
-	}
-
-	if az.RouteTableCacheTTLInSeconds == 0 {
-		az.RouteTableCacheTTLInSeconds = routeTableCacheTTLDefaultInSeconds
-	}
-	return azcache.NewTimedCache(time.Duration(az.RouteTableCacheTTLInSeconds)*time.Second, getter, az.Config.DisableAPICallCache)
-}
diff --git a/pkg/provider/azure_utils.go b/pkg/provider/azure_utils.go
index 65fef0f21..6cb2def64 100644
--- a/pkg/provider/azure_utils.go
+++ b/pkg/provider/azure_utils.go
@@ -438,9 +438,12 @@ func getResourceByIPFamily(resource string, isDualStack, isIPv6 bool) string {
 
 // isFIPIPv6 checks if the frontend IP configuration is of IPv6.
 // NOTICE: isFIPIPv6 assumes the FIP is owned by the Service and it is the primary Service.
-func (az *Cloud) isFIPIPv6(service *v1.Service, _ string, fip *network.FrontendIPConfiguration) (bool, error) {
+func (az *Cloud) isFIPIPv6(service *v1.Service, fip *network.FrontendIPConfiguration) (bool, error) {
 	isDualStack := isServiceDualStack(service)
 	if !isDualStack {
+		if len(service.Spec.IPFamilies) == 0 {
+			return false, nil
+		}
 		return service.Spec.IPFamilies[0] == v1.IPv6Protocol, nil
 	}
 	return managedResourceHasIPv6Suffix(ptr.Deref(fip.Name, "")), nil
diff --git a/pkg/provider/azure_vmsets_repo.go b/pkg/provider/azure_vmsets_repo.go
index ec7106c95..00c13e6a6 100644
--- a/pkg/provider/azure_vmsets_repo.go
+++ b/pkg/provider/azure_vmsets_repo.go
@@ -19,13 +19,10 @@ package provider
 import (
 	"context"
 	"errors"
-	"fmt"
 	"strings"
 	"time"
 
 	"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"
-
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
 	cloudprovider "k8s.io/cloud-provider"
@@ -171,20 +168,3 @@ func (az *Cloud) getVirtualMachine(ctx context.Context, nodeName types.NodeName,
 
 	return *(cachedVM.(*compute.VirtualMachine)), nil
 }
-
-func (az *Cloud) getRouteTable(ctx context.Context, crt azcache.AzureCacheReadType) (routeTable network.RouteTable, exists bool, err error) {
-	if len(az.RouteTableName) == 0 {
-		return routeTable, false, fmt.Errorf("route table name is not configured")
-	}
-
-	cachedRt, err := az.rtCache.GetWithDeepCopy(ctx, az.RouteTableName, crt)
-	if err != nil {
-		return routeTable, false, err
-	}
-
-	if cachedRt == nil {
-		return routeTable, false, nil
-	}
-
-	return *(cachedRt.(*network.RouteTable)), true, nil
-}
diff --git a/pkg/provider/azure_vmss.go b/pkg/provider/azure_vmss.go
index c48a1a5cf..06222ab63 100644
--- a/pkg/provider/azure_vmss.go
+++ b/pkg/provider/azure_vmss.go
@@ -1967,7 +1967,9 @@ func (ss *ScaleSet) EnsureBackendPoolDeleted(ctx context.Context, service *v1.Se
 
 	for _, backendPool := range *backendAddressPools {
 		for _, backendPoolID := range backendPoolIDs {
-			if strings.EqualFold(*backendPool.ID, backendPoolID) && backendPool.BackendIPConfigurations != nil {
+			if strings.EqualFold(*backendPool.ID, backendPoolID) &&
+				backendPool.BackendAddressPoolPropertiesFormat != nil &&
+				backendPool.BackendIPConfigurations != nil {
 				for _, ipConf := range *backendPool.BackendIPConfigurations {
 					if ipConf.ID == nil {
 						continue
diff --git a/pkg/provider/azure_wrap.go b/pkg/provider/azure_wrap.go
index d599ddbd2..614c01233 100644
--- a/pkg/provider/azure_wrap.go
+++ b/pkg/provider/azure_wrap.go
@@ -29,7 +29,6 @@ import (
 var (
 	vmCacheTTLDefaultInSeconds           = 60
 	loadBalancerCacheTTLDefaultInSeconds = 120
-	routeTableCacheTTLDefaultInSeconds   = 120
 	publicIPCacheTTLDefaultInSeconds     = 120
 
 	azureNodeProviderIDRE    = regexp.MustCompile(`^azure:///subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/(?:.*)`)
diff --git a/pkg/provider/routetable/cache.go b/pkg/provider/routetable/cache.go
new file mode 100644
index 000000000..96927a51c
--- /dev/null
+++ b/pkg/provider/routetable/cache.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package routetable
+
+import (
+	"context"
+	"time"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+	"sigs.k8s.io/cloud-provider-azure/pkg/util/errutils"
+)
+
+const (
+	DefaultCacheTTL = 120 * time.Second
+)
+
+func NewCache(
+	client routetableclient.Interface,
+	resourceGroup string,
+	cacheTTL time.Duration,
+	disableAPICallCache bool,
+) (cache.Resource, error) {
+	getter := func(ctx context.Context, key string) (interface{}, error) {
+		rt, err := client.Get(ctx, resourceGroup, key)
+		found, err := errutils.CheckResourceExistsFromAzcoreError(err)
+		if err != nil {
+			return nil, err
+		}
+		if !found {
+			return nil, nil
+		}
+
+		return rt, nil
+	}
+
+	if cacheTTL == 0 {
+		cacheTTL = DefaultCacheTTL
+	}
+	return cache.NewTimedCache(cacheTTL, getter, disableAPICallCache)
+}
diff --git a/pkg/provider/routetable/mock_repo.go b/pkg/provider/routetable/mock_repo.go
new file mode 100644
index 000000000..76988b62c
--- /dev/null
+++ b/pkg/provider/routetable/mock_repo.go
@@ -0,0 +1,88 @@
+// /*
+// Copyright The Kubernetes Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// */
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: repo.go
+//
+// Generated by this command:
+//
+//	mockgen -destination=./mock_repo.go -package=routetable -copyright_file ../../../hack/boilerplate/boilerplate.generatego.txt -source=repo.go Repository
+//
+// Package routetable is a generated GoMock package.
+package routetable
+
+import (
+	context "context"
+	reflect "reflect"
+
+	armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+	gomock "go.uber.org/mock/gomock"
+	cache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
+)
+
+// MockRepository is a mock of Repository interface.
+type MockRepository struct {
+	ctrl     *gomock.Controller
+	recorder *MockRepositoryMockRecorder
+}
+
+// MockRepositoryMockRecorder is the mock recorder for MockRepository.
+type MockRepositoryMockRecorder struct {
+	mock *MockRepository
+}
+
+// NewMockRepository creates a new mock instance.
+func NewMockRepository(ctrl *gomock.Controller) *MockRepository {
+	mock := &MockRepository{ctrl: ctrl}
+	mock.recorder = &MockRepositoryMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
+	return m.recorder
+}
+
+// CreateOrUpdate mocks base method.
+func (m *MockRepository) CreateOrUpdate(ctx context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, routeTable)
+	ret0, _ := ret[0].(*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateOrUpdate indicates an expected call of CreateOrUpdate.
+func (mr *MockRepositoryMockRecorder) CreateOrUpdate(ctx, routeTable any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockRepository)(nil).CreateOrUpdate), ctx, routeTable)
+}
+
+// Get mocks base method.
+func (m *MockRepository) Get(ctx context.Context, routeTableName string, crt cache.AzureCacheReadType) (*armnetwork.RouteTable, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get", ctx, routeTableName, crt)
+	ret0, _ := ret[0].(*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockRepositoryMockRecorder) Get(ctx, routeTableName, crt any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRepository)(nil).Get), ctx, routeTableName, crt)
+}
diff --git a/pkg/provider/routetable/repo.go b/pkg/provider/routetable/repo.go
new file mode 100644
index 000000000..fb5400df1
--- /dev/null
+++ b/pkg/provider/routetable/repo.go
@@ -0,0 +1,87 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package routetable
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+)
+
+// Generate mocks for the repository interface
+//go:generate mockgen -destination=./mock_repo.go -package=routetable -copyright_file ../../../hack/boilerplate/boilerplate.generatego.txt -source=repo.go Repository
+
+var (
+	ErrMissingRouteTableName = fmt.Errorf("missing RouteTable name")
+)
+
+type Repository interface {
+	Get(ctx context.Context, routeTableName string, crt cache.AzureCacheReadType) (*armnetwork.RouteTable, error)
+	CreateOrUpdate(ctx context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error)
+}
+
+type repo struct {
+	resourceGroup string
+	client        routetableclient.Interface
+	cache         cache.Resource
+}
+
+func NewRepo(
+	client routetableclient.Interface,
+	resourceGroup string,
+	cacheTTL time.Duration,
+	disableAPICallCache bool,
+) (Repository, error) {
+	c, err := NewCache(client, resourceGroup, cacheTTL, disableAPICallCache)
+	if err != nil {
+		return nil, fmt.Errorf("new RouteTable cache: %w", err)
+	}
+
+	return &repo{
+		resourceGroup: resourceGroup,
+		client:        client,
+		cache:         c,
+	}, nil
+}
+
+func (r *repo) Get(ctx context.Context, routeTableName string, crt cache.AzureCacheReadType) (*armnetwork.RouteTable, error) {
+	rt, err := r.cache.GetWithDeepCopy(ctx, routeTableName, crt)
+	if err != nil {
+		return nil, fmt.Errorf("get RouteTable: %w", err)
+	}
+
+	return rt.(*armnetwork.RouteTable), nil
+}
+
+func (r *repo) CreateOrUpdate(ctx context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+	if routeTable.Name == nil {
+		return nil, ErrMissingRouteTableName
+	}
+
+	rv, err := r.client.CreateOrUpdate(ctx, r.resourceGroup, *routeTable.Name, routeTable)
+	if err != nil {
+		return nil, fmt.Errorf("create or update RouteTable: %w", err)
+	}
+	_ = r.cache.Delete(*routeTable.Name)
+
+	return rv, nil
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/CHANGELOG.md
index fb1cc9db2..1ed8952c6 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/CHANGELOG.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Release History
 
+## 1.3.0 (2024-11-06)
+
+### Features Added
+* Added API Version support. Users can now change the default API Version by setting ClientOptions.APIVersion
+
 ## 1.2.0 (2024-10-21)
 
 ### Features Added
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/custom_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/custom_client.go
index a4070bda3..14ee4d534 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/custom_client.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/custom_client.go
@@ -38,6 +38,10 @@ func NewClient(vaultURL string, credential azcore.TokenCredential, options *Clie
 		},
 	)
 	azcoreClient, err := azcore.NewClient(moduleName, version, runtime.PipelineOptions{
+		APIVersion: runtime.APIVersionOptions{
+			Location: runtime.APIVersionLocationQueryParam,
+			Name:     "api-version",
+		},
 		PerRetry: []policy.Policy{authPolicy},
 		Tracing: runtime.TracingOptions{
 			Namespace: "Microsoft.KeyVault",
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/version.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/version.go
index ef8672ab1..0767563e8 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/version.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets/version.go
@@ -8,5 +8,5 @@ package azsecrets
 
 const (
 	moduleName = "github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets"
-	version    = "v1.2.0"
+	version    = "v1.3.0"
 )
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go
index f86286051..57d0e2777 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go
@@ -18,6 +18,8 @@ import (
 	"encoding/pem"
 	"errors"
 	"fmt"
+	"os"
+	"strings"
 
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache"
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base"
@@ -315,16 +317,21 @@ func New(authority, clientID string, cred Credential, options ...Option) (Client
 	if err != nil {
 		return Client{}, err
 	}
-
+	autoEnabledRegion := os.Getenv("MSAL_FORCE_REGION")
 	opts := clientOptions{
 		authority: authority,
 		// if the caller specified a token provider, it will handle all details of authentication, using Client only as a token cache
 		disableInstanceDiscovery: cred.tokenProvider != nil,
 		httpClient:               shared.DefaultClient,
+		azureRegion:              autoEnabledRegion,
 	}
 	for _, o := range options {
 		o(&opts)
 	}
+	if strings.EqualFold(opts.azureRegion, "DisableMsalForceRegion") {
+		opts.azureRegion = ""
+	}
+
 	baseOpts := []base.Option{
 		base.WithCacheAccessor(opts.accessor),
 		base.WithClientCapabilities(opts.capabilities),
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go
index 09a0d92f5..e473d1267 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go
@@ -89,8 +89,23 @@ type AuthResult struct {
 	ExpiresOn      time.Time
 	GrantedScopes  []string
 	DeclinedScopes []string
+	Metadata       AuthResultMetadata
 }
 
+// AuthResultMetadata which contains meta data for the AuthResult
+type AuthResultMetadata struct {
+	TokenSource TokenSource
+}
+
+type TokenSource int
+
+// These are all the types of token flows.
+const (
+	SourceUnknown    TokenSource = 0
+	IdentityProvider TokenSource = 1
+	Cache            TokenSource = 2
+)
+
 // AuthResultFromStorage creates an AuthResult from a storage token response (which is generated from the cache).
 func AuthResultFromStorage(storageTokenResponse storage.TokenResponse) (AuthResult, error) {
 	if err := storageTokenResponse.AccessToken.Validate(); err != nil {
@@ -109,7 +124,17 @@ func AuthResultFromStorage(storageTokenResponse storage.TokenResponse) (AuthResu
 			return AuthResult{}, fmt.Errorf("problem decoding JWT token: %w", err)
 		}
 	}
-	return AuthResult{account, idToken, accessToken, storageTokenResponse.AccessToken.ExpiresOn.T, grantedScopes, nil}, nil
+	return AuthResult{
+		Account:        account,
+		IDToken:        idToken,
+		AccessToken:    accessToken,
+		ExpiresOn:      storageTokenResponse.AccessToken.ExpiresOn.T,
+		GrantedScopes:  grantedScopes,
+		DeclinedScopes: nil,
+		Metadata: AuthResultMetadata{
+			TokenSource: Cache,
+		},
+	}, nil
 }
 
 // NewAuthResult creates an AuthResult.
@@ -123,6 +148,9 @@ func NewAuthResult(tokenResponse accesstokens.TokenResponse, account shared.Acco
 		AccessToken:   tokenResponse.AccessToken,
 		ExpiresOn:     tokenResponse.ExpiresOn.T,
 		GrantedScopes: tokenResponse.GrantedScopes.Slice,
+		Metadata: AuthResultMetadata{
+			TokenSource: IdentityProvider,
+		},
 	}, nil
 }
 
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/json.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/json.go
index 2238521f5..2134e57c9 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/json.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/json.go
@@ -18,10 +18,6 @@ import (
 )
 
 const addField = "AdditionalFields"
-const (
-	marshalJSON   = "MarshalJSON"
-	unmarshalJSON = "UnmarshalJSON"
-)
 
 var (
 	leftBrace  = []byte("{")[0]
@@ -106,48 +102,38 @@ func delimIs(got json.Token, want rune) bool {
 // hasMarshalJSON will determine if the value or a pointer to this value has
 // the MarshalJSON method.
 func hasMarshalJSON(v reflect.Value) bool {
-	if method := v.MethodByName(marshalJSON); method.Kind() != reflect.Invalid {
-		_, ok := v.Interface().(json.Marshaler)
-		return ok
-	}
-
-	if v.Kind() == reflect.Ptr {
-		v = v.Elem()
-	} else {
-		if !v.CanAddr() {
-			return false
+	ok := false
+	if _, ok = v.Interface().(json.Marshaler); !ok {
+		var i any
+		if v.Kind() == reflect.Ptr {
+			i = v.Elem().Interface()
+		} else if v.CanAddr() {
+			i = v.Addr().Interface()
 		}
-		v = v.Addr()
-	}
-
-	if method := v.MethodByName(marshalJSON); method.Kind() != reflect.Invalid {
-		_, ok := v.Interface().(json.Marshaler)
-		return ok
+		_, ok = i.(json.Marshaler)
 	}
-	return false
+	return ok
 }
 
 // callMarshalJSON will call MarshalJSON() method on the value or a pointer to this value.
 // This will panic if the method is not defined.
 func callMarshalJSON(v reflect.Value) ([]byte, error) {
-	if method := v.MethodByName(marshalJSON); method.Kind() != reflect.Invalid {
-		marsh := v.Interface().(json.Marshaler)
+	if marsh, ok := v.Interface().(json.Marshaler); ok {
 		return marsh.MarshalJSON()
 	}
 
 	if v.Kind() == reflect.Ptr {
-		v = v.Elem()
+		if marsh, ok := v.Elem().Interface().(json.Marshaler); ok {
+			return marsh.MarshalJSON()
+		}
 	} else {
 		if v.CanAddr() {
-			v = v.Addr()
+			if marsh, ok := v.Addr().Interface().(json.Marshaler); ok {
+				return marsh.MarshalJSON()
+			}
 		}
 	}
 
-	if method := v.MethodByName(unmarshalJSON); method.Kind() != reflect.Invalid {
-		marsh := v.Interface().(json.Marshaler)
-		return marsh.MarshalJSON()
-	}
-
 	panic(fmt.Sprintf("callMarshalJSON called on type %T that does not have MarshalJSON defined", v.Interface()))
 }
 
@@ -162,12 +148,8 @@ func hasUnmarshalJSON(v reflect.Value) bool {
 		v = v.Addr()
 	}
 
-	if method := v.MethodByName(unmarshalJSON); method.Kind() != reflect.Invalid {
-		_, ok := v.Interface().(json.Unmarshaler)
-		return ok
-	}
-
-	return false
+	_, ok := v.Interface().(json.Unmarshaler)
+	return ok
 }
 
 // hasOmitEmpty indicates if the field has instructed us to not output
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local/server.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local/server.go
index 04236ff31..fda5d7dd3 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local/server.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local/server.go
@@ -7,6 +7,7 @@ package local
 import (
 	"context"
 	"fmt"
+	"html"
 	"net"
 	"net/http"
 	"strconv"
@@ -141,7 +142,7 @@ func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
 
 	headerErr := q.Get("error")
 	if headerErr != "" {
-		desc := q.Get("error_description")
+		desc := html.EscapeString(q.Get("error_description"))
 		// Note: It is a little weird we handle some errors by not going to the failPage. If they all should,
 		// change this to s.error() and make s.error() write the failPage instead of an error code.
 		_, _ = w.Write([]byte(fmt.Sprintf(failPage, headerErr, desc)))
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/oauth.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/oauth.go
index ef8d908a4..e06531344 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/oauth.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/oauth.go
@@ -10,6 +10,8 @@ import (
 	"io"
 	"time"
 
+	"github.com/google/uuid"
+
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors"
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/exported"
 	internalTime "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/types/time"
@@ -18,7 +20,6 @@ import (
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust"
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs"
-	"github.com/google/uuid"
 )
 
 // ResolveEndpointer contains the methods for resolving authority endpoints.
@@ -331,7 +332,7 @@ func (t *Client) DeviceCode(ctx context.Context, authParams authority.AuthParams
 func (t *Client) resolveEndpoint(ctx context.Context, authParams *authority.AuthParams, userPrincipalName string) error {
 	endpoints, err := t.Resolver.ResolveEndpoints(ctx, authParams.AuthorityInfo, userPrincipalName)
 	if err != nil {
-		return fmt.Errorf("unable to resolve an endpoint: %s", err)
+		return fmt.Errorf("unable to resolve an endpoint: %w", err)
 	}
 	authParams.Endpoints = endpoints
 	return nil
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go
index 9d60734f8..362406554 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go
@@ -23,7 +23,7 @@ import (
 
 const (
 	authorizationEndpoint             = "https://%v/%v/oauth2/v2.0/authorize"
-	instanceDiscoveryEndpoint         = "https://%v/common/discovery/instance"
+	aadInstanceDiscoveryEndpoint      = "https://%v/common/discovery/instance"
 	tenantDiscoveryEndpointWithRegion = "https://%s.%s/%s/v2.0/.well-known/openid-configuration"
 	regionName                        = "REGION_NAME"
 	defaultAPIVersion                 = "2021-10-01"
@@ -47,13 +47,12 @@ type jsonCaller interface {
 }
 
 var aadTrustedHostList = map[string]bool{
-	"login.windows.net":            true, // Microsoft Azure Worldwide - Used in validation scenarios where host is not this list
-	"login.chinacloudapi.cn":       true, // Microsoft Azure China
-	"login.microsoftonline.de":     true, // Microsoft Azure Blackforest
-	"login-us.microsoftonline.com": true, // Microsoft Azure US Government - Legacy
-	"login.microsoftonline.us":     true, // Microsoft Azure US Government
-	"login.microsoftonline.com":    true, // Microsoft Azure Worldwide
-	"login.cloudgovapi.us":         true, // Microsoft Azure US Government
+	"login.windows.net":                true, // Microsoft Azure Worldwide - Used in validation scenarios where host is not this list
+	"login.partner.microsoftonline.cn": true, // Microsoft Azure China
+	"login.microsoftonline.de":         true, // Microsoft Azure Blackforest
+	"login-us.microsoftonline.com":     true, // Microsoft Azure US Government - Legacy
+	"login.microsoftonline.us":         true, // Microsoft Azure US Government
+	"login.microsoftonline.com":        true, // Microsoft Azure Worldwide
 }
 
 // TrustedHost checks if an AAD host is trusted/valid.
@@ -137,8 +136,12 @@ const (
 const (
 	AAD  = "MSSTS"
 	ADFS = "ADFS"
+	DSTS = "DSTS"
 )
 
+// DSTSTenant is referenced throughout multiple files, let us use a const in case we ever need to change it.
+const DSTSTenant = "7a433bfc-2514-4697-b467-e0933190487f"
+
 // AuthenticationScheme is an extensibility mechanism designed to be used only by Azure Arc for proof of possession access tokens.
 type AuthenticationScheme interface {
 	// Extra parameters that are added to the request to the /token endpoint.
@@ -236,23 +239,26 @@ func NewAuthParams(clientID string, authorityInfo Info) AuthParams {
 //   - the client is configured to authenticate only Microsoft accounts via the "consumers" endpoint
 //   - the resulting authority URL is invalid
 func (p AuthParams) WithTenant(ID string) (AuthParams, error) {
-	switch ID {
-	case "", p.AuthorityInfo.Tenant:
-		// keep the default tenant because the caller didn't override it
+	if ID == "" || ID == p.AuthorityInfo.Tenant {
 		return p, nil
-	case "common", "consumers", "organizations":
-		if p.AuthorityInfo.AuthorityType == AAD {
+	}
+
+	var authority string
+	switch p.AuthorityInfo.AuthorityType {
+	case AAD:
+		if ID == "common" || ID == "consumers" || ID == "organizations" {
 			return p, fmt.Errorf(`tenant ID must be a specific tenant, not "%s"`, ID)
 		}
-		// else we'll return a better error below
-	}
-	if p.AuthorityInfo.AuthorityType != AAD {
-		return p, errors.New("the authority doesn't support tenants")
-	}
-	if p.AuthorityInfo.Tenant == "consumers" {
-		return p, errors.New(`client is configured to authenticate only personal Microsoft accounts, via the "consumers" endpoint`)
+		if p.AuthorityInfo.Tenant == "consumers" {
+			return p, errors.New(`client is configured to authenticate only personal Microsoft accounts, via the "consumers" endpoint`)
+		}
+		authority = "https://" + path.Join(p.AuthorityInfo.Host, ID)
+	case ADFS:
+		return p, errors.New("ADFS authority doesn't support tenants")
+	case DSTS:
+		return p, errors.New("dSTS authority doesn't support tenants")
 	}
-	authority := "https://" + path.Join(p.AuthorityInfo.Host, ID)
+
 	info, err := NewInfoFromAuthorityURI(authority, p.AuthorityInfo.ValidateAuthority, p.AuthorityInfo.InstanceDiscoveryDisabled)
 	if err == nil {
 		info.Region = p.AuthorityInfo.Region
@@ -344,44 +350,59 @@ type Info struct {
 	Host                      string
 	CanonicalAuthorityURI     string
 	AuthorityType             string
-	UserRealmURIPrefix        string
 	ValidateAuthority         bool
 	Tenant                    string
 	Region                    string
 	InstanceDiscoveryDisabled bool
 }
 
-func firstPathSegment(u *url.URL) (string, error) {
-	pathParts := strings.Split(u.EscapedPath(), "/")
-	if len(pathParts) >= 2 {
-		return pathParts[1], nil
-	}
-
-	return "", errors.New(`authority must be an https URL such as "https://login.microsoftonline.com/<your tenant>"`)
-}
-
 // NewInfoFromAuthorityURI creates an AuthorityInfo instance from the authority URL provided.
 func NewInfoFromAuthorityURI(authority string, validateAuthority bool, instanceDiscoveryDisabled bool) (Info, error) {
-	u, err := url.Parse(strings.ToLower(authority))
-	if err != nil || u.Scheme != "https" {
-		return Info{}, errors.New(`authority must be an https URL such as "https://login.microsoftonline.com/<your tenant>"`)
+
+	cannonicalAuthority := authority
+
+	// suffix authority with / if it doesn't have one
+	if !strings.HasSuffix(cannonicalAuthority, "/") {
+		cannonicalAuthority += "/"
 	}
 
-	tenant, err := firstPathSegment(u)
+	u, err := url.Parse(strings.ToLower(cannonicalAuthority))
+
 	if err != nil {
-		return Info{}, err
+		return Info{}, fmt.Errorf("couldn't parse authority url: %w", err)
+	}
+	if u.Scheme != "https" {
+		return Info{}, errors.New("authority url scheme must be https")
+	}
+
+	pathParts := strings.Split(u.EscapedPath(), "/")
+	if len(pathParts) < 3 {
+		return Info{}, errors.New(`authority must be an URL such as "https://login.microsoftonline.com/<your tenant>"`)
 	}
-	authorityType := AAD
-	if tenant == "adfs" {
+
+	var authorityType, tenant string
+	switch pathParts[1] {
+	case "adfs":
 		authorityType = ADFS
+	case "dstsv2":
+		if len(pathParts) != 4 {
+			return Info{}, fmt.Errorf("dSTS authority must be an https URL such as https://<authority>/dstsv2/%s", DSTSTenant)
+		}
+		if pathParts[2] != DSTSTenant {
+			return Info{}, fmt.Errorf("dSTS authority only accepts a single tenant %q", DSTSTenant)
+		}
+		authorityType = DSTS
+		tenant = DSTSTenant
+	default:
+		authorityType = AAD
+		tenant = pathParts[1]
 	}
 
 	// u.Host includes the port, if any, which is required for private cloud deployments
 	return Info{
 		Host:                      u.Host,
-		CanonicalAuthorityURI:     fmt.Sprintf("https://%v/%v/", u.Host, tenant),
+		CanonicalAuthorityURI:     cannonicalAuthority,
 		AuthorityType:             authorityType,
-		UserRealmURIPrefix:        fmt.Sprintf("https://%v/common/userrealm/", u.Hostname()),
 		ValidateAuthority:         validateAuthority,
 		Tenant:                    tenant,
 		InstanceDiscoveryDisabled: instanceDiscoveryDisabled,
@@ -525,7 +546,7 @@ func (c Client) AADInstanceDiscovery(ctx context.Context, authorityInfo Info) (I
 			discoveryHost = authorityInfo.Host
 		}
 
-		endpoint := fmt.Sprintf(instanceDiscoveryEndpoint, discoveryHost)
+		endpoint := fmt.Sprintf(aadInstanceDiscoveryEndpoint, discoveryHost)
 		err = c.Comm.JSONCall(ctx, endpoint, http.Header{}, qv, nil, &resp)
 	}
 	return resp, err
@@ -543,17 +564,19 @@ func detectRegion(ctx context.Context) string {
 	client := http.Client{
 		Timeout: time.Duration(2 * time.Second),
 	}
-	req, _ := http.NewRequest("GET", imdsEndpoint, nil)
+	req, _ := http.NewRequestWithContext(ctx, http.MethodGet, imdsEndpoint, nil)
 	req.Header.Set("Metadata", "true")
 	resp, err := client.Do(req)
+	if err == nil {
+		defer resp.Body.Close()
+	}
 	// If the request times out or there is an error, it is retried once
-	if err != nil || resp.StatusCode != 200 {
+	if err != nil || resp.StatusCode != http.StatusOK {
 		resp, err = client.Do(req)
-		if err != nil || resp.StatusCode != 200 {
+		if err != nil || resp.StatusCode != http.StatusOK {
 			return ""
 		}
 	}
-	defer resp.Body.Close()
 	response, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return ""
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/comm.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/comm.go
index 7d9ec7cd3..d62aac74e 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/comm.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/comm.go
@@ -18,10 +18,11 @@ import (
 	"strings"
 	"time"
 
+	"github.com/google/uuid"
+
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors"
 	customJSON "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json"
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/version"
-	"github.com/google/uuid"
 )
 
 // HTTPClient represents an HTTP client.
@@ -70,15 +71,13 @@ func (c *Client) JSONCall(ctx context.Context, endpoint string, headers http.Hea
 		unmarshal = customJSON.Unmarshal
 	}
 
-	u, err := url.Parse(endpoint)
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s?%s", endpoint, qv.Encode()), nil)
 	if err != nil {
-		return fmt.Errorf("could not parse path URL(%s): %w", endpoint, err)
+		return fmt.Errorf("could not create request: %w", err)
 	}
-	u.RawQuery = qv.Encode()
 
 	addStdHeaders(headers)
-
-	req := &http.Request{Method: http.MethodGet, URL: u, Header: headers}
+	req.Header = headers
 
 	if body != nil {
 		// Note: In case your wondering why we are not gzip encoding....
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/resolvers.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/resolvers.go
index 0ade41179..4030ec8d8 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/resolvers.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/resolvers.go
@@ -18,9 +18,6 @@ import (
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
 )
 
-// ADFS is an active directory federation service authority type.
-const ADFS = "ADFS"
-
 type cacheEntry struct {
 	Endpoints             authority.Endpoints
 	ValidForDomainsInList map[string]bool
@@ -51,7 +48,7 @@ func (m *authorityEndpoint) ResolveEndpoints(ctx context.Context, authorityInfo
 		return endpoints, nil
 	}
 
-	endpoint, err := m.openIDConfigurationEndpoint(ctx, authorityInfo, userPrincipalName)
+	endpoint, err := m.openIDConfigurationEndpoint(ctx, authorityInfo)
 	if err != nil {
 		return authority.Endpoints{}, err
 	}
@@ -83,7 +80,7 @@ func (m *authorityEndpoint) cachedEndpoints(authorityInfo authority.Info, userPr
 	defer m.mu.Unlock()
 
 	if cacheEntry, ok := m.cache[authorityInfo.CanonicalAuthorityURI]; ok {
-		if authorityInfo.AuthorityType == ADFS {
+		if authorityInfo.AuthorityType == authority.ADFS {
 			domain, err := adfsDomainFromUpn(userPrincipalName)
 			if err == nil {
 				if _, ok := cacheEntry.ValidForDomainsInList[domain]; ok {
@@ -102,7 +99,7 @@ func (m *authorityEndpoint) addCachedEndpoints(authorityInfo authority.Info, use
 
 	updatedCacheEntry := createcacheEntry(endpoints)
 
-	if authorityInfo.AuthorityType == ADFS {
+	if authorityInfo.AuthorityType == authority.ADFS {
 		// Since we're here, we've made a call to the backend.  We want to ensure we're caching
 		// the latest values from the server.
 		if cacheEntry, ok := m.cache[authorityInfo.CanonicalAuthorityURI]; ok {
@@ -119,9 +116,12 @@ func (m *authorityEndpoint) addCachedEndpoints(authorityInfo authority.Info, use
 	m.cache[authorityInfo.CanonicalAuthorityURI] = updatedCacheEntry
 }
 
-func (m *authorityEndpoint) openIDConfigurationEndpoint(ctx context.Context, authorityInfo authority.Info, userPrincipalName string) (string, error) {
-	if authorityInfo.Tenant == "adfs" {
+func (m *authorityEndpoint) openIDConfigurationEndpoint(ctx context.Context, authorityInfo authority.Info) (string, error) {
+	if authorityInfo.AuthorityType == authority.ADFS {
 		return fmt.Sprintf("https://%s/adfs/.well-known/openid-configuration", authorityInfo.Host), nil
+	} else if authorityInfo.AuthorityType == authority.DSTS {
+		return fmt.Sprintf("https://%s/dstsv2/%s/v2.0/.well-known/openid-configuration", authorityInfo.Host, authority.DSTSTenant), nil
+
 	} else if authorityInfo.ValidateAuthority && !authority.TrustedHost(authorityInfo.Host) {
 		resp, err := m.rest.Authority().AADInstanceDiscovery(ctx, authorityInfo)
 		if err != nil {
@@ -134,7 +134,6 @@ func (m *authorityEndpoint) openIDConfigurationEndpoint(ctx context.Context, aut
 			return "", err
 		}
 		return resp.TenantDiscoveryEndpoint, nil
-
 	}
 
 	return authorityInfo.CanonicalAuthorityURI + "v2.0/.well-known/openid-configuration", nil
diff --git a/vendor/go.opentelemetry.io/otel/.gitignore b/vendor/go.opentelemetry.io/otel/.gitignore
index 895c7664b..ae8577ef3 100644
--- a/vendor/go.opentelemetry.io/otel/.gitignore
+++ b/vendor/go.opentelemetry.io/otel/.gitignore
@@ -12,11 +12,3 @@ go.work
 go.work.sum
 
 gen/
-
-/example/dice/dice
-/example/namedtracer/namedtracer
-/example/otel-collector/otel-collector
-/example/opencensus/opencensus
-/example/passthrough/passthrough
-/example/prometheus/prometheus
-/example/zipkin/zipkin
diff --git a/vendor/go.opentelemetry.io/otel/.golangci.yml b/vendor/go.opentelemetry.io/otel/.golangci.yml
index d09555506..dbfb2a165 100644
--- a/vendor/go.opentelemetry.io/otel/.golangci.yml
+++ b/vendor/go.opentelemetry.io/otel/.golangci.yml
@@ -127,8 +127,6 @@ linters-settings:
           - "**/metric/**/*.go"
           - "**/bridge/*.go"
           - "**/bridge/**/*.go"
-          - "**/example/*.go"
-          - "**/example/**/*.go"
           - "**/trace/*.go"
           - "**/trace/**/*.go"
           - "**/log/*.go"
diff --git a/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/vendor/go.opentelemetry.io/otel/CHANGELOG.md
index 4b361d026..8f68dbd04 100644
--- a/vendor/go.opentelemetry.io/otel/CHANGELOG.md
+++ b/vendor/go.opentelemetry.io/otel/CHANGELOG.md
@@ -11,6 +11,52 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 <!-- Released section -->
 <!-- Don't change this section unless doing release -->
 
+## [1.32.0/0.54.0/0.8.0/0.0.11] 2024-11-08
+
+### Added
+
+- Add `go.opentelemetry.io/otel/sdk/metric/exemplar.AlwaysOffFilter`, which can be used to disable exemplar recording. (#5850)
+- Add `go.opentelemetry.io/otel/sdk/metric.WithExemplarFilter`, which can be used to configure the exemplar filter used by the metrics SDK. (#5850)
+- Add `ExemplarReservoirProviderSelector` and `DefaultExemplarReservoirProviderSelector` to `go.opentelemetry.io/otel/sdk/metric`, which defines the exemplar reservoir to use based on the aggregation of the metric. (#5861)
+- Add `ExemplarReservoirProviderSelector` to `go.opentelemetry.io/otel/sdk/metric.Stream` to allow using views to configure the exemplar reservoir to use for a metric. (#5861)
+- Add `ReservoirProvider`, `HistogramReservoirProvider` and `FixedSizeReservoirProvider` to `go.opentelemetry.io/otel/sdk/metric/exemplar` to make it convenient to use providers of Reservoirs. (#5861)
+- The `go.opentelemetry.io/otel/semconv/v1.27.0` package.
+  The package contains semantic conventions from the `v1.27.0` version of the OpenTelemetry Semantic Conventions. (#5894)
+- Add `Attributes attribute.Set` field to `Scope` in `go.opentelemetry.io/otel/sdk/instrumentation`. (#5903)
+- Add `Attributes attribute.Set` field to `ScopeRecords` in `go.opentelemetry.io/otel/log/logtest`. (#5927)
+- `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` adds instrumentation scope attributes. (#5934)
+- `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp` adds instrumentation scope attributes. (#5934)
+- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` adds instrumentation scope attributes. (#5935)
+- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` adds instrumentation scope attributes. (#5935)
+- `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc` adds instrumentation scope attributes. (#5933)
+- `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` adds instrumentation scope attributes. (#5933)
+- `go.opentelemetry.io/otel/exporters/prometheus` adds instrumentation scope attributes in `otel_scope_info` metric as labels. (#5932)
+
+### Changed
+
+- Support scope attributes and make them as identifying for `Tracer` in `go.opentelemetry.io/otel` and `go.opentelemetry.io/otel/sdk/trace`. (#5924)
+- Support scope attributes and make them as identifying for `Meter` in `go.opentelemetry.io/otel` and `go.opentelemetry.io/otel/sdk/metric`. (#5926)
+- Support scope attributes and make them as identifying for `Logger` in `go.opentelemetry.io/otel` and `go.opentelemetry.io/otel/sdk/log`. (#5925)
+- Make schema URL and scope attributes as identifying for `Tracer` in `go.opentelemetry.io/otel/bridge/opentracing`. (#5931)
+- Clear unneeded slice elements to allow GC to collect the objects in `go.opentelemetry.io/otel/sdk/metric` and `go.opentelemetry.io/otel/sdk/trace`. (#5804)
+
+### Fixed
+
+- Global MeterProvider registration unwraps global instrument Observers, the undocumented Unwrap() methods are now private. (#5881)
+- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` now keeps the metadata already present in the context when `WithHeaders` is used. (#5892)
+- `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc` now keeps the metadata already present in the context when `WithHeaders` is used. (#5911)
+- `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` now keeps the metadata already present in the context when `WithHeaders` is used. (#5915)
+- Fix `go.opentelemetry.io/otel/exporters/prometheus` trying to add exemplars to Gauge metrics, which is unsupported. (#5912)
+- Fix `WithEndpointURL` to always use a secure connection when an https URL is passed in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#5944)
+- Fix `WithEndpointURL` to always use a secure connection when an https URL is passed in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#5944)
+- Fix `WithEndpointURL` to always use a secure connection when an https URL is passed in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#5944)
+- Fix `WithEndpointURL` to always use a secure connection when an https URL is passed in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#5944)
+- Fix incorrect metrics generated from callbacks when multiple readers are used in `go.opentelemetry.io/otel/sdk/metric`. (#5900)
+
+### Removed
+
+- Remove all examples under `go.opentelemetry.io/otel/example` as they are moved to [Contrib repository](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/examples). (#5930)
+
 ## [1.31.0/0.53.0/0.7.0/0.0.10] 2024-10-11
 
 ### Added
@@ -3110,7 +3156,8 @@ It contains api and sdk for trace and meter.
 - CircleCI build CI manifest files.
 - CODEOWNERS file to track owners of this project.
 
-[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.31.0...HEAD
+[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.32.0...HEAD
+[1.32.0/0.54.0/0.8.0/0.0.11]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.32.0
 [1.31.0/0.53.0/0.7.0/0.0.10]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.31.0
 [1.30.0/0.52.0/0.6.0/0.0.9]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.30.0
 [1.29.0/0.51.0/0.5.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.29.0
diff --git a/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md b/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md
index bb3396557..22a2e9dbd 100644
--- a/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md
+++ b/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md
@@ -629,6 +629,10 @@ should be canceled.
 
 ## Approvers and Maintainers
 
+### Triagers
+
+- [Cheng-Zhen Yang](https://github.com/scorpionknifes), Independent
+
 ### Approvers
 
 ### Maintainers
@@ -641,13 +645,13 @@ should be canceled.
 
 ### Emeritus
 
-- [Aaron Clawson](https://github.com/MadVikingGod), LightStep
-- [Anthony Mirabella](https://github.com/Aneurysm9), AWS
-- [Chester Cheung](https://github.com/hanyuancheung), Tencent
-- [Evan Torrie](https://github.com/evantorrie), Yahoo
-- [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep
-- [Josh MacDonald](https://github.com/jmacd), LightStep
-- [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb
+- [Aaron Clawson](https://github.com/MadVikingGod)
+- [Anthony Mirabella](https://github.com/Aneurysm9)
+- [Chester Cheung](https://github.com/hanyuancheung)
+- [Evan Torrie](https://github.com/evantorrie)
+- [Gustavo Silva Paiva](https://github.com/paivagustavo)
+- [Josh MacDonald](https://github.com/jmacd)
+- [Liz Fong-Jones](https://github.com/lizthegrey)
 
 ### Become an Approver or a Maintainer
 
diff --git a/vendor/go.opentelemetry.io/otel/Makefile b/vendor/go.opentelemetry.io/otel/Makefile
index a1228a212..b8292a4fb 100644
--- a/vendor/go.opentelemetry.io/otel/Makefile
+++ b/vendor/go.opentelemetry.io/otel/Makefile
@@ -260,7 +260,7 @@ SEMCONVPKG ?= "semconv/"
 semconv-generate: $(SEMCONVGEN) $(SEMCONVKIT)
 	[ "$(TAG)" ] || ( echo "TAG unset: missing opentelemetry semantic-conventions tag"; exit 1 )
 	[ "$(OTEL_SEMCONV_REPO)" ] || ( echo "OTEL_SEMCONV_REPO unset: missing path to opentelemetry semantic-conventions repo"; exit 1 )
-	$(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=attribute_group -p conventionType=trace -f attribute_group.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
+	$(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=attribute_group -p conventionType=trace -f attribute_group.go -z "$(SEMCONVPKG)/capitalizations.txt" -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
 	$(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=metric  -f metric.go -t "$(SEMCONVPKG)/metric_template.j2" -s "$(TAG)"
 	$(SEMCONVKIT) -output "$(SEMCONVPKG)/$(TAG)" -tag "$(TAG)"
 
diff --git a/vendor/go.opentelemetry.io/otel/internal/global/instruments.go b/vendor/go.opentelemetry.io/otel/internal/global/instruments.go
index 3a0cc42f6..ae92a4251 100644
--- a/vendor/go.opentelemetry.io/otel/internal/global/instruments.go
+++ b/vendor/go.opentelemetry.io/otel/internal/global/instruments.go
@@ -13,7 +13,7 @@ import (
 
 // unwrapper unwraps to return the underlying instrument implementation.
 type unwrapper interface {
-	Unwrap() metric.Observable
+	unwrap() metric.Observable
 }
 
 type afCounter struct {
@@ -40,7 +40,7 @@ func (i *afCounter) setDelegate(m metric.Meter) {
 	i.delegate.Store(ctr)
 }
 
-func (i *afCounter) Unwrap() metric.Observable {
+func (i *afCounter) unwrap() metric.Observable {
 	if ctr := i.delegate.Load(); ctr != nil {
 		return ctr.(metric.Float64ObservableCounter)
 	}
@@ -71,7 +71,7 @@ func (i *afUpDownCounter) setDelegate(m metric.Meter) {
 	i.delegate.Store(ctr)
 }
 
-func (i *afUpDownCounter) Unwrap() metric.Observable {
+func (i *afUpDownCounter) unwrap() metric.Observable {
 	if ctr := i.delegate.Load(); ctr != nil {
 		return ctr.(metric.Float64ObservableUpDownCounter)
 	}
@@ -102,7 +102,7 @@ func (i *afGauge) setDelegate(m metric.Meter) {
 	i.delegate.Store(ctr)
 }
 
-func (i *afGauge) Unwrap() metric.Observable {
+func (i *afGauge) unwrap() metric.Observable {
 	if ctr := i.delegate.Load(); ctr != nil {
 		return ctr.(metric.Float64ObservableGauge)
 	}
@@ -133,7 +133,7 @@ func (i *aiCounter) setDelegate(m metric.Meter) {
 	i.delegate.Store(ctr)
 }
 
-func (i *aiCounter) Unwrap() metric.Observable {
+func (i *aiCounter) unwrap() metric.Observable {
 	if ctr := i.delegate.Load(); ctr != nil {
 		return ctr.(metric.Int64ObservableCounter)
 	}
@@ -164,7 +164,7 @@ func (i *aiUpDownCounter) setDelegate(m metric.Meter) {
 	i.delegate.Store(ctr)
 }
 
-func (i *aiUpDownCounter) Unwrap() metric.Observable {
+func (i *aiUpDownCounter) unwrap() metric.Observable {
 	if ctr := i.delegate.Load(); ctr != nil {
 		return ctr.(metric.Int64ObservableUpDownCounter)
 	}
@@ -195,7 +195,7 @@ func (i *aiGauge) setDelegate(m metric.Meter) {
 	i.delegate.Store(ctr)
 }
 
-func (i *aiGauge) Unwrap() metric.Observable {
+func (i *aiGauge) unwrap() metric.Observable {
 	if ctr := i.delegate.Load(); ctr != nil {
 		return ctr.(metric.Int64ObservableGauge)
 	}
diff --git a/vendor/go.opentelemetry.io/otel/internal/global/meter.go b/vendor/go.opentelemetry.io/otel/internal/global/meter.go
index e3db438a0..a6acd8dca 100644
--- a/vendor/go.opentelemetry.io/otel/internal/global/meter.go
+++ b/vendor/go.opentelemetry.io/otel/internal/global/meter.go
@@ -5,6 +5,7 @@ package global // import "go.opentelemetry.io/otel/internal/global"
 
 import (
 	"container/list"
+	"context"
 	"reflect"
 	"sync"
 
@@ -66,6 +67,7 @@ func (p *meterProvider) Meter(name string, opts ...metric.MeterOption) metric.Me
 		name:    name,
 		version: c.InstrumentationVersion(),
 		schema:  c.SchemaURL(),
+		attrs:   c.InstrumentationAttributes(),
 	}
 
 	if p.meters == nil {
@@ -472,8 +474,7 @@ func (m *meter) RegisterCallback(f metric.Callback, insts ...metric.Observable)
 	defer m.mtx.Unlock()
 
 	if m.delegate != nil {
-		insts = unwrapInstruments(insts)
-		return m.delegate.RegisterCallback(f, insts...)
+		return m.delegate.RegisterCallback(unwrapCallback(f), unwrapInstruments(insts)...)
 	}
 
 	reg := &registration{instruments: insts, function: f}
@@ -487,15 +488,11 @@ func (m *meter) RegisterCallback(f metric.Callback, insts ...metric.Observable)
 	return reg, nil
 }
 
-type wrapped interface {
-	unwrap() metric.Observable
-}
-
 func unwrapInstruments(instruments []metric.Observable) []metric.Observable {
 	out := make([]metric.Observable, 0, len(instruments))
 
 	for _, inst := range instruments {
-		if in, ok := inst.(wrapped); ok {
+		if in, ok := inst.(unwrapper); ok {
 			out = append(out, in.unwrap())
 		} else {
 			out = append(out, inst)
@@ -515,9 +512,61 @@ type registration struct {
 	unregMu sync.Mutex
 }
 
-func (c *registration) setDelegate(m metric.Meter) {
-	insts := unwrapInstruments(c.instruments)
+type unwrapObs struct {
+	embedded.Observer
+	obs metric.Observer
+}
+
+// unwrapFloat64Observable returns an expected metric.Float64Observable after
+// unwrapping the global object.
+func unwrapFloat64Observable(inst metric.Float64Observable) metric.Float64Observable {
+	if unwrapped, ok := inst.(unwrapper); ok {
+		if floatObs, ok := unwrapped.unwrap().(metric.Float64Observable); ok {
+			// Note: if the unwrapped object does not
+			// unwrap as an observable for either of the
+			// predicates here, it means an internal bug in
+			// this package.  We avoid logging an error in
+			// this case, because the SDK has to try its
+			// own type conversion on the object.  The SDK
+			// will see this and be forced to respond with
+			// its own error.
+			//
+			// This code uses a double-nested if statement
+			// to avoid creating a branch that is
+			// impossible to cover.
+			inst = floatObs
+		}
+	}
+	return inst
+}
+
+// unwrapInt64Observable returns an expected metric.Int64Observable after
+// unwrapping the global object.
+func unwrapInt64Observable(inst metric.Int64Observable) metric.Int64Observable {
+	if unwrapped, ok := inst.(unwrapper); ok {
+		if unint, ok := unwrapped.unwrap().(metric.Int64Observable); ok {
+			// See the comment in unwrapFloat64Observable().
+			inst = unint
+		}
+	}
+	return inst
+}
+
+func (uo *unwrapObs) ObserveFloat64(inst metric.Float64Observable, value float64, opts ...metric.ObserveOption) {
+	uo.obs.ObserveFloat64(unwrapFloat64Observable(inst), value, opts...)
+}
+
+func (uo *unwrapObs) ObserveInt64(inst metric.Int64Observable, value int64, opts ...metric.ObserveOption) {
+	uo.obs.ObserveInt64(unwrapInt64Observable(inst), value, opts...)
+}
 
+func unwrapCallback(f metric.Callback) metric.Callback {
+	return func(ctx context.Context, obs metric.Observer) error {
+		return f(ctx, &unwrapObs{obs: obs})
+	}
+}
+
+func (c *registration) setDelegate(m metric.Meter) {
 	c.unregMu.Lock()
 	defer c.unregMu.Unlock()
 
@@ -526,7 +575,7 @@ func (c *registration) setDelegate(m metric.Meter) {
 		return
 	}
 
-	reg, err := m.RegisterCallback(c.function, insts...)
+	reg, err := m.RegisterCallback(unwrapCallback(c.function), unwrapInstruments(c.instruments)...)
 	if err != nil {
 		GetErrorHandler().Handle(err)
 		return
diff --git a/vendor/go.opentelemetry.io/otel/internal/global/trace.go b/vendor/go.opentelemetry.io/otel/internal/global/trace.go
index e31f442b4..ac65262c6 100644
--- a/vendor/go.opentelemetry.io/otel/internal/global/trace.go
+++ b/vendor/go.opentelemetry.io/otel/internal/global/trace.go
@@ -87,6 +87,7 @@ func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T
 		name:    name,
 		version: c.InstrumentationVersion(),
 		schema:  c.SchemaURL(),
+		attrs:   c.InstrumentationAttributes(),
 	}
 
 	if p.tracers == nil {
@@ -102,7 +103,12 @@ func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T
 	return t
 }
 
-type il struct{ name, version, schema string }
+type il struct {
+	name    string
+	version string
+	schema  string
+	attrs   attribute.Set
+}
 
 // tracer is a placeholder for a trace.Tracer.
 //
diff --git a/vendor/go.opentelemetry.io/otel/version.go b/vendor/go.opentelemetry.io/otel/version.go
index 6d3c7b1f4..59e248161 100644
--- a/vendor/go.opentelemetry.io/otel/version.go
+++ b/vendor/go.opentelemetry.io/otel/version.go
@@ -5,5 +5,5 @@ package otel // import "go.opentelemetry.io/otel"
 
 // Version is the current release version of OpenTelemetry in use.
 func Version() string {
-	return "1.31.0"
+	return "1.32.0"
 }
diff --git a/vendor/go.opentelemetry.io/otel/versions.yaml b/vendor/go.opentelemetry.io/otel/versions.yaml
index cdebdb5eb..c04b12f6b 100644
--- a/vendor/go.opentelemetry.io/otel/versions.yaml
+++ b/vendor/go.opentelemetry.io/otel/versions.yaml
@@ -3,19 +3,13 @@
 
 module-sets:
   stable-v1:
-    version: v1.31.0
+    version: v1.32.0
     modules:
       - go.opentelemetry.io/otel
       - go.opentelemetry.io/otel/bridge/opencensus
       - go.opentelemetry.io/otel/bridge/opencensus/test
       - go.opentelemetry.io/otel/bridge/opentracing
       - go.opentelemetry.io/otel/bridge/opentracing/test
-      - go.opentelemetry.io/otel/example/dice
-      - go.opentelemetry.io/otel/example/namedtracer
-      - go.opentelemetry.io/otel/example/opencensus
-      - go.opentelemetry.io/otel/example/otel-collector
-      - go.opentelemetry.io/otel/example/passthrough
-      - go.opentelemetry.io/otel/example/zipkin
       - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc
       - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
       - go.opentelemetry.io/otel/exporters/otlp/otlptrace
@@ -29,12 +23,11 @@ module-sets:
       - go.opentelemetry.io/otel/sdk/metric
       - go.opentelemetry.io/otel/trace
   experimental-metrics:
-    version: v0.53.0
+    version: v0.54.0
     modules:
-      - go.opentelemetry.io/otel/example/prometheus
       - go.opentelemetry.io/otel/exporters/prometheus
   experimental-logs:
-    version: v0.7.0
+    version: v0.8.0
     modules:
       - go.opentelemetry.io/otel/log
       - go.opentelemetry.io/otel/sdk/log
@@ -42,7 +35,7 @@ module-sets:
       - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp
       - go.opentelemetry.io/otel/exporters/stdout/stdoutlog
   experimental-schema:
-    version: v0.0.10
+    version: v0.0.11
     modules:
       - go.opentelemetry.io/otel/schema
 excluded-modules:
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go
index 333da285b..bd896bdc7 100644
--- a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go
+++ b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego
+//go:build (!amd64 && !ppc64le && !ppc64 && !s390x) || !gc || purego
 
 package poly1305
 
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go
similarity index 95%
rename from vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go
rename to vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go
index 4aec4874b..1a1679aaa 100644
--- a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build gc && !purego
+//go:build gc && !purego && (ppc64 || ppc64le)
 
 package poly1305
 
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s
similarity index 89%
rename from vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s
rename to vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s
index b3c1699bf..6899a1dab 100644
--- a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s
@@ -2,15 +2,25 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build gc && !purego
+//go:build gc && !purego && (ppc64 || ppc64le)
 
 #include "textflag.h"
 
 // This was ported from the amd64 implementation.
 
+#ifdef GOARCH_ppc64le
+#define LE_MOVD MOVD
+#define LE_MOVWZ MOVWZ
+#define LE_MOVHZ MOVHZ
+#else
+#define LE_MOVD MOVDBR
+#define LE_MOVWZ MOVWBR
+#define LE_MOVHZ MOVHBR
+#endif
+
 #define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \
-	MOVD (msg), t0;  \
-	MOVD 8(msg), t1; \
+	LE_MOVD (msg)( R0), t0; \
+	LE_MOVD (msg)(R24), t1; \
 	MOVD $1, t2;     \
 	ADDC t0, h0, h0; \
 	ADDE t1, h1, h1; \
@@ -50,10 +60,6 @@
 	ADDE   t3, h1, h1;  \
 	ADDZE  h2
 
-DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
-DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
-GLOBL ·poly1305Mask<>(SB), RODATA, $16
-
 // func update(state *[7]uint64, msg []byte)
 TEXT ·update(SB), $0-32
 	MOVD state+0(FP), R3
@@ -66,6 +72,8 @@ TEXT ·update(SB), $0-32
 	MOVD 24(R3), R11 // r0
 	MOVD 32(R3), R12 // r1
 
+	MOVD $8, R24
+
 	CMP R5, $16
 	BLT bytes_between_0_and_15
 
@@ -94,7 +102,7 @@ flush_buffer:
 
 	// Greater than 8 -- load the rightmost remaining bytes in msg
 	// and put into R17 (h1)
-	MOVD (R4)(R21), R17
+	LE_MOVD (R4)(R21), R17
 	MOVD $16, R22
 
 	// Find the offset to those bytes
@@ -118,7 +126,7 @@ just1:
 	BLT less8
 
 	// Exactly 8
-	MOVD (R4), R16
+	LE_MOVD (R4), R16
 
 	CMP R17, $0
 
@@ -133,7 +141,7 @@ less8:
 	MOVD  $0, R22   // shift count
 	CMP   R5, $4
 	BLT   less4
-	MOVWZ (R4), R16
+	LE_MOVWZ (R4), R16
 	ADD   $4, R4
 	ADD   $-4, R5
 	MOVD  $32, R22
@@ -141,7 +149,7 @@ less8:
 less4:
 	CMP   R5, $2
 	BLT   less2
-	MOVHZ (R4), R21
+	LE_MOVHZ (R4), R21
 	SLD   R22, R21, R21
 	OR    R16, R21, R16
 	ADD   $16, R22
diff --git a/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s b/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s
new file mode 100644
index 000000000..ec2acfe54
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s
@@ -0,0 +1,17 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin && amd64 && gc
+
+#include "textflag.h"
+
+TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0
+	JMP	libc_sysctl(SB)
+GLOBL	·libc_sysctl_trampoline_addr(SB), RODATA, $8
+DATA	·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB)
+
+TEXT libc_sysctlbyname_trampoline<>(SB),NOSPLIT,$0-0
+	JMP	libc_sysctlbyname(SB)
+GLOBL	·libc_sysctlbyname_trampoline_addr(SB), RODATA, $8
+DATA	·libc_sysctlbyname_trampoline_addr(SB)/8, $libc_sysctlbyname_trampoline<>(SB)
diff --git a/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go b/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go
new file mode 100644
index 000000000..b838cb9e9
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go
@@ -0,0 +1,61 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin && amd64 && gc
+
+package cpu
+
+// darwinSupportsAVX512 checks Darwin kernel for AVX512 support via sysctl
+// call (see issue 43089). It also restricts AVX512 support for Darwin to
+// kernel version 21.3.0 (MacOS 12.2.0) or later (see issue 49233).
+//
+// Background:
+// Darwin implements a special mechanism to economize on thread state when
+// AVX512 specific registers are not in use. This scheme minimizes state when
+// preempting threads that haven't yet used any AVX512 instructions, but adds
+// special requirements to check for AVX512 hardware support at runtime (e.g.
+// via sysctl call or commpage inspection). See issue 43089 and link below for
+// full background:
+// https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.1.10/osfmk/i386/fpu.c#L214-L240
+//
+// Additionally, all versions of the Darwin kernel from 19.6.0 through 21.2.0
+// (corresponding to MacOS 10.15.6 - 12.1) have a bug that can cause corruption
+// of the AVX512 mask registers (K0-K7) upon signal return. For this reason
+// AVX512 is considered unsafe to use on Darwin for kernel versions prior to
+// 21.3.0, where a fix has been confirmed. See issue 49233 for full background.
+func darwinSupportsAVX512() bool {
+	return darwinSysctlEnabled([]byte("hw.optional.avx512f\x00")) && darwinKernelVersionCheck(21, 3, 0)
+}
+
+// Ensure Darwin kernel version is at least major.minor.patch, avoiding dependencies
+func darwinKernelVersionCheck(major, minor, patch int) bool {
+	var release [256]byte
+	err := darwinOSRelease(&release)
+	if err != nil {
+		return false
+	}
+
+	var mmp [3]int
+	c := 0
+Loop:
+	for _, b := range release[:] {
+		switch {
+		case b >= '0' && b <= '9':
+			mmp[c] = 10*mmp[c] + int(b-'0')
+		case b == '.':
+			c++
+			if c > 2 {
+				return false
+			}
+		case b == 0:
+			break Loop
+		default:
+			return false
+		}
+	}
+	if c != 2 {
+		return false
+	}
+	return mmp[0] > major || mmp[0] == major && (mmp[1] > minor || mmp[1] == minor && mmp[2] >= patch)
+}
diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
index 910728fb1..32a44514e 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
@@ -6,10 +6,10 @@
 
 package cpu
 
-// cpuid is implemented in cpu_x86.s for gc compiler
+// cpuid is implemented in cpu_gc_x86.s for gc compiler
 // and in cpu_gccgo.c for gccgo.
 func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
 
-// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler
+// xgetbv with ecx = 0 is implemented in cpu_gc_x86.s for gc compiler
 // and in cpu_gccgo.c for gccgo.
 func xgetbv() (eax, edx uint32)
diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.s b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.s
similarity index 94%
rename from vendor/golang.org/x/sys/cpu/cpu_x86.s
rename to vendor/golang.org/x/sys/cpu/cpu_gc_x86.s
index 7d7ba33ef..ce208ce6d 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_x86.s
+++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.s
@@ -18,7 +18,7 @@ TEXT ·cpuid(SB), NOSPLIT, $0-24
 	RET
 
 // func xgetbv() (eax, edx uint32)
-TEXT ·xgetbv(SB),NOSPLIT,$0-8
+TEXT ·xgetbv(SB), NOSPLIT, $0-8
 	MOVL $0, CX
 	XGETBV
 	MOVL AX, eax+0(FP)
diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go
index 99c60fe9f..170d21ddf 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go
@@ -23,9 +23,3 @@ func xgetbv() (eax, edx uint32) {
 	gccgoXgetbv(&a, &d)
 	return a, d
 }
-
-// gccgo doesn't build on Darwin, per:
-// https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gcc.rb#L76
-func darwinSupportsAVX512() bool {
-	return false
-}
diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
index 08f35ea17..f1caf0f78 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
@@ -110,7 +110,6 @@ func doinit() {
 	ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM)
 	ARM64.HasDIT = isSet(hwCap, hwcap_DIT)
 
-
 	// HWCAP2 feature bits
 	ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2)
 	ARM64.HasI8MM = isSet(hwCap2, hwcap2_I8MM)
diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_x86.go b/vendor/golang.org/x/sys/cpu/cpu_other_x86.go
new file mode 100644
index 000000000..a0fd7e2f7
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/cpu_other_x86.go
@@ -0,0 +1,11 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build 386 || amd64p32 || (amd64 && (!darwin || !gc))
+
+package cpu
+
+func darwinSupportsAVX512() bool {
+	panic("only implemented for gc && amd64 && darwin")
+}
diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go
index c29f5e4c5..600a68078 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_x86.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go
@@ -92,10 +92,8 @@ func archInit() {
 		osSupportsAVX = isSet(1, eax) && isSet(2, eax)
 
 		if runtime.GOOS == "darwin" {
-			// Darwin doesn't save/restore AVX-512 mask registers correctly across signal handlers.
-			// Since users can't rely on mask register contents, let's not advertise AVX-512 support.
-			// See issue 49233.
-			osSupportsAVX512 = false
+			// Darwin requires special AVX512 checks, see cpu_darwin_x86.go
+			osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512()
 		} else {
 			// Check if OPMASK and ZMM registers have OS support.
 			osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax)
diff --git a/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go b/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go
new file mode 100644
index 000000000..4d0888b0c
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go
@@ -0,0 +1,98 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Minimal copy of x/sys/unix so the cpu package can make a
+// system call on Darwin without depending on x/sys/unix.
+
+//go:build darwin && amd64 && gc
+
+package cpu
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+type _C_int int32
+
+// adapted from unix.Uname() at x/sys/unix/syscall_darwin.go L419
+func darwinOSRelease(release *[256]byte) error {
+	// from x/sys/unix/zerrors_openbsd_amd64.go
+	const (
+		CTL_KERN       = 0x1
+		KERN_OSRELEASE = 0x2
+	)
+
+	mib := []_C_int{CTL_KERN, KERN_OSRELEASE}
+	n := unsafe.Sizeof(*release)
+
+	return sysctl(mib, &release[0], &n, nil, 0)
+}
+
+type Errno = syscall.Errno
+
+var _zero uintptr // Single-word zero for use when we need a valid pointer to 0 bytes.
+
+// from x/sys/unix/zsyscall_darwin_amd64.go L791-807
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
+	var _p0 unsafe.Pointer
+	if len(mib) > 0 {
+		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	if _, _, err := syscall_syscall6(
+		libc_sysctl_trampoline_addr,
+		uintptr(_p0),
+		uintptr(len(mib)),
+		uintptr(unsafe.Pointer(old)),
+		uintptr(unsafe.Pointer(oldlen)),
+		uintptr(unsafe.Pointer(new)),
+		uintptr(newlen),
+	); err != 0 {
+		return err
+	}
+
+	return nil
+}
+
+var libc_sysctl_trampoline_addr uintptr
+
+// adapted from internal/cpu/cpu_arm64_darwin.go
+func darwinSysctlEnabled(name []byte) bool {
+	out := int32(0)
+	nout := unsafe.Sizeof(out)
+	if ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); ret != nil {
+		return false
+	}
+	return out > 0
+}
+
+//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
+
+var libc_sysctlbyname_trampoline_addr uintptr
+
+// adapted from runtime/sys_darwin.go in the pattern of sysctl() above, as defined in x/sys/unix
+func sysctlbyname(name *byte, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
+	if _, _, err := syscall_syscall6(
+		libc_sysctlbyname_trampoline_addr,
+		uintptr(unsafe.Pointer(name)),
+		uintptr(unsafe.Pointer(old)),
+		uintptr(unsafe.Pointer(oldlen)),
+		uintptr(unsafe.Pointer(new)),
+		uintptr(newlen),
+		0,
+	); err != 0 {
+		return err
+	}
+
+	return nil
+}
+
+//go:cgo_import_dynamic libc_sysctlbyname sysctlbyname "/usr/lib/libSystem.B.dylib"
+
+// Implemented in the runtime package (runtime/sys_darwin.go)
+func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+
+//go:linkname syscall_syscall6 syscall.syscall6
diff --git a/vendor/golang.org/x/sys/unix/ioctl_linux.go b/vendor/golang.org/x/sys/unix/ioctl_linux.go
index dbe680eab..7ca4fa12a 100644
--- a/vendor/golang.org/x/sys/unix/ioctl_linux.go
+++ b/vendor/golang.org/x/sys/unix/ioctl_linux.go
@@ -58,6 +58,102 @@ func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) {
 	return &value, err
 }
 
+// IoctlGetEthtoolTsInfo fetches ethtool timestamping and PHC
+// association for the network device specified by ifname.
+func IoctlGetEthtoolTsInfo(fd int, ifname string) (*EthtoolTsInfo, error) {
+	ifr, err := NewIfreq(ifname)
+	if err != nil {
+		return nil, err
+	}
+
+	value := EthtoolTsInfo{Cmd: ETHTOOL_GET_TS_INFO}
+	ifrd := ifr.withData(unsafe.Pointer(&value))
+
+	err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
+	return &value, err
+}
+
+// IoctlGetHwTstamp retrieves the hardware timestamping configuration
+// for the network device specified by ifname.
+func IoctlGetHwTstamp(fd int, ifname string) (*HwTstampConfig, error) {
+	ifr, err := NewIfreq(ifname)
+	if err != nil {
+		return nil, err
+	}
+
+	value := HwTstampConfig{}
+	ifrd := ifr.withData(unsafe.Pointer(&value))
+
+	err = ioctlIfreqData(fd, SIOCGHWTSTAMP, &ifrd)
+	return &value, err
+}
+
+// IoctlSetHwTstamp updates the hardware timestamping configuration for
+// the network device specified by ifname.
+func IoctlSetHwTstamp(fd int, ifname string, cfg *HwTstampConfig) error {
+	ifr, err := NewIfreq(ifname)
+	if err != nil {
+		return err
+	}
+	ifrd := ifr.withData(unsafe.Pointer(cfg))
+	return ioctlIfreqData(fd, SIOCSHWTSTAMP, &ifrd)
+}
+
+// FdToClockID derives the clock ID from the file descriptor number
+// - see clock_gettime(3), FD_TO_CLOCKID macros. The resulting ID is
+// suitable for system calls like ClockGettime.
+func FdToClockID(fd int) int32 { return int32((int(^fd) << 3) | 3) }
+
+// IoctlPtpClockGetcaps returns the description of a given PTP device.
+func IoctlPtpClockGetcaps(fd int) (*PtpClockCaps, error) {
+	var value PtpClockCaps
+	err := ioctlPtr(fd, PTP_CLOCK_GETCAPS2, unsafe.Pointer(&value))
+	return &value, err
+}
+
+// IoctlPtpSysOffsetPrecise returns a description of the clock
+// offset compared to the system clock.
+func IoctlPtpSysOffsetPrecise(fd int) (*PtpSysOffsetPrecise, error) {
+	var value PtpSysOffsetPrecise
+	err := ioctlPtr(fd, PTP_SYS_OFFSET_PRECISE2, unsafe.Pointer(&value))
+	return &value, err
+}
+
+// IoctlPtpSysOffsetExtended returns an extended description of the
+// clock offset compared to the system clock. The samples parameter
+// specifies the desired number of measurements.
+func IoctlPtpSysOffsetExtended(fd int, samples uint) (*PtpSysOffsetExtended, error) {
+	value := PtpSysOffsetExtended{Samples: uint32(samples)}
+	err := ioctlPtr(fd, PTP_SYS_OFFSET_EXTENDED2, unsafe.Pointer(&value))
+	return &value, err
+}
+
+// IoctlPtpPinGetfunc returns the configuration of the specified
+// I/O pin on given PTP device.
+func IoctlPtpPinGetfunc(fd int, index uint) (*PtpPinDesc, error) {
+	value := PtpPinDesc{Index: uint32(index)}
+	err := ioctlPtr(fd, PTP_PIN_GETFUNC2, unsafe.Pointer(&value))
+	return &value, err
+}
+
+// IoctlPtpPinSetfunc updates configuration of the specified PTP
+// I/O pin.
+func IoctlPtpPinSetfunc(fd int, pd *PtpPinDesc) error {
+	return ioctlPtr(fd, PTP_PIN_SETFUNC2, unsafe.Pointer(pd))
+}
+
+// IoctlPtpPeroutRequest configures the periodic output mode of the
+// PTP I/O pins.
+func IoctlPtpPeroutRequest(fd int, r *PtpPeroutRequest) error {
+	return ioctlPtr(fd, PTP_PEROUT_REQUEST2, unsafe.Pointer(r))
+}
+
+// IoctlPtpExttsRequest configures the external timestamping mode
+// of the PTP I/O pins.
+func IoctlPtpExttsRequest(fd int, r *PtpExttsRequest) error {
+	return ioctlPtr(fd, PTP_EXTTS_REQUEST2, unsafe.Pointer(r))
+}
+
 // IoctlGetWatchdogInfo fetches information about a watchdog device from the
 // Linux watchdog API. For more information, see:
 // https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index ac54ecaba..6ab02b6c3 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -158,6 +158,16 @@ includes_Linux='
 #endif
 #define _GNU_SOURCE
 
+// See the description in unix/linux/types.go
+#if defined(__ARM_EABI__) || \
+	(defined(__mips__) && (_MIPS_SIM == _ABIO32)) || \
+	(defined(__powerpc__) && (!defined(__powerpc64__)))
+# ifdef   _TIME_BITS
+#  undef  _TIME_BITS
+# endif
+# define  _TIME_BITS 32
+#endif
+
 // <sys/ioctl.h> is broken on powerpc64, as it fails to include definitions of
 // these structures. We just include them copied from <bits/termios.h>.
 #if defined(__powerpc__)
@@ -256,6 +266,7 @@ struct ltchars {
 #include <linux/nsfs.h>
 #include <linux/perf_event.h>
 #include <linux/pps.h>
+#include <linux/ptp_clock.h>
 #include <linux/ptrace.h>
 #include <linux/random.h>
 #include <linux/reboot.h>
@@ -527,6 +538,7 @@ ccflags="$@"
 		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
 		$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
 		$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
+		$2 ~ /^PTP_/ ||
 		$2 ~ /^RAW_PAYLOAD_/ ||
 		$2 ~ /^[US]F_/ ||
 		$2 ~ /^TP_STATUS_/ ||
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index f08abd434..230a94549 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -1860,6 +1860,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 //sys	ClockAdjtime(clockid int32, buf *Timex) (state int, err error)
 //sys	ClockGetres(clockid int32, res *Timespec) (err error)
 //sys	ClockGettime(clockid int32, time *Timespec) (err error)
+//sys	ClockSettime(clockid int32, time *Timespec) (err error)
 //sys	ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error)
 //sys	Close(fd int) (err error)
 //sys	CloseRange(first uint, last uint, flags uint) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go
index 312ae6ac1..7bf5c04bb 100644
--- a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go
@@ -768,6 +768,15 @@ func Munmap(b []byte) (err error) {
 	return mapper.Munmap(b)
 }
 
+func MmapPtr(fd int, offset int64, addr unsafe.Pointer, length uintptr, prot int, flags int) (ret unsafe.Pointer, err error) {
+	xaddr, err := mapper.mmap(uintptr(addr), length, prot, flags, fd, offset)
+	return unsafe.Pointer(xaddr), err
+}
+
+func MunmapPtr(addr unsafe.Pointer, length uintptr) (err error) {
+	return mapper.munmap(uintptr(addr), length)
+}
+
 //sys   Gethostname(buf []byte) (err error) = SYS___GETHOSTNAME_A
 //sysnb	Getgid() (gid int)
 //sysnb	Getpid() (pid int)
@@ -816,10 +825,10 @@ func Lstat(path string, stat *Stat_t) (err error) {
 // for checking symlinks begins with $VERSION/ $SYSNAME/ $SYSSYMR/ $SYSSYMA/
 func isSpecialPath(path []byte) (v bool) {
 	var special = [4][8]byte{
-		[8]byte{'V', 'E', 'R', 'S', 'I', 'O', 'N', '/'},
-		[8]byte{'S', 'Y', 'S', 'N', 'A', 'M', 'E', '/'},
-		[8]byte{'S', 'Y', 'S', 'S', 'Y', 'M', 'R', '/'},
-		[8]byte{'S', 'Y', 'S', 'S', 'Y', 'M', 'A', '/'}}
+		{'V', 'E', 'R', 'S', 'I', 'O', 'N', '/'},
+		{'S', 'Y', 'S', 'N', 'A', 'M', 'E', '/'},
+		{'S', 'Y', 'S', 'S', 'Y', 'M', 'R', '/'},
+		{'S', 'Y', 'S', 'S', 'Y', 'M', 'A', '/'}}
 
 	var i, j int
 	for i = 0; i < len(special); i++ {
@@ -3115,3 +3124,90 @@ func legacy_Mkfifoat(dirfd int, path string, mode uint32) (err error) {
 //sys	Posix_openpt(oflag int) (fd int, err error) = SYS_POSIX_OPENPT
 //sys	Grantpt(fildes int) (rc int, err error) = SYS_GRANTPT
 //sys	Unlockpt(fildes int) (rc int, err error) = SYS_UNLOCKPT
+
+func fcntlAsIs(fd uintptr, cmd int, arg uintptr) (val int, err error) {
+	runtime.EnterSyscall()
+	r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_FCNTL<<4, uintptr(fd), uintptr(cmd), arg)
+	runtime.ExitSyscall()
+	val = int(r0)
+	if int64(r0) == -1 {
+		err = errnoErr2(e1, e2)
+	}
+	return
+}
+
+func Fcntl(fd uintptr, cmd int, op interface{}) (ret int, err error) {
+	switch op.(type) {
+	case *Flock_t:
+		err = FcntlFlock(fd, cmd, op.(*Flock_t))
+		if err != nil {
+			ret = -1
+		}
+		return
+	case int:
+		return FcntlInt(fd, cmd, op.(int))
+	case *F_cnvrt:
+		return fcntlAsIs(fd, cmd, uintptr(unsafe.Pointer(op.(*F_cnvrt))))
+	case unsafe.Pointer:
+		return fcntlAsIs(fd, cmd, uintptr(op.(unsafe.Pointer)))
+	default:
+		return -1, EINVAL
+	}
+	return
+}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	if raceenabled {
+		raceReleaseMerge(unsafe.Pointer(&ioSync))
+	}
+	return sendfile(outfd, infd, offset, count)
+}
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	// TODO: use LE call instead if the call is implemented
+	originalOffset, err := Seek(infd, 0, SEEK_CUR)
+	if err != nil {
+		return -1, err
+	}
+	//start reading data from in_fd
+	if offset != nil {
+		_, err := Seek(infd, *offset, SEEK_SET)
+		if err != nil {
+			return -1, err
+		}
+	}
+
+	buf := make([]byte, count)
+	readBuf := make([]byte, 0)
+	var n int = 0
+	for i := 0; i < count; i += n {
+		n, err := Read(infd, buf)
+		if n == 0 {
+			if err != nil {
+				return -1, err
+			} else { // EOF
+				break
+			}
+		}
+		readBuf = append(readBuf, buf...)
+		buf = buf[0:0]
+	}
+
+	n2, err := Write(outfd, readBuf)
+	if err != nil {
+		return -1, err
+	}
+
+	//When sendfile() returns, this variable will be set to the
+	// offset of the byte following the last byte that was read.
+	if offset != nil {
+		*offset = *offset + int64(n)
+		// If offset is not NULL, then sendfile() does not modify the file
+		// offset of in_fd
+		_, err := Seek(infd, originalOffset, SEEK_SET)
+		if err != nil {
+			return -1, err
+		}
+	}
+	return n2, nil
+}
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index de3b46248..ccba391c9 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -2625,6 +2625,28 @@ const (
 	PR_UNALIGN_NOPRINT                          = 0x1
 	PR_UNALIGN_SIGBUS                           = 0x2
 	PSTOREFS_MAGIC                              = 0x6165676c
+	PTP_CLK_MAGIC                               = '='
+	PTP_ENABLE_FEATURE                          = 0x1
+	PTP_EXTTS_EDGES                             = 0x6
+	PTP_EXTTS_EVENT_VALID                       = 0x1
+	PTP_EXTTS_V1_VALID_FLAGS                    = 0x7
+	PTP_EXTTS_VALID_FLAGS                       = 0x1f
+	PTP_EXT_OFFSET                              = 0x10
+	PTP_FALLING_EDGE                            = 0x4
+	PTP_MAX_SAMPLES                             = 0x19
+	PTP_PEROUT_DUTY_CYCLE                       = 0x2
+	PTP_PEROUT_ONE_SHOT                         = 0x1
+	PTP_PEROUT_PHASE                            = 0x4
+	PTP_PEROUT_V1_VALID_FLAGS                   = 0x0
+	PTP_PEROUT_VALID_FLAGS                      = 0x7
+	PTP_PIN_GETFUNC                             = 0xc0603d06
+	PTP_PIN_GETFUNC2                            = 0xc0603d0f
+	PTP_RISING_EDGE                             = 0x2
+	PTP_STRICT_FLAGS                            = 0x8
+	PTP_SYS_OFFSET_EXTENDED                     = 0xc4c03d09
+	PTP_SYS_OFFSET_EXTENDED2                    = 0xc4c03d12
+	PTP_SYS_OFFSET_PRECISE                      = 0xc0403d08
+	PTP_SYS_OFFSET_PRECISE2                     = 0xc0403d11
 	PTRACE_ATTACH                               = 0x10
 	PTRACE_CONT                                 = 0x7
 	PTRACE_DETACH                               = 0x11
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
index 8aa6d77c0..0c00cb3f3 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
@@ -237,6 +237,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x7434
 	PPPIOCXFERUNIT                   = 0x744e
 	PR_SET_PTRACER_ANY               = 0xffffffff
+	PTP_CLOCK_GETCAPS                = 0x80503d01
+	PTP_CLOCK_GETCAPS2               = 0x80503d0a
+	PTP_ENABLE_PPS                   = 0x40043d04
+	PTP_ENABLE_PPS2                  = 0x40043d0d
+	PTP_EXTTS_REQUEST                = 0x40103d02
+	PTP_EXTTS_REQUEST2               = 0x40103d0b
+	PTP_MASK_CLEAR_ALL               = 0x3d13
+	PTP_MASK_EN_SINGLE               = 0x40043d14
+	PTP_PEROUT_REQUEST               = 0x40383d03
+	PTP_PEROUT_REQUEST2              = 0x40383d0c
+	PTP_PIN_SETFUNC                  = 0x40603d07
+	PTP_PIN_SETFUNC2                 = 0x40603d10
+	PTP_SYS_OFFSET                   = 0x43403d05
+	PTP_SYS_OFFSET2                  = 0x43403d0e
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GETFPXREGS                = 0x12
 	PTRACE_GET_THREAD_AREA           = 0x19
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
index da428f425..dfb364554 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
@@ -237,6 +237,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x7434
 	PPPIOCXFERUNIT                   = 0x744e
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x80503d01
+	PTP_CLOCK_GETCAPS2               = 0x80503d0a
+	PTP_ENABLE_PPS                   = 0x40043d04
+	PTP_ENABLE_PPS2                  = 0x40043d0d
+	PTP_EXTTS_REQUEST                = 0x40103d02
+	PTP_EXTTS_REQUEST2               = 0x40103d0b
+	PTP_MASK_CLEAR_ALL               = 0x3d13
+	PTP_MASK_EN_SINGLE               = 0x40043d14
+	PTP_PEROUT_REQUEST               = 0x40383d03
+	PTP_PEROUT_REQUEST2              = 0x40383d0c
+	PTP_PIN_SETFUNC                  = 0x40603d07
+	PTP_PIN_SETFUNC2                 = 0x40603d10
+	PTP_SYS_OFFSET                   = 0x43403d05
+	PTP_SYS_OFFSET2                  = 0x43403d0e
 	PTRACE_ARCH_PRCTL                = 0x1e
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GETFPXREGS                = 0x12
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
index bf45bfec7..d46dcf78a 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
@@ -234,6 +234,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x7434
 	PPPIOCXFERUNIT                   = 0x744e
 	PR_SET_PTRACER_ANY               = 0xffffffff
+	PTP_CLOCK_GETCAPS                = 0x80503d01
+	PTP_CLOCK_GETCAPS2               = 0x80503d0a
+	PTP_ENABLE_PPS                   = 0x40043d04
+	PTP_ENABLE_PPS2                  = 0x40043d0d
+	PTP_EXTTS_REQUEST                = 0x40103d02
+	PTP_EXTTS_REQUEST2               = 0x40103d0b
+	PTP_MASK_CLEAR_ALL               = 0x3d13
+	PTP_MASK_EN_SINGLE               = 0x40043d14
+	PTP_PEROUT_REQUEST               = 0x40383d03
+	PTP_PEROUT_REQUEST2              = 0x40383d0c
+	PTP_PIN_SETFUNC                  = 0x40603d07
+	PTP_PIN_SETFUNC2                 = 0x40603d10
+	PTP_SYS_OFFSET                   = 0x43403d05
+	PTP_SYS_OFFSET2                  = 0x43403d0e
 	PTRACE_GETCRUNCHREGS             = 0x19
 	PTRACE_GETFDPIC                  = 0x1f
 	PTRACE_GETFDPIC_EXEC             = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
index 71c67162b..3af3248a7 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
@@ -240,6 +240,20 @@ const (
 	PROT_BTI                         = 0x10
 	PROT_MTE                         = 0x20
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x80503d01
+	PTP_CLOCK_GETCAPS2               = 0x80503d0a
+	PTP_ENABLE_PPS                   = 0x40043d04
+	PTP_ENABLE_PPS2                  = 0x40043d0d
+	PTP_EXTTS_REQUEST                = 0x40103d02
+	PTP_EXTTS_REQUEST2               = 0x40103d0b
+	PTP_MASK_CLEAR_ALL               = 0x3d13
+	PTP_MASK_EN_SINGLE               = 0x40043d14
+	PTP_PEROUT_REQUEST               = 0x40383d03
+	PTP_PEROUT_REQUEST2              = 0x40383d0c
+	PTP_PIN_SETFUNC                  = 0x40603d07
+	PTP_PIN_SETFUNC2                 = 0x40603d10
+	PTP_SYS_OFFSET                   = 0x43403d05
+	PTP_SYS_OFFSET2                  = 0x43403d0e
 	PTRACE_PEEKMTETAGS               = 0x21
 	PTRACE_POKEMTETAGS               = 0x22
 	PTRACE_SYSEMU                    = 0x1f
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
index 9476628fa..292bcf028 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
@@ -238,6 +238,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x7434
 	PPPIOCXFERUNIT                   = 0x744e
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x80503d01
+	PTP_CLOCK_GETCAPS2               = 0x80503d0a
+	PTP_ENABLE_PPS                   = 0x40043d04
+	PTP_ENABLE_PPS2                  = 0x40043d0d
+	PTP_EXTTS_REQUEST                = 0x40103d02
+	PTP_EXTTS_REQUEST2               = 0x40103d0b
+	PTP_MASK_CLEAR_ALL               = 0x3d13
+	PTP_MASK_EN_SINGLE               = 0x40043d14
+	PTP_PEROUT_REQUEST               = 0x40383d03
+	PTP_PEROUT_REQUEST2              = 0x40383d0c
+	PTP_PIN_SETFUNC                  = 0x40603d07
+	PTP_PIN_SETFUNC2                 = 0x40603d10
+	PTP_SYS_OFFSET                   = 0x43403d05
+	PTP_SYS_OFFSET2                  = 0x43403d0e
 	PTRACE_SYSEMU                    = 0x1f
 	PTRACE_SYSEMU_SINGLESTEP         = 0x20
 	RLIMIT_AS                        = 0x9
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
index b9e85f3cf..782b7110f 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
@@ -234,6 +234,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x20007434
 	PPPIOCXFERUNIT                   = 0x2000744e
 	PR_SET_PTRACER_ANY               = 0xffffffff
+	PTP_CLOCK_GETCAPS                = 0x40503d01
+	PTP_CLOCK_GETCAPS2               = 0x40503d0a
+	PTP_ENABLE_PPS                   = 0x80043d04
+	PTP_ENABLE_PPS2                  = 0x80043d0d
+	PTP_EXTTS_REQUEST                = 0x80103d02
+	PTP_EXTTS_REQUEST2               = 0x80103d0b
+	PTP_MASK_CLEAR_ALL               = 0x20003d13
+	PTP_MASK_EN_SINGLE               = 0x80043d14
+	PTP_PEROUT_REQUEST               = 0x80383d03
+	PTP_PEROUT_REQUEST2              = 0x80383d0c
+	PTP_PIN_SETFUNC                  = 0x80603d07
+	PTP_PIN_SETFUNC2                 = 0x80603d10
+	PTP_SYS_OFFSET                   = 0x83403d05
+	PTP_SYS_OFFSET2                  = 0x83403d0e
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GET_THREAD_AREA           = 0x19
 	PTRACE_GET_THREAD_AREA_3264      = 0xc4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
index a48b68a76..84973fd92 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
@@ -234,6 +234,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x20007434
 	PPPIOCXFERUNIT                   = 0x2000744e
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x40503d01
+	PTP_CLOCK_GETCAPS2               = 0x40503d0a
+	PTP_ENABLE_PPS                   = 0x80043d04
+	PTP_ENABLE_PPS2                  = 0x80043d0d
+	PTP_EXTTS_REQUEST                = 0x80103d02
+	PTP_EXTTS_REQUEST2               = 0x80103d0b
+	PTP_MASK_CLEAR_ALL               = 0x20003d13
+	PTP_MASK_EN_SINGLE               = 0x80043d14
+	PTP_PEROUT_REQUEST               = 0x80383d03
+	PTP_PEROUT_REQUEST2              = 0x80383d0c
+	PTP_PIN_SETFUNC                  = 0x80603d07
+	PTP_PIN_SETFUNC2                 = 0x80603d10
+	PTP_SYS_OFFSET                   = 0x83403d05
+	PTP_SYS_OFFSET2                  = 0x83403d0e
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GET_THREAD_AREA           = 0x19
 	PTRACE_GET_THREAD_AREA_3264      = 0xc4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
index ea00e8522..6d9cbc3b2 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
@@ -234,6 +234,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x20007434
 	PPPIOCXFERUNIT                   = 0x2000744e
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x40503d01
+	PTP_CLOCK_GETCAPS2               = 0x40503d0a
+	PTP_ENABLE_PPS                   = 0x80043d04
+	PTP_ENABLE_PPS2                  = 0x80043d0d
+	PTP_EXTTS_REQUEST                = 0x80103d02
+	PTP_EXTTS_REQUEST2               = 0x80103d0b
+	PTP_MASK_CLEAR_ALL               = 0x20003d13
+	PTP_MASK_EN_SINGLE               = 0x80043d14
+	PTP_PEROUT_REQUEST               = 0x80383d03
+	PTP_PEROUT_REQUEST2              = 0x80383d0c
+	PTP_PIN_SETFUNC                  = 0x80603d07
+	PTP_PIN_SETFUNC2                 = 0x80603d10
+	PTP_SYS_OFFSET                   = 0x83403d05
+	PTP_SYS_OFFSET2                  = 0x83403d0e
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GET_THREAD_AREA           = 0x19
 	PTRACE_GET_THREAD_AREA_3264      = 0xc4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
index 91c646871..5f9fedbce 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
@@ -234,6 +234,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x20007434
 	PPPIOCXFERUNIT                   = 0x2000744e
 	PR_SET_PTRACER_ANY               = 0xffffffff
+	PTP_CLOCK_GETCAPS                = 0x40503d01
+	PTP_CLOCK_GETCAPS2               = 0x40503d0a
+	PTP_ENABLE_PPS                   = 0x80043d04
+	PTP_ENABLE_PPS2                  = 0x80043d0d
+	PTP_EXTTS_REQUEST                = 0x80103d02
+	PTP_EXTTS_REQUEST2               = 0x80103d0b
+	PTP_MASK_CLEAR_ALL               = 0x20003d13
+	PTP_MASK_EN_SINGLE               = 0x80043d14
+	PTP_PEROUT_REQUEST               = 0x80383d03
+	PTP_PEROUT_REQUEST2              = 0x80383d0c
+	PTP_PIN_SETFUNC                  = 0x80603d07
+	PTP_PIN_SETFUNC2                 = 0x80603d10
+	PTP_SYS_OFFSET                   = 0x83403d05
+	PTP_SYS_OFFSET2                  = 0x83403d0e
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GET_THREAD_AREA           = 0x19
 	PTRACE_GET_THREAD_AREA_3264      = 0xc4
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
index 8cbf38d63..bb0026ee0 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
@@ -237,6 +237,20 @@ const (
 	PPPIOCXFERUNIT                   = 0x2000744e
 	PROT_SAO                         = 0x10
 	PR_SET_PTRACER_ANY               = 0xffffffff
+	PTP_CLOCK_GETCAPS                = 0x40503d01
+	PTP_CLOCK_GETCAPS2               = 0x40503d0a
+	PTP_ENABLE_PPS                   = 0x80043d04
+	PTP_ENABLE_PPS2                  = 0x80043d0d
+	PTP_EXTTS_REQUEST                = 0x80103d02
+	PTP_EXTTS_REQUEST2               = 0x80103d0b
+	PTP_MASK_CLEAR_ALL               = 0x20003d13
+	PTP_MASK_EN_SINGLE               = 0x80043d14
+	PTP_PEROUT_REQUEST               = 0x80383d03
+	PTP_PEROUT_REQUEST2              = 0x80383d0c
+	PTP_PIN_SETFUNC                  = 0x80603d07
+	PTP_PIN_SETFUNC2                 = 0x80603d10
+	PTP_SYS_OFFSET                   = 0x83403d05
+	PTP_SYS_OFFSET2                  = 0x83403d0e
 	PTRACE_GETEVRREGS                = 0x14
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GETREGS64                 = 0x16
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
index a2df73419..46120db5c 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
@@ -237,6 +237,20 @@ const (
 	PPPIOCXFERUNIT                   = 0x2000744e
 	PROT_SAO                         = 0x10
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x40503d01
+	PTP_CLOCK_GETCAPS2               = 0x40503d0a
+	PTP_ENABLE_PPS                   = 0x80043d04
+	PTP_ENABLE_PPS2                  = 0x80043d0d
+	PTP_EXTTS_REQUEST                = 0x80103d02
+	PTP_EXTTS_REQUEST2               = 0x80103d0b
+	PTP_MASK_CLEAR_ALL               = 0x20003d13
+	PTP_MASK_EN_SINGLE               = 0x80043d14
+	PTP_PEROUT_REQUEST               = 0x80383d03
+	PTP_PEROUT_REQUEST2              = 0x80383d0c
+	PTP_PIN_SETFUNC                  = 0x80603d07
+	PTP_PIN_SETFUNC2                 = 0x80603d10
+	PTP_SYS_OFFSET                   = 0x83403d05
+	PTP_SYS_OFFSET2                  = 0x83403d0e
 	PTRACE_GETEVRREGS                = 0x14
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GETREGS64                 = 0x16
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
index 247913792..5c951634f 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
@@ -237,6 +237,20 @@ const (
 	PPPIOCXFERUNIT                   = 0x2000744e
 	PROT_SAO                         = 0x10
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x40503d01
+	PTP_CLOCK_GETCAPS2               = 0x40503d0a
+	PTP_ENABLE_PPS                   = 0x80043d04
+	PTP_ENABLE_PPS2                  = 0x80043d0d
+	PTP_EXTTS_REQUEST                = 0x80103d02
+	PTP_EXTTS_REQUEST2               = 0x80103d0b
+	PTP_MASK_CLEAR_ALL               = 0x20003d13
+	PTP_MASK_EN_SINGLE               = 0x80043d14
+	PTP_PEROUT_REQUEST               = 0x80383d03
+	PTP_PEROUT_REQUEST2              = 0x80383d0c
+	PTP_PIN_SETFUNC                  = 0x80603d07
+	PTP_PIN_SETFUNC2                 = 0x80603d10
+	PTP_SYS_OFFSET                   = 0x83403d05
+	PTP_SYS_OFFSET2                  = 0x83403d0e
 	PTRACE_GETEVRREGS                = 0x14
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GETREGS64                 = 0x16
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
index d265f146e..11a84d5af 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
@@ -234,6 +234,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x7434
 	PPPIOCXFERUNIT                   = 0x744e
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x80503d01
+	PTP_CLOCK_GETCAPS2               = 0x80503d0a
+	PTP_ENABLE_PPS                   = 0x40043d04
+	PTP_ENABLE_PPS2                  = 0x40043d0d
+	PTP_EXTTS_REQUEST                = 0x40103d02
+	PTP_EXTTS_REQUEST2               = 0x40103d0b
+	PTP_MASK_CLEAR_ALL               = 0x3d13
+	PTP_MASK_EN_SINGLE               = 0x40043d14
+	PTP_PEROUT_REQUEST               = 0x40383d03
+	PTP_PEROUT_REQUEST2              = 0x40383d0c
+	PTP_PIN_SETFUNC                  = 0x40603d07
+	PTP_PIN_SETFUNC2                 = 0x40603d10
+	PTP_SYS_OFFSET                   = 0x43403d05
+	PTP_SYS_OFFSET2                  = 0x43403d0e
 	PTRACE_GETFDPIC                  = 0x21
 	PTRACE_GETFDPIC_EXEC             = 0x0
 	PTRACE_GETFDPIC_INTERP           = 0x1
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
index 3f2d64439..f78c4617c 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
@@ -234,6 +234,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x7434
 	PPPIOCXFERUNIT                   = 0x744e
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x80503d01
+	PTP_CLOCK_GETCAPS2               = 0x80503d0a
+	PTP_ENABLE_PPS                   = 0x40043d04
+	PTP_ENABLE_PPS2                  = 0x40043d0d
+	PTP_EXTTS_REQUEST                = 0x40103d02
+	PTP_EXTTS_REQUEST2               = 0x40103d0b
+	PTP_MASK_CLEAR_ALL               = 0x3d13
+	PTP_MASK_EN_SINGLE               = 0x40043d14
+	PTP_PEROUT_REQUEST               = 0x40383d03
+	PTP_PEROUT_REQUEST2              = 0x40383d0c
+	PTP_PIN_SETFUNC                  = 0x40603d07
+	PTP_PIN_SETFUNC2                 = 0x40603d10
+	PTP_SYS_OFFSET                   = 0x43403d05
+	PTP_SYS_OFFSET2                  = 0x43403d0e
 	PTRACE_DISABLE_TE                = 0x5010
 	PTRACE_ENABLE_TE                 = 0x5009
 	PTRACE_GET_LAST_BREAK            = 0x5006
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
index 5d8b727a1..aeb777c34 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
@@ -239,6 +239,20 @@ const (
 	PPPIOCUNBRIDGECHAN               = 0x20007434
 	PPPIOCXFERUNIT                   = 0x2000744e
 	PR_SET_PTRACER_ANY               = 0xffffffffffffffff
+	PTP_CLOCK_GETCAPS                = 0x40503d01
+	PTP_CLOCK_GETCAPS2               = 0x40503d0a
+	PTP_ENABLE_PPS                   = 0x80043d04
+	PTP_ENABLE_PPS2                  = 0x80043d0d
+	PTP_EXTTS_REQUEST                = 0x80103d02
+	PTP_EXTTS_REQUEST2               = 0x80103d0b
+	PTP_MASK_CLEAR_ALL               = 0x20003d13
+	PTP_MASK_EN_SINGLE               = 0x80043d14
+	PTP_PEROUT_REQUEST               = 0x80383d03
+	PTP_PEROUT_REQUEST2              = 0x80383d0c
+	PTP_PIN_SETFUNC                  = 0x80603d07
+	PTP_PIN_SETFUNC2                 = 0x80603d10
+	PTP_SYS_OFFSET                   = 0x83403d05
+	PTP_SYS_OFFSET2                  = 0x83403d0e
 	PTRACE_GETFPAREGS                = 0x14
 	PTRACE_GETFPREGS                 = 0xe
 	PTRACE_GETFPREGS64               = 0x19
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
index af30da557..5cc1e8eb2 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
@@ -592,6 +592,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ClockSettime(clockid int32, time *Timespec) (err error) {
+	_, _, e1 := Syscall(SYS_CLOCK_SETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) {
 	_, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0)
 	if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go
index 3a69e4549..8daaf3faf 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go
@@ -1752,12 +1752,6 @@ const (
 	IFLA_IPVLAN_UNSPEC                         = 0x0
 	IFLA_IPVLAN_MODE                           = 0x1
 	IFLA_IPVLAN_FLAGS                          = 0x2
-	NETKIT_NEXT                                = -0x1
-	NETKIT_PASS                                = 0x0
-	NETKIT_DROP                                = 0x2
-	NETKIT_REDIRECT                            = 0x7
-	NETKIT_L2                                  = 0x0
-	NETKIT_L3                                  = 0x1
 	IFLA_NETKIT_UNSPEC                         = 0x0
 	IFLA_NETKIT_PEER_INFO                      = 0x1
 	IFLA_NETKIT_PRIMARY                        = 0x2
@@ -1796,6 +1790,7 @@ const (
 	IFLA_VXLAN_DF                              = 0x1d
 	IFLA_VXLAN_VNIFILTER                       = 0x1e
 	IFLA_VXLAN_LOCALBYPASS                     = 0x1f
+	IFLA_VXLAN_LABEL_POLICY                    = 0x20
 	IFLA_GENEVE_UNSPEC                         = 0x0
 	IFLA_GENEVE_ID                             = 0x1
 	IFLA_GENEVE_REMOTE                         = 0x2
@@ -1825,6 +1820,8 @@ const (
 	IFLA_GTP_ROLE                              = 0x4
 	IFLA_GTP_CREATE_SOCKETS                    = 0x5
 	IFLA_GTP_RESTART_COUNT                     = 0x6
+	IFLA_GTP_LOCAL                             = 0x7
+	IFLA_GTP_LOCAL6                            = 0x8
 	IFLA_BOND_UNSPEC                           = 0x0
 	IFLA_BOND_MODE                             = 0x1
 	IFLA_BOND_ACTIVE_SLAVE                     = 0x2
@@ -1857,6 +1854,7 @@ const (
 	IFLA_BOND_AD_LACP_ACTIVE                   = 0x1d
 	IFLA_BOND_MISSED_MAX                       = 0x1e
 	IFLA_BOND_NS_IP6_TARGET                    = 0x1f
+	IFLA_BOND_COUPLED_CONTROL                  = 0x20
 	IFLA_BOND_AD_INFO_UNSPEC                   = 0x0
 	IFLA_BOND_AD_INFO_AGGREGATOR               = 0x1
 	IFLA_BOND_AD_INFO_NUM_PORTS                = 0x2
@@ -1925,6 +1923,7 @@ const (
 	IFLA_HSR_SEQ_NR                            = 0x5
 	IFLA_HSR_VERSION                           = 0x6
 	IFLA_HSR_PROTOCOL                          = 0x7
+	IFLA_HSR_INTERLINK                         = 0x8
 	IFLA_STATS_UNSPEC                          = 0x0
 	IFLA_STATS_LINK_64                         = 0x1
 	IFLA_STATS_LINK_XSTATS                     = 0x2
@@ -1977,6 +1976,15 @@ const (
 	IFLA_DSA_MASTER                            = 0x1
 )
 
+const (
+	NETKIT_NEXT     = -0x1
+	NETKIT_PASS     = 0x0
+	NETKIT_DROP     = 0x2
+	NETKIT_REDIRECT = 0x7
+	NETKIT_L2       = 0x0
+	NETKIT_L3       = 0x1
+)
+
 const (
 	NF_INET_PRE_ROUTING  = 0x0
 	NF_INET_LOCAL_IN     = 0x1
@@ -4110,6 +4118,106 @@ type EthtoolDrvinfo struct {
 	Regdump_len  uint32
 }
 
+type EthtoolTsInfo struct {
+	Cmd             uint32
+	So_timestamping uint32
+	Phc_index       int32
+	Tx_types        uint32
+	Tx_reserved     [3]uint32
+	Rx_filters      uint32
+	Rx_reserved     [3]uint32
+}
+
+type HwTstampConfig struct {
+	Flags     int32
+	Tx_type   int32
+	Rx_filter int32
+}
+
+const (
+	HWTSTAMP_FILTER_NONE            = 0x0
+	HWTSTAMP_FILTER_ALL             = 0x1
+	HWTSTAMP_FILTER_SOME            = 0x2
+	HWTSTAMP_FILTER_PTP_V1_L4_EVENT = 0x3
+	HWTSTAMP_FILTER_PTP_V2_L4_EVENT = 0x6
+	HWTSTAMP_FILTER_PTP_V2_L2_EVENT = 0x9
+	HWTSTAMP_FILTER_PTP_V2_EVENT    = 0xc
+)
+
+const (
+	HWTSTAMP_TX_OFF          = 0x0
+	HWTSTAMP_TX_ON           = 0x1
+	HWTSTAMP_TX_ONESTEP_SYNC = 0x2
+)
+
+type (
+	PtpClockCaps struct {
+		Max_adj            int32
+		N_alarm            int32
+		N_ext_ts           int32
+		N_per_out          int32
+		Pps                int32
+		N_pins             int32
+		Cross_timestamping int32
+		Adjust_phase       int32
+		Max_phase_adj      int32
+		Rsv                [11]int32
+	}
+	PtpClockTime struct {
+		Sec      int64
+		Nsec     uint32
+		Reserved uint32
+	}
+	PtpExttsEvent struct {
+		T     PtpClockTime
+		Index uint32
+		Flags uint32
+		Rsv   [2]uint32
+	}
+	PtpExttsRequest struct {
+		Index uint32
+		Flags uint32
+		Rsv   [2]uint32
+	}
+	PtpPeroutRequest struct {
+		StartOrPhase PtpClockTime
+		Period       PtpClockTime
+		Index        uint32
+		Flags        uint32
+		On           PtpClockTime
+	}
+	PtpPinDesc struct {
+		Name  [64]byte
+		Index uint32
+		Func  uint32
+		Chan  uint32
+		Rsv   [5]uint32
+	}
+	PtpSysOffset struct {
+		Samples uint32
+		Rsv     [3]uint32
+		Ts      [51]PtpClockTime
+	}
+	PtpSysOffsetExtended struct {
+		Samples uint32
+		Rsv     [3]uint32
+		Ts      [25][3]PtpClockTime
+	}
+	PtpSysOffsetPrecise struct {
+		Device   PtpClockTime
+		Realtime PtpClockTime
+		Monoraw  PtpClockTime
+		Rsv      [4]uint32
+	}
+)
+
+const (
+	PTP_PF_NONE    = 0x0
+	PTP_PF_EXTTS   = 0x1
+	PTP_PF_PEROUT  = 0x2
+	PTP_PF_PHYSYNC = 0x3
+)
+
 type (
 	HIDRawReportDescriptor struct {
 		Size  uint32
diff --git a/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go
index d9a13af46..2e5d5a443 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go
@@ -377,6 +377,12 @@ type Flock_t struct {
 	Pid    int32
 }
 
+type F_cnvrt struct {
+	Cvtcmd int32
+	Pccsid int16
+	Fccsid int16
+}
+
 type Termios struct {
 	Cflag uint32
 	Iflag uint32
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 5cee9a314..4510bfc3f 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -725,20 +725,12 @@ func DurationSinceBoot() time.Duration {
 }
 
 func Ftruncate(fd Handle, length int64) (err error) {
-	curoffset, e := Seek(fd, 0, 1)
-	if e != nil {
-		return e
-	}
-	defer Seek(fd, curoffset, 0)
-	_, e = Seek(fd, length, 0)
-	if e != nil {
-		return e
+	type _FILE_END_OF_FILE_INFO struct {
+		EndOfFile int64
 	}
-	e = SetEndOfFile(fd)
-	if e != nil {
-		return e
-	}
-	return nil
+	var info _FILE_END_OF_FILE_INFO
+	info.EndOfFile = length
+	return SetFileInformationByHandle(fd, FileEndOfFileInfo, (*byte)(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
 }
 
 func Gettimeofday(tv *Timeval) (err error) {
@@ -894,6 +886,11 @@ const socket_error = uintptr(^uint32(0))
 //sys	GetACP() (acp uint32) = kernel32.GetACP
 //sys	MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
 //sys	getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) = iphlpapi.GetBestInterfaceEx
+//sys   GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) = iphlpapi.GetIfEntry2Ex
+//sys   GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) = iphlpapi.GetUnicastIpAddressEntry
+//sys   NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyIpInterfaceChange
+//sys   NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange
+//sys   CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2
 
 // For testing: clients can set this flag to force
 // creation of IPv6 sockets to return EAFNOSUPPORT.
@@ -1685,13 +1682,16 @@ func (s NTStatus) Error() string {
 // do not use NTUnicodeString, and instead UTF16PtrFromString should be used for
 // the more common *uint16 string type.
 func NewNTUnicodeString(s string) (*NTUnicodeString, error) {
-	var u NTUnicodeString
-	s16, err := UTF16PtrFromString(s)
+	s16, err := UTF16FromString(s)
 	if err != nil {
 		return nil, err
 	}
-	RtlInitUnicodeString(&u, s16)
-	return &u, nil
+	n := uint16(len(s16) * 2)
+	return &NTUnicodeString{
+		Length:        n - 2, // subtract 2 bytes for the NULL terminator
+		MaximumLength: n,
+		Buffer:        &s16[0],
+	}, nil
 }
 
 // Slice returns a uint16 slice that aliases the data in the NTUnicodeString.
diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go
index 7b97a154c..51311e205 100644
--- a/vendor/golang.org/x/sys/windows/types_windows.go
+++ b/vendor/golang.org/x/sys/windows/types_windows.go
@@ -2203,6 +2203,132 @@ const (
 	IfOperStatusLowerLayerDown = 7
 )
 
+const (
+	IF_MAX_PHYS_ADDRESS_LENGTH = 32
+	IF_MAX_STRING_SIZE         = 256
+)
+
+// MIB_IF_ENTRY_LEVEL enumeration from netioapi.h or
+// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-getifentry2ex.
+const (
+	MibIfEntryNormal                  = 0
+	MibIfEntryNormalWithoutStatistics = 2
+)
+
+// MIB_NOTIFICATION_TYPE enumeration from netioapi.h or
+// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ne-netioapi-mib_notification_type.
+const (
+	MibParameterNotification = 0
+	MibAddInstance           = 1
+	MibDeleteInstance        = 2
+	MibInitialNotification   = 3
+)
+
+// MibIfRow2 stores information about a particular interface. See
+// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_if_row2.
+type MibIfRow2 struct {
+	InterfaceLuid               uint64
+	InterfaceIndex              uint32
+	InterfaceGuid               GUID
+	Alias                       [IF_MAX_STRING_SIZE + 1]uint16
+	Description                 [IF_MAX_STRING_SIZE + 1]uint16
+	PhysicalAddressLength       uint32
+	PhysicalAddress             [IF_MAX_PHYS_ADDRESS_LENGTH]uint8
+	PermanentPhysicalAddress    [IF_MAX_PHYS_ADDRESS_LENGTH]uint8
+	Mtu                         uint32
+	Type                        uint32
+	TunnelType                  uint32
+	MediaType                   uint32
+	PhysicalMediumType          uint32
+	AccessType                  uint32
+	DirectionType               uint32
+	InterfaceAndOperStatusFlags uint8
+	OperStatus                  uint32
+	AdminStatus                 uint32
+	MediaConnectState           uint32
+	NetworkGuid                 GUID
+	ConnectionType              uint32
+	TransmitLinkSpeed           uint64
+	ReceiveLinkSpeed            uint64
+	InOctets                    uint64
+	InUcastPkts                 uint64
+	InNUcastPkts                uint64
+	InDiscards                  uint64
+	InErrors                    uint64
+	InUnknownProtos             uint64
+	InUcastOctets               uint64
+	InMulticastOctets           uint64
+	InBroadcastOctets           uint64
+	OutOctets                   uint64
+	OutUcastPkts                uint64
+	OutNUcastPkts               uint64
+	OutDiscards                 uint64
+	OutErrors                   uint64
+	OutUcastOctets              uint64
+	OutMulticastOctets          uint64
+	OutBroadcastOctets          uint64
+	OutQLen                     uint64
+}
+
+// MIB_UNICASTIPADDRESS_ROW stores information about a unicast IP address. See
+// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_unicastipaddress_row.
+type MibUnicastIpAddressRow struct {
+	Address            RawSockaddrInet6 // SOCKADDR_INET union
+	InterfaceLuid      uint64
+	InterfaceIndex     uint32
+	PrefixOrigin       uint32
+	SuffixOrigin       uint32
+	ValidLifetime      uint32
+	PreferredLifetime  uint32
+	OnLinkPrefixLength uint8
+	SkipAsSource       uint8
+	DadState           uint32
+	ScopeId            uint32
+	CreationTimeStamp  Filetime
+}
+
+const ScopeLevelCount = 16
+
+// MIB_IPINTERFACE_ROW stores interface management information for a particular IP address family on a network interface.
+// See https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipinterface_row.
+type MibIpInterfaceRow struct {
+	Family                               uint16
+	InterfaceLuid                        uint64
+	InterfaceIndex                       uint32
+	MaxReassemblySize                    uint32
+	InterfaceIdentifier                  uint64
+	MinRouterAdvertisementInterval       uint32
+	MaxRouterAdvertisementInterval       uint32
+	AdvertisingEnabled                   uint8
+	ForwardingEnabled                    uint8
+	WeakHostSend                         uint8
+	WeakHostReceive                      uint8
+	UseAutomaticMetric                   uint8
+	UseNeighborUnreachabilityDetection   uint8
+	ManagedAddressConfigurationSupported uint8
+	OtherStatefulConfigurationSupported  uint8
+	AdvertiseDefaultRoute                uint8
+	RouterDiscoveryBehavior              uint32
+	DadTransmits                         uint32
+	BaseReachableTime                    uint32
+	RetransmitTime                       uint32
+	PathMtuDiscoveryTimeout              uint32
+	LinkLocalAddressBehavior             uint32
+	LinkLocalAddressTimeout              uint32
+	ZoneIndices                          [ScopeLevelCount]uint32
+	SitePrefixLength                     uint32
+	Metric                               uint32
+	NlMtu                                uint32
+	Connected                            uint8
+	SupportsWakeUpPatterns               uint8
+	SupportsNeighborDiscovery            uint8
+	SupportsRouterDiscovery              uint8
+	ReachableTime                        uint32
+	TransmitOffload                      uint32
+	ReceiveOffload                       uint32
+	DisableDefaultRoutes                 uint8
+}
+
 // Console related constants used for the mode parameter to SetConsoleMode. See
 // https://docs.microsoft.com/en-us/windows/console/setconsolemode for details.
 
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index 4c2e1bdc0..6f5252880 100644
--- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -181,10 +181,15 @@ var (
 	procDnsRecordListFree                                    = moddnsapi.NewProc("DnsRecordListFree")
 	procDwmGetWindowAttribute                                = moddwmapi.NewProc("DwmGetWindowAttribute")
 	procDwmSetWindowAttribute                                = moddwmapi.NewProc("DwmSetWindowAttribute")
+	procCancelMibChangeNotify2                               = modiphlpapi.NewProc("CancelMibChangeNotify2")
 	procGetAdaptersAddresses                                 = modiphlpapi.NewProc("GetAdaptersAddresses")
 	procGetAdaptersInfo                                      = modiphlpapi.NewProc("GetAdaptersInfo")
 	procGetBestInterfaceEx                                   = modiphlpapi.NewProc("GetBestInterfaceEx")
 	procGetIfEntry                                           = modiphlpapi.NewProc("GetIfEntry")
+	procGetIfEntry2Ex                                        = modiphlpapi.NewProc("GetIfEntry2Ex")
+	procGetUnicastIpAddressEntry                             = modiphlpapi.NewProc("GetUnicastIpAddressEntry")
+	procNotifyIpInterfaceChange                              = modiphlpapi.NewProc("NotifyIpInterfaceChange")
+	procNotifyUnicastIpAddressChange                         = modiphlpapi.NewProc("NotifyUnicastIpAddressChange")
 	procAddDllDirectory                                      = modkernel32.NewProc("AddDllDirectory")
 	procAssignProcessToJobObject                             = modkernel32.NewProc("AssignProcessToJobObject")
 	procCancelIo                                             = modkernel32.NewProc("CancelIo")
@@ -1606,6 +1611,14 @@ func DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, si
 	return
 }
 
+func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) {
+	r0, _, _ := syscall.SyscallN(procCancelMibChangeNotify2.Addr(), uintptr(notificationHandle))
+	if r0 != 0 {
+		errcode = syscall.Errno(r0)
+	}
+	return
+}
+
 func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
 	r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0)
 	if r0 != 0 {
@@ -1638,6 +1651,46 @@ func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
 	return
 }
 
+func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) {
+	r0, _, _ := syscall.SyscallN(procGetIfEntry2Ex.Addr(), uintptr(level), uintptr(unsafe.Pointer(row)))
+	if r0 != 0 {
+		errcode = syscall.Errno(r0)
+	}
+	return
+}
+
+func GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) {
+	r0, _, _ := syscall.SyscallN(procGetUnicastIpAddressEntry.Addr(), uintptr(unsafe.Pointer(row)))
+	if r0 != 0 {
+		errcode = syscall.Errno(r0)
+	}
+	return
+}
+
+func NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
+	var _p0 uint32
+	if initialNotification {
+		_p0 = 1
+	}
+	r0, _, _ := syscall.SyscallN(procNotifyIpInterfaceChange.Addr(), uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)))
+	if r0 != 0 {
+		errcode = syscall.Errno(r0)
+	}
+	return
+}
+
+func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
+	var _p0 uint32
+	if initialNotification {
+		_p0 = 1
+	}
+	r0, _, _ := syscall.SyscallN(procNotifyUnicastIpAddressChange.Addr(), uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)))
+	if r0 != 0 {
+		errcode = syscall.Errno(r0)
+	}
+	return
+}
+
 func AddDllDirectory(path *uint16) (cookie uintptr, err error) {
 	r0, _, e1 := syscall.Syscall(procAddDllDirectory.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
 	cookie = uintptr(r0)
diff --git a/vendor/golang.org/x/term/README.md b/vendor/golang.org/x/term/README.md
index d03d0aefe..05ff623f9 100644
--- a/vendor/golang.org/x/term/README.md
+++ b/vendor/golang.org/x/term/README.md
@@ -4,16 +4,13 @@
 
 This repository provides Go terminal and console support packages.
 
-## Download/Install
-
-The easiest way to install is to run `go get -u golang.org/x/term`. You can
-also manually git clone the repository to `$GOPATH/src/golang.org/x/term`.
-
 ## Report Issues / Send Patches
 
 This repository uses Gerrit for code changes. To learn how to submit changes to
-this repository, see https://golang.org/doc/contribute.html.
+this repository, see https://go.dev/doc/contribute.
+
+The git repository is https://go.googlesource.com/term.
 
 The main issue tracker for the term repository is located at
-https://github.com/golang/go/issues. Prefix your issue with "x/term:" in the
+https://go.dev/issues. Prefix your issue with "x/term:" in the
 subject line, so it is easy to find.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 022bf647f..b47aafef8 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -105,7 +105,7 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources
 # github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0
 ## explicit; go 1.18
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage
-# github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.2.0
+# github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0
 ## explicit; go 1.18
 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets
 # github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0
@@ -161,7 +161,7 @@ github.com/Azure/go-autorest/logger
 # github.com/Azure/go-autorest/tracing v0.6.0
 ## explicit; go 1.12
 github.com/Azure/go-autorest/tracing
-# github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2
+# github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1
 ## explicit; go 1.18
 github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache
 github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential
@@ -497,7 +497,7 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/inte
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil
-# go.opentelemetry.io/otel v1.31.0
+# go.opentelemetry.io/otel v1.32.0
 ## explicit; go 1.22
 go.opentelemetry.io/otel
 go.opentelemetry.io/otel/attribute
@@ -528,7 +528,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry
 # go.opentelemetry.io/otel/exporters/prometheus v0.53.0
 ## explicit; go 1.22
 go.opentelemetry.io/otel/exporters/prometheus
-# go.opentelemetry.io/otel/metric v1.31.0
+# go.opentelemetry.io/otel/metric v1.32.0
 ## explicit; go 1.22
 go.opentelemetry.io/otel/metric
 go.opentelemetry.io/otel/metric/embedded
@@ -549,7 +549,7 @@ go.opentelemetry.io/otel/sdk/metric/internal
 go.opentelemetry.io/otel/sdk/metric/internal/aggregate
 go.opentelemetry.io/otel/sdk/metric/internal/x
 go.opentelemetry.io/otel/sdk/metric/metricdata
-# go.opentelemetry.io/otel/trace v1.31.0
+# go.opentelemetry.io/otel/trace v1.32.0
 ## explicit; go 1.22
 go.opentelemetry.io/otel/trace
 go.opentelemetry.io/otel/trace/embedded
@@ -578,7 +578,7 @@ go.uber.org/zap/internal/pool
 go.uber.org/zap/internal/stacktrace
 go.uber.org/zap/zapcore
 go.uber.org/zap/zapgrpc
-# golang.org/x/crypto v0.28.0
+# golang.org/x/crypto v0.29.0
 ## explicit; go 1.20
 golang.org/x/crypto/cryptobyte
 golang.org/x/crypto/cryptobyte/asn1
@@ -611,12 +611,12 @@ golang.org/x/net/websocket
 ## explicit; go 1.18
 golang.org/x/oauth2
 golang.org/x/oauth2/internal
-# golang.org/x/sync v0.8.0
+# golang.org/x/sync v0.9.0
 ## explicit; go 1.18
 golang.org/x/sync/errgroup
 golang.org/x/sync/semaphore
 golang.org/x/sync/singleflight
-# golang.org/x/sys v0.26.0
+# golang.org/x/sys v0.27.0
 ## explicit; go 1.18
 golang.org/x/sys/cpu
 golang.org/x/sys/plan9
@@ -624,10 +624,10 @@ golang.org/x/sys/unix
 golang.org/x/sys/windows
 golang.org/x/sys/windows/registry
 golang.org/x/sys/windows/svc
-# golang.org/x/term v0.25.0
+# golang.org/x/term v0.26.0
 ## explicit; go 1.18
 golang.org/x/term
-# golang.org/x/text v0.19.0
+# golang.org/x/text v0.20.0
 ## explicit; go 1.18
 golang.org/x/text/cases
 golang.org/x/text/encoding
@@ -659,7 +659,7 @@ golang.org/x/text/transform
 golang.org/x/text/unicode/bidi
 golang.org/x/text/unicode/norm
 golang.org/x/text/width
-# golang.org/x/time v0.7.0
+# golang.org/x/time v0.8.0
 ## explicit; go 1.18
 golang.org/x/time/rate
 # golang.org/x/tools v0.26.0
@@ -1533,7 +1533,7 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client
-# sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.11
+# sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.1.18
 ## explicit; go 1.23.1
 sigs.k8s.io/cloud-provider-azure/pkg/azclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/accountclient
@@ -1571,6 +1571,7 @@ sigs.k8s.io/cloud-provider-azure/pkg/azclient/registryclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/resourcegroupclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/roleassignmentclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient
+sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/secretclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient/mock_securitygroupclient
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/Makefile b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/Makefile
index 084588224..0fdd6f363 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/Makefile
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/Makefile
@@ -72,7 +72,7 @@ test: ## Run tests.
 	go test -v ./...
 
 .PHONY: generate
-generate: install-dependencies build generatecode generateimpl fmt vet-all
+generate: install-dependencies build generatecode generateimpl generateclientfactory generatemock fmt vet-all test
 
 .PHONY: generatecode
 generatecode: build ## Generate client
@@ -117,6 +117,14 @@ generatecode: build ## Generate client
 generateimpl: build ## Generate client
 	PATH=$(LOCALBIN):$$PATH $(CLIENTGEN) clientgen:headerFile=../../hack/boilerplate/boilerplate.gomock.txt paths=./...
 
+.PHONY: generatemock
+generatemock: build ## Generate client
+	PATH=$(LOCALBIN):$$PATH $(CLIENTGEN) mockgen:headerFile=../../hack/boilerplate/boilerplate.generatego.txt paths=./...
+
+.PHONY: generateclientfactory
+generateclientfactory: build ## Generate client
+	PATH=$(LOCALBIN):$$PATH $(CLIENTGEN) clientfactorygen:headerFile=../../hack/boilerplate/boilerplate.gomock.txt paths=./... output:dir=.
+
 .PHONY: vet-all
 vet-all: golangci-lint ## Run go vet against code.
 	$(LOCALBIN)/golangci-lint run --timeout 10m ./...
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/accountclient/mock_accountclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/accountclient/mock_accountclient/interface.go
index 2b1f72efc..daa7112fe 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/accountclient/mock_accountclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/accountclient/mock_accountclient/interface.go
@@ -13,13 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
+//
 
 // Code generated by MockGen. DO NOT EDIT.
 // Source: accountclient/interface.go
 //
 // Generated by this command:
 //
-//	mockgen -package mock_accountclient -source accountclient/interface.go
+//	mockgen -package mock_accountclient -source accountclient/interface.go -copyright_file ../../hack/boilerplate/boilerplate.generatego.txt
 //
 
 // Package mock_accountclient is a generated GoMock package.
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/arm_conf.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/arm_conf.go
index d8fe257d5..45f1d8d05 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/arm_conf.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/arm_conf.go
@@ -19,6 +19,7 @@ package azclient
 import (
 	"os"
 	"strings"
+	"time"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
 
@@ -38,6 +39,12 @@ type ARMClientConfig struct {
 	TenantID string `json:"tenantId,omitempty" yaml:"tenantId,omitempty"`
 	// The AAD Tenant ID for the Subscription that the network resources are deployed in.
 	NetworkResourceTenantID string `json:"networkResourceTenantID,omitempty" yaml:"networkResourceTenantID,omitempty"`
+	// Enable exponential backoff to manage resource request retries
+	CloudProviderBackoff bool `json:"cloudProviderBackoff,omitempty" yaml:"cloudProviderBackoff,omitempty"`
+	// Backoff retry limit
+	CloudProviderBackoffRetries int32 `json:"cloudProviderBackoffRetries,omitempty" yaml:"cloudProviderBackoffRetries,omitempty"`
+	// Backoff duration
+	CloudProviderBackoffDuration int `json:"cloudProviderBackoffDuration,omitempty" yaml:"cloudProviderBackoffDuration,omitempty"`
 }
 
 func (config *ARMClientConfig) GetTenantID() string {
@@ -63,6 +70,13 @@ func GetAzCoreClientOption(armConfig *ARMClientConfig) (*policy.ClientOptions, e
 			return nil, err
 		}
 		azCoreClientConfig.Cloud = *cloudConfig
+		if armConfig.CloudProviderBackoff && armConfig.CloudProviderBackoffDuration > 0 {
+			azCoreClientConfig.Retry.RetryDelay = time.Duration(armConfig.CloudProviderBackoffDuration) * time.Second
+		}
+		if armConfig.CloudProviderBackoff && armConfig.CloudProviderBackoffRetries > 0 {
+			azCoreClientConfig.Retry.MaxRetries = armConfig.CloudProviderBackoffRetries
+		}
+
 	}
 	return &azCoreClientConfig, nil
 }
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/mock_azclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/mock_azclient/interface.go
index d9f82a5da..2120e1ab8 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/mock_azclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/mock_azclient/interface.go
@@ -13,13 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
+//
 
 // Code generated by MockGen. DO NOT EDIT.
-// Source: sigs.k8s.io/cloud-provider-azure/pkg/azclient (interfaces: ClientFactory)
+// Source: factory.go
 //
 // Generated by this command:
 //
-//	mockgen -package mock_azclient sigs.k8s.io/cloud-provider-azure/pkg/azclient ClientFactory
+//	mockgen -package mock_azclient -source factory.go -copyright_file ../../hack/boilerplate/boilerplate.generatego.txt
 //
 
 // Package mock_azclient is a generated GoMock package.
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient/interface.go
index 630b2663e..95290b298 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatelinkserviceclient/mock_privatelinkserviceclient/interface.go
@@ -13,13 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
+//
 
 // Code generated by MockGen. DO NOT EDIT.
 // Source: privatelinkserviceclient/interface.go
 //
 // Generated by this command:
 //
-//	mockgen -package mock_privatelinkserviceclient -source privatelinkserviceclient/interface.go
+//	mockgen -package mock_privatelinkserviceclient -source privatelinkserviceclient/interface.go -copyright_file ../../hack/boilerplate/boilerplate.generatego.txt
 //
 
 // Package mock_privatelinkserviceclient is a generated GoMock package.
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatezoneclient/mock_privatezoneclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatezoneclient/mock_privatezoneclient/interface.go
index b90d7bdb8..6adaeeab5 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatezoneclient/mock_privatezoneclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/privatezoneclient/mock_privatezoneclient/interface.go
@@ -13,13 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
+//
 
 // Code generated by MockGen. DO NOT EDIT.
 // Source: privatezoneclient/interface.go
 //
 // Generated by this command:
 //
-//	mockgen -package mock_privatezoneclient -source privatezoneclient/interface.go
+//	mockgen -package mock_privatezoneclient -source privatezoneclient/interface.go -copyright_file ../../hack/boilerplate/boilerplate.generatego.txt
 //
 
 // Package mock_privatezoneclient is a generated GoMock package.
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/providerclient/mock_providerclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/providerclient/mock_providerclient/interface.go
index 969ec4b8e..de74d3cb1 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/providerclient/mock_providerclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/providerclient/mock_providerclient/interface.go
@@ -13,13 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
+//
 
 // Code generated by MockGen. DO NOT EDIT.
 // Source: providerclient/interface.go
 //
 // Generated by this command:
 //
-//	mockgen -package mock_providerclient -source providerclient/interface.go
+//	mockgen -package mock_providerclient -source providerclient/interface.go -copyright_file ../../hack/boilerplate/boilerplate.generatego.txt
 //
 
 // Package mock_providerclient is a generated GoMock package.
diff --git a/pkg/azureclients/routetableclient/mockroutetableclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient/interface.go
similarity index 52%
rename from pkg/azureclients/routetableclient/mockroutetableclient/interface.go
rename to vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient/interface.go
index 200ff014c..ef6fedb42 100644
--- a/pkg/azureclients/routetableclient/mockroutetableclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient/interface.go
@@ -13,32 +13,31 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
-//
 
 // Code generated by MockGen. DO NOT EDIT.
-// Source: pkg/azureclients/routetableclient/interface.go
+// Source: routetableclient/interface.go
 //
 // Generated by this command:
 //
-//	mockgen -copyright_file=/home/runner/work/cloud-provider-azure/cloud-provider-azure/hack/boilerplate/boilerplate.generatego.txt -source=pkg/azureclients/routetableclient/interface.go -package=mockroutetableclient Interface
+//	mockgen -package mock_routetableclient -source routetableclient/interface.go
 //
 
-// Package mockroutetableclient is a generated GoMock package.
-package mockroutetableclient
+// Package mock_routetableclient is a generated GoMock package.
+package mock_routetableclient
 
 import (
 	context "context"
 	reflect "reflect"
 
-	network "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
+	armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	gomock "go.uber.org/mock/gomock"
-	retry "sigs.k8s.io/cloud-provider-azure/pkg/retry"
 )
 
 // MockInterface is a mock of Interface interface.
 type MockInterface struct {
 	ctrl     *gomock.Controller
 	recorder *MockInterfaceMockRecorder
+	isgomock struct{}
 }
 
 // MockInterfaceMockRecorder is the mock recorder for MockInterface.
@@ -59,30 +58,60 @@ func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
 }
 
 // CreateOrUpdate mocks base method.
-func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, routeTableName string, parameters network.RouteTable, etag string) *retry.Error {
+func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, resourceName string, resourceParam armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, routeTableName, parameters, etag)
-	ret0, _ := ret[0].(*retry.Error)
-	return ret0
+	ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, resourceName, resourceParam)
+	ret0, _ := ret[0].(*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
 }
 
 // CreateOrUpdate indicates an expected call of CreateOrUpdate.
-func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, routeTableName, parameters, etag any) *gomock.Call {
+func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, resourceName, resourceParam any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, routeTableName, parameters, etag)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, resourceName, resourceParam)
+}
+
+// Delete mocks base method.
+func (m *MockInterface) Delete(ctx context.Context, resourceGroupName, resourceName string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Delete", ctx, resourceGroupName, resourceName)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Delete indicates an expected call of Delete.
+func (mr *MockInterfaceMockRecorder) Delete(ctx, resourceGroupName, resourceName any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockInterface)(nil).Delete), ctx, resourceGroupName, resourceName)
 }
 
 // Get mocks base method.
-func (m *MockInterface) Get(ctx context.Context, resourceGroupName, routeTableName, expand string) (network.RouteTable, *retry.Error) {
+func (m *MockInterface) Get(ctx context.Context, resourceGroupName, resourceName string) (*armnetwork.RouteTable, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, routeTableName, expand)
-	ret0, _ := ret[0].(network.RouteTable)
-	ret1, _ := ret[1].(*retry.Error)
+	ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, resourceName)
+	ret0, _ := ret[0].(*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // Get indicates an expected call of Get.
-func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, routeTableName, expand any) *gomock.Call {
+func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, resourceName any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, resourceName)
+}
+
+// List mocks base method.
+func (m *MockInterface) List(ctx context.Context, resourceGroupName string) ([]*armnetwork.RouteTable, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "List", ctx, resourceGroupName)
+	ret0, _ := ret[0].([]*armnetwork.RouteTable)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// List indicates an expected call of List.
+func (mr *MockInterfaceMockRecorder) List(ctx, resourceGroupName any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, routeTableName, expand)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockInterface)(nil).List), ctx, resourceGroupName)
 }
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient/mock_securitygroupclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient/mock_securitygroupclient/interface.go
index 466a774b7..a9d719f7a 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient/mock_securitygroupclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/securitygroupclient/mock_securitygroupclient/interface.go
@@ -13,13 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
+//
 
 // Code generated by MockGen. DO NOT EDIT.
 // Source: securitygroupclient/interface.go
 //
 // Generated by this command:
 //
-//	mockgen -package mock_securitygroupclient -source securitygroupclient/interface.go
+//	mockgen -package mock_securitygroupclient -source securitygroupclient/interface.go -copyright_file ../../hack/boilerplate/boilerplate.generatego.txt
 //
 
 // Package mock_securitygroupclient is a generated GoMock package.
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/subnetclient/mock_subnetclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/subnetclient/mock_subnetclient/interface.go
index 382b6b4f8..ab770ef46 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/subnetclient/mock_subnetclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/subnetclient/mock_subnetclient/interface.go
@@ -13,13 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
+//
 
 // Code generated by MockGen. DO NOT EDIT.
 // Source: subnetclient/interface.go
 //
 // Generated by this command:
 //
-//	mockgen -package mock_subnetclient -source subnetclient/interface.go
+//	mockgen -package mock_subnetclient -source subnetclient/interface.go -copyright_file ../../hack/boilerplate/boilerplate.generatego.txt
 //
 
 // Package mock_subnetclient is a generated GoMock package.
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworklinkclient/mock_virtualnetworklinkclient/interface.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworklinkclient/mock_virtualnetworklinkclient/interface.go
index 363646052..a603655a6 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworklinkclient/mock_virtualnetworklinkclient/interface.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/virtualnetworklinkclient/mock_virtualnetworklinkclient/interface.go
@@ -13,13 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // */
+//
 
 // Code generated by MockGen. DO NOT EDIT.
 // Source: virtualnetworklinkclient/interface.go
 //
 // Generated by this command:
 //
-//	mockgen -package mock_virtualnetworklinkclient -source virtualnetworklinkclient/interface.go
+//	mockgen -package mock_virtualnetworklinkclient -source virtualnetworklinkclient/interface.go -copyright_file ../../hack/boilerplate/boilerplate.generatego.txt
 //
 
 // Package mock_virtualnetworklinkclient is a generated GoMock package.


Test patch:
diff --git a/e2e.Dockerfile b/e2e.Dockerfile
index 6e6631e48..2c221c5a5 100644
--- a/e2e.Dockerfile
+++ b/e2e.Dockerfile
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM golang:1.23-bullseye@sha256:1002103155eb5802f6876dceb8cb8bf965cc6d3deeb34f11e4774926aca6a1fd
+FROM golang:1.23-bullseye@sha256:d4387d8b2ee5b78a199fae168a761d0fb0f33f172642d20856f29a67204af16b
 
 WORKDIR /go/src/sigs.k8s.io/cloud-provider-azure
 
diff --git a/pkg/azureclients/routetableclient/azure_routetableclient_test.go b/pkg/azureclients/routetableclient/azure_routetableclient_test.go
deleted file mode 100644
index ee1d6d9d4..000000000
--- a/pkg/azureclients/routetableclient/azure_routetableclient_test.go
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package routetableclient
-
-import (
-	"bytes"
-	"context"
-	"fmt"
-	"io"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-	"github.com/Azure/go-autorest/autorest"
-	"github.com/stretchr/testify/assert"
-
-	"go.uber.org/mock/gomock"
-
-	"k8s.io/client-go/util/flowcontrol"
-	"k8s.io/utils/ptr"
-
-	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient/mockarmclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-const (
-	resourceID = "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Network/routeTables/rt1"
-)
-
-// 2065-01-24 05:20:00 +0000 UTC
-func getFutureTime() time.Time {
-	return time.Unix(3000000000, 0)
-}
-
-func TestNew(t *testing.T) {
-	config := &azclients.ClientConfig{
-		SubscriptionID:          "sub",
-		ResourceManagerEndpoint: "endpoint",
-		Location:                "eastus",
-		RateLimitConfig: &azclients.RateLimitConfig{
-			CloudProviderRateLimit:            true,
-			CloudProviderRateLimitQPS:         0.5,
-			CloudProviderRateLimitBucket:      1,
-			CloudProviderRateLimitQPSWrite:    0.5,
-			CloudProviderRateLimitBucketWrite: 1,
-		},
-		Backoff: &retry.Backoff{Steps: 1},
-	}
-
-	routetableClient := New(config)
-	assert.Equal(t, "sub", routetableClient.subscriptionID)
-	assert.NotEmpty(t, routetableClient.rateLimiterReader)
-	assert.NotEmpty(t, routetableClient.rateLimiterWriter)
-}
-
-func TestNewAzureStack(t *testing.T) {
-	config := &azclients.ClientConfig{
-		CloudName:               "AZURESTACKCLOUD",
-		SubscriptionID:          "sub",
-		ResourceManagerEndpoint: "endpoint",
-		Location:                "eastus",
-		RateLimitConfig: &azclients.RateLimitConfig{
-			CloudProviderRateLimit:            true,
-			CloudProviderRateLimitQPS:         0.5,
-			CloudProviderRateLimitBucket:      1,
-			CloudProviderRateLimitQPSWrite:    0.5,
-			CloudProviderRateLimitBucketWrite: 1,
-		},
-		Backoff: &retry.Backoff{Steps: 1},
-	}
-
-	routetableClient := New(config)
-	assert.Equal(t, "AZURESTACKCLOUD", routetableClient.cloudName)
-	assert.Equal(t, "sub", routetableClient.subscriptionID)
-}
-
-func TestGet(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusOK,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), resourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	routetableClient := getTestRouteTableClient(armClient)
-	expected := network.RouteTable{}
-	expected.Response = autorest.Response{Response: response}
-	result, rerr := routetableClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.Nil(t, rerr)
-}
-
-func TestGetNotFound(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), resourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	rtClient := getTestRouteTableClient(armClient)
-	expected := network.RouteTable{Response: autorest.Response{}}
-	result, rerr := rtClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode)
-}
-
-func TestGetInternalError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusInternalServerError,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), resourceID, "").Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	rtClient := getTestRouteTableClient(armClient)
-	expected := network.RouteTable{Response: autorest.Response{}}
-	result, rerr := rtClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.NotNil(t, rerr)
-	assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode)
-}
-
-func TestGetNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rtGetErr := &retry.Error{
-		RawError:  fmt.Errorf("azure cloud provider rate limited(%s) for operation %q", "read", "RouteTableGet"),
-		Retriable: true,
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	routetableClient := getTestRouteTableClientWithNeverRateLimiter(armClient)
-	expected := network.RouteTable{}
-	result, rerr := routetableClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.Equal(t, rtGetErr, rerr)
-}
-
-func TestGetRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rtGetErr := &retry.Error{
-		RawError:   fmt.Errorf("azure cloud provider throttled for operation %s with reason %q", "RouteTableGet", "client throttled"),
-		Retriable:  true,
-		RetryAfter: getFutureTime(),
-	}
-
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	routetableClient := getTestRouteTableClientWithRetryAfterReader(armClient)
-	expected := network.RouteTable{}
-	result, rerr := routetableClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Equal(t, expected, result)
-	assert.Equal(t, rtGetErr, rerr)
-}
-
-func TestGetThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusTooManyRequests,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().GetResourceWithExpandQuery(gomock.Any(), resourceID, "").Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	routetableClient := getTestRouteTableClient(armClient)
-	result, rerr := routetableClient.Get(context.TODO(), "rg", "rt1", "")
-	assert.Empty(t, result)
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestCreateOrUpdate(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusOK,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(rt1.ID, ""), rt1, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	rtClient := getTestRouteTableClient(armClient)
-	rerr := rtClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "*")
-	assert.Nil(t, rerr)
-}
-
-func TestCreateOrUpdateWithNeverRateLimiter(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rcCreateOrUpdateErr := retry.GetRateLimitError(true, "RouteTableCreateOrUpdate")
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	routetableClient := getTestRouteTableClientWithNeverRateLimiter(armClient)
-	rerr := routetableClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "")
-	assert.Equal(t, rcCreateOrUpdateErr, rerr)
-}
-
-func TestCreateOrUpdateRetryAfterReader(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rcCreateOrUpdateErr := retry.GetThrottlingError("RouteTableCreateOrUpdate", "client throttled", getFutureTime())
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-
-	routetableClient := getTestRouteTableClientWithRetryAfterReader(armClient)
-	rerr := routetableClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "")
-	assert.NotNil(t, rerr)
-	assert.Equal(t, rcCreateOrUpdateErr, rerr)
-}
-
-func TestCreateOrUpdateThrottle(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	response := &http.Response{
-		StatusCode: http.StatusTooManyRequests,
-		Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
-	}
-	throttleErr := &retry.Error{
-		HTTPStatusCode: http.StatusTooManyRequests,
-		RawError:       fmt.Errorf("error"),
-		Retriable:      true,
-		RetryAfter:     time.Unix(100, 0),
-	}
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(rt1.ID, ""), rt1, gomock.Any()).Return(response, throttleErr).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	routetableClient := getTestRouteTableClient(armClient)
-	rerr := routetableClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "")
-	assert.Equal(t, throttleErr, rerr)
-}
-
-func TestCreateOrUpdateWithCreateOrUpdateResponderError(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	rt1 := getTestRouteTable("rt1")
-	armClient := mockarmclient.NewMockInterface(ctrl)
-	response := &http.Response{
-		StatusCode: http.StatusNotFound,
-		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
-	}
-
-	armClient.EXPECT().PutResource(gomock.Any(), ptr.Deref(rt1.ID, ""), rt1, gomock.Any()).Return(response, nil).Times(1)
-	armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1)
-
-	routetableClient := getTestRouteTableClient(armClient)
-	rerr := routetableClient.CreateOrUpdate(context.TODO(), "rg", "rt1", rt1, "")
-	assert.NotNil(t, rerr)
-}
-
-func getTestRouteTable(name string) network.RouteTable {
-	return network.RouteTable{
-		ID:       ptr.To(fmt.Sprintf("/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Network/routeTables/%s", name)),
-		Name:     ptr.To(name),
-		Location: ptr.To("eastus"),
-	}
-}
-
-func getTestRouteTableClient(armClient armclient.Interface) *Client {
-	rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{})
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
-
-func getTestRouteTableClientWithNeverRateLimiter(armClient armclient.Interface) *Client {
-	rateLimiterReader := flowcontrol.NewFakeNeverRateLimiter()
-	rateLimiterWriter := flowcontrol.NewFakeNeverRateLimiter()
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-	}
-}
-
-func getTestRouteTableClientWithRetryAfterReader(armClient armclient.Interface) *Client {
-	rateLimiterReader := flowcontrol.NewFakeAlwaysRateLimiter()
-	rateLimiterWriter := flowcontrol.NewFakeAlwaysRateLimiter()
-	return &Client{
-		armClient:         armClient,
-		subscriptionID:    "subscriptionID",
-		rateLimiterReader: rateLimiterReader,
-		rateLimiterWriter: rateLimiterWriter,
-		RetryAfterReader:  getFutureTime(),
-		RetryAfterWriter:  getFutureTime(),
-	}
-}
diff --git a/pkg/provider/azure_loadbalancer_test.go b/pkg/provider/azure_loadbalancer_test.go
index ca8b3ffb0..3385b3072 100644
--- a/pkg/provider/azure_loadbalancer_test.go
+++ b/pkg/provider/azure_loadbalancer_test.go
@@ -6236,6 +6236,8 @@ func TestCleanOrphanedLoadBalancerLBInUseByVMSS(t *testing.T) {
 		expectedVMSS := buildTestVMSSWithLB(testVMSSName, "vmss-vm-", []string{testLBBackendpoolID0}, false)
 		mockVMSSClient := cloud.VirtualMachineScaleSetsClient.(*mockvmssclient.MockInterface)
 		mockVMSSClient.EXPECT().List(gomock.Any(), "rg").Return([]compute.VirtualMachineScaleSet{expectedVMSS}, nil)
+		mockVMSSClient.EXPECT().Get(gomock.Any(), "rg", testVMSSName).Return(expectedVMSS, nil)
+		mockVMSSClient.EXPECT().CreateOrUpdate(gomock.Any(), "rg", testVMSSName, gomock.Any()).Return(nil)
 
 		service := getTestService("test", v1.ProtocolTCP, nil, false, 80)
 		lb := getTestLoadBalancer(ptr.To("test"), ptr.To("rg"), ptr.To("test"), ptr.To("test"), service, consts.LoadBalancerSkuStandard)
diff --git a/pkg/provider/azure_routes_test.go b/pkg/provider/azure_routes_test.go
index b95165892..719dff4f1 100644
--- a/pkg/provider/azure_routes_test.go
+++ b/pkg/provider/azure_routes_test.go
@@ -18,13 +18,13 @@ package provider
 
 import (
 	"context"
+	"errors"
 	"fmt"
-	"net/http"
 	"reflect"
 	"testing"
 	"time"
 
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
 	"github.com/stretchr/testify/assert"
 	"go.uber.org/mock/gomock"
 
@@ -32,18 +32,18 @@ import (
 	cloudprovider "k8s.io/cloud-provider"
 	"k8s.io/utils/ptr"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient/mockroutetableclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
+	"sigs.k8s.io/cloud-provider-azure/pkg/provider/routetable"
 	utilsets "sigs.k8s.io/cloud-provider-azure/pkg/util/sets"
 )
 
 func TestDeleteRoute(t *testing.T) {
+	t.Parallel()
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
 
+	mockRTRepo := routetable.NewMockRepository(ctrl)
 	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
+		routeTableRepo: mockRTRepo,
 		Config: Config{
 			RouteTableResourceGroup: "foo",
 			RouteTableName:          "bar",
@@ -52,8 +52,6 @@ func TestDeleteRoute(t *testing.T) {
 		unmanagedNodes:     utilsets.NewString(),
 		nodeInformerSynced: func() bool { return true },
 	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
 	cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
 	go cloud.routeUpdater.run(context.Background())
 	route := cloudprovider.Route{
@@ -61,26 +59,33 @@ func TestDeleteRoute(t *testing.T) {
 		DestinationCIDR: "1.2.3.4/24",
 	}
 	routeName := mapNodeNameToRouteName(false, route.TargetNode, route.DestinationCIDR)
-	routeTables := network.RouteTable{
+	routeTables := &armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{
 				{
 					Name: &routeName,
 				},
 			},
 		},
 	}
-	routeTablesAfterDeletion := network.RouteTable{
+	routeTablesAfterDeletion := armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{},
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{},
 		},
 	}
-	routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(routeTables, nil).AnyTimes()
-	routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, routeTablesAfterDeletion, "").Return(nil)
+
+	mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(routeTables, nil).AnyTimes()
+	mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any()).DoAndReturn(
+		func(_ context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+			assert.Equal(t, routeTablesAfterDeletion, routeTable)
+			return nil, nil
+		},
+	).AnyTimes()
+
 	err := cloud.DeleteRoute(context.TODO(), "cluster", &route)
 	if err != nil {
 		t.Errorf("unexpected error deleting route: %v", err)
@@ -110,12 +115,13 @@ func TestDeleteRoute(t *testing.T) {
 }
 
 func TestDeleteRouteDualStack(t *testing.T) {
+	t.Parallel()
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
 
+	mockRTRepo := routetable.NewMockRepository(ctrl)
 	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
+		routeTableRepo: mockRTRepo,
 		Config: Config{
 			RouteTableResourceGroup: "foo",
 			RouteTableName:          "bar",
@@ -125,8 +131,6 @@ func TestDeleteRouteDualStack(t *testing.T) {
 		nodeInformerSynced:   func() bool { return true },
 		ipv6DualStackEnabled: true,
 	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
 	cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
 	go cloud.routeUpdater.run(context.Background())
 
@@ -136,11 +140,11 @@ func TestDeleteRouteDualStack(t *testing.T) {
 	}
 	routeName := mapNodeNameToRouteName(true, route.TargetNode, route.DestinationCIDR)
 	routeNameIPV4 := mapNodeNameToRouteName(false, route.TargetNode, route.DestinationCIDR)
-	routeTables := network.RouteTable{
+	routeTables := &armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{
 				{
 					Name: &routeName,
 				},
@@ -150,28 +154,38 @@ func TestDeleteRouteDualStack(t *testing.T) {
 			},
 		},
 	}
-	routeTablesAfterFirstDeletion := network.RouteTable{
+	routeTablesAfterFirstDeletion := armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{
 				{
 					Name: &routeNameIPV4,
 				},
 			},
 		},
 	}
-	routeTablesAfterSecondDeletion := network.RouteTable{
+	routeTablesAfterSecondDeletion := armnetwork.RouteTable{
 		Name:     &cloud.RouteTableName,
 		Location: &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-			Routes: &[]network.Route{},
+		Properties: &armnetwork.RouteTablePropertiesFormat{
+			Routes: []*armnetwork.Route{},
 		},
 	}
-	routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(routeTables, nil)
-	routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(routeTablesAfterFirstDeletion, nil)
-	routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, routeTablesAfterFirstDeletion, "").Return(nil)
-	routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, routeTablesAfterSecondDeletion, "").Return(nil)
+	mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(routeTables, nil)
+	mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(&routeTablesAfterFirstDeletion, nil)
+	mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any()).DoAndReturn(
+		func(_ context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+			assert.Equal(t, routeTablesAfterFirstDeletion, routeTable)
+			return nil, nil
+		},
+	)
+	mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any()).DoAndReturn(
+		func(_ context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+			assert.Equal(t, routeTablesAfterSecondDeletion, routeTable)
+			return nil, nil
+		},
+	)
 	err := cloud.DeleteRoute(context.TODO(), "cluster", &route)
 	if err != nil {
 		t.Errorf("unexpected error deleting route: %v", err)
@@ -181,45 +195,28 @@ func TestDeleteRouteDualStack(t *testing.T) {
 }
 
 func TestCreateRoute(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
-	mockVMSet := NewMockVMSet(ctrl)
-
-	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
-		VMSet:             mockVMSet,
-		Config: Config{
-			RouteTableResourceGroup: "foo",
-			RouteTableName:          "bar",
-			Location:                "location",
-		},
-		unmanagedNodes:     utilsets.NewString(),
-		nodeInformerSynced: func() bool { return true },
-	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
-	cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
-	go cloud.routeUpdater.run(context.Background())
+	t.Parallel()
 
-	route := cloudprovider.Route{TargetNode: "node", DestinationCIDR: "1.2.3.4/24"}
 	nodePrivateIP := "2.4.6.8"
-	networkRoute := &[]network.Route{
-		{
-			Name: ptr.To("node"),
-			RoutePropertiesFormat: &network.RoutePropertiesFormat{
-				AddressPrefix:    ptr.To("1.2.3.4/24"),
-				NextHopIPAddress: &nodePrivateIP,
-				NextHopType:      network.RouteNextHopTypeVirtualAppliance,
+
+	defaultNetworkRoute := func() []*armnetwork.Route {
+		return []*armnetwork.Route{
+			{
+				Name: ptr.To("node"),
+				Properties: &armnetwork.RoutePropertiesFormat{
+					AddressPrefix:    ptr.To("1.2.3.4/24"),
+					NextHopIPAddress: &nodePrivateIP,
+					NextHopType:      ptr.To(armnetwork.RouteNextHopTypeVirtualAppliance),
+				},
 			},
-		},
+		}
 	}
 
-	testCases := []struct {
+	tests := []struct {
 		name                  string
 		routeTableName        string
-		initialRoute          *[]network.Route
-		updatedRoute          *[]network.Route
+		initialRoute          []*armnetwork.Route
+		updatedRoute          []*armnetwork.Route
 		hasUnmanagedNodes     bool
 		nodeInformerNotSynced bool
 		ipv6DualStackEnabled  bool
@@ -229,71 +226,49 @@ func TestCreateRoute(t *testing.T) {
 		expectedRouteCIDRs    map[string]string
 
 		getIPError        error
-		getErr            *retry.Error
-		secondGetErr      *retry.Error
-		createOrUpdateErr *retry.Error
+		firstGetNotFound  bool // FIXME: it's very confusing; should refactor the whole test
+		getErr            error
+		secondGetErr      error
+		createOrUpdateErr error
 		expectedErrMsg    error
 	}{
-		{
-			name:           "CreateRoute should report an error if route table name is not configured",
-			routeTableName: "",
-			expectedErrMsg: fmt.Errorf("route table name is not configured"),
-		},
 		{
 			name:           "CreateRoute should create route if route doesn't exist",
 			routeTableName: "rt1",
-			updatedRoute:   networkRoute,
+			updatedRoute:   defaultNetworkRoute(),
 		},
 		{
-			name:           "CreateRoute should report error if error occurs when invoke CreateOrUpdateRouteTable",
-			routeTableName: "rt2",
-			updatedRoute:   networkRoute,
-			createOrUpdateErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("CreateOrUpdate error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: CreateOrUpdate error"),
+			name:              "CreateRoute should report error if error occurs when invoke CreateOrUpdateRouteTable",
+			routeTableName:    "rt2",
+			updatedRoute:      defaultNetworkRoute(),
+			createOrUpdateErr: errors.New("dummy"),
+			expectedErrMsg:    errors.New("dummy"),
 		},
 		{
 			name:           "CreateRoute should do nothing if route already exists",
 			routeTableName: "rt3",
-			initialRoute:   networkRoute,
-			updatedRoute:   networkRoute,
+			initialRoute:   defaultNetworkRoute(),
+			updatedRoute:   defaultNetworkRoute(),
 		},
 		{
-			name:           "CreateRoute should report error if error occurs when invoke createRouteTable",
-			routeTableName: "rt4",
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusNotFound,
-				RawError:       cloudprovider.InstanceNotFound,
-			},
-			createOrUpdateErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("CreateOrUpdate error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: CreateOrUpdate error"),
+			name:              "CreateRoute should report error if error occurs when invoke createRouteTable",
+			routeTableName:    "rt4",
+			firstGetNotFound:  true,
+			createOrUpdateErr: errors.New("create or update dummy"),
+			expectedErrMsg:    errors.New("create or update dummy"),
 		},
 		{
-			name:           "CreateRoute should report error if error occurs when invoke getRouteTable for the second time",
-			routeTableName: "rt5",
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusNotFound,
-				RawError:       cloudprovider.InstanceNotFound,
-			},
-			secondGetErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("Get error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: Get error"),
+			name:             "CreateRoute should report error if error occurs when invoke getRouteTable for the second time",
+			routeTableName:   "rt5",
+			firstGetNotFound: true,
+			secondGetErr:     errors.New("second get dummy"),
+			expectedErrMsg:   errors.New("second get dummy"),
 		},
 		{
 			name:           "CreateRoute should report error if error occurs when invoke routeTableClient.Get",
 			routeTableName: "rt6",
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("Get error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: Get error"),
+			getErr:         errors.New("first get dummy"),
+			expectedErrMsg: errors.New("first get dummy"),
 		},
 		{
 			name:           "CreateRoute should report error if error occurs when invoke GetIPByNodeName",
@@ -312,13 +287,13 @@ func TestCreateRoute(t *testing.T) {
 		{
 			name:           "CreateRoute should create route if cloud.ipv6DualStackEnabled is true and route doesn't exist",
 			routeTableName: "rt9",
-			updatedRoute: &[]network.Route{
+			updatedRoute: []*armnetwork.Route{
 				{
 					Name: ptr.To("node____123424"),
-					RoutePropertiesFormat: &network.RoutePropertiesFormat{
+					Properties: &armnetwork.RoutePropertiesFormat{
 						AddressPrefix:    ptr.To("1.2.3.4/24"),
 						NextHopIPAddress: &nodePrivateIP,
-						NextHopType:      network.RouteNextHopTypeVirtualAppliance,
+						NextHopType:      ptr.To(armnetwork.RouteNextHopTypeVirtualAppliance),
 					},
 				},
 			},
@@ -331,76 +306,111 @@ func TestCreateRoute(t *testing.T) {
 		},
 	}
 
-	for _, test := range testCases {
-		initialTable := network.RouteTable{
-			Name:     ptr.To(test.routeTableName),
-			Location: &cloud.Location,
-			RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-				Routes: test.initialRoute,
-			},
-		}
-		updatedTable := network.RouteTable{
-			Name:     ptr.To(test.routeTableName),
-			Location: &cloud.Location,
-			RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-				Routes: test.updatedRoute,
-			},
-		}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			t.Parallel()
 
-		cloud.RouteTableName = test.routeTableName
-		cloud.ipv6DualStackEnabled = test.ipv6DualStackEnabled
-		if test.hasUnmanagedNodes {
-			cloud.unmanagedNodes.Insert(test.unmanagedNodeName)
-			cloud.routeCIDRs = test.routeCIDRs
-		} else {
-			cloud.unmanagedNodes = utilsets.NewString()
-			cloud.routeCIDRs = nil
-		}
-		if test.nodeInformerNotSynced {
-			cloud.nodeInformerSynced = func() bool { return false }
-		} else {
-			cloud.nodeInformerSynced = func() bool { return true }
-		}
+			ctrl := gomock.NewController(t)
+			defer ctrl.Finish()
+			mockVMSet := NewMockVMSet(ctrl)
 
-		mockVMSet.EXPECT().GetIPByNodeName(gomock.Any(), gomock.Any()).Return(nodePrivateIP, "", test.getIPError).MaxTimes(1)
-		mockVMSet.EXPECT().GetPrivateIPsByNodeName(gomock.Any(), "node").Return([]string{nodePrivateIP, "10.10.10.10"}, nil).MaxTimes(1)
-		routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(initialTable, test.getErr).MaxTimes(1)
-		routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, updatedTable, "").Return(test.createOrUpdateErr).MaxTimes(1)
+			mockRTRepo := routetable.NewMockRepository(ctrl)
+			cloud := &Cloud{
+				routeTableRepo: mockRTRepo,
+				VMSet:          mockVMSet,
+				Config: Config{
+					RouteTableResourceGroup: "foo",
+					RouteTableName:          "bar",
+					Location:                "location",
+				},
+				unmanagedNodes:     utilsets.NewString(),
+				nodeInformerSynced: func() bool { return true },
+			}
+			cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
+			go cloud.routeUpdater.run(context.Background())
 
-		//Here is the second invocation when route table doesn't exist
-		routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, "").Return(initialTable, test.secondGetErr).MaxTimes(1)
+			initialTable := &armnetwork.RouteTable{
+				Name:     ptr.To(tt.routeTableName),
+				Location: &cloud.Location,
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: tt.initialRoute,
+				},
+			}
+			updatedTable := armnetwork.RouteTable{
+				Name:     ptr.To(tt.routeTableName),
+				Location: &cloud.Location,
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: tt.updatedRoute,
+				},
+			}
 
-		err := cloud.CreateRoute(context.TODO(), "cluster", "unused", &route)
-		assert.Equal(t, cloud.routeCIDRs, test.expectedRouteCIDRs, test.name)
-		if err != nil {
-			assert.EqualError(t, test.expectedErrMsg, err.Error(), test.name)
-		}
+			cloud.RouteTableName = tt.routeTableName
+			cloud.ipv6DualStackEnabled = tt.ipv6DualStackEnabled
+			if tt.hasUnmanagedNodes {
+				cloud.unmanagedNodes.Insert(tt.unmanagedNodeName)
+				cloud.routeCIDRs = tt.routeCIDRs
+			} else {
+				cloud.unmanagedNodes = utilsets.NewString()
+				cloud.routeCIDRs = nil
+			}
+			if tt.nodeInformerNotSynced {
+				cloud.nodeInformerSynced = func() bool { return false }
+			} else {
+				cloud.nodeInformerSynced = func() bool { return true }
+			}
+
+			mockVMSet.EXPECT().GetIPByNodeName(gomock.Any(), gomock.Any()).Return(nodePrivateIP, "", tt.getIPError).MaxTimes(1)
+			mockVMSet.EXPECT().GetPrivateIPsByNodeName(gomock.Any(), "node").Return([]string{nodePrivateIP, "10.10.10.10"}, nil).MaxTimes(1)
+			if tt.firstGetNotFound {
+				mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(nil, nil).MaxTimes(1)
+			} else {
+				mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(initialTable, tt.getErr).MaxTimes(1)
+			}
+
+			mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), gomock.Any()).DoAndReturn(
+				func(_ context.Context, routeTable armnetwork.RouteTable) (*armnetwork.RouteTable, error) {
+					assert.Equal(t, updatedTable, routeTable)
+					return nil, tt.createOrUpdateErr
+				},
+			).MaxTimes(1)
+
+			//Here is the second invocation when route table doesn't exist
+			mockRTRepo.EXPECT().Get(gomock.Any(), cloud.RouteTableName, gomock.Any()).Return(initialTable, tt.secondGetErr).MaxTimes(1)
+
+			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+			defer cancel()
+			route := cloudprovider.Route{TargetNode: "node", DestinationCIDR: "1.2.3.4/24"}
+			err := cloud.CreateRoute(ctx, "cluster", "unused", &route)
+			assert.Equal(t, cloud.routeCIDRs, tt.expectedRouteCIDRs, tt.name)
+			if err != nil {
+				assert.EqualError(t, tt.expectedErrMsg, err.Error(), tt.name)
+			}
+		})
 	}
 }
 
 func TestCreateRouteTable(t *testing.T) {
+	t.Parallel()
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
 
+	mockRTRepo := routetable.NewMockRepository(ctrl)
 	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
+		routeTableRepo: mockRTRepo,
 		Config: Config{
 			RouteTableResourceGroup: "foo",
 			RouteTableName:          "bar",
 			Location:                "location",
 		},
 	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
 
-	expectedTable := network.RouteTable{
-		Name:                       &cloud.RouteTableName,
-		Location:                   &cloud.Location,
-		RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{},
+	expectedTable := armnetwork.RouteTable{
+		Name:       &cloud.RouteTableName,
+		Location:   &cloud.Location,
+		Properties: &armnetwork.RouteTablePropertiesFormat{},
 	}
-	routeTableClient.EXPECT().CreateOrUpdate(gomock.Any(), cloud.RouteTableResourceGroup, cloud.RouteTableName, expectedTable, "").Return(nil)
-	err := cloud.createRouteTable()
+	mockRTRepo.EXPECT().CreateOrUpdate(gomock.Any(), expectedTable).Return(nil, nil)
+	err := cloud.createRouteTable(context.Background())
 	if err != nil {
 		t.Errorf("unexpected error in creating route table: %v", err)
 		t.FailNow()
@@ -409,9 +419,8 @@ func TestCreateRouteTable(t *testing.T) {
 
 func TestProcessRoutes(t *testing.T) {
 	tests := []struct {
-		rt            network.RouteTable
+		rt            *armnetwork.RouteTable
 		expectedRoute []cloudprovider.Route
-		exists        bool
 		expectErr     bool
 		name          string
 		expectedError string
@@ -423,35 +432,31 @@ func TestProcessRoutes(t *testing.T) {
 			expectedError: "test error",
 		},
 		{
-			exists: false,
-			name:   "doesn't exist",
+			name: "doesn't exist",
 		},
 		{
-			rt:     network.RouteTable{},
-			exists: true,
-			name:   "nil routes",
+			rt:   &armnetwork.RouteTable{},
+			name: "nil routes",
 		},
 		{
-			rt: network.RouteTable{
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{},
+			rt: &armnetwork.RouteTable{
+				Properties: &armnetwork.RouteTablePropertiesFormat{},
 			},
-			exists: true,
-			name:   "no routes",
+			name: "no routes",
 		},
 		{
-			rt: network.RouteTable{
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-					Routes: &[]network.Route{
+			rt: &armnetwork.RouteTable{
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: []*armnetwork.Route{
 						{
 							Name: ptr.To("name"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("1.2.3.4/16"),
 							},
 						},
 					},
 				},
 			},
-			exists: true,
 			expectedRoute: []cloudprovider.Route{
 				{
 					Name:            "name",
@@ -462,25 +467,24 @@ func TestProcessRoutes(t *testing.T) {
 			name: "one route",
 		},
 		{
-			rt: network.RouteTable{
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-					Routes: &[]network.Route{
+			rt: &armnetwork.RouteTable{
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: []*armnetwork.Route{
 						{
 							Name: ptr.To("name"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("1.2.3.4/16"),
 							},
 						},
 						{
 							Name: ptr.To("name2"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("5.6.7.8/16"),
 							},
 						},
 					},
 				},
 			},
-			exists: true,
 			expectedRoute: []cloudprovider.Route{
 				{
 					Name:            "name",
@@ -497,7 +501,7 @@ func TestProcessRoutes(t *testing.T) {
 		},
 	}
 	for _, test := range tests {
-		routes, err := processRoutes(false, test.rt, test.exists, test.err)
+		routes, err := processRoutes(false, test.rt, test.err)
 		if test.expectErr {
 			if err == nil {
 				t.Errorf("%s: unexpected non-error", test.name)
@@ -590,12 +594,12 @@ func TestRouteNameFuncs(t *testing.T) {
 func TestListRoutes(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
-	routeTableClient := mockroutetableclient.NewMockInterface(ctrl)
 	mockVMSet := NewMockVMSet(ctrl)
 
+	mockRTRepo := routetable.NewMockRepository(ctrl)
 	cloud := &Cloud{
-		RouteTablesClient: routeTableClient,
-		VMSet:             mockVMSet,
+		routeTableRepo: mockRTRepo,
+		VMSet:          mockVMSet,
 		Config: Config{
 			RouteTableResourceGroup: "foo",
 			RouteTableName:          "bar",
@@ -604,34 +608,32 @@ func TestListRoutes(t *testing.T) {
 		unmanagedNodes:     utilsets.NewString(),
 		nodeInformerSynced: func() bool { return true },
 	}
-	cache, _ := cloud.newRouteTableCache()
-	cloud.rtCache = cache
 	cloud.routeUpdater = newDelayedRouteUpdater(cloud, 100*time.Millisecond)
 	go cloud.routeUpdater.run(context.Background())
 
 	testCases := []struct {
 		name                  string
 		routeTableName        string
-		routeTable            network.RouteTable
+		routeTable            *armnetwork.RouteTable
 		hasUnmanagedNodes     bool
 		nodeInformerNotSynced bool
 		unmanagedNodeName     string
 		routeCIDRs            map[string]string
 		expectedRoutes        []*cloudprovider.Route
-		getErr                *retry.Error
+		getErr                error
 		expectedErrMsg        error
 	}{
 		{
 			name:           "ListRoutes should return correct routes",
 			routeTableName: "rt1",
-			routeTable: network.RouteTable{
+			routeTable: &armnetwork.RouteTable{
 				Name:     ptr.To("rt1"),
 				Location: &cloud.Location,
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-					Routes: &[]network.Route{
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: []*armnetwork.Route{
 						{
 							Name: ptr.To("node"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("1.2.3.4/24"),
 							},
 						},
@@ -652,14 +654,14 @@ func TestListRoutes(t *testing.T) {
 			hasUnmanagedNodes: true,
 			unmanagedNodeName: "unmanaged-node",
 			routeCIDRs:        map[string]string{"unmanaged-node": "2.2.3.4/24"},
-			routeTable: network.RouteTable{
+			routeTable: &armnetwork.RouteTable{
 				Name:     ptr.To("rt2"),
 				Location: &cloud.Location,
-				RouteTablePropertiesFormat: &network.RouteTablePropertiesFormat{
-					Routes: &[]network.Route{
+				Properties: &armnetwork.RouteTablePropertiesFormat{
+					Routes: []*armnetwork.Route{
 						{
 							Name: ptr.To("node"),
-							RoutePropertiesFormat: &network.RoutePropertiesFormat{
+							Properties: &armnetwork.RoutePropertiesFormat{
 								AddressPrefix: ptr.To("1.2.3.4/24"),
 							},
 						},
@@ -682,28 +684,22 @@ func TestListRoutes(t *testing.T) {
 		{
 			name:           "ListRoutes should return nil if routeTable don't exist",
 			routeTableName: "rt3",
-			routeTable:     network.RouteTable{},
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusNotFound,
-				RawError:       cloudprovider.InstanceNotFound,
-			},
+			routeTable:     &armnetwork.RouteTable{},
+			getErr:         errors.New("dummy"),
 			expectedRoutes: []*cloudprovider.Route{},
 		},
 		{
 			name:           "ListRoutes should report error if error occurs when invoke routeTableClient.Get",
 			routeTableName: "rt4",
-			routeTable:     network.RouteTable{},
-			getErr: &retry.Error{
-				HTTPStatusCode: http.StatusInternalServerError,
-				RawError:       fmt.Errorf("Get error"),
-			},
-			expectedErrMsg: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 500, RawError: Get error"),
+			routeTable:     &armnetwork.RouteTable{},
+			getErr:         errors.New("dummy"),
+			expectedErrMsg: errors.New("dummy"),
 		},
 		{
 			name:                  "ListRoutes should report error if node informer is not synced",
 			routeTableName:        "rt5",
 			nodeInformerNotSynced: true,
-			routeTable:            network.RouteTable{},
+			routeTable:            &armnetwork.RouteTable{},
 			expectedErrMsg:        fmt.Errorf("node informer is not synced when trying to GetUnmanagedNodes"),
 		},
 	}
@@ -724,11 +720,16 @@ func TestListRoutes(t *testing.T) {
 		}
 
 		cloud.RouteTableName = test.routeTableName
-		routeTableClient.EXPECT().Get(gomock.Any(), cloud.RouteTableResourceGroup, test.routeTableName, "").Return(test.routeTable, test.getErr)
+		mockRTRepo.EXPECT().Get(gomock.Any(), test.routeTableName, gomock.Any()).Return(test.routeTable, test.getErr)
 
 		routes, err := cloud.ListRoutes(context.TODO(), "cluster")
-		assert.Equal(t, test.expectedRoutes, routes, test.name)
+		if len(test.expectedRoutes) == 0 {
+			assert.Empty(t, routes, test.name)
+		} else {
+			assert.Equal(t, test.expectedRoutes, routes, test.name)
+		}
 		if test.expectedErrMsg != nil {
+			assert.Error(t, err)
 			assert.EqualError(t, test.expectedErrMsg, err.Error(), test.name)
 		}
 	}
@@ -740,17 +741,17 @@ func TestCleanupOutdatedRoutes(t *testing.T) {
 
 	for _, testCase := range []struct {
 		description                          string
-		existingRoutes, expectedRoutes       []network.Route
+		existingRoutes, expectedRoutes       []*armnetwork.Route
 		existingNodeNames                    *utilsets.IgnoreCaseSet
 		expectedChanged, enableIPV6DualStack bool
 	}{
 		{
 			description: "cleanupOutdatedRoutes should delete outdated non-dualstack routes when dualstack is enabled",
-			existingRoutes: []network.Route{
+			existingRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
-			expectedRoutes: []network.Route{
+			expectedRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 			},
 			existingNodeNames:   utilsets.NewString("aks-node1-vmss000000"),
@@ -759,11 +760,11 @@ func TestCleanupOutdatedRoutes(t *testing.T) {
 		},
 		{
 			description: "cleanupOutdatedRoutes should delete outdated dualstack routes when dualstack is disabled",
-			existingRoutes: []network.Route{
+			existingRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
-			expectedRoutes: []network.Route{
+			expectedRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
 			existingNodeNames: utilsets.NewString("aks-node1-vmss000000"),
@@ -771,11 +772,11 @@ func TestCleanupOutdatedRoutes(t *testing.T) {
 		},
 		{
 			description: "cleanupOutdatedRoutes should not delete unmanaged routes when dualstack is enabled",
-			existingRoutes: []network.Route{
+			existingRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
-			expectedRoutes: []network.Route{
+			expectedRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
@@ -784,11 +785,11 @@ func TestCleanupOutdatedRoutes(t *testing.T) {
 		},
 		{
 			description: "cleanupOutdatedRoutes should not delete unmanaged routes when dualstack is disabled",
-			existingRoutes: []network.Route{
+			existingRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
-			expectedRoutes: []network.Route{
+			expectedRoutes: []*armnetwork.Route{
 				{Name: ptr.To("aks-node1-vmss000000____xxx")},
 				{Name: ptr.To("aks-node1-vmss000000")},
 			},
@@ -823,13 +824,13 @@ func TestEnsureRouteTableTagged(t *testing.T) {
 		"a": ptr.To("b"),
 		"c": ptr.To("d"),
 	}
-	rt := &network.RouteTable{}
+	rt := &armnetwork.RouteTable{}
 	tags, changed := cloud.ensureRouteTableTagged(rt)
 	assert.Equal(t, expectedTags, tags)
 	assert.True(t, changed)
 
 	cloud.RouteTableResourceGroup = "rg1"
-	rt = &network.RouteTable{}
+	rt = &armnetwork.RouteTable{}
 	tags, changed = cloud.ensureRouteTableTagged(rt)
 	assert.Nil(t, tags)
 	assert.False(t, changed)
diff --git a/pkg/provider/azure_routetable_repo_test.go b/pkg/provider/azure_routetable_repo_test.go
deleted file mode 100644
index 68737a969..000000000
--- a/pkg/provider/azure_routetable_repo_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package provider
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-	"testing"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2022-07-01/network"
-	"github.com/stretchr/testify/assert"
-
-	"go.uber.org/mock/gomock"
-
-	"k8s.io/utils/ptr"
-
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/routetableclient/mockroutetableclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
-	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
-	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
-)
-
-func TestCreateOrUpdateRouteTable(t *testing.T) {
-	ctrl := gomock.NewController(t)
-	defer ctrl.Finish()
-
-	tests := []struct {
-		clientErr   *retry.Error
-		expectedErr error
-	}{
-		{
-			clientErr:   &retry.Error{HTTPStatusCode: http.StatusPreconditionFailed},
-			expectedErr: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 412, RawError: %w", error(nil)),
-		},
-		{
-			clientErr:   &retry.Error{RawError: fmt.Errorf(consts.OperationCanceledErrorMessage)},
-			expectedErr: fmt.Errorf("Retriable: false, RetryAfter: 0s, HTTPStatusCode: 0, RawError: %w", fmt.Errorf("canceledandsupersededduetoanotheroperation")),
-		},
-	}
-
-	for _, test := range tests {
-		az := GetTestCloud(ctrl)
-		az.rtCache.Set("rt", "test")
-
-		mockRTClient := az.RouteTablesClient.(*mockroutetableclient.MockInterface)
-		mockRTClient.EXPECT().CreateOrUpdate(gomock.Any(), az.ResourceGroup, gomock.Any(), gomock.Any(), gomock.Any()).Return(test.clientErr)
-		mockRTClient.EXPECT().Get(gomock.Any(), az.ResourceGroup, "rt", gomock.Any()).Return(network.RouteTable{}, nil)
-
-		err := az.CreateOrUpdateRouteTable(network.RouteTable{
-			Name: ptr.To("rt"),
-			Etag: ptr.To("etag"),
-		})
-		assert.EqualError(t, test.expectedErr, err.Error())
-
-		// route table should be removed from cache if the etag is mismatch or the operation is canceled
-		shouldBeEmpty, err := az.rtCache.GetWithDeepCopy(context.TODO(), "rt", cache.CacheReadTypeDefault)
-		assert.NoError(t, err)
-		assert.Empty(t, shouldBeEmpty)
-	}
-}
diff --git a/pkg/provider/azure_utils_test.go b/pkg/provider/azure_utils_test.go
index 2705f7399..7d1ae10ff 100644
--- a/pkg/provider/azure_utils_test.go
+++ b/pkg/provider/azure_utils_test.go
@@ -873,12 +873,21 @@ func TestIsFIPIPv6(t *testing.T) {
 			},
 			expectedIsIPv6: true,
 		},
+		{
+			desc: "enpty ip families",
+			svc: v1.Service{
+				Spec: v1.ServiceSpec{
+					IPFamilies: []v1.IPFamily{},
+				},
+			},
+			expectedIsIPv6: false,
+		},
 	}
 	for _, tc := range testcases {
 		tc := tc
 		t.Run(tc.desc, func(t *testing.T) {
 			az := GetTestCloud(ctrl)
-			isIPv6, err := az.isFIPIPv6(&tc.svc, "rg", tc.fip)
+			isIPv6, err := az.isFIPIPv6(&tc.svc, tc.fip)
 			assert.Nil(t, err)
 			assert.Equal(t, tc.expectedIsIPv6, isIPv6)
 		})
diff --git a/pkg/provider/privatelinkservice/repo_test.go b/pkg/provider/privatelinkservice/repo_test.go
index b6b8bee9c..4d881f218 100644
--- a/pkg/provider/privatelinkservice/repo_test.go
+++ b/pkg/provider/privatelinkservice/repo_test.go
@@ -33,7 +33,9 @@ import (
 )
 
 func TestRepo_Get(t *testing.T) {
+	t.Parallel()
 	t.Run("refresh cache", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -69,6 +71,7 @@ func TestRepo_Get(t *testing.T) {
 	})
 
 	t.Run("refresh cache with not found", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -89,6 +92,7 @@ func TestRepo_Get(t *testing.T) {
 	})
 
 	t.Run("API error", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -112,7 +116,9 @@ func TestRepo_Get(t *testing.T) {
 }
 
 func TestRepo_CreateOrUpdate(t *testing.T) {
+	t.Parallel()
 	t.Run("create one", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -148,6 +154,7 @@ func TestRepo_CreateOrUpdate(t *testing.T) {
 	})
 
 	t.Run("create one with missing PLS name", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -165,6 +172,7 @@ func TestRepo_CreateOrUpdate(t *testing.T) {
 	})
 
 	t.Run("create one with missing LoadBalancerFrontendIPConfigurations", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -185,6 +193,7 @@ func TestRepo_CreateOrUpdate(t *testing.T) {
 	})
 
 	t.Run("should clear cache", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -242,7 +251,9 @@ func TestRepo_CreateOrUpdate(t *testing.T) {
 }
 
 func TestRepo_Delete(t *testing.T) {
+	t.Parallel()
 	t.Run("delete one", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -263,6 +274,7 @@ func TestRepo_Delete(t *testing.T) {
 	})
 
 	t.Run("API error", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -286,7 +298,9 @@ func TestRepo_Delete(t *testing.T) {
 }
 
 func TestRepo_DeletePEConnection(t *testing.T) {
+	t.Parallel()
 	t.Run("delete one", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
@@ -307,6 +321,7 @@ func TestRepo_DeletePEConnection(t *testing.T) {
 	})
 
 	t.Run("API error", func(t *testing.T) {
+		t.Parallel()
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		cli := mock_privatelinkserviceclient.NewMockInterface(ctrl)
diff --git a/pkg/provider/routetable/repo_test.go b/pkg/provider/routetable/repo_test.go
new file mode 100644
index 000000000..ac6fe1648
--- /dev/null
+++ b/pkg/provider/routetable/repo_test.go
@@ -0,0 +1,196 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package routetable
+
+import (
+	"context"
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
+	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
+	"github.com/stretchr/testify/assert"
+	"go.uber.org/mock/gomock"
+	"k8s.io/utils/ptr"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/routetableclient/mock_routetableclient"
+	"sigs.k8s.io/cloud-provider-azure/pkg/cache"
+)
+
+func TestRepo_Get(t *testing.T) {
+	t.Parallel()
+
+	const ResourceGroup = "testing-rg"
+
+	t.Run("refresh cache", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		cli.EXPECT().Get(gomock.Any(), ResourceGroup, gomock.Any()).Return(&armnetwork.RouteTable{
+			Name: ptr.To(RouteTableName),
+		}, nil)
+
+		v, err := repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+
+		// cache hit
+		v, err = repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+	})
+
+	t.Run("refresh cache with not found", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		cli.EXPECT().Get(gomock.Any(), ResourceGroup, gomock.Any()).Return(nil, nil)
+
+		v, err := repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Nil(t, v)
+	})
+
+	t.Run("API error", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		expectedErr := fmt.Errorf("API error")
+		cli.EXPECT().Get(gomock.Any(), ResourceGroup, gomock.Any()).Return(nil, expectedErr)
+
+		_, err = repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, expectedErr)
+	})
+}
+
+func TestRepo_CreateOrUpdate(t *testing.T) {
+	t.Parallel()
+
+	const ResourceGroup = "testing-rg"
+
+	t.Run("create one", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		cli.EXPECT().CreateOrUpdate(gomock.Any(), ResourceGroup, RouteTableName, armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}).Return(&armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}, nil).Times(1)
+
+		v, err := repo.CreateOrUpdate(ctx, armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		})
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+	})
+
+	t.Run("create one with missing RouteTable name", func(t *testing.T) {
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		_, err = repo.CreateOrUpdate(ctx, armnetwork.RouteTable{})
+		assert.Error(t, err)
+		assert.ErrorIs(t, err, ErrMissingRouteTableName)
+	})
+
+	t.Run("should clear cache", func(t *testing.T) {
+
+		t.Parallel()
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+		cli := mock_routetableclient.NewMockInterface(ctrl)
+		repo, err := NewRepo(cli, ResourceGroup, 60*time.Second, false)
+		assert.NoError(t, err)
+		ctx := context.Background()
+
+		const (
+			RouteTableName = "route-table-name"
+		)
+
+		cli.EXPECT().Get(gomock.Any(), ResourceGroup, RouteTableName).Return(&armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}, nil).Times(2)
+
+		cli.EXPECT().CreateOrUpdate(gomock.Any(), ResourceGroup, RouteTableName, armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}).Return(&armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		}, nil).Times(1)
+
+		v, err := repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+
+		v, err = repo.CreateOrUpdate(ctx, armnetwork.RouteTable{
+			Name: to.Ptr(RouteTableName),
+		})
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+
+		v, err = repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+
+		v, err = repo.Get(ctx, RouteTableName, cache.CacheReadTypeDefault)
+		assert.NoError(t, err)
+		assert.Equal(t, RouteTableName, *v.Name)
+	})
+}