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:
parent
d9bc7df7c6
commit
2eb68aa2c3
@ -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 ]
|
if [ $never_venv -eq 0 ]
|
||||||
then
|
then
|
||||||
|
@ -23,7 +23,11 @@ packages =
|
|||||||
vmware_nsx
|
vmware_nsx
|
||||||
namespace_packages =
|
namespace_packages =
|
||||||
vmware_nsx
|
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]
|
[build_sphinx]
|
||||||
source-dir = doc/source
|
source-dir = doc/source
|
||||||
build-dir = doc/build
|
build-dir = doc/build
|
||||||
|
@ -239,7 +239,11 @@ nsxv_opts = [
|
|||||||
cfg.BoolOpt('spoofguard_enabled',
|
cfg.BoolOpt('spoofguard_enabled',
|
||||||
default=True,
|
default=True,
|
||||||
help=_("If True then plugin will use NSXV spoofguard "
|
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
|
# Register the configuration options
|
||||||
|
@ -105,3 +105,12 @@ class LsnMigrationConflict(n_exc.Conflict):
|
|||||||
|
|
||||||
class LsnConfigurationConflict(NsxPluginException):
|
class LsnConfigurationConflict(NsxPluginException):
|
||||||
message = _("Configuration conflict on Logical Service Node %(lsn_id)s")
|
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.")
|
||||||
|
30
vmware_nsx/neutron/plugins/vmware/dbexts/routertype.py
Normal file
30
vmware_nsx/neutron/plugins/vmware/dbexts/routertype.py
Normal 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
|
||||||
|
}])
|
92
vmware_nsx/neutron/plugins/vmware/plugins/managers.py
Normal file
92
vmware_nsx/neutron/plugins/vmware/plugins/managers.py
Normal 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()
|
@ -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 config # noqa
|
||||||
from vmware_nsx.neutron.plugins.vmware.common import utils as c_utils
|
from vmware_nsx.neutron.plugins.vmware.common import utils as c_utils
|
||||||
from vmware_nsx.neutron.plugins.vmware.dbexts import (
|
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 db as nsx_db
|
||||||
from vmware_nsx.neutron.plugins.vmware.dbexts import nsxv_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.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.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 (
|
from vmware_nsx.neutron.plugins.vmware.vshield.common import (
|
||||||
exceptions as vsh_exc)
|
exceptions as vsh_exc)
|
||||||
from vmware_nsx.neutron.plugins.vmware.vshield import edge_utils
|
from vmware_nsx.neutron.plugins.vmware.vshield import edge_utils
|
||||||
@ -77,7 +76,7 @@ PORTGROUP_PREFIX = 'dvportgroup'
|
|||||||
|
|
||||||
class NsxVPluginV2(agents_db.AgentDbMixin,
|
class NsxVPluginV2(agents_db.AgentDbMixin,
|
||||||
db_base_plugin_v2.NeutronDbPluginV2,
|
db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
dist_rtr.DistributedRouter_mixin,
|
rt_rtr.RouterType_mixin,
|
||||||
external_net_db.External_net_db_mixin,
|
external_net_db.External_net_db_mixin,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
@ -98,6 +97,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
"extraroute",
|
"extraroute",
|
||||||
"router",
|
"router",
|
||||||
"security-group",
|
"security-group",
|
||||||
|
"nsxv-router-type",
|
||||||
"vnic-index",
|
"vnic-index",
|
||||||
"advanced-service-providers"]
|
"advanced-service-providers"]
|
||||||
|
|
||||||
@ -130,6 +130,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
self.sg_container_id = self._create_security_group_container()
|
self.sg_container_id = self._create_security_group_container()
|
||||||
self._validate_config()
|
self._validate_config()
|
||||||
self._create_cluster_default_fw_rules()
|
self._create_cluster_default_fw_rules()
|
||||||
|
self._router_managers = managers.RouterTypeManager(self)
|
||||||
|
|
||||||
has_metadata_cfg = (
|
has_metadata_cfg = (
|
||||||
cfg.CONF.nsxv.nova_metadata_ips
|
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)
|
h, container_id = self.nsx_v.vcns.create_security_group(container)
|
||||||
return container_id
|
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):
|
def _create_cluster_default_fw_rules(self):
|
||||||
# default cluster rules
|
# default cluster rules
|
||||||
rules = [{'name': 'Default DHCP rule for OS Security Groups',
|
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)
|
gw_info = self._extract_external_gw(context, router)
|
||||||
lrouter = super(NsxVPluginV2, self).create_router(context, router)
|
lrouter = super(NsxVPluginV2, self).create_router(context, router)
|
||||||
r = router['router']
|
r = router['router']
|
||||||
distributed = r.get('distributed')
|
self._decide_router_type(context, r)
|
||||||
r['distributed'] = attr.is_attr_set(distributed) and distributed
|
|
||||||
self.edge_manager.create_lrouter(context, lrouter,
|
|
||||||
dist=r['distributed'])
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
router_db = self._get_router(context, lrouter['id'])
|
router_db = self._get_router(context, lrouter['id'])
|
||||||
self._process_nsx_router_create(context, router_db, r)
|
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:
|
if gw_info is not None:
|
||||||
self._update_router_gw_info(context, lrouter['id'], gw_info)
|
router_driver._update_router_gw_info(
|
||||||
if (not r['distributed']
|
context, lrouter['id'], gw_info)
|
||||||
and allow_metadata
|
|
||||||
and self.metadata_proxy_handler):
|
|
||||||
self.metadata_proxy_handler.configure_router_edge(lrouter['id'])
|
|
||||||
return self.get_router(context, lrouter['id'])
|
return self.get_router(context, lrouter['id'])
|
||||||
|
|
||||||
def update_router(self, context, router_id, router):
|
def update_router(self, context, router_id, router):
|
||||||
# TODO(berlin): admin_state_up update
|
# TODO(berlin): admin_state_up update
|
||||||
if router['router'].get('admin_state_up') is False:
|
if router['router'].get('admin_state_up') is False:
|
||||||
LOG.warning(_LW("admin_state_up=False router is not supported."))
|
LOG.warning(_LW("admin_state_up=False router is not supported."))
|
||||||
gw_info = self._extract_external_gw(context, router, is_extract=False)
|
router_driver = self._find_router_driver(context, router_id)
|
||||||
router_updated = super(NsxVPluginV2, self).update_router(
|
return router_driver.update_router(context, router_id, 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
|
|
||||||
|
|
||||||
def _check_router_in_use(self, context, router_id):
|
def _check_router_in_use(self, context, router_id):
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
@ -1207,10 +1230,8 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
|
|
||||||
def delete_router(self, context, id):
|
def delete_router(self, context, id):
|
||||||
self._check_router_in_use(context, id)
|
self._check_router_in_use(context, id)
|
||||||
distributed = self.get_router(context, id).get('distributed', False)
|
router_driver = self._find_router_driver(context, id)
|
||||||
if self.metadata_proxy_handler and not distributed:
|
router_driver.delete_router(context, id)
|
||||||
self.metadata_proxy_handler.cleanup_router_edge(id)
|
|
||||||
self.edge_manager.delete_lrouter(context, id, dist=distributed)
|
|
||||||
super(NsxVPluginV2, self).delete_router(context, id)
|
super(NsxVPluginV2, self).delete_router(context, id)
|
||||||
|
|
||||||
def _get_external_attachment_info(self, context, router):
|
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,
|
edge_utils.update_routes(self.nsx_v, context, router_id,
|
||||||
routes, nexthop)
|
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):
|
def _update_router_gw_info(self, context, router_id, info):
|
||||||
router = self._get_router(context, router_id)
|
router_driver = self._find_router_driver(context, router_id)
|
||||||
org_ext_net_id = router.gw_port_id and router.gw_port.network_id
|
router_driver._update_router_gw_info(context, router_id, info)
|
||||||
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)
|
|
||||||
|
|
||||||
def _get_router_interface_ports_by_network(
|
def _get_router_interface_ports_by_network(
|
||||||
self, context, router_id, network_id):
|
self, context, router_id, network_id):
|
||||||
@ -1429,96 +1358,14 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
self.nsx_v, context, router_id, snat, dnat)
|
self.nsx_v, context, router_id, snat, dnat)
|
||||||
|
|
||||||
def add_router_interface(self, context, router_id, interface_info):
|
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)
|
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):
|
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)
|
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):
|
def _get_floatingips_by_router(self, context, router_id):
|
||||||
fip_qry = context.session.query(l3_db.FloatingIP)
|
fip_qry = context.session.query(l3_db.FloatingIP)
|
||||||
@ -1546,6 +1393,10 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
floatingip_db['status'] = status
|
floatingip_db['status'] = status
|
||||||
self.update_floatingip_status(context, floatingip_db['id'], 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):
|
def create_floatingip(self, context, floatingip):
|
||||||
fip_db = super(NsxVPluginV2, self).create_floatingip(
|
fip_db = super(NsxVPluginV2, self).create_floatingip(
|
||||||
context, floatingip)
|
context, floatingip)
|
||||||
@ -1583,19 +1434,6 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
self._set_floatingip_status(context, fip_db)
|
self._set_floatingip_status(context, fip_db)
|
||||||
return 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):
|
def delete_floatingip(self, context, id):
|
||||||
fip_db = self._get_floatingip(context, id)
|
fip_db = self._get_floatingip(context, id)
|
||||||
router_id = None
|
router_id = None
|
||||||
@ -1603,21 +1441,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
router_id = fip_db.router_id
|
router_id = fip_db.router_id
|
||||||
super(NsxVPluginV2, self).delete_floatingip(context, id)
|
super(NsxVPluginV2, self).delete_floatingip(context, id)
|
||||||
if router_id:
|
if router_id:
|
||||||
router = self._get_router(context, router_id)
|
self._update_edge_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)
|
|
||||||
|
|
||||||
def disassociate_floatingips(self, context, port_id):
|
def disassociate_floatingips(self, context, port_id):
|
||||||
router_id = None
|
router_id = None
|
||||||
@ -1632,21 +1456,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
router_id = None
|
router_id = None
|
||||||
super(NsxVPluginV2, self).disassociate_floatingips(context, port_id)
|
super(NsxVPluginV2, self).disassociate_floatingips(context, port_id)
|
||||||
if router_id:
|
if router_id:
|
||||||
router = self._get_router(context, router_id)
|
self._update_edge_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)
|
|
||||||
|
|
||||||
def _update_subnets_and_dnat_firewall(self, context, router,
|
def _update_subnets_and_dnat_firewall(self, context, router,
|
||||||
router_id=None, allow_external=True):
|
router_id=None, allow_external=True):
|
||||||
@ -1659,8 +1469,8 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
fake_subnet_fw_rule = {
|
fake_subnet_fw_rule = {
|
||||||
'action': 'allow',
|
'action': 'allow',
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
'source_ip_address': subnet_cidrs,
|
'source_ip_address': sorted(subnet_cidrs),
|
||||||
'destination_ip_address': subnet_cidrs}
|
'destination_ip_address': sorted(subnet_cidrs)}
|
||||||
fake_fw_rules.append(fake_subnet_fw_rule)
|
fake_fw_rules.append(fake_subnet_fw_rule)
|
||||||
_, dnat_rules = self._get_nat_rules(context, router)
|
_, dnat_rules = self._get_nat_rules(context, router)
|
||||||
|
|
||||||
@ -1674,7 +1484,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
|
|||||||
fake_dnat_fw_rule = {
|
fake_dnat_fw_rule = {
|
||||||
'action': 'allow',
|
'action': 'allow',
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
'destination_ip_address': dnat_cidrs}
|
'destination_ip_address': sorted(dnat_cidrs)}
|
||||||
fake_fw_rules.append(fake_dnat_fw_rule)
|
fake_fw_rules.append(fake_dnat_fw_rule)
|
||||||
# TODO(berlin): Add fw rules if fw service is supported
|
# TODO(berlin): Add fw rules if fw service is supported
|
||||||
fake_fw = {'firewall_rule_list': fake_fw_rules}
|
fake_fw = {'firewall_rule_list': fake_fw_rules}
|
||||||
|
@ -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
|
@ -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)
|
@ -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)
|
@ -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
|
@ -223,6 +223,7 @@ class NsxVMetadataProxyHandler:
|
|||||||
'router': {
|
'router': {
|
||||||
'name': 'metadata_proxy_router',
|
'name': 'metadata_proxy_router',
|
||||||
'admin_state_up': True,
|
'admin_state_up': True,
|
||||||
|
'router_type': 'exclusive',
|
||||||
'tenant_id': None}}
|
'tenant_id': None}}
|
||||||
|
|
||||||
rtr = self.nsxv_plugin.create_router(
|
rtr = self.nsxv_plugin.create_router(
|
||||||
|
@ -142,7 +142,8 @@ class EdgeFirewallDriver(db_base_plugin_v2.NeutronDbPluginV2):
|
|||||||
vcns_rules.append(
|
vcns_rules.append(
|
||||||
{'action': "accept",
|
{'action': "accept",
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
'destination': {'vnicGroupId': ["external"]}})
|
'destination': {'vnicGroupId': ["external"]},
|
||||||
|
'ruleTag': ruleTag})
|
||||||
return {
|
return {
|
||||||
'featureType': "firewall_4.0",
|
'featureType': "firewall_4.0",
|
||||||
'firewallRules': {
|
'firewallRules': {
|
||||||
|
@ -37,6 +37,8 @@ from neutron import manager
|
|||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
from neutron.plugins.vmware.extensions import (
|
from neutron.plugins.vmware.extensions import (
|
||||||
vnicindex as ext_vnic_idx)
|
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
|
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_db_plugin as test_plugin
|
||||||
import neutron.tests.unit.test_extension_allowedaddresspairs as test_addr_pair
|
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_extension_security_group as ext_sg
|
||||||
import neutron.tests.unit.test_l3_plugin as test_l3_plugin
|
import neutron.tests.unit.test_l3_plugin as test_l3_plugin
|
||||||
from neutron.tests.unit import testlib_api
|
from neutron.tests.unit import testlib_api
|
||||||
|
|
||||||
from vmware_nsx.neutron.plugins.vmware.dbexts import nsxv_db
|
from vmware_nsx.neutron.plugins.vmware.dbexts import nsxv_db
|
||||||
from vmware_nsx.neutron.plugins.vmware.vshield.common import (
|
from vmware_nsx.neutron.plugins.vmware.vshield.common import (
|
||||||
constants as vcns_const)
|
constants as vcns_const)
|
||||||
@ -1033,6 +1036,8 @@ class TestL3ExtensionManager(object):
|
|||||||
l3_ext_gw_mode.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
|
l3_ext_gw_mode.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
|
||||||
l3.RESOURCE_ATTRIBUTE_MAP[key].update(
|
l3.RESOURCE_ATTRIBUTE_MAP[key].update(
|
||||||
dist_router.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
|
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
|
# Finally add l3 resources to the global attribute map
|
||||||
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||||
l3.RESOURCE_ATTRIBUTE_MAP)
|
l3.RESOURCE_ATTRIBUTE_MAP)
|
||||||
@ -1074,11 +1079,11 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxVPluginV2TestCase):
|
|||||||
ext_mgr = ext_mgr or TestL3ExtensionManager()
|
ext_mgr = ext_mgr or TestL3ExtensionManager()
|
||||||
super(L3NatTest, self).setUp(
|
super(L3NatTest, self).setUp(
|
||||||
plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins)
|
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" % (
|
self._plugin_name = "%s.%s" % (
|
||||||
plugin_instance.__module__,
|
self.plugin_instance.__module__,
|
||||||
plugin_instance.__class__.__name__)
|
self.plugin_instance.__class__.__name__)
|
||||||
self._plugin_class = plugin_instance.__class__
|
self._plugin_class = self.plugin_instance.__class__
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
@ -1116,9 +1121,31 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxVPluginV2TestCase):
|
|||||||
self._delete('routers', router['router']['id'])
|
self._delete('routers', router['router']['id'])
|
||||||
|
|
||||||
|
|
||||||
class TestL3NatTestCase(L3NatTest,
|
class TestExclusiveRouterTestCase(L3NatTest,
|
||||||
test_l3_plugin.L3NatDBIntTestCase,
|
test_l3_plugin.L3NatDBIntTestCase,
|
||||||
NsxVPluginV2TestCase):
|
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):
|
def _test_create_l3_ext_network(self, vlan_id=0):
|
||||||
name = 'l3_ext_net'
|
name = 'l3_ext_net'
|
||||||
@ -1247,7 +1274,7 @@ class TestL3NatTestCase(L3NatTest,
|
|||||||
self._test_floatingip_with_invalid_create_port(self._plugin_name)
|
self._test_floatingip_with_invalid_create_port(self._plugin_name)
|
||||||
|
|
||||||
def test_floatingip_update(self):
|
def test_floatingip_update(self):
|
||||||
super(TestL3NatTestCase, self).test_floatingip_update(
|
super(TestExclusiveRouterTestCase, self).test_floatingip_update(
|
||||||
constants.FLOATINGIP_STATUS_DOWN)
|
constants.FLOATINGIP_STATUS_DOWN)
|
||||||
|
|
||||||
def test_floatingip_disassociate(self):
|
def test_floatingip_disassociate(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user