1 # Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
21 from ryu.lib.packet.bgp import EvpnEsi
22 from ryu.lib.packet.bgp import EvpnNLRI
23 from ryu.lib.packet.bgp import EvpnEthernetAutoDiscoveryNLRI
24 from ryu.lib.packet.bgp import EvpnMacIPAdvertisementNLRI
25 from ryu.lib.packet.bgp import EvpnInclusiveMulticastEthernetTagNLRI
26 from ryu.lib.packet.bgp import EvpnEthernetSegmentNLRI
27 from ryu.lib.packet.bgp import EvpnIpPrefixNLRI
28 from ryu.lib.packet.bgp import BGPPathAttributePmsiTunnel
29 from ryu.lib.packet.bgp import FlowSpecIPv4NLRI
30 from ryu.lib.packet.bgp import FlowSpecIPv6NLRI
31 from ryu.lib.packet.bgp import FlowSpecVPNv4NLRI
32 from ryu.lib.packet.bgp import FlowSpecVPNv6NLRI
33 from ryu.lib.packet.bgp import FlowSpecL2VPNNLRI
34 from ryu.lib.packet.bgp import BGPFlowSpecTrafficRateCommunity
35 from ryu.lib.packet.bgp import BGPFlowSpecTrafficActionCommunity
36 from ryu.lib.packet.bgp import BGPFlowSpecRedirectCommunity
37 from ryu.lib.packet.bgp import BGPFlowSpecTrafficMarkingCommunity
38 from ryu.lib.packet.bgp import BGPFlowSpecVlanActionCommunity
39 from ryu.lib.packet.bgp import BGPFlowSpecTPIDActionCommunity
41 from ryu.services.protocols.bgp.api.base import EVPN_ROUTE_TYPE
42 from ryu.services.protocols.bgp.api.base import EVPN_ESI
43 from ryu.services.protocols.bgp.api.base import EVPN_ETHERNET_TAG_ID
44 from ryu.services.protocols.bgp.api.base import REDUNDANCY_MODE
45 from ryu.services.protocols.bgp.api.base import MAC_ADDR
46 from ryu.services.protocols.bgp.api.base import IP_ADDR
47 from ryu.services.protocols.bgp.api.base import IP_PREFIX
48 from ryu.services.protocols.bgp.api.base import GW_IP_ADDR
49 from ryu.services.protocols.bgp.api.base import MPLS_LABELS
50 from ryu.services.protocols.bgp.api.base import NEXT_HOP
51 from ryu.services.protocols.bgp.api.base import PREFIX
52 from ryu.services.protocols.bgp.api.base import RegisterWithArgChecks
53 from ryu.services.protocols.bgp.api.base import ROUTE_DISTINGUISHER
54 from ryu.services.protocols.bgp.api.base import VPN_LABEL
55 from ryu.services.protocols.bgp.api.base import EVPN_VNI
56 from ryu.services.protocols.bgp.api.base import TUNNEL_TYPE
57 from ryu.services.protocols.bgp.api.base import PMSI_TUNNEL_TYPE
58 from ryu.services.protocols.bgp.api.base import FLOWSPEC_FAMILY
59 from ryu.services.protocols.bgp.api.base import FLOWSPEC_RULES
60 from ryu.services.protocols.bgp.api.base import FLOWSPEC_ACTIONS
61 from ryu.services.protocols.bgp.base import add_bgp_error_metadata
62 from ryu.services.protocols.bgp.base import PREFIX_ERROR_CODE
63 from ryu.services.protocols.bgp.base import validate
64 from ryu.services.protocols.bgp.core import BgpCoreError
65 from ryu.services.protocols.bgp.core_manager import CORE_MANAGER
66 from ryu.services.protocols.bgp.rtconf.base import ConfigValueError
67 from ryu.services.protocols.bgp.rtconf.base import RuntimeConfigError
68 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF
69 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4
70 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_L2_EVPN
71 from ryu.services.protocols.bgp.utils import validation
73 LOG = logging.getLogger('bgpspeaker.api.prefix')
75 # Maximum value of the Ethernet Tag ID
76 EVPN_MAX_ET = EvpnNLRI.MAX_ET
79 ESI_TYPE_ARBITRARY = EvpnEsi.ARBITRARY
80 ESI_TYPE_LACP = EvpnEsi.LACP
81 ESI_TYPE_L2_BRIDGE = EvpnEsi.L2_BRIDGE
82 ESI_TYPE_MAC_BASED = EvpnEsi.MAC_BASED
83 ESI_TYPE_ROUTER_ID = EvpnEsi.ROUTER_ID
84 ESI_TYPE_AS_BASED = EvpnEsi.AS_BASED
85 SUPPORTED_ESI_TYPES = [
94 # Constants used in API calls for EVPN
95 EVPN_ETH_AUTO_DISCOVERY = EvpnEthernetAutoDiscoveryNLRI.ROUTE_TYPE_NAME
96 EVPN_MAC_IP_ADV_ROUTE = EvpnMacIPAdvertisementNLRI.ROUTE_TYPE_NAME
97 EVPN_MULTICAST_ETAG_ROUTE = (
98 EvpnInclusiveMulticastEthernetTagNLRI.ROUTE_TYPE_NAME)
99 EVPN_ETH_SEGMENT = EvpnEthernetSegmentNLRI.ROUTE_TYPE_NAME
100 EVPN_IP_PREFIX_ROUTE = EvpnIpPrefixNLRI.ROUTE_TYPE_NAME
101 SUPPORTED_EVPN_ROUTE_TYPES = [
102 EVPN_ETH_AUTO_DISCOVERY,
103 EVPN_MAC_IP_ADV_ROUTE,
104 EVPN_MULTICAST_ETAG_ROUTE,
106 EVPN_IP_PREFIX_ROUTE,
109 # Constants used in API calls for Flow Specification
110 FLOWSPEC_FAMILY_IPV4 = FlowSpecIPv4NLRI.FLOWSPEC_FAMILY
111 FLOWSPEC_FAMILY_IPV6 = FlowSpecIPv6NLRI.FLOWSPEC_FAMILY
112 FLOWSPEC_FAMILY_VPNV4 = FlowSpecVPNv4NLRI.FLOWSPEC_FAMILY
113 FLOWSPEC_FAMILY_VPNV6 = FlowSpecVPNv6NLRI.FLOWSPEC_FAMILY
114 FLOWSPEC_FAMILY_L2VPN = FlowSpecL2VPNNLRI.FLOWSPEC_FAMILY
115 SUPPORTED_FLOWSPEC_FAMILIES = (
116 FLOWSPEC_FAMILY_IPV4,
117 FLOWSPEC_FAMILY_IPV6,
118 FLOWSPEC_FAMILY_VPNV4,
119 FLOWSPEC_FAMILY_VPNV6,
120 FLOWSPEC_FAMILY_L2VPN,
123 # Constants for the Traffic Filtering Actions of Flow Specification
124 # Constants for the Traffic Filtering Actions of Flow Specification.
125 FLOWSPEC_ACTION_TRAFFIC_RATE = BGPFlowSpecTrafficRateCommunity.ACTION_NAME
126 FLOWSPEC_ACTION_TRAFFIC_ACTION = BGPFlowSpecTrafficActionCommunity.ACTION_NAME
127 FLOWSPEC_ACTION_REDIRECT = BGPFlowSpecRedirectCommunity.ACTION_NAME
128 FLOWSPEC_ACTION_TRAFFIC_MARKING = BGPFlowSpecTrafficMarkingCommunity.ACTION_NAME
129 FLOWSPEC_ACTION_VLAN = BGPFlowSpecVlanActionCommunity.ACTION_NAME
130 FLOWSPEC_ACTION_TPID = BGPFlowSpecTPIDActionCommunity.ACTION_NAME
132 SUPPORTTED_FLOWSPEC_ACTIONS = (
133 FLOWSPEC_ACTION_TRAFFIC_RATE,
134 FLOWSPEC_ACTION_TRAFFIC_ACTION,
135 FLOWSPEC_ACTION_REDIRECT,
136 FLOWSPEC_ACTION_TRAFFIC_MARKING,
137 FLOWSPEC_ACTION_VLAN,
138 FLOWSPEC_ACTION_TPID,
142 # Constants for ESI Label extended community
143 REDUNDANCY_MODE_ALL_ACTIVE = 'all_active'
144 REDUNDANCY_MODE_SINGLE_ACTIVE = 'single_active'
145 SUPPORTED_REDUNDANCY_MODES = [
146 REDUNDANCY_MODE_ALL_ACTIVE,
147 REDUNDANCY_MODE_SINGLE_ACTIVE,
150 # Constants for BGP Tunnel Encapsulation Attribute
151 TUNNEL_TYPE_VXLAN = 'vxlan'
152 TUNNEL_TYPE_NVGRE = 'nvgre'
153 TUNNEL_TYPE_MPLS = 'mpls'
154 TUNNEL_TYPE_MPLS_IN_GRE = 'mpls_in_gre'
155 TUNNEL_TYPE_VXLAN_GRE = 'vxlan_gre'
156 SUPPORTED_TUNNEL_TYPES = [
160 TUNNEL_TYPE_MPLS_IN_GRE,
161 TUNNEL_TYPE_VXLAN_GRE,
163 # Constants for PMSI Tunnel Attribute
164 PMSI_TYPE_NO_TUNNEL_INFO = (
165 BGPPathAttributePmsiTunnel.TYPE_NO_TUNNEL_INFORMATION_PRESENT
167 PMSI_TYPE_INGRESS_REP = (
168 BGPPathAttributePmsiTunnel.TYPE_INGRESS_REPLICATION
170 SUPPORTED_PMSI_TUNNEL_TYPES = [
171 PMSI_TYPE_NO_TUNNEL_INFO,
172 PMSI_TYPE_INGRESS_REP,
176 @add_bgp_error_metadata(code=PREFIX_ERROR_CODE,
178 def_desc='Unknown error related to operation on '
180 class PrefixError(RuntimeConfigError):
184 @validate(name=PREFIX)
185 def is_valid_prefix(prefix):
186 if not (validation.is_valid_ipv4_prefix(prefix)
187 or validation.is_valid_ipv6_prefix(prefix)):
188 raise ConfigValueError(conf_name=PREFIX,
192 @validate(name=NEXT_HOP)
193 def is_valid_next_hop(next_hop):
194 if not (validation.is_valid_ipv4(next_hop)
195 or validation.is_valid_ipv6(next_hop)):
196 raise ConfigValueError(conf_name=NEXT_HOP,
200 @validate(name=EVPN_ROUTE_TYPE)
201 def is_valid_evpn_route_type(route_type):
202 if route_type not in SUPPORTED_EVPN_ROUTE_TYPES:
203 raise ConfigValueError(conf_name=EVPN_ROUTE_TYPE,
204 conf_value=route_type)
207 @validate(name=EVPN_ESI)
208 def is_valid_esi(esi):
209 if not validation.is_valid_esi(esi):
210 raise ConfigValueError(conf_name=EVPN_ESI,
214 @validate(name=EVPN_ETHERNET_TAG_ID)
215 def is_valid_ethernet_tag_id(ethernet_tag_id):
216 if not validation.is_valid_ethernet_tag_id(ethernet_tag_id):
217 raise ConfigValueError(conf_name=EVPN_ETHERNET_TAG_ID,
218 conf_value=ethernet_tag_id)
221 @validate(name=REDUNDANCY_MODE)
222 def is_valid_redundancy_mode(redundancy_mode):
223 if redundancy_mode not in SUPPORTED_REDUNDANCY_MODES:
224 raise ConfigValueError(conf_name=REDUNDANCY_MODE,
225 conf_value=redundancy_mode)
228 @validate(name=MAC_ADDR)
229 def is_valid_mac_addr(addr):
230 if not validation.is_valid_mac(addr):
231 raise ConfigValueError(conf_name=MAC_ADDR,
235 @validate(name=IP_ADDR)
236 def is_valid_ip_addr(addr):
237 # Note: Allows empty IP Address (means length=0).
238 # e.g.) L2VPN MAC advertisement of Cisco NX-OS
240 or validation.is_valid_ipv4(addr)
241 or validation.is_valid_ipv6(addr)):
242 raise ConfigValueError(conf_name=IP_ADDR,
246 @validate(name=IP_PREFIX)
247 def is_valid_ip_prefix(prefix):
248 if not (validation.is_valid_ipv4_prefix(prefix)
249 or validation.is_valid_ipv6_prefix(prefix)):
250 raise ConfigValueError(conf_name=IP_PREFIX,
254 @validate(name=GW_IP_ADDR)
255 def is_valid_gw_ip_addr(addr):
256 if not (validation.is_valid_ipv4(addr)
257 or validation.is_valid_ipv6(addr)):
258 raise ConfigValueError(conf_name=GW_IP_ADDR,
262 @validate(name=MPLS_LABELS)
263 def is_valid_mpls_labels(labels):
264 if not validation.is_valid_mpls_labels(labels):
265 raise ConfigValueError(conf_name=MPLS_LABELS,
269 @validate(name=EVPN_VNI)
270 def is_valid_vni(vni):
271 if not validation.is_valid_vni(vni):
272 raise ConfigValueError(conf_name=EVPN_VNI,
276 @validate(name=TUNNEL_TYPE)
277 def is_valid_tunnel_type(tunnel_type):
278 if tunnel_type not in SUPPORTED_TUNNEL_TYPES:
279 raise ConfigValueError(conf_name=TUNNEL_TYPE,
280 conf_value=tunnel_type)
283 @validate(name=PMSI_TUNNEL_TYPE)
284 def is_valid_pmsi_tunnel_type(pmsi_tunnel_type):
285 if pmsi_tunnel_type not in SUPPORTED_PMSI_TUNNEL_TYPES:
286 raise ConfigValueError(conf_name=PMSI_TUNNEL_TYPE,
287 conf_value=pmsi_tunnel_type)
290 @validate(name=FLOWSPEC_FAMILY)
291 def is_valid_flowspec_family(flowspec_family):
292 if flowspec_family not in SUPPORTED_FLOWSPEC_FAMILIES:
293 raise ConfigValueError(conf_name=FLOWSPEC_FAMILY,
294 conf_value=flowspec_family)
297 @validate(name=FLOWSPEC_RULES)
298 def is_valid_flowspec_rules(rules):
299 if not isinstance(rules, dict):
300 raise ConfigValueError(conf_name=FLOWSPEC_RULES,
304 @validate(name=FLOWSPEC_ACTIONS)
305 def is_valid_flowspec_actions(actions):
307 if k not in SUPPORTTED_FLOWSPEC_ACTIONS:
308 raise ConfigValueError(conf_name=FLOWSPEC_ACTIONS,
312 @RegisterWithArgChecks(name='prefix.add_local',
313 req_args=[ROUTE_DISTINGUISHER, PREFIX, NEXT_HOP],
315 def add_local(route_dist, prefix, next_hop, route_family=VRF_RF_IPV4):
316 """Adds *prefix* from VRF identified by *route_dist* and sets the source as
320 # Create new path and insert into appropriate VRF table.
321 tm = CORE_MANAGER.get_core_service().table_manager
322 label = tm.update_vrf_table(route_dist, prefix, next_hop, route_family)
323 # Currently we only allocate one label per local_prefix,
324 # so we share first label from the list.
328 # Send success response with new label.
329 return [{ROUTE_DISTINGUISHER: route_dist, PREFIX: prefix,
330 VRF_RF: route_family, VPN_LABEL: label}]
331 except BgpCoreError as e:
332 raise PrefixError(desc=e)
335 @RegisterWithArgChecks(name='prefix.delete_local',
336 req_args=[ROUTE_DISTINGUISHER, PREFIX],
338 def delete_local(route_dist, prefix, route_family=VRF_RF_IPV4):
339 """Deletes/withdraws *prefix* from VRF identified by *route_dist* and
340 source as network controller.
343 tm = CORE_MANAGER.get_core_service().table_manager
344 tm.update_vrf_table(route_dist, prefix,
345 route_family=route_family, is_withdraw=True)
346 # Send success response.
347 return [{ROUTE_DISTINGUISHER: route_dist, PREFIX: prefix,
348 VRF_RF: route_family}]
349 except BgpCoreError as e:
350 raise PrefixError(desc=e)
353 # =============================================================================
354 # BGP EVPN Routes related APIs
355 # =============================================================================
357 @RegisterWithArgChecks(name='evpn_prefix.add_local',
358 req_args=[EVPN_ROUTE_TYPE, ROUTE_DISTINGUISHER,
360 opt_args=[EVPN_ESI, EVPN_ETHERNET_TAG_ID,
361 REDUNDANCY_MODE, MAC_ADDR, IP_ADDR, IP_PREFIX,
362 GW_IP_ADDR, EVPN_VNI, TUNNEL_TYPE,
364 def add_evpn_local(route_type, route_dist, next_hop, **kwargs):
365 """Adds EVPN route from VRF identified by *route_dist*.
368 if(route_type in [EVPN_ETH_AUTO_DISCOVERY, EVPN_ETH_SEGMENT]
369 and kwargs['esi'] == 0):
370 raise ConfigValueError(conf_name=EVPN_ESI,
371 conf_value=kwargs['esi'])
374 # Create new path and insert into appropriate VRF table.
375 tm = CORE_MANAGER.get_core_service().table_manager
376 label = tm.update_vrf_table(route_dist, next_hop=next_hop,
377 route_family=VRF_RF_L2_EVPN,
378 route_type=route_type, **kwargs)
379 # Currently we only allocate one label per local route,
380 # so we share first label from the list.
384 # Send success response with new label.
385 return [{EVPN_ROUTE_TYPE: route_type,
386 ROUTE_DISTINGUISHER: route_dist,
387 VRF_RF: VRF_RF_L2_EVPN,
388 VPN_LABEL: label}.update(kwargs)]
389 except BgpCoreError as e:
390 raise PrefixError(desc=e)
393 @RegisterWithArgChecks(name='evpn_prefix.delete_local',
394 req_args=[EVPN_ROUTE_TYPE, ROUTE_DISTINGUISHER],
395 opt_args=[EVPN_ESI, EVPN_ETHERNET_TAG_ID, MAC_ADDR,
396 IP_ADDR, IP_PREFIX, EVPN_VNI])
397 def delete_evpn_local(route_type, route_dist, **kwargs):
398 """Deletes/withdraws EVPN route from VRF identified by *route_dist*.
401 tm = CORE_MANAGER.get_core_service().table_manager
402 tm.update_vrf_table(route_dist,
403 route_family=VRF_RF_L2_EVPN,
404 route_type=route_type, is_withdraw=True, **kwargs)
405 # Send success response.
406 return [{EVPN_ROUTE_TYPE: route_type,
407 ROUTE_DISTINGUISHER: route_dist,
408 VRF_RF: VRF_RF_L2_EVPN}.update(kwargs)]
409 except BgpCoreError as e:
410 raise PrefixError(desc=e)
413 # =============================================================================
414 # BGP Flow Specification Routes related APIs
415 # =============================================================================
417 @RegisterWithArgChecks(
418 name='flowspec.add_local',
419 req_args=[FLOWSPEC_FAMILY, ROUTE_DISTINGUISHER, FLOWSPEC_RULES],
420 opt_args=[FLOWSPEC_ACTIONS])
421 def add_flowspec_local(flowspec_family, route_dist, rules, **kwargs):
422 """Adds Flow Specification route from VRF identified by *route_dist*.
425 # Create new path and insert into appropriate VRF table.
426 tm = CORE_MANAGER.get_core_service().table_manager
427 tm.update_flowspec_vrf_table(
428 flowspec_family=flowspec_family, route_dist=route_dist,
429 rules=rules, **kwargs)
431 # Send success response.
432 return [{FLOWSPEC_FAMILY: flowspec_family,
433 ROUTE_DISTINGUISHER: route_dist,
434 FLOWSPEC_RULES: rules}.update(kwargs)]
436 except BgpCoreError as e:
437 raise PrefixError(desc=e)
440 @RegisterWithArgChecks(
441 name='flowspec.del_local',
442 req_args=[FLOWSPEC_FAMILY, ROUTE_DISTINGUISHER, FLOWSPEC_RULES])
443 def del_flowspec_local(flowspec_family, route_dist, rules):
444 """Deletes/withdraws Flow Specification route from VRF identified
448 tm = CORE_MANAGER.get_core_service().table_manager
449 tm.update_flowspec_vrf_table(
450 flowspec_family=flowspec_family, route_dist=route_dist,
451 rules=rules, is_withdraw=True)
453 # Send success response.
454 return [{FLOWSPEC_FAMILY: flowspec_family,
455 ROUTE_DISTINGUISHER: route_dist,
456 FLOWSPEC_RULES: rules}]
458 except BgpCoreError as e:
459 raise PrefixError(desc=e)