bagpipe: skip network:* ports and external networks ports

With this change, bagpipe driver won't trigger agent
RPCs for any network:* port or port of external networks.
This was already done for DHCP ports, but extended to
router interfaces, gateway interfaces, and external
networks.
The documentation and unit tests are updated accordingly.
Change-Id: Iae071e1bc19f20b38cc380e37366184b15ae7088
This commit is contained in:
Thomas Morin
2016年03月30日 17:48:21 +02:00
parent 5a9642b359
commit 4488cf53ed

View File

@@ -26,6 +26,18 @@ nodes of BGP VPN instances and of their MPLS dataplane.
.. blockdiag:: overview.blockdiag
On DHCP ports, Router interface ports, external network ports, etc.
-------------------------------------------------------------------
No connectivity will be setup with BGP VPNs for DHCP ports or Router
interface ports, or other network specific ports. This improves the load on network nodes by
avoiding them to import/export a significant amount of routes, without limiting BGP VPN
deployment scenarios because no useful traffic would be exchanged between a router or DHCP
interface of a network associated to a BGP VPN.
Similarly, the driver will not bind a port on an external network. This behavior will be
revisited once a use case is well identified.
How to use ?
------------

View File

@@ -20,7 +20,9 @@ from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.common import constants as const
from neutron.common import exceptions as n_exc
from neutron import context as n_context
from neutron.db import external_net_db
from neutron.db import l3_db
from neutron.db import models_v2
from neutron.extensions import portbindings
@@ -44,6 +46,11 @@ LOG = logging.getLogger(__name__)
BAGPIPE_DRIVER_NAME = "bagpipe"
class BGPVPNExternalNetAssociation(n_exc.NeutronException):
message = _("driver does not support associating an external"
"network to a BGPVPN")
def get_network_info_for_port(context, port_id):
"""Get MAC, IP and Gateway IP addresses informations for a specific port"""
@@ -133,6 +140,15 @@ def get_bgpvpns_of_router_assocs_by_network(context, net_id):
return
def network_is_external(context, net_id):
try:
context.session.query(external_net_db.ExternalNetwork).filter_by(
network_id=net_id).one()
return True
except exc.NoResultFound:
return False
class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
"""BGPVPN Service Driver class for BaGPipe"""
@@ -324,6 +340,10 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
self._format_bgpvpn(bgpvpn, net_id)
)
def create_net_assoc_precommit(self, context, net_assoc):
if network_is_external(context, net_assoc['network_id']):
raise BGPVPNExternalNetAssociation()
def create_net_assoc_postcommit(self, context, net_assoc):
if get_network_ports(context, net_assoc['network_id']):
bgpvpn = self.get_bgpvpn(context, net_assoc['bgpvpn_id'])
@@ -357,6 +377,19 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
return port.get(portbindings.HOST_ID)
def _ignore_port(self, context, port):
if port['device_owner'].startswith(const.DEVICE_OWNER_NETWORK_PREFIX):
LOG.info("Port %s owner is network:*, we'll do nothing",
port['id'])
return True
if network_is_external(context, port['network_id']):
LOG.info("Port %s is on an external network, we'll do nothing",
port['id'])
return True
return False
def notify_port_updated(self, context, port_id, original_port):
LOG.info("notify_port_updated on port %s", port_id)
@@ -365,8 +398,7 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
port_bgpvpn_info = {'id': port['id'],
'network_id': port['network_id']}
if port['device_owner'] == const.DEVICE_OWNER_DHCP:
LOG.info("Port %s is DHCP, ignoring", port['id'])
if self._ignore_port(context, port):
return
agent_host = self._get_port_host(context, port)
@@ -413,8 +445,7 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
port_bgpvpn_info = {'id': port['id'],
'network_id': port['network_id']}
if port['device_owner'] == const.DEVICE_OWNER_DHCP:
LOG.info("Port %s is DHCP, ignoring", port['id'])
if self._ignore_port(context, port):
return
agent_host = self._get_port_host(context, port)

View File

