Signed-off-by: Satoshi Fujimoto <[email protected]>
---
 ryu/services/protocols/bgp/api/prefix.py           |  9 +++
 ryu/services/protocols/bgp/base.py                 |  2 +
 ryu/services/protocols/bgp/bgp_sample_conf.py      | 64 ++++++++++++++++++++++
 ryu/services/protocols/bgp/bgpspeaker.py           | 38 ++++++++++++-
 .../protocols/bgp/core_managers/table_manager.py   | 52 ++++++++++++++++++
 ryu/services/protocols/bgp/info_base/vrf.py        | 11 ++--
 ryu/services/protocols/bgp/model.py                |  6 +-
 ryu/services/protocols/bgp/rtconf/base.py          | 10 ++++
 ryu/services/protocols/bgp/rtconf/neighbors.py     | 15 +++++
 ryu/services/protocols/bgp/rtconf/vrfs.py          |  7 +++
 ryu/services/protocols/bgp/utils/bgp.py            | 31 +++++++++++
 11 files changed, 237 insertions(+), 8 deletions(-)

diff --git a/ryu/services/protocols/bgp/api/prefix.py 
b/ryu/services/protocols/bgp/api/prefix.py
index 1a4207a..c3e4262 100644
--- a/ryu/services/protocols/bgp/api/prefix.py
+++ b/ryu/services/protocols/bgp/api/prefix.py
@@ -30,10 +30,13 @@ from ryu.lib.packet.bgp import FlowSpecIPv4NLRI
 from ryu.lib.packet.bgp import FlowSpecIPv6NLRI
 from ryu.lib.packet.bgp import FlowSpecVPNv4NLRI
 from ryu.lib.packet.bgp import FlowSpecVPNv6NLRI
+from ryu.lib.packet.bgp import FlowSpecL2VPNNLRI
 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.lib.packet.bgp import BGPFlowSpecVlanActionCommunity
+from ryu.lib.packet.bgp import BGPFlowSpecTPIDActionCommunity
 
 from ryu.services.protocols.bgp.api.base import EVPN_ROUTE_TYPE
 from ryu.services.protocols.bgp.api.base import EVPN_ESI
@@ -108,11 +111,13 @@ FLOWSPEC_FAMILY_IPV4 = FlowSpecIPv4NLRI.FLOWSPEC_FAMILY
 FLOWSPEC_FAMILY_IPV6 = FlowSpecIPv6NLRI.FLOWSPEC_FAMILY
 FLOWSPEC_FAMILY_VPNV4 = FlowSpecVPNv4NLRI.FLOWSPEC_FAMILY
 FLOWSPEC_FAMILY_VPNV6 = FlowSpecVPNv6NLRI.FLOWSPEC_FAMILY
+FLOWSPEC_FAMILY_L2VPN = FlowSpecL2VPNNLRI.FLOWSPEC_FAMILY
 SUPPORTED_FLOWSPEC_FAMILIES = (
     FLOWSPEC_FAMILY_IPV4,
     FLOWSPEC_FAMILY_IPV6,
     FLOWSPEC_FAMILY_VPNV4,
     FLOWSPEC_FAMILY_VPNV6,
+    FLOWSPEC_FAMILY_L2VPN,
 )
 
 # Constants for the Traffic Filtering Actions of Flow Specification
@@ -121,12 +126,16 @@ 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
+FLOWSPEC_ACTION_VLAN = BGPFlowSpecVlanActionCommunity.ACTION_NAME
+FLOWSPEC_ACTION_TPID = BGPFlowSpecTPIDActionCommunity.ACTION_NAME
 
 SUPPORTTED_FLOWSPEC_ACTIONS = (
     FLOWSPEC_ACTION_TRAFFIC_RATE,
     FLOWSPEC_ACTION_TRAFFIC_ACTION,
     FLOWSPEC_ACTION_REDIRECT,
     FLOWSPEC_ACTION_TRAFFIC_MARKING,
+    FLOWSPEC_ACTION_VLAN,
+    FLOWSPEC_ACTION_TPID,
 )
 
 
diff --git a/ryu/services/protocols/bgp/base.py 
b/ryu/services/protocols/bgp/base.py
index 0dc8607..6295ed9 100644
--- a/ryu/services/protocols/bgp/base.py
+++ b/ryu/services/protocols/bgp/base.py
@@ -40,6 +40,7 @@ from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC
 from ryu.lib.packet.bgp import RF_IPv6_FLOWSPEC
 from ryu.lib.packet.bgp import RF_VPNv4_FLOWSPEC
 from ryu.lib.packet.bgp import RF_VPNv6_FLOWSPEC
+from ryu.lib.packet.bgp import RF_L2VPN_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
@@ -64,6 +65,7 @@ SUPPORTED_GLOBAL_RF = {
     RF_IPv6_FLOWSPEC,
     RF_VPNv4_FLOWSPEC,
     RF_VPNv6_FLOWSPEC,
+    RF_L2VPN_FLOWSPEC,
 }
 
 
