Hello,

I've tried connecting Ryu to Cisco NX-OS 7.x switches (Nexus 3172, Nexus 9372PX, Nexus C92160YC-X) and ran into two issues which I solved with the attached patch.


This patch adds interoperability with other MP BGP EVPN VXLAN implementations, e.g. Cisco NX-OS.


Issue #1
Interoperability with at least Cisco NX-OS requires an empty ip_addr in the
EVPN_MAC_IP_ADV_ROUTE prefix announcement.

Example usage:

         speaker.evpn_prefix_add(
             route_type=EVPN_MAC_IP_ADV_ROUTE,
             tunnel_type=TUNNEL_TYPE_VXLAN,
             route_dist=evpn_route_dist,
             ethernet_tag_id=0,
             mac_addr=evpn_mac,
ip_addr=None, # Cisco: None (make sure ip_addr_len=0 , ip_addr="0.0.0.0" != None)
             next_hop=loopback_IPv4,
             vni=0,
         )



Issue #2
A working MP-BGP EVPN VXLAN fabric needs to announce the local NVE/VTEP IP
address to all other NVE/VTEP peers through an Inclusive Multicast Ethernet
Tag Route (IMET) with the VNI in a BGPPathAttributePmsiTunnel.

Interoperability with at least Cisco NX-OS requires an IMET announcement .
Only NVE/VTEP IP addresses received through these announcements are valid
VTEP's and will thus receive BUM traffic as well. Without this
announcement, the L2VPN is not working.

On NX-OS one can check with:
show l2route evpn imet all [detail] <VNI_VLAN> <VNI> BGP <remote_NVE_VTEP_IP>
                                        e.g. 311    10311  BGP  10.1..126
sh bgp l2vpn evpn received-paths look for type 3, e.g. : [3]:[0]:[32]:[10.1.1.126]/88)

See also:
https://tools.ietf.org/html/rfc7432#section-7.3
https://tools.ietf.org/html/rfc7432#section-11


Example usage:

         speaker.evpn_prefix_add(
             route_type=EVPN_MULTICAST_ETAG_ROUTE,
             tunnel_type=TUNNEL_TYPE_VXLAN,
             pmsi_tunnel_type=PMSI_TYPE_INGRESS_REP,
             vni=vni, # send through BGPPathAttributePmsiTunnel
             #
             route_dist=evpn_route_dist,
             ethernet_tag_id=0,
             ip_addr=loopback_IPv4,
             next_hop=loopback_IPv4,
         )



Regards,
Albert Siersema

diff -uprN ryu-git_20170126_1030CET/ryu/lib/packet/bgp.py ryu-AJS/ryu/lib/packet/bgp.py
--- ryu-git_20170126_1030CET/ryu/lib/packet/bgp.py	2017-01-26 10:31:23.308450201 +0100
+++ ryu-AJS/ryu/lib/packet/bgp.py	2017-01-26 10:41:54.835909500 +0100
@@ -1405,7 +1405,7 @@ class EvpnNLRI(StringifyMixin, TypeDisp)
 
     @staticmethod
     def _ip_addr_to_bin(ip_addr):
-        return ip.text_to_bin(ip_addr)
+        return bytes() if not ip_addr else ip.text_to_bin(ip_addr) # [AJS] allow empty ip_addr (len 0), e.g. L2VPN MAC advertisement Cisco NX-OS
 
     @staticmethod
     def _mpls_label_from_bin(buf):
@@ -1748,13 +1748,14 @@ class EvpnInclusiveMulticastEthernetTagN
     }
 
     def __init__(self, route_dist, ethernet_tag_id, ip_addr,
-                 ip_addr_len=None, type_=None, length=None):
+                 ip_addr_len=None, type_=None, length=None, vni=None): # [AJS] vni
         super(EvpnInclusiveMulticastEthernetTagNLRI,
               self).__init__(type_, length)
         self.route_dist = route_dist
         self.ethernet_tag_id = ethernet_tag_id
         self.ip_addr_len = ip_addr_len
         self.ip_addr = ip_addr
