From 40fe7ffdc5aced2e30abd364d856e772b8c80d8f Mon Sep 17 00:00:00 2001 From: IWASE Yusuke Date: Mon, 5 Sep 2016 09:41:35 +0900 Subject: BGPSpeaker: Support to advertise Tunnel Encapsulation This patch adds support to advertise the BGP Tunnel Encapsulation Attribute for the Ethernet VPN Routes. Signed-off-by: IWASE Yusuke Signed-off-by: FUJITA Tomonori --- ryu/lib/packet/bgp.py | 20 ++++++++++++++++++ ryu/services/protocols/bgp/api/base.py | 1 + ryu/services/protocols/bgp/api/prefix.py | 24 +++++++++++++++++++++- ryu/services/protocols/bgp/bgpspeaker.py | 11 +++++++++- .../protocols/bgp/core_managers/table_manager.py | 4 ++-- ryu/services/protocols/bgp/info_base/vrf.py | 11 ++++++++-- 6 files changed, 65 insertions(+), 6 deletions(-) diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py index 6b39f2dc..6d7cf3f6 100644 --- a/ryu/lib/packet/bgp.py +++ b/ryu/lib/packet/bgp.py @@ -2795,6 +2795,26 @@ class BGPEncapsulationExtendedCommunity(_ExtendedCommunity): super(BGPEncapsulationExtendedCommunity, self).__init__() self.do_init(BGPEncapsulationExtendedCommunity, self, kwargs) + @classmethod + def from_str(cls, tunnel_type): + """ + Returns an instance identified with the given `tunnel_type`. + + `tunnel_type` should be a str type value and corresponding to + BGP Tunnel Encapsulation Attribute Tunnel Type constants name + omitting `TUNNEL_TYPE_` prefix. + + Example: + - `gre` means TUNNEL_TYPE_GRE + - `vxlan` means TUNNEL_TYPE_VXLAN + + And raises AttributeError when the corresponding Tunnel Type + is not found to the given `tunnel_type`. + """ + return cls(subtype=_ExtendedCommunity.SUBTYPE_ENCAPSULATION, + tunnel_type=getattr(cls, + 'TUNNEL_TYPE_' + tunnel_type.upper())) + @_ExtendedCommunity.register_type(_ExtendedCommunity.EVPN_MAC_MOBILITY) class BGPEvpnMacMobilityExtendedCommunity(_ExtendedCommunity): diff --git a/ryu/services/protocols/bgp/api/base.py b/ryu/services/protocols/bgp/api/base.py index 9624e7be..49e78063 100644 --- a/ryu/services/protocols/bgp/api/base.py +++ b/ryu/services/protocols/bgp/api/base.py @@ -49,6 +49,7 @@ EVPN_ETHERNET_TAG_ID = 'ethernet_tag_id' MAC_ADDR = 'mac_addr' IP_ADDR = 'ip_addr' MPLS_LABELS = 'mpls_labels' +TUNNEL_TYPE = 'tunnel_type' # API call registry _CALL_REGISTRY = {} diff --git a/ryu/services/protocols/bgp/api/prefix.py b/ryu/services/protocols/bgp/api/prefix.py index f047b6ae..2bcb4e08 100644 --- a/ryu/services/protocols/bgp/api/prefix.py +++ b/ryu/services/protocols/bgp/api/prefix.py @@ -31,6 +31,7 @@ from ryu.services.protocols.bgp.api.base import PREFIX from ryu.services.protocols.bgp.api.base import RegisterWithArgChecks from ryu.services.protocols.bgp.api.base import ROUTE_DISTINGUISHER from ryu.services.protocols.bgp.api.base import VPN_LABEL +from ryu.services.protocols.bgp.api.base import TUNNEL_TYPE 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 @@ -54,6 +55,20 @@ SUPPORTED_EVPN_ROUTE_TYPES = [ EVPN_MULTICAST_ETAG_ROUTE, ] +# 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, +] + @add_bgp_error_metadata(code=PREFIX_ERROR_CODE, sub_code=1, @@ -122,6 +137,13 @@ def is_valid_mpls_labels(labels): conf_value=labels) +@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) + + @RegisterWithArgChecks(name='prefix.add_local', req_args=[ROUTE_DISTINGUISHER, PREFIX, NEXT_HOP], opt_args=[VRF_RF]) @@ -171,7 +193,7 @@ def delete_local(route_dist, prefix, route_family=VRF_RF_IPV4): req_args=[EVPN_ROUTE_TYPE, ROUTE_DISTINGUISHER, NEXT_HOP], opt_args=[EVPN_ESI, EVPN_ETHERNET_TAG_ID, MAC_ADDR, - IP_ADDR]) + IP_ADDR, TUNNEL_TYPE]) def add_evpn_local(route_type, route_dist, next_hop, **kwargs): """Adds EVPN route from VRF identified by *route_dist*. """ diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py index 582e38d0..879eaf24 100644 --- a/ryu/services/protocols/bgp/bgpspeaker.py +++ b/ryu/services/protocols/bgp/bgpspeaker.py @@ -31,8 +31,10 @@ from ryu.services.protocols.bgp.api.base import MAC_ADDR from ryu.services.protocols.bgp.api.base import NEXT_HOP from ryu.services.protocols.bgp.api.base import ROUTE_DISTINGUISHER from ryu.services.protocols.bgp.api.base import ROUTE_FAMILY +from ryu.services.protocols.bgp.api.base import TUNNEL_TYPE from ryu.services.protocols.bgp.api.prefix import EVPN_MAC_IP_ADV_ROUTE from ryu.services.protocols.bgp.api.prefix import EVPN_MULTICAST_ETAG_ROUTE +from ryu.services.protocols.bgp.api.prefix import TUNNEL_TYPE_MPLS 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 BGP_SERVER_PORT @@ -490,7 +492,7 @@ class BGPSpeaker(object): def evpn_prefix_add(self, route_type, route_dist, esi=0, ethernet_tag_id=None, mac_addr=None, ip_addr=None, - next_hop=None): + next_hop=None, tunnel_type=TUNNEL_TYPE_MPLS): """ This method adds a new EVPN route to be advertised. ``route_type`` specifies one of the EVPN route type name. The @@ -509,6 +511,9 @@ class BGPSpeaker(object): ``ip_addr`` specifies an IPv4 or IPv6 address to advertise. ``next_hop`` specifies the next hop address for this prefix. + + ``tunnel_type`` specifies the data plane encapsulation type + to advertise. The default is the MPLS encapsulation type. """ func_name = 'evpn_prefix.add_local' @@ -521,6 +526,10 @@ class BGPSpeaker(object): ROUTE_DISTINGUISHER: route_dist, NEXT_HOP: next_hop} + # Set optional arguments + if tunnel_type: + kwargs[TUNNEL_TYPE] = tunnel_type + # Set route type specific arguments if route_type == EVPN_MAC_IP_ADV_ROUTE: kwargs.update({ diff --git a/ryu/services/protocols/bgp/core_managers/table_manager.py b/ryu/services/protocols/bgp/core_managers/table_manager.py index b8285ca4..5320dbfa 100644 --- a/ryu/services/protocols/bgp/core_managers/table_manager.py +++ b/ryu/services/protocols/bgp/core_managers/table_manager.py @@ -482,7 +482,7 @@ class TableCoreManager(object): LOG.debug('No VRF table found that imports RTs: %s', path_rts) def update_vrf_table(self, route_dist, prefix=None, next_hop=None, - route_family=None, route_type=None, + route_family=None, route_type=None, tunnel_type=None, is_withdraw=False, **kwargs): """Update a BGP route in the VRF table identified by `route_dist` with the given `next_hop`. @@ -547,7 +547,7 @@ class TableCoreManager(object): # withdrawal. Hence multiple withdrawals have not side effect. return vrf_table.insert_vrf_path( nlri=prefix, next_hop=next_hop, gen_lbl=gen_lbl, - is_withdraw=is_withdraw) + is_withdraw=is_withdraw, tunnel_type=tunnel_type) def update_global_table(self, prefix, next_hop=None, is_withdraw=False): """Update a BGP route in the Global table for the given `prefix` diff --git a/ryu/services/protocols/bgp/info_base/vrf.py b/ryu/services/protocols/bgp/info_base/vrf.py index 620d5226..6a60fc82 100644 --- a/ryu/services/protocols/bgp/info_base/vrf.py +++ b/ryu/services/protocols/bgp/info_base/vrf.py @@ -30,6 +30,7 @@ from ryu.lib.packet.bgp import BGPPathAttributeAsPath from ryu.lib.packet.bgp import BGPPathAttributeExtendedCommunities from ryu.lib.packet.bgp import BGPTwoOctetAsSpecificExtendedCommunity from ryu.lib.packet.bgp import BGPPathAttributeMultiExitDisc +from ryu.lib.packet.bgp import BGPEncapsulationExtendedCommunity from ryu.lib.packet.bgp import RF_L2_EVPN from ryu.lib.packet.bgp import EvpnMacIPAdvertisementNLRI @@ -211,7 +212,7 @@ class VrfTable(Table): return changed_dests def insert_vrf_path(self, nlri, next_hop=None, - gen_lbl=False, is_withdraw=False): + gen_lbl=False, is_withdraw=False, **kwargs): assert nlri pattrs = None label_list = [] @@ -243,6 +244,12 @@ class VrfTable(Table): local_administrator=int(local_admin), subtype=subtype)) + # Set Tunnel Encapsulation Attribute + tunnel_type = kwargs.get('tunnel_type', None) + if tunnel_type: + communities.append( + BGPEncapsulationExtendedCommunity.from_str(tunnel_type)) + pattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = \ BGPPathAttributeExtendedCommunities(communities=communities) if vrf_conf.multi_exit_disc: @@ -266,7 +273,7 @@ class VrfTable(Table): label_list.append(table_manager.get_next_vpnv4_label()) # Set MPLS labels with the generated labels - if isinstance(nlri, EvpnMacIPAdvertisementNLRI): + if gen_lbl and isinstance(nlri, EvpnMacIPAdvertisementNLRI): nlri.mpls_labels = label_list[:2] puid = self.VRF_PATH_CLASS.create_puid( -- cgit v1.2.3