diff --git a/ryu/services/protocols/bgp/bgp_sample_conf.py 
b/ryu/services/protocols/bgp/bgp_sample_conf.py
index 3f34fbd..f18f0f7 100644
--- a/ryu/services/protocols/bgp/bgp_sample_conf.py
+++ b/ryu/services/protocols/bgp/bgp_sample_conf.py
@@ -5,6 +5,7 @@ from ryu.services.protocols.bgp.bgpspeaker import RF_VPN_V6
 from ryu.services.protocols.bgp.bgpspeaker import RF_L2_EVPN
 from ryu.services.protocols.bgp.bgpspeaker import RF_VPNV4_FLOWSPEC
 from ryu.services.protocols.bgp.bgpspeaker import RF_VPNV6_FLOWSPEC
+from ryu.services.protocols.bgp.bgpspeaker import RF_L2VPN_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
@@ -18,8 +19,16 @@ from ryu.services.protocols.bgp.bgpspeaker import 
FLOWSPEC_FAMILY_IPV4
 from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_IPV6
 from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_VPNV4
 from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_VPNV6
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_L2VPN
 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 FLOWSPEC_VLAN_POP
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_VLAN_PUSH
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_VLAN_SWAP
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_VLAN_RW_INNER
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_VLAN_RW_OUTER
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_TPID_TI
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_TPID_TO
 from ryu.services.protocols.bgp.bgpspeaker import REDUNDANCY_MODE_SINGLE_ACTIVE
 
 # =============================================================================
@@ -60,6 +69,7 @@ BGP = {
             'enable_ipv6fs': True,
             'enable_vpnv4fs': True,
             'enable_vpnv6fs': True,
+            'enable_l2vpnfs': True,
         },
     ],
 
@@ -102,6 +112,13 @@ BGP = {
             'export_rts': ['65001:300'],
             'route_family': RF_VPNV6_FLOWSPEC,
         },
+        # Example of VRF for L2VPN FlowSpec
+        {
+            'route_dist': '65001:350',
+            'import_rts': ['65001:350'],
+            'export_rts': ['65001:350'],
+            'route_family': RF_L2VPN_FLOWSPEC,
+        },
     ],
 
     # List of BGP routes.
@@ -319,6 +336,53 @@ BGP = {
                 }
             },
         },
+        # Example of Flow Specification L2VPN prefix
+        {
+            'flowspec_family': FLOWSPEC_FAMILY_L2VPN,
+            'route_dist': '65001:350',
+            'rules': {
+                'ether_type': 0x0800,
+                'src_mac': '12:34:56:78:90:AB',
+                'dst_mac': 'BE:EF:C0:FF:EE:DD',
+                'llc_dsap': 0x42,
+                'llc_ssap': 0x42,
+                'llc_control': 100,
+                'snap': 0x12345,
+                'vlan_id': '>4000',
+                'vlan_cos': '>=3',
+                'inner_vlan_id': '<3000',
+                'inner_vlan_cos': '<=5',
+            },
+            '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,
+                },
+                'vlan_action': {
+                    'actions_1': FLOWSPEC_VLAN_POP | FLOWSPEC_VLAN_PUSH,
+                    'vlan_1': 3000,
+                    'cos_1': 3,
+                    'actions_2': FLOWSPEC_VLAN_SWAP,
+                    'vlan_2': 4000,
+                    'cos_2': 2,
+                },
+                'tpid_action': {
+                    'actions': FLOWSPEC_TPID_TI | FLOWSPEC_TPID_TO,
+                    'tpid_1': 200,
+                    'tpid_2': 300,
+                }
+            },
+        }
     ],
 }
 
diff --git a/ryu/services/protocols/bgp/bgpspeaker.py 
b/ryu/services/protocols/bgp/bgpspeaker.py
index 3c8d645..c93eacb 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
@@ -18,7 +18,11 @@
 
 import netaddr
 from ryu.lib import hub
-from ryu.lib.packet.bgp import BGPFlowSpecTrafficActionCommunity
+from ryu.lib.packet.bgp import (
+    BGPFlowSpecTrafficActionCommunity,
+    BGPFlowSpecVlanActionCommunity,
+    BGPFlowSpecTPIDActionCommunity,
+)
 
 from ryu.services.protocols.bgp.core_manager import CORE_MANAGER
 from ryu.services.protocols.bgp.signals.emit import BgpSignalBus
@@ -60,6 +64,7 @@ from ryu.services.protocols.bgp.api.prefix import (
     FLOWSPEC_FAMILY_VPNV4,
     FLOWSPEC_FAMILY_IPV6,
     FLOWSPEC_FAMILY_VPNV6,
+    FLOWSPEC_FAMILY_L2VPN,
     FLOWSPEC_RULES,
     FLOWSPEC_ACTIONS)
 from ryu.services.protocols.bgp.rtconf.common import LOCAL_AS
@@ -87,6 +92,7 @@ from ryu.services.protocols.bgp.rtconf.base import 
CAP_MBGP_IPV4FS
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6FS
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4FS
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6FS
+from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_L2VPNFS
 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
