################################################################################ # Internet table # ################################################################################ {%- set ifaces = salt['pillar.get']('nodes:' ~ grains['id'] ~ ':ifaces', {}) %} {%- set have_vrf_external = [] %} {%- for iface, iface_config in ifaces.items () %} {%- if iface_config.get ('vrf', '') == 'vrf_external' %} {%- do have_vrf_external.append (True) %} {%- break %} {%- endif %} {%- endfor %} {%- if True not in have_vrf_external %} # # No vrf_external configured on this node. Nothing to do. # {%- else %} table t_external; filter external_IPs_to_learn { # For now reject; } protocol kernel k_external { scan time 20; learn; import filter external_IPs_to_learn; export all; table t_external; kernel table 1023; } # Add unreachable routes for RFC1918, RFC 6598, APIPA so we don't route # anything private into the internet + null route some bogons. protocol static bogon_unreach_ext { table t_external; {%- if proto == 'v4' %} route 0.0.0.0/8 unreachable; # Host-Subnet route 10.0.0.0/8 unreachable; # RFC 1918 route 100.64.0.0/10 unreachable; # RFC 6598 route 169.254.0.0/16 unreachable; # APIPA route 172.16.0.0/12 unreachable; # RFC 1918 route 192.0.0.0/24 unreachable; # IANA RESERVED route 192.0.2.0/24 unreachable; # TEST-NET-1 route 192.168.0.0/16 unreachable; # RFC 1918 route 198.18.0.0/15 unreachable; # BENCHMARK route 198.51.100.0/24 unreachable; # TEST-NET-2 route 203.0.113.0/24 unreachable; # TEST-NET-3 route 224.0.0.0/3 unreachable; # MCast + Class E {%- else %} route ::/96 unreachable; # RFC 4291 route 2001:db8::/32 unreachable; # Documentation route fec0::/10 unreachable; # Site Local route fc00::/7 unreachable; # ULA {%- endif %} } {%- if 'veth_int2ext' in ifaces and 'veth_ext2int' in ifaces %} {%- set veth_ips = {} %} {%- for iface in ifaces if iface in [ 'veth_int2ext', 'veth_ext2int' ] %} {%- do veth_ips.update ({ iface : { 'v4' : None, 'v6' : None }}) %} {%- for prefix in ifaces.get (iface, {}).get ('prefixes', []) %} {%- if "." in prefix %} {%- do veth_ips[iface].update ({ 'v4' : prefix.split ('/')[0] }) %} {%- else %} {%- do veth_ips[iface].update ({ 'v6' : prefix.split ('/')[0] }) %} {%- endif %} {%- endfor %} {%- endfor %} # # VRF glue # {%- set internal_ip = veth_ips['veth_int2ext'][proto] %} {%- set external_ip = veth_ips['veth_ext2int'][proto] %} # Learn route on external side of VEth tunnel between VRFs for recursive BGP # nexthop lookup. protocol direct d_ext2int { table t_external; interface "veth_ext2int"; } template bgp ibgp_vrf_glue { local as AS_OWN; enable route refresh yes; graceful restart yes; } protocol bgp int2ext from ibgp_vrf_glue { import filter external_IPs_to_learn; export filter own_prefixes; source address {{ internal_ip }}; neighbor {{ external_ip }} as AS_OWN; rr client; next hop self; } protocol bgp ext2int from ibgp_vrf_glue { table t_external; # External router! router id {{ veth_ips['veth_ext2int']['v4'] }}; import filter own_prefixes; export filter { if proto = "k_external" then { bgp_community.add (EXTERNAL_ROUTE); accept; } reject; }; source address {{ external_ip }}; neighbor {{ internal_ip }} as AS_OWN; next hop self; } {%- endif %} {#- veth int/ext tunnel #} {%- endif %} {#- vrf_external exists #}