Repository: spidernet-io/spiderpool
Pull request #2199 (2023-08-18 10:19:24)

spidermultusconfig: ovs cni config supported
---
name: Pull request
about: Tell us about your contribution
labels: ["pr/release/none-required"]
---

---
## Thanks for contributing !

Before submitting a pull request, make sure you read about our Contribution notice here: <https://spidernet-io.github.io/spiderpool/contributing/development/pullrequest/#need-review>

**What this PR does / why we need it**:

- spidermultusconfig: ovs cni config supported, Now we can create multus NAD for CNI of type ovs via spidermultusconfig
- remove unused fields of  coordinator and ifacer cni  config

**Which issue(s) this PR fixes**:

https://github.com/spidernet-io/spiderpool/issues/2121
https://github.com/spidernet-io/spiderpool/issues/2006

**Special notes for your reviewer**:

**make sure your commit is signed off**


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/spidernet-io/spiderpool/pull/2199?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) Report
> Merging [#2199](https://app.codecov.io/gh/spidernet-io/spiderpool/pull/2199?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (c2a99d2) into [main](https://app.codecov.io/gh/spidernet-io/spiderpool/commit/4750d2d2d0eabe9deaf97573e6da56a531e8d145?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (4750d2d) will **decrease** coverage by `0.52%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://app.codecov.io/gh/spidernet-io/spiderpool/pull/2199/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://app.codecov.io/gh/spidernet-io/spiderpool/pull/2199?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    #2199      +/-   ##
==========================================
- Coverage   81.68%   81.17%   -0.52%     
==========================================
  Files          49       49              
  Lines        5210     5210              
==========================================
- Hits         4256     4229      -27     
- Misses        792      823      +31     
+ Partials      162      158       -4     
```

| [Flag](https://app.codecov.io/gh/spidernet-io/spiderpool/pull/2199/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/spidernet-io/spiderpool/pull/2199/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) | `81.17% <ø> (-0.52%)` | :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.

[see 1 file with indirect coverage changes](https://app.codecov.io/gh/spidernet-io/spiderpool/pull/2199/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io)

cyclinder: /cc @weizhoublue 

Patch:
diff --git a/.github/workflows/lint-license.yaml b/.github/workflows/lint-license.yaml
index 35a46d014..159986420 100644
--- a/.github/workflows/lint-license.yaml
+++ b/.github/workflows/lint-license.yaml
@@ -50,4 +50,4 @@ jobs:
 
       - name: Check License Header
         id: checklicense
-        uses: apache/skywalking-eyes@v0.5.0
+        uses: apache/skywalking-eyes@v0.4.0
diff --git a/Makefile b/Makefile
index ba59fb371..54ff0e6aa 100644
--- a/Makefile
+++ b/Makefile
@@ -308,10 +308,6 @@ e2e_init:
 
 .PHONY: e2e_init_underlay
 e2e_init_underlay:
-	$(QUIET)  make e2e_init -e INSTALL_OVERLAY_CNI=false -e E2E_SPIDERPOOL_ENABLE_SUBNET=false
-
-.PHONY: e2e_init_underlay_subnet
-e2e_init_underlay_subnet:
 	$(QUIET)  make e2e_init -e INSTALL_OVERLAY_CNI=false -e E2E_SPIDERPOOL_ENABLE_SUBNET=true
 
 .PHONY: e2e_init_calico
@@ -329,10 +325,6 @@ e2e_test:
 
 .PHONY: e2e_test_underlay
 e2e_test_underlay:
-	$(QUIET)  make e2e_test -e INSTALL_OVERLAY_CNI=false -e E2E_SPIDERPOOL_ENABLE_SUBNET=false
-
-.PHONY: e2e_test_underlay_subnet
-e2e_test_underlay_subnet:
 	$(QUIET)  make e2e_test -e INSTALL_OVERLAY_CNI=false -e E2E_SPIDERPOOL_ENABLE_SUBNET=true
 
 .PHONY: e2e_test_calico
diff --git a/charts/spiderpool/crds/spiderpool.spidernet.io_spidermultusconfigs.yaml b/charts/spiderpool/crds/spiderpool.spidernet.io_spidermultusconfigs.yaml
index 7b80f6f4b..54e755e9a 100644
--- a/charts/spiderpool/crds/spiderpool.spidernet.io_spidermultusconfigs.yaml
+++ b/charts/spiderpool/crds/spiderpool.spidernet.io_spidermultusconfigs.yaml
@@ -43,6 +43,7 @@ spec:
                 - macvlan
                 - ipvlan
                 - sriov
+                - ovs
                 - custom
                 type: string
               coordinator:
@@ -176,6 +177,49 @@ spec:
                 required:
                 - master
                 type: object
+              ovs:
+                properties:
+                  bridge:
+                    type: string
+                  deviceID:
+                    description: PCI address of a VF in valid sysfs format
+                    type: string
+                  ippools:
+                    description: SpiderpoolPools could specify the IPAM spiderpool
+                      CNI configuration default IPv4&IPv6 pools.
+                    properties:
+                      ipv4:
+                        items:
+                          type: string
+                        type: array
+                      ipv6:
+                        items:
+                          type: string
+                        type: array
+                    type: object
+                  trunk:
+                    items:
+                      properties:
+                        id:
+                          maximum: 4094
+                          minimum: 0
+                          type: integer
+                        maxID:
+                          maximum: 4094
+                          minimum: 0
+                          type: integer
+                        minID:
+                          maximum: 4094
+                          minimum: 0
+                          type: integer
+                      type: object
+                    type: array
+                  vlan:
+                    format: int32
+                    type: integer
+                required:
+                - bridge
+                type: object
               sriov:
                 properties:
                   ippools:
diff --git a/cmd/ifacer/cmd/types.go b/cmd/ifacer/cmd/types.go
index a7a53aafe..25e2d9242 100644
--- a/cmd/ifacer/cmd/types.go
+++ b/cmd/ifacer/cmd/types.go
@@ -40,7 +40,7 @@ func ParseConfig(stdin []byte) (*Ifacer, error) {
 	}
 
 	if conf.VlanID < 0 || conf.VlanID > 4094 {
-		return nil, fmt.Errorf("invalid vlanID %v: vlanID must be in range [0,4094]", conf.VlanID)
+		return nil, fmt.Errorf("invalid vlan tag %v: vlan tag must be in range [0,4094]", conf.VlanID)
 	}
 
 	if conf.Bond != nil && conf.Bond.Name == "" {
diff --git a/docs/concepts/allocation.md b/docs/concepts/allocation.md
index c29437c9d..d511419d0 100644
--- a/docs/concepts/allocation.md
+++ b/docs/concepts/allocation.md
@@ -7,29 +7,39 @@ When a pod is creating, it will follow steps below to get IP allocations.
     For which IPPool is used by a pod, the following rules are listed from **high to low priority** which means the previous rule would **override** the latter rule.
 
     * SpiderSubnet annotation. `ipam.spidernet.io/subnets` and `ipam.spidernet.io/subnet` will choose to use auto-created ippool if the SpiderSubnet feature is enabled. See [SpiderSubnet](../usage/spider-subnet.md) for details.
-
     * Honor pod annotation. `ipam.spidernet.io/ippools" and "ipam.spidernet.io/ippool` could be used to specify an ippool. See [Pod Annotation](../reference/annotation.md) for details.
-
     * Namespace annotation. `ipam.spidernet.io/defaultv4ippool` and `ipam.spidernet.io/defaultv6ippool` could be used to specify an ippool. See [namespace annotation](../reference/annotation.md) for details.
-
     * CNI configuration file. It can be set to `default_ipv4_ippool` and `default_ipv6_ippool` in the CNI configuration file. See [configuration](../reference/plugin-ipam.md) for details.
-
     * Cluster default IPPool. We can set SpiderIPPool CR object with `default` property, in which we'll regard it as a default pool in cluster.  See [configuration](../reference/crd-spiderippool.md) for details.
 
 2. Filter valid IPPool candidates.
 
     After getting IPv4 and IPv6 IPPool candidates, it looks into each IPPool and figures out whether it meets following rules, and learns which candidate IPPool is available.
 
-    * The "disable" field of the IPPool is "false". This property means the IPPool is not available to be used.
-    * Check current environment with IP version settings. (dual stack, IPv4 only, IPv6 only)
     * Filter terminating IPPools.
+    * The `disable` field of the IPPool is `false`. This property means the IPPool is not available to be used.
     * Check `IPPool.Spec.NodeName` and `IPPool.Spec.NodeAffinity` properties whether match the scheduled node of the pod or not. If not match, this IPPool would be filtered. (`NodeName` has higher priority than `NodeAffinity`)
     * Check `IPPool.Spec.NamespaceName` and `IPPool.Spec.NamespaceAffinity` properties whether match the namespace of the pod or not. If not match, this IPPool would be filtered. (`NamespaceName` has higher priority than `NamespaceAffinity`)
-    * The "PodAffinity" field of the IPPool must meet the pod
+    * The `IPPool.Spec.PodAffinity` field of the IPPool must meet the pod
     * Check `IPPool.Spec.MultusName` properties whether match the pod current NIC Multus configuration or not. If not match, this IPPool would be filtered.
     * The available IP resource of the IPPool is not exhausted
 
-3. Assign IP from valid IPPool candidates.
+3. Sort IPPool candidates.
+
+   We'll sort these IPPool candidates with our custom priority rules, then the IPAM prefers allocating IP addresses from the candidates in sequence.
+
+   * The IPPool resource with `IPPool.Spec.PodAffinity` property has the highest priority.
+   * The IPPool resource with `IPPool.Spec.NodeName` or `IPPool.Spec.NodeAffinity` property has the second-highest priority.
+   * The IPPool resource with `IPPool.Spec.NamespaceName` or `IPPool.Spec.NamespaceAffinity` property has the second-highest priority.
+   * The IPPool resource with `IPPool.Spec.MultusName` property has the lowest priority.
+   
+   > Notice: here are some simple instance to describe this rule.
+   >
+   > 1. *IPPoolA* with properties `IPPool.Spec.PodAffinity` and `IPPool.Spec.NodeName` has higher priority than *IPPoolB* with single affinity property `IPPool.Spec.PodAffinity`.
+   > 2. *IPPoolA* with single property `IPPool.Spec.PodAffinity` has higher priority than *IPPoolB* with properties `IPPool.Spec.NodeName` and `IPPool.Spec.NamespaceName`.
+   > 3. *IPPoolA* with properties `IPPool.Spec.PodAffinity` and `IPPool.Spec.NodeName` has higher priority than *IPPoolB* with properties `IPPool.Spec.PodAffinity`,`IPPool.Spec.NamespaceName` and `IPPool.Spec.MultusName`.
+
+4. Assign IP from valid IPPool candidates.
 
     When trying to assign IP from the IPPool candidates, it follows rules as below.
 
diff --git a/docs/develop/contributing.md b/docs/develop/contributing.md
index 6431eec62..a52146ab1 100644
--- a/docs/develop/contributing.md
+++ b/docs/develop/contributing.md
@@ -39,12 +39,11 @@ run the following command to check unitest
 
     before start the test, you shoud know there are test scenes as following 
 
-    | kind                                     | setup cluster                    | test                          |
-    |------------------------------------------|----------------------------------|-------------------------------|
-    | test underlay CNI without subnet feature | make    e2e_init_underlay        | make e2e_test_underlay        |
-    | test underlay CNI with subnet feature    | make    e2e_init_underlay_subnet | make e2e_test_underlay_subnet |
-    | test overlay CNI for calico              | make    e2e_init_overlay_calico  | make e2e_test_overlay_calico  |
-    | test overlay CNI for cilium              | make    e2e_init_overlay_cilium  | make e2e_test_overlay_cilium  |
+    | kind                                  | setup cluster                    | test                          |
+    |---------------------------------------|----------------------------------|-------------------------------|
+    | test underlay CNI                     | make    e2e_init_underlay        | make e2e_test_underlay        |
+    | test overlay CNI for calico           | make    e2e_init_overlay_calico  | make e2e_test_overlay_calico  |
+    | test overlay CNI for cilium           | make    e2e_init_overlay_cilium  | make e2e_test_overlay_cilium  |
 
     if you are in China, it could add `-e E2E_CHINA_IMAGE_REGISTRY=true` to pull images from china image registry, add `-e HTTP_PROXY=http://${ADDR}` to get chart
 
@@ -83,9 +82,6 @@ run the following command to check unitest
         # it pulls images from another image registry and just use http proxy to pull chart 
         $ make e2e_init_underlay  -e E2E_CHINA_IMAGE_REGISTRY=true -e HTTP_PROXY=http://${ADDR}
 
-        # setup cluster with subnet feature
-        $ make e2e_init_underlay_subnet -e E2E_CHINA_IMAGE_REGISTRY=true -e HTTP_PROXY=http://${ADDR}
-
         # setup cluster with calico cni
         $ make e2e_init_calico -e E2E_CHINA_IMAGE_REGISTRY=true -e HTTP_PROXY=http://${ADDR}
 
@@ -113,9 +109,6 @@ run the following command to check unitest
         # example: run a case until fails
         $ make e2e_test_underlay -e GINKGO_OPTION=" --label-filter=CaseLabel --until-it-fails "
 
-        # Run all e2e tests for enableSpiderSubnet=false cluster
-        $ make e2e_test_underlay_subnet 
-
         # Run all e2e tests for enableSpiderSubnet=false cluster
         $ make e2e_test_calico
 
diff --git a/docs/reference/crd-spidermultusconfig.md b/docs/reference/crd-spidermultusconfig.md
index 87b91ecaa..4e53a4a9c 100644
--- a/docs/reference/crd-spidermultusconfig.md
+++ b/docs/reference/crd-spidermultusconfig.md
@@ -49,15 +49,16 @@ And you can also use special annotation `multus.spidernet.io/cr-name` and `multu
 
 This is the SpiderReservedIP spec for users to configure.
 
-| Field             | Description                                       | Schema                                                                       | Validation | Values                      | Default |
-|-------------------|---------------------------------------------------|------------------------------------------------------------------------------|------------|-----------------------------|---------|
-| cniType           | expected main CNI type                            | string                                                                       | require    | macvlan,ipvlan,sriov,custom |         |
-| macvlan           | macvlan CNI configuration                         | [SpiderMacvlanCniConfig](./crd-spidermultusconfig.md#SpiderMacvlanCniConfig) | optional   |                             |         |
-| ipvlan            | ipvlan CNI configuration                          | [SpiderIPvlanCniConfig](./crd-spidermultusconfig.md#SpiderIPvlanCniConfig)   | optional   |                             |         |
-| sriov             | sriov CNI configuration                           | [SpiderSRIOVCniConfig](./crd-spidermultusconfig.md#SpiderSRIOVCniConfig)     | optional   |                             |         |
-| enableCoordinator | enable coordinator or not                         | boolean                                                                      | optional   | true,false                  | true    |
-| coordinator       | coordinator CNI configuration                     | [CoordinatorSpec](./crd-spidercoordinator.md#Spec)                           | optional   |                             |         |
-| customCNI         | a string that represents custom CNI configuration | string                                                                       | optional   |                             |         |
+| Field             | Description                                       | Schema                                                                       | Validation | Values                          | Default |
+|-------------------|---------------------------------------------------|------------------------------------------------------------------------------|------------|---------------------------------|---------|
+| cniType           | expected main CNI type                            | string                                                                       | require    | macvlan,ipvlan,sriov,ovs,custom |         |
+| macvlan           | macvlan CNI configuration                         | [SpiderMacvlanCniConfig](./crd-spidermultusconfig.md#SpiderMacvlanCniConfig) | optional   |                                 |         |
+| ipvlan            | ipvlan CNI configuration                          | [SpiderIPvlanCniConfig](./crd-spidermultusconfig.md#SpiderIPvlanCniConfig)   | optional   |                                 |         |
+| sriov             | sriov CNI configuration                           | [SpiderSRIOVCniConfig](./crd-spidermultusconfig.md#SpiderSRIOVCniConfig)     | optional   |                                 |         |
+| ovs               | ovs CNI configuration                             | [SpiderOvsCniConfig](./crd-spidermultusconfig.md#SpiderOvsCniConfig)         | optional   |                                 |         |
+| enableCoordinator | enable coordinator or not                         | boolean                                                                      | optional   | true,false                      | true    |
+| coordinator       | coordinator CNI configuration                     | [CoordinatorSpec](./crd-spidercoordinator.md#Spec)                           | optional   |                                 |         |
+| customCNI         | a string that represents custom CNI configuration | string                                                                       | optional   |                                 |         |
 
 #### SpiderMacvlanCniConfig
 
@@ -85,6 +86,16 @@ This is the SpiderReservedIP spec for users to configure.
 | vlanID       | vlan ID                                                                                   | int                                                            | optional   |
 | ippools      | the default IPPools in your CNI configurations                                            | [SpiderpoolPools](./crd-spidermultusconfig.md#SpiderpoolPools) | optional   |
 
+#### SpiderOvsCniConfig
+
+| Field        | Description                                                                               | Schema                                                         | Validation |
+|--------------|-------------------------------------------------------------------------------------------|----------------------------------------------------------------|------------|
+| bridge       | name of the bridge to use                                                                 | string                                                         | required   |
+| vlan         | vlan ID of attached port. Trunk port if not specified                                     | int                                                            | optional   |
+| trunk        | List of VLAN ID's and/or ranges of accepted VLAN ID's                                     | [Trunk](./crd-spidermultusconfig.md#Trunk)                     | optional   |
+| deviceID     | PCI address of a VF in valid sysfs format                                                 | string                                                         | optional   |
+| ippools      | the default IPPools in your CNI configurations                                            | [SpiderpoolPools](./crd-spidermultusconfig.md#SpiderpoolPools) | optional   |
+
 #### BondConfig
 
 | Field                 | Description                            | Schema | Validation | Values |
@@ -93,6 +104,14 @@ This is the SpiderReservedIP spec for users to configure.
 | Mode                  | bond interface mode                    | int    | required   | [0,6]  |
 | Options               | expected bond Interface configurations | string | optional   |        |
 
+#### Trunk
+
+| Field                 | Description                            | Schema | Validation | Values   |
+|-----------------------|----------------------------------------|--------|------------|----------|
+| minID                 | the min value of vlan ID               | int    | optional   | [0,4094] |
+| maxID                 | the max value of vlan ID               | int    | optional   | [0,4094] |
+| id                    | the value of vlan ID                   | int    | optional   | [0,4094] |
+
 #### SpiderpoolPools
 
 | Field | Description                                         | Schema          | Validation |
diff --git a/docs/usage/install/install-zh_CN.md b/docs/usage/install/install-zh_CN.md
index 2aa9718b0..365f13d18 100644
--- a/docs/usage/install/install-zh_CN.md
+++ b/docs/usage/install/install-zh_CN.md
@@ -10,7 +10,7 @@
 
     对于这一使用场景，集群可以使用一个或多个 Underlay CNI 来运行 Pod。
 
-    当 Pod 中有一个或多个 Underlay NIC 时，Spiderpool 可以帮助其分配 IP 地址、调整路由、连接 Pod 和本地节点、检测 IP 冲突等。
+    当 Pod 中有一个或多个 Underlay CNI 时，Spiderpool 可以帮助其分配 IP 地址、调整路由、连接 Pod 和本地节点、检测 IP 冲突等。
 
 - 为 Overlay CNI 的 Pod 添加 Underaly CNI 的辅助网卡
 
diff --git a/docs/usage/install/overlay/get-started-calico.md b/docs/usage/install/overlay/get-started-calico.md
index 424ddce8d..97539d542 100644
--- a/docs/usage/install/overlay/get-started-calico.md
+++ b/docs/usage/install/overlay/get-started-calico.md
@@ -229,9 +229,9 @@ default via 169.254.1.1 dev eth0
 
 Explanation of the above:
 
-> The Pod is allocated two interfaces: Calico (eth0) and Macvlan (net1), having IPv4 addresses of 10.233.73.210 and 10.6.212.145, respectively.
+> The Pod is allocated two interfaces: eth0 (Calico) and net1 (Macvlan), having IPv4 addresses of 10.233.73.210 and 10.6.212.145, respectively.
 > 10.233.0.0/18 and 10.233.64.0/18 represent the cluster's CIDR. When the Pod accesses this subnet, traffic will be forwarded through eth0. Each route table will include this route.
-> The IP address 10.6.212.132 belongs to the node where the Pod has been scheduled. This route ensures that when the Pod accesses the host, it will be forwarded through eth0.
+> 10.6.212.132 is the IP address of the node where the Pod has been scheduled. This route ensures that when the Pod accesses the host, it will be forwarded through eth0.
 > This series of routing rules guarantees that the Pod will forward traffic through eth0 when accessing targets within the cluster and through net1 for external targets.
 > By default, the Pod's default route is reserved in net1. To reserve it in eth0, add the following annotation to the Pod's metadata: "ipam.spidernet.io/default-route-nic: eth0".
 
@@ -246,7 +246,7 @@ pod/coredns-57fbf68cf6-kvcwl   1/1     Running   3 (91d ago)   91d   10.233.73.1
 NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE   SELECTOR
 service/coredns   ClusterIP   10.233.0.3   <none>        53/UDP,53/TCP,9153/TCP   91d   k8s-app=kube-dns
 
-~# Access the CoreDNS Pod across multiple nodes
+~# Access the CoreDNS Pod across nodes
 ~# kubectl  exec nginx-4653bc4f24-rswak -- ping 10.233.73.195 -c 2
 PING 10.233.73.195 (10.233.73.195): 56 data bytes
 64 bytes from 10.233.73.195: seq=0 ttl=62 time=2.348 ms
diff --git a/docs/usage/install/overlay/get-started-cilium-zh_cn.md b/docs/usage/install/overlay/get-started-cilium-zh_cn.md
index c037c68c1..199d960d4 100644
--- a/docs/usage/install/overlay/get-started-cilium-zh_cn.md
+++ b/docs/usage/install/overlay/get-started-cilium-zh_cn.md
@@ -8,7 +8,7 @@
 - Pod 访问集群内东西向流量从 Cilium 创建的网卡转发(eth0)，Pod 访问集群南北向流量从 Macvlan 创建的网卡(net1)转发。
 - Pod 多网卡的路由调协，使 Pod 对内对外访问正常
 
-> 注: 本文中 `NAD` 为 Multus **N**etwork-**A**ttachment-**D**efinition CR的简写。
+> 本文中 `NAD` 为 Multus **N**etwork-**A**ttachment-**D**efinition CR 的简写。
 
 ## 先决条件
 
@@ -81,7 +81,7 @@ Note:
 
 ### 创建 SpiderMultusConfig 
 
-本文使用 Spidermultusconfig 创建 Multus 的 NAD实例:
+本文使用 Spidermultusconfig 创建 Multus 的 NAD 实例:
 
 ```shell
 cat << EOF | kubectl apply -f -
@@ -105,7 +105,7 @@ Note:
 
 > `spec.macvlan.master` 设置为 `ens192`, `ens192`必须存在于主机上。并且 `spec.macvlan.ippools.ipv4` 设置的子网和  `ens192` 的子网保持一致。
 
-创建成功后, 查看 Multus NAD是否成功创建:
+创建成功后, 查看 Multus NAD 是否成功创建:
 
 ```shell
 ~# kubectl  get network-attachment-definitions.k8s.cni.cncf.io  macvlan-ens192 -o yaml
@@ -233,12 +233,12 @@ default via 10.233.65.96 dev eth0
 以上信息解释:
 
 > Pod 分配了两张网卡: eth0(cilium)、net1(macvlan),对应的 IPv4 地址分别为: 10.233.120.101 和 10.6.212.202
-> 10.233.0.0/18 和 10.233.64.0/18 是集群的 CIDR, Pod访问该子网时从 eth0 转发, 每个 route table 都会插入此路由
+> 10.233.0.0/18 和 10.233.64.0/18 是集群的 CIDR, Pod 访问该子网时从 eth0 转发, 每个 route table 都会插入此路由
 > 10.6.212.131 是 Pod 所在节点的地址，此路由确保 Pod 访问该主机时从 eth0 转发
 > 这一系列的路由确保 Pod 访问集群内目标时从 eth0 转发，访问外部目标时从 net1 转发
 > 在默认情况下，Pod 的默认路由保留在 net1。如果想要保留在 eth0，可以通过在 Pod 的 annotations 中注入: "ipam.spidernet.io/default-route-nic: eth0" 实现。
 
-测试 Pod 访问集群东西向流量的连通性，以访问 coredns 的 Pod 和 Service 为例:
+测试 Pod 访问集群东西向流量的连通性，以访问 CoreDNS 的 Pod 和 Service 为例:
 
 ```shell
 ~# kubectl  get all -n kube-system -l k8s-app=kube-dns -o wide
@@ -249,7 +249,7 @@ pod/coredns-57fbf68cf6-kvcwl   1/1     Running   3 (91d ago)   91d   10.233.73.1
 NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE   SELECTOR
 service/coredns   ClusterIP   10.233.0.3   <none>        53/UDP,53/TCP,9153/TCP   91d   k8s-app=kube-dns
 
-~# 跨节点访问 coredns 的 pod
+~# 跨节点访问 CoreDNS 的 pod
 ~# kubectl  exec nginx-4653bc4f24-rswak -- ping 10.233.73.195 -c 2
 PING 10.233.73.195 (10.233.73.195): 56 data bytes
 64 bytes from 10.233.73.195: seq=0 ttl=62 time=2.348 ms
@@ -259,7 +259,7 @@ PING 10.233.73.195 (10.233.73.195): 56 data bytes
 2 packets transmitted, 2 packets received, 0% packet loss
 round-trip min/avg/max = 0.586/1.467/2.348 ms
 
-~# 访问 coredns 的 service
+~# 访问 CoreDNS 的 service
 ~# kubectl exec  nginx-4653bc4f24-rswak -- curl 10.233.0.3:53 -I
   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                  Dload  Upload   Total   Spent    Left  Speed
diff --git a/docs/usage/install/overlay/get-started-cilium.md b/docs/usage/install/overlay/get-started-cilium.md
index e69de29bb..baf0e4740 100644
--- a/docs/usage/install/overlay/get-started-cilium.md
+++ b/docs/usage/install/overlay/get-started-cilium.md
@@ -0,0 +1,277 @@
+# Cilium Quick Start
+
+**English** | [**简体中文**](./get-started-cilium-zh_cn.md)
+
+This page showcases the utilization of `Spiderpool`, a comprehensive Underlay network solution, in a cluster where [Cilium](https://github.com/cilium/cilium) serves as the default CNI. `Spiderpool` leverages Multus to attach an additional NIC created with `Macvlan` to Pods and coordinates routes among multiple NICs using `coordinator`. The advantages offered by Spiderpool's solution are:
+
+- Pods have both Cilium and Macvlan NICs.
+- East-west traffic is routed through the Cilium NIC (eth0), while north-south traffic is routed through the Macvlan NIC (net1).
+- The routing coordination among multiple NICs of the Pod ensures seamless connectivity for both internal and external access.
+
+> `NAD` is an abbreviation for Multus **N**etwork-**A**ttachment-**D**efinition CR.
+
+## Prerequisites
+
+- A ready Kubernetes cluster.
+- Cilium has been already installed as the default CNI for your cluster. If it is not installed, please refer to [the official documentation](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/) or follow the commands below for installation:
+
+   ```shell
+   ~# helm repo add cilium https://helm.cilium.io/
+   ~# helm install cilium cilium/cilium -namespace kube-system
+   ~# kubectl wait --for=condition=ready -l k8s-app=cilium pod -n kube-system
+   ```
+
+- If the [cni plugins](https://www.cni.dev/plugins/current/) are not installed under `/opt/cni/bin` on each node of your cluster, follow the commands below for installation:
+
+   ```shell
+   ~# wget https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz
+   ~# tar xvfzp ./cni-plugins-linux-amd64-v1.3.0.tgz -C /opt/cni/bin
+   ```
+
+- Helm binary
+
+## Install Spiderpool
+
+Follow the command below to install Spiderpool:
+
+```shell
+~# helm repo add spiderpool https://spidernet-io.github.io/spiderpool
+~# helm repo update spiderpool
+~# helm install spiderpool spiderpool/spiderpool --namespace kube-system --set coordinator.mode=overlay --wait 
+```
+
+> By default, Spiderpool automatically installs Multus. However, if Multus has been already installed, you can skip the installation via the following command: `helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.install=false`
+> It is necessary to specify that coordinator operates in overlay mode
+
+Check the status of Spiderpool after the installation is complete:
+
+```shell
+~# kubectl get po -n kube-system | grep spiderpool
+spiderpool-agent-bcwqk                                      1/1     Running     0                 1m
+spiderpool-agent-udgi4                                      1/1     Running     0                 1m
+spiderpool-controller-bgnh3rkcb-k7sc9                       1/1     Running     0                 1m
+spiderpool-init                                             0/1     Completed   0                 1m
+spiderpool-multus-hkxb6                                     1/1     Running     0                 1m
+spiderpool-multus-l9dcs                                     1/1     Running     0                 1m
+```
+
+### Create SpiderIPPool
+
+The subnet for the interface `ens192` on the cluster nodes here is `10.6.0.0/16`. Create a SpiderIPPool using this subnet:
+
+```shell
+cat << EOF | kubectl apply -f -
+apiVersion: spiderpool.spidernet.io/v2beta1
+kind: SpiderIPPool
+metadata:
+  name: 10-6-v4
+spec:
+  disable: false
+  gateway: 10.6.0.1
+  ipVersion: 4
+  ips:
+  - 10.6.212.200-10.6.212.240
+  subnet: 10.6.0.0/16
+EOF
+```
+
+> The subnet should be consistent with the subnet of `ens192` on the nodes, and ensure that the IP addresses do not conflict with any existing ones.
+
+### Create SpiderMultusConfig
+
+The Multus NAD instance is created using Spidermultusconfig:
+
+```shell
+cat << EOF | kubectl apply -f -
+apiVersion: spiderpool.spidernet.io/v2beta1
+kind: SpiderMultusConfig
+metadata:
+  name: macvlan-ens192
+spec:
+  cniType: macvlan
+  macvlan:
+    master:
+    - ens192
+    ippools:
+      ipv4:
+      - 10-6-v4
+    vlanID: 0
+EOF
+```
+
+> Set `spec.macvlan.master` to `ens192` which must be present on the host. The subnet specified in `spec.macvlan.spiderpoolConfigPools.IPv4IPPool` should match that of `ens192`.
+
+Check if the Multus NAD has been created successfully:
+
+```shell
+~# kubectl  get network-attachment-definitions.k8s.cni.cncf.io  macvlan-ens192 -o yaml
+apiVersion: k8s.cni.cncf.io/v1
+kind: NetworkAttachmentDefinition
+metadata:
+  annotations:
+    kubectl.kubernetes.io/last-applied-configuration: |
+      {"apiVersion":"spiderpool.spidernet.io/v2beta1","kind":"SpiderMultusConfig","metadata":{"annotations":{},"name":"macvlan-ens192","namespace":"default"},"spec":{"cniType":"macvlan","coordinator":{"podCIDRType":"cluster","tuneMode":"overlay"},"enableCoordinator":true,"macvlan":{"master":["ens192"],"spiderpoolConfigPools":{"IPv4IPPool":["10-6-v4"]},"vlanID":0}}}
+  creationTimestamp: "2023-06-30T07:12:21Z"
+  generation: 1
+  name: macvlan-ens192
+  namespace: default
+  ownerReferences:
+  - apiVersion: spiderpool.spidernet.io/v2beta1
+    blockOwnerDeletion: true
+    controller: true
+    kind: SpiderMultusConfig
+    name: macvlan-ens192
+    uid: 3f902f46-d9d4-4c62-a7c3-98d4a9aa26e4
+  resourceVersion: "24713635"
+  uid: 712d1e58-ab57-49a7-9189-0fffc64aa9c3
+spec:
+  config: '{"cniVersion":"0.3.1","name":"macvlan-ens192","plugins":[{"type":"macvlan","ipam":{"type":"spiderpool","default_ipv4_ippool":["10-6-v4"]},"master":"ens192","mode":"bridge"},{"type":"coordinattor","ipam":{},"dns":{},"detectGateway":false,"tunePodRoutes":true,"mode":"overlay","hostRuleTable":500,"detectIPConflict":false}]}'
+```
+
+### Create an application
+
+Run the following command to create the demo application nginx:
+
+```shell
+~# cat <<EOF | kubectl create -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nginx
+spec:
+  replicas: 2
+  selector:
+    matchLabels:
+      app: nginx
+  template:
+    metadata:
+      annotations:
+        k8s.v1.cni.cncf.io/networks: macvlan-ens192
+      labels:
+        app: nginx
+    spec:
+      containers:
+      - name: nginx
+        image: nginx
+        imagePullPolicy: IfNotPresent
+        ports:
+        - name: http
+          containerPort: 80
+          protocol: TCP
+EOF
+```
+
+- `k8s.v1.cni.cncf.io/networks`: specifies that Multus uses `macvlan-ens192` to attach an additional interface to the Pod.
+
+Check the Pod's IP allocation after it is ready:
+
+```shell
+~#  kubectl get po -l app=nginx -o wide
+NAME                     READY   STATUS    RESTARTS   AGE   IP                NODE        NOMINATED NODE   READINESS GATES
+nginx-x34abcsf74-xngkm   1/1     Running   0          2m    10.233.120.101    controller  <none>           <none>
+nginx-x34abcsf74-ougjk   1/1     Running   0          2m    10.233.84.230     worker01    <none>           <none>
+```
+
+```shell
+~# kubectl get se
+NAME                     INTERFACE   IPV4POOL            IPV4               IPV6POOL   IPV6   NODE
+nginx-4653bc4f24-xngkm   net1        10-6-v4             10.6.212.202/16                      worker01
+nginx-4653bc4f24-ougjk   net1        10-6-v4             10.6.212.230/16                      controller
+```
+
+Use the command `ip` to view the Pod's information such as routes:
+
+```shell
+[root@controller1 ~]# kubectl exec it nginx-4653bc4f24-xngkm sh
+# ip a
+1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host
+       valid_lft forever preferred_lft forever
+4: eth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1430 qdisc noqueue state UP group default
+    link/ether a2:99:9d:04:01:80 brd ff:ff:ff:ff:ff:ff link-netnsid 0
+    inet 10.233.120.101/32 scope global eth0
+       valid_lft forever preferred_lft forever
+    inet6 fd85:ee78:d8a6:8607::1:f2d5/128 scope global
+       valid_lft forever preferred_lft forever
+    inet6 fe80::a099:9dff:fe04:131/64 scope link
+       valid_lft forever preferred_lft forever
+5: net1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
+    link/ether 2a:1e:a1:db:2a:9a brd ff:ff:ff:ff:ff:ff link-netnsid 0
+    inet 10.6.212.202/16 brd 10.6.255.255 scope global net1
+       valid_lft forever preferred_lft forever
+    inet6 fd00:10:6::df3/64 scope global
+       valid_lft forever preferred_lft forever
+    inet6 fe80::281e:a1ff:fedb:2a9a/64 scope link
+       valid_lft forever preferred_lft forever
+/ # ip rule
+0: from all lookup local
+32760: from 10.233.120.101 lookup 100
+32762: from all to 10.233.65.96 lookup 100
+32763: from all to 10.233.64.0/18 lookup 100
+32764: from all to 10.233.0.0/18 lookup 100
+32765: from all to 10.6.212.131 lookup 100
+32766: from all lookup main
+32767: from all lookup default
+/ # ip route
+default via 10.6.0.1 dev net1
+10.6.0.0/16 dev net1 scope link  src 10.6.212.202
+/ # ip route show table 100
+default via 10.233.65.96 dev eth0
+10.233.65.96 dev eth0 scope link
+10.6.212.131 dev eth0 scope link
+10.233.0.0/18 via 10.6.212.132 dev eth0 
+10.233.64.0/18 via 10.6.212.132 dev eth0
+```
+
+Explanation of the above:
+
+> The Pod is allocated two interfaces: eth0 (cilium) and net1 (macvlan), having IPv4 addresses of 10.233.120.101 and 10.6.212.202, respectively.
+> 10.233.0.0/18 and 10.233.64.0/18 represent the cluster's CIDR. When the Pod accesses this subnet, traffic will be forwarded through eth0. Each route table will include this route.
+> 10.6.212.132 is the IP address of the node where the Pod has been scheduled. This route ensures that when the Pod accesses the host, traffic will be forwarded through eth0.
+> This series of routing rules guarantees that the Pod will forward traffic through eth0 when accessing targets within the cluster and through net1 for external targets.
+> By default, the Pod's default route is reserved in net1. To reserve it in eth0, add the following annotation to the Pod's metadata: "ipam.spidernet.io/default-route-nic: eth0".
+
+To test the east-west connectivity of the Pod, we will use the example of accessing the CoreDNS Pod and Service:
+
+```shell
+~# kubectl  get all -n kube-system -l k8s-app=kube-dns -o wide
+NAME                           READY   STATUS    RESTARTS      AGE   IP               NODE          NOMINATED NODE   READINESS GATES
+pod/coredns-57fbf68cf6-2z65h   1/1     Running   1 (91d ago)   91d   10.233.105.131   worker1       <none>           <none>
+pod/coredns-57fbf68cf6-kvcwl   1/1     Running   3 (91d ago)   91d   10.233.73.195    controller    <none>           <none>
+
+NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE   SELECTOR
+service/coredns   ClusterIP   10.233.0.3   <none>        53/UDP,53/TCP,9153/TCP   91d   k8s-app=kube-dns
+
+~# Access the CoreDNS Pod across nodes
+~# kubectl  exec nginx-4653bc4f24-rswak -- ping 10.233.73.195 -c 2
+PING 10.233.73.195 (10.233.73.195): 56 data bytes
+64 bytes from 10.233.73.195: seq=0 ttl=62 time=2.348 ms
+64 bytes from 10.233.73.195: seq=1 ttl=62 time=0.586 ms
+
+--- 10.233.73.195 ping statistics ---
+2 packets transmitted, 2 packets received, 0% packet loss
+round-trip min/avg/max = 0.586/1.467/2.348 ms
+
+~# Access the CoreDNS Service
+~# kubectl exec  nginx-4653bc4f24-rswak -- curl 10.233.0.3:53 -I
+  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
+                                 Dload  Upload   Total   Spent    Left  Speed
+  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
+curl: (52) Empty reply from server
+```
+
+Test the Pod's connectivity for north-south traffic, specifically accessing targets in another subnet (10.7.212.101):
+
+```shell
+[root@controller1 cyclinder]# kubectl exec nginx-4653bc4f24-rswak -- ping 10.7.212.101 -c 2
+PING 10.7.212.101 (10.7.212.101): 56 data bytes
+64 bytes from 10.7.212.101: seq=0 ttl=61 time=4.349 ms
+64 bytes from 10.7.212.101: seq=1 ttl=61 time=0.877 ms
+
+--- 10.7.212.101 ping statistics ---
+2 packets transmitted, 2 packets received, 0% packet loss
+round-trip min/avg/max = 0.877/2.613/4.349 ms
+```
diff --git a/docs/usage/install/underlay/get-started-kind-zh_CN.md b/docs/usage/install/underlay/get-started-kind-zh_CN.md
index 1d1dcae95..f155d4892 100644
--- a/docs/usage/install/underlay/get-started-kind-zh_CN.md
+++ b/docs/usage/install/underlay/get-started-kind-zh_CN.md
@@ -26,18 +26,12 @@ Kind 是一个使用 Docker 容器节点运行本地 Kubernetes 集群的工具
 
 如果您在中国大陆，安装时可以额外指定参数 `-e E2E_CHINA_IMAGE_REGISTRY=true` ，以帮助您更快的拉取镜像。
 
-### 安装不带子网功能的 Spiderpool 在 Underlay CNI（Macvlan） 集群
+### 安装 Spiderpool 在 Underlay CNI（Macvlan） 集群
   
   ```bash
   ~# make e2e_init_underlay -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG
   ```
 
-### 安装具有子网功能的 Spiderpool 在 Underlay CNI（Macvlan）集群
-
-  ```bash
-  ~# make e2e_init_underlay_subnet -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG
-  ```
-
 ### 安装 Spiderpool 在 Calico Overlay CNI 集群
 
   ```bash
diff --git a/docs/usage/install/underlay/get-started-kind.md b/docs/usage/install/underlay/get-started-kind.md
index 57449ad7b..6982b761c 100644
--- a/docs/usage/install/underlay/get-started-kind.md
+++ b/docs/usage/install/underlay/get-started-kind.md
@@ -26,18 +26,12 @@ Kind is a tool for running local Kubernetes clusters using Docker container "nod
 
 If you are mainland user who is not available to access ghcr.io, Additional parameter `-e E2E_CHINA_IMAGE_REGISTRY=true` can be specified during installation to help you pull images faster.
 
-### Install Spiderpool without subnet function in Underlay CNI (Macvlan) cluster
+### Install Spiderpool in Underlay CNI (Macvlan) cluster
 
   ```bash
   ~# make e2e_init_underlay -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG
   ```
 
-### Install Spiderpool with subnets in Underlay CNI (Macvlan) cluster
-
-  ```bash
-  ~# make e2e_init_underlay_subnet -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG
-  ```
-
 ### Install Spiderpool on Calico Overlay CNI cluster
 
   ```bash
diff --git a/docs/usage/install/underlay/get-started-ovs-zh_CN.md b/docs/usage/install/underlay/get-started-ovs-zh_CN.md
index 0d5f04569..256436bb4 100644
--- a/docs/usage/install/underlay/get-started-ovs-zh_CN.md
+++ b/docs/usage/install/underlay/get-started-ovs-zh_CN.md
@@ -120,31 +120,23 @@ ec16d9e1-6187-4b21-9c2f-8b6cb75434b9
     ~# 
     ```
 
-4. 为 ovs-cni 创建 multus NetworkAttachmentDefinition CR
+4. Spiderpool 为简化书写 JSON 格式的 Multus CNI 配置，它提供了 SpiderMultusConfig CR 来自动管理 Multus NetworkAttachmentDefinition CR。如下是创建 Ovs SpiderMultusConfig 配置的示例：
 
-    ```bash
+* 确认 ovs-cni 所需的网桥名称，本例子以 br1 为例:
+
+    ```shell
+    BRIDGE_NAME="br1"
     cat <<EOF | kubectl apply -f -
-    apiVersion: k8s.cni.cncf.io/v1
-    kind: NetworkAttachmentDefinition
+    apiVersion: spiderpool.spidernet.io/v2beta1
+    kind: SpiderMultusConfig
     metadata:
       name: ovs-conf
       namespace: kube-system
     spec:
-      config: |-
-        {
-            "cniVersion": "0.3.1",
-            "name": "ovs-conf",
-            "plugins": [
-                {
-                    "type": "ovs",
-                    "bridge": "br1",
-                    "ipam": {
-                        "type": "spiderpool",
-                    }
-                }
-            ]
-        }
-    EOF
+      cniType: ovs
+      ovs:
+        bridge: "${BRIDGE_NAME}"
+  EOF
     ```
 
 ## 创建应用
diff --git a/docs/usage/install/underlay/get-started-ovs.md b/docs/usage/install/underlay/get-started-ovs.md
index 788f3fef6..4d06315ce 100644
--- a/docs/usage/install/underlay/get-started-ovs.md
+++ b/docs/usage/install/underlay/get-started-ovs.md
@@ -122,35 +122,23 @@ ec16d9e1-6187-4b21-9c2f-8b6cb75434b9
     ~# 
     ```
 
-4. Create a NetworkAttachmentDefinition for ovs-cni.
+4. To simplify writing Multus CNI configuration in JSON format, Spiderpool provides SpiderMultusConfig CR to automatically manage Multus NetworkAttachmentDefinition CR. Here is an example of creating an ovs-cni SpiderMultusConfig configuration:
 
-    The following parameters need to be confirmed:
+* Confirm the required host bridge for ovs-cni, for example based on the command `ovs-vsctl show`, this example takes the host bridge: `br1` as an example.
 
-     * Confirm the required host bridge for ovs-cni, for example based on the command `ovs-vsctl show`, this example takes the host bridge: `br1` as an example.
-
-    ```bash
+    ```shell
+    BRIDGE_NAME="br1"
     cat <<EOF | kubectl apply -f -
-    apiVersion: k8s.cni.cncf.io/v1
-    kind: NetworkAttachmentDefinition
+    apiVersion: spiderpool.spidernet.io/v2beta1
+    kind: SpiderMultusConfig
     metadata:
       name: ovs-conf
       namespace: kube-system
     spec:
-      config: |-
-        {
-            "cniVersion": "0.3.1",
-            "name": "ovs-conf",
-            "plugins": [
-                {
-                    "type": "ovs",
-                    "bridge": "br1",
-                    "ipam": {
-                        "type": "spiderpool",
-                    }
-                }
-            ]
-        }
-    EOF
+      cniType: ovs
+      ovs:
+        bridge: "${BRIDGE_NAME}"
+  EOF
     ```
 
 ## Create applications
diff --git a/pkg/constant/k8s.go b/pkg/constant/k8s.go
index 6fb0f65e9..2383ec78e 100644
--- a/pkg/constant/k8s.go
+++ b/pkg/constant/k8s.go
@@ -143,4 +143,5 @@ const (
 	MultusDefaultNetAnnot        = "v1.multus-cni.io/default-network"
 	MultusNetworkAttachmentAnnot = "k8s.v1.cni.cncf.io/networks"
 	ResourceNameAnnot            = "k8s.v1.cni.cncf.io/resourceName"
+	ResourceNameOvsCniValue      = "ovs-cni.network.kubevirt.io"
 )
diff --git a/pkg/ipam/allocate.go b/pkg/ipam/allocate.go
index 80c779cee..41f8a7fea 100644
--- a/pkg/ipam/allocate.go
+++ b/pkg/ipam/allocate.go
@@ -6,6 +6,7 @@ package ipam
 import (
 	"context"
 	"fmt"
+	"sort"
 	"strings"
 	"sync"
 
@@ -277,6 +278,9 @@ func (i *ipam) genToBeAllocatedSet(ctx context.Context, addArgs *models.IpamAddA
 	}
 	logger.Info("All IPPool candidates are valid")
 
+	// sort IPPool candidates
+	sortPoolCandidates(preliminary)
+
 	return preliminary, nil
 }
 
@@ -607,3 +611,27 @@ func (i *ipam) verifyPoolCandidates(tt ToBeAllocateds) error {
 
 	return nil
 }
+
+// sortPoolCandidates would sort IPPool candidates sequence depends on the IPPool multiple affinities.
+func sortPoolCandidates(preliminary ToBeAllocateds) {
+	for _, toBeAllocate := range preliminary {
+		for _, poolCandidate := range (*toBeAllocate).PoolCandidates {
+			// new IPPool candidate names
+			poolNameList := []string{}
+
+			// collect all IPPool resource from PoolCandidate.PToIPPool
+			pools := []*spiderpoolv2beta1.SpiderIPPool{}
+			for _, tmpPool := range poolCandidate.PToIPPool {
+				pools = append(pools, tmpPool.DeepCopy())
+			}
+			// make it order with ippoolmanager.ByPoolPriority interface rules
+			sort.Sort(ippoolmanager.ByPoolPriority(pools))
+			for _, tmpPool := range pools {
+				poolNameList = append(poolNameList, tmpPool.Name)
+			}
+
+			// set the new IPPool candidate names to PoolCandidate.Pools
+			(*poolCandidate).Pools = poolNameList
+		}
+	}
+}
diff --git a/pkg/ipam/pool_selections.go b/pkg/ipam/pool_selections.go
index 3dc1acf17..175b3c95a 100644
--- a/pkg/ipam/pool_selections.go
+++ b/pkg/ipam/pool_selections.go
@@ -27,15 +27,23 @@ import (
 )
 
 func (i *ipam) getPoolCandidates(ctx context.Context, addArgs *models.IpamAddArgs, pod *corev1.Pod, podController types.PodTopController) (ToBeAllocateds, error) {
+	log := logutils.FromContext(ctx)
+
 	// If feature SpiderSubnet is enabled, select IPPool candidates through the
-	// Pod annotations "ipam.spidernet.io/subnet" or "ipam.spidernet.io/subnets".
+	// Pod annotations "ipam.spidernet.io/subnet" or "ipam.spidernet.io/subnets". (expect orphan Pod controller)
 	if i.config.EnableSpiderSubnet {
 		fromSubnet, err := i.getPoolFromSubnetAnno(ctx, pod, *addArgs.IfName, addArgs.CleanGateway, podController)
 		if nil != err {
 			return nil, fmt.Errorf("failed to get IPPool candidates from Subnet: %v", err)
 		}
 		if fromSubnet != nil {
-			return ToBeAllocateds{fromSubnet}, nil
+			// The SpiderSubnet feature doesn't support orphan Pod.
+			// So the orphan pod would get the IPPool candidates from the other traditional IPPool rules.
+			if podController.APIVersion == corev1.SchemeGroupVersion.String() && podController.Kind == constant.KindPod {
+				log.Sugar().Warnf("SpiderSubnet feature doesn't support no-controller pod, try to allocate IPs in traditional IPPool way")
+			} else {
+				return ToBeAllocateds{fromSubnet}, nil
+			}
 		}
 	}
 
diff --git a/pkg/ippoolmanager/ippool_subnet_validate.go b/pkg/ippoolmanager/ippool_subnet_validate.go
index 00ba61772..cc68fe753 100644
--- a/pkg/ippoolmanager/ippool_subnet_validate.go
+++ b/pkg/ippoolmanager/ippool_subnet_validate.go
@@ -51,10 +51,7 @@ func (iw *IPPoolWebhook) validateUpdateIPPoolWhileEnableSpiderSubnet(ctx context
 func (iw *IPPoolWebhook) validateSubnetTotalIPsContainsIPPoolTotalIPs(ctx context.Context, ipPool *spiderpoolv2beta1.SpiderIPPool) *field.Error {
 	owner := metav1.GetControllerOf(ipPool)
 	if owner == nil {
-		return field.Forbidden(
-			subnetField,
-			fmt.Sprintf("orphan IPPool, must be controlled by Subnet with the same 'spec.subnet' %s", ipPool.Spec.Subnet),
-		)
+		return nil
 	}
 
 	poolTotalIPs, err := spiderpoolip.AssembleTotalIPs(*ipPool.Spec.IPVersion, ipPool.Spec.IPs, ipPool.Spec.ExcludeIPs)
diff --git a/pkg/ippoolmanager/ippool_validate.go b/pkg/ippoolmanager/ippool_validate.go
index c02e2aa9b..92b4af093 100644
--- a/pkg/ippoolmanager/ippool_validate.go
+++ b/pkg/ippoolmanager/ippool_validate.go
@@ -189,10 +189,6 @@ func (iw *IPPoolWebhook) validateIPPoolCIDR(ctx context.Context, ipPool *spiderp
 		)
 	}
 
-	if iw.EnableSpiderSubnet {
-		return nil
-	}
-
 	// TODO(iiiceoo): Use label selector.
 	var ipPoolList spiderpoolv2beta1.SpiderIPPoolList
 	if err := iw.APIReader.List(ctx, &ipPoolList); err != nil {
diff --git a/pkg/ippoolmanager/utils.go b/pkg/ippoolmanager/utils.go
index 83a670317..47d9235d2 100644
--- a/pkg/ippoolmanager/utils.go
+++ b/pkg/ippoolmanager/utils.go
@@ -4,6 +4,7 @@
 package ippoolmanager
 
 import (
+	"sort"
 	"strings"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -65,3 +66,60 @@ func IsMatchAutoPoolAffinity(podAffinity *metav1.LabelSelector, podTopController
 
 	return true
 }
+
+// ByPoolPriority implements sort.Interface
+var _ sort.Interface = &ByPoolPriority{}
+
+type ByPoolPriority []*spiderpoolv2beta1.SpiderIPPool
+
+func (b ByPoolPriority) Len() int { return len(b) }
+
+func (b ByPoolPriority) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+func (b ByPoolPriority) Less(i, j int) bool {
+	// Pod Affinity
+	if b[i].Spec.PodAffinity != nil && b[j].Spec.PodAffinity == nil {
+		return true
+	}
+	if b[i].Spec.PodAffinity == nil && b[j].Spec.PodAffinity != nil {
+		return false
+	}
+
+	// Node Affinity
+	if len(b[i].Spec.NodeName) != 0 && len(b[j].Spec.NodeName) == 0 {
+		return true
+	}
+	if len(b[i].Spec.NodeName) == 0 && len(b[j].Spec.NodeName) != 0 {
+		return false
+	}
+	if b[i].Spec.NodeAffinity != nil && b[j].Spec.NodeAffinity == nil {
+		return true
+	}
+	if b[i].Spec.NodeAffinity == nil && b[j].Spec.NodeAffinity != nil {
+		return false
+	}
+
+	// Namespace Affinity
+	if len(b[i].Spec.NamespaceName) != 0 && len(b[j].Spec.NamespaceName) == 0 {
+		return true
+	}
+	if len(b[i].Spec.NamespaceName) == 0 && len(b[j].Spec.NamespaceName) != 0 {
+		return false
+	}
+	if b[i].Spec.NamespaceAffinity != nil && b[j].Spec.NamespaceAffinity == nil {
+		return true
+	}
+	if b[i].Spec.NamespaceAffinity == nil && b[j].Spec.NamespaceAffinity != nil {
+		return false
+	}
+
+	// Multus Name
+	if len(b[i].Spec.MultusName) != 0 && len(b[j].Spec.MultusName) == 0 {
+		return true
+	}
+	if len(b[i].Spec.MultusName) == 0 && len(b[j].Spec.MultusName) != 0 {
+		return false
+	}
+
+	return false
+}
diff --git a/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1/spidermultus_types.go b/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1/spidermultus_types.go
index 7141226ce..937566d73 100644
--- a/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1/spidermultus_types.go
+++ b/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1/spidermultus_types.go
@@ -28,7 +28,7 @@ type SpiderMultusConfigList struct {
 // MultusCNIConfigSpec defines the desired state of SpiderMultusConfig.
 type MultusCNIConfigSpec struct {
 	// +kubebuilder:validation:Required
-	// +kubebuilder:validation:Enum=macvlan;ipvlan;sriov;custom
+	// +kubebuilder:validation:Enum=macvlan;ipvlan;sriov;ovs;custom
 	CniType string `json:"cniType"`
 
 	// +kubebuilder:validation:Optional
@@ -40,6 +40,9 @@ type MultusCNIConfigSpec struct {
 	// +kubebuilder:validation:Optional
 	SriovConfig *SpiderSRIOVCniConfig `json:"sriov,omitempty"`
 
+	// +kubebuilder:validation:Optional
+	OvsConfig *SpiderOvsCniConfig `json:"ovs,omitempty"`
+
 	// +kubebuilder:default=true
 	// +kubebuilder:validation:Optional
 	EnableCoordinator *bool `json:"enableCoordinator"`
@@ -97,6 +100,35 @@ type SpiderSRIOVCniConfig struct {
 	SpiderpoolConfigPools *SpiderpoolPools `json:"ippools,omitempty"`
 }
 
+type SpiderOvsCniConfig struct {
+	// +kubebuilder:validation:Required
+	BrName string `json:"bridge"`
+	// +kubebuilder:validation:Optional
+	VlanTag *int32 `json:"vlan"`
+	// +kubebuilder:validation:Optional
+	Trunk []*Trunk `json:"trunk,omitempty"`
+	// +kubebuilder:validation:Optional
+	// PCI address of a VF in valid sysfs format
+	DeviceID string `json:"deviceID"`
+	// +kubebuilder:validation:Optional
+	SpiderpoolConfigPools *SpiderpoolPools `json:"ippools,omitempty"`
+}
+
+type Trunk struct {
+	// +kubebuilder:validation:Optional
+	// +kubebuilder:validation:Minimum=0
+	// +kubebuilder:validation:Maximum=4094
+	MinID *uint `json:"minID,omitempty"`
+	// +kubebuilder:validation:Optional
+	// +kubebuilder:validation:Minimum=0
+	// +kubebuilder:validation:Maximum=4094
+	MaxID *uint `json:"maxID,omitempty"`
+	// +kubebuilder:validation:Optional
+	// +kubebuilder:validation:Minimum=0
+	// +kubebuilder:validation:Maximum=4094
+	ID *uint `json:"id,omitempty"`
+}
+
 type BondConfig struct {
 	// +kubebuilder:validation:Required
 	Name string `json:"name"`
diff --git a/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1/zz_generated.deepcopy.go b/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1/zz_generated.deepcopy.go
index a71d247e3..67ae638f9 100644
--- a/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1/zz_generated.deepcopy.go
+++ b/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1/zz_generated.deepcopy.go
@@ -316,6 +316,11 @@ func (in *MultusCNIConfigSpec) DeepCopyInto(out *MultusCNIConfigSpec) {
 		*out = new(SpiderSRIOVCniConfig)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.OvsConfig != nil {
+		in, out := &in.OvsConfig, &out.OvsConfig
+		*out = new(SpiderOvsCniConfig)
+		(*in).DeepCopyInto(*out)
+	}
 	if in.EnableCoordinator != nil {
 		in, out := &in.EnableCoordinator, &out.EnableCoordinator
 		*out = new(bool)
@@ -791,6 +796,42 @@ func (in *SpiderMultusConfigList) DeepCopyObject() runtime.Object {
 	return nil
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SpiderOvsCniConfig) DeepCopyInto(out *SpiderOvsCniConfig) {
+	*out = *in
+	if in.VlanTag != nil {
+		in, out := &in.VlanTag, &out.VlanTag
+		*out = new(int32)
+		**out = **in
+	}
+	if in.Trunk != nil {
+		in, out := &in.Trunk, &out.Trunk
+		*out = make([]*Trunk, len(*in))
+		for i := range *in {
+			if (*in)[i] != nil {
+				in, out := &(*in)[i], &(*out)[i]
+				*out = new(Trunk)
+				(*in).DeepCopyInto(*out)
+			}
+		}
+	}
+	if in.SpiderpoolConfigPools != nil {
+		in, out := &in.SpiderpoolConfigPools, &out.SpiderpoolConfigPools
+		*out = new(SpiderpoolPools)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpiderOvsCniConfig.
+func (in *SpiderOvsCniConfig) DeepCopy() *SpiderOvsCniConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(SpiderOvsCniConfig)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SpiderReservedIP) DeepCopyInto(out *SpiderReservedIP) {
 	*out = *in
@@ -1033,6 +1074,36 @@ func (in *SubnetStatus) DeepCopy() *SubnetStatus {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Trunk) DeepCopyInto(out *Trunk) {
+	*out = *in
+	if in.MinID != nil {
+		in, out := &in.MinID, &out.MinID
+		*out = new(uint)
+		**out = **in
+	}
+	if in.MaxID != nil {
+		in, out := &in.MaxID, &out.MaxID
+		*out = new(uint)
+		**out = **in
+	}
+	if in.ID != nil {
+		in, out := &in.ID, &out.ID
+		*out = new(uint)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Trunk.
+func (in *Trunk) DeepCopy() *Trunk {
+	if in == nil {
+		return nil
+	}
+	out := new(Trunk)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *WorkloadEndpointStatus) DeepCopyInto(out *WorkloadEndpointStatus) {
 	*out = *in
diff --git a/pkg/multuscniconfig/multusconfig_informer.go b/pkg/multuscniconfig/multusconfig_informer.go
index 74e4821a6..2acc282c2 100644
--- a/pkg/multuscniconfig/multusconfig_informer.go
+++ b/pkg/multuscniconfig/multusconfig_informer.go
@@ -11,7 +11,6 @@ import (
 	"reflect"
 	"time"
 
-	"github.com/containernetworking/cni/pkg/types"
 	netv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
 	"go.uber.org/zap"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -21,12 +20,10 @@ import (
 	"k8s.io/apimachinery/pkg/util/wait"
 	"k8s.io/client-go/tools/cache"
 	"k8s.io/client-go/util/workqueue"
-	"k8s.io/utils/pointer"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
 	coordinatorcmd "github.com/spidernet-io/spiderpool/cmd/coordinator/cmd"
-	ifacercmd "github.com/spidernet-io/spiderpool/cmd/ifacer/cmd"
 	"github.com/spidernet-io/spiderpool/cmd/spiderpool/cmd"
 	spiderpoolcmd "github.com/spidernet-io/spiderpool/cmd/spiderpool/cmd"
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -408,7 +405,17 @@ func generateNetAttachDef(netAttachName string, multusConf *spiderpoolv2beta1.Sp
 
 		confStr, err = marshalCniConfig2String(netAttachName, cniVersion, plugins)
 		if err != nil {
-			return nil, fmt.Errorf("failed to marshalCniConfig2String: %w", err)
+			return nil, fmt.Errorf("failed to marshal sriov cniConfig to String: %w", err)
+		}
+	case OvsType:
+		ovsConf := generateOvsCNIConf(multusConfSpec)
+		plugins = append([]interface{}{ovsConf}, plugins...)
+		confStr, err = marshalCniConfig2String(netAttachName, cniVersion, plugins)
+		if err != nil {
+			return nil, fmt.Errorf("failed to marshal ovs cniConfig to String: %w", err)
+		}
+		if multusConfSpec.OvsConfig.DeviceID != "" {
+			anno[constant.ResourceNameAnnot] = fmt.Sprintf("%s/%s", constant.ResourceNameOvsCniValue, multusConfSpec.OvsConfig.BrName)
 		}
 	case CustomType:
 		if multusConfSpec.CustomCNIConfig != nil && len(*multusConfSpec.CustomCNIConfig) > 0 {
@@ -528,34 +535,51 @@ func generateSriovCNIConf(multusConfSpec spiderpoolv2beta1.MultusCNIConfigSpec)
 	return netConf
 }
 
+func generateOvsCNIConf(multusConfSpec *spiderpoolv2beta1.MultusCNIConfigSpec) interface{} {
+	netConf := OvsNetConf{
+		Type: OvsType,
+		IPAM: spiderpoolcmd.IPAMConfig{
+			Type: constant.Spiderpool,
+		},
+	}
+
+	if multusConfSpec.OvsConfig != nil {
+		if multusConfSpec.OvsConfig.VlanTag != nil {
+			netConf.Vlan = multusConfSpec.OvsConfig.VlanTag
+		}
+
+		if len(multusConfSpec.OvsConfig.Trunk) > 0 {
+			netConf.Trunk = multusConfSpec.OvsConfig.Trunk
+		}
+
+		if multusConfSpec.OvsConfig.SpiderpoolConfigPools != nil {
+			netConf.IPAM.DefaultIPv4IPPool = multusConfSpec.OvsConfig.SpiderpoolConfigPools.IPv4IPPool
+			netConf.IPAM.DefaultIPv6IPPool = multusConfSpec.OvsConfig.SpiderpoolConfigPools.IPv6IPPool
+		}
+
+		netConf.BrName = multusConfSpec.OvsConfig.BrName
+		netConf.DeviceID = multusConfSpec.OvsConfig.DeviceID
+	}
+	return netConf
+}
+
 func generateIfacer(master []string, vlanID int32, bond *spiderpoolv2beta1.BondConfig) interface{} {
 	netConf := IfacerNetConf{
-		NetConf: types.NetConf{
-			Type: constant.Ifacer,
-		},
+		Type:       constant.Ifacer,
 		Interfaces: master,
 		VlanID:     int(vlanID),
 	}
 
 	if bond != nil {
-		netConf.Bond = &ifacercmd.Bond{
-			Name: bond.Name,
-			Mode: int(bond.Mode),
-		}
-
-		if bond.Options != nil {
-			netConf.Bond.Options = *bond.Options
-		}
+		netConf.Bond = bond
 	}
 
 	return netConf
 }
 
 func generateCoordinatorCNIConf(coordinatorSpec *spiderpoolv2beta1.CoordinatorSpec) interface{} {
-	coordinatorNetConf := coordinatorcmd.Config{
-		NetConf: types.NetConf{
-			Type: constant.Coordinator,
-		},
+	coordinatorNetConf := CoordinatorConfig{
+		Type: constant.Coordinator,
 	}
 
 	// coordinatorSpec could be nil, and we just need the coorinator CNI specified and use the default configuration
@@ -569,18 +593,9 @@ func generateCoordinatorCNIConf(coordinatorSpec *spiderpoolv2beta1.CoordinatorSp
 		if coordinatorSpec.PodMACPrefix != nil {
 			coordinatorNetConf.MacPrefix = *coordinatorSpec.PodMACPrefix
 		}
-		if coordinatorSpec.TunePodRoutes != nil {
-			coordinatorNetConf.TunePodRoutes = coordinatorSpec.TunePodRoutes
-		}
 		if coordinatorSpec.PodDefaultRouteNIC != nil {
 			coordinatorNetConf.PodDefaultRouteNIC = *coordinatorSpec.PodDefaultRouteNIC
 		}
-		if coordinatorSpec.HostRuleTable != nil {
-			coordinatorNetConf.HostRuleTable = pointer.Int64(int64(*coordinatorSpec.HostRuleTable))
-		}
-		if coordinatorSpec.HostRPFilter != nil {
-			coordinatorNetConf.RPFilter = int32(*coordinatorSpec.HostRPFilter)
-		}
 		if coordinatorSpec.DetectIPConflict != nil {
 			coordinatorNetConf.IPConflict = coordinatorSpec.DetectIPConflict
 		}
diff --git a/pkg/multuscniconfig/multusconfig_validate.go b/pkg/multuscniconfig/multusconfig_validate.go
index dd3616a26..9a7b848b1 100644
--- a/pkg/multuscniconfig/multusconfig_validate.go
+++ b/pkg/multuscniconfig/multusconfig_validate.go
@@ -22,6 +22,7 @@ var (
 	macvlanConfigField   = field.NewPath("spec").Child("macvlanConfig")
 	ipvlanConfigField    = field.NewPath("spec").Child("ipvlanConfig")
 	sriovConfigField     = field.NewPath("spec").Child("sriovConfig")
+	ovsConfigField       = field.NewPath("spec").Child("ovsConfig")
 	customCniConfigField = field.NewPath("spec").Child("customCniTypeConfig")
 	annotationField      = field.NewPath("metadata").Child("annotations")
 )
@@ -106,6 +107,39 @@ func validateCNIConfig(multusConfig *spiderpoolv2beta1.SpiderMultusConfig) *fiel
 			return field.Forbidden(cniTypeField, fmt.Sprintf("the cniType %s only supports %s, please remove other CNI configs", SriovType, sriovConfigField.String()))
 		}
 
+	case OvsType:
+		if multusConfig.Spec.OvsConfig == nil {
+			return field.Required(sriovConfigField, fmt.Sprintf("no %s specified", ovsConfigField.String()))
+		}
+
+		if multusConfig.Spec.OvsConfig.VlanTag != nil {
+			if err := validateVlanId(*multusConfig.Spec.OvsConfig.VlanTag); err != nil {
+				return field.Invalid(ovsConfigField, *multusConfig.Spec.OvsConfig.VlanTag, err.Error())
+			}
+		}
+
+		for idx, trunk := range multusConfig.Spec.OvsConfig.Trunk {
+			if trunk.MinID != nil {
+				if *trunk.MinID > 4094 {
+					return field.Invalid(ovsConfigField, multusConfig.Spec.OvsConfig.Trunk[idx], "incorrect trunk minID parameter")
+				}
+			}
+			if trunk.MaxID != nil {
+				if *trunk.MaxID > 4094 {
+					return field.Invalid(ovsConfigField, multusConfig.Spec.OvsConfig.Trunk[idx], "incorrect trunk maxID parameter")
+				}
+				if *trunk.MaxID < *trunk.MinID {
+					return field.Invalid(ovsConfigField, multusConfig.Spec.OvsConfig.Trunk[idx], "minID is greater than maxID in trunk parameter")
+				}
+			}
+
+			if trunk.ID != nil {
+				if *trunk.ID > 4096 {
+					return field.Invalid(ovsConfigField, multusConfig.Spec.OvsConfig.Trunk[idx], "incorrect trunk id parameter")
+				}
+			}
+		}
+
 	case CustomType:
 		// multusConfig.Spec.CustomCNIConfig can be empty
 		if multusConfig.Spec.MacvlanConfig != nil || multusConfig.Spec.IPVlanConfig != nil || multusConfig.Spec.SriovConfig != nil {
diff --git a/pkg/multuscniconfig/utils.go b/pkg/multuscniconfig/utils.go
index 605b4de35..42aae0bd4 100644
--- a/pkg/multuscniconfig/utils.go
+++ b/pkg/multuscniconfig/utils.go
@@ -28,38 +28,66 @@ import (
 
 	netv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
 
-	ifacercmd "github.com/spidernet-io/spiderpool/cmd/ifacer/cmd"
+	coordinatorcmd "github.com/spidernet-io/spiderpool/cmd/coordinator/cmd"
 	spiderpoolcmd "github.com/spidernet-io/spiderpool/cmd/spiderpool/cmd"
+	spiderpoolv2beta1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1"
 )
 
 const (
 	MacVlanType = "macvlan"
 	IpVlanType  = "ipvlan"
 	SriovType   = "sriov"
+	OvsType     = "ovs"
 	CustomType  = "custom"
 )
 
 type MacvlanNetConf struct {
 	Type   string                   `json:"type"`
-	IPAM   spiderpoolcmd.IPAMConfig `json:"ipam"`
 	Master string                   `json:"master"`
 	Mode   string                   `json:"mode"`
+	IPAM   spiderpoolcmd.IPAMConfig `json:"ipam"`
 }
 
 type IPvlanNetConf struct {
 	Type   string                   `json:"type"`
-	IPAM   spiderpoolcmd.IPAMConfig `json:"ipam"`
 	Master string                   `json:"master"`
+	IPAM   spiderpoolcmd.IPAMConfig `json:"ipam"`
 }
 
 type SRIOVNetConf struct {
-	Type     string                   `json:"type"`
-	IPAM     spiderpoolcmd.IPAMConfig `json:"ipam"`
 	Vlan     *int32                   `json:"vlan,omitempty"`
+	Type     string                   `json:"type"`
 	DeviceID string                   `json:"deviceID,omitempty"`
+	IPAM     spiderpoolcmd.IPAMConfig `json:"ipam"`
+}
+
+type OvsNetConf struct {
+	Vlan     *int32                     `json:"vlan,omitempty"`
+	Type     string                     `json:"type"`
+	BrName   string                     `json:"bridge"`
+	DeviceID string                     `json:"deviceID,omitempty"`
+	IPAM     spiderpoolcmd.IPAMConfig   `json:"ipam"`
+	Trunk    []*spiderpoolv2beta1.Trunk `json:"trunk,omitempty"`
 }
 
-type IfacerNetConf = ifacercmd.Ifacer
+type IfacerNetConf struct {
+	VlanID     int                           `json:"vlanID,omitempty"`
+	Type       string                        `json:"type"`
+	Interfaces []string                      `json:"interfaces,omitempty"`
+	Bond       *spiderpoolv2beta1.BondConfig `json:"bond,omitempty"`
+}
+
+type CoordinatorConfig struct {
+	IPConflict         *bool               `json:"detectIPConflict,omitempty"`
+	DetectGateway      *bool               `json:"detectGateway,omitempty"`
+	MacPrefix          string              `json:"podMACPrefix,omitempty"`
+	Mode               coordinatorcmd.Mode `json:"mode,omitempty"`
+	Type               string              `json:"type"`
+	PodDefaultRouteNIC string              `json:"podDefaultRouteNic,omitempty"`
+	OverlayPodCIDR     []string            `json:"overlayPodCIDR,omitempty"`
+	ServiceCIDR        []string            `json:"serviceCIDR,omitempty"`
+	HijackCIDR         []string            `json:"hijackCIDR,omitempty"`
+}
 
 func ParsePodNetworkAnnotation(podNetworks, defaultNamespace string) ([]*netv1.NetworkSelectionElement, error) {
 	var networks []*netv1.NetworkSelectionElement
diff --git a/pkg/subnetmanager/subnet_informer.go b/pkg/subnetmanager/subnet_informer.go
index 095351f32..05d531205 100644
--- a/pkg/subnetmanager/subnet_informer.go
+++ b/pkg/subnetmanager/subnet_informer.go
@@ -218,6 +218,7 @@ func (sc *SubnetController) enqueueSubnetOnUpdate(oldObj, newObj interface{}) {
 	logger.Debug(messageEnqueueSubnet)
 }
 
+// enqueueSubnetOnIPPoolChange receives the IPPool resources events
 func (sc *SubnetController) enqueueSubnetOnIPPoolChange(obj interface{}) {
 	ipPool := obj.(*spiderpoolv2beta1.SpiderIPPool)
 	ownerSubnet, ok := ipPool.Labels[constant.LabelIPPoolOwnerSpiderSubnet]
@@ -384,6 +385,7 @@ func (sc *SubnetController) syncHandler(ctx context.Context, subnetName string)
 	return nil
 }
 
+// syncMetadata add "ipam.spidernet.io/subnet-cidr" label for the SpiderSubnet object
 func (sc *SubnetController) syncMetadata(ctx context.Context, subnet *spiderpoolv2beta1.SpiderSubnet) error {
 	cidr, err := spiderpoolip.CIDRToLabelValue(*subnet.Spec.IPVersion, subnet.Spec.Subnet)
 	if err != nil {
@@ -406,6 +408,7 @@ func (sc *SubnetController) syncMetadata(ctx context.Context, subnet *spiderpool
 	return nil
 }
 
+// syncControllerSubnet would set ownerReference and add "ipam.spidernet.io/owner-spider-subnet" label for the previous orphan IPPool
 func (sc *SubnetController) syncControllerSubnet(ctx context.Context, subnet *spiderpoolv2beta1.SpiderSubnet) error {
 	ipPools, err := sc.IPPoolsLister.List(labels.Everything())
 	if err != nil {
diff --git a/pkg/subnetmanager/subnet_validate.go b/pkg/subnetmanager/subnet_validate.go
index 770500bdd..84effa05c 100644
--- a/pkg/subnetmanager/subnet_validate.go
+++ b/pkg/subnetmanager/subnet_validate.go
@@ -211,6 +211,49 @@ func (sw *SubnetWebhook) validateSubnetCIDR(ctx context.Context, subnet *spiderp
 		}
 	}
 
+	return sw.validateOrphanIPPool(ctx, subnet)
+}
+
+// validateOrphanIPPool will check the SpiderSubnet.Spec.Subnet whether overlaps with the cluster orphan SpiderIPPool.Spec.Subnet.
+// And we also require the IPPool.Spec.IPs belong to Subnet.Spec.IPs if they are in the same subnet
+func (sw *SubnetWebhook) validateOrphanIPPool(ctx context.Context, subnet *spiderpoolv2beta1.SpiderSubnet) *field.Error {
+	poolList := spiderpoolv2beta1.SpiderIPPoolList{}
+	err := sw.APIReader.List(ctx, &poolList)
+	if nil != err {
+		return field.InternalError(subnetField, fmt.Errorf("failed to list IPPools: %v", err))
+	}
+
+	for _, tmpPool := range poolList.Items {
+		if *tmpPool.Spec.IPVersion != *subnet.Spec.IPVersion {
+			continue
+		}
+
+		// validate the Spec.Subnet whether overlaps or not
+		if tmpPool.Spec.Subnet != subnet.Spec.Subnet {
+			isCIDROverlap, err := spiderpoolip.IsCIDROverlap(*subnet.Spec.IPVersion, tmpPool.Spec.Subnet, subnet.Spec.Subnet)
+			if nil != err {
+				return field.InternalError(subnetField, fmt.Errorf("failed to compare whether 'spec.subnet' overlaps with SpiderIPPool '%s', error: %v", tmpPool.Name, err))
+			}
+			if isCIDROverlap {
+				return field.Invalid(subnetField, subnet.Spec.Subnet, fmt.Sprintf("overlap with SpiderIPPool '%s' resource 'spec.subnet' %s", tmpPool.Name, tmpPool.Spec.Subnet))
+			}
+		} else {
+			// validate the Spec.IPs whether contains or not
+			poolIPs, err := spiderpoolip.AssembleTotalIPs(*tmpPool.Spec.IPVersion, tmpPool.Spec.IPs, tmpPool.Spec.ExcludeIPs)
+			if nil != err {
+				return field.InternalError(ipsField, fmt.Errorf("failed to assemble the total IP addresses of the IPPool '%s', error: %v", tmpPool.Name, err))
+			}
+			subnetIPs, err := spiderpoolip.AssembleTotalIPs(*subnet.Spec.IPVersion, subnet.Spec.IPs, subnet.Spec.ExcludeIPs)
+			if nil != err {
+				return field.InternalError(ipsField, fmt.Errorf("failed to assemble the total IP addresses of the Subnet '%s', error: %v", subnet.Name, err))
+			}
+			diffSet := spiderpoolip.IPsDiffSet(poolIPs, subnetIPs, false)
+			if len(diffSet) != 0 {
+				return field.Invalid(ipsField, subnet.Spec.IPs, fmt.Sprintf("SpiderIPPool '%s' owns some IP addresses that SpiderSubnet '%s' can't control", tmpPool.Name, subnet.Name))
+			}
+		}
+	}
+
 	return nil
 }
 


Test patch:
diff --git a/.github/workflows/e2e-init.yaml b/.github/workflows/e2e-init.yaml
index a97a96024..f63576146 100644
--- a/.github/workflows/e2e-init.yaml
+++ b/.github/workflows/e2e-init.yaml
@@ -37,8 +37,6 @@ jobs:
         include:
           - e2e_init_mode: e2e_init_underlay
             e2e_test_mode: e2e_test_underlay
-          - e2e_init_mode: e2e_init_underlay_subnet
-            e2e_test_mode: e2e_test_underlay_subnet
           - e2e_init_mode: e2e_init_calico
             e2e_test_mode: e2e_test_calico
           - e2e_init_mode: e2e_init_cilium
@@ -186,7 +184,7 @@ jobs:
 
       - name: Get the E2E Performance Result For Dual-stack
         id: get_performance
-        if: ${{ inputs.run_e2e == 'true' && inputs.ip_family == 'dual' && ( matrix.e2e_test_mode == 'e2e_test_underlay' || matrix.e2e_test_mode == 'e2e_test_underlay_subnet' ) }}
+        if: ${{ inputs.run_e2e == 'true' && inputs.ip_family == 'dual' && matrix.e2e_test_mode == 'e2e_test_underlay' }}
         shell: bash
         run: |
           # sudo apt-get install -y jq
diff --git a/pkg/ippoolmanager/ippool_webhook_test.go b/pkg/ippoolmanager/ippool_webhook_test.go
index 356083f7f..556602be4 100644
--- a/pkg/ippoolmanager/ippool_webhook_test.go
+++ b/pkg/ippoolmanager/ippool_webhook_test.go
@@ -1053,7 +1053,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					ipPoolWebhook.EnableSpiderSubnet = true
 				})
 
-				It("is orphan IPPool", func() {
+				It("succeed to create orphan IPPool", func() {
 					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
 					ipPoolT.Spec.Subnet = "172.18.40.0/24"
 					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
@@ -1064,7 +1064,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					)
 
 					err := ipPoolWebhook.ValidateCreate(ctx, ipPoolT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
+					Expect(err).NotTo(HaveOccurred())
 				})
 
 				It("sets owner reference to non-existent Subnet", func() {
@@ -1786,7 +1786,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					ipPoolWebhook.EnableSpiderSubnet = true
 				})
 
-				It("updates orphan IPPool", func() {
+				It("succeed to update orphan IPPool", func() {
 					ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
 					ipPoolT.Spec.Subnet = "172.18.40.0/24"
 					ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs, "172.18.40.1-172.18.40.2")
@@ -1795,7 +1795,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() {
 					newIPPoolT.Spec.IPs = append(newIPPoolT.Spec.IPs, "172.18.40.10")
 
 					err := ipPoolWebhook.ValidateUpdate(ctx, ipPoolT, newIPPoolT)
-					Expect(apierrors.IsInvalid(err)).To(BeTrue())
+					Expect(err).NotTo(HaveOccurred())
 				})
 
 				It("updates the IPPool that sets the owner reference to non-existent Subnet", func() {
diff --git a/pkg/ippoolmanager/utils_test.go b/pkg/ippoolmanager/utils_test.go
index d1136bb6e..4249a65dd 100644
--- a/pkg/ippoolmanager/utils_test.go
+++ b/pkg/ippoolmanager/utils_test.go
@@ -4,9 +4,12 @@
 package ippoolmanager
 
 import (
+	"sort"
+
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	appsv1 "k8s.io/api/apps/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	types2 "k8s.io/apimachinery/pkg/types"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -73,4 +76,218 @@ var _ = Describe("IPPoolManager-utils", Label("ippool_manager_utils"), func() {
 		})
 	})
 
+	Context("Test IPAM pool candidates order selections", func() {
+		poolTemplate := &spiderpoolv2beta1.SpiderIPPool{}
+
+		Context("IPPool with PodAffinity", func() {
+			var pool1, pool2 *spiderpoolv2beta1.SpiderIPPool
+			BeforeEach(func() {
+				pool1 = poolTemplate.DeepCopy()
+				pool1.SetName("pool1")
+				pool1.Spec.PodAffinity = &metav1.LabelSelector{
+					MatchLabels: map[string]string{
+						"PodAffinityKey": "PodAffinityValue1",
+					},
+				}
+
+				pool2 = poolTemplate.DeepCopy()
+				pool2.SetName("pool2")
+			})
+
+			It("preorder", func() {
+				byPoolPriority := ByPoolPriority{pool1, pool2}
+				sort.Sort(byPoolPriority)
+				Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+			})
+
+			It("postorder", func() {
+				byPoolPriority := ByPoolPriority{pool2, pool1}
+				sort.Sort(byPoolPriority)
+				Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+			})
+		})
+
+		Context("IPPool with NodeAffinity", func() {
+			var pool1, pool2 *spiderpoolv2beta1.SpiderIPPool
+			BeforeEach(func() {
+				pool1 = poolTemplate.DeepCopy()
+				pool1.SetName("pool1")
+				pool1.Spec.NodeAffinity = &metav1.LabelSelector{
+					MatchLabels: map[string]string{
+						"NodeAffinityKey": "NodeAffinityValue1",
+					},
+				}
+
+				pool2 = poolTemplate.DeepCopy()
+				pool2.SetName("pool2")
+			})
+
+			It("preorder", func() {
+				byPoolPriority := ByPoolPriority{pool1, pool2}
+				sort.Sort(byPoolPriority)
+				Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+			})
+
+			It("postorder", func() {
+				byPoolPriority := ByPoolPriority{pool2, pool1}
+				sort.Sort(byPoolPriority)
+				Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+			})
+		})
+
+		Context("IPPool with NamespaceAffinity", func() {
+			var pool1, pool2 *spiderpoolv2beta1.SpiderIPPool
+			BeforeEach(func() {
+				pool1 = poolTemplate.DeepCopy()
+				pool1.SetName("pool1")
+				pool1.Spec.NamespaceAffinity = &metav1.LabelSelector{
+					MatchLabels: map[string]string{
+						"NamespaceAffinityKey": "NamespaceAffinityValue1",
+					},
+				}
+
+				pool2 = poolTemplate.DeepCopy()
+				pool2.SetName("pool2")
+			})
+
+			It("preorder", func() {
+				byPoolPriority := ByPoolPriority{pool1, pool2}
+				sort.Sort(byPoolPriority)
+				Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+			})
+
+			It("postorder", func() {
+				byPoolPriority := ByPoolPriority{pool2, pool1}
+				sort.Sort(byPoolPriority)
+				Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+			})
+		})
+
+		Context("IPPool with MultusName", func() {
+			var pool1, pool2 *spiderpoolv2beta1.SpiderIPPool
+			BeforeEach(func() {
+				pool1 = poolTemplate.DeepCopy()
+				pool1.SetName("pool1")
+				pool1.Spec.MultusName = []string{"kube-system/macvlan"}
+
+				pool2 = poolTemplate.DeepCopy()
+				pool2.SetName("pool2")
+			})
+
+			It("preorder", func() {
+				byPoolPriority := ByPoolPriority{pool1, pool2}
+				sort.Sort(byPoolPriority)
+				Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+			})
+
+			It("postorder", func() {
+				byPoolPriority := ByPoolPriority{pool2, pool1}
+				sort.Sort(byPoolPriority)
+				Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+			})
+		})
+
+		It("no any affinities", func() {
+			pool1 := poolTemplate.DeepCopy()
+			pool1.SetName("pool1")
+			pool2 := poolTemplate.DeepCopy()
+			pool2.SetName("pool2")
+
+			byPoolPriority := ByPoolPriority{pool1, pool2}
+			sort.Sort(byPoolPriority)
+			Expect(byPoolPriority).To(Equal(ByPoolPriority{pool1, pool2}))
+		})
+
+		It("pool affinity priority in sequence", func() {
+			pool1 := poolTemplate.DeepCopy()
+			pool1.SetName("pool1")
+			pool1.Spec.PodAffinity = &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"PodAffinityKey": "PodAffinityValue1",
+				},
+			}
+
+			pool2 := poolTemplate.DeepCopy()
+			pool2.SetName("pool2")
+			pool2.Spec.NodeName = []string{"master"}
+			pool2.Spec.NodeAffinity = &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"NodeAffinityKey1": "NodeAffinityValue1",
+				},
+			}
+
+			pool3 := poolTemplate.DeepCopy()
+			pool3.SetName("pool3")
+			pool3.Spec.NamespaceName = []string{"kube-system"}
+			pool3.Spec.NamespaceAffinity = &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"NamespaceAffinityKey1": "NamespaceAffinityValue1",
+				},
+			}
+
+			pool4 := poolTemplate.DeepCopy()
+			pool4.SetName("pool4")
+			pool4.Spec.MultusName = []string{"kube-system/macvlan"}
+
+			pool5 := poolTemplate.DeepCopy()
+			pool5.SetName("pool5")
+
+			byPoolPriority := ByPoolPriority{pool1, pool2, pool3, pool4, pool5}
+			sort.Sort(byPoolPriority)
+			Expect(byPoolPriority).Should(Equal(ByPoolPriority{pool1, pool2, pool3, pool4, pool5}))
+		})
+
+		It("pool affinity priority in multiple cases", func() {
+			pool1 := poolTemplate.DeepCopy()
+			pool1.SetName("pool1")
+			pool1.Spec.PodAffinity = &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"PodAffinityKey": "PodAffinityValue1",
+				},
+			}
+
+			pool2 := poolTemplate.DeepCopy()
+			pool2.SetName("pool2")
+			pool2.Spec.NodeName = []string{"master"}
+
+			pool3 := poolTemplate.DeepCopy()
+			pool3.SetName("pool3")
+			pool3.Spec.NodeName = []string{"master"}
+			pool3.Spec.NamespaceName = []string{"kube-system"}
+
+			pool4 := poolTemplate.DeepCopy()
+			pool4.SetName("pool4")
+			pool4.Spec.NamespaceName = []string{"kube-system"}
+			pool4.Spec.MultusName = []string{"kube-system/macvlan"}
+
+			byPoolPriority := ByPoolPriority{pool1, pool2, pool3, pool4}
+			sort.Sort(byPoolPriority)
+			Expect(byPoolPriority).Should(Equal(ByPoolPriority{pool1, pool3, pool2, pool4}))
+		})
+
+		It("pool affinity priority in chaos cases", func() {
+			pool1 := poolTemplate.DeepCopy()
+			pool1.SetName("pool1")
+			pool1.Spec.PodAffinity = &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"PodAffinityKey": "PodAffinityValue1",
+				},
+			}
+			pool1.Spec.NamespaceName = []string{"kube-system"}
+			pool1.Spec.MultusName = []string{"kube-system/macvlan"}
+
+			pool2 := poolTemplate.DeepCopy()
+			pool2.SetName("pool2")
+			pool2.Spec.PodAffinity = &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"PodAffinityKey": "PodAffinityValue1",
+				},
+			}
+			pool2.Spec.NodeName = []string{"master"}
+
+			byPoolPriority := ByPoolPriority{pool1, pool2}
+			sort.Sort(byPoolPriority)
+			Expect(byPoolPriority).Should(Equal(ByPoolPriority{pool2, pool1}))
+		})
+	})
 })
diff --git a/pkg/subnetmanager/subnet_informer_test.go b/pkg/subnetmanager/subnet_informer_test.go
index dff20e9e5..7190810b4 100644
--- a/pkg/subnetmanager/subnet_informer_test.go
+++ b/pkg/subnetmanager/subnet_informer_test.go
@@ -197,6 +197,45 @@ var _ = Describe("SubnetController", Label("subnet_controller_test"), func() {
 			}).Should(Succeed())
 		})
 
+		It("sets the owner reference for the orphan IPPool", func() {
+			ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+			ipPoolT.Spec.Subnet = "172.18.40.0/24"
+
+			err := fakeClient.Create(ctx, ipPoolT)
+			Expect(err).NotTo(HaveOccurred())
+
+			err = ipPoolIndexer.Add(ipPoolT)
+			Expect(err).NotTo(HaveOccurred())
+
+			subnetT.SetUID(uuid.NewUUID())
+			subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+			subnetT.Spec.Subnet = "172.18.40.0/24"
+
+			err = fakeClient.Create(ctx, subnetT)
+			Expect(err).NotTo(HaveOccurred())
+
+			err = subnetIndexer.Add(subnetT)
+			Expect(err).NotTo(HaveOccurred())
+
+			fakeSubnetWatch.Add(subnetT)
+			Eventually(func(g Gomega) {
+				var subnetR spiderpoolv2beta1.SpiderSubnet
+				err = fakeClient.Get(ctx, types.NamespacedName{Name: subnetT.Name}, &subnetR)
+				g.Expect(err).NotTo(HaveOccurred())
+
+				var ipPoolR spiderpoolv2beta1.SpiderIPPool
+				err = fakeClient.Get(ctx, types.NamespacedName{Name: ipPoolT.Name}, &ipPoolR)
+				g.Expect(err).NotTo(HaveOccurred())
+
+				controlled := metav1.IsControlledBy(&ipPoolR, &subnetR)
+				g.Expect(controlled).To(BeTrue())
+
+				v, ok := ipPoolR.Labels[constant.LabelIPPoolOwnerSpiderSubnet]
+				g.Expect(ok).To(BeTrue())
+				g.Expect(v).To(Equal(subnetR.Name))
+			}).Should(Succeed())
+		})
+
 		It("aggregates pre-allocation status", func() {
 			subnetT.SetUID(uuid.NewUUID())
 			subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
@@ -340,5 +379,6 @@ var _ = Describe("SubnetController", Label("subnet_controller_test"), func() {
 				g.Expect(subnetR.Status.ControlledIPPools).To(BeNil())
 			}).Should(Succeed())
 		})
+
 	})
 })
diff --git a/pkg/subnetmanager/subnet_webhook_test.go b/pkg/subnetmanager/subnet_webhook_test.go
index d5be93845..c4d85fa66 100644
--- a/pkg/subnetmanager/subnet_webhook_test.go
+++ b/pkg/subnetmanager/subnet_webhook_test.go
@@ -516,6 +516,47 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 					err = subnetWebhook.ValidateCreate(ctx, subnetT)
 					Expect(apierrors.IsInvalid(err)).To(BeTrue())
 				})
+
+				It("overlaps with existing orphan IPPool resource", func() {
+					orphanPool := &spiderpoolv2beta1.SpiderIPPool{
+						TypeMeta: metav1.TypeMeta{
+							Kind:       constant.KindSpiderIPPool,
+							APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersion),
+						},
+						ObjectMeta: metav1.ObjectMeta{
+							Name: "orphanPool",
+						},
+						Spec: spiderpoolv2beta1.IPPoolSpec{
+							IPVersion: pointer.Int64(constant.IPv4),
+							Subnet:    "172.18.40.0/25",
+							IPs:       []string{"172.18.40.40"},
+						},
+					}
+					DeferCleanup(func() {
+						err := tracker.Delete(
+							schema.GroupVersionResource{
+								Group:    constant.SpiderpoolAPIGroup,
+								Version:  constant.SpiderpoolAPIVersion,
+								Resource: "spiderippools",
+							}, orphanPool.Namespace, orphanPool.Name)
+						Expect(err).NotTo(HaveOccurred())
+					})
+
+					err := tracker.Add(orphanPool)
+					Expect(err).NotTo(HaveOccurred())
+
+					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",
+						}...,
+					)
+
+					err = subnetWebhook.ValidateCreate(ctx, subnetT)
+					Expect(apierrors.IsInvalid(err)).To(BeTrue())
+				})
 			})
 
 			When("Validating 'spec.ips'", func() {
@@ -541,6 +582,46 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 					err := subnetWebhook.ValidateCreate(ctx, subnetT)
 					Expect(apierrors.IsInvalid(err)).To(BeTrue())
 				})
+
+				It("orphan IPPool with extra IPs", func() {
+					orphanPool := &spiderpoolv2beta1.SpiderIPPool{
+						TypeMeta: metav1.TypeMeta{
+							Kind:       constant.KindSpiderIPPool,
+							APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersion),
+						},
+						ObjectMeta: metav1.ObjectMeta{
+							Name: "orphanPool",
+						},
+						Spec: spiderpoolv2beta1.IPPoolSpec{
+							IPVersion: pointer.Int64(constant.IPv4),
+							Subnet:    "172.18.40.0/25",
+							IPs:       []string{"172.18.40.40-172.18.40.45"},
+						},
+					}
+					DeferCleanup(func() {
+						err := tracker.Delete(
+							schema.GroupVersionResource{
+								Group:    constant.SpiderpoolAPIGroup,
+								Version:  constant.SpiderpoolAPIVersion,
+								Resource: "spiderippools",
+							}, orphanPool.Namespace, orphanPool.Name)
+						Expect(err).NotTo(HaveOccurred())
+					})
+
+					err := tracker.Add(orphanPool)
+					Expect(err).NotTo(HaveOccurred())
+
+					subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+					subnetT.Spec.Subnet = "172.18.40.0/25"
+					subnetT.Spec.IPs = append(subnetT.Spec.IPs,
+						[]string{
+							"172.18.40.41-172.18.40.45",
+						}...,
+					)
+
+					err = subnetWebhook.ValidateCreate(ctx, subnetT)
+					Expect(apierrors.IsInvalid(err)).To(BeTrue())
+				})
 			})
 
 			When("Validating 'spec.excludeIPs'", func() {
@@ -789,6 +870,46 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() {
 				err := subnetWebhook.ValidateCreate(ctx, subnetT)
 				Expect(err).NotTo(HaveOccurred())
 			})
+
+			It("create IPv4 Subnet with orphan IPPool exist", func() {
+				orphanPool := &spiderpoolv2beta1.SpiderIPPool{
+					TypeMeta: metav1.TypeMeta{
+						Kind:       constant.KindSpiderIPPool,
+						APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersion),
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name: "orphanPool",
+					},
+					Spec: spiderpoolv2beta1.IPPoolSpec{
+						IPVersion: pointer.Int64(constant.IPv4),
+						Subnet:    "172.18.40.0/25",
+						IPs:       []string{"172.18.40.40-172.18.40.41"},
+					},
+				}
+				DeferCleanup(func() {
+					err := tracker.Delete(
+						schema.GroupVersionResource{
+							Group:    constant.SpiderpoolAPIGroup,
+							Version:  constant.SpiderpoolAPIVersion,
+							Resource: "spiderippools",
+						}, orphanPool.Namespace, orphanPool.Name)
+					Expect(err).NotTo(HaveOccurred())
+				})
+
+				err := tracker.Add(orphanPool)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnetT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				subnetT.Spec.Subnet = "172.18.40.0/25"
+				subnetT.Spec.IPs = append(subnetT.Spec.IPs,
+					[]string{
+						"172.18.40.40-172.18.40.45",
+					}...,
+				)
+
+				err = subnetWebhook.ValidateCreate(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+			})
 		})
 
 		Describe("ValidateUpdate", func() {
diff --git a/test/Makefile.defs b/test/Makefile.defs
index 1cf9ca2cf..770b81418 100644
--- a/test/Makefile.defs
+++ b/test/Makefile.defs
@@ -66,7 +66,7 @@ E2E_TIMEOUT ?= 60m
 
 E2E_GINKGO_PROCS ?= 4
 
-E2E_SPIDERPOOL_ENABLE_SUBNET ?= false # consistent with open source, closed by default
+E2E_SPIDERPOOL_ENABLE_SUBNET ?= true # consistent with open source, closed by default
 E2E_SPIDERPOOL_ENABLE_COORDINATOR ?= true
 E2E_SPIDERPOOL_ENABLE_MULTUSCONFIG ?= true
 
diff --git a/test/doc/annotation.md b/test/doc/annotation.md
index d220423ae..6618a854e 100644
--- a/test/doc/annotation.md
+++ b/test/doc/annotation.md
@@ -1,16 +1,15 @@
 # E2E Cases for Annotation
 
-| Case ID | Title                                                                | Priority | Smoke | Status | Other |
-| ------- | -------------------------------------------------------------------- | -------- | ----- | ------ | ----- |
-| A00001  | It fails to run a pod with different VLANs for IPv4 and IPv6 IPPools | p3       |       | done   |       |
-| A00002  | Added fields such as `"dist":"1.0.0.0/16"`, `"gw":"1.0.0.1"`, and `nics` and the pod was running successfully                              | p2       |       | done   |       |
-| A00003  | Failed to run a pod with invalid annotations                         | p3       |       | done   |       |
-| A00004  | Take a test with the Priority: pod annotation > namespace annotation > specified in a CNI profile > settings in ConfigMap                     | p1       |       | done   |       |
-| A00005  | The "IPPools" annotation has the higher Priority over the "IPPool" annotation | p1       |       | done   |         |
-| A00006  | The namespace annotation has precedence over global default IPPool   | p1       | true  | done   |       |
-| A00007  | Spiderpool will successively try to allocate IPs in the order of the elements in the IPPool array until the first allocation succeeds or all fail | p1       | true  | done   |       |
-| A00008  | Successfully run an annotated multi-container pod                    | p2       |       | done   |       |
-| A00009  | Modify the annotated IPPool for a specified Deployment pod<br />Modify the annotated IPPool for a specified StatefulSet pod                 | p2       |       |  done   |       |
-| A00010  | Modify the annotated IPPool for a pod running on multiple NICs       | p3       |       | done   |       |
-| A00011  | Use the ippool route with `cleanGateway=false` in the pod annotation as a default route | p3     |     |  done  |         |
-| A00012  | Specify the default NIC through Pod annotations  | p2     |     |    |         |
+| Case ID | Title                                                                                                                       | Priority | Smoke | Status | Other |
+| ------- |-----------------------------------------------------------------------------------------------------------------------------|----------|-------|--------|-------|
+| A00001  | It fails to run a pod with different VLANs for IPv4 and IPv6 IPPools                                                        | p3       |       | done   |       |
+| A00002  | Added fields such as `"dist":"1.0.0.0/16"`, `"gw":"1.0.0.1"`, and `nics` and the pod was running successfully               | p2       |       | done   |       |
+| A00003  | Failed to run a pod with invalid annotations                                                                                | p3       |       | done   |       |
+| A00004  | Take a test with the Priority: pod annotation > namespace annotation > specified in a CNI profile                           | p1       |       | done   |       |
+| A00005  | The "IPPools" annotation has the higher Priority over the "IPPool" annotation                                               | p1       |       | done   |       |
+| A00006  | The namespace annotation has precedence over global default IPPool                                                          | p1       | true  | done   |       |
+| A00008  | Successfully run an annotated multi-container pod                                                                           | p2       |       | done   |       |
+| A00009  | Modify the annotated IPPool for a specified Deployment pod<br />Modify the annotated IPPool for a specified StatefulSet pod | p2       |       | done   |       |
+| A00010  | Modify the annotated IPPool for a pod running on multiple NICs                                                              | p3       |       | done   |       |
+| A00011  | Use the ippool route with `cleanGateway=false` in the pod annotation as a default route                                     | p3       |       | done   |       |
+| A00012  | Specify the default NIC through Pod annotations                                                                             | p2       |       |        |       |
diff --git a/test/doc/spidermultus.md b/test/doc/spidermultus.md
index fa72af82d..c69d8ffb8 100644
--- a/test/doc/spidermultus.md
+++ b/test/doc/spidermultus.md
@@ -9,16 +9,19 @@
 | M00005  | testing creating spiderMultusConfig with cniType: custom and invalid json config, expect error happened | p2       |       |    |       |
 | M00006  | testing creating spiderMultusConfig with cniType: macvlan with vlanId with one master and checking the net-attach-conf config if works | p1       |   smoke    |    |       |
 | M00007  | testing creating spiderMultusConfig with cniType: macvlan with vlanId with two master with bond config and checking the net-attach-conf config if works | p1       |   smoke    |    |       |
-| M00008  | After deleting spiderMultusConfig, the corresponding net-attach-conf will also be deleted  | p2      |         |  done  |       |
-| M00009  | Update spidermultusConfig, the corresponding multus net-attach-conf will also be updated   | p2      |         |        |       |
-| M00010  | Update spidermultusConfig: add new bond config  | p1      |  smoke  |    |       |
-| M00011  | Manually delete the net-attach-conf of multus, it will be created automatically | p1      |     |  done  |       |
-| M00012  | Customize net-attach-conf name via annotation multus.spidernet.io/cr-name | p2       |       | done   |       |
-| M00013  | webhook validation for multus.spidernet.io/cr-name                        | p3       |       |  done  |       |
-| M00014  | Change net-attach-conf version via annotation multus.spidernet.io/cni-version | p2     |       |  done  |       |
-| M00015  | webhook validation for multus.spidernet.io/cni-version                        | p3       |       |  done |       |
-| M00016  | Set enableCoordinator to false, multus cr will not generate coordinator configuration | p3     |       |    |       |
-| M00017  | Already have multus cr, spidermultus should take care of it                     | p3     |       |  done  |       |
-| M00018  | Multiple annotations of spidermultus should be inherited by multus CR           | p3     |       |    |       |
-| M00019  | The value of webhook verification cniType is inconsistent with cniConf          | p3     |       |  done  |       |
-| M00020  | vlanID is not in the range of 0-4094 and will not be created                    | p3     |       |  done  |       |
+| M00008  | testing creating spiderMultusConfig with cniType: ovs with vlanId with and checking the net-attach-conf config if works | p1       |   smoke    |    |       |
+| M00009  | testing creating spiderMultusConfig with cniType: ovs with trunk with and checking the net-attach-conf config if works | p1       |   smoke    |    |       |
+| M00010  | testing creating spiderMultusConfig with cniType: ovs with device with and checking the net-attach-conf config if has annotations: ovs-cni.network.kubevirt.io/<brName> | p1       |   smoke    |    |       |
+| M00011  | After deleting spiderMultusConfig, the corresponding net-attach-conf will also be deleted  | p2      |         |  done  |       |
+| M00012  | Update spidermultusConfig, the corresponding multus net-attach-conf will also be updated   | p2      |         |        |       |
+| M00013  | Update spidermultusConfig: add new bond config  | p1      |  smoke  |    |       |
+| M00014  | Manually delete the net-attach-conf of multus, it will be created automatically | p1      |     |  done  |       |
+| M00015  | Customize net-attach-conf name via annotation multus.spidernet.io/cr-name | p2       |       |    |       |
+| M00016  | webhook validation for multus.spidernet.io/cr-name                        | p3       |       |    |       |
+| M00017  | Change net-attach-conf version via annotation multus.spidernet.io/cni-version | p2     |       |    |       |
+| M00018  | webhook validation for multus.spidernet.io/cni-version                        | p3       |       |    |       |
+| M00019  | Set enableCoordinator to false, multus cr will not generate coordinator configuration | p3     |       |    |       |
+| M00020  | Already have multus cr, spidermultus should take care of it                     | p3     |       |    |       |
+| M00021  | Multiple annotations of spidermultus should be inherited by multus CR           | p3     |       |    |       |
+| M00022  | The value of webhook verification cniType is inconsistent with cniConf          | p3     |       |    |       |
+| M00023  | vlan is not in the range of 0-4094 and will not be created                    | p3     |       |    |       |
diff --git a/test/doc/subnet.md b/test/doc/subnet.md
index b34ca3bf2..b28844216 100644
--- a/test/doc/subnet.md
+++ b/test/doc/subnet.md
@@ -1,26 +1,28 @@
 # E2E Cases for SpiderSubnet
 
-| Case ID | Title                                                                                                                               | Priority | Smoke | Status | Other |
-| ------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------- | ----- | ------ | ----- |
-| I00001  | Add, delete, modify, and query CIDR subnet                                                                                          |   p1     |       |  done  |       |
-| I00002  | Add and remove IP for CIDR subnet                                                                                                   |   p1     |       |  done  |       |
-| I00003  | Automatically create, scale, restart, and delete of ippools for different types of controllers                                      |   p1     |       |  done  |       |
-| I00004  | The excludeIPs in the subnet will not be used by pools created automatically or manually.                                           |   p2     |       |  done  |       |
-| I00005  | If routes and gateway are modified for CIDR, how the manually created ippools are affected?                                         |   p3     |       |  done  |       |
-| I00006  | Multiple automatic creation and recycling of ippools, eventually the free IPs in the subnet should be restored to its initial state |   p1     | true  |  done  |       |
-| I00007  | Multiple manual creation and recycling of ippools, eventually the free IPs in the subnet should be restored to its initial state    |   p1     | true  |  done  |       |
-| I00008  | Scale up and down the number of deployment several times to see if the state of the ippools is eventually stable                    |   p1     |       |  done  |       |
-| I00009  | Create 100 Subnets with the same `Subnet.spec` and see if only one succeeds in the end                                              |   p1     |       |  done  |       |
-| I00010  | Create 100 IPPools with the same `IPPool.spec` and see if only one succeeds in the end                                              |   p1     |       |  done  |       |
-| I00011  | The subnet automatically creates an ippool and allocates IP, and should consider reservedIP                                         |   p1     |       |  done  |       |
-| I00012  | SpiderSubnet supports multiple interfaces                                                                                           |   p1     |       |  done  |       |
-| I00013  | SpiderSubnet supports automatic IP assignment for Pods                                                                              |   p2     |       |  done  |       |
-| I00014  | The default subnet should support different controller types                                                                        |   p2     |       |  done  |       |
-| I00015  | Applications with the same name and type can use the reserved IPPool.      |   p2     |       |  done  |       |
-| I00016  | Applications with the same name and different types cannot use the reserved IPPool.                       |   p3     |       |  done  |       |
-| I00017  | Ability to create fixed IPPools for applications with very long names                      |   p3     |       |  done  |       |
-| I00018  | automatic IPPool IPs are not modifiable                                                    |   p3     |       |  done  |       |
-| I00019  | Change the annotation ipam.spidernet.io/ippool-reclaim to true and the reserved IPPool will be reclaimed.                   |   p3     |       |  done  |       |
-| I00020  | Redundant IPs for automatic IPPool, which cannot be used by other applications             |   p3     |       |  done  |       |
-| I00021  | Pod works correctly when multiple NICs are specified by annotations for applications of the same name             |   p3     |       |  done  |       |
-| I00022  | Dirty data in the subnet should be recycled.             |   p3     |       |  done  |       |
+| Case ID | Title                                                                                                                               | Priority | Smoke | Status  | Other |
+|---------|-------------------------------------------------------------------------------------------------------------------------------------|----------|-------|---------|-------|
+| I00001  | Add, delete, modify, and query CIDR subnet                                                                                          | p1       |       | done    |       |
+| I00002  | Add and remove IP for CIDR subnet                                                                                                   | p1       |       | done    |       |
+| I00003  | Automatically create, scale, restart, and delete of ippools for different types of controllers                                      | p1       |       | done    |       |
+| I00004  | The excludeIPs in the subnet will not be used by pools created automatically or manually.                                           | p2       |       | done    |       |
+| I00005  | If routes and gateway are modified for CIDR, how the manually created ippools are affected?                                         | p3       |       | done    |       |
+| I00006  | Multiple automatic creation and recycling of ippools, eventually the free IPs in the subnet should be restored to its initial state | p1       | true  | done    |       |
+| I00007  | Multiple manual creation and recycling of ippools, eventually the free IPs in the subnet should be restored to its initial state    | p1       | true  | done    |       |
+| I00008  | Scale up and down the number of deployment several times to see if the state of the ippools is eventually stable                    | p1       |       | done    |       |
+| I00009  | Create 100 Subnets with the same `Subnet.spec` and see if only one succeeds in the end                                              | p1       |       | done    |       |
+| I00010  | Create 100 IPPools with the same `IPPool.spec` and see if only one succeeds in the end                                              | p1       |       | done    |       |
+| I00011  | The subnet automatically creates an ippool and allocates IP, and should consider reservedIP                                         | p1       |       | done    |       |
+| I00012  | SpiderSubnet supports multiple interfaces                                                                                           | p1       |       | done    |       |
+| I00013  | SpiderSubnet supports automatic IP assignment for Pods                                                                              | p2       |       | done    |       |
+| I00014  | The default subnet should support different controller types                                                                        | p2       |       | done    |       |
+| I00015  | Applications with the same name and type can use the reserved IPPool.                                                               | p2       |       | done    |       |
+| I00016  | Applications with the same name and different types cannot use the reserved IPPool.                                                 | p3       |       | done    |       |
+| I00017  | Ability to create fixed IPPools for applications with very long names                                                               | p3       |       | done    |       |
+| I00018  | automatic IPPool IPs are not modifiable                                                                                             | p3       |       | done    |       |
+| I00019  | Change the annotation ipam.spidernet.io/ippool-reclaim to true and the reserved IPPool will be reclaimed.                           | p3       |       | done    |       |
+| I00020  | Redundant IPs for automatic IPPool, which cannot be used by other applications                                                      | p3       |       | done    |       |
+| I00021  | Pod works correctly when multiple NICs are specified by annotations for applications of the same name                               | p3       |       | done    |       |
+| I00022  | Dirty data in the subnet should be recycled.                                                                                        | p3       |       | done    |       |
+| I00023  | Orphan IPPool creation in SpiderSubnet feature.(validate spec.subnet overlaps)                                                      | p3       |       | ongoing |       |
+| I00024  | New SpiderSubnet resource controls orphan IPPool resource.(validate OwnerRef, IPs ranges containing, cascade deletion)              | p3       |       | ongoing |       |
diff --git a/test/e2e/affinity/affinity_test.go b/test/e2e/affinity/affinity_test.go
index 5e548afe8..d26661d40 100644
--- a/test/e2e/affinity/affinity_test.go
+++ b/test/e2e/affinity/affinity_test.go
@@ -545,9 +545,6 @@ var _ = Describe("test Affinity", Label("affinity"), func() {
 		nsName1 = "ns1" + tools.RandomName()
 
 		BeforeEach(func() {
-			if frame.Info.SpiderSubnetEnabled {
-				Skip("The subnet function is enabled, the namespace annotation has a lower priority than the default subnet")
-			}
 			// Create another namespace
 			GinkgoWriter.Printf("create another namespace %v \n", nsName1)
 			err := frame.CreateNamespaceUntilDefaultServiceAccountReady(nsName1, common.ServiceAccountReadyTimeout)
diff --git a/test/e2e/annotation/annotation_test.go b/test/e2e/annotation/annotation_test.go
index 100fc33cb..1dcbfc2a9 100644
--- a/test/e2e/annotation/annotation_test.go
+++ b/test/e2e/annotation/annotation_test.go
@@ -440,9 +440,6 @@ var _ = Describe("test annotation", Label("annotation"), func() {
 
 			It(`the namespace annotation has precedence over global default ippool`, Label("A00006", "smoke"), func() {
 				// Generate a pod yaml with namespace annotations
-				if frame.Info.SpiderSubnetEnabled {
-					Skip("The subnet function is enabled, the namespace annotation has a lower priority than the default subnet")
-				}
 				podYaml := common.GenerateExamplePodYaml(podName, nsName)
 				Expect(podYaml).NotTo(BeNil())
 				// The namespace annotation has precedence over global default ippool
@@ -451,105 +448,6 @@ var _ = Describe("test annotation", Label("annotation"), func() {
 		})
 	})
 
-	Context("Spiderpool will successively try to allocate IP in the order of the elements in the IPPool array until the first allocation succeeds or all fail", func() {
-		var v4PoolNameList1, v6PoolNameList1, v4PoolNameList2, v6PoolNameList2 []string
-		var err error
-		var deployName string
-		var (
-			podOriginialNum int = 1
-			podScaleupNum   int = 2
-			ippoolIpNum     int = 1
-		)
-		BeforeEach(func() {
-			deployName = "deploy" + tools.RandomName()
-			// Create one ippool to be used as backup ippool
-			if frame.Info.IpV4Enabled {
-				if frame.Info.SpiderSubnetEnabled {
-					ctx, cancel := context.WithTimeout(context.Background(), common.PodStartTimeout)
-					defer cancel()
-					v4PoolName1, iPv4PoolObj1 := common.GenerateExampleIpv4poolObject(ippoolIpNum)
-					Expect(common.CreateIppoolInSpiderSubnet(ctx, frame, v4SubnetName, iPv4PoolObj1, ippoolIpNum)).NotTo(HaveOccurred(), "Failed to create v4 pool")
-					v4PoolNameList1 = append(v4PoolNameList1, v4PoolName1)
-					v4PoolName2, iPv4PoolObj2 := common.GenerateExampleIpv4poolObject(ippoolIpNum)
-					Expect(common.CreateIppoolInSpiderSubnet(ctx, frame, v4SubnetName, iPv4PoolObj2, ippoolIpNum)).NotTo(HaveOccurred(), "Failed to create v4 pool")
-					v4PoolNameList2 = append(v4PoolNameList2, v4PoolName2)
-				} else {
-					v4PoolNameList1, err = common.BatchCreateIppoolWithSpecifiedIPNumber(frame, 1, ippoolIpNum, true)
-					Expect(err).NotTo(HaveOccurred(), "Failed to create v4 pool")
-					v4PoolNameList2, err = common.BatchCreateIppoolWithSpecifiedIPNumber(frame, 1, ippoolIpNum, true)
-					Expect(err).NotTo(HaveOccurred(), "Failed to create v4 pool")
-				}
-			}
-			if frame.Info.IpV6Enabled {
-				if frame.Info.SpiderSubnetEnabled {
-					ctx, cancel := context.WithTimeout(context.Background(), common.PodStartTimeout)
-					defer cancel()
-					v6PoolName1, iPv6PoolObj1 := common.GenerateExampleIpv6poolObject(ippoolIpNum)
-					Expect(common.CreateIppoolInSpiderSubnet(ctx, frame, v6SubnetName, iPv6PoolObj1, ippoolIpNum)).NotTo(HaveOccurred(), "Failed to create v6 pool")
-					v6PoolNameList1 = append(v6PoolNameList1, v6PoolName1)
-					v6PoolName2, iPv6PoolObj2 := common.GenerateExampleIpv6poolObject(ippoolIpNum)
-					Expect(common.CreateIppoolInSpiderSubnet(ctx, frame, v6SubnetName, iPv6PoolObj2, ippoolIpNum)).NotTo(HaveOccurred(), "Failed to create v6 pool")
-					v6PoolNameList2 = append(v6PoolNameList2, v6PoolName2)
-				} else {
-					v6PoolNameList1, err = common.BatchCreateIppoolWithSpecifiedIPNumber(frame, 1, ippoolIpNum, false)
-					Expect(err).NotTo(HaveOccurred(), "Failed to create v4 pool")
-					v6PoolNameList2, err = common.BatchCreateIppoolWithSpecifiedIPNumber(frame, 1, ippoolIpNum, false)
-					Expect(err).NotTo(HaveOccurred(), "Failed to create v4 pool")
-				}
-			}
-			GinkgoWriter.Printf("Successful creation of v4Pool %v,v6Pool %v \n", append(v4PoolNameList1, v4PoolNameList2...), append(v6PoolNameList1, v6PoolNameList2...))
-
-			DeferCleanup(func() {
-				GinkgoWriter.Printf("Try to delete v4PoolList %v, v6PoolList %v \n", append(v4PoolNameList1, v4PoolNameList2...), append(v6PoolNameList1, v6PoolNameList2...))
-				if frame.Info.IpV4Enabled {
-					for _, pool := range append(v4PoolNameList1, v4PoolNameList2...) {
-						Expect(common.DeleteIPPoolByName(frame, pool)).NotTo(HaveOccurred())
-					}
-				}
-				if frame.Info.IpV6Enabled {
-					for _, pool := range append(v6PoolNameList1, v6PoolNameList2...) {
-						Expect(common.DeleteIPPoolByName(frame, pool)).NotTo(HaveOccurred())
-					}
-				}
-			})
-		})
-		It("Spiderpool will successively try to allocate IP in the order of the elements in the IPPool array until the first allocation succeeds or all fail", Serial,
-			Label("A00007"), func() {
-
-				// Create Deployment with types.AnnoPodIPPoolValue and The Pods IP is recorded in the IPPool.
-				deploy := common.CreateDeployWithPodAnnoation(frame, deployName, nsName, podOriginialNum, common.NIC1, append(v4PoolNameList1, v4PoolNameList2...), append(v6PoolNameList1, v6PoolNameList2...))
-				podList := common.CheckPodIpReadyByLabel(frame, deploy.Spec.Template.Labels, v4PoolNameList1, v6PoolNameList1)
-
-				// Wait for new Pod to be created and expect its ip to be in the next pool in the array
-				deploy, err = frame.ScaleDeployment(deploy, int32(podScaleupNum))
-				Expect(err).NotTo(HaveOccurred(), "Failed to scale deployment")
-				ctx2, cancel2 := context.WithTimeout(context.Background(), common.PodReStartTimeout)
-				defer cancel2()
-				err = frame.WaitPodListRunning(deploy.Spec.Selector.MatchLabels, podScaleupNum, ctx2)
-				Expect(err).NotTo(HaveOccurred())
-
-				// Get an extended list of pods
-				scalePodList, err := frame.GetPodListByLabel(deploy.Spec.Selector.MatchLabels)
-				Expect(err).NotTo(HaveOccurred())
-				pods := common.GetAdditionalPods(podList, scalePodList)
-				Expect(len(pods)).To(Equal(podScaleupNum - podOriginialNum))
-				addPodList := &corev1.PodList{
-					Items: pods,
-				}
-
-				// Check the Pod's IP record backup IPPool
-				ok, _, _, err := common.CheckPodIpRecordInIppool(frame, v4PoolNameList2, v6PoolNameList2, addPodList)
-				Expect(err).NotTo(HaveOccurred())
-				Expect(ok).To(BeTrue())
-
-				// Delete Deployment and check that the Pod IP in the IPPool is reclaimed properly
-				Expect(frame.DeleteDeploymentUntilFinish(deployName, nsName, common.ResourceDeleteTimeout)).To(Succeed())
-				GinkgoWriter.Printf("Succeeded to delete deployment %v/%v \n", nsName, deployName)
-				Expect(common.WaitIPReclaimedFinish(frame, append(v4PoolNameList1, v4PoolNameList2...), append(v6PoolNameList1, v6PoolNameList2...), scalePodList, common.IPReclaimTimeout)).To(Succeed())
-				GinkgoWriter.Println("Pod IP is successfully released")
-			})
-	})
-
 	It("succeeded to running pod after added valid route field", Label("A00002"), func() {
 		var v4PoolName, v6PoolName, ipv4Dst, ipv6Dst, ipv4Gw, ipv6Gw string
 		var v4Pool, v6Pool *spiderpool.SpiderIPPool
diff --git a/test/e2e/ippoolcr/ippoolcr_test.go b/test/e2e/ippoolcr/ippoolcr_test.go
index a40ab9d72..21e2e2b56 100644
--- a/test/e2e/ippoolcr/ippoolcr_test.go
+++ b/test/e2e/ippoolcr/ippoolcr_test.go
@@ -378,10 +378,6 @@ var _ = Describe("test ippool CR", Label("ippoolCR"), func() {
 	})
 
 	It("create and delete batch of ippool and check time cost", Label("D00006"), func() {
-		if frame.Info.SpiderSubnetEnabled {
-			Skip("Suitable for no subnets")
-		}
-
 		var ipv4PoolNameList, ipv6PoolNameList []string
 		var err error
 		const ippoolNumber = 10
diff --git a/test/scripts/install-multus.sh b/test/scripts/install-multus.sh
index beae2780a..628fabe93 100755
--- a/test/scripts/install-multus.sh
+++ b/test/scripts/install-multus.sh
@@ -231,5 +231,7 @@ EOF
 Install::MultusCR
 Install::SpiderpoolCR
 
+kubectl get sp -o wide --kubeconfig ${E2E_KUBECONFIG}
+kubectl get network-attachment-definitions.k8s.cni.cncf.io --kubeconfig ${E2E_KUBECONFIG} -n kube-system -o yaml
 
 echo "$CURRENT_FILENAME : done"
\ No newline at end of file