hacking 3.2.x is quite old. Bump it to the version currently used by neutron. Change-Id: I69b4633b46a84d9dd7c6995a76379cf1072a304c
463 lines
17 KiB
Python
463 lines
17 KiB
Python
# Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""
|
|
Prefix related APIs.
|
|
"""
|
|
import logging
|
|
|
|
from os_ken.lib.packet.bgp import EvpnEsi
|
|
from os_ken.lib.packet.bgp import EvpnNLRI
|
|
from os_ken.lib.packet.bgp import EvpnEthernetAutoDiscoveryNLRI
|
|
from os_ken.lib.packet.bgp import EvpnMacIPAdvertisementNLRI
|
|
from os_ken.lib.packet.bgp import EvpnInclusiveMulticastEthernetTagNLRI
|
|
from os_ken.lib.packet.bgp import EvpnEthernetSegmentNLRI
|
|
from os_ken.lib.packet.bgp import EvpnIpPrefixNLRI
|
|
from os_ken.lib.packet.bgp import BGPPathAttributePmsiTunnel
|
|
from os_ken.lib.packet.bgp import FlowSpecIPv4NLRI
|
|
from os_ken.lib.packet.bgp import FlowSpecIPv6NLRI
|
|
from os_ken.lib.packet.bgp import FlowSpecVPNv4NLRI
|
|
from os_ken.lib.packet.bgp import FlowSpecVPNv6NLRI
|
|
from os_ken.lib.packet.bgp import FlowSpecL2VPNNLRI
|
|
from os_ken.lib.packet.bgp import BGPFlowSpecTrafficRateCommunity
|
|
from os_ken.lib.packet.bgp import BGPFlowSpecTrafficActionCommunity
|
|
from os_ken.lib.packet.bgp import BGPFlowSpecRedirectCommunity
|
|
from os_ken.lib.packet.bgp import BGPFlowSpecTrafficMarkingCommunity
|
|
from os_ken.lib.packet.bgp import BGPFlowSpecVlanActionCommunity
|
|
from os_ken.lib.packet.bgp import BGPFlowSpecTPIDActionCommunity
|
|
|
|
from os_ken.services.protocols.bgp.api.base import EVPN_ROUTE_TYPE
|
|
from os_ken.services.protocols.bgp.api.base import EVPN_ESI
|
|
from os_ken.services.protocols.bgp.api.base import EVPN_ETHERNET_TAG_ID
|
|
from os_ken.services.protocols.bgp.api.base import REDUNDANCY_MODE
|
|
from os_ken.services.protocols.bgp.api.base import MAC_ADDR
|
|
from os_ken.services.protocols.bgp.api.base import IP_ADDR
|
|
from os_ken.services.protocols.bgp.api.base import IP_PREFIX
|
|
from os_ken.services.protocols.bgp.api.base import GW_IP_ADDR
|
|
from os_ken.services.protocols.bgp.api.base import MPLS_LABELS
|
|
from os_ken.services.protocols.bgp.api.base import NEXT_HOP
|
|
from os_ken.services.protocols.bgp.api.base import PREFIX
|
|
from os_ken.services.protocols.bgp.api.base import RegisterWithArgChecks
|
|
from os_ken.services.protocols.bgp.api.base import ROUTE_DISTINGUISHER
|
|
from os_ken.services.protocols.bgp.api.base import VPN_LABEL
|
|
from os_ken.services.protocols.bgp.api.base import EVPN_VNI
|
|
from os_ken.services.protocols.bgp.api.base import TUNNEL_TYPE
|
|
from os_ken.services.protocols.bgp.api.base import PMSI_TUNNEL_TYPE
|
|
from os_ken.services.protocols.bgp.api.base import MAC_MOBILITY
|
|
from os_ken.services.protocols.bgp.api.base import TUNNEL_ENDPOINT_IP
|
|
from os_ken.services.protocols.bgp.api.base import FLOWSPEC_FAMILY
|
|
from os_ken.services.protocols.bgp.api.base import FLOWSPEC_RULES
|
|
from os_ken.services.protocols.bgp.api.base import FLOWSPEC_ACTIONS
|
|
from os_ken.services.protocols.bgp.base import add_bgp_error_metadata
|
|
from os_ken.services.protocols.bgp.base import PREFIX_ERROR_CODE
|
|
from os_ken.services.protocols.bgp.base import validate
|
|
from os_ken.services.protocols.bgp.core import BgpCoreError
|
|
from os_ken.services.protocols.bgp.core_manager import CORE_MANAGER
|
|
from os_ken.services.protocols.bgp.rtconf.base import ConfigValueError
|
|
from os_ken.services.protocols.bgp.rtconf.base import RuntimeConfigError
|
|
from os_ken.services.protocols.bgp.rtconf.vrfs import VRF_RF
|
|
from os_ken.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4
|
|
from os_ken.services.protocols.bgp.rtconf.vrfs import VRF_RF_L2_EVPN
|
|
from os_ken.services.protocols.bgp.utils import validation
|
|
|
|
LOG = logging.getLogger('bgpspeaker.api.prefix')
|
|
|
|
# Maximum value of the Ethernet Tag ID
|
|
EVPN_MAX_ET = EvpnNLRI.MAX_ET
|
|
|
|
# ESI Types
|
|
ESI_TYPE_ARBITRARY = EvpnEsi.ARBITRARY
|
|
ESI_TYPE_LACP = EvpnEsi.LACP
|
|
ESI_TYPE_L2_BRIDGE = EvpnEsi.L2_BRIDGE
|
|
ESI_TYPE_MAC_BASED = EvpnEsi.MAC_BASED
|
|
ESI_TYPE_ROUTER_ID = EvpnEsi.ROUTER_ID
|
|
ESI_TYPE_AS_BASED = EvpnEsi.AS_BASED
|
|
SUPPORTED_ESI_TYPES = [
|
|
ESI_TYPE_ARBITRARY,
|
|
ESI_TYPE_LACP,
|
|
ESI_TYPE_L2_BRIDGE,
|
|
ESI_TYPE_MAC_BASED,
|
|
ESI_TYPE_ROUTER_ID,
|
|
ESI_TYPE_AS_BASED,
|
|
]
|
|
|
|
# Constants used in API calls for EVPN
|
|
EVPN_ETH_AUTO_DISCOVERY = EvpnEthernetAutoDiscoveryNLRI.ROUTE_TYPE_NAME
|
|
EVPN_MAC_IP_ADV_ROUTE = EvpnMacIPAdvertisementNLRI.ROUTE_TYPE_NAME
|
|
EVPN_MULTICAST_ETAG_ROUTE = (
|
|
EvpnInclusiveMulticastEthernetTagNLRI.ROUTE_TYPE_NAME)
|
|
EVPN_ETH_SEGMENT = EvpnEthernetSegmentNLRI.ROUTE_TYPE_NAME
|
|
EVPN_IP_PREFIX_ROUTE = EvpnIpPrefixNLRI.ROUTE_TYPE_NAME
|
|
SUPPORTED_EVPN_ROUTE_TYPES = [
|
|
EVPN_ETH_AUTO_DISCOVERY,
|
|
EVPN_MAC_IP_ADV_ROUTE,
|
|
EVPN_MULTICAST_ETAG_ROUTE,
|
|
EVPN_ETH_SEGMENT,
|
|
EVPN_IP_PREFIX_ROUTE,
|
|
]
|
|
|
|
# Constants used in API calls for Flow Specification
|
|
FLOWSPEC_FAMILY_IPV4 = FlowSpecIPv4NLRI.FLOWSPEC_FAMILY
|
|
FLOWSPEC_FAMILY_IPV6 = FlowSpecIPv6NLRI.FLOWSPEC_FAMILY
|
|
FLOWSPEC_FAMILY_VPNV4 = FlowSpecVPNv4NLRI.FLOWSPEC_FAMILY
|
|
FLOWSPEC_FAMILY_VPNV6 = FlowSpecVPNv6NLRI.FLOWSPEC_FAMILY
|
|
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
|
|
# 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
|
|
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,
|
|
)
|
|
|
|
|
|
# Constants for ESI Label extended community
|
|
REDUNDANCY_MODE_ALL_ACTIVE = 'all_active'
|
|
REDUNDANCY_MODE_SINGLE_ACTIVE = 'single_active'
|
|
SUPPORTED_REDUNDANCY_MODES = [
|
|
REDUNDANCY_MODE_ALL_ACTIVE,
|
|
REDUNDANCY_MODE_SINGLE_ACTIVE,
|
|
]
|
|
|
|
# Constants for BGP Tunnel Encapsulation Attribute
|
|
TUNNEL_TYPE_VXLAN = 'vxlan'
|
|
TUNNEL_TYPE_NVGRE = 'nvgre'
|
|
TUNNEL_TYPE_MPLS = 'mpls'
|
|
TUNNEL_TYPE_MPLS_IN_GRE = 'mpls_in_gre'
|
|
TUNNEL_TYPE_VXLAN_GRE = 'vxlan_gre'
|
|
SUPPORTED_TUNNEL_TYPES = [
|
|
TUNNEL_TYPE_VXLAN,
|
|
TUNNEL_TYPE_NVGRE,
|
|
TUNNEL_TYPE_MPLS,
|
|
TUNNEL_TYPE_MPLS_IN_GRE,
|
|
TUNNEL_TYPE_VXLAN_GRE,
|
|
]
|
|
# Constants for PMSI Tunnel Attribute
|
|
PMSI_TYPE_NO_TUNNEL_INFO = (
|
|
BGPPathAttributePmsiTunnel.TYPE_NO_TUNNEL_INFORMATION_PRESENT
|
|
)
|
|
PMSI_TYPE_INGRESS_REP = (
|
|
BGPPathAttributePmsiTunnel.TYPE_INGRESS_REPLICATION
|
|
)
|
|
SUPPORTED_PMSI_TUNNEL_TYPES = [
|
|
PMSI_TYPE_NO_TUNNEL_INFO,
|
|
PMSI_TYPE_INGRESS_REP,
|
|
]
|
|
|
|
|
|
@add_bgp_error_metadata(code=PREFIX_ERROR_CODE,
|
|
sub_code=1,
|
|
def_desc='Unknown error related to operation on '
|
|
'prefixes')
|
|
class PrefixError(RuntimeConfigError):
|
|
pass
|
|
|
|
|
|
@validate(name=PREFIX)
|
|
def is_valid_prefix(prefix):
|
|
if not (validation.is_valid_ipv4_prefix(prefix)
|
|
or validation.is_valid_ipv6_prefix(prefix)):
|
|
raise ConfigValueError(conf_name=PREFIX,
|
|
conf_value=prefix)
|
|
|
|
|
|
@validate(name=NEXT_HOP)
|
|
def is_valid_next_hop(next_hop):
|
|
if not (validation.is_valid_ipv4(next_hop)
|
|
or validation.is_valid_ipv6(next_hop)):
|
|
raise ConfigValueError(conf_name=NEXT_HOP,
|
|
conf_value=next_hop)
|
|
|
|
|
|
@validate(name=EVPN_ROUTE_TYPE)
|
|
def is_valid_evpn_route_type(route_type):
|
|
if route_type not in SUPPORTED_EVPN_ROUTE_TYPES:
|
|
raise ConfigValueError(conf_name=EVPN_ROUTE_TYPE,
|
|
conf_value=route_type)
|
|
|
|
|
|
@validate(name=EVPN_ESI)
|
|
def is_valid_esi(esi):
|
|
if not validation.is_valid_esi(esi):
|
|
raise ConfigValueError(conf_name=EVPN_ESI,
|
|
conf_value=esi)
|
|
|
|
|
|
@validate(name=EVPN_ETHERNET_TAG_ID)
|
|
def is_valid_ethernet_tag_id(ethernet_tag_id):
|
|
if not validation.is_valid_ethernet_tag_id(ethernet_tag_id):
|
|
raise ConfigValueError(conf_name=EVPN_ETHERNET_TAG_ID,
|
|
conf_value=ethernet_tag_id)
|
|
|
|
|
|
@validate(name=REDUNDANCY_MODE)
|
|
def is_valid_redundancy_mode(redundancy_mode):
|
|
if redundancy_mode not in SUPPORTED_REDUNDANCY_MODES:
|
|
raise ConfigValueError(conf_name=REDUNDANCY_MODE,
|
|
conf_value=redundancy_mode)
|
|
|
|
|
|
@validate(name=MAC_ADDR)
|
|
def is_valid_mac_addr(addr):
|
|
if not validation.is_valid_mac(addr):
|
|
raise ConfigValueError(conf_name=MAC_ADDR,
|
|
conf_value=addr)
|
|
|
|
|
|
@validate(name=IP_ADDR)
|
|
def is_valid_ip_addr(addr):
|
|
# Note: Allows empty IP Address (means length=0).
|
|
# e.g.) L2VPN MAC advertisement of Cisco NX-OS
|
|
if not (addr is None
|
|
or validation.is_valid_ipv4(addr)
|
|
or validation.is_valid_ipv6(addr)):
|
|
raise ConfigValueError(conf_name=IP_ADDR,
|
|
conf_value=addr)
|
|
|
|
|
|
@validate(name=IP_PREFIX)
|
|
def is_valid_ip_prefix(prefix):
|
|
if not (validation.is_valid_ipv4_prefix(prefix)
|
|
or validation.is_valid_ipv6_prefix(prefix)):
|
|
raise ConfigValueError(conf_name=IP_PREFIX,
|
|
conf_value=prefix)
|
|
|
|
|
|
@validate(name=GW_IP_ADDR)
|
|
def is_valid_gw_ip_addr(addr):
|
|
if not (validation.is_valid_ipv4(addr)
|
|
or validation.is_valid_ipv6(addr)):
|
|
raise ConfigValueError(conf_name=GW_IP_ADDR,
|
|
conf_value=addr)
|
|
|
|
|
|
@validate(name=MPLS_LABELS)
|
|
def is_valid_mpls_labels(labels):
|
|
if not validation.is_valid_mpls_labels(labels):
|
|
raise ConfigValueError(conf_name=MPLS_LABELS,
|
|
conf_value=labels)
|
|
|
|
|
|
@validate(name=EVPN_VNI)
|
|
def is_valid_vni(vni):
|
|
if not validation.is_valid_vni(vni):
|
|
raise ConfigValueError(conf_name=EVPN_VNI,
|
|
conf_value=vni)
|
|
|
|
|
|
@validate(name=TUNNEL_TYPE)
|
|
def is_valid_tunnel_type(tunnel_type):
|
|
if tunnel_type not in SUPPORTED_TUNNEL_TYPES:
|
|
raise ConfigValueError(conf_name=TUNNEL_TYPE,
|
|
conf_value=tunnel_type)
|
|
|
|
|
|
@validate(name=PMSI_TUNNEL_TYPE)
|
|
def is_valid_pmsi_tunnel_type(pmsi_tunnel_type):
|
|
if pmsi_tunnel_type not in SUPPORTED_PMSI_TUNNEL_TYPES:
|
|
raise ConfigValueError(conf_name=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])
|
|
def add_local(route_dist, prefix, next_hop, route_family=VRF_RF_IPV4):
|
|
"""Adds *prefix* from VRF identified by *route_dist* and sets the source as
|
|
network controller.
|
|
"""
|
|
try:
|
|
# Create new path and insert into appropriate VRF table.
|
|
tm = CORE_MANAGER.get_core_service().table_manager
|
|
label = tm.update_vrf_table(route_dist, prefix, next_hop, route_family)
|
|
# Currently we only allocate one label per local_prefix,
|
|
# so we share first label from the list.
|
|
if label:
|
|
label = label[0]
|
|
|
|
# Send success response with new label.
|
|
return [{ROUTE_DISTINGUISHER: route_dist, PREFIX: prefix,
|
|
VRF_RF: route_family, VPN_LABEL: label}]
|
|
except BgpCoreError as e:
|
|
raise PrefixError(desc=e)
|
|
|
|
|
|
@RegisterWithArgChecks(name='prefix.delete_local',
|
|
req_args=[ROUTE_DISTINGUISHER, PREFIX],
|
|
opt_args=[VRF_RF])
|
|
def delete_local(route_dist, prefix, route_family=VRF_RF_IPV4):
|
|
"""Deletes/withdraws *prefix* from VRF identified by *route_dist* and
|
|
source as network controller.
|
|
"""
|
|
try:
|
|
tm = CORE_MANAGER.get_core_service().table_manager
|
|
tm.update_vrf_table(route_dist, prefix,
|
|
route_family=route_family, is_withdraw=True)
|
|
# Send success response.
|
|
return [{ROUTE_DISTINGUISHER: route_dist, PREFIX: prefix,
|
|
VRF_RF: route_family}]
|
|
except BgpCoreError as e:
|
|
raise PrefixError(desc=e)
|
|
|
|
|
|
# =============================================================================
|
|
# BGP EVPN Routes related APIs
|
|
# =============================================================================
|
|
|
|
@RegisterWithArgChecks(name='evpn_prefix.add_local',
|
|
req_args=[EVPN_ROUTE_TYPE, ROUTE_DISTINGUISHER,
|
|
NEXT_HOP],
|
|
opt_args=[EVPN_ESI, EVPN_ETHERNET_TAG_ID,
|
|
REDUNDANCY_MODE, MAC_ADDR, IP_ADDR, IP_PREFIX,
|
|
GW_IP_ADDR, EVPN_VNI, TUNNEL_TYPE,
|
|
PMSI_TUNNEL_TYPE, TUNNEL_ENDPOINT_IP,
|
|
MAC_MOBILITY])
|
|
def add_evpn_local(route_type, route_dist, next_hop, **kwargs):
|
|
"""Adds EVPN route from VRF identified by *route_dist*.
|
|
"""
|
|
|
|
if (route_type in [EVPN_ETH_AUTO_DISCOVERY, EVPN_ETH_SEGMENT]
|
|
and kwargs['esi'] == 0):
|
|
raise ConfigValueError(conf_name=EVPN_ESI,
|
|
conf_value=kwargs['esi'])
|
|
|
|
try:
|
|
# Create new path and insert into appropriate VRF table.
|
|
tm = CORE_MANAGER.get_core_service().table_manager
|
|
label = tm.update_vrf_table(route_dist, next_hop=next_hop,
|
|
route_family=VRF_RF_L2_EVPN,
|
|
route_type=route_type, **kwargs)
|
|
# Currently we only allocate one label per local route,
|
|
# so we share first label from the list.
|
|
if label:
|
|
label = label[0]
|
|
|
|
# Send success response with new label.
|
|
return [{EVPN_ROUTE_TYPE: route_type,
|
|
ROUTE_DISTINGUISHER: route_dist,
|
|
VRF_RF: VRF_RF_L2_EVPN,
|
|
VPN_LABEL: label}.update(kwargs)]
|
|
except BgpCoreError as e:
|
|
raise PrefixError(desc=e)
|
|
|
|
|
|
@RegisterWithArgChecks(name='evpn_prefix.delete_local',
|
|
req_args=[EVPN_ROUTE_TYPE, ROUTE_DISTINGUISHER],
|
|
opt_args=[EVPN_ESI, EVPN_ETHERNET_TAG_ID, MAC_ADDR,
|
|
IP_ADDR, IP_PREFIX, EVPN_VNI])
|
|
def delete_evpn_local(route_type, route_dist, **kwargs):
|
|
"""Deletes/withdraws EVPN route from VRF identified by *route_dist*.
|
|
"""
|
|
try:
|
|
tm = CORE_MANAGER.get_core_service().table_manager
|
|
tm.update_vrf_table(route_dist,
|
|
route_family=VRF_RF_L2_EVPN,
|
|
route_type=route_type, is_withdraw=True, **kwargs)
|
|
# Send success response.
|
|
return [{EVPN_ROUTE_TYPE: route_type,
|
|
ROUTE_DISTINGUISHER: route_dist,
|
|
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)
|