@@ -101,6 +107,7 @@ from ryu.services.protocols.bgp.rtconf.neighbors import (
     DEFAULT_CAP_MBGP_IPV6FS,
     DEFAULT_CAP_MBGP_VPNV4FS,
     DEFAULT_CAP_MBGP_VPNV6FS,
+    DEFAULT_CAP_MBGP_L2VPNFS,
 )
 from ryu.services.protocols.bgp.rtconf.neighbors import (
     DEFAULT_CAP_ENHANCED_REFRESH, DEFAULT_CAP_FOUR_OCTET_AS_NUMBER)
@@ -131,11 +138,23 @@ RF_VPN_V6 = vrfs.VRF_RF_IPV6
 RF_L2_EVPN = vrfs.VRF_RF_L2_EVPN
 RF_VPNV4_FLOWSPEC = vrfs.VRF_RF_IPV4_FLOWSPEC
 RF_VPNV6_FLOWSPEC = vrfs.VRF_RF_IPV6_FLOWSPEC
+RF_L2VPN_FLOWSPEC = vrfs.VRF_RF_L2VPN_FLOWSPEC
 
 # Constants for the Traffic Filtering Actions of Flow Specification.
 FLOWSPEC_TA_SAMPLE = BGPFlowSpecTrafficActionCommunity.SAMPLE
 FLOWSPEC_TA_TERMINAL = BGPFlowSpecTrafficActionCommunity.TERMINAL
 
