[ovs-dev] [PATCH ovn] pinctrl: Fix race condition when explicitly clearing IGMP groups.
Dumitru Ceara
dceara at redhat.com
Tue Dec 22 15:41:37 UTC 2020
When a user flushes the IGMP Groups ("ovn-sbctl ip-multicast-flush")
there's no guarantee that the ovn-controller main thread runs soon after
the pinctrl thread has flushed the in-memory IGMP groups, in
ip_mcast_snoop_flush().
To avoid unnecessarily waking the main thread just clear the local
IGMP_Group records in the main thread.
This scenario is quite hard to encounter in real deployments but every
now and then we hit it in CI.
Fixes: 70ff8243040f ("OVN: Add IGMP SB definitions and ovn-controller support")
Signed-off-by: Dumitru Ceara <dceara at redhat.com>
---
controller/pinctrl.c | 37 +++++++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 7e3abf0..e957b75 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -4507,9 +4507,16 @@ ip_mcast_snoop_state_find(int64_t dp_key)
return NULL;
}
+/* Updates the ip_mcast_snoop_cfg for a logical datapath specified by
+ * 'dp_key'. Also sets 'needs_flush' to 'true' if the config change should
+ * to trigger flushing of the existing IGMP_Groups.
+ *
+ * Returns 'true' if any changes happened to the configuration.
+ */
static bool
ip_mcast_snoop_state_update(int64_t dp_key,
- const struct ip_mcast_snoop_cfg *cfg)
+ const struct ip_mcast_snoop_cfg *cfg,
+ bool *needs_flush)
OVS_REQUIRES(pinctrl_mutex)
{
bool notify = false;
@@ -4519,6 +4526,9 @@ ip_mcast_snoop_state_update(int64_t dp_key,
ms_state = ip_mcast_snoop_state_add(dp_key);
notify = true;
} else if (memcmp(cfg, &ms_state->cfg, sizeof *cfg)) {
+ if (ms_state->cfg.seq_no != cfg->seq_no) {
+ *needs_flush = true;
+ }
notify = true;
}
@@ -4738,6 +4748,25 @@ ip_mcast_snoop_run(void)
}
}
+/* Flushes all IGMP_Groups installed by the local chassis for the logical
+ * datapath specified by 'dp_key'.
+ */
+static void
+ip_mcast_flush_groups(int64_t dp_key, const struct sbrec_chassis *chassis,
+ struct ovsdb_idl_index *sbrec_igmp_groups)
+{
+ const struct sbrec_igmp_group *sbrec_igmp;
+
+ SBREC_IGMP_GROUP_FOR_EACH_BYINDEX (sbrec_igmp, sbrec_igmp_groups) {
+ if (!sbrec_igmp->datapath ||
+ sbrec_igmp->datapath->tunnel_key != dp_key ||
+ sbrec_igmp->chassis != chassis) {
+ continue;
+ }
+ igmp_group_delete(sbrec_igmp);
+ }
+}
+
/*
* This runs in the pinctrl main thread, so it has access to the southbound
* database. It reads the IP_Multicast table and updates the local multicast
@@ -4770,11 +4799,15 @@ ip_mcast_sync(struct ovsdb_idl_txn *ovnsb_idl_txn,
int64_t dp_key = ip_mcast->datapath->tunnel_key;
struct ip_mcast_snoop_cfg cfg;
+ bool flush_groups = false;
ip_mcast_snoop_cfg_load(&cfg, ip_mcast);
- if (ip_mcast_snoop_state_update(dp_key, &cfg)) {
+ if (ip_mcast_snoop_state_update(dp_key, &cfg, &flush_groups)) {
notify = true;
}
+ if (flush_groups) {
+ ip_mcast_flush_groups(dp_key, chassis, sbrec_igmp_groups);
+ }
}
/* Then delete the old entries. */
--
1.8.3.1
More information about the dev
mailing list