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.hiro...@po.ntts.co.jp>
---
 ryu/services/protocols/bgp/bgpspeaker.py       |  8 +++++++-
 ryu/services/protocols/bgp/peer.py             | 25 ++++++++++++++++++-------
 ryu/services/protocols/bgp/rtconf/neighbors.py | 21 ++++++++++++++++++++-
 3 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/ryu/services/protocols/bgp/bgpspeaker.py 
b/ryu/services/protocols/bgp/bgpspeaker.py
index 59e781c..c969b08 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 598e593..2baf4a8 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 2e9fa86..f5eb9b1 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
-- 
1.9.3 (Apple Git-50)



------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
Ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to