+# Constants for the VLAN Actions of Flow Specification.
+FLOWSPEC_VLAN_POP = BGPFlowSpecVlanActionCommunity.POP
+FLOWSPEC_VLAN_PUSH = BGPFlowSpecVlanActionCommunity.PUSH
+FLOWSPEC_VLAN_SWAP = BGPFlowSpecVlanActionCommunity.SWAP
+FLOWSPEC_VLAN_RW_INNER = BGPFlowSpecVlanActionCommunity.REWRITE_INNER
+FLOWSPEC_VLAN_RW_OUTER = BGPFlowSpecVlanActionCommunity.REWRITE_OUTER
+
+# Constants for the TPID Actions of Flow Specification.
+FLOWSPEC_TPID_TI = BGPFlowSpecTPIDActionCommunity.TI
+FLOWSPEC_TPID_TO = BGPFlowSpecTPIDActionCommunity.TO
+
 
 class EventPrefix(object):
     """
@@ -366,6 +385,7 @@ class BGPSpeaker(object):
                      enable_ipv6fs=DEFAULT_CAP_MBGP_IPV6FS,
                      enable_vpnv4fs=DEFAULT_CAP_MBGP_VPNV4FS,
                      enable_vpnv6fs=DEFAULT_CAP_MBGP_VPNV6FS,
+                     enable_l2vpnfs=DEFAULT_CAP_MBGP_L2VPNFS,
                      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,
@@ -414,6 +434,9 @@ class BGPSpeaker(object):
         ``enable_vpnv6fs`` enables VPNv6 Flow Specification address family
         for this neighbor.
 
+        ``enable_l2vpnfs`` enables L2VPN Flow Specification address family
+        for this neighbor.
+
         ``enable_enhanced_refresh`` enables Enhanced Route Refresh for this
         neighbor.
 
@@ -477,6 +500,7 @@ class BGPSpeaker(object):
             CAP_MBGP_IPV6FS: enable_ipv6fs,
             CAP_MBGP_VPNV4FS: enable_vpnv4fs,
             CAP_MBGP_VPNV6FS: enable_vpnv6fs,
+            CAP_MBGP_L2VPNFS: enable_l2vpnfs,
         }
 
         if multi_exit_disc:
@@ -843,6 +867,7 @@ class BGPSpeaker(object):
         - FLOWSPEC_FAMILY_IPV6  = 'ipv6fs'
         - FLOWSPEC_FAMILY_VPNV4 = 'vpnv4fs'
         - FLOWSPEC_FAMILY_VPNV6 = 'vpnv6fs'
+        - FLOWSPEC_FAMILY_L2VPN = 'l2vpnfs'
 
         ``rules`` specifies NLRIs of Flow Specification as
         a dictionary type value.
@@ -853,6 +878,7 @@ class BGPSpeaker(object):
         - :py:mod:`ryu.lib.packet.bgp.FlowSpecIPv6NLRI`
         - :py:mod:`ryu.lib.packet.bgp.FlowSpecVPNv4NLRI`
         - :py:mod:`ryu.lib.packet.bgp.FlowSpecVPNv6NLRI`
+        - :py:mod:`ryu.lib.packet.bgp.FlowSpecL2VPNNLRI`
 
         ``route_dist`` specifies a route distinguisher value.
         This parameter is required only if flowspec_family is one of the
@@ -860,6 +886,7 @@ class BGPSpeaker(object):
 
         - FLOWSPEC_FAMILY_VPNV4 = 'vpnv4fs'
         - FLOWSPEC_FAMILY_VPNV6 = 'vpnv6fs'
+        - FLOWSPEC_FAMILY_L2VPN = 'l2vpnfs'
 
         ``actions`` specifies Traffic Filtering Actions of
         Flow Specification as a dictionary type value.
@@ -875,6 +902,8 @@ class BGPSpeaker(object):
         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`
+        vlan_action     
:py:mod:`ryu.lib.packet.bgp.BGPFlowSpecVlanActionCommunity`
+        tpid_action     
:py:mod:`ryu.lib.packet.bgp.BGPFlowSpecTPIDActionCommunity`
         =============== 
===============================================================
 
         Example(IPv4)::
@@ -927,7 +956,8 @@ class BGPSpeaker(object):
             FLOWSPEC_ACTIONS: actions or {},
         }
 
-        if flowspec_family in [FLOWSPEC_FAMILY_VPNV4, FLOWSPEC_FAMILY_VPNV6]:
+        if flowspec_family in [FLOWSPEC_FAMILY_VPNV4, FLOWSPEC_FAMILY_VPNV6,
+                               FLOWSPEC_FAMILY_L2VPN]:
             func_name = 'flowspec.add_local'
             kwargs.update({ROUTE_DISTINGUISHER: route_dist})
 
@@ -951,7 +981,8 @@ class BGPSpeaker(object):
             FLOWSPEC_RULES: rules,
         }
 
-        if flowspec_family in [FLOWSPEC_FAMILY_VPNV4, FLOWSPEC_FAMILY_VPNV6]:
+        if flowspec_family in [FLOWSPEC_FAMILY_VPNV4, FLOWSPEC_FAMILY_VPNV6,
+                               FLOWSPEC_FAMILY_L2VPN]:
             func_name = 'flowspec.del_local'
             kwargs.update({ROUTE_DISTINGUISHER: route_dist})
 
@@ -978,6 +1009,7 @@ class BGPSpeaker(object):
         - RF_L2_EVPN          = 'evpn'
         - RF_VPNV4_FLOWSPEC   = 'ipv4fs'
         - RF_VPNV6_FLOWSPEC   = 'ipv6fs'
+        - RF_L2VPN_FLOWSPEC   = 'l2vpnfs'
 
         ``multi_exit_disc`` specifies multi exit discriminator (MED) value.
         It must be an integer.
diff --git a/ryu/services/protocols/bgp/core_managers/table_manager.py 
b/ryu/services/protocols/bgp/core_managers/table_manager.py
index 27e0bd3..40fe943 100644
--- a/ryu/services/protocols/bgp/core_managers/table_manager.py
+++ b/ryu/services/protocols/bgp/core_managers/table_manager.py
@@ -23,14 +23,19 @@ from ryu.services.protocols.bgp.info_base.ipv6fs import 
IPv6FlowSpecPath
 from ryu.services.protocols.bgp.info_base.ipv6fs import IPv6FlowSpecTable
 from ryu.services.protocols.bgp.info_base.vpnv6fs import VPNv6FlowSpecTable
 from ryu.services.protocols.bgp.info_base.vrf6fs import Vrf6FlowSpecTable
+from ryu.services.protocols.bgp.info_base.l2vpnfs import L2VPNFlowSpecTable
+from ryu.services.protocols.bgp.info_base.vrfl2vpnfs import L2vpnFlowSpecPath
+from ryu.services.protocols.bgp.info_base.vrfl2vpnfs import L2vpnFlowSpecTable
 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4
 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV6
 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_L2_EVPN
 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4_FLOWSPEC
 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV6_FLOWSPEC
+from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_L2VPN_FLOWSPEC
 from ryu.services.protocols.bgp.rtconf.vrfs import SUPPORTED_VRF_RF
 from ryu.services.protocols.bgp.utils.bgp import create_v4flowspec_actions
 from ryu.services.protocols.bgp.utils.bgp import create_v6flowspec_actions
+from ryu.services.protocols.bgp.utils.bgp import create_l2vpnflowspec_actions
 
 from ryu.lib import type_desc
 from ryu.lib.packet.bgp import RF_IPv4_UC
@@ -42,6 +47,7 @@ from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC
 from ryu.lib.packet.bgp import RF_IPv6_FLOWSPEC
 from ryu.lib.packet.bgp import RF_VPNv4_FLOWSPEC
 from ryu.lib.packet.bgp import RF_VPNv6_FLOWSPEC
+from ryu.lib.packet.bgp import RF_L2VPN_FLOWSPEC
 from ryu.lib.packet.bgp import RF_RTC_UC
 from ryu.lib.packet.bgp import BGPPathAttributeOrigin
 from ryu.lib.packet.bgp import BGPPathAttributeAsPath
@@ -59,6 +65,7 @@ from ryu.lib.packet.bgp import IPAddrPrefix
 from ryu.lib.packet.bgp import IP6AddrPrefix
 from ryu.lib.packet.bgp import FlowSpecIPv4NLRI
 from ryu.lib.packet.bgp import FlowSpecIPv6NLRI
+from ryu.lib.packet.bgp import FlowSpecL2VPNNLRI
 
 from ryu.services.protocols.bgp.utils.validation import is_valid_ipv4
 from ryu.services.protocols.bgp.utils.validation import is_valid_ipv4_prefix
@@ -143,6 +150,8 @@ class TableCoreManager(object):
             vpn_table = self.get_vpnv4fs_table()
         elif vrf_table.route_family == Vrf6FlowSpecTable.ROUTE_FAMILY:
             vpn_table = self.get_vpnv6fs_table()
+        elif vrf_table.route_family == L2vpnFlowSpecTable.ROUTE_FAMILY:
+            vpn_table = self.get_l2vpnfs_table()
         else:
             raise ValueError('Invalid VRF table route family: %s' %
                              vrf_table.route_family)
@@ -217,6 +226,8 @@ class TableCoreManager(object):
             global_table = self.get_vpnv4fs_table()
         elif route_family == RF_VPNv6_FLOWSPEC:
             global_table = self.get_vpnv6fs_table()
+        elif route_family == RF_L2VPN_FLOWSPEC:
+            global_table = self.get_l2vpnfs_table()
         elif route_family == RF_RTC_UC:
             global_table = self.get_rtc_table()
 
@@ -387,6 +398,21 @@ class TableCoreManager(object):
 
         return vpnv6fs_table
 
+    def get_l2vpnfs_table(self):
+        """Returns global L2VPN Flow Specification table.
+
+        Creates the table if it does not exist.
+        """
+        l2vpnfs_table = self._global_tables.get(RF_L2VPN_FLOWSPEC)
+        # Lazy initialization of the table.
+        if not l2vpnfs_table:
+            l2vpnfs_table = L2VPNFlowSpecTable(self._core_service,
+                                               self._signal_bus)
+            self._global_tables[RF_L2VPN_FLOWSPEC] = l2vpnfs_table
+            self._tables[(None, RF_L2VPN_FLOWSPEC)] = l2vpnfs_table
+
+        return l2vpnfs_table
+
     def get_nexthop_label(self, label_key):
         return self._next_hop_label.get(label_key, None)
 
@@ -470,6 +496,8 @@ class TableCoreManager(object):
             vrf_table = Vrf4FlowSpecTable
         elif route_family == VRF_RF_IPV6_FLOWSPEC:
             vrf_table = Vrf6FlowSpecTable
+        elif route_family == VRF_RF_L2VPN_FLOWSPEC:
+            vrf_table = L2vpnFlowSpecTable
         else:
             raise ValueError('Unsupported route family for VRF: %s' %
                              route_family)
@@ -557,6 +585,8 @@ class TableCoreManager(object):
             route_family = RF_IPv4_FLOWSPEC
         elif vpn_path.route_family == RF_VPNv6_FLOWSPEC:
             route_family = RF_IPv6_FLOWSPEC
+        elif vpn_path.route_family == RF_L2VPN_FLOWSPEC:
+            route_family = RF_L2VPN_FLOWSPEC
         else:
             raise ValueError('Unsupported route family for VRF: %s' %
                              vpn_path.route_family)
@@ -702,6 +732,7 @@ class TableCoreManager(object):
         from ryu.services.protocols.bgp.api.prefix import (
             FLOWSPEC_FAMILY_VPNV4,
             FLOWSPEC_FAMILY_VPNV6,
+            FLOWSPEC_FAMILY_L2VPN,
         )
 
         if flowspec_family == FLOWSPEC_FAMILY_VPNV4:
@@ -718,6 +749,13 @@ class TableCoreManager(object):
                 communities = create_v6flowspec_actions(actions)
             except ValueError as e:
                 raise BgpCoreError(desc=str(e))
+        elif flowspec_family == FLOWSPEC_FAMILY_L2VPN:
+            vrf_table = self._tables.get((route_dist, VRF_RF_L2VPN_FLOWSPEC))
+            prefix = FlowSpecL2VPNNLRI.from_user(route_dist, **rules)
+            try:
+                communities = create_l2vpnflowspec_actions(actions)
+            except ValueError as e:
+                raise BgpCoreError(desc=str(e))
         else:
             raise BgpCoreError(
                 desc='Unsupported flowspec_family %s' % flowspec_family)
@@ -794,6 +832,7 @@ class TableCoreManager(object):
         from ryu.services.protocols.bgp.api.prefix import (
             FLOWSPEC_FAMILY_IPV4,
             FLOWSPEC_FAMILY_IPV6,
+            FLOWSPEC_FAMILY_L2VPN,
         )
 
         src_ver_num = 1
@@ -833,6 +872,19 @@ class TableCoreManager(object):
                 pathattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = (
                     BGPPathAttributeExtendedCommunities(
                         communities=communities))
+        elif flowspec_family == FLOWSPEC_FAMILY_L2VPN:
+            _nlri = FlowSpecL2VPNNLRI.from_user(**rules)
+            p = L2vpnFlowSpecPath
+
+            try:
+                communities = create_l2vpnflowspec_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)
diff --git a/ryu/services/protocols/bgp/info_base/vrf.py 
b/ryu/services/protocols/bgp/info_base/vrf.py
index 7994073..8b06c6a 100644
--- a/ryu/services/protocols/bgp/info_base/vrf.py
+++ b/ryu/services/protocols/bgp/info_base/vrf.py
@@ -39,7 +39,10 @@ from ryu.lib.packet.bgp import PmsiTunnelIdIngressReplication
 from ryu.lib.packet.bgp import RF_L2_EVPN
 from ryu.lib.packet.bgp import EvpnMacIPAdvertisementNLRI
 from ryu.lib.packet.bgp import EvpnIpPrefixNLRI
-from ryu.lib.packet.safi import IP_FLOWSPEC
+from ryu.lib.packet.safi import (
+    IP_FLOWSPEC,
+    VPN_FLOWSPEC,
+)
 
 from ryu.services.protocols.bgp.base import OrderedDict
 from ryu.services.protocols.bgp.constants import VPN_TABLE
@@ -168,7 +171,7 @@ class VrfTable(Table):
             # Because NLRI class is the same if the route family is EVPN,
             # we re-use the NLRI instance.
             vrf_nlri = vpn_path.nlri
-        elif self.ROUTE_FAMILY.safi == IP_FLOWSPEC:
+        elif self.ROUTE_FAMILY.safi in [IP_FLOWSPEC, VPN_FLOWSPEC]:
             vrf_nlri = self.NLRI_CLASS(rules=vpn_path.nlri.rules)
         else:  # self.VPN_ROUTE_FAMILY in [RF_IPv4_VPN, RF_IPv6_VPN]
             # Copy NLRI instance
@@ -526,7 +529,7 @@ class VrfPath(Path):
                 - `label_list`: (list) List of labels for this path.
             Note: other parameters are as documented in super class.
         """
