{% set lo_address = interfaces | selectattr('name', '==', 'lo') | map(attribute='ip_addresses') | first | selectattr('role') | selectattr('role.value', '==', 'loopback') | map(attribute='address') %} {% set iface_bgp = interfaces | iface_real | selectattr('enabled') | rejectattr('mgmt_only') | rejectattr('bridge') | rejectattr('lag') %} {% set iface_server = iface_bgp | selectattr('custom_fields.tenant') %} {% set iface_fabric = iface_bgp | difference(iface_server) | rejectattr('ip_addresses') %} {% set my_tenants = iface_server | map(attribute='custom_fields.tenant.slug') | unique -%} frr defaults datacenter log syslog informational service integrated-vtysh-config # Route installation into kernels fails (rarely) without this option. # It is not documented anywhere and appears to be a Cumulus extension. zebra nexthop proto only router-id {{ lo_address | ipv4 | first | ipaddr('address') }} router bgp {{ asn.asn }} bgp bestpath as-path multipath-relax neighbor fabric peer-group neighbor fabric remote-as external {% for interface in iface_fabric %} neighbor {{ interface.name }} interface peer-group fabric neighbor {{ interface.name }} bfd 3 150 150 {% endfor %} {% for tenant in my_tenants %} neighbor dc-{{ tenant }} peer-group neighbor dc-{{ tenant }} remote-as external {% for interface in iface_server | selectattr('custom_fields.tenant.slug', '==', tenant) %} neighbor {{ interface.name }} interface peer-group dc-{{ tenant }} neighbor {{ interface.name }} bfd {% endfor %} {% endfor %} address-family ipv4 unicast redistribute connected route-map loopbacks neighbor fabric activate {% for tenant in my_tenants %} neighbor dc-{{ tenant }} activate neighbor dc-{{ tenant }} route-map dc-{{ tenant }}->default in neighbor dc-{{ tenant }} route-map default->dc out {% endfor %} exit-address-family address-family ipv6 unicast redistribute connected route-map loopbacks neighbor fabric activate {% for tenant in my_tenants %} neighbor dc-{{ tenant }} activate neighbor dc-{{ tenant }} route-map dc-{{ tenant }}->default in neighbor dc-{{ tenant }} route-map default->dc out {% endfor %} exit-address-family address-family l2vpn evpn neighbor fabric activate {% for iface in ifaces_evpn|default([]) %} neighbor {{ iface }} activate {% endfor %} {% if interfaces | selectattr('mode') %} advertise-all-vni {% endif %} exit-address-family route-map loopbacks permit 10 match interface lo {% if my_tenants %} ip prefix-list default permit 0.0.0.0/0 ipv6 prefix-list default permit ::/0 {% for tenant in my_tenants %} {% for prefix in query('netbox.netbox.nb_lookup', 'prefixes', raw_data=true, api_filter='tenant='~tenant) | selectattr('role') | selectattr('role.slug', '==', 'bgp') | rejectattr('vlan') %} {% if prefix.family.value == 4 %} ip prefix-list dc-{{ tenant }} permit {{ prefix.prefix }} ge 32 {% else %} ipv6 prefix-list dc-{{ tenant }} permit {{ prefix.prefix }} ge 64 {% endif %} {% endfor %} {% endfor %} # We only announce the default route to DC servers. route-map default->dc permit 10 match ip address prefix-list default route-map default->dc permit 11 match ipv6 address prefix-list default {% for tenant in my_tenants %} route-map dc-{{ tenant }}->default permit 10 match ip address prefix-list dc-{{ tenant }} route-map dc-{{ tenant }}->default permit 11 match ipv6 address prefix-list dc-{{ tenant }} {% endfor %} {% endif %}