bgp: support next_hop_self

Support next_hop_self.
BGPSpeaker can replace a path's next_hop address with its own address
when it sends the path to iBGP peer.

Signed-off-by: Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Hiroshi Yokoi 2014-10-01 19:17:24 +09:00 committed by FUJITA Tomonori
parent dca514f198
commit 75753841aa
3 changed files with 45 additions and 9 deletions

View File

@ -57,6 +57,7 @@ from ryu.services.protocols.bgp.rtconf.neighbors import PASSWORD
from ryu.services.protocols.bgp.rtconf.neighbors import IN_FILTER
from ryu.services.protocols.bgp.rtconf.neighbors import OUT_FILTER
from ryu.services.protocols.bgp.rtconf.neighbors import IS_ROUTE_SERVER_CLIENT
from ryu.services.protocols.bgp.rtconf.neighbors import IS_NEXT_HOP_SELF
from ryu.services.protocols.bgp.info_base.base import Filter
@ -179,7 +180,8 @@ class BGPSpeaker(object):
enable_vpnv4=DEFAULT_CAP_MBGP_VPNV4,
enable_vpnv6=DEFAULT_CAP_MBGP_VPNV6,
next_hop=None, password=None, multi_exit_disc=None,
site_of_origins=None, is_route_server_client=False):
site_of_origins=None, is_route_server_client=False,
is_next_hop_self=False):
""" This method registers a new neighbor. The BGP speaker tries to
establish a bgp session with the peer (accepts a connection
from the peer and also tries to connect to it).
@ -215,6 +217,9 @@ class BGPSpeaker(object):
``is_route_server_client`` specifies whether this neighbor is a
router server's client or not.
``is_next_hop_self`` specifies whether the BGP speaker announces
its own ip address to iBGP neighbor or not as path's next_hop address.
"""
bgp_neighbor = {}
bgp_neighbor[neighbors.IP_ADDRESS] = address
@ -222,6 +227,7 @@ class BGPSpeaker(object):
bgp_neighbor[PEER_NEXT_HOP] = next_hop
bgp_neighbor[PASSWORD] = password
bgp_neighbor[IS_ROUTE_SERVER_CLIENT] = is_route_server_client
bgp_neighbor[IS_NEXT_HOP_SELF] = is_next_hop_self
# v6 advertizement is available with only v6 peering
if netaddr.valid_ipv4(address):
bgp_neighbor[CAP_MBGP_IPV4] = enable_ipv4

View File

@ -783,15 +783,16 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
else:
next_hop = self.host_bind_ip
if route_family == RF_IPv6_VPN:
# Next hop ipv4_mapped ipv6
def _ipv4_mapped_ipv6(ipv4):
from netaddr import IPAddress
return str(IPAddress(ipv4).ipv6())
next_hop = _ipv4_mapped_ipv6(next_hop)
next_hop = self._ipv4_mapped_ipv6(next_hop)
return next_hop
@staticmethod
def _ipv4_mapped_ipv6(ipv4_address):
# Next hop ipv4_mapped ipv6
from netaddr import IPAddress
return str(IPAddress(ipv4_address).ipv6())
def _construct_update(self, outgoing_route):
"""Construct update message with Outgoing-routes path attribute
appropriately cloned/copied/updated.
@ -835,7 +836,17 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
if not self.is_ebgp_peer() and path.source is not None:
# If the path came from a bgp peer and not from NC, according
# to RFC 4271 we should not modify next_hop.
next_hop = path.nexthop
# However RFC 4271 allows us to change next_hop
# if configured to announce its own ip address.
if self._neigh_conf.is_next_hop_self:
next_hop = self.host_bind_ip
if path.route_family == RF_IPv6_VPN:
next_hop = self._ipv4_mapped_ipv6(next_hop)
LOG.debug('using %s as a next_hop address instead'
' of path.nexthop %s' % (next_hop, path.nexthop))
else:
next_hop = path.nexthop
nexthop_attr = BGPPathAttributeNextHop(next_hop)
assert nexthop_attr, 'Missing NEXTHOP mandatory attribute.'

View File

@ -81,6 +81,7 @@ OUT_FILTER = 'out_filter'
IS_ROUTE_SERVER_CLIENT = 'is_route_server_client'
CHECK_FIRST_AS = 'check_first_as'
ATTRIBUTE_MAP = 'attribute_map'
IS_NEXT_HOP_SELF = 'is_next_hop_self'
# Default value constants.
DEFAULT_CAP_GR_NULL = True
@ -97,6 +98,7 @@ DEFAULT_IN_FILTER = []
DEFAULT_OUT_FILTER = []
DEFAULT_IS_ROUTE_SERVER_CLIENT = False
DEFAULT_CHECK_FIRST_AS = False
DEFAULT_IS_NEXT_HOP_SELF = False
# Default value for *MAX_PREFIXES* setting is set to 0.
DEFAULT_MAX_PREFIXES = 0
@ -255,6 +257,15 @@ def validate_check_first_as(check_first_as):
return check_first_as
@validate(name=IS_NEXT_HOP_SELF)
def validate_is_next_hop_self(is_next_hop_self):
if is_next_hop_self not in (True, False):
raise ConfigValueError(desc='Invalid is_next_hop_self(%s)' %
is_next_hop_self)
return is_next_hop_self
class NeighborConf(ConfWithId, ConfWithStats):
"""Class that encapsulates one neighbors' configuration."""
@ -273,7 +284,8 @@ class NeighborConf(ConfWithId, ConfWithStats):
LOCAL_ADDRESS, LOCAL_PORT,
PEER_NEXT_HOP, PASSWORD,
IN_FILTER, OUT_FILTER,
IS_ROUTE_SERVER_CLIENT, CHECK_FIRST_AS])
IS_ROUTE_SERVER_CLIENT, CHECK_FIRST_AS,
IS_NEXT_HOP_SELF])
def __init__(self, **kwargs):
super(NeighborConf, self).__init__(**kwargs)
@ -308,6 +320,9 @@ class NeighborConf(ConfWithId, ConfWithStats):
DEFAULT_IS_ROUTE_SERVER_CLIENT, **kwargs)
self._settings[CHECK_FIRST_AS] = compute_optional_conf(
CHECK_FIRST_AS, DEFAULT_CHECK_FIRST_AS, **kwargs)
self._settings[IS_NEXT_HOP_SELF] = compute_optional_conf(
IS_NEXT_HOP_SELF,
DEFAULT_IS_NEXT_HOP_SELF, **kwargs)
# We do not have valid default MED value.
# If no MED attribute is provided then we do not have to use MED.
@ -490,6 +505,10 @@ class NeighborConf(ConfWithId, ConfWithStats):
def check_first_as(self):
return self._settings[CHECK_FIRST_AS]
@property
def is_next_hop_self(self):
return self._settings[IS_NEXT_HOP_SELF]
def exceeds_max_prefix_allowed(self, prefix_count):
allowed_max = self._settings[MAX_PREFIXES]
does_exceed = False