-        if self.ROUTE_FAMILY.safi == IP_FLOWSPEC:
+        if self.ROUTE_FAMILY.safi in [IP_FLOWSPEC, VPN_FLOWSPEC]:
             nexthop = '0.0.0.0'
 
         Path.__init__(self, source, nlri, src_ver_num, pattrs, nexthop,
@@ -584,7 +587,7 @@ class VrfPath(Path):
             # we re-use the NLRI instance.
             vpn_nlri = self._nlri
 
-        elif self.ROUTE_FAMILY.safi == IP_FLOWSPEC:
+        elif self.ROUTE_FAMILY.safi in [IP_FLOWSPEC, VPN_FLOWSPEC]:
             vpn_nlri = self.VPN_NLRI_CLASS(route_dist=route_dist,
                                            rules=self.nlri.rules)
 
diff --git a/ryu/services/protocols/bgp/model.py 
b/ryu/services/protocols/bgp/model.py
index faa33f0..db32558 100644
--- a/ryu/services/protocols/bgp/model.py
+++ b/ryu/services/protocols/bgp/model.py
@@ -101,11 +101,15 @@ class FlexinetOutgoingRoute(object):
             Vrf4FlowSpecPath)
         from ryu.services.protocols.bgp.info_base.vrf6fs import (
             Vrf6FlowSpecPath)
