Security Group integration scale up

Previous implementation had to change since it was bounded to max 100
security-group due to platform limitation.
The proposed implementation will allow unlimited number of
security-group and up to 4k ports which has no security-group associated to
them.

Change-Id: I72168ae95d02496cb1f9270204c6def5042d785b
This commit is contained in:
Roey Chen 2015-10-18 04:34:39 -07:00
parent e5c24c01ef
commit 378409061c
3 changed files with 51 additions and 34 deletions

View File

@ -185,14 +185,16 @@ def get_ip_cidr_reference(ip_cidr_block, ip_protocol):
def get_firewall_rule_dict(display_name, source=None, destination=None,
direction=IN_OUT, ip_protocol=IPV4_IPV6,
service=None, action=ALLOW):
service=None, action=ALLOW, applied_tos=None):
return {'display_name': display_name,
'sources': [source] if source else [],
'destinations': [destination] if destination else [],
'direction': direction,
'ip_protocol': ip_protocol,
'services': [service] if service else [],
'action': action}
'action': action,
'applied_tos': [get_nsgroup_reference(t_id) for t_id
in applied_tos] if applied_tos else []}
def add_rule_in_section(rule, section_id):

View File

@ -24,7 +24,7 @@ from vmware_nsx.db import nsx_models
from vmware_nsx.nsxlib.v3 import dfw_api as firewall
NSGROUP_CONTAINER = 'NSGroup Container'
NO_SECGROUP_CONTAINER = 'No SecGroup port container'
DEFAULT_SECTION = 'OS default section for security-groups'
@ -182,7 +182,8 @@ def _get_remote_nsg_mapping(context, sg_rule, nsgroup_id):
return remote_nsgroup_id
def update_lport_with_security_groups(context, lport_id, original, updated):
def update_lport_with_security_groups(context, no_secgroup_id,
lport_id, original, updated):
added = set(updated) - set(original)
removed = set(original) - set(updated)
for sg_id in added:
@ -191,50 +192,65 @@ def update_lport_with_security_groups(context, lport_id, original, updated):
nsgroup_id, firewall.LOGICAL_PORT, lport_id)
for sg_id in removed:
nsgroup_id, _ = get_sg_mappings(context.session, sg_id)
firewall.remove_nsgroup_member(
nsgroup_id, lport_id)
firewall.remove_nsgroup_member(nsgroup_id, lport_id)
if list(original) == [] and added:
firewall.remove_nsgroup_member(no_secgroup_id, lport_id)
elif list(updated) == [] and removed:
firewall.add_nsgroup_member(
no_secgroup_id, firewall.LOGICAL_PORT, lport_id)
def init_nsgroup_container_and_default_section_rules():
def update_lport_with_security_groups_on_create(context, no_secgroup_id,
lport_id, updated):
for sg_id in updated:
nsgroup_id, _ = get_sg_mappings(context.session, sg_id)
firewall.add_nsgroup_member(
nsgroup_id, firewall.LOGICAL_PORT, lport_id)
if not updated:
firewall.add_nsgroup_member(
no_secgroup_id, firewall.LOGICAL_PORT, lport_id)
def init_no_secgroup_container_and_default_section_rules():
# REVISIT(roeyc): Should handle Neutron active-active
# deployment scenario.
nsgroup_description = ('This NSGroup is necessary for OpenStack '
'integration, do not delete.')
section_description = ("This section is handled by OpenStack to contain "
"default rules on security-groups.")
nsgroup_id = _init_nsgroup_container(NSGROUP_CONTAINER,
nsgroup_description)
section_id = _init_default_section(
DEFAULT_SECTION, section_description, nsgroup_id)
nsgroup_id = _init_no_secgroup_container()
section_id = _init_default_section(nsgroup_id)
return nsgroup_id, section_id
def _init_nsgroup_container(name, description):
def _init_no_secgroup_container():
description = ("This NSGroup is necessary for OpenStack integration, do "
"not delete.")
nsgroups = firewall.list_nsgroups()
for nsg in nsgroups:
if nsg['display_name'] == name:
if nsg['display_name'] == NO_SECGROUP_CONTAINER:
# NSGroup container exists.
break
else:
# Need to create the nsgroup container and the OS default
# security-groups section.
nsg = firewall.create_nsgroup(name, description, [])
nsg = firewall.create_nsgroup(NO_SECGROUP_CONTAINER, description, [])
return nsg['id']
def _init_default_section(name, description, nsgroup_id):
def _init_default_section(no_secgroup_id):
description = ("This section is handled by OpenStack to contain default "
"rules on security-groups.")
fw_sections = firewall.list_sections()
for section in fw_sections:
if section.get('display_name') == name:
if section.get('display_name') == DEFAULT_SECTION:
break
else:
section = firewall.create_empty_section(
name, description, [nsgroup_id], [])
# TODO(roeyc): Add aditional rules to allow IPV6 NDP.
DEFAULT_SECTION, description, [], [])
allow_all = firewall.get_firewall_rule_dict(
'Allow if no secgroup', action=firewall.ALLOW,
applied_tos=[no_secgroup_id])
block_rule = firewall.get_firewall_rule_dict(
'Block All', action=firewall.DROP)
# TODO(roeyc): Add aditional rules to allow IPV6 NDP.
dhcp_client = firewall.get_nsservice(firewall.L4_PORT_SET_NSSERVICE,
l4_protocol=firewall.UDP,
source_ports=[67],
@ -250,7 +266,8 @@ def _init_default_section(name, description, nsgroup_id):
dhcp_client_rule_out = firewall.get_firewall_rule_dict(
'DHCP-Client-OUT', direction=firewall.OUT, service=dhcp_server)
firewall.add_rules_in_section([dhcp_client_rule_out,
firewall.add_rules_in_section([allow_all,
dhcp_client_rule_out,
dhcp_client_rule_in,
block_rule],
section['id'])

View File

@ -120,8 +120,8 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
self._start_rpc_notifiers()
self._nsx_client = nsx_client.NSX3Client()
self._port_client = nsx_resources.LogicalPort(self._nsx_client)
self.nsgroup_container, self.default_section = (
security.init_nsgroup_container_and_default_section_rules())
self.no_secgroup, self.default_section = (
security.init_no_secgroup_container_and_default_section_rules())
self._router_client = nsx_resources.LogicalRouter(self._nsx_client)
self._router_port_client = nsx_resources.LogicalRouterPort(
self._nsx_client)
@ -658,7 +658,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
context, port_data, sgids)
if sgids:
security.update_lport_with_security_groups(
context, lport['id'], [], sgids)
context, self.no_secgroup, lport['id'], [], sgids)
return port_data
def _pre_delete_port_check(self, context, port_id, l2gw_port_check):
@ -800,10 +800,11 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
address_bindings=address_bindings,
switch_profile_ids=switch_profile_ids)
security.update_lport_with_security_groups(
context, nsx_lport_id,
original_port.get(ext_sg.SECURITYGROUPS, []),
updated_port.get(ext_sg.SECURITYGROUPS, []))
if sec_grp_updated:
security.update_lport_with_security_groups(
context, self.no_secgroup, nsx_lport_id,
original_port.get(ext_sg.SECURITYGROUPS, []),
updated_port.get(ext_sg.SECURITYGROUPS, []))
except nsx_exc.ManagerError:
# In case if there is a failure on NSX-v3 backend, rollback the
# previous update operation on neutron side.
@ -1345,7 +1346,6 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
tags = utils.build_v3_tags_payload(secgroup)
name = security.get_nsgroup_name(secgroup)
ns_group = None
firewall_section = None
try:
# NOTE(roeyc): We first create the nsgroup so that once the sg is
@ -1392,8 +1392,6 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
context, firewall_section['id'], ns_group['id'], sg_rules)
security.save_sg_rule_mappings(context.session, rules['rules'])
firewall.add_nsgroup_member(self.nsgroup_container,
firewall.NSGROUP, ns_group['id'])
except nsx_exc.ManagerError:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Failed to create backend firewall rules "