{#
   Global BGP neighbor definition
#}
{% macro neighbor_global(n,af) %}
   - peer-address: {{ n[af] }}
     description: {{ n.name }}
     peer-group: {{ 'ebgp' if n.type=='ebgp' else ('ibgp-'+af) }}
{%   if n.type != 'ibgp' %}
     peer-as: {{ n.as }}
{%   endif %}
{%   if n.local_as is defined %}
     local-as:
     - as-number: {{ n.local_as }}
{%   endif %}
{%- endmacro %}

updates:
- path: network-instance[name=default]/protocols/bgp
  val:
   autonomous-system: {{ bgp.as }}
   router-id: {{ bgp.router_id }}
   ipv4-unicast:
    admin-state: disable
   ebgp-default-policy:
    export-reject-all: False
    import-reject-all: False
{#
    Configure BGP Groups
#}
   group:
{% for g in ['ibgp-ipv4','ibgp-ipv6','ebgp'] %}
{% set ibgp_rr = (g!='ebgp' and bgp.rr|default(0)) %}
   - group-name: {{g}}
     admin-state: enable
     import-policy: accept_all
     export-policy: accept_all
     peer-as: {{ bgp.as }}
     next-hop-self: {{ bgp.next_hop_self|default(0) and not ibgp_rr }}
     timers:
      connect-retry: 1
      minimum-advertisement-interval: 1

{%   if bgp.community[ g[:4] ]|default([]) %}
{%   set list = bgp.community[ g[:4] ] %}
     send-community:
      standard: {{ 'standard' in list or 'both' in list }}
      large: {{ 'large' in list }}
{%   endif %}

{%   if g!='ebgp' and g[5:] in loopback %}
     transport:
      local-address: {{ loopback[ g[5:] ]|default('')|ipaddr('address') }}
{% endif %}

{#
    Configure iBGP Route Reflection
#}
{%   if ibgp_rr %}
     route-reflector:
      cluster-id: {{ bgp.rr_cluster_id|default(False) or bgp.router_id }}
      client: True
{%   endif %}
{% endfor %}

{#
    Configure IPv4 and IPv6 BGP neighbors
#}
   neighbor:
{% for n in bgp.neighbors %}
{%  for af in ['ipv4','ipv6'] if n[af] is defined %}
{{ neighbor_global(n,af) }}
{%  endfor %}
{% endfor %}

{# Configure BGP address families #}
{% for af in ['ipv4','ipv6'] if bgp[af] is defined %}
   {{ af }}-unicast:
    admin-state: enable
    multipath:
     max-paths-level-1: 64
     max-paths-level-2: 64 # indirect nexthops
{%   if loopback[af] is defined and bgp.advertise_loopback %}
{# {{     bgp_network(af,loopback[af]) }} #}
{%   endif %}

{% for l in interfaces|default([]) if l.bgp.advertise|default("") and l[af] is defined and not 'vrf' in l %}
{# {{     bgp_network(af,l[af]) }} #}
{%   endfor %}
{%   for pfx in bgp.originate|default([]) if af == 'ipv4' %}
{# {{     bgp_network(af,pfx) }} #}
{%   endfor %}

{% endfor %}

{#
  Define default import/export policies for iBGP and eBGP: accept all
#}
- path: routing-policy/policy[name=accept_all]
  val:
   name: accept_all
   default-action:
    accept: {}

{#
  Add extra IPv4 prefixes using static blackhole routes, add to export
#}
- path: network-instance[name=default]/next-hop-groups/group[name=blackhole]
  val:
   blackhole:
     generate-icmp: True

{% for pfx in bgp.originate|default([]) %}
- path: network-instance[name=default]/static-routes/route[prefix={{pfx}}]
  val:
   next-hop-group: blackhole
- path: routing-policy/prefix-set[name=external_routes]
  val:
   prefix:
   - ip-prefix: {{ pfx }}
     mask-length-range: exact
{% endfor %}

{% if 'sr' in module|default([]) %}
{# Configure BGP shortcuts via SR-ISIS #}
- path: network-instance[name=default]/protocols/bgp/ipv4-unicast/next-hop-resolution
  val:
   ipv4-next-hops:
    tunnel-resolution:
     mode: prefer
     _annotate_mode: "tunnel-table lookup over FIB"
     allowed-tunnel-types: [ sr-isis ]
{% endif %}