+        from ryu.services.protocols.bgp.info_base.vrfl2vpnfs import (
+            L2vpnFlowSpecPath)
         assert path.route_family in (Vrf4Path.ROUTE_FAMILY,
                                      Vrf6Path.ROUTE_FAMILY,
                                      VrfEvpnPath.ROUTE_FAMILY,
                                      Vrf4FlowSpecPath.ROUTE_FAMILY,
-                                     Vrf6FlowSpecPath.ROUTE_FAMILY)
+                                     Vrf6FlowSpecPath.ROUTE_FAMILY,
+                                     L2vpnFlowSpecPath.ROUTE_FAMILY,
+                                     )
 
         self.sink = None
         self._path = path
diff --git a/ryu/services/protocols/bgp/rtconf/base.py 
b/ryu/services/protocols/bgp/rtconf/base.py
index d839d38..c445a87 100644
--- a/ryu/services/protocols/bgp/rtconf/base.py
+++ b/ryu/services/protocols/bgp/rtconf/base.py
@@ -50,6 +50,7 @@ CAP_MBGP_IPV4FS = 'cap_mbgp_ipv4fs'
 CAP_MBGP_IPV6FS = 'cap_mbgp_ipv6fs'
 CAP_MBGP_VPNV4FS = 'cap_mbgp_vpnv4fs'
 CAP_MBGP_VPNV6FS = 'cap_mbgp_vpnv6fs'
+CAP_MBGP_L2VPNFS = 'cap_mbgp_l2vpnfs'
 CAP_RTC = 'cap_rtc'
 RTC_AS = 'rtc_as'
 HOLD_TIME = 'hold_time'
@@ -688,6 +689,15 @@ def validate_cap_mbgp_vpnv66fs(cmv6fs):
     return cmv6fs
 
 
+@validate(name=CAP_MBGP_L2VPNFS)
+def validate_cap_mbgp_l2vpnfs(cml2fs):
+    if not isinstance(cml2fs, bool):
+        raise ConfigTypeError(desc='Invalid MP-BGP '
+                              'L2VPN Flow Specification capability '
+                              'settings: %s. Boolean value expected' % cml2fs)
+    return cml2fs
+
+
 @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 d99e509..e4490c1 100644
