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