From aec9bc271e71950d9974145d1f0d22cc3caa481e Mon Sep 17 00:00:00 2001 From: Terry Wilson Date: Wed, 23 Sep 2020 20:32:33 +0000 Subject: [PATCH] Avoid race condition when processing RowEvents In https://review.opendev.org/#/c/753824/ ovsdbapp adds the ability to pass a "frozen" object to the RowEventHandler so that if a transaction is started from the main thread that changes the row, it won't step on the values that the Event is trying to process. This patch backports the needed ovsdbapp changes for RowEventHandler which converts the row to a frozen_row. Change-Id: I87489596e2ff224431f7e83f43a1725172ee0953 Related-Bug: #1896816 (cherry picked from commit ab6d4afd954d3afb0c07287915077b96121dd0fe) --- .../ovn/mech_driver/ovsdb/backports.py | 36 +++++++++++++++++++ .../ovn/mech_driver/ovsdb/ovsdb_monitor.py | 6 ++-- 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/backports.py diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/backports.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/backports.py new file mode 100644 index 00000000000..c7f9829360f --- /dev/null +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/backports.py @@ -0,0 +1,36 @@ +# Copyright 2021 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# We don't technically require ovsdbapp that has these fixes so +# just include them here for stable releases +try: + from ovsdbapp.backend.ovs_idl import idlutils + frozen_row = idlutils.frozen_row +except AttributeError: + def frozen_row(row): + return row._table.rows.IndexEntry( + uuid=row.uuid, + **{col: getattr(row, col) + for col in row._table.columns if hasattr(row, col)}) + +try: + from ovsdbapp.backend.ovs_idl import event as row_event + from ovsdbapp import event as ovsdb_event + + RowEventHandler = row_event.RowEventHandler +except AttributeError: + class RowEventHandler(ovsdb_event.RowEventHandler): + def notify(self, event, row, updates=None): + row = frozen_row(row) + super().notify(event, row, updates) diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py index c1299998400..5fa1850c8f4 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py @@ -27,7 +27,6 @@ from ovs.stream import Stream from ovsdbapp.backend.ovs_idl import connection from ovsdbapp.backend.ovs_idl import event as row_event from ovsdbapp.backend.ovs_idl import idlutils -from ovsdbapp import event from neutron.common.ovn import constants as ovn_const from neutron.common.ovn import exceptions @@ -35,6 +34,7 @@ from neutron.common.ovn import hash_ring_manager from neutron.common.ovn import utils from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf from neutron.db import ovn_hash_ring_db +from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import backports CONF = cfg.CONF @@ -358,7 +358,7 @@ class NeutronPgDropPortGroupCreated(row_event.WaitEvent): self.event_name = 'PortGroupCreated' -class OvnDbNotifyHandler(event.RowEventHandler): +class OvnDbNotifyHandler(backports.RowEventHandler): def __init__(self, driver): super(OvnDbNotifyHandler, self).__init__() self.driver = driver @@ -374,7 +374,7 @@ class Ml2OvnIdlBase(connection.OvsdbIdl): class BaseOvnIdl(Ml2OvnIdlBase): def __init__(self, remote, schema): - self.notify_handler = event.RowEventHandler() + self.notify_handler = backports.RowEventHandler() super(BaseOvnIdl, self).__init__(remote, schema) @classmethod