Add Queries For BGP Route Lookups

This patch contains code for looking in the Neutron DB and identifying
next-hops for tenant networks and floating IP's. These queries use the
centralized router as the next-hop and ignore host routes attached to
a distributed router.

Partially-Implements: blueprint bgp-dynamic-routing
Co-Authored-By: vikram.choudhary <vikram.choudhary@huawei.com>
Change-Id: If08d6595d9bc657a7ecfb487e8df40860837d200
This commit is contained in:
Ryan Tidwell 2016-01-03 20:30:08 +05:30
parent ed95209657
commit 18a8e1bc04
6 changed files with 1198 additions and 3 deletions

View File

@ -12,22 +12,33 @@
# License for the specific language governing permissions and limitations
# under the License.
import itertools
from oslo_db import exception as oslo_db_exc
from oslo_log import log as logging
from oslo_utils import uuidutils
import sqlalchemy as sa
from sqlalchemy import and_
from sqlalchemy import orm
from sqlalchemy.orm import aliased
from sqlalchemy.orm import exc as sa_exc
from neutron_lib import constants as lib_consts
from neutron.api.v2 import attributes as attr
from neutron.common import exceptions as n_exc
from neutron.db import address_scope_db
from neutron.db import common_db_mixin as common_db
from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db import model_base
from neutron.db import models_v2
from neutron.extensions import bgp as bgp_ext
LOG = logging.getLogger(__name__)
DEVICE_OWNER_ROUTER_GW = lib_consts.DEVICE_OWNER_ROUTER_GW
DEVICE_OWNER_ROUTER_INTF = lib_consts.DEVICE_OWNER_ROUTER_INTF
class BgpSpeakerPeerBinding(model_base.BASEV2):
@ -140,7 +151,9 @@ class BgpDbMixin(common_db.CommonDbMixin):
res['peers'] = self.get_bgp_peers_by_bgp_speaker(context,
bgp_speaker['id'],
fields=bgp_peer_attrs)
res['advertised_routes'] = []
res['advertised_routes'] = self.get_routes_by_bgp_speaker_id(
context,
bgp_speaker_id)
return res
def update_bgp_speaker(self, context, bgp_speaker_id, bgp_speaker):
@ -267,8 +280,30 @@ class BgpDbMixin(common_db.CommonDbMixin):
except sa_exc.NoResultFound:
raise bgp_ext.BgpSpeakerNotFound(id=bgp_speaker_id)
def _get_bgp_speaker_ids_by_router(self, context, router_id):
with context.session.begin(subtransactions=True):
network_binding = aliased(BgpSpeakerNetworkBinding)
r_port = aliased(l3_db.RouterPort)
query = context.session.query(network_binding.bgp_speaker_id)
query = query.filter(
r_port.router_id == router_id,
r_port.port_type == lib_consts.DEVICE_OWNER_ROUTER_GW,
r_port.port_id == models_v2.Port.id,
models_v2.Port.network_id == network_binding.network_id)
return [binding.bgp_speaker_id for binding in query.all()]
def _get_bgp_speaker_ids_by_binding_network(self, context, network_id):
with context.session.begin(subtransactions=True):
query = context.session.query(
BgpSpeakerNetworkBinding.bgp_speaker_id)
query = query.filter(
BgpSpeakerNetworkBinding.network_id == network_id)
return query.all()
def get_advertised_routes(self, context, bgp_speaker_id):
return self._make_advertised_routes_dict([])
routes = self.get_routes_by_bgp_speaker_id(context, bgp_speaker_id)
return self._make_advertised_routes_dict(routes)
def _get_id_for(self, resource, id_name):
try:
@ -406,3 +441,473 @@ class BgpDbMixin(common_db.CommonDbMixin):
'auth_type', 'password']
res = dict((k, bgp_peer[k]) for k in attrs)
return self._fields(res, fields)
def _get_address_scope_ids_for_bgp_speaker(self, context, bgp_speaker_id):
with context.session.begin(subtransactions=True):
binding = aliased(BgpSpeakerNetworkBinding)
address_scope = aliased(address_scope_db.AddressScope)
query = context.session.query(address_scope)
query = query.filter(
binding.bgp_speaker_id == bgp_speaker_id,
models_v2.Subnet.ip_version == binding.ip_version,
models_v2.Subnet.network_id == binding.network_id,
models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id,
models_v2.SubnetPool.address_scope_id == address_scope.id)
return [scope.id for scope in query.all()]
def get_routes_by_bgp_speaker_id(self, context, bgp_speaker_id):
"""Get all routes that should be advertised by a BgpSpeaker."""
with context.session.begin(subtransactions=True):
net_routes = self._get_tenant_network_routes_by_bgp_speaker(
context,
bgp_speaker_id)
fip_routes = self._get_central_fip_host_routes_by_bgp_speaker(
context,
bgp_speaker_id)
return itertools.chain(fip_routes, net_routes)
def get_routes_by_bgp_speaker_binding(self, context,
bgp_speaker_id, network_id):
"""Get all routes for the given bgp_speaker binding."""
with context.session.begin(subtransactions=True):
fip_routes = self._get_central_fip_host_routes_by_binding(
context,
network_id,
bgp_speaker_id)
net_routes = self._get_tenant_network_routes_by_binding(
context,
network_id,
bgp_speaker_id)
return itertools.chain(fip_routes, net_routes)
def _get_routes_by_router(self, context, router_id):
bgp_speaker_ids = self._get_bgp_speaker_ids_by_router(context,
router_id)
route_dict = {}
for bgp_speaker_id in bgp_speaker_ids:
fip_routes = self._get_central_fip_host_routes_by_router(
context,
router_id,
bgp_speaker_id)
net_routes = self._get_tenant_network_routes_by_router(
context,
router_id,
bgp_speaker_id)
routes = list(itertools.chain(fip_routes, net_routes))
route_dict[bgp_speaker_id] = routes
return route_dict
def _get_central_fip_host_routes_by_router(self, context, router_id,
bgp_speaker_id):
"""Get floating IP host routes with the given router as nexthop."""
with context.session.begin(subtransactions=True):
dest_alias = aliased(l3_db.FloatingIP,
name='destination')
next_hop_alias = aliased(models_v2.IPAllocation,
name='next_hop')
binding_alias = aliased(BgpSpeakerNetworkBinding,
name='binding')
router_attrs = aliased(l3_attrs_db.RouterExtraAttributes,
name='router_attrs')
query = context.session.query(dest_alias.floating_ip_address,
next_hop_alias.ip_address)
query = query.join(
next_hop_alias,
next_hop_alias.network_id == dest_alias.floating_network_id)
query = query.join(l3_db.Router,
dest_alias.router_id == l3_db.Router.id)
query = query.filter(
l3_db.Router.id == router_id,
dest_alias.router_id == l3_db.Router.id,
l3_db.Router.id == router_attrs.router_id,
router_attrs.distributed == sa.sql.false(),
l3_db.Router.gw_port_id == next_hop_alias.port_id,
next_hop_alias.subnet_id == models_v2.Subnet.id,
models_v2.Subnet.ip_version == 4,
binding_alias.network_id == models_v2.Subnet.network_id,
binding_alias.bgp_speaker_id == bgp_speaker_id,
binding_alias.ip_version == 4,
BgpSpeaker.advertise_floating_ip_host_routes == sa.sql.true())
query = query.outerjoin(router_attrs,
l3_db.Router.id == router_attrs.router_id)
query = query.filter(router_attrs.distributed != sa.sql.true())
return self._host_route_list_from_tuples(query.all())
def _get_central_fip_host_routes_by_binding(self, context,
network_id, bgp_speaker_id):
"""Get all floating IP host routes for the given network binding."""
with context.session.begin(subtransactions=True):
# Query the DB for floating IP's and the IP address of the
# gateway port
dest_alias = aliased(l3_db.FloatingIP,
name='destination')
next_hop_alias = aliased(models_v2.IPAllocation,
name='next_hop')
binding_alias = aliased(BgpSpeakerNetworkBinding,
name='binding')
router_attrs = aliased(l3_attrs_db.RouterExtraAttributes,
name='router_attrs')
query = context.session.query(dest_alias.floating_ip_address,
next_hop_alias.ip_address)
query = query.join(
next_hop_alias,
next_hop_alias.network_id == dest_alias.floating_network_id)
query = query.join(
binding_alias,
binding_alias.network_id == dest_alias.floating_network_id)
query = query.join(l3_db.Router,
dest_alias.router_id == l3_db.Router.id)
query = query.filter(
dest_alias.floating_network_id == network_id,
dest_alias.router_id == l3_db.Router.id,
l3_db.Router.gw_port_id == next_hop_alias.port_id,
next_hop_alias.subnet_id == models_v2.Subnet.id,
models_v2.Subnet.ip_version == 4,
binding_alias.network_id == models_v2.Subnet.network_id,
binding_alias.bgp_speaker_id == BgpSpeaker.id,
BgpSpeaker.id == bgp_speaker_id,
BgpSpeaker.advertise_floating_ip_host_routes == sa.sql.true())
query = query.outerjoin(router_attrs,
l3_db.Router.id == router_attrs.router_id)
query = query.filter(router_attrs.distributed != sa.sql.true())
return self._host_route_list_from_tuples(query.all())
def _get_central_fip_host_routes_by_bgp_speaker(self, context,
bgp_speaker_id):
"""Get all the floating IP host routes advertised by a BgpSpeaker."""
with context.session.begin(subtransactions=True):
dest_alias = aliased(l3_db.FloatingIP,
name='destination')
next_hop_alias = aliased(models_v2.IPAllocation,
name='next_hop')
speaker_binding = aliased(BgpSpeakerNetworkBinding,
name="speaker_network_mapping")
router_attrs = aliased(l3_attrs_db.RouterExtraAttributes,
name='router_attrs')
query = context.session.query(dest_alias.floating_ip_address,
next_hop_alias.ip_address)
query = query.select_from(dest_alias,
BgpSpeaker,
l3_db.Router,
models_v2.Subnet)
query = query.join(
next_hop_alias,
next_hop_alias.network_id == dest_alias.floating_network_id)
query = query.join(
speaker_binding,
speaker_binding.network_id == dest_alias.floating_network_id)
query = query.join(l3_db.Router,
dest_alias.router_id == l3_db.Router.id)
query = query.filter(
BgpSpeaker.id == bgp_speaker_id,
BgpSpeaker.advertise_floating_ip_host_routes,
speaker_binding.bgp_speaker_id == BgpSpeaker.id,
dest_alias.floating_network_id == speaker_binding.network_id,
next_hop_alias.network_id == speaker_binding.network_id,
dest_alias.router_id == l3_db.Router.id,
l3_db.Router.gw_port_id == next_hop_alias.port_id,
next_hop_alias.subnet_id == models_v2.Subnet.id,
models_v2.Subnet.ip_version == 4)
query = query.outerjoin(router_attrs,
l3_db.Router.id == router_attrs.router_id)
query = query.filter(router_attrs.distributed != sa.sql.true())
return self._host_route_list_from_tuples(query.all())
def _get_tenant_network_routes_by_binding(self, context,
network_id, bgp_speaker_id):
"""Get all tenant network routes for the given network."""
with context.session.begin(subtransactions=True):
tenant_networks_query = self._tenant_networks_by_network_query(
context,
network_id,
bgp_speaker_id)
nexthops_query = self._nexthop_ip_addresses_by_binding_query(
context,
network_id,
bgp_speaker_id)
join_q = self._join_tenant_networks_to_next_hops(
context,
tenant_networks_query.subquery(),
nexthops_query.subquery())
return self._make_advertised_routes_list(join_q.all())
def _get_tenant_network_routes_by_router(self, context, router_id,
bgp_speaker_id):
"""Get all tenant network routes with the given router as nexthop."""
with context.session.begin(subtransactions=True):
scopes = self._get_address_scope_ids_for_bgp_speaker(
context,
bgp_speaker_id)
address_scope = aliased(address_scope_db.AddressScope)
inside_query = context.session.query(
models_v2.Subnet.cidr,
models_v2.IPAllocation.ip_address,
address_scope.id)
outside_query = context.session.query(
address_scope.id,
models_v2.IPAllocation.ip_address)
speaker_binding = aliased(BgpSpeakerNetworkBinding,
name="speaker_network_mapping")
port_alias = aliased(l3_db.RouterPort, name='routerport')
inside_query = inside_query.filter(
port_alias.router_id == router_id,
models_v2.IPAllocation.port_id == port_alias.port_id,
models_v2.IPAllocation.subnet_id == models_v2.Subnet.id,
models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id,
models_v2.SubnetPool.address_scope_id == address_scope.id,
address_scope.id.in_(scopes),
port_alias.port_type != lib_consts.DEVICE_OWNER_ROUTER_GW,
speaker_binding.bgp_speaker_id == bgp_speaker_id)
outside_query = outside_query.filter(
port_alias.router_id == router_id,
port_alias.port_type == lib_consts.DEVICE_OWNER_ROUTER_GW,
models_v2.IPAllocation.port_id == port_alias.port_id,
models_v2.IPAllocation.subnet_id == models_v2.Subnet.id,
models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id,
models_v2.SubnetPool.address_scope_id == address_scope.id,
address_scope.id.in_(scopes),
speaker_binding.bgp_speaker_id == bgp_speaker_id,
speaker_binding.network_id == models_v2.Port.network_id,
port_alias.port_id == models_v2.Port.id)
inside_query = inside_query.subquery()
outside_query = outside_query.subquery()
join_query = context.session.query(inside_query.c.cidr,
outside_query.c.ip_address)
and_cond = and_(inside_query.c.id == outside_query.c.id)
join_query = join_query.join(outside_query, and_cond)
return self._make_advertised_routes_list(join_query.all())
def _get_tenant_network_routes_by_bgp_speaker(self, context,
bgp_speaker_id):
"""Get all tenant network routes to be advertised by a BgpSpeaker."""
with context.session.begin(subtransactions=True):
tenant_nets_q = self._tenant_networks_by_bgp_speaker_query(
context,
bgp_speaker_id)
nexthops_q = self._nexthop_ip_addresses_by_bgp_speaker_query(
context,
bgp_speaker_id)
join_q = self._join_tenant_networks_to_next_hops(
context,
tenant_nets_q.subquery(),
nexthops_q.subquery())
return self._make_advertised_routes_list(join_q.all())
def _join_tenant_networks_to_next_hops(self, context,
tenant_networks_subquery,
nexthops_subquery):
"""Join subquery for tenant networks to subquery for nexthop IP's"""
left_subq = tenant_networks_subquery
right_subq = nexthops_subquery
join_query = context.session.query(left_subq.c.cidr,
right_subq.c.ip_address)
and_cond = and_(left_subq.c.router_id == right_subq.c.router_id,
left_subq.c.ip_version == right_subq.c.ip_version)
join_query = join_query.join(right_subq, and_cond)
return join_query
def _tenant_networks_by_network_query(self, context,
network_id, bgp_speaker_id):
"""Return subquery for tenant networks by binding network ID"""
address_scope = aliased(address_scope_db.AddressScope,
name='address_scope')
router_attrs = aliased(l3_attrs_db.RouterExtraAttributes,
name='router_attrs')
tenant_networks_query = context.session.query(
l3_db.RouterPort.router_id,
models_v2.Subnet.cidr,
models_v2.Subnet.ip_version,
address_scope.id)
tenant_networks_query = tenant_networks_query.filter(
l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_GW,
l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_SNAT,
l3_db.RouterPort.router_id == router_attrs.router_id,
models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id,
models_v2.IPAllocation.subnet_id == models_v2.Subnet.id,
models_v2.Subnet.network_id != network_id,
models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id,
models_v2.SubnetPool.address_scope_id == address_scope.id,
BgpSpeaker.id == bgp_speaker_id,
BgpSpeaker.ip_version == address_scope.ip_version,
models_v2.Subnet.ip_version == address_scope.ip_version)
return tenant_networks_query
def _tenant_networks_by_bgp_speaker_query(self, context, bgp_speaker_id):
"""Return subquery for tenant networks by binding bgp_speaker_id"""
router_id = l3_db.RouterPort.router_id.distinct().label('router_id')
tenant_nets_subq = context.session.query(router_id,
models_v2.Subnet.cidr,
models_v2.Subnet.ip_version)
scopes = self._get_address_scope_ids_for_bgp_speaker(context,
bgp_speaker_id)
filters = self._tenant_networks_by_bgp_speaker_filters(scopes)
tenant_nets_subq = tenant_nets_subq.filter(*filters)
return tenant_nets_subq
def _tenant_networks_by_bgp_speaker_filters(self, address_scope_ids):
"""Return the filters for querying tenant networks by BGP speaker"""
router_attrs = aliased(l3_attrs_db.RouterExtraAttributes,
name='router_attrs')
return [models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id,
l3_db.RouterPort.router_id == router_attrs.router_id,
l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_GW,
l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_SNAT,
models_v2.IPAllocation.subnet_id == models_v2.Subnet.id,
models_v2.Subnet.network_id != BgpSpeakerNetworkBinding.network_id,
models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id,
models_v2.SubnetPool.address_scope_id.in_(address_scope_ids),
models_v2.Subnet.ip_version == BgpSpeakerNetworkBinding.ip_version,
BgpSpeakerNetworkBinding.bgp_speaker_id == BgpSpeaker.id,
BgpSpeaker.advertise_tenant_networks == sa.sql.true()]
def _nexthop_ip_addresses_by_binding_query(self, context,
network_id, bgp_speaker_id):
"""Return the subquery for locating nexthops by binding network"""
nexthops_query = context.session.query(
l3_db.RouterPort.router_id,
models_v2.IPAllocation.ip_address,
models_v2.Subnet.ip_version)
filters = self._next_hop_ip_addresses_by_binding_filters(
network_id,
bgp_speaker_id)
nexthops_query = nexthops_query.filter(*filters)
return nexthops_query
def _next_hop_ip_addresses_by_binding_filters(self,
network_id,
bgp_speaker_id):
"""Return the filters for querying nexthops by binding network"""
address_scope = aliased(address_scope_db.AddressScope,
name='address_scope')
return [models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id,
models_v2.IPAllocation.subnet_id == models_v2.Subnet.id,
BgpSpeaker.id == bgp_speaker_id,
BgpSpeakerNetworkBinding.bgp_speaker_id == BgpSpeaker.id,
BgpSpeakerNetworkBinding.network_id == network_id,
models_v2.Subnet.network_id == BgpSpeakerNetworkBinding.network_id,
models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id,
models_v2.SubnetPool.address_scope_id == address_scope.id,
models_v2.Subnet.ip_version == address_scope.ip_version,
l3_db.RouterPort.port_type == DEVICE_OWNER_ROUTER_GW]
def _nexthop_ip_addresses_by_bgp_speaker_query(self, context,
bgp_speaker_id):
"""Return the subquery for locating nexthops by BGP speaker"""
nexthops_query = context.session.query(
l3_db.RouterPort.router_id,
models_v2.IPAllocation.ip_address,
models_v2.Subnet.ip_version)
filters = self._next_hop_ip_addresses_by_bgp_speaker_filters(
bgp_speaker_id)
nexthops_query = nexthops_query.filter(*filters)
return nexthops_query
def _next_hop_ip_addresses_by_bgp_speaker_filters(self, bgp_speaker_id):
"""Return the filters for querying nexthops by BGP speaker"""
router_attrs = aliased(l3_attrs_db.RouterExtraAttributes,
name='router_attrs')
return [l3_db.RouterPort.port_type == DEVICE_OWNER_ROUTER_GW,
l3_db.RouterPort.router_id == router_attrs.router_id,
BgpSpeakerNetworkBinding.network_id == models_v2.Subnet.network_id,
BgpSpeakerNetworkBinding.ip_version == models_v2.Subnet.ip_version,
BgpSpeakerNetworkBinding.bgp_speaker_id == bgp_speaker_id,
models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id,
models_v2.IPAllocation.subnet_id == models_v2.Subnet.id]
def _tenant_prefixes_by_router(self, context, router_id, bgp_speaker_id):
with context.session.begin(subtransactions=True):
query = context.session.query(models_v2.Subnet.cidr.distinct())
filters = self._tenant_prefixes_by_router_filters(router_id,
bgp_speaker_id)
query = query.filter(*filters)
return [x[0] for x in query.all()]
def _tenant_prefixes_by_router_filters(self, router_id, bgp_speaker_id):
binding = aliased(BgpSpeakerNetworkBinding, name='network_binding')
subnetpool = aliased(models_v2.SubnetPool,
name='subnetpool')
router_attrs = aliased(l3_attrs_db.RouterExtraAttributes,
name='router_attrs')
return [models_v2.Subnet.id == models_v2.IPAllocation.subnet_id,
models_v2.Subnet.subnetpool_id == subnetpool.id,
l3_db.RouterPort.router_id == router_id,
l3_db.Router.id == l3_db.RouterPort.router_id,
l3_db.Router.id == router_attrs.router_id,
l3_db.Router.gw_port_id == models_v2.Port.id,
models_v2.Port.network_id == binding.network_id,
binding.bgp_speaker_id == BgpSpeaker.id,
l3_db.RouterPort.port_type == DEVICE_OWNER_ROUTER_INTF,
models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id]
def _tenant_prefixes_by_router_interface(self,
context,
router_port_id,
bgp_speaker_id):
with context.session.begin(subtransactions=True):
query = context.session.query(models_v2.Subnet.cidr.distinct())
filters = self._tenant_prefixes_by_router_filters(router_port_id,
bgp_speaker_id)
query = query.filter(*filters)
return [x[0] for x in query.all()]
def _tenant_prefixes_by_router_port_filters(self,
router_port_id,
bgp_speaker_id):
binding = aliased(BgpSpeakerNetworkBinding, name='network_binding')
return [models_v2.Subnet.id == models_v2.IPAllocation.subnet_id,
l3_db.RouterPort.port_id == router_port_id,
l3_db.Router.id == l3_db.RouterPort.router_id,
l3_db.Router.gw_port_id == models_v2.Port.id,
models_v2.Port.network_id == binding.network_id,
binding.bgp_speaker_id == BgpSpeaker.id,
models_v2.Subnet.ip_version == binding.ip_version,
l3_db.RouterPort.port_type == DEVICE_OWNER_ROUTER_INTF,
models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id]
def _bgp_speakers_for_gateway_network(self, context, network_id):
"""Return all BgpSpeakers for the given gateway network"""
with context.session.begin(subtransactions=True):
query = context.session.query(BgpSpeaker)
query = query.filter(
BgpSpeakerNetworkBinding.network_id == network_id,
BgpSpeakerNetworkBinding.bgp_speaker_id == BgpSpeaker.id)
try:
return query.all()
except sa_exc.NoResultFound:
raise bgp_ext.NetworkNotBound(network_id=network_id)
def _bgp_speaker_for_gateway_network(self, context,
network_id, ip_version):
"""Return the BgpSpeaker by given gateway network and ip_version"""
with context.session.begin(subtransactions=True):
query = context.session.query(BgpSpeaker)
query = query.filter(
BgpSpeakerNetworkBinding.network_id == network_id,
BgpSpeakerNetworkBinding.bgp_speaker_id == BgpSpeaker.id,
BgpSpeakerNetworkBinding.ip_version == ip_version)
try:
return query.one()
except sa_exc.NoResultFound:
raise bgp_ext.NetworkNotBoundForIpVersion(
network_id=network_id,
ip_version=ip_version)
def _make_advertised_routes_list(self, routes):
route_list = ({'destination': x,
'next_hop': y} for x, y in routes)
return route_list
def _route_list_from_prefixes_and_next_hop(self, routes, next_hop):
route_list = [{'destination': x,
'next_hop': next_hop} for x in routes]
return route_list
def _host_route_list_from_tuples(self, ip_next_hop_tuples):
"""Return the list of host routes given a list of (IP, nexthop)"""
return ({'destination': x + '/32',
'next_hop': y} for x, y in ip_next_hop_tuples)