+        self.vni = vni # [AJS] vni
 
     @classmethod
     def parse_value(cls, buf):
diff -uprN ryu-git_20170126_1030CET/ryu/services/protocols/bgp/api/prefix.py ryu-AJS/ryu/services/protocols/bgp/api/prefix.py
--- ryu-git_20170126_1030CET/ryu/services/protocols/bgp/api/prefix.py	2017-01-26 10:31:23.328450310 +0100
+++ ryu-AJS/ryu/services/protocols/bgp/api/prefix.py	2017-01-26 10:43:36.000463643 +0100
@@ -188,7 +188,8 @@ def is_valid_mac_addr(addr):
 
 @validate(name=IP_ADDR)
 def is_valid_ip_addr(addr):
-    if not (validation.is_valid_ipv4(addr)
+    if not (addr is None        # [AJS] allow empty ip_addr (len 0), e.g. L2VPN MAC advertisement Cisco NX-OS
+            or validation.is_valid_ipv4(addr)
             or validation.is_valid_ipv6(addr)):
         raise ConfigValueError(conf_name=IP_ADDR,
                                conf_value=addr)
diff -uprN ryu-git_20170126_1030CET/ryu/services/protocols/bgp/bgpspeaker.py ryu-AJS/ryu/services/protocols/bgp/bgpspeaker.py
--- ryu-git_20170126_1030CET/ryu/services/protocols/bgp/bgpspeaker.py	2017-01-26 10:31:23.328450310 +0100
+++ ryu-AJS/ryu/services/protocols/bgp/bgpspeaker.py	2017-01-26 10:44:02.612609423 +0100
@@ -643,6 +643,8 @@ class BGPSpeaker(object):
                     PMSI_TYPE_NO_TUNNEL_INFO,
                     PMSI_TYPE_INGRESS_REP]:
                 kwargs[PMSI_TUNNEL_TYPE] = pmsi_tunnel_type
+                if vni is not None:	# [AJS]
+                    kwargs[EVPN_VNI] = vni
             elif pmsi_tunnel_type is not None:
                 raise ValueError('Unsupported PMSI tunnel type: %s' %
                                  pmsi_tunnel_type)
diff -uprN ryu-git_20170126_1030CET/ryu/services/protocols/bgp/info_base/vrf.py ryu-AJS/ryu/services/protocols/bgp/info_base/vrf.py
--- ryu-git_20170126_1030CET/ryu/services/protocols/bgp/info_base/vrf.py	2017-01-26 10:31:23.332450332 +0100
+++ ryu-AJS/ryu/services/protocols/bgp/info_base/vrf.py	2017-01-26 10:43:05.736297867 +0100
@@ -52,6 +52,8 @@ from ryu.services.protocols.bgp.utils.st
 from ryu.services.protocols.bgp.utils.stats import RESOURCE_ID
 from ryu.services.protocols.bgp.utils.stats import RESOURCE_NAME
 
+from ryu.services.protocols.bgp.api.base import EVPN_VNI # [AJS]
+
 LOG = logging.getLogger('bgpspeaker.info_base.vrf')
 
 
@@ -326,10 +328,12 @@ class VrfTable(Table):
                         tunnel_endpoint_ip=self._core_service.router_id)
                 else:  # pmsi_tunnel_type == PMSI_TYPE_NO_TUNNEL_INFO
                     tunnel_id = None
+                vni = kwargs.get(EVPN_VNI, None) # [AJS]
                 pattrs[BGP_ATTR_TYEP_PMSI_TUNNEL_ATTRIBUTE] = \
                     BGPPathAttributePmsiTunnel(pmsi_flags=0,
                                                tunnel_type=pmsi_tunnel_type,
-                                               tunnel_id=tunnel_id)
+                                               tunnel_id=tunnel_id,
+                                               vni=vni) # [AJS] vni
 
         puid = self.VRF_PATH_CLASS.create_puid(
             vrf_conf.route_dist, nlri.prefix)
------------------------------------------------------------------------------
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
Ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to