Repository: antrea-io/antrea
Pull request #2486 (2021-07-28 09:26:54)

fix tunnel interface name issue
the purpose of this commit is to fix a tunnel interface issue founded during some IPSec PoC verification:

1. when the node name is like 'lan-k8s-0-0', the IPsec tunnel interface name will be
like '-k8s-0-2-e8dbe6', then it will failed to run command like
`ipsec up '-k8s-0-2-e8dbe6'` inside a Antrea agent with error `/usr/lib/ipsec/stroke: invalid option -- 'k'`
due to the first char is '-', ipsec command interrupted it as an
option. so changed the `generateInterfaceName` method to use `strings.TrimLeft()` to remove '-' in left.

2. `createIPSecTunnelPort` method can't handle the case when tunnel
interface name changed when there is cache matched for the node. it
will reuse the existing tunnel name without creating a new one with new
name which means any change in `generateInterfaceName` won't take
affect. so refine it with more checks.

and also add some unit test cases.

Signed-off-by: Lan Luo <luola@vmware.com>

codecov-commenter: # [Codecov](https://codecov.io/gh/antrea-io/antrea/pull/2486?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#2486](https://codecov.io/gh/antrea-io/antrea/pull/2486?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (3a68e51) into [main](https://codecov.io/gh/antrea-io/antrea/commit/42077cb16007e033fc046136694ac0f9caf1ef27?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (42077cb) will **decrease** coverage by `23.16%`.
> The diff coverage is `5.55%`.

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

```diff
@@             Coverage Diff             @@
##             main    #2486       +/-   ##
===========================================
- Coverage   61.70%   38.53%   -23.17%     
===========================================
  Files         276      278        +2     
  Lines       21317    21364       +47     
===========================================
- Hits        13154     8233     -4921     
- Misses       6782    11943     +5161     
+ Partials     1381     1188      -193     
```