View File

@ -154,6 +154,11 @@ class InvalidBgpPeerMd5Authentication(exceptions.BadRequest):
message = _("A password must be supplied when using auth_type md5.")
class NetworkNotBoundForIpVersion(NetworkNotBound):
message = _("Network %(network_id)s is not bound to a IPv%(ip_version)s "
"BgpSpeaker.")
class Bgp(extensions.ExtensionDescriptor):
@classmethod

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import netaddr
from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
@ -41,8 +42,25 @@ class BgpSpeakerTestJSONBase(base.BaseAdminNetworkTest):
msg = "BGP Speaker extension is not enabled."
raise cls.skipException(msg)
cls.admin_routerports = []
cls.admin_floatingips = []
cls.admin_routers = []
cls.ext_net_id = CONF.network.public_network_id
@classmethod
def resource_cleanup(cls):
for floatingip in cls.admin_floatingips:
cls._try_delete_resource(cls.admin_client.delete_floatingip,
floatingip['id'])
for routerport in cls.admin_routerports:
cls._try_delete_resource(
cls.admin_client.remove_router_interface_with_subnet_id,
routerport['router_id'], routerport['subnet_id'])
for router in cls.admin_routers:
cls._try_delete_resource(cls.admin_client.delete_router,
router['id'])
super(BgpSpeakerTestJSONBase, cls).resource_cleanup()
def create_bgp_speaker(self, auto_delete=True, **args):
data = {'bgp_speaker': args}
bgp_speaker = self.admin_client.create_bgp_speaker(data)
@ -171,3 +189,94 @@ class BgpSpeakerTestJSON(BgpSpeakerTestJSONBase):
bgp_speaker = self.admin_client.get_bgp_speaker(bgp_speaker_id)
network_list = bgp_speaker['bgp-speaker']['networks']
self.assertTrue(not network_list)
@test.idempotent_id('5bef22ad-5e70-4f7b-937a-dc1944642996')
def test_get_advertised_routes_null_address_scope(self):
self.useFixture(fixtures.LockFixture('gateway_network_binding'))
bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args)
bgp_speaker_id = bgp_speaker['bgp-speaker']['id']
self.admin_client.add_bgp_gateway_network(bgp_speaker_id,
self.ext_net_id)
routes = self.admin_client.get_bgp_advertised_routes(bgp_speaker_id)
self.assertEqual(0, len(routes['advertised_routes']))
@test.idempotent_id('cae9cdb1-ad65-423c-9604-d4cd0073616e')
def test_get_advertised_routes_floating_ips(self):
self.useFixture(fixtures.LockFixture('gateway_network_binding'))
bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args)
bgp_speaker_id = bgp_speaker['bgp-speaker']['id']
self.admin_client.add_bgp_gateway_network(bgp_speaker_id,
self.ext_net_id)
tenant_net = self.create_network()
tenant_subnet = self.create_subnet(tenant_net)
ext_gw_info = {'network_id': self.ext_net_id}
router = self.admin_client.create_router(
'my-router',
external_gateway_info=ext_gw_info,
admin_state_up=True,
distributed=False)
self.admin_routers.append(router['router'])
self.admin_client.add_router_interface_with_subnet_id(
router['router']['id'],
tenant_subnet['id'])
self.admin_routerports.append({'router_id': router['router']['id'],
'subnet_id': tenant_subnet['id']})
tenant_port = self.create_port(tenant_net)
floatingip = self.create_floatingip(self.ext_net_id)
self.admin_floatingips.append(floatingip)
self.client.update_floatingip(floatingip['id'],
port_id=tenant_port['id'])
routes = self.admin_client.get_bgp_advertised_routes(bgp_speaker_id)
self.assertEqual(1, len(routes['advertised_routes']))
self.assertEqual(floatingip['floating_ip_address'] + '/32',
routes['advertised_routes'][0]['destination'])
@test.idempotent_id('c9ad566e-fe8f-4559-8303-bbad9062a30c')
def test_get_advertised_routes_tenant_networks(self):
self.useFixture(fixtures.LockFixture('gateway_network_binding'))
addr_scope = self.create_address_scope('my-scope', ip_version=4)
ext_net = self.create_shared_network(**{'router:external': True})
tenant_net = self.create_network()
ext_subnetpool = self.create_subnetpool(
'test-pool-ext',
is_admin=True,
default_prefixlen=24,
address_scope_id=addr_scope['id'],
prefixes=['8.0.0.0/8'])
tenant_subnetpool = self.create_subnetpool(
'tenant-test-pool',
default_prefixlen=25,
address_scope_id=addr_scope['id'],
prefixes=['10.10.0.0/16'])
self.create_subnet({'id': ext_net['id']},
cidr=netaddr.IPNetwork('8.0.0.0/24'),
ip_version=4,
client=self.admin_client,
subnetpool_id=ext_subnetpool['id'])
tenant_subnet = self.create_subnet(
{'id': tenant_net['id']},
cidr=netaddr.IPNetwork('10.10.0.0/24'),
ip_version=4,
subnetpool_id=tenant_subnetpool['id'])
ext_gw_info = {'network_id': ext_net['id']}
router = self.admin_client.create_router(
'my-router',
external_gateway_info=ext_gw_info,
distributed=False)['router']
self.admin_routers.append(router)
self.admin_client.add_router_interface_with_subnet_id(
router['id'],
tenant_subnet['id'])
self.admin_routerports.append({'router_id': router['id'],
'subnet_id': tenant_subnet['id']})
bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args)
bgp_speaker_id = bgp_speaker['bgp-speaker']['id']
self.admin_client.add_bgp_gateway_network(bgp_speaker_id,
ext_net['id'])
routes = self.admin_client.get_bgp_advertised_routes(bgp_speaker_id)
self.assertEqual(1, len(routes['advertised_routes']))
self.assertEqual(tenant_subnet['cidr'],
routes['advertised_routes'][0]['destination'])
fixed_ip = router['external_gateway_info']['external_fixed_ips'][0]
self.assertEqual(fixed_ip['ip_address'],
routes['advertised_routes'][0]['next_hop'])

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import netaddr
from tempest.lib import exceptions as lib_exc
from neutron.tests.api import test_bgp_speaker_extensions as test_base
@ -51,3 +52,69 @@ class BgpSpeakerTestJSONNegative(test_base.BgpSpeakerTestJSONBase):
self.assertRaises(lib_exc.BadRequest, self.update_bgp_speaker,
bgp_speaker_id, local_as='4321')
@test.idempotent_id('9cc33701-51e5-421f-a5d5-fd7b330e550f')
def test_get_advertised_routes_tenant_networks(self):
addr_scope1 = self.create_address_scope('my-scope1', ip_version=4)
addr_scope2 = self.create_address_scope('my-scope2', ip_version=4)
ext_net = self.create_shared_network(**{'router:external': True})
tenant_net1 = self.create_network()
tenant_net2 = self.create_network()
ext_subnetpool = self.create_subnetpool(
'test-pool-ext',
is_admin=True,
default_prefixlen=24,
address_scope_id=addr_scope1['id'],
prefixes=['8.0.0.0/8'])
tenant_subnetpool1 = self.create_subnetpool(
'tenant-test-pool',
default_prefixlen=25,
address_scope_id=addr_scope1['id'],
prefixes=['10.10.0.0/16'])
tenant_subnetpool2 = self.create_subnetpool(
'tenant-test-pool',
default_prefixlen=25,
address_scope_id=addr_scope2['id'],
prefixes=['11.10.0.0/16'])
self.create_subnet({'id': ext_net['id']},
cidr=netaddr.IPNetwork('8.0.0.0/24'),
ip_version=4,
client=self.admin_client,
subnetpool_id=ext_subnetpool['id'])
tenant_subnet1 = self.create_subnet(
{'id': tenant_net1['id']},
cidr=netaddr.IPNetwork('10.10.0.0/24'),
ip_version=4,
subnetpool_id=tenant_subnetpool1['id'])
tenant_subnet2 = self.create_subnet(
{'id': tenant_net2['id']},
cidr=netaddr.IPNetwork('11.10.0.0/24'),
ip_version=4,
subnetpool_id=tenant_subnetpool2['id'])
ext_gw_info = {'network_id': ext_net['id']}
router = self.admin_client.create_router(
'my-router',
distributed=False,
external_gateway_info=ext_gw_info)['router']
self.admin_routers.append(router)
self.admin_client.add_router_interface_with_subnet_id(
router['id'],
tenant_subnet1['id'])
self.admin_routerports.append({'router_id': router['id'],
'subnet_id': tenant_subnet1['id']})
self.admin_client.add_router_interface_with_subnet_id(
router['id'],
tenant_subnet2['id'])
self.admin_routerports.append({'router_id': router['id'],
'subnet_id': tenant_subnet2['id']})
bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args)
bgp_speaker_id = bgp_speaker['bgp-speaker']['id']
self.admin_client.add_bgp_gateway_network(bgp_speaker_id,
ext_net['id'])
routes = self.admin_client.get_bgp_advertised_routes(bgp_speaker_id)
self.assertEqual(1, len(routes['advertised_routes']))
self.assertEqual(tenant_subnet1['cidr'],
routes['advertised_routes'][0]['destination'])
fixed_ip = router['external_gateway_info']['external_fixed_ips'][0]
self.assertEqual(fixed_ip['ip_address'],
routes['advertised_routes'][0]['next_hop'])