--- a/ryu/services/protocols/bgp/rtconf/neighbors.py
+++ b/ryu/services/protocols/bgp/rtconf/neighbors.py
@@ -31,6 +31,7 @@ from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC
 from ryu.lib.packet.bgp import RF_IPv6_FLOWSPEC
 from ryu.lib.packet.bgp import RF_VPNv4_FLOWSPEC
 from ryu.lib.packet.bgp import RF_VPNv6_FLOWSPEC
+from ryu.lib.packet.bgp import RF_L2VPN_FLOWSPEC
 from ryu.lib.packet.bgp import RF_RTC_UC
 from ryu.lib.packet.bgp import BGPOptParamCapabilityFourOctetAsNumber
 from ryu.lib.packet.bgp import BGPOptParamCapabilityEnhancedRouteRefresh
@@ -56,6 +57,7 @@ from ryu.services.protocols.bgp.rtconf.base import 
CAP_MBGP_IPV4FS
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6FS
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4FS
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6FS
+from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_L2VPNFS
 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
@@ -117,6 +119,7 @@ DEFAULT_CAP_MBGP_IPV4FS = False
 DEFAULT_CAP_MBGP_IPV6FS = False
 DEFAULT_CAP_MBGP_VPNV4FS = False
 DEFAULT_CAP_MBGP_VPNV6FS = False
+DEFAULT_CAP_MBGP_L2VPNFS = False
 DEFAULT_HOLD_TIME = 40
 DEFAULT_ENABLED = True
 DEFAULT_CAP_RTC = False
@@ -332,6 +335,7 @@ class NeighborConf(ConfWithId, ConfWithStats):
                                    CAP_RTC, CAP_MBGP_EVPN,
                                    CAP_MBGP_IPV4FS, CAP_MBGP_VPNV4FS,
                                    CAP_MBGP_IPV6FS, CAP_MBGP_VPNV6FS,
+                                   CAP_MBGP_L2VPNFS,
                                    RTC_AS, HOLD_TIME,
                                    ENABLED, MULTI_EXIT_DISC, MAX_PREFIXES,
                                    ADVERTISE_PEER_AS, SITE_OF_ORIGINS,
@@ -372,6 +376,8 @@ class NeighborConf(ConfWithId, ConfWithStats):
             CAP_MBGP_VPNV4FS, DEFAULT_CAP_MBGP_VPNV4FS, **kwargs)
         self._settings[CAP_MBGP_VPNV6FS] = compute_optional_conf(
             CAP_MBGP_VPNV6FS, DEFAULT_CAP_MBGP_VPNV6FS, **kwargs)
+        self._settings[CAP_MBGP_L2VPNFS] = compute_optional_conf(
+            CAP_MBGP_L2VPNFS, DEFAULT_CAP_MBGP_L2VPNFS, **kwargs)
         self._settings[HOLD_TIME] = compute_optional_conf(
             HOLD_TIME, DEFAULT_HOLD_TIME, **kwargs)
         self._settings[ENABLED] = compute_optional_conf(
@@ -558,6 +564,10 @@ class NeighborConf(ConfWithId, ConfWithStats):
         return self._settings[CAP_MBGP_VPNV6FS]
 
     @property
+    def cap_mbgp_l2vpnfs(self):
+        return self._settings[CAP_MBGP_L2VPNFS]
+
+    @property
     def cap_rtc(self):
         return self._settings[CAP_RTC]
 
@@ -701,6 +711,11 @@ class NeighborConf(ConfWithId, ConfWithStats):
                 BGPOptParamCapabilityMultiprotocol(
                     RF_VPNv6_FLOWSPEC.afi, RF_VPNv6_FLOWSPEC.safi))
 
