Merge "Fix L2 agent does not remove unused ipset set"

This commit is contained in:
Jenkins 2014-11-18 00:35:35 +00:00 committed by Gerrit Code Review
commit a6d7a5f450
2 changed files with 70 additions and 26 deletions

View File

@ -320,12 +320,14 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
def _get_remote_sg_ids(self, port, direction):
sg_ids = port.get('security_groups', [])
remote_sg_ids = []
remote_sg_ids = {constants.IPv4: [], constants.IPv6: []}
for sg_id in sg_ids:
remote_sg_ids.extend([rule['remote_group_id']
for rule in self.sg_rules.get(sg_id, []) if
rule['direction'] == direction
and rule.get('remote_group_id')])
for rule in self.sg_rules.get(sg_id, []):
if rule['direction'] == direction:
remote_sg_id = rule.get('remote_group_id')
ether_type = rule.get('ethertype')
if remote_sg_id and ether_type:
remote_sg_ids[ether_type].append(remote_sg_id)
return remote_sg_ids
def _add_rule_by_security_group(self, port, direction):
@ -394,16 +396,15 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
self.ipset_chains[chain_name].remove(del_ip)
def _update_ipset_chain_member(self, security_group_ids):
for sg_id in security_group_ids or []:
for ethertype in ['IPv4', 'IPv6']:
for ethertype, sg_ids in security_group_ids.items():
for sg_id in sg_ids:
add_ips = self._get_new_sg_member_ips(sg_id, ethertype)
del_ips = self._get_deleted_sg_member_ips(sg_id, ethertype)
cur_member_ips = self._get_cur_sg_member_ips(sg_id, ethertype)
chain_name = ethertype + sg_id[:IPSET_CHAIN_LEN]
if chain_name not in self.ipset_chains and cur_member_ips:
self.ipset_chains[chain_name] = []
self.ipset.create_ipset_chain(
chain_name, ethertype)
self.ipset.create_ipset_chain(chain_name, ethertype)
self._bulk_set_ips_to_chain(chain_name,
cur_member_ips, ethertype)
elif (len(add_ips) + len(del_ips)
@ -537,32 +538,47 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
self._defer_apply = True
def _remove_unused_security_group_info(self):
need_removed_ipset_chains = set()
need_removed_ipset_chains = {constants.IPv4: set(),
constants.IPv6: set()}
need_removed_security_groups = set()
remote_group_ids = set()
remote_group_ids = {constants.IPv4: set(),
constants.IPv6: set()}
cur_group_ids = set()
for port in self.filtered_ports.values():
source_groups = port.get('security_group_source_groups', [])
remote_group_ids.update(source_groups)
for direction in INGRESS_DIRECTION, EGRESS_DIRECTION:
for ethertype, sg_ids in self._get_remote_sg_ids(
port, direction).items():
remote_group_ids[ethertype].update(sg_ids)
groups = port.get('security_groups', [])
cur_group_ids.update(groups)
need_removed_ipset_chains.update(
[x for x in self.pre_sg_members if x not in remote_group_ids])
need_removed_security_groups.update(
[x for x in self.pre_sg_rules if x not in cur_group_ids])
# Remove unused remote security group member ips
for remove_chain_id in need_removed_ipset_chains:
if remove_chain_id in self.sg_members:
self.sg_members.pop(remove_chain_id, None)
if self.enable_ipset:
for ethertype in ['IPv4', 'IPv6']:
for ethertype in [constants.IPv4, constants.IPv6]:
need_removed_ipset_chains[ethertype].update(
[x for x in self.pre_sg_members if x not in remote_group_ids[
ethertype]])
need_removed_security_groups.update(
[x for x in self.pre_sg_rules if x not in cur_group_ids])
# Remove unused remote ipset set
for ethertype, remove_chain_ids in need_removed_ipset_chains.items():
for remove_chain_id in remove_chain_ids:
if self.sg_members.get(remove_chain_id, {}).get(ethertype, []):
self.sg_members[remove_chain_id][ethertype] = []
if self.enable_ipset:
removed_chain = (
ethertype + remove_chain_id[:IPSET_CHAIN_LEN])
if removed_chain in self.ipset_chains:
self.ipset.destroy_ipset_chain_by_name(removed_chain)
self.ipset.destroy_ipset_chain_by_name(
removed_chain)
self.ipset_chains.pop(removed_chain, None)
# Remove unused remote security group member ips
sg_ids = self.sg_members.keys()
for sg_id in sg_ids:
if not (self.sg_members[sg_id].get(constants.IPv4, [])
or self.sg_members[sg_id].get(constants.IPv6, [])):
self.sg_members.pop(sg_id, None)
# Remove unused security group rules
for remove_group_id in need_removed_security_groups:
if remove_group_id in self.sg_rules:

View File

@ -1419,7 +1419,10 @@ class IptablesFirewallEnhancedIpsetTestCase(BaseIptablesFirewallTestCase):
def _fake_sg_rule(self):
return {'fake_sgid': [
{'direction': 'ingress', 'remote_group_id': 'fake_sgid'}]}
{'direction': 'ingress', 'remote_group_id': 'fake_sgid',
'ethertype': 'IPv4'},
{'direction': 'ingress', 'remote_group_id': 'fake_sgid',
'ethertype': 'IPv6'}]}
def test_prepare_port_filter_with_default_sg(self):
self.firewall.sg_rules = self._fake_sg_rule()
@ -1523,7 +1526,8 @@ class IptablesFirewallEnhancedIpsetTestCase(BaseIptablesFirewallTestCase):
def test_prepare_port_filter_with_sg_no_member(self):
self.firewall.sg_rules = self._fake_sg_rule()
self.firewall.sg_rules['fake_sgid'].append(
{'direction': 'ingress', 'remote_group_id': 'fake_sgid2'})
{'direction': 'ingress', 'remote_group_id': 'fake_sgid2',
'ethertype': 'IPv4'})
self.firewall.sg_rules.update()
self.firewall.sg_members = {'fake_sgid': {
'IPv4': ['10.0.0.1', '10.0.0.2'], 'IPv6': ['fe80::1']}}
@ -1539,3 +1543,27 @@ class IptablesFirewallEnhancedIpsetTestCase(BaseIptablesFirewallTestCase):
'IPv6fake_sgid', ['fe80::1'], 'IPv6')]
self.firewall.ipset.assert_has_calls(calls)
def test_filter_defer_apply_off_with_sg_only_ipv6_rule(self):
self.firewall.sg_rules = self._fake_sg_rule()
self.firewall.pre_sg_rules = self._fake_sg_rule()
self.firewall.ipset_chains = {'IPv4fake_sgid': ['10.0.0.2'],
'IPv6fake_sgid': ['fe80::1']}
self.firewall.sg_members = {'fake_sgid': {
'IPv4': ['10.0.0.2'],
'IPv6': ['fe80::1']}}
self.firewall.pre_sg_members = {'fake_sgid': {
'IPv4': ['10.0.0.2'],
'IPv6': ['fe80::1']}}
self.firewall.sg_rules['fake_sgid'].remove(
{'direction': 'ingress', 'remote_group_id': 'fake_sgid',
'ethertype': 'IPv4'})
self.firewall.sg_rules.update()
self.firewall._defer_apply = True
port = self._fake_port()
self.firewall.filtered_ports['tapfake_dev'] = port
self.firewall._pre_defer_filtered_ports = {}
self.firewall.filter_defer_apply_off()
calls = [mock.call.destroy_ipset_chain_by_name('IPv4fake_sgid')]
self.firewall.ipset.assert_has_calls(calls, True)