summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorHiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>2014-10-01 19:17:24 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2014-10-09 23:44:20 +0900
commit75753841aa66ce1aab5f56d83ea618ede8d82193 (patch)
treee164ef35b737af08dfb9700806d7ef5b68bc1574
parentdca514f198396bfe2e147b1c00357219a5b8f6e2 (diff)
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>
-rw-r--r--ryu/services/protocols/bgp/bgpspeaker.py8
-rw-r--r--ryu/services/protocols/bgp/peer.py25
-rw-r--r--ryu/services/protocols/bgp/rtconf/neighbors.py21
3 files changed, 45 insertions, 9 deletions
diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py
index 59e781ce..c969b08e 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
@@ -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
diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py
index 598e5936..2baf4a88 100644
--- a/ryu/services/protocols/bgp/peer.py
+++ b/ryu/services/protocols/bgp/peer.py
@@ -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.'
diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py
index 2e9fa862..f5eb9b11 100644
--- a/ryu/services/protocols/bgp/rtconf/neighbors.py
+++ b/ryu/services/protocols/bgp/rtconf/neighbors.py
@@ -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