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 <[email protected]>
---
 ryu/services/protocols/bgp/api/base.py             |   3 +
 ryu/services/protocols/bgp/api/prefix.py           | 105 +++++++++++++-
 ryu/services/protocols/bgp/api/rtconf.py           |  26 ++++
 ryu/services/protocols/bgp/application.py          |   2 +
 ryu/services/protocols/bgp/base.py                 |   4 +
 ryu/services/protocols/bgp/bgp_sample_conf.py      |  92 ++++++++++++-
 ryu/services/protocols/bgp/bgpspeaker.py           | 146 ++++++++++++++++++++
 .../protocols/bgp/core_managers/table_manager.py   | 151 ++++++++++++++++++++-
 ryu/services/protocols/bgp/model.py                |   4 +-
 ryu/services/protocols/bgp/net_ctrl.py             |   7 +-
 ryu/services/protocols/bgp/peer.py                 |  23 +++-
 ryu/services/protocols/bgp/rtconf/base.py          |  20 +++
 ryu/services/protocols/bgp/rtconf/neighbors.py     |  32 ++++-
 ryu/services/protocols/bgp/rtconf/vrfs.py          |  13 +-
 ryu/services/protocols/bgp/utils/bgp.py            |  51 +++++++
 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 125fee9..87dc13b 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 a73a123..0751f2f 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 45c6420..d981499 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 a3e386b..4663ddb 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 190118f..e546902 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 9b9564c..e77ec57 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 f178424..d943082 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 5aa9454..297b7a4 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 c945754..6739139 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 972d0b9..7944ac2 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 b7c3dc9..c139855 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
@@ -1521,9 +1527,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 fdccbd6..bdd4309 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 2276c24..987d4da 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 78d20f2..9106a0d 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 4bdedf0..5aa2012 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
-- 
2.7.4


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to