From 538dd78cca791f46bfeeff46dbc79bc4d7455bc4 Mon Sep 17 00:00:00 2001 From: FAELIX SALT Date: Mon, 27 Apr 2020 03:41:13 +0000 Subject: [PATCH] add peeringdb support --- vyos.conf.j2 | 319 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 225 insertions(+), 94 deletions(-) diff --git a/vyos.conf.j2 b/vyos.conf.j2 index a26f090..335f563 100644 --- a/vyos.conf.j2 +++ b/vyos.conf.j2 @@ -1,5 +1,3 @@ -/* -=-=-=-=-=-=-=-=-=-=-=-=-=- INTERFACES -=-=-=-=-=-=-=-=-=-=-=-=-=- */ - {% macro interface_ip_ospf(iface_name) %} {% if salt['pillar.get']('interfaces:'+iface_name+':ip:ospf') %} ospf { @@ -35,6 +33,135 @@ {% endif %} {% endmacro %} +{% macro bgp_neighbor(neighbor, neighbor_data) %} + neighbor {{ neighbor }} { + remote-as {{ neighbor_data['remote-as'] }} + {% if 'password' in neighbor_data %}password {{ neighbor_data['password'] }}{% endif %} + {% if 'update-source' in neighbor_data %}update-source {{ neighbor_data['update-source'] }}{% endif %} + {% if 'ebgp-multihop' in neighbor_data %}ebgp-multihop {{ neighbor_data['ebgp-multihop'] }}{% endif %} + + {% if 'address-family' in neighbor_data %} + address-family { + {% if 'ipv4-unicast' in neighbor_data['address-family'] %} + ipv4-unicast { + {% if neighbor_data['address-family']['ipv4-unicast'].get('route-reflector-client',False) %}route-reflector-client{% endif %} + {% if neighbor_data['address-family']['ipv4-unicast'].get('route-server-client',False) %}route-server-client{% endif %} + {% if 'prefix-list' in neighbor_data['address-family']['ipv4-unicast'] %} + prefix-list { + {% if 'export' in neighbor_data['address-family']['ipv4-unicast']['prefix-list'] %}export {{ neighbor_data['address-family']['ipv4-unicast']['prefix-list']['export'] }}{% endif %} + {% if 'import' in neighbor_data['address-family']['ipv4-unicast']['prefix-list'] %}import {{ neighbor_data['address-family']['ipv4-unicast']['prefix-list']['import'] }}{% endif %} + } + {% endif %} + {% if 'route-map' in neighbor_data['address-family']['ipv4-unicast'] %} + route-map { + {% if 'export' in neighbor_data['address-family']['ipv4-unicast']['route-map'] %}export {{ neighbor_data['address-family']['ipv4-unicast']['route-map']['export'] }}{% endif %} + {% if 'import' in neighbor_data['address-family']['ipv4-unicast']['route-map'] %}import {{ neighbor_data['address-family']['ipv4-unicast']['route-map']['import'] }}{% endif %} + } + {% endif %} + {% if 'soft-reconfiguration' in neighbor_data['address-family']['ipv4-unicast'] %} + soft-reconfiguration { + {% for softreconf in neighbor_data['address-family']['ipv4-unicast']['soft-reconfiguration'] %} + {{ softreconf }} + {% endfor %} + } + {% endif %} + {% if 'allowas-in' in neighbor_data['address-family']['ipv4-unicast'] %} + allowas-in { + {# neighbor_data['address-family']['ipv4-unicast']['allowas-in'] #} + } + {% endif %} + {% if neighbor_data['address-family']['ipv4-unicast'].get('nexthop-self',False) %} + nexthop-self + {% endif %} + {% if neighbor_data['address-family']['ipv4-unicast'].get('maximum-prefix',None) != None %} + maximum-prefix {{ neighbor_data['address-family']['ipv4-unicast'].get('maximum-prefix',None) }} + {% endif %} + {% if neighbor_data['address-family']['ipv4-unicast'].get('default-originate',False) %} + default-originate { + } + {% endif %} + } + {% endif %} + {% if 'ipv6-unicast' in neighbor_data['address-family'] %} + ipv6-unicast { + {% if neighbor_data['address-family']['ipv6-unicast'].get('route-reflector-client',False) %}route-reflector-client{% endif %} + {% if neighbor_data['address-family']['ipv6-unicast'].get('route-server-client',False) %}route-server-client{% endif %} + {% if 'prefix-list' in neighbor_data['address-family']['ipv6-unicast'] %} + prefix-list { + {% if 'export' in neighbor_data['address-family']['ipv6-unicast']['prefix-list'] %}export {{ neighbor_data['address-family']['ipv6-unicast']['prefix-list']['export'] }}{% endif %} + {% if 'import' in neighbor_data['address-family']['ipv6-unicast']['prefix-list'] %}import {{ neighbor_data['address-family']['ipv6-unicast']['prefix-list']['import'] }}{% endif %} + } + {% endif %} + {% if 'route-map' in neighbor_data['address-family']['ipv6-unicast'] %} + route-map { + {% if 'export' in neighbor_data['address-family']['ipv6-unicast']['route-map'] %}export {{ neighbor_data['address-family']['ipv6-unicast']['route-map']['export'] }}{% endif %} + {% if 'import' in neighbor_data['address-family']['ipv6-unicast']['route-map'] %}import {{ neighbor_data['address-family']['ipv6-unicast']['route-map']['import'] }}{% endif %} + } + {% endif %} + {% if 'soft-reconfiguration' in neighbor_data['address-family']['ipv6-unicast'] %} + soft-reconfiguration { + {% for softreconf in neighbor_data['address-family']['ipv6-unicast']['soft-reconfiguration'] %} + {{ softreconf }} + {% endfor %} + } + {% endif %} + {% if 'allowas-in' in neighbor_data['address-family']['ipv6-unicast'] %} + allowas-in { + {# neighbor_data['address-family']['ipv6-unicast']['allowas-in'] #} + } + {% endif %} + {% if neighbor_data['address-family']['ipv6-unicast'].get('nexthop-self',False) %} + nexthop-self + {% endif %} + {% if neighbor_data['address-family']['ipv6-unicast'].get('maximum-prefix',None) != None %} + maximum-prefix {{ neighbor_data['address-family']['ipv6-unicast'].get('maximum-prefix',None) }} + {% endif %} + {% if neighbor_data['address-family']['ipv6-unicast'].get('default-originate',False) %} + default-originate { + } + {% endif %} + } + {% endif %} + } + {% endif %} + + } +{% endmacro %} + +{%- macro deep_merge(a, b): %} + {%- for k,v in b.items(): %} + {%- if v is not defined: %} + {%- do a.pop(k) %} + {%- else: %} + {%- if v is mapping: %} + {%- if a[k] is not mapping: %} + {%- do a.update({ k: { } }) %} + {%- endif %} + {%- do deep_merge(a[k], v) %} + {%- else: %} + {%- do a.update({ k: v }) %} + {%- endif %} + {% endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro normalise_peeringdb_as_set(prefix_list, pdb) %} + {%- if '::' in pdb %} + {%- set bits = pdb.split("::") %} + {%- do prefix_list.update({'sources': bits[0], 'name': 'peeringdb-' + bits[1].upper(), 'as-set': bits[1].upper()}) %} + {%- elif '@' in pdb %} + {%- set bits = pdb.split("@") %} + {%- do prefix_list.update({'sources': bits[1], 'name': 'peeringdb-' + bits[0].upper(), 'as-set': bits[0].upper()}) %} + {%- else %} + {%- do prefix_list.update({'sources': 'RIPE,RADB,ARIN,APNIC,AFRINIC,LACNIC', 'name': 'peeringdb-' + pdb, 'as-set': pdb}) %} + {% endif %} +{% endmacro %} + +{% set peeringdb_prefixlist_4 = {} %} +{% set peeringdb_prefixlist_6 = {} %} + +/* -=-=-=-=-=-=-=-=-=-=-=-=-=- INTERFACES -=-=-=-=-=-=-=-=-=-=-=-=-=- */ + interfaces { {% for iface_name, iface_data in pillar['netbox']['interfaces'].items() %}{% if iface_data['mgmt_only'] %} {% elif iface_name == 'lo' %} @@ -270,100 +397,58 @@ protocols { {% endif %} {% for neighbor, neighbor_data in as_data.get('neighbor',{}).items() %} - neighbor {{ neighbor }} { - remote-as {{ neighbor_data['remote-as'] }} - {% if 'password' in neighbor_data %}password {{ neighbor_data['password'] }}{% endif %} - {% if 'update-source' in neighbor_data %}update-source {{ neighbor_data['update-source'] }}{% endif %} - {% if 'ebgp-multihop' in neighbor_data %}ebgp-multihop {{ neighbor_data['ebgp-multihop'] }}{% endif %} - - {% if 'address-family' in neighbor_data %} - address-family { - {% if 'ipv4-unicast' in neighbor_data['address-family'] %} - ipv4-unicast { - {% if neighbor_data['address-family']['ipv4-unicast'].get('route-reflector-client',False) %}route-reflector-client{% endif %} - {% if neighbor_data['address-family']['ipv4-unicast'].get('route-server-client',False) %}route-server-client{% endif %} - {% if 'prefix-list' in neighbor_data['address-family']['ipv4-unicast'] %} - prefix-list { - {% if 'export' in neighbor_data['address-family']['ipv4-unicast']['prefix-list'] %}export {{ neighbor_data['address-family']['ipv4-unicast']['prefix-list']['export'] }}{% endif %} - {% if 'import' in neighbor_data['address-family']['ipv4-unicast']['prefix-list'] %}import {{ neighbor_data['address-family']['ipv4-unicast']['prefix-list']['import'] }}{% endif %} - } - {% endif %} - {% if 'route-map' in neighbor_data['address-family']['ipv4-unicast'] %} - route-map { - {% if 'export' in neighbor_data['address-family']['ipv4-unicast']['route-map'] %}export {{ neighbor_data['address-family']['ipv4-unicast']['route-map']['export'] }}{% endif %} - {% if 'import' in neighbor_data['address-family']['ipv4-unicast']['route-map'] %}import {{ neighbor_data['address-family']['ipv4-unicast']['route-map']['import'] }}{% endif %} - } - {% endif %} - {% if 'soft-reconfiguration' in neighbor_data['address-family']['ipv4-unicast'] %} - soft-reconfiguration { - {% for softreconf in neighbor_data['address-family']['ipv4-unicast']['soft-reconfiguration'] %} - {{ softreconf }} - {% endfor %} - } - {% endif %} - {% if 'allowas-in' in neighbor_data['address-family']['ipv4-unicast'] %} - allowas-in { - {# neighbor_data['address-family']['ipv4-unicast']['allowas-in'] #} - } - {% endif %} - {% if neighbor_data['address-family']['ipv4-unicast'].get('nexthop-self',False) %} - nexthop-self - {% endif %} - {% if neighbor_data['address-family']['ipv4-unicast'].get('maximum-prefix',None) != None %} - maximum-prefix {{ neighbor_data['address-family']['ipv4-unicast'].get('maximum-prefix',None) }} - {% endif %} - {% if neighbor_data['address-family']['ipv4-unicast'].get('default-originate',False) %} - default-originate { - } - {% endif %} - } - {% endif %} - {% if 'ipv6-unicast' in neighbor_data['address-family'] %} - ipv6-unicast { - {% if neighbor_data['address-family']['ipv6-unicast'].get('route-reflector-client',False) %}route-reflector-client{% endif %} - {% if neighbor_data['address-family']['ipv6-unicast'].get('route-server-client',False) %}route-server-client{% endif %} - {% if 'prefix-list' in neighbor_data['address-family']['ipv6-unicast'] %} - prefix-list { - {% if 'export' in neighbor_data['address-family']['ipv6-unicast']['prefix-list'] %}export {{ neighbor_data['address-family']['ipv6-unicast']['prefix-list']['export'] }}{% endif %} - {% if 'import' in neighbor_data['address-family']['ipv6-unicast']['prefix-list'] %}import {{ neighbor_data['address-family']['ipv6-unicast']['prefix-list']['import'] }}{% endif %} - } - {% endif %} - {% if 'route-map' in neighbor_data['address-family']['ipv6-unicast'] %} - route-map { - {% if 'export' in neighbor_data['address-family']['ipv6-unicast']['route-map'] %}export {{ neighbor_data['address-family']['ipv6-unicast']['route-map']['export'] }}{% endif %} - {% if 'import' in neighbor_data['address-family']['ipv6-unicast']['route-map'] %}import {{ neighbor_data['address-family']['ipv6-unicast']['route-map']['import'] }}{% endif %} - } - {% endif %} - {% if 'soft-reconfiguration' in neighbor_data['address-family']['ipv6-unicast'] %} - soft-reconfiguration { - {% for softreconf in neighbor_data['address-family']['ipv6-unicast']['soft-reconfiguration'] %} - {{ softreconf }} - {% endfor %} - } - {% endif %} - {% if 'allowas-in' in neighbor_data['address-family']['ipv6-unicast'] %} - allowas-in { - {# neighbor_data['address-family']['ipv6-unicast']['allowas-in'] #} - } - {% endif %} - {% if neighbor_data['address-family']['ipv6-unicast'].get('nexthop-self',False) %} - nexthop-self - {% endif %} - {% if neighbor_data['address-family']['ipv6-unicast'].get('maximum-prefix',None) != None %} - maximum-prefix {{ neighbor_data['address-family']['ipv6-unicast'].get('maximum-prefix',None) }} - {% endif %} - {% if neighbor_data['address-family']['ipv6-unicast'].get('default-originate',False) %} - default-originate { - } - {% endif %} - } - {% endif %} - } - {% endif %} - - } + {{ bgp_neighbor(neighbor, neighbor_data) }} {% endfor %} + {% set peeringdb = as_data.get('peeringdb',{}) %} + {% if peeringdb %} + {% for ix_name, ix_data in peeringdb.get('ix',{}).items() %} + /* {{ ix_name }} */ + {% for asn, asn_data in ix_data.get('asn',{}).items() %} + {% set net_data = salt['peeringdb.get_net'](asn=asn)['out'][0] %} + {% set pdb_data = salt['peeringdb.get_netixlan'](asn=asn,ixlan=ix_data['peeringdb_ixlan'])['out'] %} + {% for peer in pdb_data %} + {% set neighbor_data = {'description': net_data.get('name','AS%d'%asn) + ' at ' + ix_name, 'address-family':{'ipv4-unicast':{},'ipv6-unicast':{}}} %} + {%- do deep_merge(neighbor_data, peeringdb.get('default',{})) %} + {%- do deep_merge(neighbor_data, ix_data.get('default',{})) %} + {%- do deep_merge(neighbor_data, {'remote-as':asn}) %} + {% set as_set = {} %} + {%- do normalise_peeringdb_as_set(as_set, net_data['irr_as_set']) %} + {% if peer.get('operational',False) %} + {% if peer.get('ipaddr4',None) %} + {% set neighbor4_data = {} %} + {%- do deep_merge(neighbor4_data, neighbor_data) %} + {%- do deep_merge(neighbor4_data, {'address-family': {'ipv4-unicast': {'prefix-list':{'import':as_set['name']},'maximum-prefix': net_data['info_prefixes4']}}}) %} + {%- do deep_merge(neighbor4_data, asn_data.get('default',{})) %} + {% if peer['ipaddr4'] in asn_data.get('neighbor',{}) %} + {%- do deep_merge(neighbor4_data, asn_data['neighbor'][peer['ipaddr4']]) %} + {% endif %} + {%- do neighbor4_data['address-family'].pop('ipv6-unicast') %} + {{ bgp_neighbor(peer['ipaddr4'], neighbor4_data) }} + {% if neighbor4_data['address-family']['ipv4-unicast']['prefix-list']['import'] == as_set['name'] %} + {%- do peeringdb_prefixlist_4.update({as_set['name']: as_set}) %} + {% endif %} + {% endif %} + {% if peer.get('ipaddr6',None) %} + {% set neighbor6_data = {} %} + {%- do deep_merge(neighbor6_data, neighbor_data) %} + {%- do deep_merge(neighbor6_data, {'address-family': {'ipv6-unicast': {'prefix-list':{'import':as_set['name']},'maximum-prefix': net_data['info_prefixes4']}}}) %} + {%- do deep_merge(neighbor6_data, asn_data.get('default',{})) %} + {% if peer['ipaddr6'] in asn_data.get('neighbor',{}) %} + {%- do deep_merge(neighbor6_data, asn_data['neighbor'][peer['ipaddr6']]) %} + {% endif %} + {%- do neighbor6_data['address-family'].pop('ipv4-unicast') %} + {{ bgp_neighbor(peer['ipaddr6'], neighbor6_data) }} + {% if neighbor6_data['address-family']['ipv6-unicast']['prefix-list']['import'] == as_set['name'] %} + {%- do peeringdb_prefixlist_6.update({as_set['name']: as_set}) %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endfor %} + {% endfor %} + {% endif %} + } {% endfor %} } @@ -1259,6 +1344,29 @@ policy { } {% endfor %} + {% for prefix_list_name, prefix_data in peeringdb_prefixlist_4.items() %} + prefix-list {{ prefix_list_name }} { + {% if prefix_data['as-set'] %} + {% set jsonblob = salt['cmd.run']('/tmp/bgpq3 -A -4 -S ' + prefix_data["sources"] + ' -j ' + prefix_data["as-set"], env={'BIND_ADDR':pillar['loopback']['IPv4'], 'BIND_ADDR6':pillar['loopback']['IPv6'], 'LD_PRELOAD':'/tmp/bind.so'})|load_json %} + {#% set jsonblob = salt['cmd.run']('/tmp/bgpq3 -A -4 -j ' + prefix_data["as-set"], env={'BIND_ADDR':pillar['loopback']['IPv4'], 'BIND_ADDR6':pillar['loopback']['IPv6'], 'LD_PRELOAD':'/tmp/bind.so'})|load_json %#} + /* {{ '/tmp/bgpq3 -A -4 -j ' + prefix_data["as-set"] }} */ + {% for prefix in jsonblob.NN %} + rule {{ loop.index }} { + action permit + prefix {{ prefix['prefix'] }} + {% if prefix.get('less-equal',None) != None %}le {{ prefix['less-equal'] }}{% endif %} + {% if prefix.get('greater-equal',None) != None %}ge {{ prefix['greater-equal'] }}{% endif %} + } + {% endfor %} + {% endif %} + rule 65535 { + prefix 0.0.0.0/0 + le 32 + action deny + } + } + {% endfor %} + {% for prefix_list_name, prefix_data in salt['pillar.get']("policy:prefix-list",{}).items() %} prefix-list6 {{ prefix_list_name }} { {% if 'bgpq3' in prefix_data %} @@ -1294,6 +1402,29 @@ policy { } {% endfor %} + {% for prefix_list_name, prefix_data in peeringdb_prefixlist_6.items() %} + prefix-list6 {{ prefix_list_name }} { + {% if prefix_data['as-set'] %} + {% set jsonblob = salt['cmd.run']('/tmp/bgpq3 -A -6 -S ' + prefix_data["sources"] + ' -j ' + prefix_data["as-set"], env={'BIND_ADDR':pillar['loopback']['IPv4'], 'BIND_ADDR6':pillar['loopback']['IPv6'], 'LD_PRELOAD':'/tmp/bind.so'})|load_json %} + {#% set jsonblob = salt['cmd.run']('/tmp/bgpq3 -A -6 -j ' + prefix_data["as-set"], env={'BIND_ADDR':pillar['loopback']['IPv4'], 'BIND_ADDR6':pillar['loopback']['IPv6'], 'LD_PRELOAD':'/tmp/bind.so'})|load_json %#} + /* {{ '/tmp/bgpq3 -A -4 -j ' + prefix_data["as-set"] }} */ + {% for prefix in jsonblob.NN %} + rule {{ loop.index }} { + action permit + prefix {{ prefix['prefix'] }} + {% if prefix.get('less-equal',None) != None %}le {{ prefix['less-equal'] }}{% endif %} + {% if prefix.get('greater-equal',None) != None %}ge {{ prefix['greater-equal'] }}{% endif %} + } + {% endfor %} + {% endif %} + rule 65535 { + prefix ::/0 + le 128 + action deny + } + } + {% endfor %} + } /* -=-=-=-=-=-=-=-=-=-=-=-=-=- SERVICE -=-=-=-=-=-=-=-=-=-=-=-=-=- */