Exclusive Router Support

Exclusive router is the router who exclusivly occupies one edge.
You can create an exclusive router with "--router_type exclusive"
For distributed router, it would always be exclusive router.

Change-Id: Ice8cbc20912bc9becc5a82a646c76b9153418189
DocImapct:
This commit is contained in:
linb 2014-11-03 10:22:46 +08:00
parent d9bc7df7c6
commit 2eb68aa2c3
15 changed files with 710 additions and 264 deletions

View File

@ -196,7 +196,7 @@ function run_pep8_changed {
}
TESTRTESTS="python -m neutron.openstack.common.lockutils python setup.py testr"
TESTRTESTS="python setup.py testr"
if [ $never_venv -eq 0 ]
then

View File

@ -23,7 +23,11 @@ packages =
vmware_nsx
namespace_packages =
vmware_nsx
[entry_points]
vmware_nsx.neutron.nsxv.router_type_drivers =
shared = vmware_nsx.neutron.plugins.vmware.plugins.nsx_v_drivers.shared_router_driver:RouterSharedDriver
distributed = vmware_nsx.neutron.plugins.vmware.plugins.nsx_v_drivers.distributed_router_driver:RouterDistributedDriver
exclusive = vmware_nsx.neutron.plugins.vmware.plugins.nsx_v_drivers.exclusive_router_driver:RouterExclusiveDriver
[build_sphinx]
source-dir = doc/source
build-dir = doc/build

View File

@ -239,7 +239,11 @@ nsxv_opts = [
cfg.BoolOpt('spoofguard_enabled',
default=True,
help=_("If True then plugin will use NSXV spoofguard "
"component for port-security feature."))
"component for port-security feature.")),
cfg.ListOpt('tenant_router_types',
default=['shared', 'distributed', 'exclusive'],
help=_("Ordered list of router_types to allocate as tenant "
"routers."))
]
# Register the configuration options

View File

@ -105,3 +105,12 @@ class LsnMigrationConflict(n_exc.Conflict):
class LsnConfigurationConflict(NsxPluginException):
message = _("Configuration conflict on Logical Service Node %(lsn_id)s")
class DvsNotFound(n_exc.NotFound):
message = _('Unable to find DVS %(dvs)s')
class NoRouterAvailable(n_exc.ResourceExhausted):
message = _("Unable to create the router. "
"No tenant router is available for allocation.")

View File

@ -0,0 +1,30 @@
# Copyright 2014 VMware, Inc. All rights reserved.
#
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutron.plugins.vmware.extensions import routertype as rt_rtr
from vmware_nsx.neutron.plugins.vmware.dbexts import (
distributedrouter as dist_rtr)
class RouterType_mixin(dist_rtr.DistributedRouter_mixin):
"""Mixin class to enable Router type support."""
nsx_attributes = (
dist_rtr.DistributedRouter_mixin.nsx_attributes + [{
'name': rt_rtr.ROUTER_TYPE,
'default': False
}])

View File

@ -0,0 +1,92 @@
# Copyright 2014 VMware, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo.config import cfg
import stevedore
from neutron.openstack.common import log
from neutron.plugins.vmware.common import exceptions as nsx_exc
LOG = log.getLogger(__name__)
ROUTER_TYPE_DRIVERS = ["distributed", "exclusive", "shared"]
class RouterTypeManager(stevedore.named.NamedExtensionManager):
"""Manage router segment types using drivers."""
def __init__(self, plugin):
# Mapping from type name to DriverManager
self.drivers = {}
LOG.info(_("Configured router type driver names: %s"),
ROUTER_TYPE_DRIVERS)
super(RouterTypeManager, self).__init__(
'vmware_nsx.neutron.nsxv.router_type_drivers',
ROUTER_TYPE_DRIVERS,
invoke_on_load=True,
invoke_args=(plugin,))
LOG.info(_("Loaded type driver names: %s"), self.names())
self._register_types()
self._check_tenant_router_types(cfg.CONF.nsxv.tenant_router_types)
def _register_types(self):
for ext in self:
router_type = ext.obj.get_type()
if router_type in self.drivers:
LOG.error(_("Type driver '%(new_driver)s' ignored because "
"type driver '%(old_driver)s' is already "
"registered for type '%(type)s'"),
{'new_driver': ext.name,
'old_driver': self.drivers[router_type].name,
'type': router_type})
else:
self.drivers[router_type] = ext
LOG.info(_("Registered types: %s"), self.drivers.keys())
def _check_tenant_router_types(self, types):
self.tenant_router_types = []
for router_type in types:
if router_type in self.drivers:
self.tenant_router_types.append(router_type)
else:
msg = _("No type driver for tenant router_type: %s. "
"Service terminated!") % router_type
LOG.error(msg)
raise SystemExit(msg)
LOG.info(_("Tenant router_types: %s"), self.tenant_router_types)
def get_tenant_router_driver(self, context, router_type):
driver = self.drivers.get(router_type)
if driver:
return driver.obj
raise nsx_exc.NoRouterAvailable()
def decide_tenant_router_type(self, context, router_type=None):
if router_type is None:
for rt in self.tenant_router_types:
driver = self.drivers.get(rt)
if driver:
return rt
raise nsx_exc.NoRouterAvailable()
elif context.is_admin:
driver = self.drivers.get(router_type)
if driver:
return router_type
elif router_type in self.tenant_router_types:
driver = self.drivers.get(router_type)
if driver:
return router_type
raise nsx_exc.NoRouterAvailable()