View File

@ -320,6 +320,22 @@ class NetworkClientJSON(service_client.ServiceClient):
body = json.loads(body)
return service_client.ResponseBody(resp, body)
def get_bgp_advertised_routes(self, bgp_speaker_id):
base_uri = '%s/bgp-speakers/%s/get_advertised_routes'
uri = base_uri % (self.uri_prefix, bgp_speaker_id)
resp, body = self.get(uri)
body = {'advertised_routes': self.deserialize_list(body)}
self.expected_success(200, resp.status)
return service_client.ResponseBody(resp, body)
def get_bgp_router_routes(self, router_id):
base_uri = '%s/router-routes/%s'
uri = base_uri % (self.uri_prefix, router_id)
resp, body = self.get(uri)
body = self.deserialize_list(body)
self.expected_success(200, resp.status)
return service_client.ResponseBody(resp, body)
# Common methods that are hard to automate
def create_bulk_network(self, names, shared=False):
network_list = [{'name': name, 'shared': shared} for name in names]

View File

@ -13,10 +13,13 @@
# under the License.
import contextlib
import netaddr
from oslo_utils import uuidutils
from neutron.api.v2 import attributes as attrs
from neutron.common import exceptions as n_exc
from neutron.extensions import bgp
from neutron.extensions import external_net
from neutron import manager
from neutron.plugins.common import constants as p_const
from neutron.services.bgp import bgp_plugin
@ -67,10 +70,79 @@ class BgpEntityCreationMixin(object):
yield bgp_peer
self.bgp_plugin.delete_bgp_peer(self.context, bgp_peer['id'])
@contextlib.contextmanager
def bgp_speaker_with_gateway_network(self, address_scope_id, local_as,
advertise_fip_host_routes=True,
advertise_tenant_networks=True,
network_external=True,
fmt=None, set_context=False):
pass
@contextlib.contextmanager
def bgp_speaker_with_router(self, address_scope_id, local_as,
gw_network_id=None, gw_subnet_ids=None,
tenant_subnet_ids=None,
advertise_fip_host_routes=True,
advertise_tenant_networks=True,
fmt=None, set_context=False,
router_distributed=False):
pass
@contextlib.contextmanager
def router(self, name='bgp-test-router', tenant_id=_uuid(),
admin_state_up=True, **kwargs):
request = {'router': {'tenant_id': tenant_id,
'name': name,
'admin_state_up': admin_state_up}}
for arg in kwargs:
request['router'][arg] = kwargs[arg]
router = self.l3plugin.create_router(self.context, request)
yield router
@contextlib.contextmanager
def router_with_external_and_tenant_networks(
self,
tenant_id=_uuid(),
gw_prefix='8.8.8.0/24',
tenant_prefix='192.168.0.0/16',
address_scope=None,
distributed=False):
prefixes = [gw_prefix, tenant_prefix]
gw_ip_net = netaddr.IPNetwork(gw_prefix)
tenant_ip_net = netaddr.IPNetwork(tenant_prefix)
subnetpool_args = {'tenant_id': tenant_id,
'name': 'bgp-pool'}
if address_scope:
subnetpool_args['address_scope_id'] = address_scope['id']
with self.network() as ext_net, self.network() as int_net,\
self.subnetpool(prefixes, **subnetpool_args) as pool:
subnetpool_id = pool['subnetpool']['id']
gw_net_id = ext_net['network']['id']
with self.subnet(ext_net,
cidr=gw_prefix,
subnetpool_id=subnetpool_id,
ip_version=gw_ip_net.version),\
self.subnet(int_net,
cidr=tenant_prefix,
subnetpool_id=subnetpool_id,
ip_version=tenant_ip_net.version) as int_subnet:
self._update('networks', gw_net_id,
{'network': {external_net.EXTERNAL: True}})
ext_gw_info = {'network_id': gw_net_id}
with self.router(external_gateway_info=ext_gw_info,
distributed=distributed) as router:
router_id = router['id']
router_interface_info = {'subnet_id':
int_subnet['subnet']['id']}
self.l3plugin.add_router_interface(self.context,
router_id,
router_interface_info)
yield router, ext_net, int_net
class BgpTests(test_plugin.Ml2PluginV2TestCase,
BgpEntityCreationMixin):
#FIXME(tidwellr) Lots of duplicated setup code, try to streamline
fmt = 'json'
def setUp(self):
@ -79,6 +151,8 @@ class BgpTests(test_plugin.Ml2PluginV2TestCase,
p_const.L3_ROUTER_NAT)
self.bgp_plugin = bgp_plugin.BgpPlugin()
self.plugin = manager.NeutronManager.get_plugin()
self.l3plugin = manager.NeutronManager.get_service_plugins().get(
p_const.L3_ROUTER_NAT)
@contextlib.contextmanager
def subnetpool_with_address_scope(self, ip_version, prefixes=None,
@ -335,3 +409,422 @@ class BgpTests(test_plugin.Ml2PluginV2TestCase,
self.assertRaises(bgp.InvalidBgpPeerMd5Authentication,
self.bgp_plugin.create_bgp_peer,
self.context, bgp_peer)
def test__get_address_scope_ids_for_bgp_speaker(self):
prefixes1 = ['8.0.0.0/8']
prefixes2 = ['9.0.0.0/8']
prefixes3 = ['10.0.0.0/8']
tenant_id = _uuid()
with self.bgp_speaker(4, 1234) as speaker,\
self.subnetpool_with_address_scope(4,
prefixes=prefixes1,
tenant_id=tenant_id) as sp1,\
self.subnetpool_with_address_scope(4,
prefixes=prefixes2,
tenant_id=tenant_id) as sp2,\
self.subnetpool_with_address_scope(4,
prefixes=prefixes3,
tenant_id=tenant_id) as sp3,\
self.network() as network1, self.network() as network2,\
self.network() as network3:
network1_id = network1['network']['id']
network2_id = network2['network']['id']
network3_id = network3['network']['id']
base_subnet_data = {'allocation_pools': attrs.ATTR_NOT_SPECIFIED,
'cidr': attrs.ATTR_NOT_SPECIFIED,
'prefixlen': attrs.ATTR_NOT_SPECIFIED,
'ip_version': 4,
'enable_dhcp': True,
'dns_nameservers': attrs.ATTR_NOT_SPECIFIED,
'host_routes': attrs.ATTR_NOT_SPECIFIED}
subnet1_data = {'network_id': network1_id,
'subnetpool_id': sp1['id'],
'name': 'subnet1',
'tenant_id': tenant_id}
subnet2_data = {'network_id': network2_id,
'subnetpool_id': sp2['id'],
'name': 'subnet2',
'tenant_id': tenant_id}
subnet3_data = {'network_id': network3_id,
'subnetpool_id': sp3['id'],
'name': 'subnet2',
'tenant_id': tenant_id}
for k in base_subnet_data:
subnet1_data[k] = base_subnet_data[k]
subnet2_data[k] = base_subnet_data[k]
subnet3_data[k] = base_subnet_data[k]
self.plugin.create_subnet(self.context, {'subnet': subnet1_data})
self.plugin.create_subnet(self.context, {'subnet': subnet2_data})
self.plugin.create_subnet(self.context, {'subnet': subnet3_data})
self.bgp_plugin.add_gateway_network(self.context, speaker['id'],
{'network_id': network1_id})
self.bgp_plugin.add_gateway_network(self.context, speaker['id'],
{'network_id': network2_id})
scopes = self.bgp_plugin._get_address_scope_ids_for_bgp_speaker(
self.context,
speaker['id'])
self.assertEqual(2, len(scopes))
self.assertTrue(sp1['address_scope_id'] in scopes)
self.assertTrue(sp2['address_scope_id'] in scopes)
def test_get_routes_by_bgp_speaker_binding(self):
gw_prefix = '172.16.10.0/24'
tenant_prefix = '10.10.10.0/24'
tenant_id = _uuid()
scope_data = {'tenant_id': tenant_id, 'ip_version': 4,
'shared': True, 'name': 'bgp-scope'}
scope = self.plugin.create_address_scope(
self.context,
{'address_scope': scope_data})
with self.router_with_external_and_tenant_networks(
tenant_id=tenant_id,
gw_prefix=gw_prefix,
tenant_prefix=tenant_prefix,
address_scope=scope) as res:
router, ext_net, int_net = res
ext_gw_info = router['external_gateway_info']
gw_net_id = ext_net['network']['id']
with self.bgp_speaker(4, 1234,
networks=[gw_net_id]) as speaker:
bgp_speaker_id = speaker['id']
routes = self.bgp_plugin.get_routes_by_bgp_speaker_binding(
self.context,
bgp_speaker_id,
gw_net_id)
routes = list(routes)
next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address']
self.assertEqual(1, len(routes))
self.assertEqual(tenant_prefix, routes[0]['destination'])
self.assertEqual(next_hop, routes[0]['next_hop'])
def test_get_routes_by_binding_network(self):
gw_prefix = '172.16.10.0/24'
tenant_prefix = '10.10.10.0/24'
tenant_id = _uuid()
scope_data = {'tenant_id': tenant_id, 'ip_version': 4,
'shared': True, 'name': 'bgp-scope'}
scope = self.plugin.create_address_scope(
self.context,
{'address_scope': scope_data})
with self.router_with_external_and_tenant_networks(
tenant_id=tenant_id,
gw_prefix=gw_prefix,
tenant_prefix=tenant_prefix,
address_scope=scope) as res:
router, ext_net, int_net = res
ext_gw_info = router['external_gateway_info']
gw_net_id = ext_net['network']['id']
with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker:
bgp_speaker_id = speaker['id']
routes = self.bgp_plugin.get_routes_by_bgp_speaker_binding(
self.context,
bgp_speaker_id,
gw_net_id)
routes = list(routes)
next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address']
self.assertEqual(1, len(routes))
self.assertEqual(tenant_prefix, routes[0]['destination'])
self.assertEqual(next_hop, routes[0]['next_hop'])
def _advertised_routes_by_bgp_speaker(self,
bgp_speaker_ip_version,
local_as,
tenant_cidr,
gateway_cidr,
fip_routes=True,
router_distributed=False):
tenant_id = _uuid()
scope_data = {'tenant_id': tenant_id,
'ip_version': bgp_speaker_ip_version,
'shared': True,
'name': 'bgp-scope'}
scope = self.plugin.create_address_scope(
self.context,
{'address_scope': scope_data})
with self.router_with_external_and_tenant_networks(
tenant_id=tenant_id,
gw_prefix=gateway_cidr,
tenant_prefix=tenant_cidr,
address_scope=scope,
distributed=router_distributed) as res:
router, ext_net, int_net = res
gw_net_id = ext_net['network']['id']
with self.bgp_speaker(
bgp_speaker_ip_version,
local_as,
networks=[gw_net_id],
advertise_fip_host_routes=fip_routes) as speaker:
routes = self.bgp_plugin.get_advertised_routes(
self.context,
speaker['id'])
return routes['advertised_routes']
def test__tenant_prefixes_by_router_no_gateway_port(self):
with self.network() as net1, self.network() as net2,\
self.subnetpool_with_address_scope(6, tenant_id='test-tenant',
prefixes=['2001:db8::/63']) as pool:
subnetpool_id = pool['id']
with self.subnet(network=net1,
cidr=None,
subnetpool_id=subnetpool_id,
ip_version=6) as ext_subnet,\
self.subnet(network=net2,
cidr=None,
subnetpool_id=subnetpool_id,
ip_version=6) as int_subnet,\
self.router() as router:
router_id = router['id']
int_subnet_id = int_subnet['subnet']['id']
ext_subnet_id = ext_subnet['subnet']['id']
self.l3plugin.add_router_interface(self.context,
router_id,
{'subnet_id':
int_subnet_id})
self.l3plugin.add_router_interface(self.context,
router_id,
{'subnet_id':
ext_subnet_id})
with self.bgp_speaker(6, 1234) as speaker:
bgp_speaker_id = speaker['id']
cidrs = list(self.bgp_plugin._tenant_prefixes_by_router(
self.context,
router_id,
bgp_speaker_id))
self.assertFalse(cidrs)
def test_get_ipv6_tenant_subnet_routes_by_bgp_speaker_ipv6(self):
tenant_cidr = '2001:db8::/64'
binding_cidr = '2001:ab8::/64'
routes = self._advertised_routes_by_bgp_speaker(6, 1234, tenant_cidr,
binding_cidr)
self.assertEqual(1, len(routes))
dest_prefix = routes[0]['destination']
next_hop = routes[0]['next_hop']
self.assertEqual(tenant_cidr, dest_prefix)
self.assertTrue(netaddr.IPSet([binding_cidr]).__contains__(next_hop))
def test_get_ipv4_tenant_subnet_routes_by_bgp_speaker_ipv4(self):
tenant_cidr = '172.16.10.0/24'
binding_cidr = '20.10.1.0/24'
routes = self._advertised_routes_by_bgp_speaker(4, 1234, tenant_cidr,
binding_cidr)
routes = list(routes)
self.assertEqual(1, len(routes))
dest_prefix = routes[0]['destination']
next_hop = routes[0]['next_hop']
self.assertEqual(tenant_cidr, dest_prefix)
self.assertTrue(netaddr.IPSet([binding_cidr]).__contains__(next_hop))
def test_get_ipv4_tenant_subnet_routes_by_bgp_speaker_dvr_router(self):
tenant_cidr = '172.16.10.0/24'
binding_cidr = '20.10.1.0/24'
routes = self._advertised_routes_by_bgp_speaker(
4,
1234,
tenant_cidr,
binding_cidr,
router_distributed=True)
routes = list(routes)
self.assertEqual(1, len(routes))
def test_all_routes_by_bgp_speaker_different_tenant_address_scope(self):
binding_cidr = '2001:db8::/64'
tenant_cidr = '2002:ab8::/64'
with self.subnetpool_with_address_scope(6, tenant_id='test-tenant',
prefixes=[binding_cidr]) as ext_pool,\
self.subnetpool_with_address_scope(6, tenant_id='test-tenant',
prefixes=[tenant_cidr]) as int_pool,\
self.network() as ext_net, self.network() as int_net:
gw_net_id = ext_net['network']['id']
ext_pool_id = ext_pool['id']
int_pool_id = int_pool['id']
self._update('networks', gw_net_id,
{'network': {external_net.EXTERNAL: True}})
with self.subnet(cidr=None,
subnetpool_id=ext_pool_id,
network=ext_net,
ip_version=6) as ext_subnet,\
self.subnet(cidr=None,
subnetpool_id=int_pool_id,
network=int_net,
ip_version=6) as int_subnet,\
self.router() as router:
router_id = router['id']
int_subnet_id = int_subnet['subnet']['id']
ext_subnet_id = ext_subnet['subnet']['id']
self.l3plugin.add_router_interface(self.context,
router_id,
{'subnet_id':
int_subnet_id})
self.l3plugin.add_router_interface(self.context,
router_id,
{'subnet_id':
ext_subnet_id})
with self.bgp_speaker(6, 1234,
networks=[gw_net_id]) as speaker:
bgp_speaker_id = speaker['id']
cidrs = self.bgp_plugin.get_routes_by_bgp_speaker_id(
self.context,
bgp_speaker_id)
self.assertEqual(0, len(list(cidrs)))
def test__get_routes_by_router_with_fip(self):
gw_prefix = '172.16.10.0/24'
tenant_prefix = '10.10.10.0/24'
tenant_id = _uuid()
scope_data = {'tenant_id': tenant_id, 'ip_version': 4,
'shared': True, 'name': 'bgp-scope'}
scope = self.plugin.create_address_scope(
self.context,
{'address_scope': scope_data})
with self.router_with_external_and_tenant_networks(
tenant_id=tenant_id,
gw_prefix=gw_prefix,
tenant_prefix=tenant_prefix,
address_scope=scope) as res:
router, ext_net, int_net = res
ext_gw_info = router['external_gateway_info']
gw_net_id = ext_net['network']['id']
tenant_net_id = int_net['network']['id']
fixed_port_data = {'port':
{'name': 'test',
'network_id': tenant_net_id,
'tenant_id': tenant_id,
'admin_state_up': True,
'device_id': _uuid(),
'device_owner': 'compute:nova',
'mac_address': attrs.ATTR_NOT_SPECIFIED,
'fixed_ips': attrs.ATTR_NOT_SPECIFIED}}
fixed_port = self.plugin.create_port(self.context,
fixed_port_data)
fip_data = {'floatingip': {'floating_network_id': gw_net_id,
'tenant_id': tenant_id,
'port_id': fixed_port['id']}}
fip = self.l3plugin.create_floatingip(self.context, fip_data)
fip_prefix = fip['floating_ip_address'] + '/32'
with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker:
bgp_speaker_id = speaker['id']
routes = self.bgp_plugin._get_routes_by_router(self.context,
router['id'])
routes = routes[bgp_speaker_id]
next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address']
self.assertEqual(2, len(routes))
tenant_prefix_found = False
fip_prefix_found = False
for route in routes:
self.assertEqual(next_hop, route['next_hop'])
if route['destination'] == tenant_prefix:
tenant_prefix_found = True
if route['destination'] == fip_prefix:
fip_prefix_found = True
self.assertTrue(tenant_prefix_found)
self.assertTrue(fip_prefix_found)
def test_get_routes_by_bgp_speaker_id_with_fip(self):
gw_prefix = '172.16.10.0/24'
tenant_prefix = '10.10.10.0/24'
tenant_id = _uuid()
scope_data = {'tenant_id': tenant_id, 'ip_version': 4,
'shared': True, 'name': 'bgp-scope'}
scope = self.plugin.create_address_scope(
self.context,
{'address_scope': scope_data})
with self.router_with_external_and_tenant_networks(
tenant_id=tenant_id,
gw_prefix=gw_prefix,
tenant_prefix=tenant_prefix,
address_scope=scope) as res:
router, ext_net, int_net = res
ext_gw_info = router['external_gateway_info']
gw_net_id = ext_net['network']['id']
tenant_net_id = int_net['network']['id']
fixed_port_data = {'port':
{'name': 'test',
'network_id': tenant_net_id,
'tenant_id': tenant_id,
'admin_state_up': True,
'device_id': _uuid(),
'device_owner': 'compute:nova',
'mac_address': attrs.ATTR_NOT_SPECIFIED,
'fixed_ips': attrs.ATTR_NOT_SPECIFIED}}
fixed_port = self.plugin.create_port(self.context,
fixed_port_data)
fip_data = {'floatingip': {'floating_network_id': gw_net_id,
'tenant_id': tenant_id,
'port_id': fixed_port['id']}}
fip = self.l3plugin.create_floatingip(self.context, fip_data)
fip_prefix = fip['floating_ip_address'] + '/32'
with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker:
bgp_speaker_id = speaker['id']
routes = self.bgp_plugin.get_routes_by_bgp_speaker_id(
self.context,
bgp_speaker_id)
routes = list(routes)
next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address']
self.assertEqual(2, len(routes))
tenant_prefix_found = False
fip_prefix_found = False
for route in routes:
self.assertEqual(next_hop, route['next_hop'])
if route['destination'] == tenant_prefix:
tenant_prefix_found = True
if route['destination'] == fip_prefix:
fip_prefix_found = True
self.assertTrue(tenant_prefix_found)
self.assertTrue(fip_prefix_found)
def test_get_routes_by_bgp_speaker_binding_with_fip(self):
gw_prefix = '172.16.10.0/24'
tenant_prefix = '10.10.10.0/24'
tenant_id = _uuid()
scope_data = {'tenant_id': tenant_id, 'ip_version': 4,
'shared': True, 'name': 'bgp-scope'}
scope = self.plugin.create_address_scope(
self.context,
{'address_scope': scope_data})
with self.router_with_external_and_tenant_networks(
tenant_id=tenant_id,
gw_prefix=gw_prefix,
tenant_prefix=tenant_prefix,
address_scope=scope) as res:
router, ext_net, int_net = res
ext_gw_info = router['external_gateway_info']
gw_net_id = ext_net['network']['id']
tenant_net_id = int_net['network']['id']
fixed_port_data = {'port':
{'name': 'test',
'network_id': tenant_net_id,
'tenant_id': tenant_id,
'admin_state_up': True,
'device_id': _uuid(),
'device_owner': 'compute:nova',
'mac_address': attrs.ATTR_NOT_SPECIFIED,
'fixed_ips': attrs.ATTR_NOT_SPECIFIED}}
fixed_port = self.plugin.create_port(self.context,
fixed_port_data)
fip_data = {'floatingip': {'floating_network_id': gw_net_id,
'tenant_id': tenant_id,
'port_id': fixed_port['id']}}
fip = self.l3plugin.create_floatingip(self.context, fip_data)
fip_prefix = fip['floating_ip_address'] + '/32'
with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker:
bgp_speaker_id = speaker['id']
routes = self.bgp_plugin.get_routes_by_bgp_speaker_binding(
self.context,
bgp_speaker_id,
gw_net_id)
routes = list(routes)
next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address']
self.assertEqual(2, len(routes))
tenant_prefix_found = False
fip_prefix_found = False
for route in routes:
self.assertEqual(next_hop, route['next_hop'])
if route['destination'] == tenant_prefix:
tenant_prefix_found = True
if route['destination'] == fip_prefix:
fip_prefix_found = True
self.assertTrue(tenant_prefix_found)
self.assertTrue(fip_prefix_found)