| Flag | Coverage Δ | |
|---|---|---|
| kind-e2e-tests | `38.53% <5.55%> (-14.39%)` | :arrow_down: |
| unit-tests | `?` | |

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=None#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/antrea-io/antrea/pull/2486?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [...gent/controller/noderoute/node\_route\_controller.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2FnZW50L2NvbnRyb2xsZXIvbm9kZXJvdXRlL25vZGVfcm91dGVfY29udHJvbGxlci5nbw==) | `39.47% <0.00%> (-7.61%)` | :arrow_down: |
| [pkg/agent/util/net.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2FnZW50L3V0aWwvbmV0Lmdv) | `51.28% <50.00%> (ø)` | |
| [pkg/agent/controller/egress/id\_allocator.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2FnZW50L2NvbnRyb2xsZXIvZWdyZXNzL2lkX2FsbG9jYXRvci5nbw==) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/controller/networkpolicy/crd\_utils.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NvbnRyb2xsZXIvbmV0d29ya3BvbGljeS9jcmRfdXRpbHMuZ28=) | `0.00% <0.00%> (-91.57%)` | :arrow_down: |
| [pkg/controller/networkpolicy/endpoint\_querier.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NvbnRyb2xsZXIvbmV0d29ya3BvbGljeS9lbmRwb2ludF9xdWVyaWVyLmdv) | `2.85% <0.00%> (-88.58%)` | :arrow_down: |
| [pkg/controller/networkpolicy/status\_controller.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NvbnRyb2xsZXIvbmV0d29ya3BvbGljeS9zdGF0dXNfY29udHJvbGxlci5nbw==) | `0.00% <0.00%> (-87.10%)` | :arrow_down: |
| [...agent/flowexporter/connections/deny\_connections.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2FnZW50L2Zsb3dleHBvcnRlci9jb25uZWN0aW9ucy9kZW55X2Nvbm5lY3Rpb25zLmdv) | `7.31% <0.00%> (-85.55%)` | :arrow_down: |
| [...kg/controller/networkpolicy/antreanetworkpolicy.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NvbnRyb2xsZXIvbmV0d29ya3BvbGljeS9hbnRyZWFuZXR3b3JrcG9saWN5Lmdv) | `0.00% <0.00%> (-85.00%)` | :arrow_down: |
| [pkg/controller/egress/controller.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NvbnRyb2xsZXIvZWdyZXNzL2NvbnRyb2xsZXIuZ28=) | `0.00% <0.00%> (-83.88%)` | :arrow_down: |
| [pkg/agent/util/iptables/lock.go](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2FnZW50L3V0aWwvaXB0YWJsZXMvbG9jay5nbw==) | `0.00% <0.00%> (-81.82%)` | :arrow_down: |
| ... and [151 more](https://codecov.io/gh/antrea-io/antrea/pull/2486/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | |

luolanzone: @antoninbas @abhiraut Could you help to take a look again? thanks!

Patch:
diff --git a/build/yamls/antrea-aks.yml b/build/yamls/antrea-aks.yml
index c2f0194a6..5805b70a1 100644
--- a/build/yamls/antrea-aks.yml
+++ b/build/yamls/antrea-aks.yml
@@ -4180,7 +4180,7 @@ spec:
           name: api
           protocol: TCP
         readinessProbe:
-          failureThreshold: 5
+          failureThreshold: 8
           httpGet:
             host: localhost
             path: /readyz
diff --git a/build/yamls/antrea-eks.yml b/build/yamls/antrea-eks.yml
index 53788c248..2ac92a80b 100644
--- a/build/yamls/antrea-eks.yml
+++ b/build/yamls/antrea-eks.yml
@@ -4182,7 +4182,7 @@ spec:
           name: api
           protocol: TCP
         readinessProbe:
-          failureThreshold: 5
+          failureThreshold: 8
           httpGet:
             host: localhost
             path: /readyz
diff --git a/build/yamls/antrea-gke.yml b/build/yamls/antrea-gke.yml
index eccc11946..30ed457d7 100644
--- a/build/yamls/antrea-gke.yml
+++ b/build/yamls/antrea-gke.yml
@@ -4180,7 +4180,7 @@ spec:
           name: api
           protocol: TCP
         readinessProbe:
-          failureThreshold: 5
+          failureThreshold: 8
           httpGet:
             host: localhost
             path: /readyz
diff --git a/build/yamls/antrea-ipsec.yml b/build/yamls/antrea-ipsec.yml
index 8677b97d2..8edd9ccda 100644
--- a/build/yamls/antrea-ipsec.yml
+++ b/build/yamls/antrea-ipsec.yml
@@ -4229,7 +4229,7 @@ spec:
           name: api
           protocol: TCP
         readinessProbe:
-          failureThreshold: 5
+          failureThreshold: 8
           httpGet:
             host: localhost
             path: /readyz
diff --git a/build/yamls/antrea.yml b/build/yamls/antrea.yml
index 64a1b3db7..03d947c71 100644
--- a/build/yamls/antrea.yml
+++ b/build/yamls/antrea.yml
@@ -4185,7 +4185,7 @@ spec:
           name: api
           protocol: TCP
         readinessProbe:
-          failureThreshold: 5
+          failureThreshold: 8
           httpGet:
             host: localhost
             path: /readyz
diff --git a/build/yamls/base/agent.yml b/build/yamls/base/agent.yml
index e8a8b32f5..a1a0ec5dc 100644
--- a/build/yamls/base/agent.yml
+++ b/build/yamls/base/agent.yml
@@ -110,7 +110,11 @@ spec:
             initialDelaySeconds: 5
             timeoutSeconds: 5
             periodSeconds: 10
-            failureThreshold: 5
+            # In large-scale clusters, it may take up to 40~50 seconds for the antrea-agent to reconnect to the antrea
+            # Service after the antrea-controller restarts. The antrea-agent shouldn't be reported as NotReady in this
+            # scenario, otherwise the DaemonSet controller would restart all agents at once, as opposed to performing a
+            # rolling update. Set failureThreshold to 8 so it can tolerate 70s of disconnection.
+            failureThreshold: 8
           securityContext:
             # antrea-agent needs to perform sysctl configuration.
             privileged: true
diff --git a/cmd/flow-aggregator/flow-aggregator.go b/cmd/flow-aggregator/flow-aggregator.go
index bfc04ea8d..10f47fc3c 100644
--- a/cmd/flow-aggregator/flow-aggregator.go
+++ b/cmd/flow-aggregator/flow-aggregator.go
@@ -52,12 +52,12 @@ func genObservationDomainID(k8sClient kubernetes.Interface) uint32 {
 	)
 	var clusterUUID uuid.UUID
 	if err := wait.PollImmediate(retryInterval, timeout, func() (bool, error) {
-		if clusterIdentity, _, err := clusterIdentityProvider.Get(); err != nil {
+		clusterIdentity, _, err := clusterIdentityProvider.Get()
+		if err != nil {
 			return false, nil
-		} else {
-			clusterUUID = clusterIdentity.UUID
-			return true, nil
 		}
+		clusterUUID = clusterIdentity.UUID
+		return true, nil
 	}); err != nil {
 		klog.Warningf(
 			"Unable to retrieve cluster UUID after %v (does ConfigMap '%s/%s' exist?); will generate a random observation domain ID",
diff --git a/docs/egress.md b/docs/egress.md
index 3ad0ca797..a10d75adc 100644
--- a/docs/egress.md
+++ b/docs/egress.md
@@ -284,7 +284,7 @@ egress-staging       10.10.0.105    1m    node-5
 Now, the packets from the Pods with in the `prod` Namespace to the external
 network will be redirected to the `node-4` Node and SNATed to `10.10.0.104`
 while the packets from the Pods in the `staging` Namespace to the external
-network will be redirected to the `node-5` Node and SNATed to `10.10.0.12`.
+network will be redirected to the `node-5` Node and SNATed to `10.10.0.105`.
 
 In this configuration, if the `node-4` Node powers off, re-configuring
 `10.10.0.104` to another Node or updating the `egressIP` of `egress-prod` to
diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go
index fe5733d65..e6925ee46 100644
--- a/pkg/agent/agent.go
+++ b/pkg/agent/agent.go
@@ -589,9 +589,8 @@ func (i *Initializer) setupDefaultTunnelInterface() error {
 		if err := i.ovsBridgeClient.DeletePort(tunnelIface.PortUUID); err != nil {
 			if i.networkConfig.TrafficEncapMode.SupportsEncap() {
 				return fmt.Errorf("failed to remove tunnel port %s with wrong tunnel type: %s", tunnelPortName, err)
-			} else {
-				klog.Errorf("Failed to remove tunnel port %s in NoEncapMode: %v", tunnelPortName, err)
 			}
+			klog.Errorf("Failed to remove tunnel port %s in NoEncapMode: %v", tunnelPortName, err)
 		} else {
 			klog.Infof("Removed tunnel port %s with tunnel type: %s", tunnelPortName, tunnelIface.TunnelInterfaceConfig.Type)
 			i.ifaceStore.DeleteInterface(tunnelIface)
diff --git a/pkg/agent/cniserver/pod_configuration.go b/pkg/agent/cniserver/pod_configuration.go
index 7f762efa6..3d823ea6e 100644
--- a/pkg/agent/cniserver/pod_configuration.go
+++ b/pkg/agent/cniserver/pod_configuration.go
@@ -107,9 +107,8 @@ func parseContainerIPs(ipcs []*current.IPConfig) ([]net.IP, error) {
 	}
 	if len(ips) > 0 {
 		return ips, nil
-	} else {
-		return nil, fmt.Errorf("failed to find a valid IP address")
 	}
+	return nil, fmt.Errorf("failed to find a valid IP address")
 }
 
 func buildContainerConfig(
@@ -240,9 +239,8 @@ func (pc *podConfigurator) configureInterfaces(
 	var containerConfig *interfacestore.InterfaceConfig
 	if containerConfig, err = pc.connectInterfaceToOVS(podName, podNameSpace, containerID, hostIface, containerIface, result.IPs, containerAccess); err != nil {
 		return fmt.Errorf("failed to connect to ovs for container %s: %v", containerID, err)
-	} else {
-		success = true
 	}
+	success = true
 	defer func() {
 		if !success {
 			_ = pc.disconnectInterfaceFromOVS(containerConfig)
@@ -272,9 +270,8 @@ func (pc *podConfigurator) createOVSPort(ovsPortName string, ovsAttachInfo map[s
 	if err != nil {
 		klog.Errorf("Failed to add OVS port %s, remove from local cache: %v", ovsPortName, err)
 		return "", err
-	} else {
-		return portUUID, nil
 	}
+	return portUUID, nil
 }
 
 func (pc *podConfigurator) removeInterfaces(containerID string) error {
@@ -380,9 +377,8 @@ func (pc *podConfigurator) validateOVSInterfaceConfig(containerID string, contai
 		}
 		return fmt.Errorf("interface IP %s does not match container %s IP",
 			getContainerIPsString(containerConfig.IPs), containerID)
-	} else {
-		return fmt.Errorf("container %s interface not found from local cache", containerID)
 	}
+	return fmt.Errorf("container %s interface not found from local cache", containerID)
 }
 
 func parsePrevResult(conf *NetworkConfig) error {
diff --git a/pkg/agent/controller/egress/egress_controller.go b/pkg/agent/controller/egress/egress_controller.go
index dda8d89c7..3061caeb4 100644
--- a/pkg/agent/controller/egress/egress_controller.go
+++ b/pkg/agent/controller/egress/egress_controller.go
@@ -32,6 +32,7 @@ import (
 	"k8s.io/apimachinery/pkg/watch"
 	coreinformers "k8s.io/client-go/informers/core/v1"
 	"k8s.io/client-go/tools/cache"
+	"k8s.io/client-go/util/retry"
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
 
@@ -521,15 +522,34 @@ func (c *EgressController) unbindPodEgress(pod, egress string) (string, bool) {
 	return "", false
 }
 
-func (c *EgressController) updateEgressStatus(egress *crdv1a2.Egress, nodeName string) error {
-	if egress.Status.EgressNode == nodeName {
-		return nil
-	}
-	klog.V(2).InfoS("Updating Egress status", "Egress", egress.Name, "oldNode", egress.Status.EgressNode, "newNode", nodeName)
+func (c *EgressController) updateEgressStatus(egress *crdv1a2.Egress, isLocal bool) error {
 	toUpdate := egress.DeepCopy()
-	toUpdate.Status.EgressNode = nodeName
-	if _, err := c.crdClient.CrdV1alpha2().Egresses().UpdateStatus(context.TODO(), toUpdate, metav1.UpdateOptions{}); err != nil {
-		return fmt.Errorf("updating Egress %s status error: %v", egress.Name, err)
+	var updateErr, getErr error
+	if err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
+		if isLocal {
+			// Do nothing if the current EgressNode in status is already this Node.
+			if toUpdate.Status.EgressNode == c.nodeName {
+				return nil
+			}
+			toUpdate.Status.EgressNode = c.nodeName
+		} else {
+			// Do nothing if the current EgressNode in status is not this Node.
+			if toUpdate.Status.EgressNode != c.nodeName {
+				return nil
+			}
+			toUpdate.Status.EgressNode = ""
+		}
+		klog.V(2).InfoS("Updating Egress status", "Egress", egress.Name, "oldNode", egress.Status.EgressNode, "newNode", toUpdate.Status.EgressNode)
+		_, updateErr = c.crdClient.CrdV1alpha2().Egresses().UpdateStatus(context.TODO(), toUpdate, metav1.UpdateOptions{})
+		if updateErr != nil && errors.IsConflict(updateErr) {
+			if toUpdate, getErr = c.crdClient.CrdV1alpha2().Egresses().Get(context.TODO(), egress.Name, metav1.GetOptions{}); getErr != nil {
+				return getErr
+			}
+		}
+		// Return the error from UPDATE.
+		return updateErr
+	}); err != nil {
+		return err
 	}
 	klog.V(2).InfoS("Updated Egress status", "Egress", egress.Name)
 	metrics.AntreaEgressStatusUpdates.Inc()
@@ -584,9 +604,6 @@ func (c *EgressController) syncEgress(egressName string) error {
 		if err := c.ipAssigner.AssignIP(egress.Spec.EgressIP); err != nil {
 			return err
 		}
-		if err := c.updateEgressStatus(egress, c.nodeName); err != nil {
-			return err
-		}
 	} else {
 		// Unassign the Egress IP from the local Node if it was assigned by the agent.
 		if err := c.ipAssigner.UnassignIP(egress.Spec.EgressIP); err != nil {
@@ -610,6 +627,10 @@ func (c *EgressController) syncEgress(egressName string) error {
 		eState.mark = mark
 	}
 
+	if err := c.updateEgressStatus(egress, c.localIPDetector.IsLocalIP(egress.Spec.EgressIP)); err != nil {
+		return fmt.Errorf("update Egress %s status error: %v", egressName, err)
+	}
+
 	// Copy the previous ofPorts and Pods. They will be used to identify stale ofPorts and Pods.
 	staleOFPorts := eState.ofPorts.Union(nil)
 	stalePods := eState.pods.Union(nil)
diff --git a/pkg/agent/controller/networkpolicy/packetin.go b/pkg/agent/controller/networkpolicy/packetin.go
index 8657c633b..5f531e5d5 100644
--- a/pkg/agent/controller/networkpolicy/packetin.go
+++ b/pkg/agent/controller/networkpolicy/packetin.go
@@ -305,34 +305,33 @@ func (c *Controller) rejectRequest(pktIn *ofctrl.PacketIn) error {
 			oriTCPSeqNum+1,
 			TCPAck|TCPRst,
 			true)
-	} else {
-		// Use ICMP host administratively prohibited for ICMP, UDP, SCTP reject.
-		icmpType := ICMPDstUnreachableType
-		icmpCode := ICMPDstHostAdminProhibitedCode
-		ipHdrLen := IPv4HdrLen
-		if isIPv6 {
-			icmpType = ICMPv6DstUnreachableType
-			icmpCode = ICMPv6DstAdminProhibitedCode
-			ipHdrLen = IPv6HdrLen
-		}
-		ipHdr, _ := pktIn.Data.Data.MarshalBinary()
-		icmpData := make([]byte, int(ICMPUnusedHdrLen+ipHdrLen+8))
-		// Put ICMP unused header in Data prop and set it to zero.
-		binary.BigEndian.PutUint32(icmpData[:ICMPUnusedHdrLen], 0)
-		copy(icmpData[ICMPUnusedHdrLen:], ipHdr[:ipHdrLen+8])
-		return c.ofClient.SendICMPPacketOut(
-			srcMAC.String(),
-			dstMAC.String(),
-			srcIP,
-			dstIP,
-			inPort,
-			-1,
-			isIPv6,
-			icmpType,
-			icmpCode,
-			icmpData,
-			true)
 	}
+	// Use ICMP host administratively prohibited for ICMP, UDP, SCTP reject.
+	icmpType := ICMPDstUnreachableType
+	icmpCode := ICMPDstHostAdminProhibitedCode
+	ipHdrLen := IPv4HdrLen
+	if isIPv6 {
+		icmpType = ICMPv6DstUnreachableType
+		icmpCode = ICMPv6DstAdminProhibitedCode
+		ipHdrLen = IPv6HdrLen
+	}
+	ipHdr, _ := pktIn.Data.Data.MarshalBinary()
+	icmpData := make([]byte, int(ICMPUnusedHdrLen+ipHdrLen+8))
+	// Put ICMP unused header in Data prop and set it to zero.
+	binary.BigEndian.PutUint32(icmpData[:ICMPUnusedHdrLen], 0)
+	copy(icmpData[ICMPUnusedHdrLen:], ipHdr[:ipHdrLen+8])
+	return c.ofClient.SendICMPPacketOut(
+		srcMAC.String(),
+		dstMAC.String(),
+		srcIP,
+		dstIP,
+		inPort,
+		-1,
+		isIPv6,
+		icmpType,
+		icmpCode,
+		icmpData,
+		true)
 }
 
 func (c *Controller) storeDenyConnection(pktIn *ofctrl.PacketIn) error {
diff --git a/pkg/agent/controller/networkpolicy/reconciler.go b/pkg/agent/controller/networkpolicy/reconciler.go
index c6b2c0eec..a559fee5a 100644
--- a/pkg/agent/controller/networkpolicy/reconciler.go
+++ b/pkg/agent/controller/networkpolicy/reconciler.go
@@ -268,9 +268,8 @@ func (r *reconciler) getOFRuleTable(rule *CompletedRule) binding.TableIDType {
 	if !rule.isAntreaNetworkPolicyRule() {
 		if rule.Direction == v1beta2.DirectionIn {
 			return openflow.IngressRuleTable
-		} else {
-			return openflow.EgressRuleTable
 		}
+		return openflow.EgressRuleTable
 	}
 	var ruleTables []binding.TableIDType
 	if rule.Direction == v1beta2.DirectionIn {
diff --git a/pkg/agent/controller/noderoute/node_route_controller.go b/pkg/agent/controller/noderoute/node_route_controller.go
index 0dd33bbe3..848039598 100644
--- a/pkg/agent/controller/noderoute/node_route_controller.go
+++ b/pkg/agent/controller/noderoute/node_route_controller.go
@@ -222,10 +222,8 @@ func (c *Controller) removeStaleTunnelPorts() error {
 			}
 
 			ifaceID := util.GenerateNodeTunnelInterfaceKey(node.Name)
-			validConfiguration := interfaceConfig.PSK == c.networkConfig.IPSecPSK &&
-				interfaceConfig.RemoteIP.Equal(peerNodeIP) &&
-				interfaceConfig.TunnelInterfaceConfig.Type == c.networkConfig.TunnelType
-			if validConfiguration {
+			ifaceName := util.GenerateNodeTunnelInterfaceName(node.Name)
+			if c.compareInterfaceConfig(interfaceConfig, peerNodeIP, ifaceName) {
 				desiredInterfaces[ifaceID] = true
 			}
 		}
@@ -258,6 +256,14 @@ func (c *Controller) removeStaleTunnelPorts() error {
 	return nil
 }
 
+func (c *Controller) compareInterfaceConfig(interfaceConfig *interfacestore.InterfaceConfig,
+	peerNodeIP net.IP, interfaceName string) bool {
+	return interfaceConfig.InterfaceName == interfaceName &&
+		interfaceConfig.PSK == c.networkConfig.IPSecPSK &&
+		interfaceConfig.RemoteIP.Equal(peerNodeIP) &&
+		interfaceConfig.TunnelInterfaceConfig.Type == c.networkConfig.TunnelType
+}
+
 func (c *Controller) reconcile() error {
 	klog.Infof("Reconciliation for %s", controllerName)
 	// reconciliation consists of removing stale routes and stale / invalid tunnel ports:
@@ -527,16 +533,20 @@ func getPodCIDRsOnNode(node *corev1.Node) []string {
 // createIPSecTunnelPort creates an IPSec tunnel port for the remote Node if the
 // tunnel does not exist, and returns the ofport number.
 func (c *Controller) createIPSecTunnelPort(nodeName string, nodeIP net.IP) (int32, error) {
+	portName := util.GenerateNodeTunnelInterfaceName(nodeName)
 	interfaceConfig, ok := c.interfaceStore.GetNodeTunnelInterface(nodeName)
+	// check if Node IP, PSK, or tunnel type changes. This can
+	// happen if removeStaleTunnelPorts fails to remove a "stale"
+	// tunnel port for which the configuration has changed, return error to requeue the Node.
 	if ok {
-		// TODO: check if Node IP, PSK, or tunnel type changes. This can
-		// happen if removeStaleTunnelPorts fails to remove a "stale"
-		// tunnel port for which the configuration has changed.
+		if !c.compareInterfaceConfig(interfaceConfig, nodeIP, portName) {
+			return 0, fmt.Errorf("IPSec tunnel interface config doesn't match cached one, stale IPSec tunnel port %s", interfaceConfig.InterfaceName)
+		}
+		klog.V(2).InfoS("Found cached IPSec tunnel interface", "interfaceName", interfaceConfig.InterfaceName, "port", interfaceConfig.OFPort, "nodeName", nodeName)
 		if interfaceConfig.OFPort != 0 {
 			return interfaceConfig.OFPort, nil
 		}
 	} else {
-		portName := util.GenerateNodeTunnelInterfaceName(nodeName)
 		ovsExternalIDs := map[string]interface{}{ovsExternalIDNodeName: nodeName}
 		portUUID, err := c.ovsBridgeClient.CreateTunnelPortExt(
 			portName,
diff --git a/pkg/agent/controller/traceflow/traceflow_controller.go b/pkg/agent/controller/traceflow/traceflow_controller.go
index 79ad1b9a6..c88a89c07 100644
--- a/pkg/agent/controller/traceflow/traceflow_controller.go
+++ b/pkg/agent/controller/traceflow/traceflow_controller.go
@@ -472,9 +472,8 @@ func (c *Controller) preparePacket(tf *crdv1alpha1.Traceflow, intf *interfacesto
 		if packet.DestinationIP == nil {
 			if packet.IsIPv6 {
 				return nil, errors.New("destination Pod does not have an IPv6 address")
-			} else {
-				return nil, errors.New("destination Pod does not have an IPv4 address")
 			}
+			return nil, errors.New("destination Pod does not have an IPv4 address")
 		}
 	} else if tf.Spec.Destination.Service != "" {
 		dstSvc, err := c.serviceLister.Services(tf.Spec.Destination.Namespace).Get(tf.Spec.Destination.Service)
diff --git a/pkg/agent/flowexporter/connections/conntrack_linux.go b/pkg/agent/flowexporter/connections/conntrack_linux.go
index 0138bbdbc..1725b85fc 100644
--- a/pkg/agent/flowexporter/connections/conntrack_linux.go
+++ b/pkg/agent/flowexporter/connections/conntrack_linux.go
@@ -201,7 +201,6 @@ func stateToString(state uint8) string {
 	}
 	if state > uint8(9) { // invalid state number
 		return ""
-	} else {
-		return stateList[state]
 	}
+	return stateList[state]
 }
diff --git a/pkg/agent/flowexporter/connections/deny_connections.go b/pkg/agent/flowexporter/connections/deny_connections.go
index e422cf8b0..63a81d2d1 100644
--- a/pkg/agent/flowexporter/connections/deny_connections.go
+++ b/pkg/agent/flowexporter/connections/deny_connections.go
@@ -74,21 +74,20 @@ func (ds *DenyConnectionStore) AddOrUpdateConn(conn *flowexporter.Connection, ti
 		conn.StopTime = timeSeen
 		klog.V(2).Infof("Deny connection with flowKey %v has been updated.", connKey)
 		return
-	} else {
-		conn.StartTime = timeSeen
-		conn.StopTime = timeSeen
-		conn.LastExportTime = timeSeen
-		conn.DeltaBytes = bytes
-		conn.OriginalBytes = bytes
-		conn.DeltaPackets = uint64(1)
-		conn.OriginalPackets = uint64(1)
-		ds.fillPodInfo(conn)
-		protocolStr := ip.IPProtocolNumberToString(conn.FlowKey.Protocol, "UnknownProtocol")
-		serviceStr := fmt.Sprintf("%s:%d/%s", conn.DestinationServiceAddress, conn.DestinationServicePort, protocolStr)
-		ds.fillServiceInfo(conn, serviceStr)
-		metrics.TotalDenyConnections.Inc()
-		ds.connections[connKey] = conn
 	}
+	conn.StartTime = timeSeen
+	conn.StopTime = timeSeen
+	conn.LastExportTime = timeSeen
+	conn.DeltaBytes = bytes
+	conn.OriginalBytes = bytes
+	conn.DeltaPackets = uint64(1)
+	conn.OriginalPackets = uint64(1)
+	ds.fillPodInfo(conn)
+	protocolStr := ip.IPProtocolNumberToString(conn.FlowKey.Protocol, "UnknownProtocol")
+	serviceStr := fmt.Sprintf("%s:%d/%s", conn.DestinationServiceAddress, conn.DestinationServicePort, protocolStr)
+	ds.fillServiceInfo(conn, serviceStr)
+	metrics.TotalDenyConnections.Inc()
+	ds.connections[connKey] = conn
 }
 
 // ResetConnStatsWithoutLock resets DeltaBytes and DeltaPackets of connection
diff --git a/pkg/agent/flowexporter/exporter/exporter.go b/pkg/agent/flowexporter/exporter/exporter.go
index 332f5bfd5..42cffc167 100644
--- a/pkg/agent/flowexporter/exporter/exporter.go
+++ b/pkg/agent/flowexporter/exporter/exporter.go
@@ -710,12 +710,10 @@ func (exp *flowExporter) findFlowType(conn flowexporter.Connection) uint8 {
 				return ipfixregistry.FlowTypeInterNode
 			}
 			return ipfixregistry.FlowTypeIntraNode
-		} else {
-			return ipfixregistry.FlowTypeToExternal
 		}
-	} else {
-		// We do not support External-To-Pod flows for now.
-		klog.Warningf("Source IP: %s doesn't exist in PodCIDRs", conn.FlowKey.SourceAddress.String())
-		return 0
+		return ipfixregistry.FlowTypeToExternal
 	}
+	// We do not support External-To-Pod flows for now.
+	klog.Warningf("Source IP: %s doesn't exist in PodCIDRs", conn.FlowKey.SourceAddress.String())
+	return 0
 }
diff --git a/pkg/agent/nodeportlocal/portcache/port_table.go b/pkg/agent/nodeportlocal/portcache/port_table.go
index 644af03ce..19a776913 100644
--- a/pkg/agent/nodeportlocal/portcache/port_table.go
+++ b/pkg/agent/nodeportlocal/portcache/port_table.go
@@ -119,7 +119,7 @@ func (pt *PortTable) AddRule(podIP string, podPort int) (int, error) {
 	if err != nil {
 		return 0, err
 	}
-	if err := pt.PodPortRules.AddRule(nodePort, fmt.Sprintf("%s:%d", podIP, podPort)); err != nil {
+	if err := pt.PodPortRules.AddRule(nodePort, podIP, podPort); err != nil {
 		if err := socket.Close(); err != nil {
 			klog.ErrorS(err, "Unexpected error when closing socket")
 		}
@@ -138,7 +138,7 @@ func (pt *PortTable) DeleteRule(podIP string, podPort int) error {
 	pt.tableLock.Lock()
 	defer pt.tableLock.Unlock()
 	data := pt.getEntryByPodIPPort(podIP, podPort)
-	if err := pt.PodPortRules.DeleteRule(data.NodePort, fmt.Sprintf("%s:%d", podIP, podPort)); err != nil {
+	if err := pt.PodPortRules.DeleteRule(data.NodePort, podIP, podPort); err != nil {
 		return err
 	}
 	if err := data.socket.Close(); err != nil {
diff --git a/pkg/agent/nodeportlocal/rules/iptable_rule.go b/pkg/agent/nodeportlocal/rules/iptable_rule.go
index 7cdb0cf9e..af4bb91e9 100644
--- a/pkg/agent/nodeportlocal/rules/iptable_rule.go
+++ b/pkg/agent/nodeportlocal/rules/iptable_rule.go
@@ -56,16 +56,16 @@ func (ipt *iptablesRules) Init() error {
 // traffic) and OUTPUT chain (for locally-generated traffic). All NPL DNAT rules
 // will be added to this chain.
 func (ipt *iptablesRules) initRules() error {
-	if err := ipt.table.EnsureChain(iptables.NATTable, NodePortLocalChain); err != nil {
+	if err := ipt.table.EnsureChain(iptables.ProtocolIPv4, iptables.NATTable, NodePortLocalChain); err != nil {
 		return err
 	}
 	ruleSpec := []string{
 		"-p", "tcp", "-m", "addrtype", "--dst-type", "LOCAL", "-j", NodePortLocalChain,
 	}
-	if err := ipt.table.EnsureRule(iptables.NATTable, iptables.PreRoutingChain, ruleSpec); err != nil {
+	if err := ipt.table.AppendRule(iptables.ProtocolIPv4, iptables.NATTable, iptables.PreRoutingChain, ruleSpec); err != nil {
 		return err
 	}
-	if err := ipt.table.EnsureRule(iptables.NATTable, iptables.OutputChain, ruleSpec); err != nil {
+	if err := ipt.table.AppendRule(iptables.ProtocolIPv4, iptables.NATTable, iptables.OutputChain, ruleSpec); err != nil {
 		return err
 	}
 	return nil
@@ -78,13 +78,14 @@ func buildRuleForPod(port int, podIP string) []string {
 	}
 }
 
-// AddRule appends a DNAT rule in NodePortLocalChain chain of NAT table
-func (ipt *iptablesRules) AddRule(port int, podIP string) error {
-	rule := buildRuleForPod(port, podIP)
-	if err := ipt.table.EnsureRule(iptables.NATTable, NodePortLocalChain, rule); err != nil {
+// AddRule appends a DNAT rule in NodePortLocalChain chain of NAT table.
+func (ipt *iptablesRules) AddRule(nodePort int, podIP string, podPort int) error {
+	podAddr := fmt.Sprintf("%s:%d", podIP, podPort)
+	rule := buildRuleForPod(nodePort, podAddr)
+	if err := ipt.table.AppendRule(iptables.ProtocolIPv4, iptables.NATTable, NodePortLocalChain, rule); err != nil {
 		return err
 	}
-	klog.Infof("Successfully added DNAT rule for Pod IP %s, port %d", podIP, port)
+	klog.InfoS("Successfully added DNAT rule", "podAddr", podAddr, "nodePort", nodePort)
 	return nil
 }
 
@@ -107,18 +108,19 @@ func (ipt *iptablesRules) AddAllRules(nplList []PodNodePort) error {
 }
 
 // DeleteRule deletes a specific NPL rule from NodePortLocalChain chain
-func (ipt *iptablesRules) DeleteRule(port int, podIP string) error {
-	klog.Infof("Deleting DNAT rule for Pod IP %s, port %d", podIP, port)
-	rule := buildRuleForPod(port, podIP)
-	if err := ipt.table.DeleteRule(iptables.NATTable, NodePortLocalChain, rule); err != nil {
+func (ipt *iptablesRules) DeleteRule(nodePort int, podIP string, podPort int) error {
+	podAddr := fmt.Sprintf("%s:%d", podIP, podPort)
+	rule := buildRuleForPod(nodePort, podAddr)
+	if err := ipt.table.DeleteRule(iptables.ProtocolIPv4, iptables.NATTable, NodePortLocalChain, rule); err != nil {
 		return err
 	}
+	klog.InfoS("Successfully deleted DNAT rule", "podAddr", podAddr, "nodePort", nodePort)
 	return nil
 }
 
 // DeleteAllRules deletes all NPL rules programmed in the node
 func (ipt *iptablesRules) DeleteAllRules() error {
-	exists, err := ipt.table.ChainExists(iptables.NATTable, NodePortLocalChain)
+	exists, err := ipt.table.ChainExists(iptables.ProtocolIPv4, iptables.NATTable, NodePortLocalChain)
 	if err != nil {
 		return fmt.Errorf("failed to check if NodePortLocal chain exists in NAT table: %v", err)
 	}
@@ -128,13 +130,13 @@ func (ipt *iptablesRules) DeleteAllRules() error {
 	ruleSpec := []string{
 		"-p", "tcp", "-m", "addrtype", "--dst-type", "LOCAL", "-j", NodePortLocalChain,
 	}
-	if err := ipt.table.DeleteRule(iptables.NATTable, iptables.PreRoutingChain, ruleSpec); err != nil {
+	if err := ipt.table.DeleteRule(iptables.ProtocolIPv4, iptables.NATTable, iptables.PreRoutingChain, ruleSpec); err != nil {
 		return err
 	}
-	if err := ipt.table.DeleteRule(iptables.NATTable, iptables.OutputChain, ruleSpec); err != nil {
+	if err := ipt.table.DeleteRule(iptables.ProtocolIPv4, iptables.NATTable, iptables.OutputChain, ruleSpec); err != nil {
 		return err
 	}
-	if err := ipt.table.DeleteChain(iptables.NATTable, NodePortLocalChain); err != nil {
+	if err := ipt.table.DeleteChain(iptables.ProtocolIPv4, iptables.NATTable, NodePortLocalChain); err != nil {
 		return err
 	}
 	return nil
diff --git a/pkg/agent/nodeportlocal/rules/rules.go b/pkg/agent/nodeportlocal/rules/rules.go
index a4a70b6d8..7c9bca1ab 100644
--- a/pkg/agent/nodeportlocal/rules/rules.go
+++ b/pkg/agent/nodeportlocal/rules/rules.go
@@ -19,8 +19,8 @@ package rules
 // PodPortRules is an interface to abstract operations on rules for Pods
 type PodPortRules interface {
 	Init() error
-	AddRule(port int, podip string) error
-	DeleteRule(port int, podip string) error
+	AddRule(nodePort int, podIP string, podPort int) error
+	DeleteRule(nodePort int, podIP string, podPort int) error
 	DeleteAllRules() error
 	AddAllRules(nplList []PodNodePort) error
 }
diff --git a/pkg/agent/openflow/network_policy.go b/pkg/agent/openflow/network_policy.go
index 416bfd772..26b3dd4cb 100644
--- a/pkg/agent/openflow/network_policy.go
+++ b/pkg/agent/openflow/network_policy.go
@@ -63,15 +63,13 @@ func (a *IPAddress) GetMatchKey(addrType types.AddressType) *types.MatchKey {
 	case types.SrcAddress:
 		if ipArr.To4() != nil {
 			return MatchSrcIP
-		} else {
-			return MatchSrcIPv6
 		}
+		return MatchSrcIPv6
 	case types.DstAddress:
 		if ipArr.To4() != nil {
 			return MatchDstIP
-		} else {
-			return MatchDstIPv6
 		}
+		return MatchDstIPv6
 	default:
 		klog.Errorf("Unknown AddressType %d in IPAddress", addrType)
 		return Unsupported
@@ -101,15 +99,13 @@ func (a *IPNetAddress) GetMatchKey(addrType types.AddressType) *types.MatchKey {
 	case types.SrcAddress:
 		if ipAddr.IP.To4() != nil {
 			return MatchSrcIPNet
-		} else {
-			return MatchSrcIPNetv6
 		}
+		return MatchSrcIPNetv6
 	case types.DstAddress:
 		if ipAddr.IP.To4() != nil {
 			return MatchDstIPNet
-		} else {
-			return MatchDstIPNetv6
 		}
+		return MatchDstIPNetv6
 	default:
 		klog.Errorf("Unknown AddressType %d in IPNetAddress", addrType)
 		return Unsupported
@@ -335,16 +331,15 @@ func (ctx *conjMatchFlowContext) deleteAction(conjID uint32) *flowChange {
 			flow:       ctx.flow,
 			changeType: deletion,
 		}
-	} else {
-		// Modify the Openflow entry and reset the other conjunctive actions.
-		var actions []*conjunctiveAction
-		for _, act := range ctx.actions {
-			if act.conjID != conjID {
-				actions = append(actions, act)
-			}
+	}
+	// Modify the Openflow entry and reset the other conjunctive actions.
+	var actions []*conjunctiveAction
+	for _, act := range ctx.actions {
+		if act.conjID != conjID {
+			actions = append(actions, act)
 		}
-		return ctx.createOrUpdateConjunctiveMatchFlow(actions)
 	}
+	return ctx.createOrUpdateConjunctiveMatchFlow(actions)
 }
 
 // addAction adds the specified policyRuleConjunction into conjunctiveMatchFlow's actions, and then returns the flowChange.
@@ -1572,9 +1567,8 @@ func parseMetricFlow(flow string) (uint32, types.RuleMetric) {
 	// table=101, n_packets=9, n_bytes=666, priority=200,reg0=0x100000/0x100000,reg3=0x5 actions=drop
 	if _, ok := flowMap[dropIdentifier]; ok {
 		return parseDropFlow(flowMap)
-	} else {
-		return parseAllowFlow(flowMap)
 	}
+	return parseAllowFlow(flowMap)
 }
 
 func (c *client) NetworkPolicyMetrics() map[uint32]*types.RuleMetric {
diff --git a/pkg/agent/openflow/pipeline.go b/pkg/agent/openflow/pipeline.go
index 9028f263a..be90f0861 100644
--- a/pkg/agent/openflow/pipeline.go
+++ b/pkg/agent/openflow/pipeline.go
@@ -1533,16 +1533,15 @@ func (c *client) conjunctionActionFlow(conjunctionID uint32, tableID binding.Tab
 				CTDone().
 				Cookie(c.cookieAllocator.Request(cookie.Policy).Raw()).
 				Done()
-		} else {
-			return c.pipeline[tableID].BuildFlow(ofPriority).MatchProtocol(proto).
-				MatchConjID(conjunctionID).
-				Action().LoadRegRange(int(conjReg), conjunctionID, binding.Range{0, 31}). // Traceflow.
-				Action().CT(true, nextTable, ctZone).                                     // CT action requires commit flag if actions other than NAT without arguments are specified.
-				LoadToLabelRange(uint64(conjunctionID), &labelRange).
-				CTDone().
-				Cookie(c.cookieAllocator.Request(cookie.Policy).Raw()).
-				Done()
 		}
+		return c.pipeline[tableID].BuildFlow(ofPriority).MatchProtocol(proto).
+			MatchConjID(conjunctionID).
+			Action().LoadRegRange(int(conjReg), conjunctionID, binding.Range{0, 31}). // Traceflow.
+			Action().CT(true, nextTable, ctZone).                                     // CT action requires commit flag if actions other than NAT without arguments are specified.
+			LoadToLabelRange(uint64(conjunctionID), &labelRange).
+			CTDone().
+			Cookie(c.cookieAllocator.Request(cookie.Policy).Raw()).
+			Done()
 	}
 	var flows []binding.Flow
 	for _, proto := range c.ipProtocols {
@@ -1875,19 +1874,18 @@ func (c *client) snatRuleFlow(ofPort uint32, snatIP net.IP, snatMark uint32, loc
 			Action().GotoTable(snatTable.GetNext()).
 			Cookie(c.cookieAllocator.Request(cookie.SNAT).Raw()).
 			Done()
-	} else {
-		// SNAT IP should be on a remote Node.
-		return snatTable.BuildFlow(priorityNormal).
-			MatchProtocol(ipProto).
-			MatchInPort(ofPort).
-			Action().SetSrcMAC(localGatewayMAC).
-			Action().SetDstMAC(globalVirtualMAC).
-			// Set tunnel destination to the SNAT IP.
-			Action().SetTunnelDst(snatIP).
-			Action().GotoTable(l3DecTTLTable).
-			Cookie(c.cookieAllocator.Request(cookie.SNAT).Raw()).
-			Done()
 	}
+	// SNAT IP should be on a remote Node.
+	return snatTable.BuildFlow(priorityNormal).
+		MatchProtocol(ipProto).
+		MatchInPort(ofPort).
+		Action().SetSrcMAC(localGatewayMAC).
+		Action().SetDstMAC(globalVirtualMAC).
+		// Set tunnel destination to the SNAT IP.
+		Action().SetTunnelDst(snatIP).
+		Action().GotoTable(l3DecTTLTable).
+		Cookie(c.cookieAllocator.Request(cookie.SNAT).Raw()).
+		Done()
 }
 
 // loadBalancerServiceFromOutsideFlow generates the flow to forward LoadBalancer service traffic from outside node
diff --git a/pkg/agent/proxy/proxier.go b/pkg/agent/proxy/proxier.go
index 71fe7c1f3..ebee1993c 100644
--- a/pkg/agent/proxy/proxier.go
+++ b/pkg/agent/proxy/proxier.go
@@ -686,9 +686,8 @@ func (p *metaProxierWrapper) GetServiceByIP(serviceStr string) (k8sproxy.Service
 	lastColonIndex := strings.LastIndex(serviceStr, ":")
 	if utilnet.IsIPv6String(serviceStr[:lastColonIndex]) {
 		return p.ipv6Proxier.GetServiceByIP(serviceStr)
-	} else {
-		return p.ipv4Proxier.GetServiceByIP(serviceStr)
 	}
+	return p.ipv4Proxier.GetServiceByIP(serviceStr)
 }
 
 func NewDualStackProxier(
diff --git a/pkg/agent/route/route_linux.go b/pkg/agent/route/route_linux.go
index 06cfca5b3..68aae961d 100644
--- a/pkg/agent/route/route_linux.go
+++ b/pkg/agent/route/route_linux.go
@@ -258,6 +258,7 @@ func (c *Client) syncIPTables() error {
 	var err error
 	v4Enabled := config.IsIPv4Enabled(c.nodeConfig, c.networkConfig.TrafficEncapMode)
 	v6Enabled := config.IsIPv6Enabled(c.nodeConfig, c.networkConfig.TrafficEncapMode)
+
 	c.ipt, err = iptables.New(v4Enabled, v6Enabled)
 	if err != nil {
 		return fmt.Errorf("error creating IPTables instance: %v", err)
@@ -274,11 +275,11 @@ func (c *Client) syncIPTables() error {
 		{iptables.MangleTable, iptables.OutputChain, antreaOutputChain, "Antrea: jump to Antrea output rules"},
 	}
 	for _, rule := range jumpRules {
-		if err := c.ipt.EnsureChain(rule.table, rule.dstChain); err != nil {
+		if err := c.ipt.EnsureChain(iptables.ProtocolDual, rule.table, rule.dstChain); err != nil {
 			return err
 		}
 		ruleSpec := []string{"-j", rule.dstChain, "-m", "comment", "--comment", rule.comment}
-		if err := c.ipt.EnsureRule(rule.table, rule.srcChain, ruleSpec); err != nil {
+		if err := c.ipt.AppendRule(iptables.ProtocolDual, rule.table, rule.srcChain, ruleSpec); err != nil {
 			return err
 		}
 	}
@@ -771,5 +772,5 @@ func (c *Client) DeleteSNATRule(mark uint32) error {
 	}
 	c.markToSNATIP.Delete(mark)
 	snatIP := value.(net.IP)
-	return c.ipt.DeleteRule(iptables.NATTable, antreaPostRoutingChain, c.snatRuleSpec(snatIP, mark))
+	return c.ipt.DeleteRule(iptables.ProtocolDual, iptables.NATTable, antreaPostRoutingChain, c.snatRuleSpec(snatIP, mark))
 }
diff --git a/pkg/agent/util/iptables/iptables.go b/pkg/agent/util/iptables/iptables.go
index 2c6a3fb74..dfc14a090 100644
--- a/pkg/agent/util/iptables/iptables.go
+++ b/pkg/agent/util/iptables/iptables.go
@@ -52,6 +52,15 @@ const (
 
 type Protocol byte
 
+var protocolStrMap = map[Protocol]string{
+	ProtocolIPv4: "IPv4",
+	ProtocolIPv6: "IPv6",
+}
+
+func (p Protocol) String() string {
+	return protocolStrMap[p]
+}
+
 const (
 	ProtocolDual Protocol = iota
 	ProtocolIPv4
@@ -63,20 +72,20 @@ const (
 var restoreWaitSupportedMinVersion = semver.Version{Major: 1, Minor: 6, Patch: 2}
 
 type Client struct {
-	ipts []*iptables.IPTables
+	ipts map[Protocol]*iptables.IPTables
 	// restoreWaitSupported indicates whether iptables-restore (or ip6tables-restore) supports --wait flag.
 	restoreWaitSupported bool
 }
 
 func New(enableIPV4, enableIPV6 bool) (*Client, error) {
-	var ipts []*iptables.IPTables
+	ipts := make(map[Protocol]*iptables.IPTables)
 	var restoreWaitSupported bool
 	if enableIPV4 {
 		ipt, err := iptables.New()
 		if err != nil {
 			return nil, fmt.Errorf("error creating IPTables instance: %v", err)
 		}
-		ipts = append(ipts, ipt)
+		ipts[ProtocolIPv4] = ipt
 		restoreWaitSupported = isRestoreWaitSupported(ipt)
 	}
 	if enableIPV6 {
@@ -84,7 +93,7 @@ func New(enableIPV4, enableIPV6 bool) (*Client, error) {
 		if err != nil {
 			return nil, fmt.Errorf("error creating IPTables instance for IPv6: %v", err)
 		}
-		ipts = append(ipts, ip6t)
+		ipts[ProtocolIPv6] = ip6t
 		if !restoreWaitSupported {
 			restoreWaitSupported = isRestoreWaitSupported(ip6t)
 		}
@@ -99,9 +108,12 @@ func isRestoreWaitSupported(ipt *iptables.IPTables) bool {
 }
 
 // EnsureChain checks if target chain already exists, creates it if not.
-func (c *Client) EnsureChain(table string, chain string) error {
-	for idx := range c.ipts {
-		ipt := c.ipts[idx]
+func (c *Client) EnsureChain(protocol Protocol, table string, chain string) error {
+	for p := range c.ipts {
+		ipt := c.ipts[p]
+		if !matchProtocol(ipt, protocol) {
+			continue
+		}
 		exists, err := ipt.ChainExists(table, chain)
 		if err != nil {
 			return fmt.Errorf("error checking if chain %s exists in table %s: %v", chain, table, err)
@@ -112,48 +124,56 @@ func (c *Client) EnsureChain(table string, chain string) error {
 		if err := ipt.NewChain(table, chain); err != nil {
 			return fmt.Errorf("error creating chain %s in table %s: %v", chain, table, err)
 		}
-		klog.V(2).Infof("Created chain %s in table %s", chain, table)
+		klog.V(2).InfoS("Created a chain", "chain", chain, "table", table, "protocol", p)
 	}
 	return nil
 }
 
-// ChainExists checks if a chain already exists in a table
-func (c *Client) ChainExists(table string, chain string) (bool, error) {
-	for idx := range c.ipts {
-		exists, err := c.ipts[idx].ChainExists(table, chain)
+// ChainExists checks if target chain already exists in a table
+func (c *Client) ChainExists(protocol Protocol, table string, chain string) (bool, error) {
+	for p := range c.ipts {
+		ipt := c.ipts[p]
+		if !matchProtocol(ipt, protocol) {
+			continue
+		}
+		exists, err := ipt.ChainExists(table, chain)
 		if err != nil {
 			return false, fmt.Errorf("error checking if chain %s exists in table %s: %v", chain, table, err)
 		}
-		if exists {
-			return true, nil
+		if !exists {
+			return false, nil
 		}
+		klog.V(2).InfoS("A chain exists", "chain", chain, "table", table, "protocol", p)
 	}
-	return false, nil
+	return true, nil
 }
 
-// EnsureRule checks if target rule already exists, appends it if not.
-func (c *Client) EnsureRule(table string, chain string, ruleSpec []string) error {
-	for idx := range c.ipts {
-		ipt := c.ipts[idx]
+// AppendRule checks if target rule already exists with the protocol, appends it if not.
+func (c *Client) AppendRule(protocol Protocol, table string, chain string, ruleSpec []string) error {
+	for p := range c.ipts {
+		ipt := c.ipts[p]
+		if !matchProtocol(ipt, protocol) {
+			continue
+		}
 		exist, err := ipt.Exists(table, chain, ruleSpec...)
 		if err != nil {
 			return fmt.Errorf("error checking if rule %v exists in table %s chain %s: %v", ruleSpec, table, chain, err)
 		}
 		if exist {
-			return nil
+			continue
 		}
 		if err := ipt.Append(table, chain, ruleSpec...); err != nil {
 			return fmt.Errorf("error appending rule %v to table %s chain %s: %v", ruleSpec, table, chain, err)
 		}
+		klog.V(2).InfoS("Appended a rule", "rule", ruleSpec, "table", table, "chain", chain, "protocol", p)
 	}
-	klog.V(2).Infof("Appended rule %v to table %s chain %s", ruleSpec, table, chain)
 	return nil
 }
 
 // InsertRule checks if target rule already exists, inserts it if not.
 func (c *Client) InsertRule(protocol Protocol, table string, chain string, ruleSpec []string) error {
-	for idx := range c.ipts {
-		ipt := c.ipts[idx]
+	for p := range c.ipts {
+		ipt := c.ipts[p]
 		if !matchProtocol(ipt, protocol) {
 			continue
 		}
@@ -162,13 +182,13 @@ func (c *Client) InsertRule(protocol Protocol, table string, chain string, ruleS
 			return fmt.Errorf("error checking if rule %v exists in table %s chain %s: %v", ruleSpec, table, chain, err)
 		}
 		if exist {
-			return nil
+			continue
 		}
 		if err := ipt.Insert(table, chain, 1, ruleSpec...); err != nil {
 			return fmt.Errorf("error inserting rule %v to table %s chain %s: %v", ruleSpec, table, chain, err)
 		}
+		klog.V(2).InfoS("Inserted a rule", "rule", ruleSpec, "table", table, "chain", chain)
 	}
-	klog.V(2).Infof("Inserted rule %v to table %s chain %s", ruleSpec, table, chain)
 	return nil
 }
 
@@ -185,46 +205,59 @@ func matchProtocol(ipt *iptables.IPTables, protocol Protocol) bool {
 }
 
 // DeleteRule checks if target rule already exists, deletes the rule if found.
-func (c *Client) DeleteRule(table string, chain string, ruleSpec []string) error {
-	for idx := range c.ipts {
-		exist, err := c.ipts[idx].Exists(table, chain, ruleSpec...)
+func (c *Client) DeleteRule(protocol Protocol, table string, chain string, ruleSpec []string) error {
+	for p := range c.ipts {
+		ipt := c.ipts[p]
+		if !matchProtocol(ipt, protocol) {
+			continue
+		}
+		exist, err := ipt.Exists(table, chain, ruleSpec...)
 		if err != nil {
 			return fmt.Errorf("error checking if rule %v exists in table %s chain %s: %v", ruleSpec, table, chain, err)
 		}
 		if !exist {
-			return nil
+			continue
 		}
-		if err := c.ipts[idx].Delete(table, chain, ruleSpec...); err != nil {
+		if err := ipt.Delete(table, chain, ruleSpec...); err != nil {
 			return fmt.Errorf("error deleting rule %v from table %s chain %s: %v", ruleSpec, table, chain, err)
 		}
-		klog.V(2).Infof("Deleted rule %v from table %s chain %s", ruleSpec, table, chain)
+		klog.V(2).InfoS("Deleted a rule", "rule", ruleSpec, "table", table, "chain", chain, "protocol", p)
 	}
 	return nil
 }
 
-// DeleteChain deletes all rules from a chain in a table and then delete the chain
-func (c *Client) DeleteChain(table string, chain string) error {
-	for idx := range c.ipts {
-		err := c.ipts[idx].ClearChain(table, chain)
+// DeleteChain deletes all rules from a chain in a table and then delete the chain.
+func (c *Client) DeleteChain(protocol Protocol, table string, chain string) error {
+	for p := range c.ipts {
+		ipt := c.ipts[p]
+		if !matchProtocol(ipt, protocol) {
+			continue
+		}
+		exists, err := ipt.ChainExists(table, chain)
 		if err != nil {
+			return fmt.Errorf("error checking if chain %s exists in table %s: %v", chain, table, err)
+		}
+		if !exists {
+			continue
+		}
+		if err = ipt.ClearChain(table, chain); err != nil {
 			return fmt.Errorf("error clearing rules from table %s chain %s: %v", table, chain, err)
 		}
-		err = c.ipts[idx].DeleteChain(table, chain)
-		if err != nil {
+		if err = ipt.DeleteChain(table, chain); err != nil {
 			return fmt.Errorf("error deleting chain %s from table %s: %v", chain, table, err)
 		}
-		klog.V(2).Infof("Deleted chain %s from table %s", chain, table)
+		klog.V(2).InfoS("Deleted a chain", "chain", chain, "table", table, "protocol", p)
 	}
 	return nil
 }
 
-// ListRules lists all rules from a chain in a table
+// ListRules lists all rules from a chain in a table.
 func (c *Client) ListRules(table string, chain string) ([]string, error) {
 	var allRules []string
-	for idx := range c.ipts {
-		rules, err := c.ipts[idx].List(table, chain)
+	for p := range c.ipts {
+		rules, err := c.ipts[p].List(table, chain)
 		if err != nil {
-			return rules, fmt.Errorf("error getting rules from table %s chain %s: %v", table, chain, err)
+			return rules, fmt.Errorf("error getting rules from table %s chain %s protocol %s: %v", table, chain, p, err)
 		}
 		allRules = append(allRules, rules...)
 	}
@@ -265,7 +298,7 @@ func (c *Client) Restore(data []byte, flush bool, useIPv6 bool) error {
 		defer unlockFunc()
 	}
 	if err := cmd.Run(); err != nil {
-		klog.Errorf("Failed to execute %s: %v\nstdin:\n%s\nstderr:\n%s", iptablesCmd, err, data, stderr)
+		klog.ErrorS(err, "Failed to execute iptables command", "iptablesCmd", iptablesCmd, "stdin", data, "stderr", stderr)
 		return fmt.Errorf("error executing %s: %v", iptablesCmd, err)
 	}
 	return nil
@@ -274,9 +307,9 @@ func (c *Client) Restore(data []byte, flush bool, useIPv6 bool) error {
 // Save calls iptables-saves to dump chains and tables in iptables.
 func (c *Client) Save() ([]byte, error) {
 	var output []byte
-	for idx := range c.ipts {
+	for p := range c.ipts {
 		var cmd string
-		ipt := c.ipts[idx]
+		ipt := c.ipts[p]
 		switch ipt.Proto() {
 		case iptables.ProtocolIPv6:
 			cmd = "ip6tables-save"
diff --git a/pkg/agent/util/net.go b/pkg/agent/util/net.go
index 9fcd7fabc..6b1ef2443 100644
--- a/pkg/agent/util/net.go
+++ b/pkg/agent/util/net.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"io"
 	"net"
+	"strings"
 )
 
 const (
@@ -38,10 +39,15 @@ func generateInterfaceName(key string, name string, useHead bool) string {
 	interfaceKey := hex.EncodeToString(hash.Sum(nil))
 	prefix := name
 	if len(name) > interfacePrefixLength {
+		// We use Node/Pod name to generate the interface name,
+		// valid chars for Node/Pod name are ASCII letters from a to z,
+		// the digits from 0 to 9, and the hyphen (-).
+		// Hyphen (-) is the only char which will impact command-line interpretation
+		// if the interface name starts with one, so we remove it here.
 		if useHead {
-			prefix = name[:interfacePrefixLength]
+			prefix = strings.TrimLeft(name[:interfacePrefixLength], "-")
 		} else {
-			prefix = name[len(name)-interfacePrefixLength:]
+			prefix = strings.TrimLeft(name[len(name)-interfacePrefixLength:], "-")
 		}
 	}
 	return fmt.Sprintf("%s-%s", prefix, interfaceKey[:interfaceKeyLength])
@@ -160,12 +166,11 @@ func GetIPWithFamily(ips []net.IP, addrFamily uint8) (net.IP, error) {
 			}
 		}
 		return nil, errors.New("no IP found with IPv6 AddressFamily")
-	} else {
-		for _, ip := range ips {
-			if ip.To4() != nil {
-				return ip, nil
-			}
+	}
+	for _, ip := range ips {
+		if ip.To4() != nil {
+			return ip, nil
 		}
-		return nil, errors.New("no IP found with IPv4 AddressFamily")
 	}
+	return nil, errors.New("no IP found with IPv4 AddressFamily")
 }
diff --git a/pkg/agent/util/net_linux.go b/pkg/agent/util/net_linux.go
index 54f5d7361..7b6782383 100644
--- a/pkg/agent/util/net_linux.go
+++ b/pkg/agent/util/net_linux.go
@@ -116,9 +116,8 @@ func SetLinkUp(name string) (net.HardwareAddr, int, error) {
 	if err != nil {
 		if _, ok := err.(netlink.LinkNotFoundError); ok {
 			return nil, 0, newLinkNotFoundError(name)
-		} else {
-			return nil, 0, err
 		}
+		return nil, 0, err
 	}
 	// Set host gateway interface up.
 	if err := netlink.LinkSetUp(link); err != nil {
diff --git a/pkg/antctl/raw/supportbundle/command.go b/pkg/antctl/raw/supportbundle/command.go
index 5a9ade8fb..8bf2b007d 100644
--- a/pkg/antctl/raw/supportbundle/command.go
+++ b/pkg/antctl/raw/supportbundle/command.go
@@ -513,16 +513,16 @@ func controllerRemoteRunE(cmd *cobra.Command, args []string) error {
 	bar := barTmpl.Start(amount)
 	defer bar.Finish()
 	defer bar.Set("prefix", "Finish ")
-	if reader, err := getClusterInfo(k8sClientset); err != nil {
+	reader, err := getClusterInfo(k8sClientset)
+	if err != nil {
+		return err
+	}
+	f, err := os.Create(filepath.Join(option.dir, "clusterinfo"))
+	if err != nil {
 		return err
-	} else {
-		f, err := os.Create(filepath.Join(option.dir, "clusterinfo"))
-		if err != nil {
-			return err
-		}
-		defer f.Close()
-		io.Copy(f, reader)
 	}
+	defer f.Close()
+	io.Copy(f, reader)
 	if err := requestAll(agentClients, controllerClient, bar); err != nil {
 		return err
 	}
diff --git a/pkg/antctl/runtime/runtime.go b/pkg/antctl/runtime/runtime.go
index 7c4f88c7a..9531f9191 100644
--- a/pkg/antctl/runtime/runtime.go
+++ b/pkg/antctl/runtime/runtime.go
@@ -44,9 +44,8 @@ func ResolveKubeconfig(path string) (*rest.Config, error) {
 	}
 	if _, err = os.Stat(path); path == clientcmd.RecommendedHomeFile && os.IsNotExist(err) {
 		return rest.InClusterConfig()
-	} else {
-		return clientcmd.BuildConfigFromFlags("", path)
 	}
+	return clientcmd.BuildConfigFromFlags("", path)
 }
 
 func init() {
diff --git a/pkg/apis/controlplane/helper.go b/pkg/apis/controlplane/helper.go
index 7f73cbd05..d229dbe4e 100644
--- a/pkg/apis/controlplane/helper.go
+++ b/pkg/apis/controlplane/helper.go
@@ -19,7 +19,6 @@ import "fmt"
 func (r *NetworkPolicyReference) ToString() string {
 	if r.Type == AntreaClusterNetworkPolicy {
 		return fmt.Sprintf("%s:%s", r.Type, r.Name)
-	} else {
-		return fmt.Sprintf("%s:%s/%s", r.Type, r.Namespace, r.Name)
 	}
+	return fmt.Sprintf("%s:%s/%s", r.Type, r.Namespace, r.Name)
 }
diff --git a/pkg/apis/controlplane/v1beta1/helper.go b/pkg/apis/controlplane/v1beta1/helper.go
index 7d7b18fb6..3f3f0b536 100644
--- a/pkg/apis/controlplane/v1beta1/helper.go
+++ b/pkg/apis/controlplane/v1beta1/helper.go
@@ -37,7 +37,6 @@ func (p *GroupMemberPod) ToGroupMember() *GroupMember {
 func (r *NetworkPolicyReference) ToString() string {
 	if r.Type == AntreaClusterNetworkPolicy {
 		return fmt.Sprintf("%s:%s", r.Type, r.Name)
-	} else {
-		return fmt.Sprintf("%s:%s/%s", r.Type, r.Namespace, r.Name)
 	}
+	return fmt.Sprintf("%s:%s/%s", r.Type, r.Namespace, r.Name)
 }
diff --git a/pkg/apis/controlplane/v1beta2/helper.go b/pkg/apis/controlplane/v1beta2/helper.go
index f6a88933e..2fd9bd157 100644
--- a/pkg/apis/controlplane/v1beta2/helper.go
+++ b/pkg/apis/controlplane/v1beta2/helper.go
@@ -19,7 +19,6 @@ import "fmt"
 func (r *NetworkPolicyReference) ToString() string {
 	if r.Type == AntreaClusterNetworkPolicy {
 		return fmt.Sprintf("%s:%s", r.Type, r.Name)
-	} else {
-		return fmt.Sprintf("%s:%s/%s", r.Type, r.Namespace, r.Name)
 	}
+	return fmt.Sprintf("%s:%s/%s", r.Type, r.Namespace, r.Name)
 }
diff --git a/pkg/apiserver/handlers/featuregates/handler.go b/pkg/apiserver/handlers/featuregates/handler.go
index 34b3335cb..4f491d01b 100644
--- a/pkg/apiserver/handlers/featuregates/handler.go
+++ b/pkg/apiserver/handlers/featuregates/handler.go
@@ -123,7 +123,6 @@ func getControllerGatesResponse() []Response {
 func getStatus(status bool) string {
 	if status {
 		return "Enabled"
-	} else {
-		return "Disabled"
 	}
+	return "Disabled"
 }
diff --git a/pkg/controller/crdmirroring/crdmirroring_controller.go b/pkg/controller/crdmirroring/crdmirroring_controller.go
index 3109fafd2..64fa0f1cc 100644
--- a/pkg/controller/crdmirroring/crdmirroring_controller.go
+++ b/pkg/controller/crdmirroring/crdmirroring_controller.go
@@ -138,9 +138,8 @@ func (c *Controller) syncMirroring(key string) error {
 	if err != nil {
 		if !apierrors.IsNotFound(err) {
 			return fmt.Errorf("failed to get legacy %s %s/%s: %v", c.crdName, namespace, name, err)
-		} else {
-			legacyExist = false
 		}
+		legacyExist = false
 	}
 
 	// Get the new object, and if got an error that is not "IsNotFound", return the error
@@ -149,9 +148,8 @@ func (c *Controller) syncMirroring(key string) error {
 	if err != nil {
 		if !apierrors.IsNotFound(err) {
 			return fmt.Errorf("failed to get new %s %s/%s: %v", c.crdName, namespace, name, err)
-		} else {
-			newExist = false
 		}
+		newExist = false
 	}
 
 	// If neither the old object nor the new object exists, return
diff --git a/pkg/controller/networkpolicy/status_controller.go b/pkg/controller/networkpolicy/status_controller.go
index 4df998fd0..380e220f2 100644
--- a/pkg/controller/networkpolicy/status_controller.go
+++ b/pkg/controller/networkpolicy/status_controller.go
@@ -275,9 +275,8 @@ func (c *StatusController) syncHandler(key string) error {
 		}
 		if internalNP.SourceRef.Type == controlplane.AntreaNetworkPolicy {
 			return c.npControlInterface.UpdateAntreaNetworkPolicyStatus(internalNP.SourceRef.Namespace, internalNP.SourceRef.Name, status)
-		} else {
-			return c.npControlInterface.UpdateAntreaClusterNetworkPolicyStatus(internalNP.SourceRef.Name, status)
 		}
+		return c.npControlInterface.UpdateAntreaClusterNetworkPolicyStatus(internalNP.SourceRef.Name, status)
 	}
 	desiredNodes := len(internalNP.SpanMeta.NodeNames)
 	currentNodes := 0
@@ -307,9 +306,8 @@ func (c *StatusController) syncHandler(key string) error {
 	klog.V(2).Infof("Updating NetworkPolicy %s status: %v", internalNP.SourceRef.ToString(), status)
 	if internalNP.SourceRef.Type == controlplane.AntreaNetworkPolicy {
 		return c.npControlInterface.UpdateAntreaNetworkPolicyStatus(internalNP.SourceRef.Namespace, internalNP.SourceRef.Name, status)
-	} else {
-		return c.npControlInterface.UpdateAntreaClusterNetworkPolicyStatus(internalNP.SourceRef.Name, status)
 	}
+	return c.npControlInterface.UpdateAntreaClusterNetworkPolicyStatus(internalNP.SourceRef.Name, status)
 }
 
 // networkPolicyControlInterface is an interface that knows how to update Antrea NetworkPolicy status.
diff --git a/pkg/controller/traceflow/controller.go b/pkg/controller/traceflow/controller.go
index e949021e5..dc66a9928 100644
--- a/pkg/controller/traceflow/controller.go
+++ b/pkg/controller/traceflow/controller.go
@@ -219,21 +219,21 @@ func (c *Controller) processTraceflowItem() bool {
 	defer c.queue.Done(obj)
 
 	// We expect strings (Traceflow name) to come off the workqueue.
-	if key, ok := obj.(string); !ok {
+	key, ok := obj.(string)
+	if !ok {
 		// As the item in the workqueue is actually invalid, we call Forget here else we'd
 		// go into a loop of attempting to process a work item that is invalid.
 		// This should not happen: enqueueTraceflow only enqueues strings.
 		c.queue.Forget(obj)
 		klog.Errorf("Expected string in work queue but got %#v", obj)
 		return true
+	}
+	err := c.syncTraceflow(key)
+	if err != nil {
+		klog.Errorf("Error syncing Traceflow %s, exiting. Error: %v", key, err)
+		c.queue.AddRateLimited(key)
 	} else {
-		err := c.syncTraceflow(key)
-		if err != nil {
-			klog.Errorf("Error syncing Traceflow %s, exiting. Error: %v", key, err)
-			c.queue.AddRateLimited(key)
-		} else {
-			c.queue.Forget(key)
-		}
+		c.queue.Forget(key)
 	}
 	return true
 }
@@ -364,9 +364,8 @@ func (c *Controller) occupyTag(tf *crdv1alpha1.Traceflow) error {
 	if existingTraceflowName, ok := c.runningTraceflows[tag]; ok {
 		if tf.Name == existingTraceflowName {
 			return nil
-		} else {
-			return errors.New("this Traceflow's CRD data plane tag is already taken")
 		}
+		return errors.New("this Traceflow's CRD data plane tag is already taken")
 	}
 
 	c.runningTraceflows[tag] = tf.Name
diff --git a/pkg/flowaggregator/flowaggregator.go b/pkg/flowaggregator/flowaggregator.go
index 0e0cd5f51..e169776a1 100644
--- a/pkg/flowaggregator/flowaggregator.go
+++ b/pkg/flowaggregator/flowaggregator.go
@@ -298,21 +298,26 @@ func (fa *flowAggregator) InitAggregationProcess() error {
 	return err
 }
 
-func (fa *flowAggregator) createAndSendTemplate(isRecordIPv6 bool) (uint16, error) {
+func (fa *flowAggregator) createAndSendTemplate(isRecordIPv6 bool) error {
 	templateID := fa.exportingProcess.NewTemplateID()
 	recordIPFamily := "IPv4"
 	if isRecordIPv6 {
 		recordIPFamily = "IPv6"
 	}
+	if isRecordIPv6 {
+		fa.templateIDv6 = templateID
+	} else {
+		fa.templateIDv4 = templateID
+	}
 	bytesSent, err := fa.sendTemplateSet(isRecordIPv6)
 	if err != nil {
 		fa.exportingProcess.CloseConnToCollector()
 		fa.exportingProcess = nil
 		fa.set.ResetSet()
-		return 0, fmt.Errorf("sending %s template set failed, err: %v", recordIPFamily, err)
+		return fmt.Errorf("sending %s template set failed, err: %v", recordIPFamily, err)
 	}
 	klog.V(2).InfoS("Exporting process initialized", "bytesSent", bytesSent, "templateSetIPFamily", recordIPFamily)
-	return templateID, nil
+	return nil
 }
 
 func (fa *flowAggregator) initExportingProcess() error {
@@ -346,10 +351,10 @@ func (fa *flowAggregator) initExportingProcess() error {
 	}
 	fa.exportingProcess = ep
 	// Currently, we send two templates for IPv4 and IPv6 regardless of the IP families supported by cluster
-	if fa.templateIDv4, err = fa.createAndSendTemplate(false); err != nil {
+	if err = fa.createAndSendTemplate(false); err != nil {
 		return err
 	}
-	if fa.templateIDv6, err = fa.createAndSendTemplate(true); err != nil {
+	if err = fa.createAndSendTemplate(true); err != nil {
 		return err
 	}
 	return nil
diff --git a/pkg/graphviz/traceflow.go b/pkg/graphviz/traceflow.go
index 8bfb6373c..9136d165e 100644
--- a/pkg/graphviz/traceflow.go
+++ b/pkg/graphviz/traceflow.go
@@ -153,9 +153,8 @@ func getSrcNodeName(tf *crdv1alpha1.Traceflow) string {
 	if tf.Spec.LiveTraffic {
 		if len(tf.Spec.Source.IP) > 0 {
 			return getWrappedStr(tf.Spec.Source.IP)
-		} else {
-			return getWrappedStr(tf.Status.CapturedPacket.SrcIP)
 		}
+		return getWrappedStr(tf.Status.CapturedPacket.SrcIP)
 	}
 	return ""
 }
diff --git a/pkg/ovs/ovsconfig/ovs_client.go b/pkg/ovs/ovsconfig/ovs_client.go
index 479fcc16a..8659cd807 100644
--- a/pkg/ovs/ovsconfig/ovs_client.go
+++ b/pkg/ovs/ovsconfig/ovs_client.go
@@ -625,9 +625,9 @@ func buildMapFromOVSDBMap(data []interface{}) map[string]string {
 			ret[pair.([]interface{})[0].(string)] = pair.([]interface{})[1].(string)
 		}
 		return ret
-	} else { // Should not be possible
-		return map[string]string{}
 	}
+	// Should not be possible
+	return map[string]string{}
 }
 
 func buildPortDataCommon(port, intf map[string]interface{}, portData *OVSPortData) {
@@ -768,9 +768,8 @@ func (br *OVSBridge) GetOVSVersion() (string, Error) {
 	if len(res[0].Rows) == 0 {
 		klog.Warning("Could not find ovs_version in the OVS query result")
 		return "", NewTransactionError(fmt.Errorf("no results from OVS query"), false)
-	} else {
-		return parseOvsVersion(res[0].Rows[0])
 	}
+	return parseOvsVersion(res[0].Rows[0])
 }
 
 // parseOvsVersion parses the version from an interface type, which can be a map of string[interface] or string[string], and returns it as a string, we have special logic here so that a panic doesn't happen.
diff --git a/pkg/ovs/ovsctl/appctl.go b/pkg/ovs/ovsctl/appctl.go
index 36014bc2b..024e6c47f 100644
--- a/pkg/ovs/ovsctl/appctl.go
+++ b/pkg/ovs/ovsctl/appctl.go
@@ -80,9 +80,8 @@ func (c *ovsCtlClient) Trace(req *TracingRequest) (string, error) {
 		ipKey, nwSrcKey = getNwSrcKey(req.SrcIP)
 		if strings.Contains(req.Flow, fmt.Sprintf("%s=", nwSrcKey)) {
 			return "", newBadRequestError(fmt.Sprintf("duplicated '%s' in flow", nwSrcKey))
-		} else {
-			nwSrc = fmt.Sprintf("%s=%s,", nwSrcKey, req.SrcIP.String())
 		}
+		nwSrc = fmt.Sprintf("%s=%s,", nwSrcKey, req.SrcIP.String())
 	}
 	if req.DstIP != nil {
 		var nwDstKey string
@@ -90,9 +89,8 @@ func (c *ovsCtlClient) Trace(req *TracingRequest) (string, error) {
 		// Do not allow overriding destination IP.
 		if strings.Contains(req.Flow, fmt.Sprintf("%s=", nwDstKey)) {
 			return "", newBadRequestError(fmt.Sprintf("duplicated '%s' in flow", nwDstKey))
-		} else {
-			nwDst = fmt.Sprintf("%s=%s,", nwDstKey, req.DstIP.String())
 		}
+		nwDst = fmt.Sprintf("%s=%s,", nwDstKey, req.DstIP.String())
 	}
 
 	// Always allow overriding source and destination MACs.
@@ -128,17 +126,15 @@ func (c *ovsCtlClient) Trace(req *TracingRequest) (string, error) {
 func getNwSrcKey(ip net.IP) (string, string) {
 	if ip.To4() != nil {
 		return "ip", "nw_src"
-	} else {
-		return "ipv6", "ipv6_src"
 	}
+	return "ipv6", "ipv6_src"
 }
 
 func getNwDstKey(ip net.IP) (string, string) {
 	if ip.To4() != nil {
 		return "ip", "nw_dst"
-	} else {
-		return "ipv6", "ipv6_dst"
 	}
+	return "ipv6", "ipv6_dst"
 }
 
 func (c *ovsCtlClient) runTracing(flow string) (string, error) {


Test patch:
diff --git a/pkg/agent/controller/egress/egress_controller_test.go b/pkg/agent/controller/egress/egress_controller_test.go
index 95502c359..31e54b7cf 100644
--- a/pkg/agent/controller/egress/egress_controller_test.go
+++ b/pkg/agent/controller/egress/egress_controller_test.go
@@ -16,6 +16,7 @@ package egress
 
 import (
 	"context"
+	"fmt"
 	"net"
 	"reflect"
 	"testing"
@@ -24,10 +25,12 @@ import (
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/apimachinery/pkg/util/wait"
+	k8stesting "k8s.io/client-go/testing"
 	"k8s.io/client-go/util/workqueue"
 
 	ipassignertest "antrea.io/antrea/pkg/agent/controller/egress/ipassigner/testing"
@@ -38,7 +41,6 @@ import (
 	cpv1b2 "antrea.io/antrea/pkg/apis/controlplane/v1beta2"
 	crdv1a2 "antrea.io/antrea/pkg/apis/crd/v1alpha2"
 	"antrea.io/antrea/pkg/client/clientset/versioned"
-	"antrea.io/antrea/pkg/client/clientset/versioned/fake"
 	fakeversioned "antrea.io/antrea/pkg/client/clientset/versioned/fake"
 	crdinformers "antrea.io/antrea/pkg/client/informers/externalversions"
 	"antrea.io/antrea/pkg/util/k8s"
@@ -98,7 +100,7 @@ func newFakeController(t *testing.T, initObjects []runtime.Object) *fakeControll
 	mockRouteClient := routetest.NewMockInterface(controller)
 	mockIPAssigner := ipassignertest.NewMockIPAssigner(controller)
 
-	clientset := &fake.Clientset{}
+	clientset := &fakeversioned.Clientset{}
 	crdClient := fakeversioned.NewSimpleClientset(initObjects...)
 	crdInformerFactory := crdinformers.NewSharedInformerFactory(crdClient, 0)
 	egressInformer := crdInformerFactory.Crd().V1alpha2().Egresses()
@@ -114,6 +116,7 @@ func newFakeController(t *testing.T, initObjects []runtime.Object) *fakeControll
 	egressController := &EgressController{
 		ofClient:             mockOFClient,
 		routeClient:          mockRouteClient,
+		crdClient:            crdClient,
 		antreaClientProvider: &antreaClientGetter{clientset},
 		egressInformer:       egressInformer.Informer(),
 		egressLister:         egressInformer.Lister(),
@@ -148,6 +151,7 @@ func TestSyncEgress(t *testing.T) {
 		existingEgressGroup *cpv1b2.EgressGroup
 		newEgressGroup      *cpv1b2.EgressGroup
 		newLocalIPs         sets.String
+		expectedEgresses    []*crdv1a2.Egress
 		expectedCalls       func(mockOFClient *openflowtest.MockClient, mockRouteClient *routetest.MockInterface, mockIPAssigner *ipassignertest.MockIPAssigner)
 	}{
 		{
@@ -175,6 +179,12 @@ func TestSyncEgress(t *testing.T) {
 				},
 			},
 			newLocalIPs: sets.NewString(),
+			expectedEgresses: []*crdv1a2.Egress{
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressA", UID: "uidA"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeLocalEgressIP1},
+				},
+			},
 			expectedCalls: func(mockOFClient *openflowtest.MockClient, mockRouteClient *routetest.MockInterface, mockIPAssigner *ipassignertest.MockIPAssigner) {
 				mockOFClient.EXPECT().InstallSNATMarkFlows(net.ParseIP(fakeLocalEgressIP1), uint32(1))
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(1), net.ParseIP(fakeLocalEgressIP1), uint32(1))
@@ -218,6 +228,13 @@ func TestSyncEgress(t *testing.T) {
 				},
 			},
 			newLocalIPs: sets.NewString(fakeRemoteEgressIP1),
+			expectedEgresses: []*crdv1a2.Egress{
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressA", UID: "uidA"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeRemoteEgressIP1},
+					Status:     crdv1a2.EgressStatus{EgressNode: fakeNode},
+				},
+			},
 			expectedCalls: func(mockOFClient *openflowtest.MockClient, mockRouteClient *routetest.MockInterface, mockIPAssigner *ipassignertest.MockIPAssigner) {
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(1), net.ParseIP(fakeRemoteEgressIP1), uint32(0))
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(2), net.ParseIP(fakeRemoteEgressIP1), uint32(0))
@@ -258,6 +275,13 @@ func TestSyncEgress(t *testing.T) {
 					{Pod: &cpv1b2.PodReference{Name: "pod3", Namespace: "ns3"}},
 				},
 			},
+			expectedEgresses: []*crdv1a2.Egress{
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressA", UID: "uidA"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeLocalEgressIP2},
+					Status:     crdv1a2.EgressStatus{EgressNode: fakeNode},
+				},
+			},
 			expectedCalls: func(mockOFClient *openflowtest.MockClient, mockRouteClient *routetest.MockInterface, mockIPAssigner *ipassignertest.MockIPAssigner) {
 				mockOFClient.EXPECT().InstallSNATMarkFlows(net.ParseIP(fakeLocalEgressIP1), uint32(1))
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(1), net.ParseIP(fakeLocalEgressIP1), uint32(1))
@@ -303,6 +327,12 @@ func TestSyncEgress(t *testing.T) {
 					{Pod: &cpv1b2.PodReference{Name: "pod3", Namespace: "ns3"}},
 				},
 			},
+			expectedEgresses: []*crdv1a2.Egress{
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressA", UID: "uidA"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeRemoteEgressIP1},
+				},
+			},
 			expectedCalls: func(mockOFClient *openflowtest.MockClient, mockRouteClient *routetest.MockInterface, mockIPAssigner *ipassignertest.MockIPAssigner) {
 				mockOFClient.EXPECT().InstallSNATMarkFlows(net.ParseIP(fakeLocalEgressIP1), uint32(1))
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(1), net.ParseIP(fakeLocalEgressIP1), uint32(1))
@@ -346,6 +376,13 @@ func TestSyncEgress(t *testing.T) {
 					{Pod: &cpv1b2.PodReference{Name: "pod3", Namespace: "ns3"}},
 				},
 			},
+			expectedEgresses: []*crdv1a2.Egress{
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressA", UID: "uidA"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeLocalEgressIP1},
+					Status:     crdv1a2.EgressStatus{EgressNode: fakeNode},
+				},
+			},
 			expectedCalls: func(mockOFClient *openflowtest.MockClient, mockRouteClient *routetest.MockInterface, mockIPAssigner *ipassignertest.MockIPAssigner) {
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(1), net.ParseIP(fakeRemoteEgressIP1), uint32(0))
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(2), net.ParseIP(fakeRemoteEgressIP1), uint32(0))
@@ -387,6 +424,18 @@ func TestSyncEgress(t *testing.T) {
 					{Pod: &cpv1b2.PodReference{Name: "pod3", Namespace: "ns3"}},
 				},
 			},
+			expectedEgresses: []*crdv1a2.Egress{
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressA", UID: "uidA"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeLocalEgressIP1},
+					Status:     crdv1a2.EgressStatus{EgressNode: fakeNode},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressB", UID: "uidB"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeLocalEgressIP2},
+					Status:     crdv1a2.EgressStatus{EgressNode: fakeNode},
+				},
+			},
 			expectedCalls: func(mockOFClient *openflowtest.MockClient, mockRouteClient *routetest.MockInterface, mockIPAssigner *ipassignertest.MockIPAssigner) {
 				mockOFClient.EXPECT().InstallSNATMarkFlows(net.ParseIP(fakeLocalEgressIP1), uint32(1))
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(1), net.ParseIP(fakeLocalEgressIP1), uint32(1))
@@ -426,6 +475,18 @@ func TestSyncEgress(t *testing.T) {
 					{Pod: &cpv1b2.PodReference{Name: "pod3", Namespace: "ns3"}},
 				},
 			},
+			expectedEgresses: []*crdv1a2.Egress{
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressA", UID: "uidA"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeLocalEgressIP1},
+					Status:     crdv1a2.EgressStatus{EgressNode: fakeNode},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "egressB", UID: "uidB"},
+					Spec:       crdv1a2.EgressSpec{EgressIP: fakeLocalEgressIP1},
+					Status:     crdv1a2.EgressStatus{EgressNode: fakeNode},
+				},
+			},
 			expectedCalls: func(mockOFClient *openflowtest.MockClient, mockRouteClient *routetest.MockInterface, mockIPAssigner *ipassignertest.MockIPAssigner) {
 				mockOFClient.EXPECT().InstallSNATMarkFlows(net.ParseIP(fakeLocalEgressIP1), uint32(1))
 				mockOFClient.EXPECT().InstallPodSNATFlows(uint32(1), net.ParseIP(fakeLocalEgressIP1), uint32(1))
@@ -470,6 +531,11 @@ func TestSyncEgress(t *testing.T) {
 			// Call it one more time to ensure it's idempotent, no extra datapath calls are supposed to be made.
 			err = c.syncEgress(tt.newEgress.Name)
 			assert.NoError(t, err)
+			for _, expectedEgress := range tt.expectedEgresses {
+				gotEgress, err := c.crdClient.CrdV1alpha2().Egresses().Get(context.TODO(), expectedEgress.Name, metav1.GetOptions{})
+				require.NoError(t, err)
+				assert.Equal(t, expectedEgress, gotEgress)
+			}
 		})
 	}
 }
@@ -624,3 +690,90 @@ func addPodInterface(ifaceStore interfacestore.InterfaceStore, podNamespace, pod
 		OVSPortConfig:            &interfacestore.OVSPortConfig{OFPort: ofPort},
 	})
 }
+
+func TestUpdateEgressStatus(t *testing.T) {
+	getError := fmt.Errorf("fake get Egress error")
+	updateConflictError := &errors.StatusError{ErrStatus: metav1.Status{Reason: metav1.StatusReasonConflict, Message: "update Egress conflict"}}
+	updateError := fmt.Errorf("update Egress error")
+	tests := []struct {
+		name                 string
+		updateErrorNum       int
+		updateError          error
+		getErrorNum          int
+		expectedUpdateCalled int
+		expectedGetCalled    int
+		expectedError        error
+	}{
+		{
+			name:                 "succeed immediately",
+			updateErrorNum:       0,
+			updateError:          nil,
+			getErrorNum:          0,
+			expectedUpdateCalled: 1,
+			expectedGetCalled:    0,
+			expectedError:        nil,
+		},
+		{
+			name:                 "succeed after one update conflict failure",
+			updateErrorNum:       1,
+			updateError:          updateConflictError,
+			getErrorNum:          0,
+			expectedUpdateCalled: 2,
+			expectedGetCalled:    1,
+			expectedError:        nil,
+		},
+		{
+			name:                 "fail after one update failure",
+			updateErrorNum:       1,
+			updateError:          updateError,
+			getErrorNum:          0,
+			expectedUpdateCalled: 1,
+			expectedGetCalled:    0,
+			expectedError:        updateError,
+		},
+		{
+			name:                 "fail after one update conflict failure and one get failure",
+			updateErrorNum:       1,
+			updateError:          updateConflictError,
+			getErrorNum:          1,
+			expectedUpdateCalled: 1,
+			expectedGetCalled:    1,
+			expectedError:        getError,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			egress := crdv1a2.Egress{
+				ObjectMeta: metav1.ObjectMeta{Name: "egressA", UID: "uidA", ResourceVersion: "fake-ResourceVersion"},
+				Spec:       crdv1a2.EgressSpec{EgressIP: fakeLocalEgressIP1},
+			}
+			fakeClient := &fakeversioned.Clientset{}
+			getCalled := 0
+			fakeClient.AddReactor("get", "egresses", func(action k8stesting.Action) (bool, runtime.Object, error) {
+				getCalled += 1
+				if getCalled <= tt.getErrorNum {
+					return true, nil, getError
+				}
+				return true, &egress, nil
+			})
+			updateCalled := 0
+			fakeClient.AddReactor("update", "*", func(action k8stesting.Action) (bool, runtime.Object, error) {
+				updateCalled += 1
+				if updateCalled <= tt.updateErrorNum {
+					return true, nil, tt.updateError
+				}
+				return true, &egress, nil
+			})
+
+			c := &EgressController{crdClient: fakeClient, nodeName: fakeNode}
+			_, err := c.crdClient.CrdV1alpha2().Egresses().Create(context.TODO(), &egress, metav1.CreateOptions{})
+			assert.NoError(t, err)
+			err = c.updateEgressStatus(&egress, true)
+			if err != tt.expectedError {
+				t.Errorf("Update Egress error not match, got: %v, expected: %v", err, tt.expectedError)
+			}
+			assert.Equal(t, tt.expectedGetCalled, getCalled, "Get called num not match")
+			assert.Equal(t, tt.expectedUpdateCalled, updateCalled, "Update called num not match")
+		})
+	}
+}
diff --git a/pkg/agent/controller/noderoute/node_route_controller_test.go b/pkg/agent/controller/noderoute/node_route_controller_test.go
index 162055cbe..893ea50a9 100644
--- a/pkg/agent/controller/noderoute/node_route_controller_test.go
+++ b/pkg/agent/controller/noderoute/node_route_controller_test.go
@@ -32,6 +32,8 @@ import (
 	"antrea.io/antrea/pkg/agent/interfacestore"
 	oftest "antrea.io/antrea/pkg/agent/openflow/testing"
 	routetest "antrea.io/antrea/pkg/agent/route/testing"
+	"antrea.io/antrea/pkg/agent/util"
+	"antrea.io/antrea/pkg/ovs/ovsconfig"
 	ovsconfigtest "antrea.io/antrea/pkg/ovs/ovsconfig/testing"
 )
 
@@ -55,7 +57,7 @@ type fakeController struct {
 	interfaceStore  interfacestore.InterfaceStore
 }
 
-func newController(t *testing.T) (*fakeController, func()) {
+func newController(t *testing.T, networkConfig *config.NetworkConfig) (*fakeController, func()) {
 	clientset := fake.NewSimpleClientset()
 	informerFactory := informers.NewSharedInformerFactory(clientset, 12*time.Hour)
 	ctrl := gomock.NewController(t)
@@ -63,7 +65,8 @@ func newController(t *testing.T) (*fakeController, func()) {
 	ovsClient := ovsconfigtest.NewMockOVSBridgeClient(ctrl)
 	routeClient := routetest.NewMockInterface(ctrl)
 	interfaceStore := interfacestore.NewInterfaceStore()
-	c := NewNodeRouteController(clientset, informerFactory, ofClient, ovsClient, routeClient, interfaceStore, &config.NetworkConfig{}, &config.NodeConfig{GatewayConfig: &config.GatewayConfig{
+
+	c := NewNodeRouteController(clientset, informerFactory, ofClient, ovsClient, routeClient, interfaceStore, networkConfig, &config.NodeConfig{GatewayConfig: &config.GatewayConfig{
 		IPv4: nil,
 		MAC:  gatewayMAC,
 	}})
@@ -79,7 +82,7 @@ func newController(t *testing.T) (*fakeController, func()) {
 }
 
 func TestControllerWithDuplicatePodCIDR(t *testing.T) {
-	c, closeFn := newController(t)
+	c, closeFn := newController(t, &config.NetworkConfig{})
 	defer closeFn()
 	defer c.queue.ShutDown()
 
@@ -163,7 +166,7 @@ func TestControllerWithDuplicatePodCIDR(t *testing.T) {
 }
 
 func TestIPInPodSubnets(t *testing.T) {
-	c, closeFn := newController(t)
+	c, closeFn := newController(t, &config.NetworkConfig{})
 	defer closeFn()
 	defer c.queue.ShutDown()
 
@@ -228,3 +231,148 @@ func TestIPInPodSubnets(t *testing.T) {
 	assert.Equal(t, false, c.Controller.IPInPodSubnets(net.ParseIP("10.10.10.10")))
 	assert.Equal(t, false, c.Controller.IPInPodSubnets(net.ParseIP("8.8.8.8")))
 }
+
+func setup(t *testing.T, ifaces []*interfacestore.InterfaceConfig) (*fakeController, func()) {
+	c, closeFn := newController(t, &config.NetworkConfig{
+		TrafficEncapMode:  0,
+		TunnelType:        ovsconfig.TunnelType("vxlan"),
+		EnableIPSecTunnel: true,
+		IPSecPSK:          "changeme",
+	})
+	for _, i := range ifaces {
+		c.interfaceStore.AddInterface(i)
+	}
+	return c, closeFn
+}
+
+func TestRemoveStaleTunnelPorts(t *testing.T) {
+	c, closeFn := setup(t, []*interfacestore.InterfaceConfig{
+		{
+			Type:          interfacestore.TunnelInterface,
+			InterfaceName: util.GenerateNodeTunnelInterfaceName("xyz-k8s-0-1"),
+			TunnelInterfaceConfig: &interfacestore.TunnelInterfaceConfig{
+				NodeName: "xyz-k8s-0-1",
+				Type:     ovsconfig.TunnelType("vxlan"),
+				PSK:      "mismatchpsk",
+				RemoteIP: nodeIP1,
+			},
+			OVSPortConfig: &interfacestore.OVSPortConfig{
+				PortUUID: "123",
+			},
+		},
+	})
+
+	defer closeFn()
+	defer c.queue.ShutDown()
+	stopCh := make(chan struct{})
+	defer close(stopCh)
+	c.informerFactory.Start(stopCh)
+	c.informerFactory.WaitForCacheSync(stopCh)
+	node1 := &corev1.Node{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "xyz-k8s-0-1",
+		},
+		Spec: corev1.NodeSpec{
+			PodCIDR:  podCIDR.String(),
+			PodCIDRs: []string{podCIDR.String()},
+		},
+		Status: corev1.NodeStatus{
+			Addresses: []corev1.NodeAddress{
+				{
+					Type:    corev1.NodeInternalIP,
+					Address: nodeIP1.String(),
+				},
+			},
+		},
+	}
+
+	c.clientset.CoreV1().Nodes().Create(context.TODO(), node1, metav1.CreateOptions{})
+	c.ovsClient.EXPECT().DeletePort("123").Times(1)
+
+	err := c.removeStaleTunnelPorts()
+	assert.NoError(t, err)
+}
+
+func TestCreateIPSecTunnelPort(t *testing.T) {
+	c, closeFn := setup(t, []*interfacestore.InterfaceConfig{
+		{
+			Type:          interfacestore.TunnelInterface,
+			InterfaceName: "mismatchedname",
+			TunnelInterfaceConfig: &interfacestore.TunnelInterfaceConfig{
+				NodeName: "xyz-k8s-0-2",
+				Type:     "vxlan",
+				PSK:      "changeme",
+				RemoteIP: nodeIP2,
+			},
+			OVSPortConfig: &interfacestore.OVSPortConfig{
+				PortUUID: "123",
+			},
+		},
+		{
+			Type:          interfacestore.TunnelInterface,
+			InterfaceName: util.GenerateNodeTunnelInterfaceName("xyz-k8s-0-3"),
+			TunnelInterfaceConfig: &interfacestore.TunnelInterfaceConfig{
+				NodeName: "xyz-k8s-0-3",
+				Type:     "vxlan",
+				PSK:      "changeme",
+				RemoteIP: net.ParseIP("10.10.10.1"),
+			},
+			OVSPortConfig: &interfacestore.OVSPortConfig{
+				PortUUID: "abc",
+				OFPort:   int32(5),
+			},
+		},
+	})
+
+	defer closeFn()
+	defer c.queue.ShutDown()
+	stopCh := make(chan struct{})
+	defer close(stopCh)
+	c.informerFactory.Start(stopCh)
+	c.informerFactory.WaitForCacheSync(stopCh)
+
+	node1PortName := util.GenerateNodeTunnelInterfaceName("xyz-k8s-0-1")
+	c.ovsClient.EXPECT().CreateTunnelPortExt(
+		node1PortName, ovsconfig.TunnelType("vxlan"), int32(0),
+		false, "", nodeIP1.String(), "changeme",
+		map[string]interface{}{ovsExternalIDNodeName: "xyz-k8s-0-1"}).Times(1)
+	c.ovsClient.EXPECT().GetOFPort(node1PortName).Return(int32(1), nil)
+
+	tests := []struct {
+		name       string
+		nodeName   string
+		peerNodeIP net.IP
+		wantErr    bool
+		want       int32
+	}{
+		{
+			name:       "create new port",
+			nodeName:   "xyz-k8s-0-1",
+			peerNodeIP: nodeIP1,
+			wantErr:    false,
+			want:       1,
+		},
+		{
+			name:       "hit cache but interface name changed for the same node",
+			nodeName:   "xyz-k8s-0-2",
+			peerNodeIP: nodeIP2,
+			wantErr:    true,
+		},
+		{
+			name:       "hit cache and return directly",
+			nodeName:   "xyz-k8s-0-3",
+			peerNodeIP: net.ParseIP("10.10.10.1"),
+			wantErr:    false,
+			want:       5,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := c.createIPSecTunnelPort(tt.nodeName, tt.peerNodeIP)
+			hasErr := err != nil
+			assert.Equal(t, tt.wantErr, hasErr)
+			assert.Equal(t, tt.want, got)
+		})
+	}
+}
diff --git a/pkg/agent/nodeportlocal/npl_agent_test.go b/pkg/agent/nodeportlocal/npl_agent_test.go
index ea9aae035..2a77df15c 100644
--- a/pkg/agent/nodeportlocal/npl_agent_test.go
+++ b/pkg/agent/nodeportlocal/npl_agent_test.go
@@ -191,8 +191,8 @@ func setUp(t *testing.T, tc *testConfig, objects ...runtime.Object) *testData {
 	mockCtrl := gomock.NewController(t)
 
 	mockIPTables := rulestesting.NewMockPodPortRules(mockCtrl)
-	mockIPTables.EXPECT().AddRule(gomock.Any(), gomock.Any()).AnyTimes()
-	mockIPTables.EXPECT().DeleteRule(gomock.Any(), gomock.Any()).AnyTimes()
+	mockIPTables.EXPECT().AddRule(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
+	mockIPTables.EXPECT().DeleteRule(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
 	mockIPTables.EXPECT().AddAllRules(gomock.Any()).AnyTimes()
 
 	mockPortOpener := portcachetesting.NewMockLocalPortOpener(mockCtrl)
@@ -267,9 +267,8 @@ func (t *testData) pollForPodAnnotation(podName string, found bool) (string, err
 		data, exists = ann[nplk8s.NPLAnnotationKey]
 		if found {
 			return exists, nil
-		} else {
-			return !exists, nil
 		}
+		return !exists, nil
 	})
 
 	return data, err
diff --git a/pkg/agent/nodeportlocal/rules/testing/mock_rules.go b/pkg/agent/nodeportlocal/rules/testing/mock_rules.go
index b0ce5f010..da1d7a03e 100644
--- a/pkg/agent/nodeportlocal/rules/testing/mock_rules.go
+++ b/pkg/agent/nodeportlocal/rules/testing/mock_rules.go
@@ -63,17 +63,17 @@ func (mr *MockPodPortRulesMockRecorder) AddAllRules(arg0 interface{}) *gomock.Ca
 }
 
 // AddRule mocks base method
-func (m *MockPodPortRules) AddRule(arg0 int, arg1 string) error {
+func (m *MockPodPortRules) AddRule(arg0 int, arg1 string, arg2 int) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AddRule", arg0, arg1)
+	ret := m.ctrl.Call(m, "AddRule", arg0, arg1, arg2)
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // AddRule indicates an expected call of AddRule
-func (mr *MockPodPortRulesMockRecorder) AddRule(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockPodPortRulesMockRecorder) AddRule(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRule", reflect.TypeOf((*MockPodPortRules)(nil).AddRule), arg0, arg1)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRule", reflect.TypeOf((*MockPodPortRules)(nil).AddRule), arg0, arg1, arg2)
 }
 
 // DeleteAllRules mocks base method
@@ -91,17 +91,17 @@ func (mr *MockPodPortRulesMockRecorder) DeleteAllRules() *gomock.Call {
 }
 
 // DeleteRule mocks base method
-func (m *MockPodPortRules) DeleteRule(arg0 int, arg1 string) error {
+func (m *MockPodPortRules) DeleteRule(arg0 int, arg1 string, arg2 int) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteRule", arg0, arg1)
+	ret := m.ctrl.Call(m, "DeleteRule", arg0, arg1, arg2)
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // DeleteRule indicates an expected call of DeleteRule
-func (mr *MockPodPortRulesMockRecorder) DeleteRule(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockPodPortRulesMockRecorder) DeleteRule(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRule", reflect.TypeOf((*MockPodPortRules)(nil).DeleteRule), arg0, arg1)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRule", reflect.TypeOf((*MockPodPortRules)(nil).DeleteRule), arg0, arg1, arg2)
 }
 
 // Init mocks base method
diff --git a/pkg/agent/openflow/client_test.go b/pkg/agent/openflow/client_test.go
index 7f3af062e..d2e4f3edd 100644
--- a/pkg/agent/openflow/client_test.go
+++ b/pkg/agent/openflow/client_test.go
@@ -62,9 +62,8 @@ func installNodeFlows(ofClient Client, cacheKey string) (int, error) {
 	fCacheI, ok := client.nodeFlowCache.Load(hostName)
 	if ok {
 		return len(fCacheI.(flowCache)), err
-	} else {
-		return 0, err
 	}
+	return 0, err
 }
 
 func installPodFlows(ofClient Client, cacheKey string) (int, error) {
@@ -77,9 +76,8 @@ func installPodFlows(ofClient Client, cacheKey string) (int, error) {
 	fCacheI, ok := client.podFlowCache.Load(containerID)
 	if ok {
 		return len(fCacheI.(flowCache)), err
-	} else {
-		return 0, err
 	}
+	return 0, err
 }
 
 // TestIdempotentFlowInstallation checks that InstallNodeFlows and InstallPodFlows are idempotent.
diff --git a/pkg/controller/networkpolicy/status_controller_test.go b/pkg/controller/networkpolicy/status_controller_test.go
index 614e85080..6155a272b 100644
--- a/pkg/controller/networkpolicy/status_controller_test.go
+++ b/pkg/controller/networkpolicy/status_controller_test.go
@@ -120,13 +120,12 @@ func toAntreaNetworkPolicy(inp *types.NetworkPolicy) runtime.Object {
 				Generation: inp.Generation,
 			},
 		}
-	} else {
-		return &crdv1alpha1.ClusterNetworkPolicy{
-			ObjectMeta: v1.ObjectMeta{
-				Name:       inp.SourceRef.Name,
-				Generation: inp.Generation,
-			},
-		}
+	}
+	return &crdv1alpha1.ClusterNetworkPolicy{
+		ObjectMeta: v1.ObjectMeta{
+			Name:       inp.SourceRef.Name,
+			Generation: inp.Generation,
+		},
 	}
 }
 
diff --git a/test/e2e/basic_test.go b/test/e2e/basic_test.go
index 57497ec6b..b4a26f3af 100644
--- a/test/e2e/basic_test.go
+++ b/test/e2e/basic_test.go
@@ -283,11 +283,11 @@ func testIPAMRestart(t *testing.T, data *TestData) {
 			return nil, err
 		}
 		pods = append(pods, podName)
-		if podIP, err := data.podWaitForIPs(defaultTimeout, podName, testNamespace); err != nil {
+		podIP, err := data.podWaitForIPs(defaultTimeout, podName, testNamespace)
+		if err != nil {
 			return nil, err
-		} else {
-			return podIP, nil
 		}
+		return podIP, nil
 	}
 
 	if podIP1, err = createPodAndGetIP(podName1); err != nil {
@@ -577,11 +577,11 @@ func getRoundNumber(data *TestData, podName string) (uint64, error) {
 		key := externalIDArray[0].(string)
 		value := externalIDArray[1].(string)
 		if key == "roundNum" {
-			if roundNum, err := strconv.ParseUint(value, 10, 64); err != nil {
+			roundNum, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
 				return 0, fmt.Errorf("cannot convert roundNum to uint64: %v", err)
-			} else {
-				return roundNum, nil
 			}
+			return roundNum, nil
 		}
 	}
 
@@ -768,13 +768,13 @@ func testClusterIdentity(t *testing.T, data *TestData) {
 	const timeout = 10 * time.Second
 	var clusterUUID uuid.UUID
 	err := wait.PollImmediate(retryInterval, timeout, func() (bool, error) {
-		if clusterIdentity, _, err := clusterIdentityProvider.Get(); err != nil {
+		clusterIdentity, _, err := clusterIdentityProvider.Get()
+		if err != nil {
 			return false, nil
-		} else {
-			clusterUUID = clusterIdentity.UUID
-			t.Logf("Cluster UUID: %v", clusterUUID)
-			return true, nil
 		}
+		clusterUUID = clusterIdentity.UUID
+		t.Logf("Cluster UUID: %v", clusterUUID)
+		return true, nil
 	})
 
 	assert.NoError(t, err, "Failed to retrieve cluster identity information within %v", timeout)
diff --git a/test/e2e/egress_test.go b/test/e2e/egress_test.go
index 29c2928fc..5394beb8f 100644
--- a/test/e2e/egress_test.go
+++ b/test/e2e/egress_test.go
@@ -169,13 +169,23 @@ ip netns exec %[1]s /agnhost netexec
 	assertClientIP(localPod, egressNodeIP)
 	assertClientIP(remotePod, egressNodeIP)
 
+	var err error
+	err = wait.Poll(time.Millisecond*100, time.Second, func() (bool, error) {
+		egress, err = data.crdClient.CrdV1alpha2().Egresses().Get(context.TODO(), egress.Name, metav1.GetOptions{})
+		if err != nil {
+			return false, err
+		}
+		return egress.Status.EgressNode == egressNode, nil
+	})
+	assert.NoError(t, err, "Egress failed to reach expected status")
+
 	t.Log("Updating the Egress's AppliedTo to remotePod only")
 	egress.Spec.AppliedTo = v1alpha2.AppliedTo{
 		PodSelector: &metav1.LabelSelector{
 			MatchLabels: map[string]string{"antrea-e2e": remotePod},
 		},
 	}
-	egress, err := data.crdClient.CrdV1alpha2().Egresses().Update(context.TODO(), egress, metav1.UpdateOptions{})
+	egress, err = data.crdClient.CrdV1alpha2().Egresses().Update(context.TODO(), egress, metav1.UpdateOptions{})
 	if err != nil {
 		t.Fatalf("Failed to update Egress %v: %v", egress, err)
 	}
@@ -342,7 +352,7 @@ func testEgressUpdateEgressIP(t *testing.T, data *TestData) {
 			toUpdate.Spec.ExternalIPPool = newPool.Name
 			toUpdate.Spec.EgressIP = newIP
 			egress, err = data.crdClient.CrdV1alpha2().Egresses().Update(context.TODO(), toUpdate, metav1.UpdateOptions{})
-			require.NoError(t, err, "Failed to delete Egress")
+			require.NoError(t, err, "Failed to update Egress")
 
 			_, err = data.checkEgressState(egress.Name, newIP, tt.newNode, "", time.Second)
 			require.NoError(t, err)
diff --git a/test/e2e/fixtures.go b/test/e2e/fixtures.go
index 74af68c7b..cc183ba9e 100644
--- a/test/e2e/fixtures.go
+++ b/test/e2e/fixtures.go
@@ -429,13 +429,12 @@ func createTestBusyboxPods(tb testing.TB, data *TestData, num int, ns string, no
 			tb.Errorf("Error when creating busybox test Pod '%s': %v", podName, err)
 			return "", nil, err
 		}
-
-		if podIP, err := data.podWaitForIPs(defaultTimeout, podName, ns); err != nil {
+		podIP, err := data.podWaitForIPs(defaultTimeout, podName, ns)
+		if err != nil {
 			tb.Errorf("Error when waiting for IP for Pod '%s': %v", podName, err)
 			return podName, nil, err
-		} else {
-			return podName, podIP, nil
 		}
+		return podName, podIP, nil
 	}
 
 	podsCh := make(chan podData, num)
diff --git a/test/e2e/flowaggregator_test.go b/test/e2e/flowaggregator_test.go
index f96db55a8..54fa74468 100644
--- a/test/e2e/flowaggregator_test.go
+++ b/test/e2e/flowaggregator_test.go
@@ -775,9 +775,8 @@ func getCollectorOutput(t *testing.T, srcIP, dstIP, srcPort string, timeStart ti
 				}
 			}
 			return false, nil
-		} else {
-			return strings.Contains(collectorOutput, srcIP) && strings.Contains(collectorOutput, dstIP) && strings.Contains(collectorOutput, srcPort), nil
 		}
+		return strings.Contains(collectorOutput, srcIP) && strings.Contains(collectorOutput, dstIP) && strings.Contains(collectorOutput, srcPort), nil
 	})
 	require.NoErrorf(t, err, "IPFIX collector did not receive the expected records in collector output: %v time start: %s iperf source port: %s", collectorOutput, timeStart.String(), srcPort)
 	return collectorOutput, recordSlices
diff --git a/test/e2e/framework.go b/test/e2e/framework.go
index dcaaf3a91..8b7e6d98b 100644
--- a/test/e2e/framework.go
+++ b/test/e2e/framework.go
@@ -219,11 +219,11 @@ func workerNodeName(idx int) string {
 	if idx == 0 { // control-plane Node
 		return ""
 	}
-	if node, ok := clusterInfo.nodes[idx]; !ok {
+	node, ok := clusterInfo.nodes[idx]
+	if !ok {
 		return ""
-	} else {
-		return node.name
 	}
+	return node.name
 }
 
 // workerNodeIP returns an empty string if there is no worker Node with the provided idx
@@ -232,21 +232,21 @@ func workerNodeIP(idx int) string {
 	if idx == 0 { // control-plane Node
 		return ""
 	}
-	if node, ok := clusterInfo.nodes[idx]; !ok {
+	node, ok := clusterInfo.nodes[idx]
+	if !ok {
 		return ""
-	} else {
-		return node.ip
 	}
+	return node.ip
 }
 
 // nodeGatewayIPs returns the Antrea gateway's IPv4 address and IPv6 address for the provided Node
 // (if applicable), in that order.
 func nodeGatewayIPs(idx int) (string, string) {
-	if node, ok := clusterInfo.nodes[idx]; !ok {
+	node, ok := clusterInfo.nodes[idx]
+	if !ok {
 		return "", ""
-	} else {
-		return node.gwV4Addr, node.gwV6Addr
 	}
+	return node.gwV4Addr, node.gwV6Addr
 }
 
 func controlPlaneNodeName() string {
@@ -260,21 +260,21 @@ func controlPlaneNodeIP() string {
 // nodeName returns an empty string if there is no Node with the provided idx. If idx is 0, the name
 // of the control-plane Node will be returned.
 func nodeName(idx int) string {
-	if node, ok := clusterInfo.nodes[idx]; !ok {
+	node, ok := clusterInfo.nodes[idx]
+	if !ok {
 		return ""
-	} else {
-		return node.name
 	}
+	return node.name
 }
 
 // nodeIP returns an empty string if there is no Node with the provided idx. If idx is 0, the IP
 // of the control-plane Node will be returned.
 func nodeIP(idx int) string {
-	if node, ok := clusterInfo.nodes[idx]; !ok {
+	node, ok := clusterInfo.nodes[idx]
+	if !ok {
 		return ""
-	} else {
-		return node.ip
 	}
+	return node.ip
 }
 
 func labelNodeRoleControlPlane() string {
@@ -305,11 +305,11 @@ func initProvider() error {
 		"remote":  providers.NewRemoteProvider,
 	}
 	if fn, ok := providerFactory[testOptions.providerName]; ok {
-		if newProvider, err := fn(testOptions.providerConfigPath); err != nil {
+		newProvider, err := fn(testOptions.providerConfigPath)
+		if err != nil {
 			return err
-		} else {
-			provider = newProvider
 		}
+		provider = newProvider
 	} else {
 		return fmt.Errorf("unknown provider '%s'", testOptions.providerName)
 	}
@@ -410,35 +410,35 @@ func collectClusterInfo() error {
 			return res, fmt.Errorf("error when running the following command `%s` on control-plane Node: %v, %s", cmd, err, stdout)
 		}
 		re := regexp.MustCompile(reg)
-		if matches := re.FindStringSubmatch(stdout); len(matches) == 0 {
+		matches := re.FindStringSubmatch(stdout)
+		if len(matches) == 0 {
 			return res, fmt.Errorf("cannot retrieve CIDR, unexpected kubectl output: %s", stdout)
-		} else {
-			cidrs := strings.Split(matches[1], ",")
-			if len(cidrs) == 1 {
-				_, cidr, err := net.ParseCIDR(cidrs[0])
-				if err != nil {
-					return res, fmt.Errorf("CIDR cannot be parsed: %s", cidrs[0])
-				}
-				if cidr.IP.To4() != nil {
-					res[0] = cidrs[0]
-				} else {
-					res[1] = cidrs[0]
-				}
-			} else if len(cidrs) == 2 {
-				_, cidr, err := net.ParseCIDR(cidrs[0])
-				if err != nil {
-					return res, fmt.Errorf("CIDR cannot be parsed: %s", cidrs[0])
-				}
-				if cidr.IP.To4() != nil {
-					res[0] = cidrs[0]
-					res[1] = cidrs[1]
-				} else {
-					res[0] = cidrs[1]
-					res[1] = cidrs[0]
-				}
+		}
+		cidrs := strings.Split(matches[1], ",")
+		if len(cidrs) == 1 {
+			_, cidr, err := net.ParseCIDR(cidrs[0])
+			if err != nil {
+				return res, fmt.Errorf("CIDR cannot be parsed: %s", cidrs[0])
+			}
+			if cidr.IP.To4() != nil {
+				res[0] = cidrs[0]
 			} else {
-				return res, fmt.Errorf("unexpected cluster CIDR: %s", matches[1])
+				res[1] = cidrs[0]
 			}
+		} else if len(cidrs) == 2 {
+			_, cidr, err := net.ParseCIDR(cidrs[0])
+			if err != nil {
+				return res, fmt.Errorf("CIDR cannot be parsed: %s", cidrs[0])
+			}
+			if cidr.IP.To4() != nil {
+				res[0] = cidrs[0]
+				res[1] = cidrs[1]
+			} else {
+				res[0] = cidrs[1]
+				res[1] = cidrs[0]
+			}
+		} else {
+			return res, fmt.Errorf("unexpected cluster CIDR: %s", matches[1])
 		}
 		return res, nil
 	}
@@ -1027,8 +1027,7 @@ func (data *TestData) deletePodAndWait(timeout time.Duration, name string, ns st
 	if err := data.deletePod(ns, name); err != nil {
 		return err
 	}
-
-	if err := wait.Poll(defaultInterval, timeout, func() (bool, error) {
+	err := wait.Poll(defaultInterval, timeout, func() (bool, error) {
 		if _, err := data.clientset.CoreV1().Pods(ns).Get(context.TODO(), name, metav1.GetOptions{}); err != nil {
 			if errors.IsNotFound(err) {
 				return true, nil
@@ -1037,11 +1036,11 @@ func (data *TestData) deletePodAndWait(timeout time.Duration, name string, ns st
 		}
 		// Keep trying
 		return false, nil
-	}); err == wait.ErrWaitTimeout {
+	})
+	if err == wait.ErrWaitTimeout {
 		return fmt.Errorf("Pod '%s' still visible to client after %v", name, timeout)
-	} else {
-		return err
 	}
+	return err
 }
 
 type PodCondition func(*corev1.Pod) (bool, error)
@@ -1050,14 +1049,14 @@ type PodCondition func(*corev1.Pod) (bool, error)
 // the condition predicate is met (or until the provided timeout expires).
 func (data *TestData) podWaitFor(timeout time.Duration, name, namespace string, condition PodCondition) (*corev1.Pod, error) {
 	err := wait.Poll(defaultInterval, timeout, func() (bool, error) {
-		if pod, err := data.clientset.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{}); err != nil {
+		pod, err := data.clientset.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{})
+		if err != nil {
 			if errors.IsNotFound(err) {
 				return false, nil
 			}
 			return false, fmt.Errorf("error when getting Pod '%s': %v", name, err)
-		} else {
-			return condition(pod)
 		}
+		return condition(pod)
 	})
 	if err != nil {
 		return nil, err
@@ -1412,7 +1411,7 @@ func (data *TestData) deleteServiceAndWait(timeout time.Duration, name string) e
 		return err
 	}
 
-	if err := wait.Poll(defaultInterval, timeout, func() (bool, error) {
+	err := wait.Poll(defaultInterval, timeout, func() (bool, error) {
 		if _, err := data.clientset.CoreV1().Services(testNamespace).Get(context.TODO(), name, metav1.GetOptions{}); err != nil {
 			if errors.IsNotFound(err) {
 				return true, nil
@@ -1421,11 +1420,11 @@ func (data *TestData) deleteServiceAndWait(timeout time.Duration, name string) e
 		}
 		// Keep trying
 		return false, nil
-	}); err == wait.ErrWaitTimeout {
+	})
+	if err == wait.ErrWaitTimeout {
 		return fmt.Errorf("Service '%s' still visible to client after %v", name, timeout)
-	} else {
-		return err
 	}
+	return err
 }
 
 // createNetworkPolicy creates a network policy with spec.
@@ -1539,16 +1538,17 @@ func parseArpingStdout(out string) (sent uint32, received uint32, loss float32,
 	if len(matches) == 0 {
 		return 0, 0, 0.0, fmt.Errorf("Unexpected arping output")
 	}
-	if v, err := strconv.ParseUint(matches[1], 10, 32); err != nil {
+	v, err := strconv.ParseUint(matches[1], 10, 32)
+	if err != nil {
 		return 0, 0, 0.0, fmt.Errorf("Error when retrieving 'sent probes' from arpping output: %v", err)
-	} else {
-		sent = uint32(v)
 	}
-	if v, err := strconv.ParseUint(matches[2], 10, 32); err != nil {
+	sent = uint32(v)
+
+	v, err = strconv.ParseUint(matches[2], 10, 32)
+	if err != nil {
 		return 0, 0, 0.0, fmt.Errorf("Error when retrieving 'received responses' from arpping output: %v", err)
-	} else {
-		received = uint32(v)
 	}
+	received = uint32(v)
 	loss = 100. * float32(sent-received) / float32(sent)
 	return sent, received, loss, nil
 }
@@ -2037,14 +2037,14 @@ func (data *TestData) createDaemonSet(name string, ns string, ctrName string, im
 
 func (data *TestData) waitForDaemonSetPods(timeout time.Duration, dsName string, namespace string) error {
 	err := wait.Poll(defaultInterval, timeout, func() (bool, error) {
-		if ds, err := data.clientset.AppsV1().DaemonSets(namespace).Get(context.TODO(), dsName, metav1.GetOptions{}); err != nil {
+		ds, err := data.clientset.AppsV1().DaemonSets(namespace).Get(context.TODO(), dsName, metav1.GetOptions{})
+		if err != nil {
 			return false, err
-		} else {
-			if ds.Status.NumberReady != int32(clusterInfo.numNodes) {
-				return false, nil
-			}
-			return true, nil
 		}
+		if ds.Status.NumberReady != int32(clusterInfo.numNodes) {
+			return false, nil
+		}
+		return true, nil
 	})
 	if err != nil {
 		return err
diff --git a/test/e2e/infra/vagrant/playbook/roles/common/tasks/docker.yml b/test/e2e/infra/vagrant/playbook/roles/common/tasks/docker.yml
index 62cc47da8..5784acb90 100644
--- a/test/e2e/infra/vagrant/playbook/roles/common/tasks/docker.yml
+++ b/test/e2e/infra/vagrant/playbook/roles/common/tasks/docker.yml
@@ -46,3 +46,16 @@
 # Install docker-py so that docker images can be pulled
 - pip:
     name: docker-py
+
+- name: Create Docker daemon configuration from template
+  template:
+    src: templates/docker.json.j2
+    dest: /etc/docker/daemon.json
+  register: docker_config
+
+- name: Restart Docker
+  service:
+    name: docker
+    daemon_reload: yes
+    state: restarted
+  when: docker_config.changed
diff --git a/test/e2e/infra/vagrant/playbook/roles/common/templates/docker.json.j2 b/test/e2e/infra/vagrant/playbook/roles/common/templates/docker.json.j2
new file mode 100644
index 000000000..5d18abccd
--- /dev/null
+++ b/test/e2e/infra/vagrant/playbook/roles/common/templates/docker.json.j2
@@ -0,0 +1,8 @@
+{
+  "exec-opts": ["native.cgroupdriver=systemd"],
+  "log-driver": "json-file",
+  "log-opts": {
+    "max-size": "100m"
+  },
+  "storage-driver": "overlay2"
+}
diff --git a/test/e2e/ipsec_test.go b/test/e2e/ipsec_test.go
index 610ed43e2..cb2c1b3d4 100644
--- a/test/e2e/ipsec_test.go
+++ b/test/e2e/ipsec_test.go
@@ -58,16 +58,16 @@ func (data *TestData) readSecurityAssociationsStatus(nodeName string) (up int, c
 	if len(matches) == 0 {
 		return 0, 0, fmt.Errorf("unexpected 'ipsec status' output: %s", stdout)
 	}
-	if v, err := strconv.ParseUint(matches[1], 10, 32); err != nil {
+	v, err := strconv.ParseUint(matches[1], 10, 32)
+	if err != nil {
 		return 0, 0, fmt.Errorf("error when retrieving 'up' SAs from 'ipsec status' output: %v", err)
-	} else {
-		up = int(v)
 	}
-	if v, err := strconv.ParseUint(matches[2], 10, 32); err != nil {
+	up = int(v)
+	v, err = strconv.ParseUint(matches[2], 10, 32)
+	if err != nil {
 		return 0, 0, fmt.Errorf("error when retrieving 'connecting' SAs from 'ipsec status' output: %v", err)
-	} else {
-		connecting = int(v)
 	}
+	connecting = int(v)
 	return up, connecting, nil
 }
 
diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go
index 989fd6254..ab011f519 100644
--- a/test/e2e/main_test.go
+++ b/test/e2e/main_test.go
@@ -43,14 +43,13 @@ func (tOptions *TestOptions) setupLogging() func() {
 				log.Printf("Logs exported under '%s', it is your responsibility to delete the directory when you no longer need it", name)
 			}
 		}
-	} else {
-		fInfo, err := os.Stat(tOptions.logsExportDir)
-		if err != nil {
-			log.Fatalf("Cannot stat provided directory '%s': %v", tOptions.logsExportDir, err)
-		}
-		if !fInfo.Mode().IsDir() {
-			log.Fatalf("'%s' is not a valid directory", tOptions.logsExportDir)
-		}
+	}
+	fInfo, err := os.Stat(tOptions.logsExportDir)
+	if err != nil {
+		log.Fatalf("Cannot stat provided directory '%s': %v", tOptions.logsExportDir, err)
+	}
+	if !fInfo.Mode().IsDir() {
+		log.Fatalf("'%s' is not a valid directory", tOptions.logsExportDir)
 	}
 	// no-op cleanup function
 	return func() {}
diff --git a/test/e2e/providers/vagrant.go b/test/e2e/providers/vagrant.go
index b68644c45..1ce53a26d 100644
--- a/test/e2e/providers/vagrant.go
+++ b/test/e2e/providers/vagrant.go
@@ -73,11 +73,11 @@ func convertConfig(inConfig *ssh_config.Config, name string) (string, *ssh.Clien
 	values := make(map[string]string)
 
 	for _, key := range keyList {
-		if value, err := getFromKeyStrict(key); err != nil {
+		value, err := getFromKeyStrict(key)
+		if err != nil {
 			return "", nil, err
-		} else {
-			values[key] = value
 		}
+		values[key] = value
 	}
 
 	identityFile := values["IdentityFile"]
diff --git a/test/integration/agent/cniserver_test.go b/test/integration/agent/cniserver_test.go
index c814e4be1..34fb02f29 100644
--- a/test/integration/agent/cniserver_test.go
+++ b/test/integration/agent/cniserver_test.go
@@ -282,9 +282,8 @@ func (tc testCase) createCheckCmdArgs(targetNS ns.NetNS, config *Net, dataDir st
 func ipVersion(ip net.IP) string {
 	if ip.To4() != nil {
 		return "4"
-	} else {
-		return "6"
 	}
+	return "6"
 }
 
 type cmdAddDelTester struct {
diff --git a/test/integration/agent/openflow_test.go b/test/integration/agent/openflow_test.go
index 8adc762d2..e343658d7 100644
--- a/test/integration/agent/openflow_test.go
+++ b/test/integration/agent/openflow_test.go
@@ -799,9 +799,8 @@ func getIPProtoStr(addr types.Address) (bool, string) {
 	}
 	if addrIP.To4() != nil {
 		return false, "ip"
-	} else {
-		return true, "ipv6"
 	}
+	return true, "ipv6"
 }
 
 func checkOVSFlowMetrics(t *testing.T, client ofClient.Client) {