summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorShinpei Muraoka <shinpei.muraoka@gmail.com>2017-03-24 17:10:48 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-03-28 10:00:21 +0900
commitb3a83ef185970dfd1c3bfa895cf0eb2c40d2be4e (patch)
tree68e20e06d15cc62bcf7eefb431895725bf1f160e
parenta486539400f5348f14826dab6b1a3f685d157e53 (diff)
BGPSpeaker: Support Flow Specification update messages
This patch enables BGPSpeaker to store FlowSpec routes into the global table and VRF tables and to provide the API for advertising routes. Signed-off-by: Shinpei Muraoka <shinpei.muraoka@gmail.com> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/services/protocols/bgp/api/base.py3
-rw-r--r--ryu/services/protocols/bgp/api/prefix.py105
-rw-r--r--ryu/services/protocols/bgp/api/rtconf.py26
-rw-r--r--ryu/services/protocols/bgp/application.py2
-rw-r--r--ryu/services/protocols/bgp/base.py4
-rw-r--r--ryu/services/protocols/bgp/bgp_sample_conf.py92
-rw-r--r--ryu/services/protocols/bgp/bgpspeaker.py146
-rw-r--r--ryu/services/protocols/bgp/core_managers/table_manager.py151
-rw-r--r--ryu/services/protocols/bgp/model.py4
-rw-r--r--ryu/services/protocols/bgp/net_ctrl.py7
-rw-r--r--ryu/services/protocols/bgp/peer.py23
-rw-r--r--ryu/services/protocols/bgp/rtconf/base.py20
-rw-r--r--ryu/services/protocols/bgp/rtconf/neighbors.py32
-rw-r--r--ryu/services/protocols/bgp/rtconf/vrfs.py13
-rw-r--r--ryu/services/protocols/bgp/utils/bgp.py51
15 files changed, 666 insertions, 13 deletions
diff --git a/ryu/services/protocols/bgp/api/base.py b/ryu/services/protocols/bgp/api/base.py
index 125fee93..87dc13b6 100644
--- a/ryu/services/protocols/bgp/api/base.py
+++ b/ryu/services/protocols/bgp/api/base.py
@@ -54,6 +54,9 @@ MPLS_LABELS = 'mpls_labels'
TUNNEL_TYPE = 'tunnel_type'
EVPN_VNI = 'vni'
PMSI_TUNNEL_TYPE = 'pmsi_tunnel_type'
+FLOWSPEC_FAMILY = 'flowspec_family'
+FLOWSPEC_RULES = 'rules'
+FLOWSPEC_ACTIONS = 'actions'
# API call registry
_CALL_REGISTRY = {}
diff --git a/ryu/services/protocols/bgp/api/prefix.py b/ryu/services/protocols/bgp/api/prefix.py
index a73a123c..0751f2f5 100644
--- a/ryu/services/protocols/bgp/api/prefix.py
+++ b/ryu/services/protocols/bgp/api/prefix.py
@@ -26,6 +26,13 @@ from ryu.lib.packet.bgp import EvpnInclusiveMulticastEthernetTagNLRI
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 FlowSpecVPNv4NLRI
+from ryu.lib.packet.bgp import BGPFlowSpecTrafficRateCommunity
+from ryu.lib.packet.bgp import BGPFlowSpecTrafficActionCommunity
+from ryu.lib.packet.bgp import BGPFlowSpecRedirectCommunity
+from ryu.lib.packet.bgp import BGPFlowSpecTrafficMarkingCommunity
+
from ryu.services.protocols.bgp.api.base import EVPN_ROUTE_TYPE
from ryu.services.protocols.bgp.api.base import EVPN_ESI
from ryu.services.protocols.bgp.api.base import EVPN_ETHERNET_TAG_ID
@@ -43,6 +50,9 @@ from ryu.services.protocols.bgp.api.base import VPN_LABEL
from ryu.services.protocols.bgp.api.base import EVPN_VNI
from ryu.services.protocols.bgp.api.base import TUNNEL_TYPE
from ryu.services.protocols.bgp.api.base import PMSI_TUNNEL_TYPE
+from ryu.services.protocols.bgp.api.base import FLOWSPEC_FAMILY
+from ryu.services.protocols.bgp.api.base import FLOWSPEC_RULES
+from ryu.services.protocols.bgp.api.base import FLOWSPEC_ACTIONS
from ryu.services.protocols.bgp.base import add_bgp_error_metadata
from ryu.services.protocols.bgp.base import PREFIX_ERROR_CODE
from ryu.services.protocols.bgp.base import validate
@@ -55,7 +65,6 @@ from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4
from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_L2_EVPN
from ryu.services.protocols.bgp.utils import validation
-
LOG = logging.getLogger('bgpspeaker.api.prefix')
# Maximum value of the Ethernet Tag ID
@@ -92,6 +101,29 @@ SUPPORTED_EVPN_ROUTE_TYPES = [
EVPN_IP_PREFIX_ROUTE,
]
+# Constants used in API calls for Flow Specification
+FLOWSPEC_FAMILY_IPV4 = FlowSpecIPv4NLRI.FLOWSPEC_FAMILY
+FLOWSPEC_FAMILY_VPNV4 = FlowSpecVPNv4NLRI.FLOWSPEC_FAMILY
+SUPPORTED_FLOWSPEC_FAMILIES = (
+ FLOWSPEC_FAMILY_IPV4,
+ FLOWSPEC_FAMILY_VPNV4,
+)
+
+# Constants for the Traffic Filtering Actions of Flow Specification
+# Constants for the Traffic Filtering Actions of Flow Specification.
+FLOWSPEC_ACTION_TRAFFIC_RATE = BGPFlowSpecTrafficRateCommunity.ACTION_NAME
+FLOWSPEC_ACTION_TRAFFIC_ACTION = BGPFlowSpecTrafficActionCommunity.ACTION_NAME
+FLOWSPEC_ACTION_REDIRECT = BGPFlowSpecRedirectCommunity.ACTION_NAME
+FLOWSPEC_ACTION_TRAFFIC_MARKING = BGPFlowSpecTrafficMarkingCommunity.ACTION_NAME
+
+SUPPORTTED_FLOWSPEC_ACTIONS = (
+ FLOWSPEC_ACTION_TRAFFIC_RATE,
+ FLOWSPEC_ACTION_TRAFFIC_ACTION,
+ FLOWSPEC_ACTION_REDIRECT,
+ FLOWSPEC_ACTION_TRAFFIC_MARKING,
+)
+
+
# Constants for ESI Label extended community
REDUNDANCY_MODE_ALL_ACTIVE = 'all_active'
REDUNDANCY_MODE_SINGLE_ACTIVE = 'single_active'
@@ -241,6 +273,28 @@ def is_valid_pmsi_tunnel_type(pmsi_tunnel_type):
conf_value=pmsi_tunnel_type)
+@validate(name=FLOWSPEC_FAMILY)
+def is_valid_flowspec_family(flowspec_family):
+ if flowspec_family not in SUPPORTED_FLOWSPEC_FAMILIES:
+ raise ConfigValueError(conf_name=FLOWSPEC_FAMILY,
+ conf_value=flowspec_family)
+
+
+@validate(name=FLOWSPEC_RULES)
+def is_valid_flowspec_rules(rules):
+ if not isinstance(rules, dict):
+ raise ConfigValueError(conf_name=FLOWSPEC_RULES,
+ conf_value=rules)
+
+
+@validate(name=FLOWSPEC_ACTIONS)
+def is_valid_flowspec_actions(actions):
+ for k in actions:
+ if k not in SUPPORTTED_FLOWSPEC_ACTIONS:
+ raise ConfigValueError(conf_name=FLOWSPEC_ACTIONS,
+ conf_value=actions)
+
+
@RegisterWithArgChecks(name='prefix.add_local',
req_args=[ROUTE_DISTINGUISHER, PREFIX, NEXT_HOP],
opt_args=[VRF_RF])
@@ -340,3 +394,52 @@ def delete_evpn_local(route_type, route_dist, **kwargs):
VRF_RF: VRF_RF_L2_EVPN}.update(kwargs)]
except BgpCoreError as e:
raise PrefixError(desc=e)
+
+
+# =============================================================================
+# BGP Flow Specification Routes related APIs
+# =============================================================================
+
+@RegisterWithArgChecks(
+ name='flowspec.add_local',
+ req_args=[FLOWSPEC_FAMILY, ROUTE_DISTINGUISHER, FLOWSPEC_RULES],
+ opt_args=[FLOWSPEC_ACTIONS])
+def add_flowspec_local(flowspec_family, route_dist, rules, **kwargs):
+ """Adds Flow Specification route from VRF identified by *route_dist*.
+ """
+ try:
+ # Create new path and insert into appropriate VRF table.
+ tm = CORE_MANAGER.get_core_service().table_manager
+ tm.update_flowspec_vrf_table(
+ flowspec_family=flowspec_family, route_dist=route_dist,
+ rules=rules, **kwargs)
+
+ # Send success response.
+ return [{FLOWSPEC_FAMILY: flowspec_family,
+ ROUTE_DISTINGUISHER: route_dist,
+ FLOWSPEC_RULES: rules}.update(kwargs)]
+
+ except BgpCoreError as e:
+ raise PrefixError(desc=e)
+
+
+@RegisterWithArgChecks(
+ name='flowspec.del_local',
+ req_args=[FLOWSPEC_FAMILY, ROUTE_DISTINGUISHER, FLOWSPEC_RULES])
+def del_flowspec_local(flowspec_family, route_dist, rules):
+ """Deletes/withdraws Flow Specification route from VRF identified
+ by *route_dist*.
+ """
+ try:
+ tm = CORE_MANAGER.get_core_service().table_manager
+ tm.update_flowspec_vrf_table(
+ flowspec_family=flowspec_family, route_dist=route_dist,
+ rules=rules, is_withdraw=True)
+
+ # Send success response.
+ return [{FLOWSPEC_FAMILY: flowspec_family,
+ ROUTE_DISTINGUISHER: route_dist,
+ FLOWSPEC_RULES: rules}]
+
+ except BgpCoreError as e:
+ raise PrefixError(desc=e)
diff --git a/ryu/services/protocols/bgp/api/rtconf.py b/ryu/services/protocols/bgp/api/rtconf.py
index 45c6420b..d981499b 100644
--- a/ryu/services/protocols/bgp/api/rtconf.py
+++ b/ryu/services/protocols/bgp/api/rtconf.py
@@ -20,6 +20,9 @@ import logging
from ryu.services.protocols.bgp.api.base import register
from ryu.services.protocols.bgp.api.base import RegisterWithArgChecks
+from ryu.services.protocols.bgp.api.base import FLOWSPEC_FAMILY
+from ryu.services.protocols.bgp.api.base import FLOWSPEC_RULES
+from ryu.services.protocols.bgp.api.base import FLOWSPEC_ACTIONS
from ryu.services.protocols.bgp.core_manager import CORE_MANAGER
from ryu.services.protocols.bgp.rtconf.base import ConfWithId
from ryu.services.protocols.bgp.rtconf.base import RuntimeConfigError
@@ -297,3 +300,26 @@ def bmp_start(host, port):
def bmp_stop(host, port):
core = CORE_MANAGER.get_core_service()
return core.stop_bmp(host, port)
+
+
+# =============================================================================
+# BGP Flow Specification Routes related APIs
+# =============================================================================
+
+@RegisterWithArgChecks(
+ name='flowspec.add',
+ req_args=[FLOWSPEC_FAMILY, FLOWSPEC_RULES],
+ opt_args=[FLOWSPEC_ACTIONS])
+def add_flowspec(flowspec_family, rules, **kwargs):
+ tm = CORE_MANAGER.get_core_service().table_manager
+ tm.update_flowspec_global_table(flowspec_family, rules, **kwargs)
+ return True
+
+
+@RegisterWithArgChecks(
+ name='flowspec.del',
+ req_args=[FLOWSPEC_FAMILY, FLOWSPEC_RULES])
+def del_flowspec(flowspec_family, rules):
+ tm = CORE_MANAGER.get_core_service().table_manager
+ tm.update_flowspec_global_table(flowspec_family, rules, is_withdraw=True)
+ return True
diff --git a/ryu/services/protocols/bgp/application.py b/ryu/services/protocols/bgp/application.py
index a3e386bc..4663ddb8 100644
--- a/ryu/services/protocols/bgp/application.py
+++ b/ryu/services/protocols/bgp/application.py
@@ -331,6 +331,8 @@ class RyuBGPSpeaker(RyuApp):
prefix_add = self.speaker.prefix_add
elif 'route_type' in route_settings:
prefix_add = self.speaker.evpn_prefix_add
+ elif 'flowspec_family' in route_settings:
+ prefix_add = self.speaker.flowspec_prefix_add
else:
LOG.debug('Skip invalid route settings: %s', route_settings)
continue
diff --git a/ryu/services/protocols/bgp/base.py b/ryu/services/protocols/bgp/base.py
index 190118f5..e5469020 100644
--- a/ryu/services/protocols/bgp/base.py
+++ b/ryu/services/protocols/bgp/base.py
@@ -36,6 +36,8 @@ from ryu.lib.packet.bgp import RF_IPv6_UC
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_VPNv4_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
@@ -56,6 +58,8 @@ SUPPORTED_GLOBAL_RF = {
RF_RTC_UC,
RF_IPv6_VPN,
RF_L2_EVPN,
+ RF_IPv4_FLOWSPEC,
+ RF_VPNv4_FLOWSPEC,
}
diff --git a/ryu/services/protocols/bgp/bgp_sample_conf.py b/ryu/services/protocols/bgp/bgp_sample_conf.py
index 9b9564c3..e77ec578 100644
--- a/ryu/services/protocols/bgp/bgp_sample_conf.py
+++ b/ryu/services/protocols/bgp/bgp_sample_conf.py
@@ -3,6 +3,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 RF_VPNV4_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
@@ -12,6 +13,10 @@ from ryu.services.protocols.bgp.bgpspeaker import TUNNEL_TYPE_VXLAN
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_VPNV4
+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
# =============================================================================
@@ -42,6 +47,12 @@ BGP = {
'remote_as': 65001,
'enable_evpn': True,
},
+ {
+ 'address': '172.17.0.4',
+ 'remote_as': 65001,
+ 'enable_ipv4fs': True,
+ 'enable_vpnv4fs': True,
+ },
],
# List of BGP VRF tables.
@@ -69,11 +80,21 @@ BGP = {
'export_rts': ['65001:200'],
'route_family': RF_L2_EVPN,
},
+ # Example of VRF for FlowSpec
+ {
+ 'route_dist': '65001:250',
+ 'import_rts': ['65001:250'],
+ 'export_rts': ['65001:250'],
+ 'route_family': RF_VPNV4_FLOWSPEC,
+ },
],
# List of BGP routes.
# The parameters for each route are the same as the arguments of
- # BGPSpeaker.prefix_add() or BGPSpeaker.evpn_prefix_add() method.
+ # the following methods:
+ # - BGPSpeaker.prefix_add()
+ # - BGPSpeaker.evpn_prefix_add()
+ # - BGPSpeaker.flowspec_prefix_add()
'routes': [
# Example of IPv4 prefix
{
@@ -143,6 +164,75 @@ BGP = {
'ip_prefix': '10.50.1.0/24',
'gw_ip_addr': '172.16.0.1',
},
+ # Example of Flow Specification IPv4 prefix
+ {
+ 'flowspec_family': FLOWSPEC_FAMILY_IPV4,
+ 'rules': {
+ 'dst_prefix': '10.60.1.0/24',
+ 'src_prefix': '172.17.0.0/24',
+ 'ip_proto': 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',
+ },
+ '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 VPNv4 prefix
+ {
+ 'flowspec_family': FLOWSPEC_FAMILY_VPNV4,
+ 'route_dist': '65001:250',
+ 'rules': {
+ 'dst_prefix': '10.70.1.0/24',
+ 'src_prefix': '172.18.0.0/24',
+ 'ip_proto': 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',
+ },
+ '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 f1784240..d943082a 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
@@ -18,6 +18,7 @@
import netaddr
from ryu.lib import hub
+from ryu.lib.packet.bgp import BGPFlowSpecTrafficActionCommunity
from ryu.services.protocols.bgp.core_manager import CORE_MANAGER
from ryu.services.protocols.bgp.signals.emit import BgpSignalBus
@@ -53,6 +54,12 @@ from ryu.services.protocols.bgp.api.prefix import TUNNEL_TYPE_NVGRE
from ryu.services.protocols.bgp.api.prefix import (
PMSI_TYPE_NO_TUNNEL_INFO,
PMSI_TYPE_INGRESS_REP)
+from ryu.services.protocols.bgp.api.prefix import (
+ FLOWSPEC_FAMILY,
+ FLOWSPEC_FAMILY_IPV4,
+ FLOWSPEC_FAMILY_VPNV4,
+ FLOWSPEC_RULES,
+ FLOWSPEC_ACTIONS)
from ryu.services.protocols.bgp.rtconf.common import LOCAL_AS
from ryu.services.protocols.bgp.rtconf.common import ROUTER_ID
from ryu.services.protocols.bgp.rtconf.common import CLUSTER_ID
@@ -72,6 +79,8 @@ from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6
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_VPNV4FS
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
@@ -81,6 +90,8 @@ 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_ENHANCED_REFRESH, DEFAULT_CAP_FOUR_OCTET_AS_NUMBER)
from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CONNECT_MODE
@@ -108,6 +119,11 @@ NEIGHBOR_CONF_MED = MULTI_EXIT_DISC # for backward compatibility
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
+
+# Constants for the Traffic Filtering Actions of Flow Specification.
+FLOWSPEC_TA_SAMPLE = BGPFlowSpecTrafficActionCommunity.SAMPLE
+FLOWSPEC_TA_TERMINAL = BGPFlowSpecTrafficActionCommunity.TERMINAL
class EventPrefix(object):
@@ -330,6 +346,8 @@ class BGPSpeaker(object):
enable_vpnv4=DEFAULT_CAP_MBGP_VPNV4,
enable_vpnv6=DEFAULT_CAP_MBGP_VPNV6,
enable_evpn=DEFAULT_CAP_MBGP_EVPN,
+ enable_ipv4fs=DEFAULT_CAP_MBGP_IPV4FS,
+ enable_vpnv4fs=DEFAULT_CAP_MBGP_VPNV4FS,
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,
@@ -366,6 +384,12 @@ class BGPSpeaker(object):
``enable_evpn`` enables Ethernet VPN address family for this
neighbor. The default is False.
+ ``enable_ipv4fs`` enables IPv4 Flow Specification address family
+ for this neighbor. The default is False.
+
+ ``enable_vpnv4fs`` enables VPNv4 Flow Specification address family
+ for this neighbor. The default is False.
+
``enable_enhanced_refresh`` enables Enhanced Route Refresh for this
neighbor. The default is False.
@@ -424,6 +448,8 @@ class BGPSpeaker(object):
CAP_MBGP_VPNV4: enable_vpnv4,
CAP_MBGP_VPNV6: enable_vpnv6,
CAP_MBGP_EVPN: enable_evpn,
+ CAP_MBGP_IPV4FS: enable_ipv4fs,
+ CAP_MBGP_VPNV4FS: enable_vpnv4fs,
}
if multi_exit_disc:
@@ -761,6 +787,126 @@ class BGPSpeaker(object):
call(func_name, **kwargs)
+ def flowspec_prefix_add(self, flowspec_family, rules, route_dist=None,
+ actions=None):
+ """ This method adds a new Flow Specification prefix to be advertised.
+
+ ``flowspec_family`` specifies one of the flowspec family name.
+ The supported flowspec families are FLOWSPEC_FAMILY_IPV4 and
+ FLOWSPEC_FAMILY_VPNV4.
+
+ ``route_dist`` specifies a route distinguisher value.
+ This parameter is necessary for only VPNv4 Flow Specification
+ address family.
+
+ ``rules`` specifies NLRIs of Flow Specification as
+ a dictionary type value.
+ For the supported NLRI types and arguments,
+ see `from_user()` method of the following classes.
+
+ - :py:mod:`ryu.lib.packet.bgp.FlowSpecIPv4NLRI`
+ - :py:mod:`ryu.lib.packet.bgp.FlowSpecVPNv4NLRI`
+
+ `` actions`` specifies Traffic Filtering Actions of
+ Flow Specification as a dictionary type value.
+ The keys are "ACTION_NAME" for each action class and
+ values are used for the arguments to that class.
+ For the supported "ACTION_NAME" and arguments,
+ see the following table.
+
+ =============== ===============================================================
+ ACTION_NAME Action Class
+ =============== ===============================================================
+ traffic_rate :py:mod:`ryu.lib.packet.bgp.BGPFlowSpecTrafficRateCommunity`
+ traffic_action :py:mod:`ryu.lib.packet.bgp.BGPFlowSpecTrafficActionCommunity`
+ redirect :py:mod:`ryu.lib.packet.bgp.BGPFlowSpecRedirectCommunity`
+ traffic_marking :py:mod:`ryu.lib.packet.bgp.BGPFlowSpecTrafficMarkingCommunity`
+ =============== ===============================================================
+
+ Example(IPv4)::
+
+ >>> speaker = BGPSpeaker(as_number=65001, router_id='172.17.0.1')
+ >>> speaker.neighbor_add(address='172.17.0.2',
+ ... remote_as=65002,
+ ... enable_ipv4fs=True)
+ >>> speaker.flowspec_prefix_add(
+ ... flowspec_family=FLOWSPEC_FAMILY_IPV4,
+ ... rules={
+ ... 'dst_prefix': '10.60.1.0/24'
+ ... },
+ ... actions={
+ ... 'traffic_marking': {
+ ... 'dscp': 24
+ ... }
+ ... }
+ ... )
+
+ Example(VPNv4)::
+
+ >>> speaker = BGPSpeaker(as_number=65001, router_id='172.17.0.1')
+ >>> speaker.neighbor_add(address='172.17.0.2',
+ ... remote_as=65002,
+ ... enable_vpnv4fs=True)
+ >>> speaker.vrf_add(route_dist='65001:100',
+ ... import_rts=['65001:100'],
+ ... export_rts=['65001:100'],
+ ... route_family=RF_VPNV4_FLOWSPEC)
+ >>> speaker.flowspec_prefix_add(
+ ... flowspec_family=FLOWSPEC_FAMILY_VPNV4,
+ ... route_dist='65000:100',
+ ... rules={
+ ... 'dst_prefix': '10.60.1.0/24'
+ ... },
+ ... actions={
+ ... 'traffic_marking': {
+ ... 'dscp': 24
+ ... }
+ ... }
+ ... )
+ """
+ func_name = 'flowspec.add'
+
+ # Set required arguments
+ kwargs = {
+ FLOWSPEC_FAMILY: flowspec_family,
+ FLOWSPEC_RULES: rules,
+ FLOWSPEC_ACTIONS: actions or {},
+ }
+
+ if flowspec_family == FLOWSPEC_FAMILY_VPNV4:
+ func_name = 'flowspec.add_local'
+ kwargs.update({ROUTE_DISTINGUISHER: route_dist})
+
+ call(func_name, **kwargs)
+
+ def flowspec_prefix_del(self, flowspec_family, rules, route_dist=None):
+ """ This method deletes an advertised Flow Specification route.
+
+ ``flowspec_family`` specifies one of the flowspec family name.
+
+ ``route_dist`` specifies a route distinguisher value.
+
+ ``rules`` specifies NLRIs of Flow Specification as
+ a dictionary type value.
+
+ See the following method for details of each parameter and usages.
+
+ - :py:mod:`ryu.services.protocols.bgp.bgpspeaker.BGPSpeaker.flowspec_prefix_add`
+ """
+ func_name = 'flowspec.del'
+
+ # Set required arguments
+ kwargs = {
+ FLOWSPEC_FAMILY: flowspec_family,
+ FLOWSPEC_RULES: rules,
+ }
+
+ if flowspec_family == FLOWSPEC_FAMILY_VPNV4:
+ func_name = 'flowspec.del_local'
+ kwargs.update({ROUTE_DISTINGUISHER: route_dist})
+
+ call(func_name, **kwargs)
+
def vrf_add(self, route_dist, import_rts, export_rts, site_of_origins=None,
route_family=RF_VPN_V4, multi_exit_disc=None):
""" This method adds a new vrf used for VPN.
diff --git a/ryu/services/protocols/bgp/core_managers/table_manager.py b/ryu/services/protocols/bgp/core_managers/table_manager.py
index 5aa9454a..297b7a41 100644
--- a/ryu/services/protocols/bgp/core_managers/table_manager.py
+++ b/ryu/services/protocols/bgp/core_managers/table_manager.py
@@ -15,10 +15,16 @@ from ryu.services.protocols.bgp.info_base.vrf4 import Vrf4Table
from ryu.services.protocols.bgp.info_base.vrf6 import Vrf6Table
from ryu.services.protocols.bgp.info_base.vrfevpn import VrfEvpnTable
from ryu.services.protocols.bgp.info_base.evpn import EvpnTable
+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.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 SUPPORTED_VRF_RF
+from ryu.services.protocols.bgp.utils.bgp import create_v4flowspec_actions
from ryu.lib import type_desc
from ryu.lib.packet.bgp import RF_IPv4_UC
@@ -26,12 +32,16 @@ from ryu.lib.packet.bgp import RF_IPv6_UC
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_VPNv4_FLOWSPEC
from ryu.lib.packet.bgp import RF_RTC_UC
from ryu.lib.packet.bgp import BGPPathAttributeOrigin
from ryu.lib.packet.bgp import BGPPathAttributeAsPath
+from ryu.lib.packet.bgp import BGPPathAttributeExtendedCommunities
from ryu.lib.packet.bgp import BGP_ATTR_TYPE_ORIGIN
from ryu.lib.packet.bgp import BGP_ATTR_TYPE_AS_PATH
from ryu.lib.packet.bgp import BGP_ATTR_ORIGIN_IGP
+from ryu.lib.packet.bgp import BGP_ATTR_TYPE_EXTENDED_COMMUNITIES
from ryu.lib.packet.bgp import EvpnEsi
from ryu.lib.packet.bgp import EvpnArbitraryEsi
from ryu.lib.packet.bgp import EvpnNLRI
@@ -39,6 +49,7 @@ from ryu.lib.packet.bgp import EvpnMacIPAdvertisementNLRI
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.services.protocols.bgp.utils.validation import is_valid_ipv4
from ryu.services.protocols.bgp.utils.validation import is_valid_ipv4_prefix
@@ -119,6 +130,8 @@ class TableCoreManager(object):
vpn_table = self.get_vpn6_table()
elif vrf_table.route_family == VrfEvpnTable.ROUTE_FAMILY:
vpn_table = self.get_evpn_table()
+ elif vrf_table.route_family == Vrf4FlowSpecTable.ROUTE_FAMILY:
+ vpn_table = self.get_vpnv4fs_table()
else:
raise ValueError('Invalid VRF table route family: %s' %
vrf_table.route_family)
@@ -185,6 +198,10 @@ class TableCoreManager(object):
global_table = self.get_vpn6_table()
elif route_family == RF_L2_EVPN:
global_table = self.get_evpn_table()
+ elif route_family == RF_IPv4_FLOWSPEC:
+ global_table = self.get_ipv4fs_table()
+ elif route_family == RF_VPNv4_FLOWSPEC:
+ global_table = self.get_vpnv4fs_table()
elif route_family == RF_RTC_UC:
global_table = self.get_rtc_table()
@@ -295,6 +312,36 @@ class TableCoreManager(object):
self._next_vpnv4_label += 1
return lbl
+ def get_ipv4fs_table(self):
+ """Returns global IPv4 Flow Specification table.
+
+ Creates the table if it does not exist.
+ """
+ ipv4fs_table = self._global_tables.get(RF_IPv4_FLOWSPEC)
+ # Lazy initialization of the table.
+ if not ipv4fs_table:
+ ipv4fs_table = IPv4FlowSpecTable(self._core_service,
+ self._signal_bus)
+ self._global_tables[RF_IPv4_FLOWSPEC] = ipv4fs_table
+ self._tables[(None, RF_IPv4_FLOWSPEC)] = ipv4fs_table
+
+ return ipv4fs_table
+
+ def get_vpnv4fs_table(self):
+ """Returns global VPNv4 Flow Specification table.
+
+ Creates the table if it does not exist.
+ """
+ vpnv4fs_table = self._global_tables.get(RF_VPNv4_FLOWSPEC)
+ # Lazy initialization of the table.
+ if not vpnv4fs_table:
+ vpnv4fs_table = VPNv4FlowSpecTable(self._core_service,
+ self._signal_bus)
+ self._global_tables[RF_VPNv4_FLOWSPEC] = vpnv4fs_table
+ self._tables[(None, RF_VPNv4_FLOWSPEC)] = vpnv4fs_table
+
+ return vpnv4fs_table
+
def get_nexthop_label(self, label_key):
return self._next_hop_label.get(label_key, None)
@@ -374,6 +421,8 @@ class TableCoreManager(object):
vrf_table = Vrf6Table
elif route_family == VRF_RF_L2_EVPN:
vrf_table = VrfEvpnTable
+ elif route_family == VRF_RF_IPV4_FLOWSPEC:
+ vrf_table = Vrf4FlowSpecTable
else:
raise ValueError('Unsupported route family for VRF: %s' %
route_family)
@@ -457,6 +506,8 @@ class TableCoreManager(object):
route_family = RF_IPv6_UC
elif vpn_path.route_family == RF_L2_EVPN:
route_family = RF_L2_EVPN
+ elif vpn_path.route_family == RF_VPNv4_FLOWSPEC:
+ route_family = RF_IPv4_FLOWSPEC
else:
raise ValueError('Unsupported route family for VRF: %s' %
vpn_path.route_family)
@@ -580,6 +631,49 @@ class TableCoreManager(object):
vni=vni, tunnel_type=tunnel_type,
pmsi_tunnel_type=pmsi_tunnel_type)
+ def update_flowspec_vrf_table(self, flowspec_family, route_dist, rules,
+ actions=None, is_withdraw=False):
+ """Update a BGP route in the VRF table for Flow Specification.
+
+ ``flowspec_family`` specifies one of the flowspec family name.
+
+ ``route_dist`` specifies a route distinguisher value.
+
+ ``rules`` specifies NLRIs of Flow Specification as
+ a dictionary type value.
+
+ `` actions`` specifies Traffic Filtering Actions of
+ Flow Specification as a dictionary type value.
+
+ If `is_withdraw` is False, which is the default, add a BGP route
+ to the VRF table identified by `route_dist`.
+ 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
+
+ if flowspec_family == FLOWSPEC_FAMILY_VPNV4:
+ vrf_table = self._tables.get((route_dist, VRF_RF_IPV4_FLOWSPEC))
+ prefix = FlowSpecIPv4NLRI.from_user(**rules)
+ try:
+ communities = create_v4flowspec_actions(actions)
+ except ValueError as e:
+ raise BgpCoreError(desc=str(e))
+ else:
+ raise BgpCoreError(
+ desc='Unsupported flowspec_family %s' % flowspec_family)
+
+ if vrf_table is None:
+ raise BgpCoreError(
+ desc='VRF table does not exist: route_dist=%s, '
+ 'flowspec_family=%s' % (route_dist, flowspec_family))
+
+ # We do not check if we have a path to given prefix, we issue
+ # withdrawal. Hence multiple withdrawals have not side effect.
+ vrf_table.insert_vrffs_path(
+ nlri=prefix, communities=communities,
+ is_withdraw=is_withdraw)
+
def update_global_table(self, prefix, next_hop=None, is_withdraw=False):
"""Update a BGP route in the Global table for the given `prefix`
with the given `next_hop`.
@@ -616,7 +710,62 @@ class TableCoreManager(object):
pattrs=pathattrs, nexthop=next_hop,
is_withdraw=is_withdraw)
- # add to global ipv4 table and propagates to neighbors
+ # add to global table and propagates to neighbors
+ self.learn_path(new_path)
+
+ def update_flowspec_global_table(self, flowspec_family, rules,
+ actions=None, is_withdraw=False):
+ """Update a BGP route in the Global table for Flow Specification.
+
+ ``flowspec_family`` specifies one of the Flow Specification
+ family name.
+
+ ``rules`` specifies NLRIs of Flow Specification as
+ a dictionary type value.
+
+ `` actions`` specifies Traffic Filtering Actions of
+ Flow Specification as a dictionary type value.
+
+ If `is_withdraw` is False, which is the default, add a BGP route
+ to the Global table.
+ If `is_withdraw` is True, remove a BGP route from the Global table.
+ """
+
+ from ryu.services.protocols.bgp.core import BgpCoreError
+ from ryu.services.protocols.bgp.api.prefix import FLOWSPEC_FAMILY_IPV4
+
+ src_ver_num = 1
+ peer = None
+
+ # set mandatory path attributes
+ origin = BGPPathAttributeOrigin(BGP_ATTR_ORIGIN_IGP)
+ aspath = BGPPathAttributeAsPath([[]])
+
+ pathattrs = OrderedDict()
+ pathattrs[BGP_ATTR_TYPE_ORIGIN] = origin
+ pathattrs[BGP_ATTR_TYPE_AS_PATH] = aspath
+
+ if flowspec_family == FLOWSPEC_FAMILY_IPV4:
+ _nlri = FlowSpecIPv4NLRI.from_user(**rules)
+ p = IPv4FlowSpecPath
+
+ try:
+ communities = create_v4flowspec_actions(actions)
+ except ValueError as e:
+ raise BgpCoreError(desc=str(e))
+
+ if communities:
+ pathattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = (
+ BGPPathAttributeExtendedCommunities(
+ communities=communities))
+ else:
+ raise BgpCoreError(
+ desc='Unsupported flowspec family %s' % flowspec_family)
+
+ new_path = p(peer, _nlri, src_ver_num,
+ pattrs=pathattrs, is_withdraw=is_withdraw)
+
+ # add to global table and propagates to neighbors
self.learn_path(new_path)
def clean_stale_routes(self, peer, route_family=None):
diff --git a/ryu/services/protocols/bgp/model.py b/ryu/services/protocols/bgp/model.py
index c945754a..67391397 100644
--- a/ryu/services/protocols/bgp/model.py
+++ b/ryu/services/protocols/bgp/model.py
@@ -97,9 +97,11 @@ 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
assert path.route_family in (Vrf4Path.ROUTE_FAMILY,
Vrf6Path.ROUTE_FAMILY,
- VrfEvpnPath.ROUTE_FAMILY)
+ VrfEvpnPath.ROUTE_FAMILY,
+ Vrf4FlowSpecPath.ROUTE_FAMILY)
self.sink = None
self._path = path
diff --git a/ryu/services/protocols/bgp/net_ctrl.py b/ryu/services/protocols/bgp/net_ctrl.py
index 972d0b98..7944ac20 100644
--- a/ryu/services/protocols/bgp/net_ctrl.py
+++ b/ryu/services/protocols/bgp/net_ctrl.py
@@ -25,6 +25,8 @@ import traceback
import msgpack
+from ryu.lib.packet import safi as subaddr_family
+
from ryu.services.protocols.bgp import api
from ryu.services.protocols.bgp.api.base import ApiException
from ryu.services.protocols.bgp.api.base import NEXT_HOP
@@ -268,8 +270,11 @@ def _create_prefix_notification(outgoing_msg, rpc_session):
params = [{ROUTE_DISTINGUISHER: outgoing_msg.route_dist,
PREFIX: vpn_nlri.prefix,
NEXT_HOP: path.nexthop,
- VPN_LABEL: path.label_list[0],
VRF_RF: VrfConf.rf_2_vrf_rf(path.route_family)}]
+ if path.nlri.ROUTE_FAMILY.safi not in (subaddr_family.IP_FLOWSPEC,
+ subaddr_family.VPN_FLOWSPEC):
+ params[VPN_LABEL] = path.label_list[0]
+
if not path.is_withdraw:
# Create notification to NetworkController.
rpc_msg = rpc_session.create_notification(
diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py
index 37027395..dbd04545 100644
--- a/ryu/services/protocols/bgp/peer.py
+++ b/ryu/services/protocols/bgp/peer.py
@@ -54,6 +54,8 @@ 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_IPv4_VPN
from ryu.lib.packet.bgp import RF_IPv6_VPN
+from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC
+from ryu.lib.packet.bgp import RF_VPNv4_FLOWSPEC
from ryu.lib.packet.bgp import RF_RTC_UC
from ryu.lib.packet.bgp import get_rf
@@ -100,6 +102,8 @@ from ryu.lib.packet.bgp import BGP_ATTR_TYEP_PMSI_TUNNEL_ATTRIBUTE
from ryu.lib.packet.bgp import BGPTwoOctetAsSpecificExtendedCommunity
from ryu.lib.packet.bgp import BGPIPv4AddressSpecificExtendedCommunity
+from ryu.lib.packet import safi as subaddr_family
+
LOG = logging.getLogger('bgpspeaker.peer')
@@ -1030,9 +1034,11 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
unknown_opttrans_attrs = None
nlri_list = [path.nlri]
- # By default, we use BGPSpeaker's interface IP with this peer
- # as next_hop.
- if self.is_ebgp_peer():
+ if path.route_family.safi in (subaddr_family.IP_FLOWSPEC,
+ subaddr_family.VPN_FLOWSPEC):
+ # Flow Specification does not have next_hop.
+ next_hop = []
+ elif self.is_ebgp_peer():
next_hop = self._session_next_hop(path)
if path.is_local() and path.has_nexthop():
next_hop = path.nexthop
@@ -1518,9 +1524,14 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
raise bgp.MissingWellKnown(BGP_ATTR_TYPE_ORIGIN)
# Validate Next hop.
- # TODO(PH): Currently ignore other cases.
- if (not mp_reach_attr.next_hop or
- (mp_reach_attr.next_hop == self.host_bind_ip)):
+ if mp_reach_attr.route_family.safi in (
+ subaddr_family.IP_FLOWSPEC,
+ subaddr_family.VPN_FLOWSPEC):
+ # Because the Flow Specification does not have nexthop,
+ # skips check.
+ pass
+ elif (not mp_reach_attr.next_hop or
+ mp_reach_attr.next_hop == self.host_bind_ip):
LOG.error('Nexthop of received UPDATE msg. (%s) same as local'
' interface address %s.',
mp_reach_attr.next_hop,
diff --git a/ryu/services/protocols/bgp/rtconf/base.py b/ryu/services/protocols/bgp/rtconf/base.py
index fdccbd62..bdd43091 100644
--- a/ryu/services/protocols/bgp/rtconf/base.py
+++ b/ryu/services/protocols/bgp/rtconf/base.py
@@ -46,6 +46,8 @@ CAP_MBGP_IPV6 = 'cap_mbgp_ipv6'
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_VPNV4FS = 'cap_mbgp_vpnv4fs'
CAP_RTC = 'cap_rtc'
RTC_AS = 'rtc_as'
HOLD_TIME = 'hold_time'
@@ -648,6 +650,24 @@ def validate_cap_mbgp_evpn(cmevpn):
return cmevpn
+@validate(name=CAP_MBGP_IPV4FS)
+def validate_cap_mbgp_ipv4fs(cmv4fs):
+ if not isinstance(cmv4fs, bool):
+ raise ConfigTypeError(desc='Invalid MP-BGP '
+ 'IPv4 Flow Specification capability '
+ 'settings: %s. Boolean value expected' % cmv4fs)
+ return cmv4fs
+
+
+@validate(name=CAP_MBGP_VPNV4FS)
+def validate_cap_mbgp_vpnv4fs(cmv4fs):
+ if not isinstance(cmv4fs, bool):
+ raise ConfigTypeError(desc='Invalid MP-BGP '
+ 'VPNv4 Flow Specification capability '
+ 'settings: %s. Boolean value expected' % cmv4fs)
+ return cmv4fs
+
+
@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 2276c242..987d4da0 100644
--- a/ryu/services/protocols/bgp/rtconf/neighbors.py
+++ b/ryu/services/protocols/bgp/rtconf/neighbors.py
@@ -27,6 +27,8 @@ from ryu.lib.packet.bgp import RF_IPv6_UC
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_VPNv4_FLOWSPEC
from ryu.lib.packet.bgp import RF_RTC_UC
from ryu.lib.packet.bgp import BGPOptParamCapabilityFourOctetAsNumber
from ryu.lib.packet.bgp import BGPOptParamCapabilityEnhancedRouteRefresh
@@ -48,6 +50,8 @@ from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6
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_VPNV4FS
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
@@ -105,6 +109,8 @@ DEFAULT_CAP_MBGP_IPV6 = False
DEFAULT_CAP_MBGP_VPNV4 = False
DEFAULT_CAP_MBGP_VPNV6 = False
DEFAULT_CAP_MBGP_EVPN = False
+DEFAULT_CAP_MBGP_IPV4FS = False
+DEFAULT_CAP_MBGP_VPNV4FS = False
DEFAULT_HOLD_TIME = 40
DEFAULT_ENABLED = True
DEFAULT_CAP_RTC = False
@@ -317,7 +323,9 @@ class NeighborConf(ConfWithId, ConfWithStats):
CAP_FOUR_OCTET_AS_NUMBER,
CAP_MBGP_IPV4, CAP_MBGP_IPV6,
CAP_MBGP_VPNV4, CAP_MBGP_VPNV6,
- CAP_RTC, CAP_MBGP_EVPN, RTC_AS, HOLD_TIME,
+ CAP_RTC, CAP_MBGP_EVPN,
+ CAP_MBGP_IPV4FS, CAP_MBGP_VPNV4FS,
+ RTC_AS, HOLD_TIME,
ENABLED, MULTI_EXIT_DISC, MAX_PREFIXES,
ADVERTISE_PEER_AS, SITE_OF_ORIGINS,
LOCAL_ADDRESS, LOCAL_PORT, LOCAL_AS,
@@ -349,6 +357,10 @@ class NeighborConf(ConfWithId, ConfWithStats):
CAP_MBGP_EVPN, DEFAULT_CAP_MBGP_EVPN, **kwargs)
self._settings[CAP_MBGP_VPNV6] = compute_optional_conf(
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_VPNV4FS] = compute_optional_conf(
+ CAP_MBGP_VPNV4FS, DEFAULT_CAP_MBGP_VPNV4FS, **kwargs)
self._settings[HOLD_TIME] = compute_optional_conf(
HOLD_TIME, DEFAULT_HOLD_TIME, **kwargs)
self._settings[ENABLED] = compute_optional_conf(
@@ -519,6 +531,14 @@ class NeighborConf(ConfWithId, ConfWithStats):
return self._settings[CAP_MBGP_EVPN]
@property
+ def cap_mbgp_ipv4fs(self):
+ return self._settings[CAP_MBGP_IPV4FS]
+
+ @property
+ def cap_mbgp_vpnv4fs(self):
+ return self._settings[CAP_MBGP_VPNV4FS]
+
+ @property
def cap_rtc(self):
return self._settings[CAP_RTC]
@@ -642,6 +662,16 @@ class NeighborConf(ConfWithId, ConfWithStats):
BGPOptParamCapabilityMultiprotocol(
RF_L2_EVPN.afi, RF_L2_EVPN.safi))
+ if self.cap_mbgp_ipv4fs:
+ mbgp_caps.append(
+ BGPOptParamCapabilityMultiprotocol(
+ RF_IPv4_FLOWSPEC.afi, RF_IPv4_FLOWSPEC.safi))
+
+ if self.cap_mbgp_vpnv4fs:
+ mbgp_caps.append(
+ BGPOptParamCapabilityMultiprotocol(
+ RF_VPNv4_FLOWSPEC.afi, RF_VPNv4_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 78d20f22..9106a0de 100644
--- a/ryu/services/protocols/bgp/rtconf/vrfs.py
+++ b/ryu/services/protocols/bgp/rtconf/vrfs.py
@@ -23,6 +23,7 @@ import logging
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.services.protocols.bgp.utils import validation
from ryu.services.protocols.bgp.base import get_validator
@@ -59,7 +60,13 @@ IMPORT_MAPS = 'import_maps'
VRF_RF_IPV4 = 'ipv4'
VRF_RF_IPV6 = 'ipv6'
VRF_RF_L2_EVPN = 'evpn'
-SUPPORTED_VRF_RF = (VRF_RF_IPV4, VRF_RF_IPV6, VRF_RF_L2_EVPN)
+VRF_RF_IPV4_FLOWSPEC = 'ipv4fs'
+SUPPORTED_VRF_RF = (
+ VRF_RF_IPV4,
+ VRF_RF_IPV6,
+ VRF_RF_L2_EVPN,
+ VRF_RF_IPV4_FLOWSPEC,
+)
# Default configuration values.
@@ -226,6 +233,8 @@ class VrfConf(ConfWithId, ConfWithStats):
return RF_IPv6_UC
elif vrf_rf == VRF_RF_L2_EVPN:
return RF_L2_EVPN
+ elif vrf_rf == VRF_RF_IPV4_FLOWSPEC:
+ return RF_IPv4_FLOWSPEC
else:
raise ValueError('Unsupported VRF route family given %s' % vrf_rf)
@@ -237,6 +246,8 @@ class VrfConf(ConfWithId, ConfWithStats):
return VRF_RF_IPV6
elif route_family == RF_L2_EVPN:
return VRF_RF_L2_EVPN
+ elif route_family == RF_IPv4_FLOWSPEC:
+ return VRF_RF_IPV4_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 4bdedf00..5aa2012d 100644
--- a/ryu/services/protocols/bgp/utils/bgp.py
+++ b/ryu/services/protocols/bgp/utils/bgp.py
@@ -28,6 +28,8 @@ from ryu.lib.packet.bgp import (
RF_IPv4_VPN,
RF_IPv6_VPN,
RF_L2_EVPN,
+ RF_IPv4_FLOWSPEC,
+ RF_VPNv4_FLOWSPEC,
RF_RTC_UC,
RouteTargetMembershipNLRI,
BGP_ATTR_TYPE_MULTI_EXIT_DISC,
@@ -41,6 +43,10 @@ from ryu.lib.packet.bgp import (
BGPTwoOctetAsSpecificExtendedCommunity,
BGPIPv4AddressSpecificExtendedCommunity,
BGPFourOctetAsSpecificExtendedCommunity,
+ BGPFlowSpecTrafficRateCommunity,
+ BGPFlowSpecTrafficActionCommunity,
+ BGPFlowSpecRedirectCommunity,
+ BGPFlowSpecTrafficMarkingCommunity,
)
from ryu.services.protocols.bgp.info_base.rtc import RtcPath
from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Path
@@ -48,6 +54,8 @@ from ryu.services.protocols.bgp.info_base.ipv6 import Ipv6Path
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.vpnv4fs import VPNv4FlowSpecPath
LOG = logging.getLogger('utils.bgp')
@@ -58,6 +66,8 @@ _ROUTE_FAMILY_TO_PATH_MAP = {RF_IPv4_UC: Ipv4Path,
RF_IPv4_VPN: Vpnv4Path,
RF_IPv6_VPN: Vpnv6Path,
RF_L2_EVPN: EvpnPath,
+ RF_IPv4_FLOWSPEC: IPv4FlowSpecPath,
+ RF_VPNv4_FLOWSPEC: VPNv4FlowSpecPath,
RF_RTC_UC: RtcPath}
@@ -178,3 +188,44 @@ def create_rt_extended_community(value, subtype=2):
'Invalid Route Target or Route Origin value: %s' % value)
return ext_com
+
+
+def create_v4flowspec_actions(actions=None):
+ """
+ Create list of traffic filtering actions
+ for Ipv4 Flow Specification and VPNv4 Flow Specification.
+
+ `` actions`` specifies Traffic Filtering Actions of
+ Flow Specification as a dictionary type value.
+
+ Returns a list of extended community values.
+ """
+ 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 IPv4 and VPNv4.
+ action_types = {
+ FLOWSPEC_ACTION_TRAFFIC_RATE: BGPFlowSpecTrafficRateCommunity,
+ FLOWSPEC_ACTION_TRAFFIC_ACTION: BGPFlowSpecTrafficActionCommunity,
+ FLOWSPEC_ACTION_REDIRECT: BGPFlowSpecRedirectCommunity,
+ FLOWSPEC_ACTION_TRAFFIC_MARKING: BGPFlowSpecTrafficMarkingCommunity,
+ }
+
+ communities = []
+
+ if actions is None:
+ return communities
+
+ for name, action in actions.items():
+ cls_ = action_types.get(name, None)
+ if cls_:
+ communities.append(cls_(**action))
+ else:
+ raise ValueError(
+ 'Unsupported flowspec action %s' % name)
+
+ return communities