Repository: spidernet-io/spiderpool
Pull request #338 (2022-06-18 01:33:37)

ipam:Add code to release IP
- Roll back allocated IP when Allocate() failed.
- Add backbone code to release IP.

Signed-off-by: iiiceoo <ziqian.xue@daocloud.io>

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

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

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


codecov[bot]: # [Codecov](https://codecov.io/gh/spidernet-io/spiderpool/pull/338?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) Report
> Merging [#338](https://codecov.io/gh/spidernet-io/spiderpool/pull/338?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (3a353a3) into [main](https://codecov.io/gh/spidernet-io/spiderpool/commit/ad4c142bf78836ea38f761f6700669baf9ed5e2d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (ad4c142) will **decrease** coverage by `1.58%`.
> The diff coverage is `0.00%`.

[![Impacted file tree graph](https://codecov.io/gh/spidernet-io/spiderpool/pull/338/graphs/tree.svg?width=650&height=150&src=pr&token=YKXY2E4Q8G&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io)](https://codecov.io/gh/spidernet-io/spiderpool/pull/338?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     #338      +/-   ##
==========================================
- Coverage   72.31%   70.73%   -1.59%     
==========================================
  Files           7        7              
  Lines         401      410       +9     
==========================================
  Hits          290      290              
- Misses         88       97       +9     
  Partials       23       23              
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `70.73% <0.00%> (-1.59%)` | :arrow_down: |

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

| [Impacted Files](https://codecov.io/gh/spidernet-io/spiderpool/pull/338?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) | Coverage Δ | |
|---|---|---|
| [pkg/logutils/log.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/338/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL2xvZ3V0aWxzL2xvZy5nbw==) | `74.38% <0.00%> (-5.98%)` | :arrow_down: |

iiiceoo: Kind 集群中 100 Pod 启杀测试结论（IP-Pod 1：1 / 双栈）：
- 排除 GC 单独运行时，应该已无并发问题，IP 基本不会发生错分现象，不排除隐性的未发现的场景。
- 100 Pod 启动时间，稳定在 100s 左右，大量的冲突会集中在 IPv4 的分配（因为双栈场景下总是先分 IPv4），少量冲突发生在更新 Pod 注解。在分配过程中，发生错误就会回滚 IPPool；回滚 IPPool 也发生错误时（重试次数耗尽），即产生 IP 泄漏，agent 无法处理此场景。大约每测三次，会有一次出现即启动 99 Pod 的情况。
- 100 Pod 删除的速度非常的慢，可能要 10 分钟？？？耗时长感觉与 CNI DEL 失败重试的间隔有关，需后续确认。删除总能删完，因为删除无需回滚，无副作用，所以当返回错误时，Kubelet 一定会重试，直到成功。
- 一个特殊场景，Pod A 删除，释放 IPv4 IP 成功，而释放 IPv6 IP 失败了，接下来 Kubelet 会收到 CNI DEL 的错误，进而重试，在此重试的期间，IPv4 IP 对应的 IPPool 中的数据已擦除，IPv6 IP 反之；Pod B 启动，正常的分配到了这个 IPv4 IP，此时相当于 IP 冲突了。当 Pod A 在重试后被成功删除时，此中间状态解除，Pod B 的 IPv4 IP 正常工作。

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

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

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


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

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

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


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

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

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



Patch:
diff --git a/api/v1/agent/models/ip_config.go b/api/v1/agent/models/ip_config.go
index 6c2c83ec3..0e06e0c50 100644
--- a/api/v1/agent/models/ip_config.go
+++ b/api/v1/agent/models/ip_config.go
@@ -30,6 +30,9 @@ type IPConfig struct {
 	// gateway
 	Gateway string `json:"gateway,omitempty"`
 
+	// ip pool
+	IPPool string `json:"ipPool,omitempty"`
+
 	// nic
 	// Required: true
 	Nic *string `json:"nic"`
diff --git a/api/v1/agent/openapi.yaml b/api/v1/agent/openapi.yaml
index 76d44fb46..36323a1b6 100644
--- a/api/v1/agent/openapi.yaml
+++ b/api/v1/agent/openapi.yaml
@@ -234,6 +234,8 @@ definitions:
           - 6
       address:
         type: string
+      ipPool:
+        type: string
       gateway:
         type: string
       nic:
diff --git a/api/v1/agent/server/embedded_spec.go b/api/v1/agent/server/embedded_spec.go
index cf3315c77..491f1b744 100644
--- a/api/v1/agent/server/embedded_spec.go
+++ b/api/v1/agent/server/embedded_spec.go
@@ -263,6 +263,9 @@ func init() {
         "gateway": {
           "type": "string"
         },
+        "ipPool": {
+          "type": "string"
+        },
         "nic": {
           "type": "string"
         },
@@ -622,6 +625,9 @@ func init() {
         "gateway": {
           "type": "string"
         },
+        "ipPool": {
+          "type": "string"
+        },
         "nic": {
           "type": "string"
         },
diff --git a/charts/spiderpool/crds/spiderpool.spidernet.io_ippools.yaml b/charts/spiderpool/crds/spiderpool.spidernet.io_ippools.yaml
index 86106673d..c9bdc476a 100644
--- a/charts/spiderpool/crds/spiderpool.spidernet.io_ippools.yaml
+++ b/charts/spiderpool/crds/spiderpool.spidernet.io_ippools.yaml
@@ -247,10 +247,6 @@ spec:
           status:
             description: IPPoolStatus defines the observed state of IPPool
             properties:
-              allocateCount:
-                format: int64
-                minimum: 0
-                type: integer
               allocatedIPCount:
                 format: int32
                 minimum: 0
@@ -279,10 +275,6 @@ spec:
                 description: PoolIPAllocations is a map of allocated IPs indexed by
                   IP
                 type: object
-              deallocateCount:
-                format: int64
-                minimum: 0
-                type: integer
               totalIPCount:
                 format: int32
                 minimum: 0
diff --git a/charts/spiderpool/crds/spiderpool.spidernet.io_workloadendpoints.yaml b/charts/spiderpool/crds/spiderpool.spidernet.io_workloadendpoints.yaml
index c923d59bc..07f4e1e75 100644
--- a/charts/spiderpool/crds/spiderpool.spidernet.io_workloadendpoints.yaml
+++ b/charts/spiderpool/crds/spiderpool.spidernet.io_workloadendpoints.yaml
@@ -80,30 +80,20 @@ spec:
                     items:
                       description: TODO
                       properties:
-                        gateway:
-                          type: string
                         interface:
                           type: string
                         ipv4:
                           type: string
+                        ipv4Gateway:
+                          type: string
                         ipv4Pool:
                           type: string
                         ipv6:
                           type: string
+                        ipv6Gateway:
+                          type: string
                         ipv6Pool:
                           type: string
-                        routes:
-                          items:
-                            properties:
-                              dst:
-                                type: string
-                              gw:
-                                type: string
-                            required:
-                            - dst
-                            - gw
-                            type: object
-                          type: array
                         vlan:
                           format: int32
                           maximum: 4095
@@ -135,30 +125,20 @@ spec:
                       items:
                         description: TODO
                         properties:
-                          gateway:
-                            type: string
                           interface:
                             type: string
                           ipv4:
                             type: string
+                          ipv4Gateway:
+                            type: string
                           ipv4Pool:
                             type: string
                           ipv6:
                             type: string
+                          ipv6Gateway:
+                            type: string
                           ipv6Pool:
                             type: string
-                          routes:
-                            items:
-                              properties:
-                                dst:
-                                  type: string
-                                gw:
-                                  type: string
-                              required:
-                              - dst
-                              - gw
-                              type: object
-                            type: array
                           vlan:
                             format: int32
                             maximum: 4095
diff --git a/cmd/spiderpool-agent/cmd/crd_manager.go b/cmd/spiderpool-agent/cmd/crd_manager.go
index 3dbfdd63d..b0626be24 100644
--- a/cmd/spiderpool-agent/cmd/crd_manager.go
+++ b/cmd/spiderpool-agent/cmd/crd_manager.go
@@ -6,7 +6,6 @@ package cmd
 import (
 	// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
 	// to ensure that exec-entrypoint and run can make use of them.
-	"context"
 
 	_ "k8s.io/client-go/plugin/pkg/client/auth"
 
@@ -14,7 +13,6 @@ import (
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
 	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/v1"
 )
@@ -36,12 +34,5 @@ func newCRDManager() (ctrl.Manager, error) {
 		return nil, err
 	}
 
-	if err := mgr.GetFieldIndexer().IndexField(context.Background(), &spiderpoolv1.ReservedIP{}, ".spec.ipVersion", func(raw client.Object) []string {
-		reservedIP := raw.(*spiderpoolv1.ReservedIP)
-		return []string{string(*reservedIP.Spec.IPVersion)}
-	}); err != nil {
-		return nil, err
-	}
-
 	return mgr, nil
 }
diff --git a/cmd/spiderpool-agent/cmd/daemon.go b/cmd/spiderpool-agent/cmd/daemon.go
index 6e12af8f5..858c19d7a 100644
--- a/cmd/spiderpool-agent/cmd/daemon.go
+++ b/cmd/spiderpool-agent/cmd/daemon.go
@@ -67,21 +67,21 @@ func DaemonMain() {
 	agentContext.WEManager = weManager
 
 	logger.Debug("Begin to initialize ReservedIP Manager")
-	rIPManager, err := reservedipmanager.NewReservedIPManager(mgr.GetClient())
+	rIPManager, err := reservedipmanager.NewReservedIPManager(mgr.GetClient(), mgr)
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
 	agentContext.RIPManager = rIPManager
 
 	logger.Debug("Begin to initialize Node Manager")
-	nodeManager, err := nodemanager.NewNodeManager(mgr.GetClient())
+	nodeManager, err := nodemanager.NewNodeManager(mgr.GetClient(), mgr)
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
 	agentContext.NodeManager = nodeManager
 
 	logger.Debug("Begin to initialize Namespace Manager")
-	nsManager, err := namespacemanager.NewNamespaceManager(mgr.GetClient())
+	nsManager, err := namespacemanager.NewNamespaceManager(mgr.GetClient(), mgr)
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
@@ -92,7 +92,7 @@ func DaemonMain() {
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
-	podManager, err := podmanager.NewPodManager(mgr.GetClient(), retrys)
+	podManager, err := podmanager.NewPodManager(mgr.GetClient(), mgr, retrys)
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
diff --git a/cmd/spiderpool-agent/cmd/ipam.go b/cmd/spiderpool-agent/cmd/ipam.go
index 80b23eca8..8f95b59e6 100644
--- a/cmd/spiderpool-agent/cmd/ipam.go
+++ b/cmd/spiderpool-agent/cmd/ipam.go
@@ -10,9 +10,10 @@ import (
 	"github.com/spidernet-io/spiderpool/api/v1/agent/server/restapi/daemonset"
 	"github.com/spidernet-io/spiderpool/pkg/constant"
 	"github.com/spidernet-io/spiderpool/pkg/logutils"
+	"go.uber.org/zap"
 )
 
-var ipamAPILogger = logutils.Logger.Named("IPAM")
+var ipamLogger = logutils.Logger.Named("IPAM")
 
 // Singleton
 var (
@@ -26,11 +27,17 @@ type _unixPostAgentIpamIp struct{}
 
 // Handle handles POST requests for /ipam/ip .
 func (g *_unixPostAgentIpamIp) Handle(params daemonset.PostIpamIPParams) middleware.Responder {
-	// TODO (Icarus9913): return the http status code with logic.
-	resp, err := agentContext.IPAM.Allocate(params.HTTPRequest.Context(), params.IpamAddArgs)
+	logger := ipamLogger.With(zap.String("CNICommand", "ADD"),
+		zap.String("ContainerID", *params.IpamAddArgs.ContainerID),
+		zap.String("IfName", *params.IpamAddArgs.IfName),
+		zap.String("NetNamespace", *params.IpamAddArgs.NetNamespace),
+		zap.String("PodNamespace", *params.IpamAddArgs.PodNamespace),
+		zap.String("PodName", *params.IpamAddArgs.PodName))
+	ctx := logutils.IntoContext(params.HTTPRequest.Context(), logger)
+
+	resp, err := agentContext.IPAM.Allocate(ctx, params.IpamAddArgs)
 	if err != nil {
-		ipamAPILogger.Sugar().Errorf("Failed to allocate: %v", err)
-
+		logger.Sugar().Errorf("Failed to allocate: %v", err)
 		if errors.Is(err, constant.ErrWrongInput) {
 			return daemonset.NewPostIpamIPStatus512()
 		}
@@ -43,8 +50,7 @@ func (g *_unixPostAgentIpamIp) Handle(params daemonset.PostIpamIPParams) middlew
 		if errors.Is(err, constant.ErrIPUsedOut) {
 			return daemonset.NewPostIpamIPStatus515()
 		}
-
-		return daemonset.NewDeleteIpamIPInternalServerError()
+		return daemonset.NewPostIpamIPInternalServerError()
 	}
 
 	return daemonset.NewPostIpamIPOK().WithPayload(resp)
@@ -54,7 +60,18 @@ type _unixDeleteAgentIpamIp struct{}
 
 // Handle handles DELETE requests for /ipam/ip .
 func (g *_unixDeleteAgentIpamIp) Handle(params daemonset.DeleteIpamIPParams) middleware.Responder {
-	// TODO (Icarus9913): return the http status code with logic.
+	logger := ipamLogger.With(zap.String("CNICommand", "DEL"),
+		zap.String("ContainerID", *params.IpamDelArgs.ContainerID),
+		zap.String("IfName", *params.IpamDelArgs.IfName),
+		zap.String("NetNamespace", params.IpamDelArgs.NetNamespace),
+		zap.String("PodNamespace", *params.IpamDelArgs.PodNamespace),
+		zap.String("PodName", *params.IpamDelArgs.PodName))
+	ctx := logutils.IntoContext(params.HTTPRequest.Context(), logger)
+
+	if err := agentContext.IPAM.Release(ctx, params.IpamDelArgs); err != nil {
+		logger.Sugar().Errorf("Failed to release: %v", err)
+		return daemonset.NewDeleteIpamIPInternalServerError()
+	}
 
 	return daemonset.NewDeleteIpamIPOK()
 }
diff --git a/pkg/ipam/ipam.go b/pkg/ipam/ipam.go
index a1587aff9..b38e8554e 100644
--- a/pkg/ipam/ipam.go
+++ b/pkg/ipam/ipam.go
@@ -9,12 +9,13 @@ import (
 	"errors"
 	"fmt"
 	"strconv"
+	"strings"
+	"sync"
 	"time"
 
-	"go.uber.org/zap"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"sigs.k8s.io/controller-runtime/pkg/client"
+	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 
 	"github.com/spidernet-io/spiderpool/api/v1/agent/models"
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -27,12 +28,9 @@ import (
 	"github.com/spidernet-io/spiderpool/pkg/workloadendpointmanager"
 )
 
-var logger = logutils.Logger.Named("IPAM")
-
 type IPAM interface {
 	Allocate(ctx context.Context, addArgs *models.IpamAddArgs) (*models.IpamAddResponse, error)
 	Release(ctx context.Context, delArgs *models.IpamDelArgs) error
-	release(ctx context.Context, delArgs *models.IpamDelArgs) error
 }
 
 type IPAMConfig struct {
@@ -88,26 +86,9 @@ type ToBeAllocated struct {
 }
 
 func (i *ipam) Allocate(ctx context.Context, addArgs *models.IpamAddArgs) (*models.IpamAddResponse, error) {
-	logger := logger.With(zap.String("ContainerID", *addArgs.ContainerID),
-		zap.String("IfName", *addArgs.IfName),
-		zap.String("NetNamespace", *addArgs.NetNamespace),
-		zap.String("PodNamespace", *addArgs.PodNamespace),
-		zap.String("PodName", *addArgs.PodName))
+	logger := logutils.FromContext(ctx)
 	logger.Info("Start to allocate IP")
 
-	allocation, currently, err := i.weManager.RetriveIPAllocation(ctx, *addArgs.PodNamespace, *addArgs.PodName, *addArgs.ContainerID, *addArgs.IfName, true)
-	if client.IgnoreNotFound(err) != nil {
-		return nil, err
-	}
-
-	addResp := &models.IpamAddResponse{}
-	if allocation != nil && currently {
-		// TODO(iiiceoo): Return routes or DNS
-		logger.Sugar().Infof("Retrieve an existing IP allocation: %+v", allocation.IPs)
-		addResp.Ips = convertToIPConfigs(allocation.IPs)
-		return addResp, nil
-	}
-
 	pod, err := i.podManager.GetPodByName(ctx, *addArgs.PodNamespace, *addArgs.PodName)
 	if err != nil {
 		return nil, fmt.Errorf("failed to get pod %s: %v", *addArgs.PodName, err)
@@ -118,6 +99,22 @@ func (i *ipam) Allocate(ctx context.Context, addArgs *models.IpamAddArgs) (*mode
 		return nil, fmt.Errorf("pod is %s: %w", podStatus, constant.ErrNotAllocatablePod)
 	}
 
+	allocation, currently, err := i.weManager.RetriveIPAllocation(ctx, *addArgs.PodNamespace, *addArgs.PodName, *addArgs.ContainerID, *addArgs.IfName, false)
+	if err != nil {
+		return nil, err
+	}
+
+	addResp := &models.IpamAddResponse{}
+	if allocation != nil && currently {
+		logger.Sugar().Infof("Retrieve an existing IP allocation: %+v", allocation.IPs)
+		addResp.Ips = convertToIPConfigs(allocation.IPs)
+		// TODO(iiiceoo): Return routes or DNS
+		// addResp.DNS = xxx
+		// addResp.Routes = xxx
+
+		return addResp, nil
+	}
+
 	preliminary, err := getPodIPPoolCandidates(ctx, i.nsManager, i.ipamConfig, *addArgs.IfName, pod)
 	if err != nil {
 		return nil, err
@@ -133,98 +130,120 @@ func (i *ipam) Allocate(ctx context.Context, addArgs *models.IpamAddArgs) (*mode
 	ownerType := i.podManager.GetOwnerType(ctx, pod)
 	logger.Sugar().Infof("Pod owner type: %s", ownerType)
 
-	poolToIPConfigs := make(map[string][]*models.IPConfig)
-	podAnnotations := make(map[string]string, len(toBeAllocatedSet))
-	for _, e := range toBeAllocatedSet {
-		var v4Succeed, v6Succeed bool
-		annoPodAssigned := &types.AnnoPodAssignedEthxValue{
-			NIC: e.NIC,
+	var resIPs []*models.IPConfig
+	defer func() {
+		if err != nil {
+			if err := i.release(ctx, *addArgs.ContainerID, convertToIPAllocationDetails(resIPs)); err != nil {
+				logger.Sugar().Warnf("Failed to roll back allocated IP: %v", err)
+			}
 		}
+	}()
 
-		if len(e.V4PoolCandidates) != 0 {
-			var errs []error
-			for _, pool := range e.V4PoolCandidates {
-				ipv4, err := i.ipPoolManager.AllocateIP(ctx, ownerType, pool, *addArgs.ContainerID, *addArgs.IfName, pod)
-				if err != nil {
-					errs = append(errs, err)
-					logger.Sugar().Warnf("Failed to allocate IP(v4) to %s from IP pool %s: %v", e.NIC, pool, err)
-					continue
-				}
-				logger.Sugar().Infof("Allocate IP(v4) %s to %s from IP pool %s", *ipv4.Address, e.NIC, pool)
-				poolToIPConfigs[pool] = append(poolToIPConfigs[pool], ipv4)
-
-				annoPodAssigned.IPv4Pool = pool
-				annoPodAssigned.IPv4 = *ipv4.Address
-				annoPodAssigned.Vlan = strconv.FormatInt(ipv4.Vlan, 10)
+	resIPs, podAnnotations, err := execAllocate(ctx, i.ipPoolManager, toBeAllocatedSet, ownerType, *addArgs.ContainerID, pod)
+	if err != nil {
+		return nil, err
+	}
 
-				v4Succeed = true
-				break
-			}
+	err = i.podManager.MergeAnnotations(ctx, pod, podAnnotations)
+	if err != nil {
+		return nil, fmt.Errorf("failed to merge IP assignment annotation of pod: %v", err)
+	}
 
-			if !v4Succeed {
-				return nil, fmt.Errorf("failed to allocate any IP(v4) to %s from IP pools %v: %v", e.NIC, e.V4PoolCandidates, errs)
-			}
-		}
+	err = i.weManager.UpdateIPAllocation(ctx, *addArgs.PodNamespace, *addArgs.PodName, &spiderpoolv1.PodIPAllocation{
+		ContainerID:  *addArgs.ContainerID,
+		Node:         pod.Spec.NodeName,
+		IPs:          convertToIPAllocationDetails(resIPs),
+		CreationTime: metav1.Time{Time: time.Now()},
+	})
+	if err != nil {
+		return nil, fmt.Errorf("failed to update IP allocation of workload endpoint: %v", err)
+	}
 
-		if len(e.V6PoolCandidates) != 0 {
-			var errs []error
-			for _, pool := range e.V6PoolCandidates {
-				ipv6, err := i.ipPoolManager.AllocateIP(ctx, ownerType, pool, *addArgs.ContainerID, *addArgs.IfName, pod)
-				if err != nil {
-					errs = append(errs, err)
-					logger.Sugar().Warnf("Failed to allocate IP(v6) to %s from IP pool %s: %v", e.NIC, pool, err)
-					continue
-				}
-				logger.Sugar().Infof("Allocate IP(v6) %s to %s from IP pool %s", *ipv6.Address, e.NIC, pool)
-				poolToIPConfigs[pool] = append(poolToIPConfigs[pool], ipv6)
+	addResp.Ips = resIPs
+	logger.Sugar().Infof("Succeed to allocate: %+v", addResp)
 
-				annoPodAssigned.IPv6Pool = pool
-				annoPodAssigned.IPv6 = *ipv6.Address
-				annoPodAssigned.Vlan = strconv.FormatInt(ipv6.Vlan, 10)
+	return addResp, nil
+}
 
-				v6Succeed = true
-				break
-			}
+func (i *ipam) Release(ctx context.Context, delArgs *models.IpamDelArgs) error {
+	logger := logutils.FromContext(ctx)
+	logger.Info("Start to release IP")
 
-			if !v6Succeed {
-				return nil, fmt.Errorf("failed to allocate any IP(v6) to %s from IP pools %v: %v", e.NIC, e.V6PoolCandidates, errs)
-			}
-		}
+	allocation, currently, err := i.weManager.RetriveIPAllocation(ctx, *delArgs.PodNamespace, *delArgs.PodName, *delArgs.ContainerID, *delArgs.IfName, true)
+	if err != nil {
+		return err
+	}
 
-		v, err := json.Marshal(annoPodAssigned)
-		if err != nil {
-			return nil, err
-		}
-		podAnnotations[constant.AnnotationPre+"/assigned-"+e.NIC] = string(v)
+	if allocation == nil {
+		logger.Info("Nothing retrieved for releasing")
+		return nil
 	}
 
-	for _, v := range poolToIPConfigs {
-		addResp.Ips = append(addResp.Ips, v...)
+	if !currently {
+		logger.Warn("Request to release a non current IP allocation, there may be concurrency between the same pod")
 	}
 
-	if err := i.podManager.MergeAnnotations(ctx, pod, podAnnotations); err != nil {
-		return nil, fmt.Errorf("failed to merge the IP assignment annotation of pod: %v", err)
+	if err = i.release(ctx, allocation.ContainerID, allocation.IPs); err != nil {
+		return err
 	}
 
-	if err := i.weManager.UpdateIPAllocation(ctx, *addArgs.PodNamespace, *addArgs.PodName, &spiderpoolv1.PodIPAllocation{
-		ContainerID:  *addArgs.ContainerID,
-		Node:         pod.Spec.NodeName,
-		IPs:          convertToIPAllocationDetails(poolToIPConfigs),
-		CreationTime: metav1.Time{Time: time.Now()},
-	}); err != nil {
-		return nil, fmt.Errorf("failed to update the IP allocation of workload endpoint: %v", err)
+	if err := i.weManager.ClearCurrentIPAllocation(ctx, *delArgs.PodNamespace, *delArgs.PodName, *delArgs.ContainerID, *delArgs.IfName); err != nil {
+		return err
 	}
 
-	logger.Sugar().Infof("Succeed to allocate: %+v", addResp)
+	logger.Sugar().Infof("Succeed to release: %+v", allocation.IPs)
 
-	return addResp, nil
+	return nil
 }
 
-func (i *ipam) Release(ctx context.Context, delArgs *models.IpamDelArgs) error {
-	return i.release(ctx, delArgs)
-}
+func (i *ipam) release(ctx context.Context, containerID string, details []spiderpoolv1.IPAllocationDetail) error {
+	logger := logutils.FromContext(ctx)
+
+	if len(details) == 0 {
+		return nil
+	}
+
+	poolToIPAndCIDs := map[string][]ippoolmanager.IPAndContainerID{}
+	for _, d := range details {
+		if d.IPv4 != nil {
+			poolToIPAndCIDs[*d.IPv4Pool] = append(poolToIPAndCIDs[*d.IPv4Pool], ippoolmanager.IPAndContainerID{
+				IP:          strings.Split(*d.IPv4, "/")[0],
+				ContainerID: containerID,
+			})
+		}
+		if d.IPv6 != nil {
+			poolToIPAndCIDs[*d.IPv6Pool] = append(poolToIPAndCIDs[*d.IPv6Pool], ippoolmanager.IPAndContainerID{
+				IP:          strings.Split(*d.IPv6, "/")[0],
+				ContainerID: containerID,
+			})
+		}
+	}
+
+	errCh := make(chan error, len(poolToIPAndCIDs))
+	wg := sync.WaitGroup{}
+	wg.Add(len(poolToIPAndCIDs))
+
+	for pool, ipAndCIDs := range poolToIPAndCIDs {
+		go func(pool string, ipAndCIDs []ippoolmanager.IPAndContainerID) {
+			defer wg.Done()
+			if err := i.ipPoolManager.ReleaseIP(ctx, pool, ipAndCIDs); err != nil {
+				errCh <- err
+			}
+			logger.Sugar().Infof("Succeed to release IP %+v from IP pool %s", ipAndCIDs, pool)
+		}(pool, ipAndCIDs)
+	}
+	wg.Wait()
+	close(errCh)
+
+	var errs []error
+	for err := range errCh {
+		errs = append(errs, err)
+	}
+
+	if len(errs) != 0 {
+		return fmt.Errorf("failed to release all allocated IP %+v: %v", poolToIPAndCIDs, utilerrors.NewAggregate(errs).Error())
+	}
 
-func (i *ipam) release(ctx context.Context, delArgs *models.IpamDelArgs) error {
 	return nil
 }
 
@@ -232,63 +251,82 @@ func convertToIPConfigs(details []spiderpoolv1.IPAllocationDetail) []*models.IPC
 	var ipConfigs []*models.IPConfig
 	for _, d := range details {
 		var version int64
-		var address string
 		if d.IPv4 != nil {
 			version = 4
-			address = *d.IPv4
-		} else {
-			version = 6
-			address = *d.IPv6
+			ipConfigs = append(ipConfigs, &models.IPConfig{
+				Address: d.IPv4,
+				Nic:     &d.NIC,
+				Version: &version,
+				Vlan:    int64(*d.Vlan),
+				Gateway: *d.IPv4Gateway,
+			})
 		}
 
-		ipConfigs = append(ipConfigs, &models.IPConfig{
-			Address: &address,
-			Gateway: *d.Gateway,
-			Nic:     &d.NIC,
-			Version: &version,
-			Vlan:    int64(*d.Vlan),
-		})
+		if d.IPv6 != nil {
+			version = 6
+			ipConfigs = append(ipConfigs, &models.IPConfig{
+				Address: d.IPv6,
+				Nic:     &d.NIC,
+				Version: &version,
+				Vlan:    int64(*d.Vlan),
+				Gateway: *d.IPv6Gateway,
+			})
+		}
 	}
 
 	return ipConfigs
 }
 
-func convertToIPAllocationDetails(poolToIPConfigs map[string][]*models.IPConfig) []spiderpoolv1.IPAllocationDetail {
-	var details []spiderpoolv1.IPAllocationDetail
-	for pool, ipConfigs := range poolToIPConfigs {
-		for _, c := range ipConfigs {
-			var ipv4Pool, ipv6Pool string
-			var ipv4, ipv6 string
+func convertToIPAllocationDetails(ipConfigs []*models.IPConfig) []spiderpoolv1.IPAllocationDetail {
+	nicToDetail := map[string]*spiderpoolv1.IPAllocationDetail{}
+	for _, c := range ipConfigs {
+		if d, ok := nicToDetail[*c.Nic]; ok {
 			if *c.Version == 4 {
-				ipv4Pool = pool
-				ipv4 = *c.Address
+				d.IPv4 = c.Address
+				d.IPv4Pool = &c.IPPool
+				d.IPv4Gateway = &c.Gateway
 			} else {
-				ipv6Pool = pool
-				ipv6 = *c.Address
+				d.IPv6 = c.Address
+				d.IPv6Pool = &c.IPPool
+				d.IPv6Gateway = &c.Gateway
 			}
+		} else {
 			vlan := spiderpoolv1.Vlan(c.Vlan)
-
-			details = append(details, spiderpoolv1.IPAllocationDetail{
-				NIC:      *c.Nic,
-				IPv4:     &ipv4,
-				IPv6:     &ipv6,
-				IPv4Pool: &ipv4Pool,
-				IPv6Pool: &ipv6Pool,
-				Vlan:     &vlan,
-				Gateway:  &c.Gateway,
-				// TODO(iiiceoo): Routes
-			})
+			if *c.Version == 4 {
+				nicToDetail[*c.Nic] = &spiderpoolv1.IPAllocationDetail{
+					NIC:         *c.Nic,
+					IPv4:        c.Address,
+					IPv4Pool:    &c.IPPool,
+					Vlan:        &vlan,
+					IPv4Gateway: &c.Gateway,
+				}
+			} else {
+				nicToDetail[*c.Nic] = &spiderpoolv1.IPAllocationDetail{
+					NIC:         *c.Nic,
+					IPv6:        c.Address,
+					IPv6Pool:    &c.IPPool,
+					Vlan:        &vlan,
+					IPv6Gateway: &c.Gateway,
+				}
+			}
 		}
 	}
 
+	details := []spiderpoolv1.IPAllocationDetail{}
+	for _, d := range nicToDetail {
+		details = append(details, *d)
+	}
+
 	return details
 }
 
 func getPodIPPoolCandidates(ctx context.Context, nsManager namespacemanager.NamespaceManager, ipamConfig *IPAMConfig, nic string, pod *corev1.Pod) ([]ToBeAllocated, error) {
 	// TODO(iiiceoo): Validate annotations
+	logger := logutils.FromContext(ctx)
+
 	var preliminary []ToBeAllocated
 	if anno, ok := pod.Annotations[constant.AnnoPodIPPools]; ok {
-		logger.Sugar().Infof("Use IP pools from Pod annotation \"%s\"", constant.AnnoPodIPPools)
+		logger.Sugar().Infof("Use IP pools from Pod annotation '%s'", constant.AnnoPodIPPools)
 		var annoPodIPPools types.AnnoPodIPPoolsValue
 		err := json.Unmarshal([]byte(anno), &annoPodIPPools)
 		if err != nil {
@@ -303,14 +341,14 @@ func getPodIPPoolCandidates(ctx context.Context, nsManager namespacemanager.Name
 			})
 		}
 	} else if anno, ok := pod.Annotations[constant.AnnoPodIPPool]; ok {
-		logger.Sugar().Infof("Use IP pools from Pod annotation \"%s\"", constant.AnnoPodIPPool)
+		logger.Sugar().Infof("Use IP pools from Pod annotation '%s'", constant.AnnoPodIPPool)
 		var annoPodIPPool types.AnnoPodIPPoolValue
 		if err := json.Unmarshal([]byte(anno), &annoPodIPPool); err != nil {
 			return nil, err
 		}
 
 		if annoPodIPPool.NIC != nil && *annoPodIPPool.NIC != nic {
-			return nil, fmt.Errorf("interface of pod annotaiton is not same with the runtime request: %w", constant.ErrWrongInput)
+			return nil, fmt.Errorf("interface of pod annotaiton is not same with runtime request: %w", constant.ErrWrongInput)
 		}
 
 		preliminary = append(preliminary, ToBeAllocated{
@@ -325,7 +363,7 @@ func getPodIPPoolCandidates(ctx context.Context, nsManager namespacemanager.Name
 		}
 
 		if !(nsDefautlV4Pools == nil && nsDefautlV6Pools == nil) {
-			logger.Sugar().Infof("Use IP pools from Namespace annotation \"%s\"", constant.AnnotationPre+"/defaultv(4/6)ippool")
+			logger.Sugar().Infof("Use IP pools from Namespace annotation '%s'", constant.AnnotationPre+"/defaultv(4/6)ippool")
 			preliminary = append(preliminary, ToBeAllocated{
 				NIC:              nic,
 				V4PoolCandidates: nsDefautlV4Pools,
@@ -402,3 +440,75 @@ func filterPodIPPoolCandidates(ctx context.Context, ipPoolManager ippoolmanager.
 
 	return toBeAllocatedSet, nil
 }
+
+// TODO(iiiceoo): refactor
+func execAllocate(ctx context.Context, ipPoolManager ippoolmanager.IPPoolManager, toBeAllocatedSet []ToBeAllocated, ownerType types.OwnerType, containerID string, pod *corev1.Pod) ([]*models.IPConfig, map[string]string, error) {
+	logger := logutils.FromContext(ctx)
+
+	resIPs := []*models.IPConfig{}
+	podAnnotations := map[string]string{}
+	for _, e := range toBeAllocatedSet {
+		var v4Succeed, v6Succeed bool
+		annoPodAssigned := &types.AnnoPodAssignedEthxValue{
+			NIC: e.NIC,
+		}
+
+		if len(e.V4PoolCandidates) != 0 {
+			var errs []error
+			for _, pool := range e.V4PoolCandidates {
+				ipv4, err := ipPoolManager.AllocateIP(ctx, ownerType, pool, containerID, e.NIC, pod)
+				if err != nil {
+					errs = append(errs, err)
+					logger.Sugar().Warnf("Failed to allocate IP(v4) to %s from IP pool %s: %v", e.NIC, pool, err)
+					continue
+				}
+				logger.Sugar().Infof("Allocate IP(v4) %s to %s from IP pool %s", *ipv4.Address, e.NIC, pool)
+				resIPs = append(resIPs, ipv4)
+
+				annoPodAssigned.IPv4Pool = ipv4.IPPool
+				annoPodAssigned.IPv4 = *ipv4.Address
+				annoPodAssigned.Vlan = strconv.FormatInt(ipv4.Vlan, 10)
+
+				v4Succeed = true
+				break
+			}
+
+			if !v4Succeed {
+				return resIPs, nil, fmt.Errorf("failed to allocate any IP(v4) to %s from IP pools %v: %v", e.NIC, e.V4PoolCandidates, utilerrors.NewAggregate(errs).Error())
+			}
+		}
+
+		if len(e.V6PoolCandidates) != 0 {
+			var errs []error
+			for _, pool := range e.V6PoolCandidates {
+				ipv6, err := ipPoolManager.AllocateIP(ctx, ownerType, pool, containerID, e.NIC, pod)
+				if err != nil {
+					errs = append(errs, err)
+					logger.Sugar().Warnf("Failed to allocate IP(v6) to %s from IP pool %s: %v", e.NIC, pool, err)
+					continue
+				}
+				logger.Sugar().Infof("Allocate IP(v6) %s to %s from IP pool %s", *ipv6.Address, e.NIC, pool)
+				resIPs = append(resIPs, ipv6)
+
+				annoPodAssigned.IPv6Pool = ipv6.IPPool
+				annoPodAssigned.IPv6 = *ipv6.Address
+				annoPodAssigned.Vlan = strconv.FormatInt(ipv6.Vlan, 10)
+
+				v6Succeed = true
+				break
+			}
+
+			if !v6Succeed {
+				return resIPs, nil, fmt.Errorf("failed to allocate any IP(v6) to %s from IP pools %v: %v", e.NIC, e.V6PoolCandidates, utilerrors.NewAggregate(errs).Error())
+			}
+		}
+
+		v, err := json.Marshal(annoPodAssigned)
+		if err != nil {
+			return nil, nil, err
+		}
+		podAnnotations[constant.AnnotationPre+"/assigned-"+e.NIC] = string(v)
+	}
+
+	return resIPs, podAnnotations, nil
+}
diff --git a/pkg/ippoolmanager/ippool_manager.go b/pkg/ippoolmanager/ippool_manager.go
index d510af81e..f741e31a2 100644
--- a/pkg/ippoolmanager/ippool_manager.go
+++ b/pkg/ippoolmanager/ippool_manager.go
@@ -27,11 +27,9 @@ import (
 	"github.com/spidernet-io/spiderpool/pkg/types"
 )
 
-var logger = logutils.Logger.Named("IPPool Manager")
-
 type IPPoolManager interface {
 	AllocateIP(ctx context.Context, ownerType types.OwnerType, poolName, containerID, nic string, pod *corev1.Pod) (*models.IPConfig, error)
-	ReleaseIP(ctx context.Context, poolName, containerID string, pod *corev1.Pod) error
+	ReleaseIP(ctx context.Context, poolName string, ipAndCIDs []IPAndContainerID) error
 	ListPoolAll(ctx context.Context) (*spiderpoolv1.IPPoolList, error)
 	SelectByPod(ctx context.Context, version string, poolName string, pod *corev1.Pod) (bool, error)
 	CheckVlanSame(ctx context.Context, poolList []string) (map[spiderpoolv1.Vlan][]string, bool, error)
@@ -129,23 +127,19 @@ func (r *ipPoolManager) AllocateIP(ctx context.Context, ownerType types.OwnerTyp
 		}
 
 		// TODO(iiiceoo): Remove when Defaulter webhook work
-		if ipPool.Status.AllocateCount == nil {
-			ipPool.Status.AllocateCount = new(int64)
-		}
 		if ipPool.Status.AllocatedIPCount == nil {
 			ipPool.Status.AllocatedIPCount = new(int32)
 		}
 
-		*ipPool.Status.AllocateCount++
 		*ipPool.Status.AllocatedIPCount++
 		if *ipPool.Status.AllocatedIPCount > int32(r.maxAllocatedIPs) {
-			return nil, fmt.Errorf("threshold for the sum of IP allocations(<=%d) exceeded: %w", r.maxAllocatedIPs, constant.ErrIPUsedOut)
+			return nil, fmt.Errorf("threshold of IP allocations(<=%d) for IP pool exceeded: %w", r.maxAllocatedIPs, constant.ErrIPUsedOut)
 		}
 
 		if err := r.client.Status().Update(ctx, &ipPool); err != nil {
 			if apierrors.IsConflict(err) {
 				if i == r.maxConflictRetrys {
-					return nil, fmt.Errorf("insufficient retries(<=%d) to update IP pool", r.maxConflictRetrys)
+					return nil, fmt.Errorf("insufficient retries(<=%d) to allocate IP from IP pool %s", r.maxConflictRetrys, poolName)
 				}
 
 				time.Sleep(time.Duration(rand.Intn(1<<(i+1))) * time.Second)
@@ -154,10 +148,9 @@ func (r *ipPoolManager) AllocateIP(ctx context.Context, ownerType types.OwnerTyp
 			return nil, err
 		}
 
-		var address string
 		ipNet := ip.ParseIP(ipPool.Spec.Subnet)
 		ipNet.IP = allocateIP
-		address = ipNet.String()
+		address := ipNet.String()
 
 		var version int64
 		if *ipPool.Spec.IPVersion == spiderpoolv1.IPv4 {
@@ -175,6 +168,7 @@ func (r *ipPoolManager) AllocateIP(ctx context.Context, ownerType types.OwnerTyp
 		ipConfig = &models.IPConfig{
 			Address: &address,
 			Gateway: gateway,
+			IPPool:  poolName,
 			Nic:     &nic,
 			Version: &version,
 			Vlan:    int64(*ipPool.Spec.Vlan),
@@ -185,7 +179,56 @@ func (r *ipPoolManager) AllocateIP(ctx context.Context, ownerType types.OwnerTyp
 	return ipConfig, nil
 }
 
-func (r *ipPoolManager) ReleaseIP(ctx context.Context, poolName, containerID string, pod *corev1.Pod) error {
+type IPAndContainerID struct {
+	IP          string
+	ContainerID string
+}
+
+func (r *ipPoolManager) ReleaseIP(ctx context.Context, poolName string, ipAndCIDs []IPAndContainerID) error {
+	rand.Seed(time.Now().UnixNano())
+	for i := 0; i <= r.maxConflictRetrys; i++ {
+		var ipPool spiderpoolv1.IPPool
+		if err := r.client.Get(ctx, apitypes.NamespacedName{Name: poolName}, &ipPool); err != nil {
+			return err
+		}
+
+		// TODO(iiiceoo): Remove when Defaulter webhook work
+		if ipPool.Status.AllocatedIPs == nil {
+			ipPool.Status.AllocatedIPs = spiderpoolv1.PoolIPAllocations{}
+		}
+		if ipPool.Status.AllocatedIPCount == nil {
+			ipPool.Status.AllocatedIPCount = new(int32)
+		}
+
+		needRelease := false
+		for _, e := range ipAndCIDs {
+			if a, ok := ipPool.Status.AllocatedIPs[e.IP]; ok {
+				if a.ContainerID == e.ContainerID {
+					delete(ipPool.Status.AllocatedIPs, e.IP)
+					*ipPool.Status.AllocatedIPCount--
+					needRelease = true
+				}
+			}
+		}
+
+		if !needRelease {
+			return nil
+		}
+
+		if err := r.client.Status().Update(ctx, &ipPool); err != nil {
+			if apierrors.IsConflict(err) {
+				if i == r.maxConflictRetrys {
+					return fmt.Errorf("insufficient retries(<=%d) to release IP %+v from IP pool %s", r.maxConflictRetrys, ipAndCIDs, poolName)
+				}
+
+				time.Sleep(time.Duration(rand.Intn(1<<(i+1))) * time.Second)
+				continue
+			}
+			return err
+		}
+		break
+	}
+
 	return nil
 }
 
@@ -194,6 +237,8 @@ func (r *ipPoolManager) ListPoolAll(ctx context.Context) (*spiderpoolv1.IPPoolLi
 }
 
 func (r *ipPoolManager) SelectByPod(ctx context.Context, version string, poolName string, pod *corev1.Pod) (bool, error) {
+	logger := logutils.FromContext(ctx).Named("IPPoolManager")
+
 	var ipPool spiderpoolv1.IPPool
 	if err := r.client.Get(ctx, apitypes.NamespacedName{Name: poolName}, &ipPool); err != nil {
 		logger.Sugar().Warnf("IP pool %s is not found", poolName)
@@ -252,7 +297,7 @@ func (r *ipPoolManager) SelectByPod(ctx context.Context, version string, poolNam
 }
 
 func (r *ipPoolManager) CheckVlanSame(ctx context.Context, poolList []string) (map[spiderpoolv1.Vlan][]string, bool, error) {
-	vlanToPools := make(map[spiderpoolv1.Vlan][]string)
+	vlanToPools := map[spiderpoolv1.Vlan][]string{}
 	for _, p := range poolList {
 		var ipPool spiderpoolv1.IPPool
 		if err := r.client.Get(ctx, apitypes.NamespacedName{Name: p}, &ipPool); err != nil {
diff --git a/pkg/k8s/apis/v1/ippool_types.go b/pkg/k8s/apis/v1/ippool_types.go
index 9d3878297..ba9d83753 100644
--- a/pkg/k8s/apis/v1/ippool_types.go
+++ b/pkg/k8s/apis/v1/ippool_types.go
@@ -108,18 +108,6 @@ type IPPoolStatus struct {
 
 	// TODO
 
-	// +kubebuilder:validation:Minimum=0
-	// +kubebuilder:validation:Optional
-	AllocateCount *int64 `json:"allocateCount,omitempty"`
-
-	// TODO
-
-	// +kubebuilder:validation:Minimum=0
-	// +kubebuilder:validation:Optional
-	DeallocateCount *int64 `json:"deallocateCount,omitempty"`
-
-	// TODO
-
 	// +kubebuilder:validation:Minimum=0
 	// +kubebuilder:validation:Optional
 	TotalIPCount *int32 `json:"totalIPCount,omitempty"`
diff --git a/pkg/k8s/apis/v1/workloadendpoint_types.go b/pkg/k8s/apis/v1/workloadendpoint_types.go
index 4a091df8b..5b7f9c598 100644
--- a/pkg/k8s/apis/v1/workloadendpoint_types.go
+++ b/pkg/k8s/apis/v1/workloadendpoint_types.go
@@ -79,12 +79,12 @@ type IPAllocationDetail struct {
 	// TODO
 
 	// +kubebuilder:validation:Optional
-	Routes []Route `json:"routes,omitempty"`
+	IPv4Gateway *string `json:"ipv4Gateway,omitempty"`
 
 	// TODO
 
 	// +kubebuilder:validation:Optional
-	Gateway *string `json:"gateway,omitempty"`
+	IPv6Gateway *string `json:"ipv6Gateway,omitempty"`
 }
 
 // +kubebuilder:resource:categories={spiderpool},path="workloadendpoints",scope="Namespaced",shortName={swe},singular="workloadendpoint"
diff --git a/pkg/k8s/apis/v1/zz_generated.deepcopy.go b/pkg/k8s/apis/v1/zz_generated.deepcopy.go
index 394ed74fe..872251ef5 100644
--- a/pkg/k8s/apis/v1/zz_generated.deepcopy.go
+++ b/pkg/k8s/apis/v1/zz_generated.deepcopy.go
@@ -41,13 +41,13 @@ func (in *IPAllocationDetail) DeepCopyInto(out *IPAllocationDetail) {
 		*out = new(Vlan)
 		**out = **in
 	}
-	if in.Routes != nil {
-		in, out := &in.Routes, &out.Routes
-		*out = make([]Route, len(*in))
-		copy(*out, *in)
+	if in.IPv4Gateway != nil {
+		in, out := &in.IPv4Gateway, &out.IPv4Gateway
+		*out = new(string)
+		**out = **in
 	}
-	if in.Gateway != nil {
-		in, out := &in.Gateway, &out.Gateway
+	if in.IPv6Gateway != nil {
+		in, out := &in.IPv6Gateway, &out.IPv6Gateway
 		*out = new(string)
 		**out = **in
 	}
@@ -197,16 +197,6 @@ func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) {
 			(*out)[key] = val
 		}
 	}
-	if in.AllocateCount != nil {
-		in, out := &in.AllocateCount, &out.AllocateCount
-		*out = new(int64)
-		**out = **in
-	}
-	if in.DeallocateCount != nil {
-		in, out := &in.DeallocateCount, &out.DeallocateCount
-		*out = new(int64)
-		**out = **in
-	}
 	if in.TotalIPCount != nil {
 		in, out := &in.TotalIPCount, &out.TotalIPCount
 		*out = new(int32)
diff --git a/pkg/logutils/log.go b/pkg/logutils/log.go
index b8e58a7ad..391f3cde7 100644
--- a/pkg/logutils/log.go
+++ b/pkg/logutils/log.go
@@ -4,6 +4,7 @@
 package logutils
 
 import (
+	"context"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -218,3 +219,24 @@ func InitFileLogger(logLevel LogLevel, filePath string, fileMaxSize, fileMaxAge,
 	LoggerFile = l
 	return nil
 }
+
+// loggerKey is how we find Loggers in a context.Context.
+type loggerKey struct{}
+
+// FromContext returns a logger with predefined values from a context.Context.
+func FromContext(ctx context.Context) *zap.Logger {
+	log := Logger
+	if ctx != nil {
+		if logger, ok := ctx.Value(loggerKey{}).(*zap.Logger); ok {
+			log = logger
+		}
+	}
+
+	return log
+}
+
+// IntoContext takes a context and sets the logger as one of its values.
+// Use FromContext function to retrieve the logger.
+func IntoContext(ctx context.Context, logger *zap.Logger) context.Context {
+	return context.WithValue(ctx, loggerKey{}, logger)
+}
diff --git a/pkg/namespacemanager/namespace_manager.go b/pkg/namespacemanager/namespace_manager.go
index 4800408a0..86b6aed45 100644
--- a/pkg/namespacemanager/namespace_manager.go
+++ b/pkg/namespacemanager/namespace_manager.go
@@ -11,6 +11,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	apitypes "k8s.io/apimachinery/pkg/types"
+	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -23,16 +24,29 @@ type NamespaceManager interface {
 }
 
 type namespaceManager struct {
-	client client.Client
+	client     client.Client
+	runtimeMgr ctrl.Manager
 }
 
-func NewNamespaceManager(c client.Client) (NamespaceManager, error) {
+func NewNamespaceManager(c client.Client, mgr ctrl.Manager) (NamespaceManager, error) {
 	if c == nil {
 		return nil, errors.New("k8s client must be specified")
 	}
 
+	if mgr == nil {
+		return nil, errors.New("runtime manager must be specified")
+	}
+
+	if err := mgr.GetFieldIndexer().IndexField(context.Background(), &corev1.Namespace{}, metav1.ObjectNameField, func(raw client.Object) []string {
+		namespace := raw.(*corev1.Namespace)
+		return []string{namespace.Name}
+	}); err != nil {
+		return nil, err
+	}
+
 	return &namespaceManager{
-		client: c,
+		client:     c,
+		runtimeMgr: mgr,
 	}, nil
 }
 
@@ -70,7 +84,7 @@ func (r *namespaceManager) MatchLabelSelector(ctx context.Context, nsName string
 		ctx,
 		&namespaces,
 		client.MatchingLabelsSelector{Selector: selector},
-		client.MatchingFields{".metadata.name": nsName},
+		client.MatchingFields{metav1.ObjectNameField: nsName},
 	)
 	if err != nil {
 		return false, err
diff --git a/pkg/nodemanager/node_manager.go b/pkg/nodemanager/node_manager.go
index 352d38e74..2fa8bc05a 100644
--- a/pkg/nodemanager/node_manager.go
+++ b/pkg/nodemanager/node_manager.go
@@ -9,6 +9,7 @@ import (
 
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
@@ -17,16 +18,29 @@ type NodeManager interface {
 }
 
 type nodeManager struct {
-	client client.Client
+	client     client.Client
+	runtimeMgr ctrl.Manager
 }
 
-func NewNodeManager(c client.Client) (NodeManager, error) {
+func NewNodeManager(c client.Client, mgr ctrl.Manager) (NodeManager, error) {
 	if c == nil {
 		return nil, errors.New("k8s client must be specified")
 	}
 
+	if mgr == nil {
+		return nil, errors.New("runtime manager must be specified")
+	}
+
+	if err := mgr.GetFieldIndexer().IndexField(context.Background(), &corev1.Node{}, metav1.ObjectNameField, func(raw client.Object) []string {
+		node := raw.(*corev1.Node)
+		return []string{node.Name}
+	}); err != nil {
+		return nil, err
+	}
+
 	return &nodeManager{
-		client: c,
+		client:     c,
+		runtimeMgr: mgr,
 	}, nil
 }
 
@@ -41,7 +55,7 @@ func (r *nodeManager) MatchLabelSelector(ctx context.Context, nodeName string, l
 		ctx,
 		&nodes,
 		client.MatchingLabelsSelector{Selector: selector},
-		client.MatchingFields{".metadata.name": nodeName},
+		client.MatchingFields{metav1.ObjectNameField: nodeName},
 	)
 	if err != nil {
 		return false, err
diff --git a/pkg/podmanager/pod_manager.go b/pkg/podmanager/pod_manager.go
index 77c30a599..b3fc87a8e 100644
--- a/pkg/podmanager/pod_manager.go
+++ b/pkg/podmanager/pod_manager.go
@@ -14,6 +14,7 @@ import (
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	apitypes "k8s.io/apimachinery/pkg/types"
+	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -30,16 +31,29 @@ type PodManager interface {
 
 type podManager struct {
 	client            client.Client
+	runtimeMgr        ctrl.Manager
 	maxConflictRetrys int
 }
 
-func NewPodManager(c client.Client, maxConflictRetrys int) (PodManager, error) {
+func NewPodManager(c client.Client, mgr ctrl.Manager, maxConflictRetrys int) (PodManager, error) {
 	if c == nil {
 		return nil, errors.New("k8s client must be specified")
 	}
 
+	if mgr == nil {
+		return nil, errors.New("runtime manager must be specified")
+	}
+
+	if err := mgr.GetFieldIndexer().IndexField(context.Background(), &corev1.Pod{}, metav1.ObjectNameField, func(raw client.Object) []string {
+		pod := raw.(*corev1.Pod)
+		return []string{pod.Name}
+	}); err != nil {
+		return nil, err
+	}
+
 	return &podManager{
 		client:            c,
+		runtimeMgr:        mgr,
 		maxConflictRetrys: maxConflictRetrys,
 	}, nil
 }
@@ -100,7 +114,7 @@ func (r *podManager) IsIPAllocatable(ctx context.Context, pod *corev1.Pod) (type
 }
 
 func (r *podManager) MergeAnnotations(ctx context.Context, pod *corev1.Pod, annotations map[string]string) error {
-	merge := make(map[string]string)
+	merge := map[string]string{}
 	for k, v := range pod.Annotations {
 		merge[k] = v
 	}
@@ -116,7 +130,7 @@ func (r *podManager) MergeAnnotations(ctx context.Context, pod *corev1.Pod, anno
 		if err := r.client.Update(ctx, pod); err != nil {
 			if apierrors.IsConflict(err) {
 				if i == r.maxConflictRetrys {
-					return fmt.Errorf("insufficient retries(<=%d) to update Pod annotations", r.maxConflictRetrys)
+					return fmt.Errorf("insufficient retries(<=%d) to merge Pod annotations", r.maxConflictRetrys)
 				}
 
 				time.Sleep(time.Duration(rand.Intn(1<<(i+1))) * time.Second)
@@ -124,6 +138,7 @@ func (r *podManager) MergeAnnotations(ctx context.Context, pod *corev1.Pod, anno
 			}
 			return err
 		}
+		break
 	}
 
 	return nil
@@ -141,7 +156,7 @@ func (r *podManager) MatchLabelSelector(ctx context.Context, namespace, podName
 		&pods,
 		client.InNamespace(namespace),
 		client.MatchingLabelsSelector{Selector: selector},
-		client.MatchingFields{".metadata.name": podName},
+		client.MatchingFields{metav1.ObjectNameField: podName},
 	)
 	if err != nil {
 		return false, err
diff --git a/pkg/reservedipmanager/reservedip_manager.go b/pkg/reservedipmanager/reservedip_manager.go
index 35a73b89c..9b014aefc 100644
--- a/pkg/reservedipmanager/reservedip_manager.go
+++ b/pkg/reservedipmanager/reservedip_manager.go
@@ -7,6 +7,7 @@ import (
 	"context"
 	"errors"
 
+	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/v1"
@@ -17,22 +18,35 @@ type ReservedIPManager interface {
 }
 
 type reservedIPManager struct {
-	client client.Client
+	client     client.Client
+	runtimeMgr ctrl.Manager
 }
 
-func NewReservedIPManager(c client.Client) (ReservedIPManager, error) {
+func NewReservedIPManager(c client.Client, mgr ctrl.Manager) (ReservedIPManager, error) {
 	if c == nil {
 		return nil, errors.New("k8s client must be specified")
 	}
 
+	if mgr == nil {
+		return nil, errors.New("runtime manager must be specified")
+	}
+
+	if err := mgr.GetFieldIndexer().IndexField(context.Background(), &spiderpoolv1.ReservedIP{}, "spec.ipVersion", func(raw client.Object) []string {
+		reservedIP := raw.(*spiderpoolv1.ReservedIP)
+		return []string{string(*reservedIP.Spec.IPVersion)}
+	}); err != nil {
+		return nil, err
+	}
+
 	return &reservedIPManager{
-		client: c,
+		client:     c,
+		runtimeMgr: mgr,
 	}, nil
 }
 
 func (r *reservedIPManager) GetReservedIPRanges(ctx context.Context, version string) ([]string, error) {
 	var reservedIPs spiderpoolv1.ReservedIPList
-	if err := r.client.List(ctx, &reservedIPs, client.MatchingFields{".spec.ipVersion": version}); err != nil {
+	if err := r.client.List(ctx, &reservedIPs, client.MatchingFields{"spec.ipVersion": version}); err != nil {
 		return nil, err
 	}
 
diff --git a/pkg/workloadendpointmanager/workloadendpoint_manager.go b/pkg/workloadendpointmanager/workloadendpoint_manager.go
index b230c24d5..7b05aa454 100644
--- a/pkg/workloadendpointmanager/workloadendpoint_manager.go
+++ b/pkg/workloadendpointmanager/workloadendpoint_manager.go
@@ -13,12 +13,13 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/v1"
+	"github.com/spidernet-io/spiderpool/pkg/logutils"
 )
 
 type WorkloadEndpointManager interface {
 	RetriveIPAllocation(ctx context.Context, namespace, podName, containerID, nic string, includeHistory bool) (*spiderpoolv1.PodIPAllocation, bool, error)
 	UpdateIPAllocation(ctx context.Context, namespace, podName string, allocation *spiderpoolv1.PodIPAllocation) error
-	ClearCurrentIPs(ctx context.Context, namspace, podName, containerID string) error
+	ClearCurrentIPAllocation(ctx context.Context, namespace, podName, containerID, nic string) error
 	Delete(ctx context.Context, we *spiderpoolv1.WorkloadEndpoint) error
 }
 
@@ -41,23 +42,26 @@ func NewWorkloadEndpointManager(c client.Client, maxHistoryRecords int) (Workloa
 func (r *workloadEndpointManager) RetriveIPAllocation(ctx context.Context, namespace, podName, containerID, nic string, includeHistory bool) (*spiderpoolv1.PodIPAllocation, bool, error) {
 	var we spiderpoolv1.WorkloadEndpoint
 	if err := r.client.Get(ctx, apitypes.NamespacedName{Namespace: namespace, Name: podName}, &we); err != nil {
+		if apierrors.IsNotFound(err) {
+			return nil, false, nil
+		}
 		return nil, false, err
 	}
 
-	if we.Status.Current.ContainerID == containerID {
+	if we.Status.Current != nil && we.Status.Current.ContainerID == containerID {
 		for _, d := range we.Status.Current.IPs {
 			if d.NIC == nic {
 				return we.Status.Current, true, nil
 			}
 		}
-	} else {
-		if includeHistory {
-			for _, a := range we.Status.History {
-				if a.ContainerID == containerID {
-					for _, d := range a.IPs {
-						if d.NIC == nic {
-							return &a, false, nil
-						}
+	}
+
+	if includeHistory {
+		for _, a := range we.Status.History[1:] {
+			if a.ContainerID == containerID {
+				for _, d := range a.IPs {
+					if d.NIC == nic {
+						return &a, false, nil
 					}
 				}
 			}
@@ -68,6 +72,8 @@ func (r *workloadEndpointManager) RetriveIPAllocation(ctx context.Context, names
 }
 
 func (r *workloadEndpointManager) UpdateIPAllocation(ctx context.Context, namespace, podName string, allocation *spiderpoolv1.PodIPAllocation) error {
+	logger := logutils.FromContext(ctx)
+
 	var we spiderpoolv1.WorkloadEndpoint
 	if err := r.client.Get(ctx, apitypes.NamespacedName{Namespace: namespace, Name: podName}, &we); err != nil {
 		if !apierrors.IsNotFound(err) {
@@ -91,13 +97,14 @@ func (r *workloadEndpointManager) UpdateIPAllocation(ctx context.Context, namesp
 			return err
 		}
 	} else {
-		if we.Status.Current.ContainerID == allocation.ContainerID {
+		if we.Status.Current != nil && we.Status.Current.ContainerID == allocation.ContainerID {
 			we.Status.Current.IPs = append(we.Status.Current.IPs, allocation.IPs...)
 			we.Status.History[0].IPs = append(we.Status.History[0].IPs, allocation.IPs...)
 		} else {
 			we.Status.Current = allocation
 			we.Status.History = append([]spiderpoolv1.PodIPAllocation{*allocation}, we.Status.History...)
 			if len(we.Status.History) > r.maxHistoryRecords {
+				logger.Sugar().Warnf("threshold of historical IP allocation records(<=%d) exceeded", r.maxHistoryRecords)
 				we.Status.History = we.Status.History[:r.maxHistoryRecords]
 			}
 		}
@@ -110,7 +117,31 @@ func (r *workloadEndpointManager) UpdateIPAllocation(ctx context.Context, namesp
 	return nil
 }
 
-func (r *workloadEndpointManager) ClearCurrentIPs(ctx context.Context, namspace, podName, containerID string) error {
+func (r *workloadEndpointManager) ClearCurrentIPAllocation(ctx context.Context, namespace, podName, containerID, nic string) error {
+	var we spiderpoolv1.WorkloadEndpoint
+	if err := r.client.Get(ctx, apitypes.NamespacedName{Namespace: namespace, Name: podName}, &we); err != nil {
+		if apierrors.IsNotFound(err) {
+			return nil
+		}
+		return err
+	}
+
+	if we.Status.Current == nil {
+		return nil
+	}
+
+	if we.Status.Current.ContainerID != containerID {
+		return nil
+	}
+
+	we.Status.Current = nil
+	if err := r.client.Status().Update(ctx, &we); err != nil {
+		if apierrors.IsNotFound(err) {
+			return nil
+		}
+		return err
+	}
+
 	return nil
 }
 


Test patch:
diff --git a/pkg/logutils/log_test.go b/pkg/logutils/log_test.go
index 0e583a1ed..9b7baf7d8 100644
--- a/pkg/logutils/log_test.go
+++ b/pkg/logutils/log_test.go
@@ -4,6 +4,8 @@
 package logutils_test
 
 import (
+	"context"
+
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 
@@ -11,50 +13,74 @@ import (
 	"go.uber.org/zap"
 )
 
-var _ = Describe("logutils", Label("unitest", "logutils_test"), Ordered, func() {
-	var badFileLoggerConf logutils.FileOutputOption
+var _ = Describe("logutils", Label("unitest", "logutils_test"), func() {
+	Context("When on a nice day", func() {
+		It("log with stdout", func() {
+			err := logutils.InitStdoutLogger(logutils.InfoLevel)
+			Expect(err).NotTo(HaveOccurred())
+			logutils.Logger.Info("Test the stdout logger.", zap.String("pkg name", "logutils"))
+			logutils.Logger.Sugar().Infow("Test stdout logger sugar.", "key", "value")
+			logutils.Logger.Sugar().Info("Info uses fmt.Sprint to construct and log a message. ", "args1 , ", "args2, ", "args3")
+		})
 
-	BeforeAll(func() {
-		badFileLoggerConf.Filename = ""
-		badFileLoggerConf.MaxSize = -1
-		badFileLoggerConf.MaxAge = -2
-		badFileLoggerConf.MaxBackups = -3
-	})
+		It("log for file output mode", func() {
+			err := logutils.InitFileLogger(logutils.InfoLevel, logutils.DefaultLogFilePath, logutils.DefaultLogFileMaxSize, logutils.DefaultLogFileMaxAge, logutils.DefaultLogFileMaxBackups)
+			Expect(err).NotTo(HaveOccurred())
+			logutils.LoggerFile.Info("This is log test.", zap.Int("log mode", 1))
+		})
 
-	It("Test log with stdout", func() {
-		err := logutils.InitStdoutLogger(logutils.InfoLevel)
-		Expect(err).NotTo(HaveOccurred())
-		logutils.Logger.Info("Test the stdout logger.", zap.String("pkg name", "logutils"))
-		logutils.Logger.Sugar().Infow("Test stdout logger sugar.", "key", "value")
-		logutils.Logger.Sugar().Info("Info uses fmt.Sprint to construct and log a message. ", "args1 , ", "args2, ", "args3")
+		It("log with stderr", func() {
+			err := logutils.InitStderrLogger(logutils.InfoLevel)
+			Expect(err).NotTo(HaveOccurred())
+			logutils.LoggerStderr.Info("This is a clean log.")
+			name := "tony"
+			logutils.LoggerStderr.Sugar().Infof("Student %s is a good boy", name)
+		})
 	})
 
-	It("Test log for file output mode", func() {
-		err := logutils.InitFileLogger(logutils.InfoLevel, logutils.DefaultLogFilePath, logutils.DefaultLogFileMaxSize, logutils.DefaultLogFileMaxAge, logutils.DefaultLogFileMaxBackups)
-		Expect(err).NotTo(HaveOccurred())
-		logutils.LoggerFile.Info("This is log test.", zap.Int("log mode", 1))
-	})
+	Context("When NewLoggerWithOption with wrong input", func() {
+		var badFileLoggerConf logutils.FileOutputOption
 
-	It("Test log with stderr", func() {
-		err := logutils.InitStderrLogger(logutils.InfoLevel)
-		Expect(err).NotTo(HaveOccurred())
-		logutils.LoggerStderr.Info("This is a clean log.")
-		name := "tony"
-		logutils.LoggerStderr.Sugar().Infof("Student %s is a good boy", name)
-	})
+		BeforeEach(func() {
+			badFileLoggerConf.Filename = ""
+			badFileLoggerConf.MaxSize = -1
+			badFileLoggerConf.MaxAge = -2
+			badFileLoggerConf.MaxBackups = -3
+		})
 
-	It("Test NewLoggerWithOption with wrong output mode", func() {
-		_, err := logutils.NewLoggerWithOption(logutils.JsonLogFormat, logutils.OUTPUT_STDOUT|logutils.OUTPUT_STDERR,
-			nil, false, false, false, logutils.DebugLevel)
-		Expect(err).To(HaveOccurred())
-	})
+		It("wrong output mode only", func() {
+			_, err := logutils.NewLoggerWithOption(logutils.JsonLogFormat, logutils.OUTPUT_STDOUT|logutils.OUTPUT_STDERR,
+				nil, false, false, false, logutils.DebugLevel)
+			Expect(err).To(HaveOccurred())
+		})
 
-	It("Test NewLoggerWithOption with wrong params", func() {
-		By("If fortmat and outputMode all wrong, then it will return the default config logger")
-		logger, err := logutils.NewLoggerWithOption(logutils.ConsoleLogFormat+logutils.JsonLogFormat, logutils.OUTPUT_STDOUT|logutils.OUTPUT_FILE|logutils.OUTPUT_STDOUT|logutils.OUTPUT_STDERR,
-			&badFileLoggerConf, true, true, true, logutils.WarnLevel)
-		Expect(err).NotTo(HaveOccurred())
-		logger.Warn("hi.")
+		It("wrong params", func() {
+			// If fortmat and outputMode all wrong, then it will return the default config logger
+			logger, err := logutils.NewLoggerWithOption(logutils.ConsoleLogFormat+logutils.JsonLogFormat, logutils.OUTPUT_STDOUT|logutils.OUTPUT_FILE|logutils.OUTPUT_STDOUT|logutils.OUTPUT_STDERR,
+				&badFileLoggerConf, true, true, true, logutils.WarnLevel)
+			Expect(err).NotTo(HaveOccurred())
+			logger.Warn("hi.")
+		})
 	})
 
+	Context("When logger used with context", func() {
+		var ctx context.Context
+
+		BeforeEach(func() {
+			ctx = context.Background()
+		})
+
+		It("none value context", func() {
+			logger := logutils.FromContext(ctx)
+			Expect(logger).To(Equal(logutils.Logger))
+		})
+
+		It("retrieve logger from context", func() {
+			original := logutils.Logger.Named("TEST")
+			newCtx := logutils.IntoContext(ctx, original)
+
+			logger := logutils.FromContext(newCtx)
+			Expect(logger).To(Equal(original))
+		})
+	})
 })
diff --git a/test/e2e/common/spiderpool.go b/test/e2e/common/spiderpool.go
index ff8f1fb04..d13cc64e2 100644
--- a/test/e2e/common/spiderpool.go
+++ b/test/e2e/common/spiderpool.go
@@ -3,16 +3,12 @@
 package common
 
 import (
-	"encoding/json"
 	"errors"
 	"github.com/asaskevich/govalidator"
 	. "github.com/onsi/ginkgo/v2"
-	"github.com/spidernet-io/spiderpool/pkg/types"
-
 	// . "github.com/onsi/gomega"
 	frame "github.com/spidernet-io/e2eframework/framework"
 	"github.com/spidernet-io/spiderpool/cmd/spiderpool-agent/cmd"
-	"github.com/spidernet-io/spiderpool/pkg/constant"
 	spiderpool "github.com/spidernet-io/spiderpool/pkg/k8s/apis/v1"
 	"gopkg.in/yaml.v3"
 	corev1 "k8s.io/api/core/v1"
@@ -189,34 +185,9 @@ func GetClusterDefaultIppool(f *frame.Framework) (v4IppoolList, v6IppoolList []s
 	return d.ClusterDefaultIPv4IPPool, d.ClusterDefaultIPv6IPPool, nil
 }
 
-func GetNamespaceDefaultIppool(f *frame.Framework, namespace string) (v4IppoolList, v6IppoolList []string, e error) {
-	ns, err := f.GetNamespace(namespace)
-	if err != nil {
-		return nil, nil, err
-	}
-	GinkgoWriter.Printf("Get DefaultIppool for namespace: %v\n", ns)
-
-	annoNSIPv4 := types.AnnoNSDefautlV4PoolValue{}
-	annoNSIPv6 := types.AnnoNSDefautlV6PoolValue{}
-
-	v4Data, v4OK := ns.Annotations[constant.AnnoNSDefautlV4Pool]
-	v6Data, v6OK := ns.Annotations[constant.AnnoNSDefautlV6Pool]
-
-	if v4OK && len(v4Data) > 0 {
-		if err := json.Unmarshal([]byte(v4Data), &annoNSIPv4); err != nil {
-			GinkgoWriter.Printf("fail to decode namespace annotation v4 value: %v\n", v4Data)
-			return nil, nil, errors.New("invalid namespace annotation")
-		}
-		v4IppoolList = annoNSIPv4
-	}
-	if v6OK && len(v6Data) > 0 {
-		if err := json.Unmarshal([]byte(v6Data), &annoNSIPv6); err != nil {
-			GinkgoWriter.Printf("fail to decode namespace annotation v6 value: %v\n", v6Data)
-			return nil, nil, errors.New("invalid namespace annotation")
-		}
-		v6IppoolList = annoNSIPv6
-	}
-	return v4IppoolList, v6IppoolList, nil
+func GetNamespaceDefaultIppool(f *frame.Framework) (v4IppoolList, v6IppoolList []string, e error) {
+	// TODO (binzeSun)
+	return nil, nil, nil
 }
 
 func GetWorkloadByName(f *frame.Framework, namespace, name string) *spiderpool.WorkloadEndpoint {
diff --git a/test/e2e/performance/performance_test.go b/test/e2e/performance/performance_test.go
index 9ce98ccc9..d127f238b 100644
--- a/test/e2e/performance/performance_test.go
+++ b/test/e2e/performance/performance_test.go
@@ -15,7 +15,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 )
 
-var _ = Describe("performance test case", Serial, Label("performance"), Pending, func() {
+var _ = Describe("performance test case", Serial, Label("performance"), func() {
 	var perName, nsName string
 	var err error
 	var dpm *appsv1.Deployment