mirror of
https://github.com/faucetsdn/ryu.git
synced 2026-01-22 17:12:01 +01:00
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>
This commit is contained in:
parent
a486539400
commit
b3a83ef185
@ -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 = {}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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,
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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(
|
||||
@ -518,6 +530,14 @@ class NeighborConf(ConfWithId, ConfWithStats):
|
||||
def cap_mbgp_evpn(self):
|
||||
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
|
||||
|
||||
|
||||
@ -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' %
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user