The conntrack flush of a removed ECMP next-hop is queued in front of
the flow bundle that takes the next-hop out of the flows.  A packet that
the switch handles in between finds no conntrack entry and goes through
the old flows, which can still pick the removed next-hop and commit a
new entry with its MAC in ct_label.  Nothing flushes that entry later.

Queue the flush after the bundle instead, next to the LB 5-tuple
flushes.  The test now checks that the flush follows the bundle commit.

CC: Lorenzo Bianconi <[email protected]>
CC: Dumitru Ceara <[email protected]>
Fixes: b4cacd5c2142 ("ofctrl: Introduce ecmp_nexthop_monitor.")
Assisted-by: Claude Opus 5.5, Claude Code
Signed-off-by: Bekei Park <[email protected]>
---
 controller/ofctrl.c | 15 +++++++++------
 tests/ovn.at        |  6 +++++-
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/controller/ofctrl.c b/controller/ofctrl.c
index 12da7f7..194a0c0 100644
--- a/controller/ofctrl.c
+++ b/controller/ofctrl.c
@@ -2821,12 +2821,6 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table,
     /* OpenFlow messages to send to the switch to bring it up-to-date. */
     struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
 
-    /* Removed ECMP next-hops stay pending while the connection is down,
-     * because rconn drops the messages queued then. */
-    if (rconn_is_connected(swconn)) {
-        ecmp_nexthop_monitor_flush(swconn, &msgs);
-    }
-
     /* Iterate through ct zones that need to be flushed. */
     struct shash_node *iter;
     SHASH_FOR_EACH(iter, pending_ct_zones) {
@@ -3024,6 +3018,15 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table,
         }
     }
 
+    /* Flush the conntrack entries of removed ECMP next-hops after the flow
+     * bundle, so that a packet in between cannot commit a new entry towards
+     * a removed next-hop through the old flows.  Removed next-hops stay
+     * pending while the connection is down, because rconn drops the
+     * messages queued then. */
+    if (rconn_is_connected(swconn)) {
+        ecmp_nexthop_monitor_flush(swconn, &msgs);
+    }
+
     acl_ids_flush_expired(tracked_acl_ids, rconn_get_version(swconn), &msgs);
 
     if (!ovs_list_is_empty(&msgs)) {
diff --git a/tests/ovn.at b/tests/ovn.at
index d14418b..62bb542 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -48718,7 +48718,7 @@ check test -n "$zone"
 flush_10="NXT_CT_FLUSH .* zone=$zone labels=0xf0000000101000000000/"
 flush_20="NXT_CT_FLUSH .* zone=$zone labels=0xf0000000202000000000/"
 
-AS_BOX([Removed next-hop is flushed])
+AS_BOX([Removed next-hop is flushed after the flow bundle])
 n=$(wc -l < hv1/ovs-vswitchd.log)
 check ovn-nbctl --wait=hv lr-route-del lr0 1.0.0.0/24 192.168.10.20
 tail -n +$((n + 1)) hv1/ovs-vswitchd.log > vswitchd-del.log
@@ -48726,6 +48726,10 @@ AT_CHECK([grep -c "$flush_20" vswitchd-del.log], [0], 
[1
 ])
 AT_CHECK([grep -c "$flush_10" vswitchd-del.log], [1], [0
 ])
+commit=$(grep -n "type=COMMIT_REQUEST" vswitchd-del.log | head -1 | cut -d: 
-f1)
+flush=$(grep -n "$flush_20" vswitchd-del.log | cut -d: -f1)
+check test -n "$commit"
+check test "$commit" -lt "$flush"
 
 AS_BOX([Removed next-hop is flushed when ofctrl could not send at removal])
 check ovn-nbctl --ecmp-symmetric-reply lr-route-add lr0 1.0.0.0/24 
192.168.10.20
-- 
2.43.0


_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to