From 3ab6aea2639dd52867c3bc12fbca2fac3848452f Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Tue, 30 Nov 2021 16:01:27 +0000 Subject: [PATCH] Do no use "--strict" for OF deletion in TRANSIENT_TABLE There are two types of OF rules in TRANSIENT_TABLE: - With priority 100: these rules match by "in_port", that is a unique identifier. - With priority 90: these rules match by MAC address and VLAN ID. This combination (MAC, VLAN) is unique. That means when a deleting an OF rule in TRANSIENT_TABLE, it is enough to specify the "in_port" or the (MAC, VLAN) tuple. The "--strict" parameter, added to also define the priority, is not needed. By removing the "--strict" parameter, these deletion commands can be executed synchronously at the end of the OVS deferred context, when all the OF rule commands (addition or deletion), are executed at the same time. That removes the small window, detected in the related bug, when the OF rule set for a port is not complete. Closes-Bug: #1952770 Change-Id: I9f5bd8a1404dde3a0aa163ce72aef2961f537676 (cherry picked from commit ef7f673098c2a4574365f6f4ed20734f29309f08) --- .../linux/openvswitch_firewall/firewall.py | 41 +++++-------------- .../openvswitch_firewall/test_firewall.py | 12 ++---- 2 files changed, 14 insertions(+), 39 deletions(-) diff --git a/neutron/agent/linux/openvswitch_firewall/firewall.py b/neutron/agent/linux/openvswitch_firewall/firewall.py index 2e95cf1c39c..110521f023a 100644 --- a/neutron/agent/linux/openvswitch_firewall/firewall.py +++ b/neutron/agent/linux/openvswitch_firewall/firewall.py @@ -546,14 +546,6 @@ class OVSFirewallDriver(firewall.FirewallDriver): else: self.int_br.br.delete_flows(**kwargs) - def _strict_delete_flow(self, **kwargs): - """Delete given flow right away even if bridge is deferred. - - Delete command will use strict delete. - """ - create_reg_numbers(kwargs) - self.int_br.br.delete_flows(strict=True, **kwargs) - @staticmethod def initialize_bridge(int_br): int_br.add_protocols(*OVSFirewallDriver.REQUIRED_PROTOCOLS) @@ -734,13 +726,6 @@ class OVSFirewallDriver(firewall.FirewallDriver): def _update_flows_for_port(self, of_port, old_of_port): with self.update_cookie_context(): self._set_port_filters(of_port) - # Flush the flows caused by changes made to deferred bridge. The reason - # is that following delete_all_port_flows() call uses --strict - # parameter that cannot be combined with other non-strict rules, hence - # all parameters with --strict are applied right away. In order to - # avoid applying delete rules with --strict *before* - # _set_port_filters() we dump currently cached flows here. - self.int_br.apply_flows() self.delete_all_port_flows(old_of_port) # Rewrite update cookie with default cookie self._set_port_filters(of_port) @@ -853,15 +838,13 @@ class OVSFirewallDriver(firewall.FirewallDriver): def delete_physical_direct_flow(self, mac, segment_id): if segment_id: - self._strict_delete_flow(priority=90, - table=ovs_consts.TRANSIENT_TABLE, - dl_dst=mac, - dl_vlan=segment_id) + self._delete_flows(table=ovs_consts.TRANSIENT_TABLE, + dl_dst=mac, + dl_vlan=segment_id) else: - self._strict_delete_flow(priority=90, - table=ovs_consts.TRANSIENT_TABLE, - dl_dst=mac, - vlan_tci=ovs_consts.FLAT_VLAN_TCI) + self._delete_flows(table=ovs_consts.TRANSIENT_TABLE, + dl_dst=mac, + vlan_tci=ovs_consts.FLAT_VLAN_TCI) def initialize_port_flows(self, port): """Set base flows for port @@ -1506,19 +1489,17 @@ class OVSFirewallDriver(firewall.FirewallDriver): def delete_all_port_flows(self, port): """Delete all flows for given port""" for mac_addr in port.all_allowed_macs: - self._strict_delete_flow(priority=90, - table=ovs_consts.TRANSIENT_TABLE, - dl_dst=mac_addr, - dl_vlan=port.vlan_tag) + self._delete_flows(table=ovs_consts.TRANSIENT_TABLE, + dl_dst=mac_addr, + dl_vlan=port.vlan_tag) self.delete_physical_direct_flow(mac_addr, port.segment_id) self._delete_flows(table=ovs_consts.ACCEPT_OR_INGRESS_TABLE, dl_dst=mac_addr, reg_net=port.vlan_tag) self.delete_accepted_egress_direct_flow( port.mac, port.vlan_tag) - self._strict_delete_flow(priority=100, - table=ovs_consts.TRANSIENT_TABLE, - in_port=port.ofport) + self._delete_flows(table=ovs_consts.TRANSIENT_TABLE, + in_port=port.ofport) self._delete_flows(reg_port=port.ofport) def delete_flows_for_flow_state( diff --git a/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py b/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py index cccdbbb537b..bed5e481650 100644 --- a/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py +++ b/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py @@ -774,16 +774,12 @@ class TestOVSFirewallDriver(base.BaseTestCase): self.firewall.delete_all_port_flows(port) - call_args1 = {"strict": True, - "priority": 90, - "table": ovs_consts.TRANSIENT_TABLE, + call_args1 = {"table": ovs_consts.TRANSIENT_TABLE, "dl_dst": port.mac, "dl_vlan": port.vlan_tag} flow1 = mock.call(**call_args1) - call_args2 = {"strict": True, - "priority": 90, - "table": ovs_consts.TRANSIENT_TABLE, + call_args2 = {"table": ovs_consts.TRANSIENT_TABLE, "dl_dst": port.mac, "dl_vlan": port.segment_id} flow2 = mock.call(**call_args2) @@ -794,8 +790,6 @@ class TestOVSFirewallDriver(base.BaseTestCase): flow3 = mock.call(**call_args3) call_args4 = {"in_port": port.ofport, - "strict": True, - "priority": 100, "table": ovs_consts.TRANSIENT_TABLE} flow4 = mock.call(**call_args4) @@ -896,7 +890,7 @@ class TestOVSFirewallDriver(base.BaseTestCase): self.firewall.prepare_port_filter(port_dict) with self.firewall.defer_apply(): self.firewall.update_port_filter(port_dict) - self.assertEqual(2, self.mock_bridge.apply_flows.call_count) + self.mock_bridge.apply_flows.assert_called_once() def test_update_port_filter_clean_when_port_not_found(self): """Check flows are cleaned if port is not found in the bridge."""