Skip to content

Commit f4e2c17

Browse files
committed
Fix cleanup of LRP for deleted pods
When the EIP controller cleans up a stale EIP assignment for a pod, it also removes the pod object from the podAssignment cache. This is incorrect, as it prevents the EIP controller from processing the subsequent pod delete event. Scenario: 1. pod-1 is served by eip-1, both hosted on node1. 2. node1’s ovnkube-controller restarts. 3. Pod add event is received by the EIP controller — no changes. 4. eip-1 moves from node1 to node0. 5. The EIP controller receives the eip-1 add event. 6. eip-1 cleans up pod-1’s stale assignment (SNAT and LRP) for node1, but removes the pod object from the podAssignment cache when no other assignments found. 7. The EIP controller programs the LRP entry with node0’s transit IP as the next hop, but the pod assignment cache is not updated with new podAssignmentState. 8. The pod delete event is received by the EIP controller but ignored, since the pod object is missing from the assignment cache. So this commit fixes the issue by adding podAssignmentState back into podAssignment cache at step 7. Signed-off-by: Periyasamy Palanisamy <[email protected]> (cherry picked from commit 16dedd1)
1 parent b8303a2 commit f4e2c17

File tree

2 files changed

+144
-1
lines changed

2 files changed

+144
-1
lines changed

go-controller/pkg/ovn/egressip.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,6 @@ func (e *EgressIPController) addPodEgressIPAssignments(ni util.NetInfo, name str
818818
podIPs: podIPs,
819819
network: ni,
820820
}
821-
e.podAssignment.Store(podKey, podState)
822821
} else if podState.egressIPName == name || podState.egressIPName == "" {
823822
// We do the setup only if this egressIP object is the one serving this pod OR
824823
// podState.egressIPName can be empty if no re-routes were found in
@@ -863,6 +862,10 @@ func (e *EgressIPController) addPodEgressIPAssignments(ni util.NetInfo, name str
863862
}
864863
delete(podState.egressStatuses.statusMap, staleStatus)
865864
}
865+
// We store podState into podAssignment cache at this place for two reasons.
866+
// 1. When podAssignmentState is newly created.
867+
// 2. deletePodEgressIPAssignments might clean the podAssignment cache, make sure we add it back.
868+
e.podAssignment.Store(podKey, podState)
866869
// We need to proceed with add only under two conditions
867870
// 1) egressNode present in at least one status is local to this zone
868871
// (NOTE: The relation between egressIPName and nodeName is 1:1 i.e in the same object the given node will be present only in one status)

go-controller/pkg/ovn/egressip_test.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11355,6 +11355,7 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network"
1135511355
}
1135611356
err = fakeOvn.controller.eIPC.reconcileEgressIP(nil, &eIP)
1135711357
gomega.Expect(err).NotTo(gomega.HaveOccurred())
11358+
gomega.Expect(getPodAssignmentState(&egressPod)).NotTo(gomega.BeNil())
1135811359

