Skip to content

Commit 0cccea3

Browse files
committed
[OVN] Remove ACLs with remote SG during deletion of SG
When a security group is removed, the rules having this security group as remote are removed. But the OVN ACL registers related to those rules are not removed. This patch catches the security group deletion precommit event to perform this cleanup. Closes-Bug: #1983600 Change-Id: I6bb84cb748a2f80f2ff640ceeb3223413f7e92c7 (cherry picked from commit 1957353)
1 parent 1fda7ab commit 0cccea3

File tree

2 files changed

+56
-9
lines changed

2 files changed

+56
-9
lines changed

neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ def subscribe(self):
255255
registry.subscribe(self._create_security_group,
256256
resources.SECURITY_GROUP,
257257
events.AFTER_CREATE)
258+
registry.subscribe(self._delete_security_group_precommit,
259+
resources.SECURITY_GROUP,
260+
events.PRECOMMIT_DELETE)
258261
registry.subscribe(self._delete_security_group,
259262
resources.SECURITY_GROUP,
260263
events.AFTER_DELETE)
@@ -425,6 +428,14 @@ def _create_security_group(self, resource, event, trigger, payload):
425428
self._ovn_client.create_security_group(context,
426429
security_group)
427430

431+
def _delete_security_group_precommit(self, resource, event, trigger,
432+
payload):
433+
context = n_context.get_admin_context()
434+
security_group_id = payload.resource_id
435+
for sg_rule in self._plugin.get_security_group_rules(
436+
context, filters={'remote_group_id': [security_group_id]}):
437+
self._ovn_client.delete_security_group_rule(context, sg_rule)
438+
428439
def _delete_security_group(self, resource, event, trigger, payload):
429440
context = payload.context
430441
security_group_id = payload.resource_id

neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,12 @@ def setUp(self):
784784
super(TestSecurityGroup, self).setUp()
785785
self._ovn_client = self.mech_driver._ovn_client
786786
self.plugin = self.mech_driver._plugin
787+
self.sg_data = {
788+
'name': 'testsg',
789+
'description': 'Test Security Group',
790+
'tenant_id': self._tenant_id,
791+
'is_default': True,
792+
}
787793

788794
def _find_acls_for_sg(self, sg_id):
789795
rows = self.nb_api.db_find_rows('ACL').execute(check_error=True)
@@ -800,28 +806,29 @@ def get_api_id(r):
800806
return [r for r in rows if get_api_id(r) in rule_ids]
801807
return []
802808

809+
def _find_acl_remote_sg(self, remote_sg_id):
810+
# NOTE: the ACL to be found has ethertype=IPv4 and protocol=ICMP.
811+
sg_match = '$pg_' + remote_sg_id.replace('-', '_') + '_ip4 && icmp4'
812+
for row in self.nb_api.db_find_rows('ACL').execute(check_error=True):
813+
if sg_match in row.match:
814+
return row
815+
803816
def test_sg_stateful_toggle_updates_ovn_acls(self):
804817
def check_acl_actions(sg_id, expected):
805818
self.assertEqual(
806819
{expected},
807820
set(a.action for a in self._find_acls_for_sg(sg_id))
808821
)
809822

810-
sg_data = {
811-
'name': 'testsg',
812-
'description': 'Test Security Group',
813-
'tenant_id': self._tenant_id,
814-
'is_default': True,
815-
}
816823
sg = self.plugin.create_security_group(
817-
self.context, security_group={'security_group': sg_data})
824+
self.context, security_group={'security_group': self.sg_data})
818825
check_acl_actions(sg['id'], 'allow-related')
819826

820827
def update_sg(stateful):
821-
sg_data['stateful'] = stateful
828+
self.sg_data['stateful'] = stateful
822829
self.plugin.update_security_group(
823830
self.context, sg['id'],
824-
security_group={'security_group': sg_data})
831+
security_group={'security_group': self.sg_data})
825832

826833
update_sg(False)
827834
check_acl_actions(sg['id'], 'allow-stateless')
@@ -832,6 +839,35 @@ def update_sg(stateful):
832839
update_sg(False)
833840
check_acl_actions(sg['id'], 'allow-stateless')
834841

842+
def test_remove_sg_with_related_rule_remote_sg(self):
843+
self.sg_data['is_default'] = False
844+
sg1 = self.plugin.create_security_group(
845+
self.context, security_group={'security_group': self.sg_data})
846+
sg2 = self.plugin.create_security_group(
847+
self.context, security_group={'security_group': self.sg_data})
848+
rule_data = {'direction': constants.INGRESS_DIRECTION,
849+
'ethertype': constants.IPv4,
850+
'protocol': constants.PROTO_NAME_ICMP,
851+
'port_range_max': None,
852+
'port_range_min': None,
853+
'remote_ip_prefix': None,
854+
'tenant_id': sg1['project_id'],
855+
'remote_address_group_id': None,
856+
'security_group_id': sg1['id'],
857+
'remote_group_id': sg2['id']}
858+
sg_rule = {'security_group_rule': rule_data}
859+
rule = self.plugin.create_security_group_rule(self.context, sg_rule)
860+
acl = self._find_acl_remote_sg(sg2['id'])
861+
self.assertEqual(rule['id'],
862+
acl.external_ids[ovn_const.OVN_SG_RULE_EXT_ID_KEY])
863+
acls = self._find_acls_for_sg(sg1['id'])
864+
self.assertEqual(3, len(acls))
865+
866+
self.plugin.delete_security_group(self.context, sg2['id'])
867+
self.assertIsNone(self._find_acl_remote_sg(sg2['id']))
868+
acls = self._find_acls_for_sg(sg1['id'])
869+
self.assertEqual(2, len(acls))
870+
835871

836872
class TestProvnetPorts(base.TestOVNFunctionalBase):
837873

0 commit comments

Comments
 (0)