+        if self.cap_mbgp_l2vpnfs:
+            mbgp_caps.append(
+                BGPOptParamCapabilityMultiprotocol(
+                    RF_L2VPN_FLOWSPEC.afi, RF_L2VPN_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 a918c5b..72958df 100644
--- a/ryu/services/protocols/bgp/rtconf/vrfs.py
+++ b/ryu/services/protocols/bgp/rtconf/vrfs.py
@@ -25,6 +25,7 @@ from ryu.lib.packet.bgp import RF_IPv6_UC
 from ryu.lib.packet.bgp import RF_L2_EVPN
 from ryu.lib.packet.bgp import RF_IPv4_FLOWSPEC
 from ryu.lib.packet.bgp import RF_IPv6_FLOWSPEC
+from ryu.lib.packet.bgp import RF_L2VPN_FLOWSPEC
 
 from ryu.services.protocols.bgp.utils import validation
 from ryu.services.protocols.bgp.base import get_validator
@@ -63,12 +64,14 @@ VRF_RF_IPV6 = 'ipv6'
 VRF_RF_L2_EVPN = 'evpn'
 VRF_RF_IPV4_FLOWSPEC = 'ipv4fs'
 VRF_RF_IPV6_FLOWSPEC = 'ipv6fs'
+VRF_RF_L2VPN_FLOWSPEC = 'l2vpnfs'
 SUPPORTED_VRF_RF = (
     VRF_RF_IPV4,
     VRF_RF_IPV6,
     VRF_RF_L2_EVPN,
     VRF_RF_IPV4_FLOWSPEC,
     VRF_RF_IPV6_FLOWSPEC,
+    VRF_RF_L2VPN_FLOWSPEC,
 )
 
 
@@ -240,6 +243,8 @@ class VrfConf(ConfWithId, ConfWithStats):
             return RF_IPv4_FLOWSPEC
         elif vrf_rf == VRF_RF_IPV6_FLOWSPEC:
             return RF_IPv6_FLOWSPEC
+        elif vrf_rf == VRF_RF_L2VPN_FLOWSPEC:
+            return RF_L2VPN_FLOWSPEC
         else:
             raise ValueError('Unsupported VRF route family given %s' % vrf_rf)
 
@@ -255,6 +260,8 @@ class VrfConf(ConfWithId, ConfWithStats):
             return VRF_RF_IPV4_FLOWSPEC
         elif route_family == RF_IPv6_FLOWSPEC:
             return VRF_RF_IPV6_FLOWSPEC
+        elif route_family == RF_L2VPN_FLOWSPEC:
+            return VRF_RF_L2VPN_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 2d06694..5a9824d 100644
--- a/ryu/services/protocols/bgp/utils/bgp.py
+++ b/ryu/services/protocols/bgp/utils/bgp.py
@@ -32,6 +32,7 @@ from ryu.lib.packet.bgp import (
     RF_IPv6_FLOWSPEC,
     RF_VPNv4_FLOWSPEC,
     RF_VPNv6_FLOWSPEC,
+    RF_L2VPN_FLOWSPEC,
     RF_RTC_UC,
     RouteTargetMembershipNLRI,
     BGP_ATTR_TYPE_MULTI_EXIT_DISC,
@@ -49,6 +50,8 @@ from ryu.lib.packet.bgp import (
     BGPFlowSpecTrafficActionCommunity,
     BGPFlowSpecRedirectCommunity,
     BGPFlowSpecTrafficMarkingCommunity,
+    BGPFlowSpecVlanActionCommunity,
+    BGPFlowSpecTPIDActionCommunity,
 )
 from ryu.services.protocols.bgp.info_base.rtc import RtcPath
 from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Path
@@ -60,6 +63,7 @@ from ryu.services.protocols.bgp.info_base.ipv4fs import 
IPv4FlowSpecPath
 from ryu.services.protocols.bgp.info_base.ipv6fs import IPv6FlowSpecPath
 from ryu.services.protocols.bgp.info_base.vpnv4fs import VPNv4FlowSpecPath
 from ryu.services.protocols.bgp.info_base.vpnv6fs import VPNv6FlowSpecPath
+from ryu.services.protocols.bgp.info_base.l2vpnfs import L2VPNFlowSpecPath
 
 
 LOG = logging.getLogger('utils.bgp')
@@ -74,6 +78,7 @@ _ROUTE_FAMILY_TO_PATH_MAP = {RF_IPv4_UC: Ipv4Path,
                              RF_IPv6_FLOWSPEC: IPv6FlowSpecPath,
                              RF_VPNv4_FLOWSPEC: VPNv4FlowSpecPath,
                              RF_VPNv6_FLOWSPEC: VPNv6FlowSpecPath,
+                             RF_L2VPN_FLOWSPEC: L2VPNFlowSpecPath,
                              RF_RTC_UC: RtcPath}
 
 
@@ -249,6 +254,32 @@ def create_v6flowspec_actions(actions=None):
     return _create_actions(actions, action_types)
 
 
+def create_l2vpnflowspec_actions(actions=None):
+    """
+    Create list of traffic filtering actions for L2VPN Flow Specification.
+    """
+    from ryu.services.protocols.bgp.api.prefix import (
+        FLOWSPEC_ACTION_TRAFFIC_RATE,
+        FLOWSPEC_ACTION_TRAFFIC_ACTION,
+        FLOWSPEC_ACTION_REDIRECT,
+        FLOWSPEC_ACTION_TRAFFIC_MARKING,
+        FLOWSPEC_ACTION_VLAN,
+        FLOWSPEC_ACTION_TPID,
+    )
+
+    # Supported action type for L2VPN.
+    action_types = {
+        FLOWSPEC_ACTION_TRAFFIC_RATE: BGPFlowSpecTrafficRateCommunity,
+        FLOWSPEC_ACTION_TRAFFIC_ACTION: BGPFlowSpecTrafficActionCommunity,
+        FLOWSPEC_ACTION_REDIRECT: BGPFlowSpecRedirectCommunity,
+        FLOWSPEC_ACTION_TRAFFIC_MARKING: BGPFlowSpecTrafficMarkingCommunity,
+        FLOWSPEC_ACTION_VLAN: BGPFlowSpecVlanActionCommunity,
+        FLOWSPEC_ACTION_TPID: BGPFlowSpecTPIDActionCommunity,
+    }
+
+    return _create_actions(actions, action_types)
+
+
 def _create_actions(actions, action_types):
     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