diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2014-10-01 19:17:24 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-10-09 23:44:20 +0900 |
commit | 75753841aa66ce1aab5f56d83ea618ede8d82193 (patch) | |
tree | e164ef35b737af08dfb9700806d7ef5b68bc1574 | |
parent | dca514f198396bfe2e147b1c00357219a5b8f6e2 (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.py | 8 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/peer.py | 25 | ||||
-rw-r--r-- | 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 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 |