Skip to content

Commit 7ac9eda

Browse files
committed
Improve the SG RPC callback security_group_info_for_ports
This method populates the SG rules in a dictionary. Each SG rule inherits the "stateful" value of the SG. Prior to this patch, each SG rule was isuing a database call to retrieve the SG register. In this patch, the SG "stateful" retrieval is done in one database query for all SG. That improves the performance of this method reducing the database access to only one single call. This improvement, as commented in the LP bug, affects to ML2/LinuxBridge. ML2/OVS agent uses a cached RPC implementation that not requires to perform any RPC call/database query. Conflicts: neutron/objects/securitygroup.py Closes-Bug: #2045950 Change-Id: Iafd0419a1d1eeb25d5589edc2570ebf287450957 (cherry picked from commit 6b6abb9)
1 parent 6b86538 commit 7ac9eda

File tree

4 files changed

+46
-13
lines changed

4 files changed

+46
-13
lines changed

neutron/api/rpc/handlers/securitygroups_rpc.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,10 @@ def _select_sg_ids_for_ports(self, context, ports):
431431
for sg_id in p['security_group_ids']))
432432
return [(sg_id, ) for sg_id in sg_ids]
433433

434-
def _is_security_group_stateful(self, context, sg_id):
435-
sg = self.rcache.get_resource_by_id(resources.SECURITYGROUP, sg_id)
436-
return sg.stateful
434+
def _get_sgs_stateful_flag(self, context, sg_ids):
435+
sgs_stateful = {}
436+
for sg_id in sg_ids:
437+
sg = self.rcache.get_resource_by_id(resources.SECURITYGROUP, sg_id)
438+
sgs_stateful[sg_id] = sg.stateful
439+
440+
return sgs_stateful

neutron/db/securitygroups_rpc_base.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,10 @@ def security_group_info_for_ports(self, context, ports):
211211
# this set will be serialized into a list by rpc code
212212
remote_address_group_info[remote_ag_id][ethertype] = set()
213213
direction = rule_in_db['direction']
214-
stateful = self._is_security_group_stateful(context,
215-
security_group_id)
216214
rule_dict = {
217215
'direction': direction,
218216
'ethertype': ethertype,
219-
'stateful': stateful}
217+
}
220218

221219
for key in ('protocol', 'port_range_min', 'port_range_max',
222220
'remote_ip_prefix', 'remote_group_id',
@@ -234,6 +232,13 @@ def security_group_info_for_ports(self, context, ports):
234232
if rule_dict not in sg_info['security_groups'][security_group_id]:
235233
sg_info['security_groups'][security_group_id].append(
236234
rule_dict)
235+
236+
# Populate the security group "stateful" flag in the SGs list of rules.
237+
for sg_id, stateful in self._get_sgs_stateful_flag(
238+
context, sg_info['security_groups'].keys()).items():
239+
for rule in sg_info['security_groups'][sg_id]:
240+
rule['stateful'] = stateful
241+
237242
# Update the security groups info if they don't have any rules
238243
sg_ids = self._select_sg_ids_for_ports(context, ports)
239244
for (sg_id, ) in sg_ids:
@@ -427,13 +432,13 @@ def _select_sg_ids_for_ports(self, context, ports):
427432
"""
428433
raise NotImplementedError()
429434

430-
def _is_security_group_stateful(self, context, sg_id):
431-
"""Return whether the security group is stateful or not.
435+
def _get_sgs_stateful_flag(self, context, sg_id):
436+
"""Return the security groups stateful flag.
432437
433-
Return True if the security group associated with the given ID
434-
is stateful, else False.
438+
Returns a dictionary with the SG ID as key and the stateful flag:
439+
{sg_1: True, sg_2: False, ...}
435440
"""
436-
return True
441+
raise NotImplementedError()
437442

438443

439444
class SecurityGroupServerRpcMixin(SecurityGroupInfoAPIMixin,
@@ -526,5 +531,5 @@ def _select_ips_for_remote_address_group(self, context,
526531
return ips_by_group
527532

528533
@db_api.retry_if_session_inactive()
529-
def _is_security_group_stateful(self, context, sg_id):
530-
return sg_obj.SecurityGroup.get_sg_by_id(context, sg_id).stateful
534+
def _get_sgs_stateful_flag(self, context, sg_ids):
535+
return sg_obj.SecurityGroup.get_sgs_stateful_flag(context, sg_ids)

neutron/objects/securitygroup.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# under the License.
1212

1313
from neutron_lib import context as context_lib
14+
from neutron_lib.db import api as db_api
1415
from neutron_lib.objects import common_types
1516
from neutron_lib.utils import net as net_utils
1617
from oslo_utils import versionutils
@@ -132,6 +133,13 @@ def get_bound_project_ids(cls, context, obj_id):
132133
security_group_ids=[obj_id])
133134
return {port.project_id for port in port_objs}
134135

136+
@classmethod
137+
@db_api.CONTEXT_READER
138+
def get_sgs_stateful_flag(cls, context, sg_ids):
139+
query = context.session.query(cls.db_model.id, cls.db_model.stateful)
140+
query = query.filter(cls.db_model.id.in_(sg_ids))
141+
return dict(query.all())
142+
135143

136144
@base.NeutronObjectRegistry.register
137145
class DefaultSecurityGroup(base.NeutronDbObject):

neutron/tests/unit/objects/test_securitygroup.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,22 @@ def test_get_objects_no_synth(self):
210210
self.assertEqual(len(sg_obj.rules), 0)
211211
self.assertIsNone(listed_objs[0].rules)
212212

213+
def test_get_sgs_stateful_flag(self):
214+
for obj in self.objs:
215+
obj.create()
216+
217+
sg_ids = tuple(sg.id for sg in self.objs)
218+
sgs_stateful = securitygroup.SecurityGroup.get_sgs_stateful_flag(
219+
self.context, sg_ids)
220+
for sg_id, stateful in sgs_stateful.items():
221+
for obj in (obj for obj in self.objs if obj.id == sg_id):
222+
self.assertEqual(obj.stateful, stateful)
223+
224+
sg_ids = sg_ids + ('random_id_not_present', )
225+
sgs_stateful = securitygroup.SecurityGroup.get_sgs_stateful_flag(
226+
self.context, sg_ids)
227+
self.assertEqual(len(self.objs), len(sgs_stateful))
228+
213229

214230
class DefaultSecurityGroupIfaceObjTestCase(test_base.BaseObjectIfaceTestCase):
215231

0 commit comments

Comments
 (0)