This patch fixes BGPSpeaker to support IPv6 and VPNv6 unicast routes and enable to set IPv6 address in router_id.
Signed-off-by: IWASE Yusuke <[email protected]> --- ryu/services/protocols/bgp/bgp_sample_conf.py | 22 ++++++++++++++++++++++ ryu/services/protocols/bgp/bgpspeaker.py | 23 +++++++---------------- ryu/services/protocols/bgp/processor.py | 6 +++--- ryu/services/protocols/bgp/rtconf/common.py | 3 ++- ryu/services/protocols/bgp/utils/bgp.py | 24 +++++++++++++----------- ryu/tests/integrated/common/ryubgp.py | 11 +++++------ 6 files changed, 52 insertions(+), 37 deletions(-) diff --git a/ryu/services/protocols/bgp/bgp_sample_conf.py b/ryu/services/protocols/bgp/bgp_sample_conf.py index 4c40fef..9f9fc98 100644 --- a/ryu/services/protocols/bgp/bgp_sample_conf.py +++ b/ryu/services/protocols/bgp/bgp_sample_conf.py @@ -1,6 +1,7 @@ import os from ryu.services.protocols.bgp.bgpspeaker import RF_VPN_V4 +from ryu.services.protocols.bgp.bgpspeaker import RF_VPN_V6 from ryu.services.protocols.bgp.bgpspeaker import RF_L2_EVPN from ryu.services.protocols.bgp.bgpspeaker import EVPN_MAC_IP_ADV_ROUTE from ryu.services.protocols.bgp.bgpspeaker import TUNNEL_TYPE_VXLAN @@ -25,7 +26,9 @@ BGP = { 'address': '172.17.0.2', 'remote_as': 65002, 'enable_ipv4': True, + 'enable_ipv6': True, 'enable_vpnv4': True, + 'enable_vpnv6': True, }, { 'address': '172.17.0.3', @@ -38,12 +41,21 @@ BGP = { # The parameters for each VRF table are the same as the arguments of # BGPSpeaker.vrf_add() method. 'vrfs': [ + # Example of VRF for IPv4 { 'route_dist': '65001:100', 'import_rts': ['65001:100'], 'export_rts': ['65001:100'], 'route_family': RF_VPN_V4, }, + # Example of VRF for IPv6 + { + 'route_dist': '65001:150', + 'import_rts': ['65001:150'], + 'export_rts': ['65001:150'], + 'route_family': RF_VPN_V6, + }, + # Example of VRF for EVPN { 'route_dist': '65000:200', 'import_rts': ['65000:200'], @@ -66,6 +78,16 @@ BGP = { 'next_hop': '172.17.0.1', 'route_dist': '65001:100', }, + # Example of IPv6 prefix + { + 'prefix': '2001:db8:1::/64', + }, + # Example of VPNv6 prefix + { + 'prefix': '2001:db8:2::/64', + 'next_hop': '172.17.0.1', + 'route_dist': '65001:150', + }, # Example of EVPN prefix { 'route_type': EVPN_MAC_IP_ADV_ROUTE, diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py index 4934e41..586eaf5 100644 --- a/ryu/services/protocols/bgp/bgpspeaker.py +++ b/ryu/services/protocols/bgp/bgpspeaker.py @@ -64,6 +64,7 @@ from ryu.services.protocols.bgp.rtconf.base import CAP_FOUR_OCTET_AS_NUMBER from ryu.services.protocols.bgp.rtconf.base import MULTI_EXIT_DISC from ryu.services.protocols.bgp.rtconf.base import SITE_OF_ORIGINS from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_IPV4 +from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_IPV6 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV4 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV6 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_EVPN @@ -289,6 +290,7 @@ class BGPSpeaker(object): def neighbor_add(self, address, remote_as, enable_ipv4=DEFAULT_CAP_MBGP_IPV4, + enable_ipv6=DEFAULT_CAP_MBGP_IPV6, enable_vpnv4=DEFAULT_CAP_MBGP_VPNV4, enable_vpnv6=DEFAULT_CAP_MBGP_VPNV6, enable_evpn=DEFAULT_CAP_MBGP_EVPN, @@ -371,23 +373,12 @@ class BGPSpeaker(object): CONNECT_MODE: connect_mode, CAP_ENHANCED_REFRESH: enable_enhanced_refresh, CAP_FOUR_OCTET_AS_NUMBER: enable_four_octet_as_number, + CAP_MBGP_IPV4: enable_ipv4, + CAP_MBGP_IPV6: enable_ipv6, + CAP_MBGP_VPNV4: enable_vpnv4, + CAP_MBGP_VPNV6: enable_vpnv6, + CAP_MBGP_EVPN: enable_evpn, } - # v6 advertisement is available with only v6 peering - if netaddr.valid_ipv4(address): - bgp_neighbor[CAP_MBGP_IPV4] = enable_ipv4 - bgp_neighbor[CAP_MBGP_IPV6] = False - bgp_neighbor[CAP_MBGP_VPNV4] = enable_vpnv4 - bgp_neighbor[CAP_MBGP_VPNV6] = enable_vpnv6 - bgp_neighbor[CAP_MBGP_EVPN] = enable_evpn - elif netaddr.valid_ipv6(address): - bgp_neighbor[CAP_MBGP_IPV4] = False - bgp_neighbor[CAP_MBGP_IPV6] = True - bgp_neighbor[CAP_MBGP_VPNV4] = False - bgp_neighbor[CAP_MBGP_VPNV6] = False - bgp_neighbor[CAP_MBGP_EVPN] = enable_evpn - else: - # FIXME: should raise an exception - pass if multi_exit_disc: bgp_neighbor[MULTI_EXIT_DISC] = multi_exit_disc diff --git a/ryu/services/protocols/bgp/processor.py b/ryu/services/protocols/bgp/processor.py index 086b777..a16a253 100644 --- a/ryu/services/protocols/bgp/processor.py +++ b/ryu/services/protocols/bgp/processor.py @@ -254,7 +254,7 @@ def compute_best_path(local_asn, path1, path2): if best_path is None: best_path_reason = BPR_UNKNOWN - return (best_path, best_path_reason) + return best_path, best_path_reason def _cmp_by_reachable_nh(path1, path2): @@ -482,7 +482,7 @@ def _cmp_by_router_id(local_asn, path1, path2): is_ebgp2 = asn2 != local_asn # If both paths are from eBGP peers, then according to RFC we need # not tie break using router id. - if (is_ebgp1 and is_ebgp2): + if is_ebgp1 and is_ebgp2: return None if ((is_ebgp1 is True and is_ebgp2 is False) or @@ -507,7 +507,7 @@ def _cmp_by_router_id(local_asn, path1, path2): # Select the path with lowest router Id. from ryu.services.protocols.bgp.utils.bgp import from_inet_ptoi - if (from_inet_ptoi(router_id1) < from_inet_ptoi(router_id2)): + if from_inet_ptoi(router_id1) < from_inet_ptoi(router_id2): return path1 else: return path2 diff --git a/ryu/services/protocols/bgp/rtconf/common.py b/ryu/services/protocols/bgp/rtconf/common.py index acf4634..ee9f728 100644 --- a/ryu/services/protocols/bgp/rtconf/common.py +++ b/ryu/services/protocols/bgp/rtconf/common.py @@ -20,6 +20,7 @@ import logging import numbers from ryu.services.protocols.bgp.utils.validation import is_valid_ipv4 +from ryu.services.protocols.bgp.utils.validation import is_valid_ipv6 from ryu.services.protocols.bgp.utils.validation import is_valid_asn from ryu.services.protocols.bgp import rtconf @@ -98,7 +99,7 @@ def validate_router_id(router_id): if not isinstance(router_id, str): raise ConfigTypeError(conf_name=ROUTER_ID) - if not is_valid_ipv4(router_id): + if not is_valid_ipv4(router_id) and not is_valid_ipv6(router_id): raise ConfigValueError(desc='Invalid router id %s' % router_id) return router_id diff --git a/ryu/services/protocols/bgp/utils/bgp.py b/ryu/services/protocols/bgp/utils/bgp.py index 48ac3c6..b95b14d 100644 --- a/ryu/services/protocols/bgp/utils/bgp.py +++ b/ryu/services/protocols/bgp/utils/bgp.py @@ -17,8 +17,10 @@ Utilities related to bgp data types and models. """ import logging -import socket +from netaddr.core import AddrFormatError + +from ryu.lib import ip from ryu.lib.packet.bgp import ( BGPUpdate, RF_IPv4_UC, @@ -97,18 +99,18 @@ def clone_rtcpath_update_rt_as(path, new_rt_as): is_withdraw=path.is_withdraw) -def from_inet_ptoi(bgp_id): - """Convert an IPv4 address string format to a four byte long. +def from_inet_ptoi(router_id): + """Converts the given `router_id` which should be IPv4 or IPv6 address + str type value into int type value. + + Note: If the given `router_id` is invalid address, returns the max + value of 128 bits considering the case of IPv6 address. """ - four_byte_id = None try: - packed_byte = socket.inet_pton(socket.AF_INET, bgp_id) - four_byte_id = int(packed_byte.encode('hex'), 16) - except ValueError: - LOG.debug('Invalid bgp id given for conversion to integer value %s', - bgp_id) - - return four_byte_id + return ip.text_to_int(router_id) + except AddrFormatError: + LOG.debug('Invalid router_id to convert into int: %s', router_id) + return (1 << 128) - 1 def get_unknown_opttrans_attr(path): diff --git a/ryu/tests/integrated/common/ryubgp.py b/ryu/tests/integrated/common/ryubgp.py index 5b5114a..35c9afe 100644 --- a/ryu/tests/integrated/common/ryubgp.py +++ b/ryu/tests/integrated/common/ryubgp.py @@ -18,8 +18,6 @@ from __future__ import absolute_import import logging import time -import netaddr - from . import docker_base as base LOG = logging.getLogger(__name__) @@ -61,9 +59,10 @@ class RyuBGPContainer(base.BGPContainer): n_addr = info['neigh_addr'].split('/')[0] c << " 'address': '%s'," % n_addr c << " 'remote_as': %s," % str(peer.asn) - if netaddr.IPNetwork(n_addr).version == 4: - c << " 'enable_ipv4': True," - c << " 'enable_vpnv4': True," + c << " 'enable_ipv4': True," + c << " 'enable_ipv6': True," + c << " 'enable_vpnv4': True," + c << " 'enable_vpnv6': True," c << ' },' c << ' ],' c << " 'routes': [" @@ -201,7 +200,7 @@ class RyuBGPContainer(base.BGPContainer): time.sleep(1) return result - def run(self, wait=False): + def run(self, wait=False, w_time=WAIT_FOR_BOOT): w_time = super(RyuBGPContainer, self).run(wait=wait, w_time=self.WAIT_FOR_BOOT) return w_time -- 2.7.4 ------------------------------------------------------------------------------ The Command Line: Reinvented for Modern Developers Did the resurgence of CLI tooling catch you by surprise? Reconnect with the command line and become more productive. Learn the new .NET and ASP.NET CLI. Get your free copy! http://sdm.link/telerik _______________________________________________ Ryu-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ryu-devel