@@ -19,7 +19,7 @@ import webob.exc
from neutron import context as n_context
from neutron.common.constants import DEVICE_OWNER_DHCP
from neutron.common.constants import DEVICE_OWNER_NETWORK_PREFIX
from neutron.common.constants import DEVICE_OWNER_ROUTER_INTF
from neutron.common.constants import PORT_STATUS_ACTIVE
from neutron.common.constants import PORT_STATUS_DOWN
@@ -46,6 +46,18 @@ class TestBagpipeCommon(test_plugin.BgpvpnTestCaseMixin):
super(TestBagpipeCommon, self).setUp(service_provider=provider,
core_plugin=plugin)
self.ctxt = n_context.Context('fake_user', 'fake_project')
n_dict = {"name": "netfoo",
"tenant_id": "fake_project",
"admin_state_up": True,
"router:external": True,
"shared": True}
self.external_net = {'network':
self.plugin.create_network(self.ctxt,
{'network': n_dict})}
class TestBagpipeServiceDriver(TestBagpipeCommon):
@@ -101,6 +113,21 @@ class TestBagpipeServiceDriver(TestBagpipeCommon):
mocked_update.assert_called_once_with(mock.ANY,
formatted_bgpvpn)
def test_bagpipe_associate_external_net_failed(self):
net_id = self.external_net['network']['id']
with self.bgpvpn(tenant_id='another_tenant') as bgpvpn:
id = bgpvpn['bgpvpn']['id']
data = {'network_association': {'network_id': net_id,
'tenant_id': self._tenant_id}}
bgpvpn_net_req = self.new_create_request(
'bgpvpn/bgpvpns',
data=data,
fmt=self.fmt,
id=id,
subresource='network_associations')
res = bgpvpn_net_req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPForbidden.code)
def test_bagpipe_associate_router(self):
mocked_update = self.mocked_bagpipeAPI.update_bgpvpn
with self.router(tenant_id=self._tenant_id) as router:
@@ -265,8 +292,6 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
self.mock_update_bgpvpn_rpc = self.mocked_bagpipeAPI.update_bgpvpn
self.mock_delete_bgpvpn_rpc = self.mocked_bagpipeAPI.delete_bgpvpn
self.ctxt = n_context.Context('fake_user', 'fake_project')
def _build_expected_return_active(self, port):
bgpvpn_info_port = BGPVPN_INFO.copy()
bgpvpn_info_port.update({'id': port['id'],
@@ -368,8 +393,8 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
TESTHOST)
self.assertFalse(self.mock_attach_rpc.called)
def test_bagpipe_callback_to_rpc_update_active_ignore_DHCP(self):
with self.port(device_owner=DEVICE_OWNER_DHCP,
def test_bagpipe_callback_to_rpc_update_active_ignore_net_ports(self):
with self.port(device_owner=DEVICE_OWNER_NETWORK_PREFIX,
arg_list=(portbindings.HOST_ID,),
**{portbindings.HOST_ID: TESTHOST}) as port:
self._update_port_status(port, PORT_STATUS_ACTIVE)
@@ -381,8 +406,8 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
self.assertFalse(self.mock_attach_rpc.called)
self.assertFalse(self.mock_detach_rpc.called)
def test_bagpipe_callback_to_rpc_update_down_ignore_DHCP(self):
with self.port(device_owner=DEVICE_OWNER_DHCP,
def test_bagpipe_callback_to_rpc_update_down_ignore_net_ports(self):
with self.port(device_owner=DEVICE_OWNER_NETWORK_PREFIX,
arg_list=(portbindings.HOST_ID,),
**{portbindings.HOST_ID: TESTHOST}) as port:
self._update_port_status(port, PORT_STATUS_DOWN)
@@ -394,8 +419,8 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
self.assertFalse(self.mock_attach_rpc.called)
self.assertFalse(self.mock_detach_rpc.called)
def test_bagpipe_callback_to_rpc_deleted_ignore_DHCP(self):
with self.port(device_owner=DEVICE_OWNER_DHCP,
def test_bagpipe_callback_to_rpc_deleted_ignore_net_ports(self):
with self.port(device_owner=DEVICE_OWNER_NETWORK_PREFIX,
arg_list=(portbindings.HOST_ID,),
**{portbindings.HOST_ID: TESTHOST}) as port:
self._update_port_status(port, PORT_STATUS_DOWN)
@@ -407,10 +432,49 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
self.assertFalse(self.mock_attach_rpc.called)
self.assertFalse(self.mock_detach_rpc.called)
def test_bagpipe_callback_to_rpc_update_active_ignore_external_net(self):
with self.subnet(network=self.external_net) as subnet, \
self.port(subnet=subnet,
arg_list=(portbindings.HOST_ID,),
**{portbindings.HOST_ID: TESTHOST}) as port:
self._update_port_status(port, PORT_STATUS_ACTIVE)
self.bagpipe_driver.registry_port_updated(
None, None, None,
context=self.ctxt,
port=port['port']
)
self.assertFalse(self.mock_attach_rpc.called)
self.assertFalse(self.mock_detach_rpc.called)
def test_bagpipe_callback_to_rpc_update_down_ignore_external_net(self):
with self.subnet(network=self.external_net) as subnet, \
self.port(subnet=subnet,
arg_list=(portbindings.HOST_ID,),
**{portbindings.HOST_ID: TESTHOST}) as port:
self._update_port_status(port, PORT_STATUS_DOWN)
self.bagpipe_driver.registry_port_updated(
None, None, None,
context=self.ctxt,
port=port['port']
)
self.assertFalse(self.mock_attach_rpc.called)
self.assertFalse(self.mock_detach_rpc.called)
def test_bagpipe_callback_to_rpc_deleted_ignore_external_net(self):
with self.subnet(network=self.external_net) as subnet, \
self.port(subnet=subnet,
arg_list=(portbindings.HOST_ID,),
**{portbindings.HOST_ID: TESTHOST}) as port:
self._update_port_status(port, PORT_STATUS_DOWN)
self.bagpipe_driver.registry_port_deleted(
None, None, None,
context=self.ctxt,
port_id=port['port']['id']
)
self.assertFalse(self.mock_attach_rpc.called)
self.assertFalse(self.mock_detach_rpc.called)
def test_delete_port_to_bgpvpn_rpc(self):
ctxt = n_context.Context('fake_user', 'fake_project')
with self.network() as net, \
self.subnet(network=net) as subnet, \
self.port(subnet=subnet) as port, \
@@ -421,7 +485,7 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
port['port'].update({'binding:host_id': TESTHOST})
self.plugin.delete_port(ctxt, port['port']['id'])
self.plugin.delete_port(self.ctxt, port['port']['id'])
self.mock_detach_rpc.assert_called_once_with(
mock.ANY,
Reference in New Issue
openstack/networking-bgpvpn
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.

The note is not visible to the blocked user.