NSX|P: Allow only 1 router interface per network
Change-Id: Ia8c5ac5d8a9564d9cdb6e3e8831866b4a254abe2
This commit is contained in:
parent
a13d49b0ab
commit
c734899100
@ -56,6 +56,7 @@ from neutron_lib.db import api as db_api
|
||||
from neutron_lib.db import utils as db_utils
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib.exceptions import allowedaddresspairs as addr_exc
|
||||
from neutron_lib.exceptions import l3 as l3_exc
|
||||
from neutron_lib.exceptions import port_security as psec_exc
|
||||
from neutron_lib.plugins import utils as plugin_utils
|
||||
from neutron_lib.services.qos import constants as qos_consts
|
||||
@ -2352,3 +2353,44 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
'os-neutron-net-id', network_id)
|
||||
if port_id:
|
||||
self.nsxlib.logical_port.delete(port_id)
|
||||
|
||||
def _support_vlan_router_interfaces(self):
|
||||
"""Should be implemented by each plugin"""
|
||||
pass
|
||||
|
||||
def _validate_multiple_subnets_routers(self, context, router_id, net_id):
|
||||
network = self.get_network(context, net_id)
|
||||
net_type = network.get(pnet.NETWORK_TYPE)
|
||||
if (net_type and
|
||||
not self._support_vlan_router_interfaces() and
|
||||
not self._is_overlay_network(context, net_id)):
|
||||
err_msg = (_("Only overlay networks can be attached to a logical "
|
||||
"router. Network %(net_id)s is a %(net_type)s based "
|
||||
"network") % {'net_id': net_id, 'net_type': net_type})
|
||||
LOG.error(err_msg)
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
# Unable to attach a trunked network to a router interface
|
||||
if cfg.CONF.vlan_transparent:
|
||||
if network.get('vlan_transparent') is True:
|
||||
err_msg = (_("Transparent VLAN networks cannot be attached to "
|
||||
"a logical router."))
|
||||
LOG.error(err_msg)
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
port_filters = {'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF],
|
||||
'network_id': [net_id]}
|
||||
intf_ports = self.get_ports(context.elevated(), filters=port_filters)
|
||||
router_ids = [port['device_id']
|
||||
for port in intf_ports if port['device_id']]
|
||||
if len(router_ids) > 0:
|
||||
err_msg = _("Only one subnet of network %(net_id)s can be "
|
||||
"attached to router, one subnet is already attached "
|
||||
"to router %(router_id)s") % {
|
||||
'net_id': net_id,
|
||||
'router_id': router_ids[0]}
|
||||
LOG.error(err_msg)
|
||||
if router_id in router_ids:
|
||||
# attach to the same router again
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
else:
|
||||
# attach to multiple routers
|
||||
raise l3_exc.RouterInterfaceAttachmentConflict(reason=err_msg)
|
||||
|
@ -1350,23 +1350,39 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
|
||||
def add_router_interface(self, context, router_id, interface_info):
|
||||
network_id = self._get_interface_network(context, interface_info)
|
||||
extern_net = self._network_is_external(context, network_id)
|
||||
overlay_net = self._is_overlay_network(context, network_id)
|
||||
router_db = self._get_router(context, router_id)
|
||||
gw_network_id = (router_db.gw_port.network_id if router_db.gw_port
|
||||
else None)
|
||||
|
||||
# A router interface cannot be an external network
|
||||
if extern_net:
|
||||
msg = _("An external network cannot be attached as "
|
||||
"an interface to a router")
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
with locking.LockManager.get_lock(str(network_id)):
|
||||
# disallow more than one subnets belong to same network being
|
||||
# attached to routers
|
||||
self._validate_multiple_subnets_routers(
|
||||
context, router_id, network_id)
|
||||
|
||||
# Update the interface of the neutron router
|
||||
info = super(NsxPolicyPlugin, self).add_router_interface(
|
||||
context, router_id, interface_info)
|
||||
# A router interface cannot be an external network
|
||||
if extern_net:
|
||||
msg = _("An external network cannot be attached as "
|
||||
"an interface to a router")
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
self._validate_interface_address_scope(context, router_db, info)
|
||||
# Non overlay networks should be configured with a centralized
|
||||
# router, which is allowed only if GW network is attached
|
||||
if not overlay_net and not gw_network_id:
|
||||
msg = _("A router attached to a VLAN backed network "
|
||||
"must have an external network assigned")
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
# Update the interface of the neutron router
|
||||
info = super(NsxPolicyPlugin, self).add_router_interface(
|
||||
context, router_id, interface_info)
|
||||
|
||||
try:
|
||||
# If it is a no-snat router, interface address scope must be the
|
||||
# same as the gateways
|
||||
self._validate_interface_address_scope(context, router_db, info)
|
||||
|
||||
# Check GW & subnets TZ
|
||||
subnets = self._find_router_subnets(context.elevated(), router_id)
|
||||
tier0_uuid = self._get_tier0_uuid_by_router(
|
||||
@ -2091,3 +2107,6 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
|
||||
def _get_net_dhcp_relay(self, context, net_id):
|
||||
# No dhcp relay support yet
|
||||
return None
|
||||
|
||||
def _support_vlan_router_interfaces(self):
|
||||
return True
|
||||
|
@ -44,7 +44,6 @@ from neutron.extensions import providernet
|
||||
from neutron.extensions import securitygroup as ext_sg
|
||||
from neutron.quota import resource_registry
|
||||
from neutron_lib.api.definitions import extra_dhcp_opt as ext_edo
|
||||
from neutron_lib.api.definitions import provider_net as pnet
|
||||
from neutron_lib.api.definitions import vlantransparent as vlan_apidef
|
||||
from neutron_lib.api import validators
|
||||
from neutron_lib.callbacks import events
|
||||
@ -2637,44 +2636,6 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
|
||||
address_groups.append(address_group)
|
||||
return (ports, address_groups)
|
||||
|
||||
def _validate_multiple_subnets_routers(self, context, router_id, net_id):
|
||||
network = self.get_network(context, net_id)
|
||||
net_type = network.get(pnet.NETWORK_TYPE)
|
||||
if (net_type and
|
||||
not self.nsxlib.feature_supported(
|
||||
nsxlib_consts.FEATURE_VLAN_ROUTER_INTERFACE) and
|
||||
not self._is_overlay_network(context, net_id)):
|
||||
err_msg = (_("Only overlay networks can be attached to a logical "
|
||||
"router. Network %(net_id)s is a %(net_type)s based "
|
||||
"network") % {'net_id': net_id, 'net_type': net_type})
|
||||
LOG.error(err_msg)
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
# Unable to attach a trunked network to a router interface
|
||||
if cfg.CONF.vlan_transparent:
|
||||
if network.get('vlan_transparent') is True:
|
||||
err_msg = (_("Transparent VLAN networks cannot be attached to "
|
||||
"a logical router."))
|
||||
LOG.error(err_msg)
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
port_filters = {'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF],
|
||||
'network_id': [net_id]}
|
||||
intf_ports = self.get_ports(context.elevated(), filters=port_filters)
|
||||
router_ids = [port['device_id']
|
||||
for port in intf_ports if port['device_id']]
|
||||
if len(router_ids) > 0:
|
||||
err_msg = _("Only one subnet of network %(net_id)s can be "
|
||||
"attached to router, one subnet is already attached "
|
||||
"to router %(router_id)s") % {
|
||||
'net_id': net_id,
|
||||
'router_id': router_ids[0]}
|
||||
LOG.error(err_msg)
|
||||
if router_id in router_ids:
|
||||
# attach to the same router again
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
else:
|
||||
# attach to multiple routers
|
||||
raise l3_exc.RouterInterfaceAttachmentConflict(reason=err_msg)
|
||||
|
||||
def _add_router_interface_wrapper(self, context, router_id,
|
||||
interface_info):
|
||||
if cfg.CONF.api_replay_mode:
|
||||
@ -3418,3 +3379,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
|
||||
def _get_net_dhcp_relay(self, context, net_id):
|
||||
return self.get_network_az_by_net_id(
|
||||
context, net_id).dhcp_relay_service
|
||||
|
||||
def _support_vlan_router_interfaces(self):
|
||||
return self.nsxlib.feature_supported(
|
||||
nsxlib_consts.FEATURE_VLAN_ROUTER_INTERFACE)
|
||||
|
Loading…
x
Reference in New Issue
Block a user