View File

@ -58,13 +58,12 @@ from vmware_nsx.neutron.plugins import vmware
from vmware_nsx.neutron.plugins.vmware.common import config # noqa
from vmware_nsx.neutron.plugins.vmware.common import utils as c_utils
from vmware_nsx.neutron.plugins.vmware.dbexts import (
distributedrouter as dist_rtr)
routertype as rt_rtr)
from vmware_nsx.neutron.plugins.vmware.dbexts import db as nsx_db
from vmware_nsx.neutron.plugins.vmware.dbexts import nsxv_db
from vmware_nsx.neutron.plugins.vmware.dbexts import vnic_index_db
from vmware_nsx.neutron.plugins.vmware.plugins import managers
from vmware_nsx.neutron.plugins.vmware.plugins import nsx_v_md_proxy
from vmware_nsx.neutron.plugins.vmware.vshield.common import (
constants as vcns_const)
from vmware_nsx.neutron.plugins.vmware.vshield.common import (
exceptions as vsh_exc)
from vmware_nsx.neutron.plugins.vmware.vshield import edge_utils
@ -77,7 +76,7 @@ PORTGROUP_PREFIX = 'dvportgroup'
class NsxVPluginV2(agents_db.AgentDbMixin,
db_base_plugin_v2.NeutronDbPluginV2,
dist_rtr.DistributedRouter_mixin,
rt_rtr.RouterType_mixin,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
@ -98,6 +97,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
"extraroute",
"router",
"security-group",
"nsxv-router-type",
"vnic-index",
"advanced-service-providers"]
@ -130,6 +130,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
self.sg_container_id = self._create_security_group_container()
self._validate_config()
self._create_cluster_default_fw_rules()
self._router_managers = managers.RouterTypeManager(self)
has_metadata_cfg = (
cfg.CONF.nsxv.nova_metadata_ips
@ -151,6 +152,37 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
h, container_id = self.nsx_v.vcns.create_security_group(container)
return container_id
def _find_router_driver(self, context, router_id):
router_db = self._get_router(context, router_id)
return self._get_router_driver(context, router_db)
def _get_router_driver(self, context, router_db):
router_type_dict = {}
self._extend_nsx_router_dict(router_type_dict, router_db)
router_type = None
if router_type_dict.get("distributed", False):
router_type = "distributed"
else:
router_type = router_type_dict.get("router_type")
return self._router_managers.get_tenant_router_driver(
context, router_type)
def _decide_router_type(self, context, r):
router_type = None
if attr.is_attr_set(r.get("distributed")) and r.get("distributed"):
router_type = "distributed"
elif attr.is_attr_set(r.get("router_type")):
router_type = r.get("router_type")
router_type = self._router_managers.decide_tenant_router_type(
context, router_type)
if router_type == "distributed":
r["distributed"] = True
r["router_type"] = "exclusive"
else:
r["distributed"] = False
r["router_type"] = router_type
def _create_cluster_default_fw_rules(self):
# default cluster rules
rules = [{'name': 'Default DHCP rule for OS Security Groups',
@ -1160,34 +1192,25 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
gw_info = self._extract_external_gw(context, router)
lrouter = super(NsxVPluginV2, self).create_router(context, router)
r = router['router']
distributed = r.get('distributed')
r['distributed'] = attr.is_attr_set(distributed) and distributed
self.edge_manager.create_lrouter(context, lrouter,
dist=r['distributed'])
self._decide_router_type(context, r)
with context.session.begin(subtransactions=True):
router_db = self._get_router(context, lrouter['id'])
self._process_nsx_router_create(context, router_db, r)
router_driver = self._get_router_driver(context, router_db)
router_driver.create_router(
context, lrouter,
allow_metadata=(allow_metadata and self.metadata_proxy_handler))
if gw_info is not None:
self._update_router_gw_info(context, lrouter['id'], gw_info)
if (not r['distributed']
and allow_metadata
and self.metadata_proxy_handler):
self.metadata_proxy_handler.configure_router_edge(lrouter['id'])
router_driver._update_router_gw_info(
context, lrouter['id'], gw_info)
return self.get_router(context, lrouter['id'])
def update_router(self, context, router_id, router):
# TODO(berlin): admin_state_up update
if router['router'].get('admin_state_up') is False:
LOG.warning(_LW("admin_state_up=False router is not supported."))
gw_info = self._extract_external_gw(context, router, is_extract=False)
router_updated = super(NsxVPluginV2, self).update_router(
context, router_id, router)
# here is used to handle routes which tenant updates.
if gw_info is None:
router_db = self._get_router(context, router_id)
nexthop = self._get_external_attachment_info(context, router_db)[2]
self._update_routes(context, router_id, nexthop)
return router_updated
router_driver = self._find_router_driver(context, router_id)
return router_driver.update_router(context, router_id, router)
def _check_router_in_use(self, context, router_id):
with context.session.begin(subtransactions=True):
@ -1207,10 +1230,8 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
def delete_router(self, context, id):
self._check_router_in_use(context, id)
distributed = self.get_router(context, id).get('distributed', False)
if self.metadata_proxy_handler and not distributed:
self.metadata_proxy_handler.cleanup_router_edge(id)
self.edge_manager.delete_lrouter(context, id, dist=distributed)
router_driver = self._find_router_driver(context, id)
router_driver.delete_router(context, id)
super(NsxVPluginV2, self).delete_router(context, id)
def _get_external_attachment_info(self, context, router):
@ -1258,101 +1279,9 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
edge_utils.update_routes(self.nsx_v, context, router_id,
routes, nexthop)
def _update_routes_on_plr(self, context, router_id, plr_id, newnexthop):
subnets = self._find_router_subnets_cidrs(
context.elevated(), router_id)
routes = []
for subnet in subnets:
routes.append({
'destination': subnet,
'nexthop': (vcns_const.INTEGRATION_LR_IPADDRESS.
split('/')[0])
})
edge_utils.update_routes_on_plr(self.nsx_v, context,
plr_id, router_id, routes,
nexthop=newnexthop)
def _update_router_gw_info(self, context, router_id, info):
router = self._get_router(context, router_id)
org_ext_net_id = router.gw_port_id and router.gw_port.network_id
org_enable_snat = router.enable_snat
orgaddr, orgmask, orgnexthop = self._get_external_attachment_info(
context, router)
super(NsxVPluginV2, self)._update_router_gw_info(
context, router_id, info, router=router)
new_ext_net_id = router.gw_port_id and router.gw_port.network_id
new_enable_snat = router.enable_snat
newaddr, newmask, newnexthop = self._get_external_attachment_info(
context, router)
router_dict = self._make_router_dict(router)
if not router_dict.get('distributed', False):
if new_ext_net_id != org_ext_net_id and orgnexthop:
# network changed, so need to remove default gateway before
# vnic can be configured
LOG.debug("Delete default gateway %s", orgnexthop)
edge_utils.clear_gateway(self.nsx_v, context, router_id)
# Delete SNAT rules
if org_enable_snat:
edge_utils.clear_nat_rules(self.nsx_v, context, router_id)
# Update external vnic if addr or mask is changed
if orgaddr != newaddr or orgmask != newmask:
edge_utils.update_external_interface(
self.nsx_v, context, router_id,
new_ext_net_id, newaddr, newmask)
# Update SNAT rules if ext net changed and snat enabled
# or ext net not changed but snat is changed.
if ((new_ext_net_id != org_ext_net_id and
newnexthop and new_enable_snat) or
(new_ext_net_id == org_ext_net_id and
new_enable_snat != org_enable_snat)):
self._update_nat_rules(context, router)
# Update static routes in all.
self._update_routes(context, router_id, newnexthop)
else:
plr_id = self.edge_manager.get_plr_by_tlr_id(context, router_id)
if not new_ext_net_id:
if plr_id:
# delete all plr relative conf
self.edge_manager.delete_plr_by_tlr_id(
context, plr_id, router_id)
else:
# Connecting one plr to the tlr if new_ext_net_id is not None.
if not plr_id:
plr_id = self.edge_manager.create_plr_with_tlr_id(
context, router_id, router_dict.get('name'))
if new_ext_net_id != org_ext_net_id and orgnexthop:
# network changed, so need to remove default gateway and
# all static routes before vnic can be configured
edge_utils.clear_gateway(self.nsx_v, context, plr_id)
# Delete SNAT rules
if org_enable_snat:
edge_utils.clear_nat_rules(self.nsx_v, context, plr_id)
# Update external vnic if addr or mask is changed
if orgaddr != newaddr or orgmask != newmask:
edge_utils.update_external_interface(
self.nsx_v, context, plr_id,
new_ext_net_id, newaddr, newmask)
# Update SNAT rules if ext net changed and snat enabled
# or ext net not changed but snat is changed.
if ((new_ext_net_id != org_ext_net_id and
newnexthop and new_enable_snat) or
(new_ext_net_id == org_ext_net_id and
new_enable_snat != org_enable_snat)):
self._update_nat_rules(context, router, plr_id)
# Open firewall flows on plr
self._update_subnets_and_dnat_firewall(
context, router, router_id=plr_id)
# Update static routes of plr
self._update_routes_on_plr(
context, router_id, plr_id, newnexthop)
router_driver = self._find_router_driver(context, router_id)
router_driver._update_router_gw_info(context, router_id, info)
def _get_router_interface_ports_by_network(
self, context, router_id, network_id):
@ -1429,96 +1358,14 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
self.nsx_v, context, router_id, snat, dnat)
def add_router_interface(self, context, router_id, interface_info):
info = super(NsxVPluginV2, self).add_router_interface(
router_driver = self._find_router_driver(context, router_id)
return router_driver.add_router_interface(
context, router_id, interface_info)
router_db = self._get_router(context, router_id)
router = self._make_router_dict(router_db)
distributed = router.get('distributed', False)
subnet = self.get_subnet(context, info['subnet_id'])
network_id = subnet['network_id']
address_groups = self._get_address_groups(
context, router_id, network_id)
if not distributed:
edge_utils.update_internal_interface(
self.nsx_v, context, router_id, network_id, address_groups)
else:
try:
edge_utils.add_vdr_internal_interface(
self.nsx_v, context, router_id, network_id, address_groups)
except n_exc.BadRequest:
with excutils.save_and_reraise_exception():
super(NsxVPluginV2, self).remove_router_interface(
context, router_id, interface_info)
# Update edge's firewall rules to accept subnets flows.
self._update_subnets_and_dnat_firewall(context, router_db)
if router_db.gw_port and router_db.enable_snat:
if not distributed:
# Update Nat rules on external edge vnic
self._update_nat_rules(context, router_db)
else:
plr_id = self.edge_manager.get_plr_by_tlr_id(
context, router_id)
self._update_nat_rules(context, router_db, plr_id)
# Open firewall flows on plr
self._update_subnets_and_dnat_firewall(
context, router_db, router_id=plr_id)
# Update static routes of plr
nexthop = self._get_external_attachment_info(
context, router_db)[2]
self._update_routes_on_plr(
context, router_id, plr_id, nexthop)
return info
def remove_router_interface(self, context, router_id, interface_info):
info = super(NsxVPluginV2, self).remove_router_interface(
router_driver = self._find_router_driver(context, router_id)
return router_driver.remove_router_interface(
context, router_id, interface_info)
router_db = self._get_router(context, router_id)
router = self._make_router_dict(router_db)
distributed = router.get('distributed', False)
subnet = self.get_subnet(context, info['subnet_id'])
network_id = subnet['network_id']
if router_db.gw_port and router_db.enable_snat:
if not distributed:
# First update nat rules
self._update_nat_rules(context, router_db)
else:
plr_id = self.edge_manager.get_plr_by_tlr_id(
context, router_id)
self._update_nat_rules(context, router_db, plr_id)
# Open firewall flows on plr
self._update_subnets_and_dnat_firewall(
context, router_db, router_id=plr_id)
# Update static routes of plr
nexthop = self._get_external_attachment_info(
context, router_db)[2]
nexthop = self._get_external_attachment_info(
context, router_db)[2]
self._update_routes_on_plr(
context, router_id, plr_id, nexthop)
ports = self._get_router_interface_ports_by_network(
context, router_id, network_id)
self._update_subnets_and_dnat_firewall(context, router_db)
# No subnet on the network connects to the edge vnic
if not ports:
edge_utils.delete_interface(self.nsx_v, context,
router_id, network_id,
dist=distributed)
else:
address_groups = self._get_address_groups(
context, router_id, network_id)
if not distributed:
edge_utils.update_internal_interface(self.nsx_v, context,
router_id, network_id,
address_groups)
else:
edge_utils.update_vdr_internal_interface(
self.nsx_v, context, router_id, network_id, address_groups)
return info
def _get_floatingips_by_router(self, context, router_id):
fip_qry = context.session.query(l3_db.FloatingIP)
@ -1546,6 +1393,10 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
floatingip_db['status'] = status
self.update_floatingip_status(context, floatingip_db['id'], status)
def _update_edge_router(self, context, router_id):
router_driver = self._find_router_driver(context, router_id)
router_driver._update_edge_router(context, router_id)
def create_floatingip(self, context, floatingip):
fip_db = super(NsxVPluginV2, self).create_floatingip(
context, floatingip)
@ -1583,19 +1434,6 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
self._set_floatingip_status(context, fip_db)
return fip_db
def _update_edge_router(self, context, router_id):
router = self._get_router(context, router_id)
distributed = self._make_router_dict(router).get(
'distributed', False)
if distributed:
plr_id = self.edge_manager.get_plr_by_tlr_id(context, router_id)
else:
plr_id = None
self._update_external_interface(context, router, router_id=plr_id)
self._update_nat_rules(context, router, router_id=plr_id)
self._update_subnets_and_dnat_firewall(context, router,
router_id=plr_id)
def delete_floatingip(self, context, id):
fip_db = self._get_floatingip(context, id)
router_id = None
@ -1603,21 +1441,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
router_id = fip_db.router_id
super(NsxVPluginV2, self).delete_floatingip(context, id)
if router_id:
router = self._get_router(context, router_id)
distributed = self._make_router_dict(router).get(
'distributed', False)
if not distributed:
self._update_subnets_and_dnat_firewall(context, router)
self._update_nat_rules(context, router)
self._update_external_interface(context, router)
else:
plr_id = self.edge_manager.get_plr_by_tlr_id(context,
router_id)
self._update_subnets_and_dnat_firewall(
context, router, router_id=plr_id)
self._update_nat_rules(context, router, router_id=plr_id)
self._update_external_interface(
context, router, router_id=plr_id)
self._update_edge_router(context, router_id)
def disassociate_floatingips(self, context, port_id):
router_id = None
@ -1632,21 +1456,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
router_id = None
super(NsxVPluginV2, self).disassociate_floatingips(context, port_id)
if router_id:
router = self._get_router(context, router_id)
distributed = self._make_router_dict(router).get(
'distributed', False)
if not distributed:
self._update_subnets_and_dnat_firewall(context, router)
self._update_nat_rules(context, router)
self._update_external_interface(context, router)
else:
plr_id = self.edge_manager.get_plr_by_tlr_id(context,
router_id)
self._update_subnets_and_dnat_firewall(
context, router, router_id=plr_id)
self._update_nat_rules(context, router, router_id=plr_id)
self._update_external_interface(
context, router, router_id=plr_id)
self._update_edge_router(context, router_id)
def _update_subnets_and_dnat_firewall(self, context, router,
router_id=None, allow_external=True):
@ -1659,8 +1469,8 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
fake_subnet_fw_rule = {
'action': 'allow',
'enabled': True,
'source_ip_address': subnet_cidrs,
'destination_ip_address': subnet_cidrs}
'source_ip_address': sorted(subnet_cidrs),
'destination_ip_address': sorted(subnet_cidrs)}
fake_fw_rules.append(fake_subnet_fw_rule)
_, dnat_rules = self._get_nat_rules(context, router)
@ -1674,7 +1484,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
fake_dnat_fw_rule = {
'action': 'allow',
'enabled': True,
'destination_ip_address': dnat_cidrs}
'destination_ip_address': sorted(dnat_cidrs)}
fake_fw_rules.append(fake_dnat_fw_rule)
# TODO(berlin): Add fw rules if fw service is supported
fake_fw = {'firewall_rule_list': fake_fw_rules}

View File

@ -0,0 +1,66 @@
# Copyright 2014 VMware, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class RouterAbstractDriver(object):
"""Abstract router driver that expose API for nsxv plugin."""
@abc.abstractmethod
def get_type(self):
pass
@abc.abstractmethod
def create_router(self, context, lrouter):
pass
@abc.abstractmethod
def update_router(self, context, router_id, router):
pass
@abc.abstractmethod
def delete_router(self, context, router_id):
pass
@abc.abstractmethod
def update_routes(self, context, router_id, nexthop):
pass
@abc.abstractmethod
def _update_router_gw_info(self, context, router_id, info):
pass
@abc.abstractmethod
def add_router_interface(self, context, router_id, interface_info):
pass
@abc.abstractmethod
def remove_router_interface(self, context, router_id, interface_info):
pass
@abc.abstractmethod
def _update_edge_router(self, context, router_id):
pass
class RouterBaseDriver(RouterAbstractDriver):
def __init__(self, plugin):
self.plugin = plugin
self.nsx_v = plugin.nsx_v
self.edge_manager = plugin.edge_manager

View File

@ -0,0 +1,194 @@
# Copyright 2014 VMware, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo.utils import excutils
from neutron.common import exceptions as n_exc
from vmware_nsx.neutron.plugins.vmware.plugins import nsx_v
from vmware_nsx.neutron.plugins.vmware.plugins.nsx_v_drivers import (
abstract_router_driver as router_driver)
from vmware_nsx.neutron.plugins.vmware.vshield.common import (
constants as vcns_const)
from vmware_nsx.neutron.plugins.vmware.vshield import edge_utils
class RouterDistributedDriver(router_driver.RouterBaseDriver):
def get_type(self):
return "distributed"
def _update_routes_on_plr(self, context, router_id, plr_id, newnexthop):
subnets = self.plugin._find_router_subnets_cidrs(
context.elevated(), router_id)
routes = []
for subnet in subnets:
routes.append({
'destination': subnet,
'nexthop': (vcns_const.INTEGRATION_LR_IPADDRESS.
split('/')[0])
})
edge_utils.update_routes_on_plr(self.nsx_v, context,
plr_id, router_id, routes,
nexthop=newnexthop)
def create_router(self, context, lrouter, allow_metadata=True):
self.edge_manager.create_lrouter(context, lrouter, dist=True)
# TODO(kobi) can't configure metadata service on VDR at present.
def update_router(self, context, router_id, router):
return super(nsx_v.NsxVPluginV2, self.plugin).update_router(
context, router_id, router)
def delete_router(self, context, router_id):
self.edge_manager.delete_lrouter(context, router_id, dist=True)
def update_routes(self, context, router_id, nexthop):
# Since there may be an internal plr connected to the VDR affecting
# static routes, static routes feature should be avoided on VDR now.
pass
def _update_router_gw_info(self, context, router_id, info):
router = self.plugin._get_router(context, router_id)
org_ext_net_id = router.gw_port_id and router.gw_port.network_id
org_enable_snat = router.enable_snat
orgaddr, orgmask, orgnexthop = (
self.plugin._get_external_attachment_info(
context, router))
super(nsx_v.NsxVPluginV2, self.plugin)._update_router_gw_info(
context, router_id, info, router=router)
new_ext_net_id = router.gw_port_id and router.gw_port.network_id
new_enable_snat = router.enable_snat
newaddr, newmask, newnexthop = (
self.plugin._get_external_attachment_info(
context, router))
plr_id = self.edge_manager.get_plr_by_tlr_id(context, router_id)
if not new_ext_net_id:
if plr_id:
# delete all plr relative conf
self.edge_manager.delete_plr_by_tlr_id(
context, plr_id, router_id)
else:
# Connecting plr to the tlr if new_ext_net_id is not None.
if not plr_id:
plr_id = self.edge_manager.create_plr_with_tlr_id(
context, router_id, router.get('name'))
if new_ext_net_id != org_ext_net_id and orgnexthop:
# network changed, so need to remove default gateway
# and all static routes before vnic can be configured
edge_utils.clear_gateway(self.nsx_v, context, plr_id)
# Delete SNAT rules
if org_enable_snat:
edge_utils.clear_nat_rules(self.nsx_v, context,
plr_id)
# Update external vnic if addr or mask is changed
if orgaddr != newaddr or orgmask != newmask:
edge_utils.update_external_interface(
self.nsx_v, context, plr_id,
new_ext_net_id, newaddr, newmask)
# Update SNAT rules if ext net changed and snat enabled
# or ext net not changed but snat is changed.
if ((new_ext_net_id != org_ext_net_id and
newnexthop and new_enable_snat) or
(new_ext_net_id == org_ext_net_id and
new_enable_snat != org_enable_snat)):
self.plugin._update_nat_rules(context, router, plr_id)
# Open firewall flows on plr
self.plugin._update_subnets_and_dnat_firewall(
context, router, router_id=plr_id)
# Update static routes of plr
self._update_routes_on_plr(
context, router_id, plr_id, newnexthop)
def add_router_interface(self, context, router_id, interface_info):
info = super(nsx_v.NsxVPluginV2, self.plugin).add_router_interface(
context, router_id, interface_info)
router_db = self.plugin._get_router(context, router_id)
subnet = self.plugin.get_subnet(context, info['subnet_id'])
network_id = subnet['network_id']
address_groups = self.plugin._get_address_groups(
context, router_id, network_id)
try:
edge_utils.add_vdr_internal_interface(
self.nsx_v, context, router_id,
network_id, address_groups)
except n_exc.BadRequest:
with excutils.save_and_reraise_exception():
super(nsx_v.NsxVPluginV2, self.plugin).remove_router_interface(
context, router_id, interface_info)
# Update edge's firewall rules to accept subnets flows.
self.plugin._update_subnets_and_dnat_firewall(context, router_db)
if router_db.gw_port and router_db.enable_snat:
plr_id = self.edge_manager.get_plr_by_tlr_id(context, router_id)
self.plugin._update_nat_rules(context, router_db, plr_id)
# Open firewall flows on plr
self.plugin._update_subnets_and_dnat_firewall(
context, router_db, router_id=plr_id)
# Update static routes of plr
nexthop = self.plugin._get_external_attachment_info(
context, router_db)[2]
self._update_routes_on_plr(
context, router_id, plr_id, nexthop)
return info
def remove_router_interface(self, context, router_id, interface_info):
info = super(nsx_v.NsxVPluginV2, self.plugin).remove_router_interface(
context, router_id, interface_info)
router_db = self.plugin._get_router(context, router_id)
subnet = self.plugin.get_subnet(context, info['subnet_id'])
network_id = subnet['network_id']
if router_db.gw_port and router_db.enable_snat:
plr_id = self.edge_manager.get_plr_by_tlr_id(
context, router_id)
self.plugin._update_nat_rules(context, router_db, plr_id)
# Open firewall flows on plr
self.plugin._update_subnets_and_dnat_firewall(
context, router_db, router_id=plr_id)
# Update static routes of plr
nexthop = self.plugin._get_external_attachment_info(
context, router_db)[2]
self._update_routes_on_plr(
context, router_id, plr_id, nexthop)
ports = self.plugin._get_router_interface_ports_by_network(
context, router_id, network_id)
self.plugin._update_subnets_and_dnat_firewall(context, router_db)
# No subnet on the network connects to the edge vnic
if not ports:
edge_utils.delete_interface(self.nsx_v, context,
router_id, network_id,
dist=True)
else:
address_groups = self.plugin._get_address_groups(
context, router_id, network_id)
edge_utils.update_vdr_internal_interface(
self.nsx_v, context, router_id,
network_id, address_groups)
return info
def _update_edge_router(self, context, router_id):
router = self.plugin._get_router(context, router_id)
plr_id = self.edge_manager.get_plr_by_tlr_id(context, router_id)
self.plugin._update_external_interface(
context, router, router_id=plr_id)
self.plugin._update_nat_rules(context, router, router_id=plr_id)
self.plugin._update_subnets_and_dnat_firewall(context, router,
router_id=plr_id)

View File

@ -0,0 +1,148 @@
# Copyright 2014 VMware, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.openstack.common import log as logging
from vmware_nsx.neutron.plugins.vmware.plugins import nsx_v
from vmware_nsx.neutron.plugins.vmware.plugins.nsx_v_drivers import (
abstract_router_driver as router_driver)
from vmware_nsx.neutron.plugins.vmware.vshield import edge_utils
LOG = logging.getLogger(__name__)
class RouterExclusiveDriver(router_driver.RouterBaseDriver):
def get_type(self):
return "exclusive"
def create_router(self, context, lrouter, allow_metadata=True):
self.edge_manager.create_lrouter(context, lrouter, dist=False)
if allow_metadata:
self.plugin.metadata_proxy_handler.configure_router_edge(
lrouter['id'])
def update_router(self, context, router_id, router):
gw_info = self.plugin._extract_external_gw(context, router,
is_extract=False)
router_updated = super(nsx_v.NsxVPluginV2, self.plugin).update_router(
context, router_id, router)
# here is used to handle routes which tenant updates.
if gw_info is None:
router_db = self.plugin._get_router(context, router_id)
nexthop = self.plugin._get_external_attachment_info(
context, router_db)[2]
self.update_routes(context, router_id, nexthop)
return router_updated
def delete_router(self, context, router_id):
self.edge_manager.delete_lrouter(context, router_id, dist=False)
if self.plugin.metadata_proxy_handler:
self.plugin.metadata_proxy_handler.cleanup_router_edge(router_id)
def update_routes(self, context, router_id, nexthop):
self.plugin._update_routes(context, router_id, nexthop)
def _update_router_gw_info(self, context, router_id, info):
router = self.plugin._get_router(context, router_id)
org_ext_net_id = router.gw_port_id and router.gw_port.network_id
org_enable_snat = router.enable_snat
orgaddr, orgmask, orgnexthop = (
self.plugin._get_external_attachment_info(
context, router))
super(nsx_v.NsxVPluginV2, self.plugin)._update_router_gw_info(
context, router_id, info, router=router)
new_ext_net_id = router.gw_port_id and router.gw_port.network_id
new_enable_snat = router.enable_snat
newaddr, newmask, newnexthop = (
self.plugin._get_external_attachment_info(
context, router))
if new_ext_net_id != org_ext_net_id and orgnexthop:
# network changed, so need to remove default gateway before
# vnic can be configured
LOG.debug("Delete default gateway %s", orgnexthop)
edge_utils.clear_gateway(self.nsx_v, context, router_id)
# Delete SNAT rules
if org_enable_snat:
edge_utils.clear_nat_rules(self.nsx_v, context, router_id)
# Update external vnic if addr or mask is changed
if orgaddr != newaddr or orgmask != newmask:
edge_utils.update_external_interface(
self.nsx_v, context, router_id,
new_ext_net_id, newaddr, newmask)
# Update SNAT rules if ext net changed and snat enabled
# or ext net not changed but snat is changed.
if ((new_ext_net_id != org_ext_net_id and
newnexthop and new_enable_snat) or
(new_ext_net_id == org_ext_net_id and
new_enable_snat != org_enable_snat)):
self.plugin._update_nat_rules(context, router)
# Update static routes in all.
self.plugin._update_routes(context, router_id, newnexthop)
def add_router_interface(self, context, router_id, interface_info):
info = super(nsx_v.NsxVPluginV2, self.plugin).add_router_interface(
context, router_id, interface_info)
router_db = self.plugin._get_router(context, router_id)
subnet = self.plugin.get_subnet(context, info['subnet_id'])
network_id = subnet['network_id']
address_groups = self.plugin._get_address_groups(
context, router_id, network_id)
edge_utils.update_internal_interface(
self.nsx_v, context, router_id, network_id, address_groups)
# Update edge's firewall rules to accept subnets flows.
self.plugin._update_subnets_and_dnat_firewall(context, router_db)
if router_db.gw_port and router_db.enable_snat:
# Update Nat rules on external edge vnic
self.plugin._update_nat_rules(context, router_db)
return info
def remove_router_interface(self, context, router_id, interface_info):
info = super(nsx_v.NsxVPluginV2, self.plugin).remove_router_interface(
context, router_id, interface_info)
router_db = self.plugin._get_router(context, router_id)
subnet = self.plugin.get_subnet(context, info['subnet_id'])
network_id = subnet['network_id']
if router_db.gw_port and router_db.enable_snat:
# First update nat rules
self.plugin._update_nat_rules(context, router_db)
ports = self.plugin._get_router_interface_ports_by_network(
context, router_id, network_id)
self.plugin._update_subnets_and_dnat_firewall(context, router_db)
# No subnet on the network connects to the edge vnic
if not ports:
edge_utils.delete_interface(self.nsx_v, context,
router_id, network_id,
dist=False)
else:
address_groups = self.plugin._get_address_groups(
context, router_id, network_id)
edge_utils.update_internal_interface(self.nsx_v, context,
router_id, network_id,
address_groups)
return info
def _update_edge_router(self, context, router_id):
router = self.plugin._get_router(context, router_id)
self.plugin._update_external_interface(context, router)
self.plugin._update_nat_rules(context, router)
self.plugin._update_subnets_and_dnat_firewall(context, router)

View File

@ -0,0 +1,60 @@
# Copyright 2014 VMware, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from vmware_nsx.neutron.plugins.vmware.plugins import nsx_v
from vmware_nsx.neutron.plugins.vmware.plugins.nsx_v_drivers import (
abstract_router_driver as router_driver)
class RouterSharedDriver(router_driver.RouterBaseDriver):
def get_type(self):
return "shared"
def create_router(self, context, lrouter, allow_metadata=True):
pass
def update_router(self, context, router_id, router):
return super(nsx_v.NsxVPluginV2, self.plugin).update_router(
context, router_id, router)
def delete_router(self, context, router_id):
pass
def update_routes(self, context, router_id, nexthop):
#TODO(berlin) do non-exclusive router op.
pass
def _update_router_gw_info(self, context, router_id, info):
#TODO(berlin) do non-exclusive router op.
router = self.plugin._get_router(context, router_id)
super(nsx_v.NsxVPluginV2, self.plugin)._update_router_gw_info(
context, router_id, info, router=router)
pass
def add_router_interface(self, context, router_id, interface_info):
#TODO(berlin): add router interface.
info = super(nsx_v.NsxVPluginV2, self.plugin).add_router_interface(
context, router_id, interface_info)
return info
def remove_router_interface(self, context, router_id, interface_info):
#TODO(berlin) do non-exclusive router op.
info = super(nsx_v.NsxVPluginV2, self.plugin).remove_router_interface(
context, router_id, interface_info)
return info
def _update_edge_router(self, context, router_id):
#TODO(berlin) do non-exclusive router op.
pass

View File

@ -223,6 +223,7 @@ class NsxVMetadataProxyHandler:
'router': {
'name': 'metadata_proxy_router',
'admin_state_up': True,
'router_type': 'exclusive',
'tenant_id': None}}
rtr = self.nsxv_plugin.create_router(

View File

@ -142,7 +142,8 @@ class EdgeFirewallDriver(db_base_plugin_v2.NeutronDbPluginV2):
vcns_rules.append(
{'action': "accept",
'enabled': True,
'destination': {'vnicGroupId': ["external"]}})
'destination': {'vnicGroupId': ["external"]},
'ruleTag': ruleTag})
return {
'featureType': "firewall_4.0",
'firewallRules': {

View File

@ -37,6 +37,8 @@ from neutron import manager
from neutron.openstack.common import uuidutils
from neutron.plugins.vmware.extensions import (
vnicindex as ext_vnic_idx)
from neutron.plugins.vmware.extensions import routertype as router_type
from neutron.tests.unit import _test_extension_portbindings as test_bindings
import neutron.tests.unit.test_db_plugin as test_plugin
import neutron.tests.unit.test_extension_allowedaddresspairs as test_addr_pair
@ -45,6 +47,7 @@ import neutron.tests.unit.test_extension_portsecurity as test_psec
import neutron.tests.unit.test_extension_security_group as ext_sg
import neutron.tests.unit.test_l3_plugin as test_l3_plugin
from neutron.tests.unit import testlib_api
from vmware_nsx.neutron.plugins.vmware.dbexts import nsxv_db
from vmware_nsx.neutron.plugins.vmware.vshield.common import (
constants as vcns_const)
@ -1033,6 +1036,8 @@ class TestL3ExtensionManager(object):
l3_ext_gw_mode.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
l3.RESOURCE_ATTRIBUTE_MAP[key].update(
dist_router.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
l3.RESOURCE_ATTRIBUTE_MAP[key].update(
router_type.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
# Finally add l3 resources to the global attribute map
attributes.RESOURCE_ATTRIBUTE_MAP.update(
l3.RESOURCE_ATTRIBUTE_MAP)
@ -1074,11 +1079,11 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxVPluginV2TestCase):
ext_mgr = ext_mgr or TestL3ExtensionManager()
super(L3NatTest, self).setUp(
plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins)
plugin_instance = manager.NeutronManager.get_plugin()
self.plugin_instance = manager.NeutronManager.get_plugin()
self._plugin_name = "%s.%s" % (
plugin_instance.__module__,
plugin_instance.__class__.__name__)
self._plugin_class = plugin_instance.__class__
self.plugin_instance.__module__,
self.plugin_instance.__class__.__name__)
self._plugin_class = self.plugin_instance.__class__
def tearDown(self):
plugin = manager.NeutronManager.get_plugin()
@ -1116,9 +1121,31 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxVPluginV2TestCase):
self._delete('routers', router['router']['id'])
class TestL3NatTestCase(L3NatTest,
test_l3_plugin.L3NatDBIntTestCase,
NsxVPluginV2TestCase):
class TestExclusiveRouterTestCase(L3NatTest,
test_l3_plugin.L3NatDBIntTestCase,
NsxVPluginV2TestCase):
def _create_router(self, fmt, tenant_id, name=None,
admin_state_up=None, set_context=False,
arg_list=None, **kwargs):
data = {'router': {'tenant_id': tenant_id}}
if name:
data['router']['name'] = name
if admin_state_up:
data['router']['admin_state_up'] = admin_state_up
for arg in (('admin_state_up', 'tenant_id') + (arg_list or ())):
# Arg must be present and not empty
if arg in kwargs and kwargs[arg]:
data['router'][arg] = kwargs[arg]
data['router']['router_type'] = kwargs.get('router_type', 'exclusive')
router_req = self.new_create_request('routers', data, fmt)
if set_context and tenant_id:
# create a specific auth context for this request
router_req.environ['neutron.context'] = context.Context(
'', tenant_id)
return router_req.get_response(self.ext_api)
def _test_create_l3_ext_network(self, vlan_id=0):
name = 'l3_ext_net'
@ -1247,7 +1274,7 @@ class TestL3NatTestCase(L3NatTest,
self._test_floatingip_with_invalid_create_port(self._plugin_name)
def test_floatingip_update(self):
super(TestL3NatTestCase, self).test_floatingip_update(
super(TestExclusiveRouterTestCase, self).test_floatingip_update(
constants.FLOATINGIP_STATUS_DOWN)
def test_floatingip_disassociate(self):