1135911360
egressSVCServedPodsASv4, _ := buildEgressServiceAddressSets(nil)
1136011361
egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets([]string{podV4IP}, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName)
@@ -11495,6 +11496,145 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network"
1149511496
egressSVCServedPodsASv4, egressIPServedPodsASv4, egressNodeIPsASv4,
1149611497
}
1149711498
gomega.Eventually(fakeOvn.nbClient).Should(libovsdbtest.HaveData(expectedDatabaseState))
11499+
// Since we called reconcileEgressIP manually with new eIP status in the above step, so update EIP object with
11500+
// same status as well.
11501+
_, err = fakeOvn.fakeClient.EgressIPClient.K8sV1().EgressIPs().Update(context.TODO(), &eIP, metav1.UpdateOptions{})
11502+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
11503+
gomega.Eventually(fakeOvn.nbClient).Should(libovsdbtest.HaveData(expectedDatabaseState))
11504+
11505+
// Now delete local zone egressPod and check LRP is removed.
11506+
err = fakeOvn.fakeClient.KubeClient.CoreV1().Pods(egressPod.Namespace).Delete(context.TODO(), egressPod.Name, metav1.DeleteOptions{})
11507+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
11508+
egressIPServedPodsASv4, _ = buildEgressIPServedPodsAddressSets([]string{}, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName)
11509+
node1Switch.QOSRules = []string{"default-QoS-UUID"}
11510+
expectedDatabaseState = []libovsdbtest.TestData{
11511+
&nbdb.LogicalRouterPolicy{
11512+
Priority: types.DefaultNoRereoutePriority,
11513+
Match: fmt.Sprintf("(ip4.src == $%s || ip4.src == $%s) && ip4.dst == $%s",
11514+
egressIPServedPodsASv4.Name, egressSVCServedPodsASv4.Name, egressNodeIPsASv4.Name),
11515+
Action: nbdb.LogicalRouterPolicyActionAllow,
11516+
UUID: "default-no-reroute-node-UUID",
11517+
Options: map[string]string{"pkt_mark": types.EgressIPNodeConnectionMark},
11518+
ExternalIDs: getEgressIPLRPNoReRoutePodToNodeDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(),
11519+
},
11520+
getNoReRouteReplyTrafficPolicy(types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName),
11521+
&nbdb.LogicalRouterPolicy{
11522+
Priority: types.DefaultNoRereoutePriority,
11523+
Match: "ip4.src == 10.128.0.0/14 && ip4.dst == 10.128.0.0/14",
11524+
Action: nbdb.LogicalRouterPolicyActionAllow,
11525+
UUID: "no-reroute-UUID",
11526+
ExternalIDs: getEgressIPLRPNoReRoutePodToPodDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(),
11527+
},
11528+
&nbdb.LogicalRouterPolicy{
11529+
Priority: types.DefaultNoRereoutePriority,
11530+
Match: fmt.Sprintf("ip4.src == 10.128.0.0/14 && ip4.dst == %s", config.Gateway.V4JoinSubnet),
11531+
Action: nbdb.LogicalRouterPolicyActionAllow,
11532+
UUID: "no-reroute-service-UUID",
11533+
ExternalIDs: getEgressIPLRPNoReRoutePodToJoinDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(),
11534+
},
11535+
&nbdb.LogicalRouter{
11536+
Name: types.OVNClusterRouter,
11537+
UUID: types.OVNClusterRouter + "-UUID",
11538+
Policies: []string{"no-reroute-UUID", "no-reroute-service-UUID", "default-no-reroute-node-UUID", "default-no-reroute-reply-traffic"},
11539+
},
11540+
&nbdb.LogicalRouter{
11541+
Name: types.GWRouterPrefix + node1.Name,
11542+
UUID: types.GWRouterPrefix + node1.Name + "-UUID",
11543+
Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"},
11544+
Nat: []string{"pod-node-nat-UUID1"},
11545+
Options: logicalRouterOptions,
11546+
},
11547+
&nbdb.LogicalRouter{
11548+
Name: types.GWRouterPrefix + node2.Name,
11549+
UUID: types.GWRouterPrefix + node2.Name + "-UUID",
11550+
Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"},
11551+
Options: logicalRouterOptions,
11552+
},
11553+
&nbdb.LogicalRouter{
11554+
Name: types.GWRouterPrefix + node3.Name,
11555+
UUID: types.GWRouterPrefix + node3.Name + "-UUID",
11556+
Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"},
11557+
Options: logicalRouterOptions,
11558+
},
11559+
// we still expect the SNAT at the end because we are not watching pod events that would remove the SNAT on pod deletion
11560+
&nbdb.NAT{
11561+
UUID: "pod-node-nat-UUID1",
11562+
LogicalIP: podV4IP,
11563+
ExternalIP: node1IPv4,
11564+
ExternalIDs: nil,
11565+
Type: nbdb.NATTypeSNAT,
11566+
Options: map[string]string{
11567+
"stateless": "false",
11568+
},
11569+
},
11570+
&nbdb.LogicalRouterPort{
11571+
UUID: types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID",
11572+
Name: types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name,
11573+
Networks: []string{node2LogicalRouterIfAddrV4},
11574+
},
11575+
&nbdb.LogicalRouterPort{
11576+
UUID: types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID",
11577+
Name: types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name,
11578+
Networks: []string{nodeLogicalRouterIfAddrV4},
11579+
},
11580+
&nbdb.LogicalRouterPort{
11581+
UUID: types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID",
11582+
Name: types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name,
11583+
Networks: []string{node3LogicalRouterIfAddrV4},
11584+
},
11585+
&nbdb.LogicalSwitchPort{
11586+
UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID",
11587+
Name: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name,
11588+
Type: "router",
11589+
Options: map[string]string{
11590+
libovsdbops.RouterPort: types.GWRouterToExtSwitchPrefix + "GR_" + node1Name,
11591+
"nat-addresses": "router",
11592+
"exclude-lb-vips-from-garp": "true",
11593+
},
11594+
},
11595+
&nbdb.LogicalSwitchPort{
11596+
UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node2Name + "-UUID",
11597+
Name: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node2Name,
11598+
Type: "router",
11599+
Options: map[string]string{
11600+
libovsdbops.RouterPort: types.GWRouterToExtSwitchPrefix + "GR_" + node2Name,
11601+
"nat-addresses": "router",
11602+
"exclude-lb-vips-from-garp": "true",
11603+
},
11604+
},
11605+
&nbdb.LogicalSwitchPort{
11606+
UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node3Name + "-UUID",
11607+
Name: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node3Name,
11608+
Type: "router",
11609+
Options: map[string]string{
11610+
libovsdbops.RouterPort: types.GWRouterToExtSwitchPrefix + "GR_" + node3Name,
11611+
"nat-addresses": "router",
11612+
"exclude-lb-vips-from-garp": "true",
11613+
},
11614+
},
11615+
&nbdb.LogicalSwitch{
11616+
UUID: types.ExternalSwitchPrefix + node1Name + "-UUID",
11617+
Name: types.ExternalSwitchPrefix + node1Name,
11618+
Ports: []string{types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID"},
11619+
},
11620+
&nbdb.LogicalSwitch{
11621+
UUID: types.ExternalSwitchPrefix + node2Name + "-UUID",
11622+
Name: types.ExternalSwitchPrefix + node2Name,
11623+
Ports: []string{types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node2Name + "-UUID"},
11624+
},
11625+
&nbdb.LogicalSwitch{
11626+
UUID: types.ExternalSwitchPrefix + node3Name + "-UUID",
11627+
Name: types.ExternalSwitchPrefix + node3Name,
11628+
Ports: []string{types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node3Name + "-UUID"},
11629+
},
11630+
node1Switch,
11631+
node2Switch,
11632+
node3Switch,
11633+
getDefaultQoSRule(false, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName),
11634+
egressSVCServedPodsASv4, egressIPServedPodsASv4, egressNodeIPsASv4,
11635+
}
11636+
gomega.Eventually(fakeOvn.nbClient).Should(libovsdbtest.HaveData(expectedDatabaseState))
11637+
1149811638
return nil
1149911639
}
1150011640
err := app.Run([]string{app.Name})

0 commit comments

Comments
 (0)