Merge "bagpipe: compatibility with Neutron routers"
This commit is contained in:
4 changed files with 274 additions and 165 deletions
@@ -41,12 +41,6 @@ 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.
On Networks both associated to a BGP VPN and attached to a router
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A network associated to a bgpvpn will loose access to its gateway, hence to any network
accessible behind its router which holds this gateway.
How to use ?
------------
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy.orm import exc
from sqlalchemy import orm
from sqlalchemy import sql
from neutron.callbacks import events
@@ -52,10 +52,9 @@ class BGPVPNExternalNetAssociation(n_exc.NeutronException):
"network to a BGPVPN")
def get_network_info_for_port(context, port_id):
@log_helpers.log_method_call
def get_network_info_for_port(context, port_id, network_id):
"""Get MAC, IP and Gateway IP addresses informations for a specific port"""
LOG.debug("get_network_info_for_port() called for port %s" % port_id)
try:
with context.session.begin(subtransactions=True):
net_info = (context.session.
@@ -71,74 +70,90 @@ def get_network_info_for_port(context, port_id):
filter(models_v2.Port.id == port_id).one())
(mac_address, ip_address, cidr, gateway_ip) = net_info
return {'mac_address': mac_address,
'ip_address': ip_address + cidr[cidr.index('/'):],
'gateway_ip': gateway_ip}
except exc.NoResultFound:
except orm.exc.NoResultFound:
return
gateway_mac = (
context.session.
query(models_v2.Port.mac_address).
filter(
models_v2.Port.network_id == network_id,
(models_v2.Port.device_owner ==
const.DEVICE_OWNER_ROUTER_INTF)
).
one_or_none()
)
return {'mac_address': mac_address,
'ip_address': ip_address + cidr[cidr.index('/'):],
'gateway_ip': gateway_ip,
'gateway_mac': gateway_mac[0] if gateway_mac else None}
def get_gateway_mac(context, network_id):
with context.session.begin(subtransactions=True):
gateway_mac = (
context.session.
query(models_v2.Port.mac_address).
filter(
models_v2.Port.network_id == network_id,
(models_v2.Port.device_owner ==
const.DEVICE_OWNER_ROUTER_INTF)
).
one_or_none()
)
return gateway_mac[0] if gateway_mac else None
def get_network_ports(context, network_id):
try:
return (context.session.query(models_v2.Port).
filter(models_v2.Port.network_id == network_id,
models_v2.Port.admin_state_up == sql.true()).all())
except exc.NoResultFound:
return
# NOTE(tmorin): currents callers don't look at detailed results
# but only test if at least one result exist => can be optimized
# by returning a count, rather than all port information
return (context.session.query(models_v2.Port).
filter(models_v2.Port.network_id == network_id,
models_v2.Port.admin_state_up == sql.true()).all())
def get_router_ports(context, router_id):
try:
return (
context.session.query(models_v2.Port).
filter(
models_v2.Port.device_id == router_id,
models_v2.Port.device_owner == const.DEVICE_OWNER_ROUTER_INTF
).all()
)
except exc.NoResultFound:
return
return (
context.session.query(models_v2.Port).
filter(
models_v2.Port.device_id == router_id,
models_v2.Port.device_owner == const.DEVICE_OWNER_ROUTER_INTF
).all()
)
def get_router_bgpvpn_assocs(context, router_id):
try:
return (
context.session.query(bgpvpn_db.BGPVPNRouterAssociation).
filter(
bgpvpn_db.BGPVPNRouterAssociation.router_id == router_id
).all()
)
except exc.NoResultFound:
return []
return (
context.session.query(bgpvpn_db.BGPVPNRouterAssociation).
filter(
bgpvpn_db.BGPVPNRouterAssociation.router_id == router_id
).all()
)
def get_network_bgpvpn_assocs(context, net_id):
try:
return (
context.session.query(bgpvpn_db.BGPVPNNetAssociation).
filter(
bgpvpn_db.BGPVPNNetAssociation.network_id == net_id
).all()
)
except exc.NoResultFound:
return
return (
context.session.query(bgpvpn_db.BGPVPNNetAssociation).
filter(
bgpvpn_db.BGPVPNNetAssociation.network_id == net_id
).all()
)
def get_bgpvpns_of_router_assocs_by_network(context, net_id):
try:
return (
context.session.query(bgpvpn_db.BGPVPN).
join(bgpvpn_db.BGPVPN.router_associations).
join(bgpvpn_db.BGPVPNRouterAssociation.router).
join(l3_db.Router.attached_ports).
join(l3_db.RouterPort.port).
filter(
models_v2.Port.network_id == net_id
).all()
)
except exc.NoResultFound:
return
return (
context.session.query(bgpvpn_db.BGPVPN).
join(bgpvpn_db.BGPVPN.router_associations).
join(bgpvpn_db.BGPVPNRouterAssociation.router).
join(l3_db.Router.attached_ports).
join(l3_db.RouterPort.port).
filter(
models_v2.Port.network_id == net_id
).all()
)
def network_is_external(context, net_id):
@@ -146,7 +161,7 @@ def network_is_external(context, net_id):
context.session.query(external_net_db.ExternalNetwork).filter_by(
network_id=net_id).one()
return True
except exc.NoResultFound:
except orm.exc.NoResultFound:
return False
@@ -168,13 +183,15 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
registry.subscribe(self.registry_port_created, resources.PORT,
events.AFTER_CREATE)
def _format_bgpvpn(self, bgpvpn, network_id):
def _format_bgpvpn(self, context, bgpvpn, network_id):
"""JSON-format BGPVPN
BGPVPN, network identifiers, and route targets.
"""
formatted_bgpvpn = {'id': bgpvpn['id'],
'network_id': network_id}
'network_id': network_id,
'gateway_mac': get_gateway_mac(context,
network_id)}
formatted_bgpvpn.update(
self._format_bgpvpn_network_route_targets([bgpvpn]))
@@ -234,6 +251,13 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
return bgpvpn_rts
def _bgpvpns_for_network(self, context, network_id):
return (
self.bgpvpn_db.find_bgpvpns_for_network(context, network_id)
or self.retrieve_bgpvpns_of_router_assocs_by_network(context,
network_id)
)
def _retrieve_bgpvpn_network_info_for_port(self, context, port):
"""Retrieve BGP VPN network informations for a specific port
@@ -242,6 +266,7 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
'mac_address': '00:00:de:ad:be:ef',
'ip_address': '10.0.0.2',
'gateway_ip': '10.0.0.1',
'gateway_mac': 'aa:bb:cc:dd:ee:ff', # if a router interface exists
'l3vpn' : {
'import_rt': ['12345:1', '12345:2', '12345:3'],
'export_rt': ['12345:1', '12345:2', '12345:4']
@@ -253,12 +278,7 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
bgpvpn_network_info = {}
# Check if port is connected on a BGP VPN network
bgpvpns = (
self.bgpvpn_db.find_bgpvpns_for_network(context, network_id)
or self.retrieve_bgpvpns_of_router_assocs_by_network(context,
network_id)
)
bgpvpns = self._bgpvpns_for_network(context, network_id)
# NOTE(tmorin): We currently need to send 'network_id', 'mac_address',
# 'ip_address', 'gateway_ip' to the agent, even in the absence of
@@ -275,7 +295,7 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
bgpvpn_network_info.update(bgpvpn_rts)
LOG.debug("Getting port %s network details" % port_id)
network_info = get_network_info_for_port(context, port_id)
network_info = get_network_info_for_port(context, port_id, network_id)
if not network_info:
LOG.warning("No network information for net %s", network_id)
@@ -309,7 +329,7 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
# Format BGPVPN before sending notification
self.agent_rpc.delete_bgpvpn(
context,
self._format_bgpvpn(bgpvpn, net_id))
self._format_bgpvpn(context, bgpvpn, net_id))
def update_bgpvpn_precommit(self, context, old_bgpvpn, bgpvpn):
self._common_precommit_checks(bgpvpn)
@@ -328,10 +348,7 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
(key in changed_keys for key in ('route_targets',
'import_targets',
'export_targets'))):
self.agent_rpc.update_bgpvpn(
context,
self._format_bgpvpn(bgpvpn, net_id)
)
self._update_bgpvpn_for_network(context, net_id, bgpvpn)
def create_net_assoc_precommit(self, context, net_assoc):
if network_is_external(context, net_assoc['network_id']):
@@ -340,16 +357,18 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
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'])
formated_bgpvpn = self._format_bgpvpn(bgpvpn,
net_assoc['network_id'])
self.agent_rpc.update_bgpvpn(
context,
formated_bgpvpn)
self._update_bgpvpn_for_network(context,
net_assoc['network_id'], bgpvpn)
def _update_bgpvpn_for_network(self, context, net_id, bgpvpn):
formated_bgpvpn = self._format_bgpvpn(context, bgpvpn, net_id)
self.agent_rpc.update_bgpvpn(context,
formated_bgpvpn)
def delete_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'])
formated_bgpvpn = self._format_bgpvpn(bgpvpn,
formated_bgpvpn = self._format_bgpvpn(context, bgpvpn,
net_assoc['network_id'])
self.agent_rpc.delete_bgpvpn(context, formated_bgpvpn)
@@ -443,14 +462,19 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
@log_helpers.log_method_call
def router_interface_added(self, context, port):
net_assocs = get_network_bgpvpn_assocs(context, port['network_id'])
router_assocs = get_router_bgpvpn_assocs(context, port['device_id'])
if net_assocs and router_assocs:
msg = 'Can not add router interface because both router %(rtr)s' \
'and network %(net)s have bgpvpnassociation(s)'
LOG.error(msg % {'rtr': port['device_id'],
'net': port['network_id']})
return
net_id = port['network_id']
router_id = port['device_id']
net_assocs = get_network_bgpvpn_assocs(context, net_id)
router_assocs = get_router_bgpvpn_assocs(context, router_id)
# if this router_interface is on a network bound to a BGPVPN,
# or if this router is bound to a BGPVPN,
# then we need to send and update for this network, including
# the gateway_mac
if net_assocs or router_assocs:
for bgpvpn in self._bgpvpns_for_network(context, net_id):
self._update_bgpvpn_for_network(context, net_id, bgpvpn)
for router_assoc in router_assocs:
net_assoc = {'network_id': port['network_id'],
@@ -459,9 +483,18 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver):
@log_helpers.log_method_call
def router_interface_removed(self, context, port):
for router_assoc in get_router_bgpvpn_assocs(context,
port['device_id']):
net_assoc = {'network_id': port['network_id'],
net_id = port['network_id']
router_id = port['device_id']
net_assocs = get_network_bgpvpn_assocs(context, net_id)
router_assocs = get_router_bgpvpn_assocs(context, router_id)
if net_assocs or router_assocs:
for bgpvpn in self._bgpvpns_for_network(context, net_id):
self._update_bgpvpn_for_network(context, net_id, bgpvpn)
for router_assoc in router_assocs:
net_assoc = {'network_id': net_id,
'bgpvpn_id': router_assoc['bgpvpn_id']}
self.delete_net_assoc_postcommit(context, net_assoc)
@@ -46,13 +46,26 @@ from networking_bgpvpn.neutron.services.service_drivers.bagpipe import bagpipe
from networking_bgpvpn.tests.unit.services import test_plugin
def _expected_formatted_bgpvpn(id, net_id, rt, gateway_mac=None):
return {'id': id,
'network_id': net_id,
'l3vpn': {'import_rt': rt,
'export_rt': rt},
'gateway_mac': gateway_mac}
class TestBagpipeCommon(test_plugin.BgpvpnTestCaseMixin):
def setUp(self, plugin=None):
self.mocked_bagpipeAPI = mock.patch(
self.mocked_rpc = mock.patch(
'networking_bagpipe.agent.bgpvpn.rpc_client'
'.BGPVPNAgentNotifyApi').start().return_value
self.mock_attach_rpc = self.mocked_rpc.attach_port_on_bgpvpn
self.mock_detach_rpc = self.mocked_rpc.detach_port_from_bgpvpn
self.mock_update_rpc = self.mocked_rpc.update_bgpvpn
self.mock_delete_rpc = self.mocked_rpc.delete_bgpvpn
provider = ('networking_bgpvpn.neutron.services.service_drivers.'
'bagpipe.bagpipe.BaGPipeBGPVPNDriver')
super(TestBagpipeCommon, self).setUp(service_provider=provider,
@@ -109,21 +122,16 @@ class TestBagpipeServiceDriver(TestBagpipeCommon):
show_bgpvpn['bgpvpn']['route_distinguishers'])
def test_bagpipe_associate_net(self):
mocked_update = self.mocked_bagpipeAPI.update_bgpvpn
with self.port() as port1:
net_id = port1['port']['network_id']
with self.bgpvpn() as bgpvpn:
id = bgpvpn['bgpvpn']['id']
rt = bgpvpn['bgpvpn']['route_targets']
mocked_update.reset_mock()
self.mock_update_rpc.reset_mock()
with self.assoc_net(id, net_id):
formatted_bgpvpn = {'id': id,
'network_id': net_id,
'l3vpn':
{'import_rt': rt,
'export_rt': rt}}
mocked_update.assert_called_once_with(mock.ANY,
formatted_bgpvpn)
self.mock_update_rpc.assert_called_once_with(
mock.ANY,
_expected_formatted_bgpvpn(id, net_id, rt))
def test_bagpipe_associate_external_net_failed(self):
net_id = self.external_net['network']['id']
@@ -141,31 +149,31 @@ class TestBagpipeServiceDriver(TestBagpipeCommon):
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:
router_id = router['router']['id']
with self.subnet() as subnet:
with self.port(subnet=subnet) as port:
net_id = port['port']['network_id']
subnet_id = subnet['subnet']['id']
self._router_interface_action('add', router_id,
subnet_id, None)
itf = self._router_interface_action('add', router_id,
subnet_id, None)
itf_port = self.plugin.get_port(self.ctxt, itf['port_id'])
with self.bgpvpn() as bgpvpn:
id = bgpvpn['bgpvpn']['id']
rt = bgpvpn['bgpvpn']['route_targets']
mocked_update.reset_mock()
self.mock_update_rpc.reset_mock()
with self.assoc_router(id, router_id):
formatted_bgpvpn = {'id': id,
'network_id': net_id,
'l3vpn': {
'import_rt': rt,
'export_rt': rt}}
mocked_update.assert_called_once_with(
mock.ANY, formatted_bgpvpn)
self.mock_update_rpc.assert_called_once_with(
mock.ANY,
_expected_formatted_bgpvpn(
id, net_id,
rt,
itf_port['mac_address']))
def test_bagpipe_disassociate_net(self):
mocked_delete = self.mocked_bagpipeAPI.delete_bgpvpn
mocked_delete = self.mocked_rpc.delete_bgpvpn
with self.port() as port1:
net_id = port1['port']['network_id']
with self.bgpvpn() as bgpvpn:
@@ -184,37 +192,28 @@ class TestBagpipeServiceDriver(TestBagpipeCommon):
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
formatted_bgpvpn = {'id': id,
'network_id': net_id,
'l3vpn':
{'import_rt': rt,
'export_rt': rt}}
mocked_delete.assert_called_once_with(mock.ANY,
formatted_bgpvpn)
mocked_delete.assert_called_once_with(
mock.ANY,
_expected_formatted_bgpvpn(id, net_id, rt))
def test_bagpipe_update_bgpvpn_rt(self):
mocked_update = self.mocked_bagpipeAPI.update_bgpvpn
with self.port() as port1:
net_id = port1['port']['network_id']
with self.bgpvpn() as bgpvpn:
id = bgpvpn['bgpvpn']['id']
rt = ['6543:21']
with self.assoc_net(id, net_id):
formatted_bgpvpn = {'id': id,
'network_id': net_id,
'l3vpn':
{'import_rt': rt,
'export_rt': rt}}
update_data = {'bgpvpn': {'route_targets': ['6543:21']}}
mocked_update.reset_mock()
self.mock_update_rpc.reset_mock()
self._update('bgpvpn/bgpvpns',
bgpvpn['bgpvpn']['id'],
update_data)
mocked_update.assert_called_once_with(mock.ANY,
formatted_bgpvpn)
self.mock_update_rpc.assert_called_once_with(
mock.ANY,
_expected_formatted_bgpvpn(id, net_id, rt))
def test_bagpipe_delete_bgpvpn(self):
mocked_delete = self.mocked_bagpipeAPI.delete_bgpvpn
mocked_delete = self.mocked_rpc.delete_bgpvpn
with self.port() as port1:
net_id = port1['port']['network_id']
with self.bgpvpn(do_delete=False) as bgpvpn:
@@ -223,13 +222,9 @@ class TestBagpipeServiceDriver(TestBagpipeCommon):
mocked_delete.reset_mock()
with self.assoc_net(id, net_id, do_disassociate=False):
self._delete('bgpvpn/bgpvpns', id)
formatted_bgpvpn = {'id': id,
'network_id': net_id,
'l3vpn':
{'import_rt': rt,
'export_rt': rt}}
mocked_delete.assert_called_once_with(mock.ANY,
formatted_bgpvpn)
mocked_delete.assert_called_once_with(
mock.ANY,
_expected_formatted_bgpvpn(id, net_id, rt))
def test_bagpipe_callback_to_rpc_update_port_after_router_itf_added(self):
driver = self.bgpvpn_plugin.driver
@@ -237,38 +232,64 @@ class TestBagpipeServiceDriver(TestBagpipeCommon):
self.subnet(network=net) as subnet, \
self.router(tenant_id=self._tenant_id) as router, \
self.bgpvpn() as bgpvpn:
self._router_interface_action('add',
router['router']['id'],
subnet['subnet']['id'],
None)
itf = self._router_interface_action('add',
router['router']['id'],
subnet['subnet']['id'],
None)
with self.assoc_router(bgpvpn['bgpvpn']['id'],
router['router']['id']), \
self.port(subnet=subnet) as port:
context = n_context.Context(user_id='fake_user',
tenant_id=self._tenant_id)
mac_address = port['port']['mac_address']
formatted_ip = (port['port']['fixed_ips'][0]['ip_address'] +
'/' + subnet['subnet']['cidr'].split('/')[-1])
itf_port = self.plugin.get_port(self.ctxt, itf['port_id'])
expected = {
'gateway_ip': subnet['subnet']['gateway_ip'],
'mac_address': mac_address,
'ip_address': formatted_ip
'ip_address': formatted_ip,
'gateway_mac': itf_port['mac_address']
}
expected.update(driver._format_bgpvpn_network_route_targets(
[bgpvpn['bgpvpn']]))
actual = driver._retrieve_bgpvpn_network_info_for_port(
context, port['port'])
self.ctxt, port['port'])
self.assertEqual(expected, actual)
def test_bagpipe_get_network_info_for_port(self):
with self.network() as net, \
self.subnet(network=net) as subnet, \
self.router(tenant_id=self._tenant_id) as router, \
self.port(subnet=subnet) as port:
itf = self._router_interface_action('add',
router['router']['id'],
subnet['subnet']['id'],
None)
itf_port = self.plugin.get_port(self.ctxt, itf['port_id'])
r = bagpipe.get_network_info_for_port(self.ctxt,
port['port']['id'],
net['network']['id'])
expected_ip = port['port']['fixed_ips'][0]['ip_address'] + "/24"
self.assertEqual({
'mac_address': port['port']['mac_address'],
'ip_address': expected_ip,
'gateway_ip': subnet['subnet']['gateway_ip'],
'gateway_mac': itf_port['mac_address']
}, r)
RT = '12345:1'
BGPVPN_INFO = {'mac_address': 'de:ad:00:00:be:ef',
'ip_address': '10.0.0.2',
'gateway_ip': '10.0.0.1',
'l3vpn': {'import_rt': ['12345:1'],
'export_rt': ['12345:1']
}
'l3vpn': {'import_rt': [RT],
'export_rt': [RT]
},
'gateway_mac': None
}
@@ -296,11 +317,6 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
return_value=BGPVPN_INFO)
self.patched_driver.start()
self.mock_attach_rpc = self.mocked_bagpipeAPI.attach_port_on_bgpvpn
self.mock_detach_rpc = self.mocked_bagpipeAPI.detach_port_from_bgpvpn
self.mock_update_bgpvpn_rpc = self.mocked_bagpipeAPI.update_bgpvpn
self.mock_delete_bgpvpn_rpc = self.mocked_bagpipeAPI.delete_bgpvpn
# we choose an agent of type const.AGENT_TYPE_OFA
# because this is the type used by the fake_agent mech driver
helpers.register_ovs_agent(helpers.HOST, const.AGENT_TYPE_OFA)
@@ -544,9 +560,10 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
port=port['port'],
original_port=original_port
)
self.mock_update_bgpvpn_rpc.assert_called_once_with(
self.mock_update_rpc.assert_called_once_with(
mock.ANY,
self.bagpipe_driver._format_bgpvpn(bgpvpn['bgpvpn'],
self.bagpipe_driver._format_bgpvpn(self.ctxt,
bgpvpn['bgpvpn'],
port['port']['network_id']))
def test_bagpipe_callback_to_rpc_update_port_router_itf_removed(self):
@@ -569,9 +586,10 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
port=port['port'],
original_port=original_port
)
self.mock_delete_bgpvpn_rpc.assert_called_once_with(
self.mock_delete_rpc.assert_called_once_with(
mock.ANY,
self.bagpipe_driver._format_bgpvpn(bgpvpn['bgpvpn'],
self.bagpipe_driver._format_bgpvpn(self.ctxt,
bgpvpn['bgpvpn'],
port['port']['network_id']))
def test_l3agent_add_remove_router_interface_to_bgpvpn_rpc(self):
@@ -591,19 +609,71 @@ class TestBagpipeServiceDriverCallbacks(TestBagpipeCommon):
router['router']['id'],
subnet['subnet']['id'],
None)
self.mock_update_bgpvpn_rpc.assert_called_once_with(
self.mock_update_rpc.assert_called_once_with(
mock.ANY,
self.bagpipe_driver._format_bgpvpn(bgpvpn['bgpvpn'],
self.bagpipe_driver._format_bgpvpn(self.ctxt,
bgpvpn['bgpvpn'],
net['network']['id']))
self._router_interface_action('remove',
router['router']['id'],
subnet['subnet']['id'],
None)
self.mock_delete_bgpvpn_rpc.assert_called_once_with(
self.mock_delete_rpc.assert_called_once_with(
mock.ANY,
self.bagpipe_driver._format_bgpvpn(bgpvpn['bgpvpn'],
self.bagpipe_driver._format_bgpvpn(self.ctxt,
bgpvpn['bgpvpn'],
net['network']['id']))
def test_gateway_mac_info_rpc(self):
BGPVPN_INFO_GW_MAC = copy.copy(BGPVPN_INFO)
BGPVPN_INFO_GW_MAC.update(gateway_mac='aa:bb:cc:dd:ee:ff')
self.patched_driver.stop()
with self.network() as net, \
self.subnet(network=net) as subnet, \
self.router(tenant_id=self._tenant_id) as router, \
self.bgpvpn(route_targets=[RT]) as bgpvpn, \
self.port(subnet=subnet,
arg_list=(portbindings.HOST_ID,),
**{portbindings.HOST_ID: helpers.HOST}) as port, \
self.assoc_net(bgpvpn['bgpvpn']['id'],
net['network']['id']), \
mock.patch.object(self.bgpvpn_plugin.driver,
'retrieve_bgpvpns_of_router_assocs'
'_by_network',
return_value=[{'type': 'l3',
'route_targets': [RT]}]
):
self._update_port_status(port, const.PORT_STATUS_ACTIVE)
itf = self._router_interface_action('add',
router['router']['id'],
subnet['subnet']['id'],
None)
itf_port = self.plugin.get_port(self.ctxt, itf['port_id'])
self.mock_update_rpc.assert_called_with(
mock.ANY,
_expected_formatted_bgpvpn(bgpvpn['bgpvpn']['id'],
net['network']['id'],
[RT],
gateway_mac=itf_port['mac_address'])
)
self._router_interface_action('remove',
router['router']['id'],
subnet['subnet']['id'],
None)
self.mock_update_rpc.assert_called_with(
mock.ANY,
_expected_formatted_bgpvpn(bgpvpn['bgpvpn']['id'],
net['network']['id'],
[RT],
gateway_mac=None)
)
self.patched_driver.start()
def test_l2agent_rpc_to_bgpvpn_rpc(self):
#
# Test that really simulate the ML2 codepath that
@@ -732,7 +802,6 @@ class TestOVSAgentExtension(ovs_test_base.OVSOFCtlTestBase):
def setUp(self):
super(TestOVSAgentExtension, self).setUp()
self.agent_ext = bagpipe_agt_ext.BagpipeBgpvpnAgentExtension()
self.context = n_context.get_admin_context()
self.connection = mock.Mock()
@mock.patch('networking_bagpipe.agent.bagpipe_bgp_agent.BaGPipeBGPAgent')
@@ -0,0 +1,13 @@
---
prelude:>
The ovs/bagpipe driver now let you use both a Neutron
router and a BGPVPN association simultaneously on a
given Port.
features:
- The bagpipe driver now let happily coexist a BGPVPN
association and a Neutron router. Traffic that does
not match any VPN route will be handled by the Neutron
router. This evolution depends on corresponding evolutions
in networking-bagpipe and bagpipe-bgp.
(`see bug 1627645 <https://bugs.launchpad.net/networking-bgpvpn/+bug/1627645>`_)
Reference in New Issue
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.