diff --git a/ryu/services/protocols/bgp/api/prefix.py b/ryu/services/protocols/bgp/api/prefix.py index c169ed82..1a4207a1 100644 --- a/ryu/services/protocols/bgp/api/prefix.py +++ b/ryu/services/protocols/bgp/api/prefix.py @@ -27,7 +27,9 @@ from ryu.lib.packet.bgp import EvpnEthernetSegmentNLRI from ryu.lib.packet.bgp import EvpnIpPrefixNLRI from ryu.lib.packet.bgp import BGPPathAttributePmsiTunnel from ryu.lib.packet.bgp import FlowSpecIPv4NLRI +from ryu.lib.packet.bgp import FlowSpecIPv6NLRI from ryu.lib.packet.bgp import FlowSpecVPNv4NLRI +from ryu.lib.packet.bgp import FlowSpecVPNv6NLRI from ryu.lib.packet.bgp import BGPFlowSpecTrafficRateCommunity from ryu.lib.packet.bgp import BGPFlowSpecTrafficActionCommunity from ryu.lib.packet.bgp import BGPFlowSpecRedirectCommunity @@ -103,10 +105,14 @@ SUPPORTED_EVPN_ROUTE_TYPES = [ # Constants used in API calls for Flow Specification FLOWSPEC_FAMILY_IPV4 = FlowSpecIPv4NLRI.FLOWSPEC_FAMILY +FLOWSPEC_FAMILY_IPV6 = FlowSpecIPv6NLRI.FLOWSPEC_FAMILY FLOWSPEC_FAMILY_VPNV4 = FlowSpecVPNv4NLRI.FLOWSPEC_FAMILY +FLOWSPEC_FAMILY_VPNV6 = FlowSpecVPNv6NLRI.FLOWSPEC_FAMILY SUPPORTED_FLOWSPEC_FAMILIES = ( FLOWSPEC_FAMILY_IPV4, + FLOWSPEC_FAMILY_IPV6, FLOWSPEC_FAMILY_VPNV4, + FLOWSPEC_FAMILY_VPNV6, ) # Constants for the Traffic Filtering Actions of Flow Specification diff --git a/ryu/services/protocols/bgp/base.py b/ryu/services/protocols/bgp/base.py index e5469020..0dc86079 100644 --- a/ryu/services/protocols/bgp/base.py +++ b/ryu/services/protocols/bgp/base.py @@ -37,7 +37,9 @@ from ryu.lib.packet.bgp import RF_IPv4_VPN from ryu.lib.packet.bgp import RF_IPv6_VPN from ryu.lib.packet.bgp import RF_L2_EVPN from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC +from ryu.lib.packet.bgp import RF_IPv6_FLOWSPEC from ryu.lib.packet.bgp import RF_VPNv4_FLOWSPEC +from ryu.lib.packet.bgp import RF_VPNv6_FLOWSPEC from ryu.lib.packet.bgp import RF_RTC_UC from ryu.services.protocols.bgp.utils.circlist import CircularListType from ryu.services.protocols.bgp.utils.evtlet import LoopingCall @@ -59,7 +61,9 @@ SUPPORTED_GLOBAL_RF = { RF_IPv6_VPN, RF_L2_EVPN, RF_IPv4_FLOWSPEC, + RF_IPv6_FLOWSPEC, RF_VPNv4_FLOWSPEC, + RF_VPNv6_FLOWSPEC, } diff --git a/ryu/services/protocols/bgp/bgp_sample_conf.py b/ryu/services/protocols/bgp/bgp_sample_conf.py index 01afd489..3f34fbdc 100644 --- a/ryu/services/protocols/bgp/bgp_sample_conf.py +++ b/ryu/services/protocols/bgp/bgp_sample_conf.py @@ -4,6 +4,7 @@ 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 RF_VPNV4_FLOWSPEC +from ryu.services.protocols.bgp.bgpspeaker import RF_VPNV6_FLOWSPEC from ryu.services.protocols.bgp.bgpspeaker import EVPN_MAX_ET from ryu.services.protocols.bgp.bgpspeaker import ESI_TYPE_LACP from ryu.services.protocols.bgp.bgpspeaker import ESI_TYPE_MAC_BASED @@ -14,7 +15,9 @@ from ryu.services.protocols.bgp.bgpspeaker import EVPN_MULTICAST_ETAG_ROUTE from ryu.services.protocols.bgp.bgpspeaker import EVPN_ETH_SEGMENT from ryu.services.protocols.bgp.bgpspeaker import EVPN_IP_PREFIX_ROUTE from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_IPV4 +from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_IPV6 from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_VPNV4 +from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_VPNV6 from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_TA_SAMPLE from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_TA_TERMINAL from ryu.services.protocols.bgp.bgpspeaker import REDUNDANCY_MODE_SINGLE_ACTIVE @@ -54,7 +57,9 @@ BGP = { 'address': '172.17.0.4', 'remote_as': 65001, 'enable_ipv4fs': True, + 'enable_ipv6fs': True, 'enable_vpnv4fs': True, + 'enable_vpnv6fs': True, }, ], @@ -83,13 +88,20 @@ BGP = { 'export_rts': ['65001:200'], 'route_family': RF_L2_EVPN, }, - # Example of VRF for FlowSpec + # Example of VRF for IPv4 FlowSpec { 'route_dist': '65001:250', 'import_rts': ['65001:250'], 'export_rts': ['65001:250'], 'route_family': RF_VPNV4_FLOWSPEC, }, + # Example of VRF for IPv6 FlowSpec + { + 'route_dist': '65001:300', + 'import_rts': ['65001:300'], + 'export_rts': ['65001:300'], + 'route_family': RF_VPNV6_FLOWSPEC, + }, ], # List of BGP routes. @@ -236,6 +248,77 @@ BGP = { } }, }, + # Example of Flow Specification IPv6 prefix + { + 'flowspec_family': FLOWSPEC_FAMILY_IPV6, + 'rules': { + 'dst_prefix': '2001::1/128/32', + 'src_prefix': '3001::2/128', + 'next_header': 6, + 'port': '80 | 8000', + 'dst_port': '>9000 & <9050', + 'src_port': '>=8500 & <=9000', + 'icmp_type': 0, + 'icmp_code': 6, + 'tcp_flags': 'SYN+ACK & !=URGENT', + 'packet_len': 1000, + 'dscp': '22 | 24', + 'fragment': 'LF | ==FF', + 'flow_label': 100, + }, + 'actions': { + 'traffic_rate': { + 'as_number': 0, + 'rate_info': 100.0, + }, + 'traffic_action': { + 'action': FLOWSPEC_TA_SAMPLE | FLOWSPEC_TA_TERMINAL, + }, + 'redirect': { + 'as_number': 10, + 'local_administrator': 100, + }, + 'traffic_marking': { + 'dscp': 24, + } + }, + }, + # Example of Flow Specification VPNv6 prefix + { + 'flowspec_family': FLOWSPEC_FAMILY_VPNV6, + 'route_dist': '65001:300', + 'rules': { + 'dst_prefix': '2001::1/128/32', + 'src_prefix': '3001::2/128', + 'next_header': 6, + 'port': '80 | 8000', + 'dst_port': '>9000 & <9050', + 'src_port': '>=8500 & <=9000', + 'icmp_type': 0, + 'icmp_code': 6, + 'tcp_flags': 'SYN+ACK & !=URGENT', + 'packet_len': 1000, + 'dscp': '22 | 24', + 'fragment': 'LF | ==FF', + 'flow_label': 100, + }, + 'actions': { + 'traffic_rate': { + 'as_number': 0, + 'rate_info': 100.0, + }, + 'traffic_action': { + 'action': FLOWSPEC_TA_SAMPLE | FLOWSPEC_TA_TERMINAL, + }, + 'redirect': { + 'as_number': 10, + 'local_administrator': 100, + }, + 'traffic_marking': { + 'dscp': 24, + } + }, + }, ], } diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py index 4965da87..3c8d6450 100644 --- a/ryu/services/protocols/bgp/bgpspeaker.py +++ b/ryu/services/protocols/bgp/bgpspeaker.py @@ -58,6 +58,8 @@ from ryu.services.protocols.bgp.api.prefix import ( FLOWSPEC_FAMILY, FLOWSPEC_FAMILY_IPV4, FLOWSPEC_FAMILY_VPNV4, + FLOWSPEC_FAMILY_IPV6, + FLOWSPEC_FAMILY_VPNV6, FLOWSPEC_RULES, FLOWSPEC_ACTIONS) from ryu.services.protocols.bgp.rtconf.common import LOCAL_AS @@ -82,18 +84,24 @@ from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_EVPN from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV4FS +from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6FS from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4FS +from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6FS from ryu.services.protocols.bgp.rtconf.base import CAP_ENHANCED_REFRESH 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 -from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_IPV4FS -from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV4FS +from ryu.services.protocols.bgp.rtconf.neighbors import ( + DEFAULT_CAP_MBGP_IPV4, + DEFAULT_CAP_MBGP_IPV6, + DEFAULT_CAP_MBGP_VPNV4, + DEFAULT_CAP_MBGP_VPNV6, + DEFAULT_CAP_MBGP_EVPN, + DEFAULT_CAP_MBGP_IPV4FS, + DEFAULT_CAP_MBGP_IPV6FS, + DEFAULT_CAP_MBGP_VPNV4FS, + DEFAULT_CAP_MBGP_VPNV6FS, +) from ryu.services.protocols.bgp.rtconf.neighbors import ( DEFAULT_CAP_ENHANCED_REFRESH, DEFAULT_CAP_FOUR_OCTET_AS_NUMBER) from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CONNECT_MODE @@ -122,6 +130,7 @@ RF_VPN_V4 = vrfs.VRF_RF_IPV4 RF_VPN_V6 = vrfs.VRF_RF_IPV6 RF_L2_EVPN = vrfs.VRF_RF_L2_EVPN RF_VPNV4_FLOWSPEC = vrfs.VRF_RF_IPV4_FLOWSPEC +RF_VPNV6_FLOWSPEC = vrfs.VRF_RF_IPV6_FLOWSPEC # Constants for the Traffic Filtering Actions of Flow Specification. FLOWSPEC_TA_SAMPLE = BGPFlowSpecTrafficActionCommunity.SAMPLE @@ -354,7 +363,9 @@ class BGPSpeaker(object): enable_vpnv6=DEFAULT_CAP_MBGP_VPNV6, enable_evpn=DEFAULT_CAP_MBGP_EVPN, enable_ipv4fs=DEFAULT_CAP_MBGP_IPV4FS, + enable_ipv6fs=DEFAULT_CAP_MBGP_IPV6FS, enable_vpnv4fs=DEFAULT_CAP_MBGP_VPNV4FS, + enable_vpnv6fs=DEFAULT_CAP_MBGP_VPNV6FS, enable_enhanced_refresh=DEFAULT_CAP_ENHANCED_REFRESH, enable_four_octet_as_number=DEFAULT_CAP_FOUR_OCTET_AS_NUMBER, next_hop=None, password=None, multi_exit_disc=None, @@ -394,9 +405,15 @@ class BGPSpeaker(object): ``enable_ipv4fs`` enables IPv4 Flow Specification address family for this neighbor. + ``enable_ipv6fs`` enables IPv6 Flow Specification address family + for this neighbor. + ``enable_vpnv4fs`` enables VPNv4 Flow Specification address family for this neighbor. + ``enable_vpnv6fs`` enables VPNv6 Flow Specification address family + for this neighbor. + ``enable_enhanced_refresh`` enables Enhanced Route Refresh for this neighbor. @@ -457,7 +474,9 @@ class BGPSpeaker(object): CAP_MBGP_VPNV6: enable_vpnv6, CAP_MBGP_EVPN: enable_evpn, CAP_MBGP_IPV4FS: enable_ipv4fs, + CAP_MBGP_IPV6FS: enable_ipv6fs, CAP_MBGP_VPNV4FS: enable_vpnv4fs, + CAP_MBGP_VPNV6FS: enable_vpnv6fs, } if multi_exit_disc: @@ -821,7 +840,9 @@ class BGPSpeaker(object): This parameter must be one of the following. - FLOWSPEC_FAMILY_IPV4 = 'ipv4fs' + - FLOWSPEC_FAMILY_IPV6 = 'ipv6fs' - FLOWSPEC_FAMILY_VPNV4 = 'vpnv4fs' + - FLOWSPEC_FAMILY_VPNV6 = 'vpnv6fs' ``rules`` specifies NLRIs of Flow Specification as a dictionary type value. @@ -829,13 +850,16 @@ class BGPSpeaker(object): see `from_user()` method of the following classes. - :py:mod:`ryu.lib.packet.bgp.FlowSpecIPv4NLRI` + - :py:mod:`ryu.lib.packet.bgp.FlowSpecIPv6NLRI` - :py:mod:`ryu.lib.packet.bgp.FlowSpecVPNv4NLRI` + - :py:mod:`ryu.lib.packet.bgp.FlowSpecVPNv6NLRI` ``route_dist`` specifies a route distinguisher value. This parameter is required only if flowspec_family is one of the following address family. - FLOWSPEC_FAMILY_VPNV4 = 'vpnv4fs' + - FLOWSPEC_FAMILY_VPNV6 = 'vpnv6fs' ``actions`` specifies Traffic Filtering Actions of Flow Specification as a dictionary type value. @@ -903,7 +927,7 @@ class BGPSpeaker(object): FLOWSPEC_ACTIONS: actions or {}, } - if flowspec_family == FLOWSPEC_FAMILY_VPNV4: + if flowspec_family in [FLOWSPEC_FAMILY_VPNV4, FLOWSPEC_FAMILY_VPNV6]: func_name = 'flowspec.add_local' kwargs.update({ROUTE_DISTINGUISHER: route_dist}) @@ -927,7 +951,7 @@ class BGPSpeaker(object): FLOWSPEC_RULES: rules, } - if flowspec_family == FLOWSPEC_FAMILY_VPNV4: + if flowspec_family in [FLOWSPEC_FAMILY_VPNV4, FLOWSPEC_FAMILY_VPNV6]: func_name = 'flowspec.del_local' kwargs.update({ROUTE_DISTINGUISHER: route_dist}) @@ -953,6 +977,7 @@ class BGPSpeaker(object): - RF_VPN_V6 = 'ipv6' - RF_L2_EVPN = 'evpn' - RF_VPNV4_FLOWSPEC = 'ipv4fs' + - RF_VPNV6_FLOWSPEC = 'ipv6fs' ``multi_exit_disc`` specifies multi exit discriminator (MED) value. It must be an integer. diff --git a/ryu/services/protocols/bgp/core_managers/table_manager.py b/ryu/services/protocols/bgp/core_managers/table_manager.py index 297b7a41..27e0bd31 100644 --- a/ryu/services/protocols/bgp/core_managers/table_manager.py +++ b/ryu/services/protocols/bgp/core_managers/table_manager.py @@ -19,12 +19,18 @@ from ryu.services.protocols.bgp.info_base.ipv4fs import IPv4FlowSpecPath from ryu.services.protocols.bgp.info_base.ipv4fs import IPv4FlowSpecTable from ryu.services.protocols.bgp.info_base.vpnv4fs import VPNv4FlowSpecTable from ryu.services.protocols.bgp.info_base.vrf4fs import Vrf4FlowSpecTable +from ryu.services.protocols.bgp.info_base.ipv6fs import IPv6FlowSpecPath +from ryu.services.protocols.bgp.info_base.ipv6fs import IPv6FlowSpecTable +from ryu.services.protocols.bgp.info_base.vpnv6fs import VPNv6FlowSpecTable +from ryu.services.protocols.bgp.info_base.vrf6fs import Vrf6FlowSpecTable from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV6 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_L2_EVPN from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4_FLOWSPEC +from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV6_FLOWSPEC from ryu.services.protocols.bgp.rtconf.vrfs import SUPPORTED_VRF_RF from ryu.services.protocols.bgp.utils.bgp import create_v4flowspec_actions +from ryu.services.protocols.bgp.utils.bgp import create_v6flowspec_actions from ryu.lib import type_desc from ryu.lib.packet.bgp import RF_IPv4_UC @@ -33,7 +39,9 @@ from ryu.lib.packet.bgp import RF_IPv4_VPN from ryu.lib.packet.bgp import RF_IPv6_VPN from ryu.lib.packet.bgp import RF_L2_EVPN from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC +from ryu.lib.packet.bgp import RF_IPv6_FLOWSPEC from ryu.lib.packet.bgp import RF_VPNv4_FLOWSPEC +from ryu.lib.packet.bgp import RF_VPNv6_FLOWSPEC from ryu.lib.packet.bgp import RF_RTC_UC from ryu.lib.packet.bgp import BGPPathAttributeOrigin from ryu.lib.packet.bgp import BGPPathAttributeAsPath @@ -50,6 +58,7 @@ from ryu.lib.packet.bgp import EvpnInclusiveMulticastEthernetTagNLRI from ryu.lib.packet.bgp import IPAddrPrefix from ryu.lib.packet.bgp import IP6AddrPrefix from ryu.lib.packet.bgp import FlowSpecIPv4NLRI +from ryu.lib.packet.bgp import FlowSpecIPv6NLRI from ryu.services.protocols.bgp.utils.validation import is_valid_ipv4 from ryu.services.protocols.bgp.utils.validation import is_valid_ipv4_prefix @@ -132,6 +141,8 @@ class TableCoreManager(object): vpn_table = self.get_evpn_table() elif vrf_table.route_family == Vrf4FlowSpecTable.ROUTE_FAMILY: vpn_table = self.get_vpnv4fs_table() + elif vrf_table.route_family == Vrf6FlowSpecTable.ROUTE_FAMILY: + vpn_table = self.get_vpnv6fs_table() else: raise ValueError('Invalid VRF table route family: %s' % vrf_table.route_family) @@ -200,8 +211,12 @@ class TableCoreManager(object): global_table = self.get_evpn_table() elif route_family == RF_IPv4_FLOWSPEC: global_table = self.get_ipv4fs_table() + elif route_family == RF_IPv6_FLOWSPEC: + global_table = self.get_ipv6fs_table() elif route_family == RF_VPNv4_FLOWSPEC: global_table = self.get_vpnv4fs_table() + elif route_family == RF_VPNv6_FLOWSPEC: + global_table = self.get_vpnv6fs_table() elif route_family == RF_RTC_UC: global_table = self.get_rtc_table() @@ -327,6 +342,21 @@ class TableCoreManager(object): return ipv4fs_table + def get_ipv6fs_table(self): + """Returns global IPv6 Flow Specification table. + + Creates the table if it does not exist. + """ + ipv6fs_table = self._global_tables.get(RF_IPv6_FLOWSPEC) + # Lazy initialization of the table. + if not ipv6fs_table: + ipv6fs_table = IPv6FlowSpecTable(self._core_service, + self._signal_bus) + self._global_tables[RF_IPv6_FLOWSPEC] = ipv6fs_table + self._tables[(None, RF_IPv6_FLOWSPEC)] = ipv6fs_table + + return ipv6fs_table + def get_vpnv4fs_table(self): """Returns global VPNv4 Flow Specification table. @@ -342,6 +372,21 @@ class TableCoreManager(object): return vpnv4fs_table + def get_vpnv6fs_table(self): + """Returns global VPNv6 Flow Specification table. + + Creates the table if it does not exist. + """ + vpnv6fs_table = self._global_tables.get(RF_VPNv6_FLOWSPEC) + # Lazy initialization of the table. + if not vpnv6fs_table: + vpnv6fs_table = VPNv6FlowSpecTable(self._core_service, + self._signal_bus) + self._global_tables[RF_VPNv6_FLOWSPEC] = vpnv6fs_table + self._tables[(None, RF_VPNv6_FLOWSPEC)] = vpnv6fs_table + + return vpnv6fs_table + def get_nexthop_label(self, label_key): return self._next_hop_label.get(label_key, None) @@ -423,6 +468,8 @@ class TableCoreManager(object): vrf_table = VrfEvpnTable elif route_family == VRF_RF_IPV4_FLOWSPEC: vrf_table = Vrf4FlowSpecTable + elif route_family == VRF_RF_IPV6_FLOWSPEC: + vrf_table = Vrf6FlowSpecTable else: raise ValueError('Unsupported route family for VRF: %s' % route_family) @@ -508,6 +555,8 @@ class TableCoreManager(object): route_family = RF_L2_EVPN elif vpn_path.route_family == RF_VPNv4_FLOWSPEC: route_family = RF_IPv4_FLOWSPEC + elif vpn_path.route_family == RF_VPNv6_FLOWSPEC: + route_family = RF_IPv6_FLOWSPEC else: raise ValueError('Unsupported route family for VRF: %s' % vpn_path.route_family) @@ -650,7 +699,10 @@ class TableCoreManager(object): If `is_withdraw` is True, remove a BGP route from the VRF table. """ from ryu.services.protocols.bgp.core import BgpCoreError - from ryu.services.protocols.bgp.api.prefix import FLOWSPEC_FAMILY_VPNV4 + from ryu.services.protocols.bgp.api.prefix import ( + FLOWSPEC_FAMILY_VPNV4, + FLOWSPEC_FAMILY_VPNV6, + ) if flowspec_family == FLOWSPEC_FAMILY_VPNV4: vrf_table = self._tables.get((route_dist, VRF_RF_IPV4_FLOWSPEC)) @@ -659,6 +711,13 @@ class TableCoreManager(object): communities = create_v4flowspec_actions(actions) except ValueError as e: raise BgpCoreError(desc=str(e)) + elif flowspec_family == FLOWSPEC_FAMILY_VPNV6: + vrf_table = self._tables.get((route_dist, VRF_RF_IPV6_FLOWSPEC)) + prefix = FlowSpecIPv6NLRI.from_user(**rules) + try: + communities = create_v6flowspec_actions(actions) + except ValueError as e: + raise BgpCoreError(desc=str(e)) else: raise BgpCoreError( desc='Unsupported flowspec_family %s' % flowspec_family) @@ -732,7 +791,10 @@ class TableCoreManager(object): """ from ryu.services.protocols.bgp.core import BgpCoreError - from ryu.services.protocols.bgp.api.prefix import FLOWSPEC_FAMILY_IPV4 + from ryu.services.protocols.bgp.api.prefix import ( + FLOWSPEC_FAMILY_IPV4, + FLOWSPEC_FAMILY_IPV6, + ) src_ver_num = 1 peer = None @@ -754,6 +816,19 @@ class TableCoreManager(object): except ValueError as e: raise BgpCoreError(desc=str(e)) + if communities: + pathattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = ( + BGPPathAttributeExtendedCommunities( + communities=communities)) + elif flowspec_family == FLOWSPEC_FAMILY_IPV6: + _nlri = FlowSpecIPv6NLRI.from_user(**rules) + p = IPv6FlowSpecPath + + try: + communities = create_v6flowspec_actions(actions) + except ValueError as e: + raise BgpCoreError(desc=str(e)) + if communities: pathattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = ( BGPPathAttributeExtendedCommunities( diff --git a/ryu/services/protocols/bgp/model.py b/ryu/services/protocols/bgp/model.py index 67391397..faa33f04 100644 --- a/ryu/services/protocols/bgp/model.py +++ b/ryu/services/protocols/bgp/model.py @@ -97,11 +97,15 @@ class FlexinetOutgoingRoute(object): from ryu.services.protocols.bgp.info_base.vrf4 import Vrf4Path from ryu.services.protocols.bgp.info_base.vrf6 import Vrf6Path from ryu.services.protocols.bgp.info_base.vrfevpn import VrfEvpnPath - from ryu.services.protocols.bgp.info_base.vrf4fs import Vrf4FlowSpecPath + from ryu.services.protocols.bgp.info_base.vrf4fs import ( + Vrf4FlowSpecPath) + from ryu.services.protocols.bgp.info_base.vrf6fs import ( + Vrf6FlowSpecPath) assert path.route_family in (Vrf4Path.ROUTE_FAMILY, Vrf6Path.ROUTE_FAMILY, VrfEvpnPath.ROUTE_FAMILY, - Vrf4FlowSpecPath.ROUTE_FAMILY) + Vrf4FlowSpecPath.ROUTE_FAMILY, + Vrf6FlowSpecPath.ROUTE_FAMILY) self.sink = None self._path = path diff --git a/ryu/services/protocols/bgp/rtconf/base.py b/ryu/services/protocols/bgp/rtconf/base.py index bdd43091..d839d385 100644 --- a/ryu/services/protocols/bgp/rtconf/base.py +++ b/ryu/services/protocols/bgp/rtconf/base.py @@ -47,7 +47,9 @@ CAP_MBGP_VPNV4 = 'cap_mbgp_vpnv4' CAP_MBGP_VPNV6 = 'cap_mbgp_vpnv6' CAP_MBGP_EVPN = 'cap_mbgp_evpn' CAP_MBGP_IPV4FS = 'cap_mbgp_ipv4fs' +CAP_MBGP_IPV6FS = 'cap_mbgp_ipv6fs' CAP_MBGP_VPNV4FS = 'cap_mbgp_vpnv4fs' +CAP_MBGP_VPNV6FS = 'cap_mbgp_vpnv6fs' CAP_RTC = 'cap_rtc' RTC_AS = 'rtc_as' HOLD_TIME = 'hold_time' @@ -659,6 +661,15 @@ def validate_cap_mbgp_ipv4fs(cmv4fs): return cmv4fs +@validate(name=CAP_MBGP_IPV6FS) +def validate_cap_mbgp_ipv6fs(cmv6fs): + if not isinstance(cmv6fs, bool): + raise ConfigTypeError(desc='Invalid MP-BGP ' + 'IPv6 Flow Specification capability ' + 'settings: %s. Boolean value expected' % cmv6fs) + return cmv6fs + + @validate(name=CAP_MBGP_VPNV4FS) def validate_cap_mbgp_vpnv4fs(cmv4fs): if not isinstance(cmv4fs, bool): @@ -668,6 +679,15 @@ def validate_cap_mbgp_vpnv4fs(cmv4fs): return cmv4fs +@validate(name=CAP_MBGP_VPNV6FS) +def validate_cap_mbgp_vpnv66fs(cmv6fs): + if not isinstance(cmv6fs, bool): + raise ConfigTypeError(desc='Invalid MP-BGP ' + 'VPNv6 Flow Specification capability ' + 'settings: %s. Boolean value expected' % cmv6fs) + return cmv6fs + + @validate(name=CAP_RTC) def validate_cap_rtc(cap_rtc): if not isinstance(cap_rtc, bool): diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py index 987d4da0..d99e509a 100644 --- a/ryu/services/protocols/bgp/rtconf/neighbors.py +++ b/ryu/services/protocols/bgp/rtconf/neighbors.py @@ -28,7 +28,9 @@ from ryu.lib.packet.bgp import RF_IPv4_VPN from ryu.lib.packet.bgp import RF_IPv6_VPN from ryu.lib.packet.bgp import RF_L2_EVPN from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC +from ryu.lib.packet.bgp import RF_IPv6_FLOWSPEC from ryu.lib.packet.bgp import RF_VPNv4_FLOWSPEC +from ryu.lib.packet.bgp import RF_VPNv6_FLOWSPEC from ryu.lib.packet.bgp import RF_RTC_UC from ryu.lib.packet.bgp import BGPOptParamCapabilityFourOctetAsNumber from ryu.lib.packet.bgp import BGPOptParamCapabilityEnhancedRouteRefresh @@ -51,7 +53,9 @@ from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_EVPN from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV4FS +from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6FS from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4FS +from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6FS from ryu.services.protocols.bgp.rtconf.base import CAP_REFRESH from ryu.services.protocols.bgp.rtconf.base import CAP_RTC from ryu.services.protocols.bgp.rtconf.base import compute_optional_conf @@ -110,7 +114,9 @@ DEFAULT_CAP_MBGP_VPNV4 = False DEFAULT_CAP_MBGP_VPNV6 = False DEFAULT_CAP_MBGP_EVPN = False DEFAULT_CAP_MBGP_IPV4FS = False +DEFAULT_CAP_MBGP_IPV6FS = False DEFAULT_CAP_MBGP_VPNV4FS = False +DEFAULT_CAP_MBGP_VPNV6FS = False DEFAULT_HOLD_TIME = 40 DEFAULT_ENABLED = True DEFAULT_CAP_RTC = False @@ -325,6 +331,7 @@ class NeighborConf(ConfWithId, ConfWithStats): CAP_MBGP_VPNV4, CAP_MBGP_VPNV6, CAP_RTC, CAP_MBGP_EVPN, CAP_MBGP_IPV4FS, CAP_MBGP_VPNV4FS, + CAP_MBGP_IPV6FS, CAP_MBGP_VPNV6FS, RTC_AS, HOLD_TIME, ENABLED, MULTI_EXIT_DISC, MAX_PREFIXES, ADVERTISE_PEER_AS, SITE_OF_ORIGINS, @@ -359,8 +366,12 @@ class NeighborConf(ConfWithId, ConfWithStats): CAP_MBGP_VPNV6, DEFAULT_CAP_MBGP_VPNV6, **kwargs) self._settings[CAP_MBGP_IPV4FS] = compute_optional_conf( CAP_MBGP_IPV4FS, DEFAULT_CAP_MBGP_IPV4FS, **kwargs) + self._settings[CAP_MBGP_IPV6FS] = compute_optional_conf( + CAP_MBGP_IPV6FS, DEFAULT_CAP_MBGP_IPV6FS, **kwargs) self._settings[CAP_MBGP_VPNV4FS] = compute_optional_conf( CAP_MBGP_VPNV4FS, DEFAULT_CAP_MBGP_VPNV4FS, **kwargs) + self._settings[CAP_MBGP_VPNV6FS] = compute_optional_conf( + CAP_MBGP_VPNV6FS, DEFAULT_CAP_MBGP_VPNV6FS, **kwargs) self._settings[HOLD_TIME] = compute_optional_conf( HOLD_TIME, DEFAULT_HOLD_TIME, **kwargs) self._settings[ENABLED] = compute_optional_conf( @@ -534,10 +545,18 @@ class NeighborConf(ConfWithId, ConfWithStats): def cap_mbgp_ipv4fs(self): return self._settings[CAP_MBGP_IPV4FS] + @property + def cap_mbgp_ipv6fs(self): + return self._settings[CAP_MBGP_IPV6FS] + @property def cap_mbgp_vpnv4fs(self): return self._settings[CAP_MBGP_VPNV4FS] + @property + def cap_mbgp_vpnv6fs(self): + return self._settings[CAP_MBGP_VPNV6FS] + @property def cap_rtc(self): return self._settings[CAP_RTC] @@ -667,11 +686,21 @@ class NeighborConf(ConfWithId, ConfWithStats): BGPOptParamCapabilityMultiprotocol( RF_IPv4_FLOWSPEC.afi, RF_IPv4_FLOWSPEC.safi)) + if self.cap_mbgp_ipv6fs: + mbgp_caps.append( + BGPOptParamCapabilityMultiprotocol( + RF_IPv6_FLOWSPEC.afi, RF_IPv6_FLOWSPEC.safi)) + if self.cap_mbgp_vpnv4fs: mbgp_caps.append( BGPOptParamCapabilityMultiprotocol( RF_VPNv4_FLOWSPEC.afi, RF_VPNv4_FLOWSPEC.safi)) + if self.cap_mbgp_vpnv6fs: + mbgp_caps.append( + BGPOptParamCapabilityMultiprotocol( + RF_VPNv6_FLOWSPEC.afi, RF_VPNv6_FLOWSPEC.safi)) + if mbgp_caps: capabilities[BGP_CAP_MULTIPROTOCOL] = mbgp_caps diff --git a/ryu/services/protocols/bgp/rtconf/vrfs.py b/ryu/services/protocols/bgp/rtconf/vrfs.py index 9106a0de..a918c5b9 100644 --- a/ryu/services/protocols/bgp/rtconf/vrfs.py +++ b/ryu/services/protocols/bgp/rtconf/vrfs.py @@ -24,6 +24,7 @@ from ryu.lib.packet.bgp import RF_IPv4_UC from ryu.lib.packet.bgp import RF_IPv6_UC from ryu.lib.packet.bgp import RF_L2_EVPN from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC +from ryu.lib.packet.bgp import RF_IPv6_FLOWSPEC from ryu.services.protocols.bgp.utils import validation from ryu.services.protocols.bgp.base import get_validator @@ -61,11 +62,13 @@ VRF_RF_IPV4 = 'ipv4' VRF_RF_IPV6 = 'ipv6' VRF_RF_L2_EVPN = 'evpn' VRF_RF_IPV4_FLOWSPEC = 'ipv4fs' +VRF_RF_IPV6_FLOWSPEC = 'ipv6fs' SUPPORTED_VRF_RF = ( VRF_RF_IPV4, VRF_RF_IPV6, VRF_RF_L2_EVPN, VRF_RF_IPV4_FLOWSPEC, + VRF_RF_IPV6_FLOWSPEC, ) @@ -235,6 +238,8 @@ class VrfConf(ConfWithId, ConfWithStats): return RF_L2_EVPN elif vrf_rf == VRF_RF_IPV4_FLOWSPEC: return RF_IPv4_FLOWSPEC + elif vrf_rf == VRF_RF_IPV6_FLOWSPEC: + return RF_IPv6_FLOWSPEC else: raise ValueError('Unsupported VRF route family given %s' % vrf_rf) @@ -248,6 +253,8 @@ class VrfConf(ConfWithId, ConfWithStats): return VRF_RF_L2_EVPN elif route_family == RF_IPv4_FLOWSPEC: return VRF_RF_IPV4_FLOWSPEC + elif route_family == RF_IPv6_FLOWSPEC: + return VRF_RF_IPV6_FLOWSPEC else: raise ValueError('No supported mapping for route family ' 'to vrf_route_family exists for %s' % diff --git a/ryu/services/protocols/bgp/utils/bgp.py b/ryu/services/protocols/bgp/utils/bgp.py index 5aa2012d..2d066944 100644 --- a/ryu/services/protocols/bgp/utils/bgp.py +++ b/ryu/services/protocols/bgp/utils/bgp.py @@ -29,7 +29,9 @@ from ryu.lib.packet.bgp import ( RF_IPv6_VPN, RF_L2_EVPN, RF_IPv4_FLOWSPEC, + RF_IPv6_FLOWSPEC, RF_VPNv4_FLOWSPEC, + RF_VPNv6_FLOWSPEC, RF_RTC_UC, RouteTargetMembershipNLRI, BGP_ATTR_TYPE_MULTI_EXIT_DISC, @@ -55,7 +57,9 @@ from ryu.services.protocols.bgp.info_base.vpnv4 import Vpnv4Path from ryu.services.protocols.bgp.info_base.vpnv6 import Vpnv6Path from ryu.services.protocols.bgp.info_base.evpn import EvpnPath from ryu.services.protocols.bgp.info_base.ipv4fs import IPv4FlowSpecPath +from ryu.services.protocols.bgp.info_base.ipv6fs import IPv6FlowSpecPath from ryu.services.protocols.bgp.info_base.vpnv4fs import VPNv4FlowSpecPath +from ryu.services.protocols.bgp.info_base.vpnv6fs import VPNv6FlowSpecPath LOG = logging.getLogger('utils.bgp') @@ -67,7 +71,9 @@ _ROUTE_FAMILY_TO_PATH_MAP = {RF_IPv4_UC: Ipv4Path, RF_IPv6_VPN: Vpnv6Path, RF_L2_EVPN: EvpnPath, RF_IPv4_FLOWSPEC: IPv4FlowSpecPath, + RF_IPv6_FLOWSPEC: IPv6FlowSpecPath, RF_VPNv4_FLOWSPEC: VPNv4FlowSpecPath, + RF_VPNv6_FLOWSPEC: VPNv6FlowSpecPath, RF_RTC_UC: RtcPath} @@ -215,6 +221,35 @@ def create_v4flowspec_actions(actions=None): FLOWSPEC_ACTION_TRAFFIC_MARKING: BGPFlowSpecTrafficMarkingCommunity, } + return _create_actions(actions, action_types) + + +def create_v6flowspec_actions(actions=None): + """ + Create list of traffic filtering actions + for Ipv6 Flow Specification and VPNv6 Flow Specification. + + "FLOWSPEC_ACTION_REDIRECT_IPV6" is not implemented yet. + """ + from ryu.services.protocols.bgp.api.prefix import ( + FLOWSPEC_ACTION_TRAFFIC_RATE, + FLOWSPEC_ACTION_TRAFFIC_ACTION, + FLOWSPEC_ACTION_REDIRECT, + FLOWSPEC_ACTION_TRAFFIC_MARKING, + ) + + # Supported action type for IPv6 and VPNv6. + action_types = { + FLOWSPEC_ACTION_TRAFFIC_RATE: BGPFlowSpecTrafficRateCommunity, + FLOWSPEC_ACTION_TRAFFIC_ACTION: BGPFlowSpecTrafficActionCommunity, + FLOWSPEC_ACTION_REDIRECT: BGPFlowSpecRedirectCommunity, + FLOWSPEC_ACTION_TRAFFIC_MARKING: BGPFlowSpecTrafficMarkingCommunity, + } + + return _create_actions(actions, action_types) + + +def _create_actions(actions, action_types): communities = [] if actions is None: