Repository: spidernet-io/spiderpool
Pull request #1336 (2023-02-17 10:18:38)

Refactor webhook
Signed-off-by: iiiceoo <ziqian.xue@daocloud.io>

codecov[bot]: # [Codecov](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) Report
> Merging [#1336](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (0da6c02) into [main](https://codecov.io/gh/spidernet-io/spiderpool/commit/15be784c19efb6b8f2c89ae80bb54a82f496dd70?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (15be784) will **decrease** coverage by `0.18%`.
> The diff coverage is `98.11%`.

[![Impacted file tree graph](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336/graphs/tree.svg?width=650&height=150&src=pr&token=YKXY2E4Q8G&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io)](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io)

```diff
@@            Coverage Diff             @@
##             main    #1336      +/-   ##
==========================================
- Coverage   53.13%   52.96%   -0.18%     
==========================================
  Files          44       44              
  Lines        4411     4395      -16     
==========================================
- Hits         2344     2328      -16     
  Misses       2043     2043              
  Partials       24       24              
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `52.96% <98.11%> (-0.18%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) | Coverage Δ | |
|---|---|---|
| [pkg/ippoolmanager/ippool\_subnet\_validate.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL2lwcG9vbG1hbmFnZXIvaXBwb29sX3N1Ym5ldF92YWxpZGF0ZS5nbw==) | `90.47% <ø> (-0.44%)` | :arrow_down: |
| [pkg/ippoolmanager/ippool\_validate.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL2lwcG9vbG1hbmFnZXIvaXBwb29sX3ZhbGlkYXRlLmdv) | `96.17% <90.90%> (-0.02%)` | :arrow_down: |
| [pkg/ippoolmanager/ippool\_mutate.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL2lwcG9vbG1hbmFnZXIvaXBwb29sX211dGF0ZS5nbw==) | `100.00% <100.00%> (ø)` | |
| [pkg/reservedipmanager/reservedip\_validate.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL3Jlc2VydmVkaXBtYW5hZ2VyL3Jlc2VydmVkaXBfdmFsaWRhdGUuZ28=) | `100.00% <100.00%> (ø)` | |
| [pkg/subnetmanager/subnet\_mutate.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL3N1Ym5ldG1hbmFnZXIvc3VibmV0X211dGF0ZS5nbw==) | `100.00% <100.00%> (ø)` | |
| [pkg/subnetmanager/subnet\_validate.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1336?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL3N1Ym5ldG1hbmFnZXIvc3VibmV0X3ZhbGlkYXRlLmdv) | `100.00% <100.00%> (ø)` | |

sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=spidernet-io_spiderpool&pullRequest=1336)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=SECURITY_HOTSPOT) [![E](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/E-16px.png 'E')](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=SECURITY_HOTSPOT) [18 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=CODE_SMELL) [9 Code Smells](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1336) No Coverage information  
[![12.9%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/20-16px.png '12.9%')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1336&metric=new_duplicated_lines_density&view=list) [12.9% Duplication](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1336&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=spidernet-io_spiderpool&pullRequest=1336)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=SECURITY_HOTSPOT) [![E](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/E-16px.png 'E')](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=SECURITY_HOTSPOT) [18 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=CODE_SMELL) [6 Code Smells](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1336&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1336) No Coverage information  
[![12.6%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/20-16px.png '12.6%')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1336&metric=new_duplicated_lines_density&view=list) [12.6% Duplication](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1336&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/charts/spiderpool/crds/spiderpool.spidernet.io_spidersubnets.yaml b/charts/spiderpool/crds/spiderpool.spidernet.io_spidersubnets.yaml
index 5690d9ae5..68de22682 100644
--- a/charts/spiderpool/crds/spiderpool.spidernet.io_spidersubnets.yaml
+++ b/charts/spiderpool/crds/spiderpool.spidernet.io_spidersubnets.yaml
@@ -71,7 +71,6 @@ spec:
               ips:
                 items:
                   type: string
-                minItems: 1
                 type: array
               routes:
                 items:
@@ -94,7 +93,6 @@ spec:
                 minimum: 0
                 type: integer
             required:
-            - ips
             - subnet
             type: object
           status:
diff --git a/pkg/constant/k8s.go b/pkg/constant/k8s.go
index 52aa32e65..2b6ddc3a5 100644
--- a/pkg/constant/k8s.go
+++ b/pkg/constant/k8s.go
@@ -72,10 +72,13 @@ const (
 	LabelIPPoolOwnerApplication    = AnnotationPre + "/owner-application"
 	LabelIPPoolOwnerApplicationUID = AnnotationPre + "/owner-application-uid"
 	LabelIPPoolVersion             = AnnotationPre + "/ippool-version"
-	LabelIPPoolReclaimIPPool       = AnnoSpiderSubnetReclaimIPPool
-	LabelIPPoolInterface           = AnnotationPre + "/interface"
 	LabelIPPoolVersionV4           = "IPv4"
 	LabelIPPoolVersionV6           = "IPv6"
+	LabelIPPoolReclaimIPPool       = AnnoSpiderSubnetReclaimIPPool
+	LabelIPPoolInterface           = AnnotationPre + "/interface"
+
+	LabelSubnetCIDR = AnnotationPre + "/subnet-cidr"
+	LabelIPPoolCIDR = AnnotationPre + "/ippool-cidr"
 )
 
 const (
diff --git a/pkg/ip/utils.go b/pkg/ip/utils.go
index 9bb659a04..773d1a30a 100644
--- a/pkg/ip/utils.go
+++ b/pkg/ip/utils.go
@@ -5,6 +5,7 @@ package ip
 
 import (
 	"net"
+	"strings"
 
 	"github.com/spidernet-io/spiderpool/pkg/types"
 )
@@ -22,3 +23,15 @@ func AssembleTotalIPs(ipVersion types.IPVersion, ipRanges, excludedIPRanges []st
 
 	return totalIPs, nil
 }
+
+func CIDRToLabelValue(ipVersion types.IPVersion, subnet string) (string, error) {
+	if err := IsCIDR(ipVersion, subnet); err != nil {
+		return "", err
+	}
+
+	value := strings.Replace(subnet, ".", "-", 3)
+	value = strings.Replace(value, ":", "-", 7)
+	value = strings.Replace(value, "/", "-", 1)
+
+	return value, nil
+}
diff --git a/pkg/ippoolmanager/ippool_mutate.go b/pkg/ippoolmanager/ippool_mutate.go
index a2cc2a71b..a12325d4e 100644
--- a/pkg/ippoolmanager/ippool_mutate.go
+++ b/pkg/ippoolmanager/ippool_mutate.go
@@ -5,12 +5,12 @@ package ippoolmanager
 
 import (
 	"context"
-	"errors"
 	"fmt"
 
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -29,12 +29,6 @@ func (iw *IPPoolWebhook) mutateIPPool(ctx context.Context, ipPool *spiderpoolv1.
 		return nil
 	}
 
-	if iw.EnableSpiderSubnet {
-		if err := iw.setControllerSubnet(ctx, ipPool); err != nil {
-			return apierrors.NewInternalError(fmt.Errorf("failed to set the reference of the controller Subnet: %v", err))
-		}
-	}
-
 	if !controllerutil.ContainsFinalizer(ipPool, constant.SpiderFinalizer) {
 		controllerutil.AddFinalizer(ipPool, constant.SpiderFinalizer)
 		logger.Sugar().Infof("Add finalizer %s", constant.SpiderFinalizer)
@@ -47,7 +41,7 @@ func (iw *IPPoolWebhook) mutateIPPool(ctx context.Context, ipPool *spiderpoolv1.
 		} else if spiderpoolip.IsIPv6CIDR(ipPool.Spec.Subnet) {
 			version = constant.IPv6
 		} else {
-			return errors.New("invalid 'spec.ipVersion', noting to mutate")
+			return fmt.Errorf("failed to generate 'spec.ipVersion' from 'spec.subnet' %s, nothing to mutate", ipPool.Spec.Subnet)
 		}
 
 		ipPool.Spec.IPVersion = new(types.IPVersion)
@@ -55,6 +49,25 @@ func (iw *IPPoolWebhook) mutateIPPool(ctx context.Context, ipPool *spiderpoolv1.
 		logger.Sugar().Infof("Set 'spec.ipVersion' to %d", version)
 	}
 
+	cidr, err := spiderpoolip.CIDRToLabelValue(*ipPool.Spec.IPVersion, ipPool.Spec.Subnet)
+	if err != nil {
+		return fmt.Errorf("failed to parse 'spec.subnet' %s as a valid label value: %v", ipPool.Spec.Subnet, err)
+	}
+
+	if v, ok := ipPool.Labels[constant.LabelIPPoolCIDR]; !ok || v != cidr {
+		if ipPool.Labels == nil {
+			ipPool.Labels = make(map[string]string)
+		}
+		ipPool.Labels[constant.LabelIPPoolCIDR] = cidr
+		logger.Sugar().Infof("Set label %s: %s", constant.LabelIPPoolCIDR, cidr)
+	}
+
+	if iw.EnableSpiderSubnet {
+		if err := iw.setControllerSubnet(ctx, ipPool); err != nil {
+			return apierrors.NewInternalError(fmt.Errorf("failed to set the reference of the controller Subnet: %v", err))
+		}
+	}
+
 	if len(ipPool.Spec.IPs) > 1 {
 		mergedIPs, err := spiderpoolip.MergeIPRanges(*ipPool.Spec.IPVersion, ipPool.Spec.IPs)
 		if err != nil {
@@ -87,29 +100,35 @@ func (iw *IPPoolWebhook) setControllerSubnet(ctx context.Context, ipPool *spider
 		return nil
 	}
 
+	cidr, err := spiderpoolip.CIDRToLabelValue(*ipPool.Spec.IPVersion, ipPool.Spec.Subnet)
+	if err != nil {
+		return fmt.Errorf("failed to parse CIDR %s as a valid label value: %v", ipPool.Spec.Subnet, err)
+	}
+
 	var subnetList spiderpoolv1.SpiderSubnetList
-	if err := iw.Client.List(ctx, &subnetList); err != nil {
+	if err := iw.Client.List(
+		ctx,
+		&subnetList,
+		client.MatchingLabels{constant.LabelSubnetCIDR: cidr},
+	); err != nil {
 		return fmt.Errorf("failed to list Subnets: %v", err)
 	}
 
-	for _, subnet := range subnetList.Items {
-		if subnet.Spec.Subnet == ipPool.Spec.Subnet {
-			if !metav1.IsControlledBy(ipPool, &subnet) {
-				if err := ctrl.SetControllerReference(&subnet, ipPool, iw.Scheme); err != nil {
-					return fmt.Errorf("failed to set owner reference: %v", err)
-				}
-				logger.Sugar().Infof("Set owner reference as Subnet %s", subnet.Name)
-			}
-
-			if ipPool.Labels == nil {
-				ipPool.Labels = make(map[string]string)
-			}
-			if v, ok := ipPool.Labels[constant.LabelIPPoolOwnerSpiderSubnet]; !ok || v != subnet.Name {
-				ipPool.Labels[constant.LabelIPPoolOwnerSpiderSubnet] = subnet.Name
-				logger.Sugar().Infof("Set label %s: %s", constant.LabelIPPoolOwnerSpiderSubnet, subnet.Name)
-			}
-			break
+	if len(subnetList.Items) == 0 {
+		return nil
+	}
+
+	subnet := subnetList.Items[0]
+	if !metav1.IsControlledBy(ipPool, &subnet) {
+		if err := ctrl.SetControllerReference(&subnet, ipPool, iw.Scheme); err != nil {
+			return fmt.Errorf("failed to set owner reference: %v", err)
 		}
+		logger.Sugar().Infof("Set owner reference as Subnet %s", subnet.Name)
+	}
+
+	if v, ok := ipPool.Labels[constant.LabelIPPoolOwnerSpiderSubnet]; !ok || v != subnet.Name {
+		ipPool.Labels[constant.LabelIPPoolOwnerSpiderSubnet] = subnet.Name
+		logger.Sugar().Infof("Set label %s: %s", constant.LabelIPPoolOwnerSpiderSubnet, subnet.Name)
 	}
 
 	return nil
diff --git a/pkg/ippoolmanager/ippool_subnet_validate.go b/pkg/ippoolmanager/ippool_subnet_validate.go
index 424bf18a5..5c661d0e4 100644
--- a/pkg/ippoolmanager/ippool_subnet_validate.go
+++ b/pkg/ippoolmanager/ippool_subnet_validate.go
@@ -66,10 +66,6 @@ func (iw *IPPoolWebhook) validateSubnetControllerExist(ctx context.Context, ipPo
 		return nil, field.InternalError(subnetField, fmt.Errorf("failed to get controller Subnet %s: %v", owner.Name, err))
 	}
 
-	if subnet.Spec.Subnet != ipPool.Spec.Subnet {
-		return nil, field.InternalError(subnetField, fmt.Errorf("invalid controller Subnet %s with different 'spec.subnet' %s", owner.Name, subnet.Spec.Subnet))
-	}
-
 	if subnet.DeletionTimestamp != nil {
 		return nil, field.Forbidden(
 			subnetField,
diff --git a/pkg/ippoolmanager/ippool_validate.go b/pkg/ippoolmanager/ippool_validate.go
index df6624781..084322efa 100644
--- a/pkg/ippoolmanager/ippool_validate.go
+++ b/pkg/ippoolmanager/ippool_validate.go
@@ -9,6 +9,7 @@ import (
 	"strconv"
 
 	"k8s.io/apimachinery/pkg/util/validation/field"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
 	spiderpoolip "github.com/spidernet-io/spiderpool/pkg/ip"
@@ -30,7 +31,7 @@ func (iw *IPPoolWebhook) validateCreateIPPool(ctx context.Context, ipPool *spide
 		return field.ErrorList{err}
 	}
 
-	if err := iw.validateIPPoolSubnet(ctx, ipPool); err != nil {
+	if err := iw.validateIPPoolCIDR(ctx, ipPool); err != nil {
 		return field.ErrorList{err}
 	}
 
@@ -160,7 +161,7 @@ func (iw *IPPoolWebhook) validateIPPoolIPVersion(version *types.IPVersion) *fiel
 	return nil
 }
 
-func (iw *IPPoolWebhook) validateIPPoolSubnet(ctx context.Context, ipPool *spiderpoolv1.SpiderIPPool) *field.Error {
+func (iw *IPPoolWebhook) validateIPPoolCIDR(ctx context.Context, ipPool *spiderpoolv1.SpiderIPPool) *field.Error {
 	if err := spiderpoolip.IsCIDR(*ipPool.Spec.IPVersion, ipPool.Spec.Subnet); err != nil {
 		return field.Invalid(
 			subnetField,
@@ -169,6 +170,11 @@ func (iw *IPPoolWebhook) validateIPPoolSubnet(ctx context.Context, ipPool *spide
 		)
 	}
 
+	if iw.EnableSpiderSubnet {
+		return nil
+	}
+
+	// TODO(iiiceoo): Use label selector.
 	var ipPoolList spiderpoolv1.SpiderIPPoolList
 	if err := iw.Client.List(ctx, &ipPoolList); err != nil {
 		return field.InternalError(subnetField, fmt.Errorf("failed to list IPPools: %v", err))
@@ -210,8 +216,18 @@ func (iw *IPPoolWebhook) validateIPPoolAvailableIPs(ctx context.Context, ipPool
 		return err
 	}
 
+	cidr, err := spiderpoolip.CIDRToLabelValue(*ipPool.Spec.IPVersion, ipPool.Spec.Subnet)
+	if err != nil {
+		return field.InternalError(ipsField, fmt.Errorf("failed to parse CIDR %s as a valid label value: %v", ipPool.Spec.Subnet, err))
+	}
+
+	// TODO(iiiceoo): The list in validateIPPoolCIDR should be reused.
 	var ipPoolList spiderpoolv1.SpiderIPPoolList
-	if err := iw.Client.List(ctx, &ipPoolList); err != nil {
+	if err := iw.Client.List(
+		ctx,
+		&ipPoolList,
+		client.MatchingLabels{constant.LabelIPPoolCIDR: cidr},
+	); err != nil {
 		return field.InternalError(ipsField, fmt.Errorf("failed to list IPPools: %v", err))
 	}
 
@@ -221,7 +237,7 @@ func (iw *IPPoolWebhook) validateIPPoolAvailableIPs(ctx context.Context, ipPool
 	}
 
 	for _, pool := range ipPoolList.Items {
-		if pool.Spec.Subnet == ipPool.Spec.Subnet && pool.Name != ipPool.Name {
+		if pool.Name != ipPool.Name {
 			existIPs, err := spiderpoolip.AssembleTotalIPs(*pool.Spec.IPVersion, pool.Spec.IPs, pool.Spec.ExcludeIPs)
 			if err != nil {
 				return field.InternalError(ipsField, fmt.Errorf("failed to assemble the total IP addresses of the existing IPPool %s: %v", pool.Name, err))
@@ -242,17 +258,6 @@ func (iw *IPPoolWebhook) validateIPPoolAvailableIPs(ctx context.Context, ipPool
 }
 
 func (iw *IPPoolWebhook) validateIPPoolIPs(version types.IPVersion, subnet string, ips []string) *field.Error {
-	if len(ips) == 0 {
-		if iw.EnableSpiderSubnet {
-			return nil
-		}
-
-		return field.Required(
-			ipsField,
-			"requires at least one item",
-		)
-	}
-
 	for i, r := range ips {
 		if err := ValidateContainsIPRange(ipsField.Index(i), version, subnet, r); err != nil {
 			return err
diff --git a/pkg/k8s/apis/spiderpool.spidernet.io/v1/spidersubnet_types.go b/pkg/k8s/apis/spiderpool.spidernet.io/v1/spidersubnet_types.go
index 035000e76..d96403acb 100644
--- a/pkg/k8s/apis/spiderpool.spidernet.io/v1/spidersubnet_types.go
+++ b/pkg/k8s/apis/spiderpool.spidernet.io/v1/spidersubnet_types.go
@@ -16,8 +16,7 @@ type SubnetSpec struct {
 	// +kubebuilder:validation:Required
 	Subnet string `json:"subnet"`
 
-	// +kubebuilder:validation:MinItems=1
-	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:Optional
 	IPs []string `json:"ips"`
 
 	// +kubebuilder:validation:Optional
diff --git a/pkg/reservedipmanager/reservedip_mutate.go b/pkg/reservedipmanager/reservedip_mutate.go
index 363010575..cc59435bf 100644
--- a/pkg/reservedipmanager/reservedip_mutate.go
+++ b/pkg/reservedipmanager/reservedip_mutate.go
@@ -35,7 +35,7 @@ func (rw *ReservedIPWebhook) mutateReservedIP(ctx context.Context, rIP *spiderpo
 		} else if spiderpoolip.IsIPv6IPRange(rIP.Spec.IPs[0]) {
 			version = constant.IPv6
 		} else {
-			return errors.New("invalid 'spec.ipVersion', noting to mutate")
+			return fmt.Errorf("failed to generate 'spec.ipVersion' from 'spec.ips[0]' %s, nothing to mutate", rIP.Spec.IPs[0])
 		}
 
 		rIP.Spec.IPVersion = new(types.IPVersion)
diff --git a/pkg/reservedipmanager/reservedip_validate.go b/pkg/reservedipmanager/reservedip_validate.go
index f046f0777..6ba4e5e19 100644
--- a/pkg/reservedipmanager/reservedip_validate.go
+++ b/pkg/reservedipmanager/reservedip_validate.go
@@ -5,7 +5,6 @@ package reservedipmanager
 
 import (
 	"context"
-	"fmt"
 	"strconv"
 
 	"k8s.io/apimachinery/pkg/util/validation/field"
@@ -72,7 +71,7 @@ func validateReservedIPShouldNotBeChanged(oldRIP, newRIP *spiderpoolv1.SpiderRes
 }
 
 func (rw *ReservedIPWebhook) validateReservedIPSpec(ctx context.Context, rIP *spiderpoolv1.SpiderReservedIP) *field.Error {
-	return rw.validateReservedIPAvailableIP(ctx, *rIP.Spec.IPVersion, rIP)
+	return rw.validateReservedIPs(ctx, *rIP.Spec.IPVersion, rIP.Spec.IPs)
 }
 
 func (rw *ReservedIPWebhook) validateReservedIPIPVersion(version *types.IPVersion) *field.Error {
@@ -112,38 +111,13 @@ func (rw *ReservedIPWebhook) validateReservedIPIPVersion(version *types.IPVersio
 	return nil
 }
 
-func (rw *ReservedIPWebhook) validateReservedIPAvailableIP(ctx context.Context, version types.IPVersion, rIP *spiderpoolv1.SpiderReservedIP) *field.Error {
-	if len(rIP.Spec.IPs) == 0 {
-		return nil
-	}
-
-	newReservedIPs, err := spiderpoolip.ParseIPRanges(version, rIP.Spec.IPs)
-	if err != nil {
-		return field.Invalid(
-			ipsField,
-			rIP.Spec.IPs,
-			err.Error(),
-		)
-	}
-
-	var rIPList spiderpoolv1.SpiderReservedIPList
-	if err := rw.List(ctx, &rIPList); err != nil {
-		return field.InternalError(ipsField, fmt.Errorf("failed to list ReservedIPs: %v", err))
-	}
-
-	for _, r := range rIPList.Items {
-		if r.Name == rIP.Name || *r.Spec.IPVersion != version {
-			continue
-		}
-
-		existReservedIPs, err := spiderpoolip.ParseIPRanges(version, r.Spec.IPs)
-		if err != nil {
-			return field.InternalError(ipsField, fmt.Errorf("failed to parse 'spec.ips':\n%v\n of the existing ReservedIP %s: %v", r.Spec.IPs, r.Name, err))
-		}
-		if len(spiderpoolip.IPsIntersectionSet(newReservedIPs, existReservedIPs)) > 0 {
-			return field.Forbidden(
-				ipsField,
-				fmt.Sprintf("overlaps with the existing ReservedIP %s", r.Name),
+func (rw *ReservedIPWebhook) validateReservedIPs(ctx context.Context, version types.IPVersion, ips []string) *field.Error {
+	for i, r := range ips {
+		if err := spiderpoolip.IsIPRange(version, r); err != nil {
+			return field.Invalid(
+				ipsField.Index(i),
+				ips[i],
+				err.Error(),
 			)
 		}
 	}
diff --git a/pkg/subnetmanager/subnet_mutate.go b/pkg/subnetmanager/subnet_mutate.go
index ec26ab629..c5decbac8 100644
--- a/pkg/subnetmanager/subnet_mutate.go
+++ b/pkg/subnetmanager/subnet_mutate.go
@@ -5,7 +5,6 @@ package subnetmanager
 
 import (
 	"context"
-	"errors"
 	"fmt"
 
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -38,7 +37,7 @@ func (sw *SubnetWebhook) mutateSubnet(ctx context.Context, subnet *spiderpoolv1.
 		} else if spiderpoolip.IsIPv6CIDR(subnet.Spec.Subnet) {
 			version = constant.IPv6
 		} else {
-			return errors.New("invalid 'spec.ipVersion', noting to mutate")
+			return fmt.Errorf("failed to generate 'spec.ipVersion' from 'spec.subnet' %s, nothing to mutate", subnet.Spec.Subnet)
 		}
 
 		subnet.Spec.IPVersion = new(types.IPVersion)
@@ -46,6 +45,19 @@ func (sw *SubnetWebhook) mutateSubnet(ctx context.Context, subnet *spiderpoolv1.
 		logger.Sugar().Infof("Set 'spec.ipVersion' to %d", version)
 	}
 
+	cidr, err := spiderpoolip.CIDRToLabelValue(*subnet.Spec.IPVersion, subnet.Spec.Subnet)
+	if err != nil {
+		return fmt.Errorf("failed to parse 'spec.subnet' %s as a valid label value: %v", subnet.Spec.Subnet, err)
+	}
+
+	if v, ok := subnet.Labels[constant.LabelSubnetCIDR]; !ok || v != cidr {
+		if subnet.Labels == nil {
+			subnet.Labels = make(map[string]string)
+		}
+		subnet.Labels[constant.LabelSubnetCIDR] = cidr
+		logger.Sugar().Infof("Set label %s: %s", constant.LabelSubnetCIDR, cidr)
+	}
+
 	if len(subnet.Spec.IPs) > 1 {
 		mergedIPs, err := spiderpoolip.MergeIPRanges(*subnet.Spec.IPVersion, subnet.Spec.IPs)
 		if err != nil {
diff --git a/pkg/subnetmanager/subnet_validate.go b/pkg/subnetmanager/subnet_validate.go
index 3d8012683..be4894ab3 100644
--- a/pkg/subnetmanager/subnet_validate.go
+++ b/pkg/subnetmanager/subnet_validate.go
@@ -32,7 +32,7 @@ func (sw *SubnetWebhook) validateCreateSubnet(ctx context.Context, subnet *spide
 		return field.ErrorList{err}
 	}
 
-	if err := sw.validateSubnetSubnet(ctx, subnet); err != nil {
+	if err := sw.validateSubnetCIDR(ctx, subnet); err != nil {
 		return field.ErrorList{err}
 	}
 
@@ -166,7 +166,7 @@ func (sw *SubnetWebhook) validateSubnetIPVersion(version *types.IPVersion) *fiel
 	return nil
 }
 
-func (sw *SubnetWebhook) validateSubnetSubnet(ctx context.Context, subnet *spiderpoolv1.SpiderSubnet) *field.Error {
+func (sw *SubnetWebhook) validateSubnetCIDR(ctx context.Context, subnet *spiderpoolv1.SpiderSubnet) *field.Error {
 	if err := spiderpoolip.IsCIDR(*subnet.Spec.IPVersion, subnet.Spec.Subnet); err != nil {
 		return field.Invalid(
 			subnetField,
@@ -175,6 +175,7 @@ func (sw *SubnetWebhook) validateSubnetSubnet(ctx context.Context, subnet *spide
 		)
 	}
 
+	// TODO(iiiceoo): Use label selector.
 	subnetList := spiderpoolv1.SpiderSubnetList{}
 	if err := sw.List(ctx, &subnetList); err != nil {
 		return field.InternalError(subnetField, fmt.Errorf("failed to list Subnets: %v", err))
@@ -205,13 +206,6 @@ func (sw *SubnetWebhook) validateSubnetSubnet(ctx context.Context, subnet *spide
 }
 
 func validateSubnetIPs(version types.IPVersion, subnet string, ips []string) *field.Error {
-	if len(ips) == 0 {
-		return field.Required(
-			ipsField,
-			"requires at least one item",
-		)
-	}
-
 	for i, r := range ips {
 		if err := ippoolmanager.ValidateContainsIPRange(ipsField.Index(i), version, subnet, r); err != nil {
 			return err


Test patch:
diff --git a/pkg/ip/utils_test.go b/pkg/ip/utils_test.go
index 6631300c1..afad9ef6d 100644
--- a/pkg/ip/utils_test.go
+++ b/pkg/ip/utils_test.go
@@ -65,4 +65,32 @@ var _ = Describe("IP utils", Label("ip_utils_test"), func() {
 			Expect(ips).To(Equal([]net.IP{net.ParseIP("abcd:1234::1")}))
 		})
 	})
+
+	Describe("Test CIDRToLabelValue", func() {
+		When("Verifying", func() {
+			It("inputs invalid IP version", func() {
+				cidr, err := spiderpoolip.CIDRToLabelValue(constant.InvalidIPVersion, "172.18.40.0/24")
+				Expect(err).To(MatchError(spiderpoolip.ErrInvalidIPVersion))
+				Expect(cidr).To(BeEmpty())
+			})
+
+			It("inputs invalid CIDR address", func() {
+				cidr, err := spiderpoolip.CIDRToLabelValue(constant.IPv4, constant.InvalidCIDR)
+				Expect(err).To(MatchError(spiderpoolip.ErrInvalidCIDRFormat))
+				Expect(cidr).To(BeEmpty())
+			})
+		})
+
+		It("parses IPv4 CIDR address", func() {
+			cidr, err := spiderpoolip.CIDRToLabelValue(constant.IPv4, "172.18.40.0/24")
+			Expect(err).NotTo(HaveOccurred())
+			Expect(cidr).To(Equal("172-18-40-0-24"))
+		})
+
+		It("parses IPv6 CIDR address", func() {
+			cidr, err := spiderpoolip.CIDRToLabelValue(constant.IPv6, "abcd:1234::/120")
+			Expect(err).NotTo(HaveOccurred())
+			Expect(cidr).To(Equal("abcd-1234---120"))
+		})
+	})
 })
diff --git a/pkg/ippoolmanager/ippool_webhook_test.go b/pkg/ippoolmanager/ippool_webhook_test.go
index a77a0c827..7bf02efbb 100644
--- a/pkg/ippoolmanager/ippool_webhook_test.go
+++ b/pkg/ippoolmanager/ippool_webhook_test.go
@@ -22,6 +22,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/manager"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
+	spiderpoolip "github.com/spidernet-io/spiderpool/pkg/ip"
 	"github.com/spidernet-io/spiderpool/pkg/ippoolmanager"
 	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
 	"github.com/spidernet-io/spiderpool/pkg/logutils"
@@ -63,7 +64,8 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersionV1),
 				},
 				ObjectMeta: metav1.ObjectMeta{
-					Name: subnetName,
+					Name:   subnetName,
+					Labels: map[string]string{},
 				},
 				Spec: spiderpoolv1.SubnetSpec{},
 			}
@@ -87,7 +89,8 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersionV1),
 				},
 				ObjectMeta: metav1.ObjectMeta{
-					Name: existIPPoolName,
+					Name:   existIPPoolName,
+					Labels: map[string]string{},
 				},
 				Spec: spiderpoolv1.IPPoolSpec{},
 			}
@@ -123,14 +126,74 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 				Expect(err).NotTo(HaveOccurred())
 			})
 
+			It("adds finalizer", func() {
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
+
+				ctx := context.TODO()
+				err := ipPoolWebhook.Default(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				contains := controllerutil.ContainsFinalizer(ipPoolT, constant.SpiderFinalizer)
+				Expect(contains).To(BeTrue())
+			})
+
+			It("failed to parse 'spec.subnet' as a valid label value", func() {
+				ipPoolT.Spec.IPVersion = pointer.Int64(constant.InvalidIPVersion)
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
+
+				ctx := context.TODO()
+				err := ipPoolWebhook.Default(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				v, ok := ipPoolT.Labels[constant.LabelIPPoolCIDR]
+				Expect(ok).To(BeFalse())
+				Expect(v).To(BeEmpty())
+			})
+
+			It("sets CIDR label", func() {
+				subnet := "172.18.40.0/24"
+				ipPoolT.Spec.Subnet = subnet
+
+				ctx := context.TODO()
+				err := ipPoolWebhook.Default(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				cidr, err := spiderpoolip.CIDRToLabelValue(*ipPoolT.Spec.IPVersion, subnet)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(cidr).NotTo(BeEmpty())
+
+				v, ok := ipPoolT.Labels[constant.LabelIPPoolCIDR]
+				Expect(ok).To(BeTrue())
+				Expect(v).To(Equal(cidr))
+			})
+
+			It("is orphan IPPool", func() {
+				ipPoolWebhook.EnableSpiderSubnet = true
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
+
+				ctx := context.TODO()
+				err := ipPoolWebhook.Default(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				owner := metav1.GetControllerOf(ipPoolT)
+				Expect(owner).To(BeNil())
+			})
+
 			It("failed to list Subnets due to some unknown errors", func() {
 				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
 				defer patches.Reset()
 
+				ipVersion := constant.IPv4
+				subnet := "172.18.40.0/24"
+				cidr, err := spiderpoolip.CIDRToLabelValue(ipVersion, subnet)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(cidr).NotTo(BeEmpty())
+
 				ipPoolWebhook.EnableSpiderSubnet = true
 				subnetT.SetUID(uuid.NewUUID())
-				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-				subnetT.Spec.Subnet = "172.18.40.0/24"
+				subnetT.Labels[constant.LabelSubnetCIDR] = cidr
+				subnetT.Spec.IPVersion = pointer.Int64(ipVersion)
+				subnetT.Spec.Subnet = subnet
 				subnetT.Spec.IPs = append(subnetT.Spec.IPs,
 					[]string{
 						"172.18.40.1-172.18.40.2",
@@ -139,12 +202,10 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 				)
 
 				ctx := context.TODO()
-				err := fakeClient.Create(ctx, subnetT)
+				err = fakeClient.Create(ctx, subnetT)
 				Expect(err).NotTo(HaveOccurred())
 
-				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-				ipPoolT.Spec.Subnet = "172.18.40.0/24"
-
+				ipPoolT.Spec.Subnet = subnet
 				err = ipPoolWebhook.Default(ctx, ipPoolT)
 				Expect(err).NotTo(HaveOccurred())
 
@@ -160,10 +221,17 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 				patches := gomonkey.ApplyFuncReturn(controllerutil.SetControllerReference, constant.ErrUnknown)
 				defer patches.Reset()
 
+				ipVersion := constant.IPv4
+				subnet := "172.18.40.0/24"
+				cidr, err := spiderpoolip.CIDRToLabelValue(ipVersion, subnet)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(cidr).NotTo(BeEmpty())
+
 				ipPoolWebhook.EnableSpiderSubnet = true
 				subnetT.SetUID(uuid.NewUUID())
-				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-				subnetT.Spec.Subnet = "172.18.40.0/24"
+				subnetT.Labels[constant.LabelSubnetCIDR] = cidr
+				subnetT.Spec.IPVersion = pointer.Int64(ipVersion)
+				subnetT.Spec.Subnet = subnet
 				subnetT.Spec.IPs = append(subnetT.Spec.IPs,
 					[]string{
 						"172.18.40.1-172.18.40.2",
@@ -172,12 +240,10 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 				)
 
 				ctx := context.TODO()
-				err := fakeClient.Create(ctx, subnetT)
+				err = fakeClient.Create(ctx, subnetT)
 				Expect(err).NotTo(HaveOccurred())
 
-				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-				ipPoolT.Spec.Subnet = "172.18.40.0/24"
-
+				ipPoolT.Spec.Subnet = subnet
 				err = ipPoolWebhook.Default(ctx, ipPoolT)
 				Expect(err).NotTo(HaveOccurred())
 
@@ -190,10 +256,17 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 			})
 
 			It("sets the reference of the controller Subnet", func() {
+				ipVersion := constant.IPv4
+				subnet := "172.18.50.0/24"
+				cidr, err := spiderpoolip.CIDRToLabelValue(ipVersion, subnet)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(cidr).NotTo(BeEmpty())
+
 				ipPoolWebhook.EnableSpiderSubnet = true
 				subnetT.SetUID(uuid.NewUUID())
-				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-				subnetT.Spec.Subnet = "172.18.50.0/24"
+				subnetT.Labels[constant.LabelSubnetCIDR] = cidr
+				subnetT.Spec.IPVersion = pointer.Int64(ipVersion)
+				subnetT.Spec.Subnet = subnet
 				subnetT.Spec.IPs = append(subnetT.Spec.IPs,
 					[]string{
 						"172.18.50.1-172.18.50.2",
@@ -202,22 +275,14 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 				)
 
 				ctx := context.TODO()
-				err := fakeClient.Create(ctx, subnetT)
+				err = fakeClient.Create(ctx, subnetT)
 				Expect(err).NotTo(HaveOccurred())
 
-				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-				ipPoolT.Spec.Subnet = "172.18.50.0/24"
-
+				ipPoolT.Spec.Subnet = subnet
 				err = ipPoolWebhook.Default(ctx, ipPoolT)
 				Expect(err).NotTo(HaveOccurred())
 
 				controlled := metav1.IsControlledBy(ipPoolT, subnetT)
-
-				// TODO(Icarus9913): maybe fail
-				ownerReference := metav1.GetControllerOf(ipPoolT)
-				fmt.Printf("The SpiderIPPool '%+v' corresponding owner reference: '%+v'", ipPoolT, ownerReference)
-				fmt.Printf("Print SpiderSubnet details: '%+v'", subnetT)
-
 				Expect(controlled).To(BeTrue())
 
 				v, ok := ipPoolT.Labels[constant.LabelIPPoolOwnerSpiderSubnet]
@@ -228,17 +293,6 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 				Expect(err).NotTo(HaveOccurred())
 			})
 
-			It("adds finalizer", func() {
-				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-
-				ctx := context.TODO()
-				err := ipPoolWebhook.Default(ctx, ipPoolT)
-				Expect(err).NotTo(HaveOccurred())
-
-				contains := controllerutil.ContainsFinalizer(ipPoolT, constant.SpiderFinalizer)
-				Expect(contains).To(BeTrue())
-			})
-
 			It("failed to set 'spec.ipVersion' due to the invalid 'spec.subnet'", func() {
 				ipPoolT.Spec.Subnet = constant.InvalidCIDR
 
@@ -268,6 +322,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 
 			It("failed to merge 'spec.ips' due to the invalid 'spec.ipVersion'", func() {
 				ipPoolT.Spec.IPVersion = pointer.Int64(constant.InvalidIPVersion)
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
 				ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
 					[]string{
 						"172.18.40.10",
@@ -290,6 +345,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 
 			It("failed to merge 'spec.ips' due to the invalid 'spec.ips'", func() {
 				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
 				ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
 					[]string{
 						constant.InvalidIPRange,
@@ -313,7 +369,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 			})
 
 			It("merges IPv4 'spec.ips'", func() {
-				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
 				ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
 					[]string{
 						"172.18.40.10",
@@ -334,7 +390,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 			})
 
 			It("merges IPv6 'spec.ips'", func() {
-				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv6)
+				ipPoolT.Spec.Subnet = "abcd:1234::/120"
 				ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
 					[]string{
 						"abcd:1234::a",
@@ -356,6 +412,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 
 			It("failed to merge 'spec.excludeIPs' due to the invalid 'spec.ipVersion'", func() {
 				ipPoolT.Spec.IPVersion = pointer.Int64(constant.InvalidIPVersion)
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
 				ipPoolT.Spec.ExcludeIPs = append(ipPoolT.Spec.ExcludeIPs,
 					[]string{
 						"172.18.40.10",
@@ -378,6 +435,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 
 			It("failed to merge 'spec.excludeIPs' due to the invalid 'spec.ips'", func() {
 				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
 				ipPoolT.Spec.ExcludeIPs = append(ipPoolT.Spec.ExcludeIPs,
 					[]string{
 						constant.InvalidIPRange,
@@ -401,7 +459,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 			})
 
 			It("merges IPv4 'spec.excludeIPs'", func() {
-				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				ipPoolT.Spec.Subnet = "172.18.40.0/24"
 				ipPoolT.Spec.ExcludeIPs = append(ipPoolT.Spec.ExcludeIPs,
 					[]string{
 						"172.18.40.10",
@@ -422,7 +480,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 			})
 
 			It("merges IPv6 'spec.excludeIPs'", func() {
-				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv6)
+				ipPoolT.Spec.Subnet = "abcd:1234::/120"
 				ipPoolT.Spec.ExcludeIPs = append(ipPoolT.Spec.ExcludeIPs,
 					[]string{
 						"abcd:1234::a",
@@ -622,40 +680,6 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 			})
 
 			When("Validating 'spec.ips'", func() {
-				It("inputs empty 'spec.ips' while feature SpiderSubnet is enabled", func() {
-					ipPoolWebhook.EnableSpiderSubnet = true
-					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					subnetT.Spec.Subnet = "172.18.40.0/24"
-					subnetT.Spec.IPs = append(subnetT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, subnetT)
-					Expect(err).NotTo(HaveOccurred())
-
-					err = controllerutil.SetControllerReference(subnetT, ipPoolT, scheme)
-					Expect(err).NotTo(HaveOccurred())
-
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/24"
-
-					err = ipPoolWebhook.ValidateCreate(ctx, ipPoolT)
-					Expect(err).NotTo(HaveOccurred())
-				})
-
-				It("inputs empty 'spec.ips'", func() {
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/24"
-
-					ctx := context.TODO()
-					err := ipPoolWebhook.ValidateCreate(ctx, ipPoolT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
 				It("inputs invalid 'spec.ips'", func() {
 					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
 					ipPoolT.Spec.Subnet = "172.18.40.0/24"
@@ -681,21 +705,24 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					Expect(apierrors.IsInvalid(err)).To(BeTrue())
 				})
 
-				PIt("failed to list IPPools due to some unknown errors", func() {})
-
-				PIt("failed to assemble the total IP addresses of the IPPool due to some unknown errors", func() {})
-
 				It("exists invalid IPPool in the cluster", func() {
-					existIPPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					existIPPoolT.Spec.Subnet = "172.18.40.0/24"
+					ipVersion := constant.IPv4
+					subnet := "172.18.40.0/24"
+					cidr, err := spiderpoolip.CIDRToLabelValue(ipVersion, subnet)
+					Expect(err).NotTo(HaveOccurred())
+					Expect(cidr).NotTo(BeEmpty())
+
+					existIPPoolT.Labels[constant.LabelIPPoolCIDR] = cidr
+					existIPPoolT.Spec.IPVersion = pointer.Int64(ipVersion)
+					existIPPoolT.Spec.Subnet = subnet
 					existIPPoolT.Spec.IPs = append(existIPPoolT.Spec.IPs, constant.InvalidIPRange)
 
 					ctx := context.TODO()
-					err := fakeClient.Create(ctx, existIPPoolT)
+					err = fakeClient.Create(ctx, existIPPoolT)
 					Expect(err).NotTo(HaveOccurred())
 
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/24"
+					ipPoolT.Spec.IPVersion = pointer.Int64(ipVersion)
+					ipPoolT.Spec.Subnet = subnet
 					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
 						[]string{
 							"172.18.40.1-172.18.40.2",
@@ -708,16 +735,23 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 				})
 
 				It("overlaps with existing IPPool", func() {
-					existIPPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					existIPPoolT.Spec.Subnet = "172.18.40.0/24"
+					ipVersion := constant.IPv4
+					subnet := "172.18.40.0/24"
+					cidr, err := spiderpoolip.CIDRToLabelValue(ipVersion, subnet)
+					Expect(err).NotTo(HaveOccurred())
+					Expect(cidr).NotTo(BeEmpty())
+
+					existIPPoolT.Labels[constant.LabelIPPoolCIDR] = cidr
+					existIPPoolT.Spec.IPVersion = pointer.Int64(ipVersion)
+					existIPPoolT.Spec.Subnet = subnet
 					existIPPoolT.Spec.IPs = append(existIPPoolT.Spec.IPs, "172.18.40.10")
 
 					ctx := context.TODO()
-					err := fakeClient.Create(ctx, existIPPoolT)
+					err = fakeClient.Create(ctx, existIPPoolT)
 					Expect(err).NotTo(HaveOccurred())
 
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/24"
+					ipPoolT.Spec.IPVersion = pointer.Int64(ipVersion)
+					ipPoolT.Spec.Subnet = subnet
 					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
 						[]string{
 							"172.18.40.1-172.18.40.2",
@@ -911,37 +945,6 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					Expect(apierrors.IsInvalid(err)).To(BeTrue())
 				})
 
-				It("sets owner reference to a Subnet with different 'spec.subnet'", func() {
-					subnetT.SetUID(uuid.NewUUID())
-					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					subnetT.Spec.Subnet = "172.18.40.0/24"
-					subnetT.Spec.IPs = append(subnetT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, subnetT)
-					Expect(err).NotTo(HaveOccurred())
-
-					err = controllerutil.SetControllerReference(subnetT, ipPoolT, scheme)
-					Expect(err).NotTo(HaveOccurred())
-
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/25"
-					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					err = ipPoolWebhook.ValidateCreate(ctx, ipPoolT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
 				It("sets owner reference to a terminating Subnet", func() {
 					controllerutil.AddFinalizer(subnetT, constant.SpiderFinalizer)
 					subnetT.SetUID(uuid.NewUUID())
@@ -983,10 +986,6 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					ipPoolWebhook.EnableSpiderSubnet = true
 				})
 
-				PIt("failed to assemble the total IP addresses of the IPPool due to some unknown errors", func() {})
-
-				PIt("failed to assemble the total IP addresses of the Subnet due to some unknown errors", func() {})
-
 				It("is out of the IP range of the Subnet", func() {
 					subnetT.SetUID(uuid.NewUUID())
 					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
@@ -1190,73 +1189,6 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 			})
 
 			When("Validating 'spec.ips'", func() {
-				It("removes all 'spec.ips' while feature SpiderSubnet is enabled", func() {
-					ipPoolWebhook.EnableSpiderSubnet = true
-					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					subnetT.Spec.Subnet = "172.18.40.0/24"
-					subnetT.Spec.IPs = append(subnetT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, subnetT)
-					Expect(err).NotTo(HaveOccurred())
-
-					err = controllerutil.SetControllerReference(subnetT, ipPoolT, scheme)
-					Expect(err).NotTo(HaveOccurred())
-
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/24"
-					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					newIPPoolT := ipPoolT.DeepCopy()
-					newIPPoolT.Spec.IPs = nil
-
-					err = ipPoolWebhook.ValidateUpdate(ctx, ipPoolT, newIPPoolT)
-					Expect(err).NotTo(HaveOccurred())
-				})
-
-				It("removes all 'spec.ips'", func() {
-					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					subnetT.Spec.Subnet = "172.18.40.0/24"
-					subnetT.Spec.IPs = append(subnetT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, subnetT)
-					Expect(err).NotTo(HaveOccurred())
-
-					err = controllerutil.SetControllerReference(subnetT, ipPoolT, scheme)
-					Expect(err).NotTo(HaveOccurred())
-
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/24"
-					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					newIPPoolT := ipPoolT.DeepCopy()
-					newIPPoolT.Spec.IPs = nil
-
-					err = ipPoolWebhook.ValidateUpdate(ctx, ipPoolT, newIPPoolT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
 				It("appends invalid IP range to 'spec.ips'", func() {
 					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
 					ipPoolT.Spec.Subnet = "172.18.40.0/24"
@@ -1288,21 +1220,24 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					Expect(apierrors.IsInvalid(err)).To(BeTrue())
 				})
 
-				PIt("failed to list IPPools due to some unknown errors", func() {})
-
-				PIt("failed to assemble the total IP addresses of the IPPool due to some unknown errors", func() {})
-
 				It("exists invalid IPPool in the cluster", func() {
-					existIPPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					existIPPoolT.Spec.Subnet = "172.18.40.0/24"
+					ipVersion := constant.IPv4
+					subnet := "172.18.40.0/24"
+					cidr, err := spiderpoolip.CIDRToLabelValue(ipVersion, subnet)
+					Expect(err).NotTo(HaveOccurred())
+					Expect(cidr).NotTo(BeEmpty())
+
+					existIPPoolT.Labels[constant.LabelIPPoolCIDR] = cidr
+					existIPPoolT.Spec.IPVersion = pointer.Int64(ipVersion)
+					existIPPoolT.Spec.Subnet = subnet
 					existIPPoolT.Spec.IPs = append(existIPPoolT.Spec.IPs, constant.InvalidIPRange)
 
 					ctx := context.TODO()
-					err := fakeClient.Create(ctx, existIPPoolT)
+					err = fakeClient.Create(ctx, existIPPoolT)
 					Expect(err).NotTo(HaveOccurred())
 
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/24"
+					ipPoolT.Spec.IPVersion = pointer.Int64(ipVersion)
+					ipPoolT.Spec.Subnet = subnet
 					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs, "172.18.40.1-172.18.40.2")
 
 					newIPPoolT := ipPoolT.DeepCopy()
@@ -1313,16 +1248,23 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 				})
 
 				It("overlaps with existing IPPool", func() {
-					existIPPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					existIPPoolT.Spec.Subnet = "172.18.40.0/24"
+					ipVersion := constant.IPv4
+					subnet := "172.18.40.0/24"
+					cidr, err := spiderpoolip.CIDRToLabelValue(ipVersion, subnet)
+					Expect(err).NotTo(HaveOccurred())
+					Expect(cidr).NotTo(BeEmpty())
+
+					existIPPoolT.Labels[constant.LabelIPPoolCIDR] = cidr
+					existIPPoolT.Spec.IPVersion = pointer.Int64(ipVersion)
+					existIPPoolT.Spec.Subnet = subnet
 					existIPPoolT.Spec.IPs = append(existIPPoolT.Spec.IPs, "172.18.40.10")
 
 					ctx := context.TODO()
-					err := fakeClient.Create(ctx, existIPPoolT)
+					err = fakeClient.Create(ctx, existIPPoolT)
 					Expect(err).NotTo(HaveOccurred())
 
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/24"
+					ipPoolT.Spec.IPVersion = pointer.Int64(ipVersion)
+					ipPoolT.Spec.Subnet = subnet
 					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs, "172.18.40.1-172.18.40.2")
 
 					newIPPoolT := ipPoolT.DeepCopy()
@@ -1483,8 +1425,6 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 			})
 
 			When("Validating the IP addresses being used", func() {
-				PIt("failed to assemble the total IP addresses of the IPPool due to some unknown errors", func() {})
-
 				It("removes IP range that is being used by IPPool", func() {
 					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
 					ipPoolT.Spec.Subnet = "172.18.40.0/24"
@@ -1552,35 +1492,6 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					Expect(apierrors.IsInvalid(err)).To(BeTrue())
 				})
 
-				It("updates the IPPool that sets the owner reference to a Subnet with different 'spec.subnet'", func() {
-					subnetT.SetUID(uuid.NewUUID())
-					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					subnetT.Spec.Subnet = "172.18.40.0/24"
-					subnetT.Spec.IPs = append(subnetT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, subnetT)
-					Expect(err).NotTo(HaveOccurred())
-
-					err = controllerutil.SetControllerReference(subnetT, ipPoolT, scheme)
-					Expect(err).NotTo(HaveOccurred())
-
-					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					ipPoolT.Spec.Subnet = "172.18.40.0/25"
-					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs, "172.18.40.1-172.18.40.2")
-
-					newIPPoolT := ipPoolT.DeepCopy()
-					newIPPoolT.Spec.IPs = append(newIPPoolT.Spec.IPs, "172.18.40.10")
-
-					err = ipPoolWebhook.ValidateUpdate(ctx, ipPoolT, newIPPoolT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
 				It("updates the IPPool that sets the owner reference to a terminating Subnet", func() {
 					controllerutil.AddFinalizer(subnetT, constant.SpiderFinalizer)
 					subnetT.SetUID(uuid.NewUUID())
@@ -1620,10 +1531,6 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					ipPoolWebhook.EnableSpiderSubnet = true
 				})
 
-				PIt("failed to assemble the total IP addresses of the IPPool due to some unknown errors", func() {})
-
-				PIt("failed to assemble the total IP addresses of the Subnet due to some unknown errors", func() {})
-
 				It("is out of the IP range of the Subnet", func() {
 					subnetT.SetUID(uuid.NewUUID())
 					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
diff --git a/pkg/reservedipmanager/reservedip_webhook_test.go b/pkg/reservedipmanager/reservedip_webhook_test.go
index 22cf9b01b..c09f43912 100644
--- a/pkg/reservedipmanager/reservedip_webhook_test.go
+++ b/pkg/reservedipmanager/reservedip_webhook_test.go
@@ -8,7 +8,6 @@ import (
 	"fmt"
 	"sync/atomic"
 
-	"github.com/agiledragon/gomonkey/v2"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -42,8 +41,8 @@ var _ = Describe("ReservedIPWebhook", Label("reservedip_webhook_test"), func() {
 
 	Describe("Test ReservedIPWebhook's method", func() {
 		var count uint64
-		var rIPName, existRIPName string
-		var rIPT, existRIPT *spiderpoolv1.SpiderReservedIP
+		var rIPName string
+		var rIPT *spiderpoolv1.SpiderReservedIP
 
 		BeforeEach(func() {
 			reservedipmanager.WebhookLogger = logutils.Logger.Named("ReservedIP-Webhook")
@@ -62,18 +61,6 @@ var _ = Describe("ReservedIPWebhook", Label("reservedip_webhook_test"), func() {
 				},
 				Spec: spiderpoolv1.ReservedIPSpec{},
 			}
-
-			existRIPName = fmt.Sprintf("z-exist-reservedip-%v", count)
-			existRIPT = &spiderpoolv1.SpiderReservedIP{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       constant.SpiderReservedIPKind,
-					APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersionV1),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name: existRIPName,
-				},
-				Spec: spiderpoolv1.ReservedIPSpec{},
-			}
 		})
 
 		var deleteOption *client.DeleteOptions
@@ -88,9 +75,6 @@ var _ = Describe("ReservedIPWebhook", Label("reservedip_webhook_test"), func() {
 			ctx := context.TODO()
 			err := fakeClient.Delete(ctx, rIPT, deleteOption)
 			Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
-
-			err = fakeClient.Delete(ctx, existRIPT, deleteOption)
-			Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
 		})
 
 		Describe("Default", func() {
@@ -261,14 +245,6 @@ var _ = Describe("ReservedIPWebhook", Label("reservedip_webhook_test"), func() {
 			})
 
 			When("Validating 'spec.ips'", func() {
-				It("inputs empty 'spec.ips'", func() {
-					rIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-
-					ctx := context.TODO()
-					err := rIPWebhook.ValidateCreate(ctx, rIPT)
-					Expect(err).NotTo(HaveOccurred())
-				})
-
 				It("inputs invalid 'spec.ips'", func() {
 					rIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
 					rIPT.Spec.IPs = append(rIPT.Spec.IPs, constant.InvalidIPRange)
@@ -277,63 +253,6 @@ var _ = Describe("ReservedIPWebhook", Label("reservedip_webhook_test"), func() {
 					err := rIPWebhook.ValidateCreate(ctx, rIPT)
 					Expect(apierrors.IsInvalid(err)).To(BeTrue())
 				})
-
-				It("failed to list ReservedIPs due to some unknown errors", func() {
-					patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
-					defer patches.Reset()
-
-					rIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					ctx := context.TODO()
-					err := rIPWebhook.ValidateCreate(ctx, rIPT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
-				It("exists invalid ReservedIPs in the cluster", func() {
-					existRIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					existRIPT.Spec.IPs = append(existRIPT.Spec.IPs, constant.InvalidIPRange)
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, existRIPT)
-					Expect(err).NotTo(HaveOccurred())
-
-					rIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					err = rIPWebhook.ValidateCreate(ctx, rIPT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
-				It("overlaps with existing ReservedIP", func() {
-					existRIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					existRIPT.Spec.IPs = append(existRIPT.Spec.IPs, "172.18.40.10")
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, existRIPT)
-					Expect(err).NotTo(HaveOccurred())
-
-					rIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					err = rIPWebhook.ValidateCreate(ctx, rIPT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
 			})
 
 			It("creates IPv4 ReservedIP with all fields valid", func() {
@@ -425,61 +344,6 @@ var _ = Describe("ReservedIPWebhook", Label("reservedip_webhook_test"), func() {
 					err := rIPWebhook.ValidateUpdate(ctx, rIPT, newRIPT)
 					Expect(apierrors.IsInvalid(err)).To(BeTrue())
 				})
-
-				It("failed to list ReservedIPs due to some unknown errors", func() {
-					patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
-					defer patches.Reset()
-
-					rIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs, "172.18.40.1-172.18.40.2")
-
-					newRIPT := rIPT.DeepCopy()
-					newRIPT.Spec.IPs = append(newRIPT.Spec.IPs, "172.18.40.10")
-
-					ctx := context.TODO()
-					err := rIPWebhook.ValidateUpdate(ctx, rIPT, newRIPT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
-				It("exists invalid ReservedIPs in the cluster", func() {
-					existRIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					existRIPT.Spec.IPs = append(existRIPT.Spec.IPs, constant.InvalidIPRange)
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, existRIPT)
-					Expect(err).NotTo(HaveOccurred())
-
-					rIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs, "172.18.40.1-172.18.40.2")
-					err = fakeClient.Create(ctx, rIPT)
-					Expect(err).NotTo(HaveOccurred())
-
-					newRIPT := rIPT.DeepCopy()
-					newRIPT.Spec.IPs = append(newRIPT.Spec.IPs, "172.18.40.10")
-
-					err = rIPWebhook.ValidateUpdate(ctx, rIPT, newRIPT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
-				It("overlaps with existing ReservedIP", func() {
-					existRIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					existRIPT.Spec.IPs = append(existRIPT.Spec.IPs, "172.18.40.10")
-
-					ctx := context.TODO()
-					err := fakeClient.Create(ctx, existRIPT)
-					Expect(err).NotTo(HaveOccurred())
-
-					rIPT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs, "172.18.40.1-172.18.40.2")
-					err = fakeClient.Create(ctx, rIPT)
-					Expect(err).NotTo(HaveOccurred())
-
-					newRIPT := rIPT.DeepCopy()
-					newRIPT.Spec.IPs = append(newRIPT.Spec.IPs, "172.18.40.10")
-
-					err = rIPWebhook.ValidateUpdate(ctx, rIPT, newRIPT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
 			})
 
 			It("deletes ReservedIP", func() {
diff --git a/pkg/subnetmanager/subnet_webhook_test.go b/pkg/subnetmanager/subnet_webhook_test.go
index 9d8c4a90b..6fe65fb45 100644
--- a/pkg/subnetmanager/subnet_webhook_test.go
+++ b/pkg/subnetmanager/subnet_webhook_test.go
@@ -106,7 +106,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 			})
 
 			It("adds finalizer", func() {
-				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				subnetT.Spec.Subnet = "172.18.40.0/24"
 
 				ctx := context.TODO()
 				err := subnetWebhook.Default(ctx, subnetT)
@@ -116,6 +116,36 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 				Expect(contains).To(BeTrue())
 			})
 
+			It("failed to parse 'spec.subnet' as a valid label value", func() {
+				subnetT.Spec.IPVersion = pointer.Int64(constant.InvalidIPVersion)
+				subnetT.Spec.Subnet = "172.18.40.0/24"
+
+				ctx := context.TODO()
+				err := subnetWebhook.Default(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				v, ok := subnetT.Labels[constant.LabelSubnetCIDR]
+				Expect(ok).To(BeFalse())
+				Expect(v).To(BeEmpty())
+			})
+
+			It("sets CIDR label", func() {
+				subnet := "172.18.40.0/24"
+				subnetT.Spec.Subnet = subnet
+
+				ctx := context.TODO()
+				err := subnetWebhook.Default(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				cidr, err := spiderpoolip.CIDRToLabelValue(*subnetT.Spec.IPVersion, subnet)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(cidr).NotTo(BeEmpty())
+
+				v, ok := subnetT.Labels[constant.LabelSubnetCIDR]
+				Expect(ok).To(BeTrue())
+				Expect(v).To(Equal(cidr))
+			})
+
 			It("failed to set 'spec.ipVersion' due to the invalid 'spec.subnet'", func() {
 				subnetT.Spec.Subnet = constant.InvalidCIDR
 
@@ -145,6 +175,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 
 			It("failed to merge 'spec.ips' due to the invalid 'spec.ipVersion'", func() {
 				subnetT.Spec.IPVersion = pointer.Int64(constant.InvalidIPVersion)
+				subnetT.Spec.Subnet = "172.18.40.0/24"
 				subnetT.Spec.IPs = append(subnetT.Spec.IPs,
 					[]string{
 						"172.18.40.10",
@@ -167,6 +198,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 
 			It("failed to merge 'spec.ips' due to the invalid 'spec.ips'", func() {
 				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				subnetT.Spec.Subnet = "172.18.40.0/24"
 				subnetT.Spec.IPs = append(subnetT.Spec.IPs,
 					[]string{
 						constant.InvalidIPRange,
@@ -190,7 +222,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 			})
 
 			It("merges IPv4 'spec.ips'", func() {
-				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				subnetT.Spec.Subnet = "172.18.40.0/24"
 				subnetT.Spec.IPs = append(subnetT.Spec.IPs,
 					[]string{
 						"172.18.40.10",
@@ -211,7 +243,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 			})
 
 			It("merges IPv6 'spec.ips'", func() {
-				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv6)
+				subnetT.Spec.Subnet = "abcd:1234::/120"
 				subnetT.Spec.IPs = append(subnetT.Spec.IPs,
 					[]string{
 						"abcd:1234::a",
@@ -233,6 +265,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 
 			It("failed to merge 'spec.excludeIPs' due to the invalid 'spec.ipVersion'", func() {
 				subnetT.Spec.IPVersion = pointer.Int64(constant.InvalidIPVersion)
+				subnetT.Spec.Subnet = "172.18.40.0/24"
 				subnetT.Spec.ExcludeIPs = append(subnetT.Spec.ExcludeIPs,
 					[]string{
 						"172.18.40.10",
@@ -255,6 +288,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 
 			It("failed to merge 'spec.excludeIPs' due to the invalid 'spec.ips'", func() {
 				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				subnetT.Spec.Subnet = "172.18.40.0/24"
 				subnetT.Spec.ExcludeIPs = append(subnetT.Spec.ExcludeIPs,
 					[]string{
 						constant.InvalidIPRange,
@@ -278,7 +312,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 			})
 
 			It("merges IPv4 'spec.excludeIPs'", func() {
-				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				subnetT.Spec.Subnet = "172.18.40.0/24"
 				subnetT.Spec.ExcludeIPs = append(subnetT.Spec.ExcludeIPs,
 					[]string{
 						"172.18.40.10",
@@ -299,7 +333,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 			})
 
 			It("merges IPv6 'spec.excludeIPs'", func() {
-				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv6)
+				subnetT.Spec.Subnet = "abcd:1234::/120"
 				subnetT.Spec.ExcludeIPs = append(subnetT.Spec.ExcludeIPs,
 					[]string{
 						"abcd:1234::a",
@@ -482,15 +516,6 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 			})
 
 			When("Validating 'spec.ips'", func() {
-				It("inputs empty 'spec.ips'", func() {
-					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					subnetT.Spec.Subnet = "172.18.40.0/24"
-
-					ctx := context.TODO()
-					err := subnetWebhook.ValidateCreate(ctx, subnetT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
 				It("inputs invalid 'spec.ips'", func() {
 					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
 					subnetT.Spec.Subnet = "172.18.40.0/24"
@@ -787,24 +812,6 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 			})
 
 			When("Validating 'spec.ips'", func() {
-				It("removes all 'spec.ips'", func() {
-					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
-					subnetT.Spec.Subnet = "172.18.40.0/24"
-					subnetT.Spec.IPs = append(subnetT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
-
-					newSubnetT := subnetT.DeepCopy()
-					newSubnetT.Spec.IPs = nil
-
-					ctx := context.TODO()
-					err := subnetWebhook.ValidateUpdate(ctx, subnetT, newSubnetT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
-				})
-
 				It("appends invalid IP range to 'spec.ips'", func() {
 					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
 					subnetT.Spec.Subnet = "172.18.40.0/24"