{% set env_exec = {} %} {% if pillar.get('loopback',{}).get('IPv4',None) %} {% do env_exec.update({'BIND_ADDR':pillar['loopback']['IPv4']}) %} {% endif %} {% if pillar.get('loopback',{}).get('IPv6',None) %} {% do env_exec.update({'BIND_ADDR6':pillar['loopback']['IPv6']}) %} {% endif %} {% if env_exec %} {% do env_exec.update({'LD_PRELOAD':'/tmp/bind.so'}) %} {% endif %} {% macro interface_ip_ospf(iface_name) %} {% if salt['pillar.get']('interfaces:'+iface_name+':ip:ospf') %} ospf { {% if salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:cost',None) != None %}cost {{ salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:cost') }}{% endif %} {% if salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:passive',False) %} {% else %} network {{ salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:network') }} dead-interval {{ salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:dead-interval',40) }} hello-interval {{ salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:hello-interval',10) }} priority {{ salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:priority',1) }} retransmit-interval {{ salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:retransmit-interval',5) }} transmit-delay {{ salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:transmit-delay',1) }} {% endif %} } {% endif %} {% endmacro %} {% macro interface_ipv6_ospfv3(iface_name) %} {% if salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3') %} ospfv3 { {% if salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:cost',None) != None %}cost {{ salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:cost') }}{% endif %} instance-id {{ salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:instance-id',0) }} {% if salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:passive',False) %} passive {% else %} dead-interval {{ salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:dead-interval',40) }} hello-interval {{ salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:hello-interval',10) }} priority {{ salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:priority',1) }} retransmit-interval {{ salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:retransmit-interval',5) }} transmit-delay {{ salt['pillar.get']('interfaces:'+iface_name+':ipv6:ospfv3:transmit-delay',1) }} {% endif %} } {% 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' %} loopback lo { description "{{ iface_data['description'].replace('"','\\"') or "-" }}{% if iface_data['connected_endpoint'] and iface_data['connected_endpoint']['device'] %} ({% if iface_data['connected_endpoint']['device'] %}{{ iface_data['connected_endpoint']['name'] }} @ {{ iface_data['connected_endpoint']['device']['display_name'] }}{% endif %}){% endif %}" {% for address in iface_data['addresses'] %} address {{ address['address'] }} {% endfor %} {% if salt['pillar.get']('interfaces:'+iface_name+':ip') %} ip { {{ interface_ip_ospf(iface_name) }} } {% endif %} {% if salt['pillar.get']('interfaces:'+iface_name+':ipv6') %} ipv6 { {{ interface_ipv6_ospfv3(iface_name) }} } {% endif %} } {% elif iface_data.get('type',{}).get('label','') != 'Virtual' %} ethernet {{ iface_name }} { description "{{ iface_data['description'].replace('"','\\"') or "-" }}{% if iface_data['connected_endpoint'] and iface_data['connected_endpoint']['device'] %} ({% if iface_data['connected_endpoint']['device'] %}{{ iface_data['connected_endpoint']['name'] }} @ {{ iface_data['connected_endpoint']['device']['display_name'] }}{% endif %}){% endif %}" {% if 'vrf' in salt['pillar.get']('interfaces:'+iface_name,{}) %}vrf {{ salt['pillar.get']('interfaces:'+iface_name+':vrf') }}{% endif %} {% for address in iface_data['addresses'] %} address {{ address['address'] }} {% endfor %} {% if iface_data['mac_address'] %}hw-id {{ iface_data['mac_address'].lower() }}{% endif %} duplex auto policy { } smp-affinity auto speed auto {% if not iface_data['enabled'] %}disable{% endif %} {% if iface_data['lag'] %}bond-group {{ iface_data['lag']['name'] }}{% endif %} {% if iface_data.get('mtu',None) %}mtu {{ iface_data.get('mtu',1500) }}{% endif %} {% for tagged_vlan in iface_data['tagged_vlans'] %} {% set subiface_data = salt['pillar.get']('netbox:interfaces:%s.%d'%(iface_name,tagged_vlan['vid']),{'description':'','addresses':[],'enabled':False}) %} vif {{ tagged_vlan['vid'] }} { description "{{ tagged_vlan['name'].replace('"','\\"') or "-" }} => {{ subiface_data['description'].replace('"','\\"') or "-" }}" {% if 'vrf' in salt['pillar.get']('interfaces:'+iface_name+"."+("%d"%tagged_vlan['vid']),{}) %}vrf {{ salt['pillar.get']('interfaces:'+iface_name+"."+("%d"%tagged_vlan['vid'])+':vrf') }}{% endif %} {% for address in subiface_data['addresses'] %} address {{ address['address'] }} {% endfor %} {% if not subiface_data['enabled'] %}disable{% endif %} {% if subiface_data.get('mtu',None) or iface_data.get('mtu',None) %}mtu {{ subiface_data.get('mtu',iface_data.get('mtu',1500)) }}{% endif %} {% if salt['pillar.get']('interfaces:'+iface_name+"."+("%d"%tagged_vlan['vid'])+':ip') %} ip { {{ interface_ip_ospf(iface_name+"."+("%d"%tagged_vlan['vid'])) }} } {% endif %} {% if salt['pillar.get']('interfaces:'+iface_name+"."+("%d"%tagged_vlan['vid'])+':ipv6') %} ipv6 { dup-addr-detect-transmits 1 {{ interface_ipv6_ospfv3(iface_name+"."+("%d"%tagged_vlan['vid'])) }} } {% endif %} } {% endfor %} {% for subiface_name, subiface_data in pillar['netbox']['interfaces'].items() %}{% if subiface_data.get('form_factor',{}).get('label','') == 'Virtual' and subiface_name.startswith( iface_name + "." ) %} {% endif %}{% endfor %} {% if salt['pillar.get']('interfaces:'+iface_name+':ip') %} ip { {{ interface_ip_ospf(iface_name) }} } {% endif %} {% if salt['pillar.get']('interfaces:'+iface_name+':ipv6') %} ipv6 { dup-addr-detect-transmits 1 {{ interface_ipv6_ospfv3(iface_name) }} } {% endif %} } {% endif %}{% endfor %} } /* -=-=-=-=-=-=-=-=-=-=-=-=-=- VRFS -=-=-=-=-=-=-=-=-=-=-=-=-=- */ vrf { {% for vrf_name, vrf_data in salt['pillar.get']('vrf',{}).items() %} name {{ vrf_name }} { {% if 'table' in vrf_data %}table {{ vrf_data['table'] }}{% endif %} } {% endfor %} } /* -=-=-=-=-=-=-=-=-=-=-=-=-=- PROTOCOLS -=-=-=-=-=-=-=-=-=-=-=-=-=- */ protocols { /* -=-=-=-=-=-=-=-=-=-=-=-=-=- RPKI -=-=-=-=-=-=-=-=-=-=-=-=-=- */ rpki { {% for cache_name,cache_data in salt['pillar.get']('protocols:rpki:cache',{}).items() %} cache {{ cache_name }} { address {{ cache_data[ 'address' ] }} port {{ cache_data.get('port',3233) }} } {% endfor %} } /* -=-=-=-=-=-=-=-=-=-=-=-=-=- OSPF -=-=-=-=-=-=-=-=-=-=-=-=-=- */ ospf { parameters { router-id {{ salt['pillar.get']('protocols:ospf:parameters:router-id') }} abr-type {{ salt['pillar.get']('protocols:ospf:parameters:abr-type','cisco') }} } {% if 'default-information' in salt['pillar.get']('protocols:ospf') %} default-information { {% if 'originate' in salt['pillar.get']('protocols:ospf:default-information') %} originate { {% if salt['pillar.get']('protocols:ospf:default-information:originate:metric',None) %}metric {{ salt['pillar.get']('protocols:ospf:default-information:originate:metric') }}{% endif %} {% if salt['pillar.get']('protocols:ospf:default-information:originate:metric-type',None) %}metric-type {{ salt['pillar.get']('protocols:ospf:default-information:originate:metric-type') }}{% endif %} } {% endif %} } {% endif %} {% for iface_name, iface_data in pillar['netbox']['interfaces'].items() %}{% if salt['pillar.get']('interfaces:'+iface_name+':ip:ospf:passive') %} passive-interface {{ iface_name }} {% endif %}{% endfor %} {% for area_name, area_data in pillar['protocols']['ospf']['area'].items() %} area {{ area_name }} { {% for network, network_data in area_data['networks'].items() %} network {{ network }} {% endfor %} } {% endfor %} } ospfv3 { parameters { router-id {{ salt['pillar.get']('protocols:ospfv3:parameters:router-id') }} } {% for area_name, area_data in pillar['protocols']['ospfv3']['area'].items() %} area {{ area_name }} { {% for range, range_data in area_data.get('range',{}).items() %} range {{ range }} { } {% endfor %} {% for interface, interface_data in area_data.get('interface',{}).items() %} interface {{ interface }} {% endfor %} } {% endfor %} } /* -=-=-=-=-=-=-=-=-=-=-=-=-=- STATIC -=-=-=-=-=-=-=-=-=-=-=-=-=- */ static { {% for iface_name, iface_data in pillar['netbox']['interfaces'].items() %} {% for address in iface_data['addresses'] %} {% if address['address'].endswith("/32") and address.get('description','')|is_ipv4(options='public') %} interface-route {{ address['description'] }} { next-hop-interface {{ iface_name }} } {% endif %} {% if address['address'].endswith("/128") and address.get('description','')|is_ipv6(options='public') %} interface-route6 {{ address['description'] }} { next-hop-interface {{ iface_name }} } {% endif %} {% endfor %} {% endfor %} {% for route_name, route_data in pillar['protocols']['static']['route'].items() %} route {{ route_name }} { {% for nexthop, nexthop_data in route_data.get('next-hop',{}).items() %} next-hop {{ nexthop }} { } {% endfor %} {% if route_data.get('blackhole',None) %} blackhole { distance {{ route_data['blackhole'].get('distance',254) }} } {% endif %} } {% endfor %} {% for route_name, route_data in pillar['protocols']['static']['route6'].items() %} route6 {{ route_name }} { {% for nexthop, nexthop_data in route_data.get('next-hop',{}).items() %} next-hop {{ nexthop }} { } {% endfor %} {% if route_data.get('blackhole',None) %} blackhole { distance {{ route_data['blackhole'].get('distance',254) }} } {% endif %} } {% endfor %} } {% for vrf_name, vrf_data in salt['pillar.get']('protocols:vrf',{}).items() %} {% if 'static' in vrf_data %} vrf {{ vrf_name }} { static { {% for route_name, route_data in vrf_data['static'].get('route',{}).items() %} route {{ route_name }} { {% for nexthop, nexthop_data in route_data.get('next-hop',{}).items() %} next-hop {{ nexthop }} { } {% endfor %} {% if route_data.get('blackhole',None) %} blackhole { distance {{ route_data['blackhole'].get('distance',254) }} } {% endif %} } {% endfor %} {% for route_name, route_data in vrf_data['static'].get('route6',{}).items() %} route6 {{ route_name }} { {% for nexthop, nexthop_data in route_data.get('next-hop',{}).items() %} next-hop {{ nexthop }} { } {% endfor %} {% if route_data.get('blackhole',None) %} blackhole { distance {{ route_data['blackhole'].get('distance',254) }} } {% endif %} } {% endfor %} } } {% endif %} {% endfor %} /* -=-=-=-=-=-=-=-=-=-=-=-=-=- BGP -=-=-=-=-=-=-=-=-=-=-=-=-=- */ {% for bgp_as, as_data in salt['pillar.get']('protocols:bgp',{}).items() %} bgp {{ bgp_as }} { parameters { router-id {{ as_data['parameters']['router-id'] }} default { no-ipv4-unicast } } {% if as_data.get('address-family',None) %} address-family { {% if as_data['address-family'].get('ipv4-unicast',None) %} ipv4-unicast { redistribute { {% for redistribute, redist_data in as_data['address-family']['ipv4-unicast'].get('redistribute',{}).items() %} {{ redistribute }} { {% if 'route-map' in redist_data %}route-map {{ redist_data['route-map'] }}{% endif %} } {% endfor %} } {% for network, network_data in as_data['address-family']['ipv4-unicast'].get('network',{}).items() %} network {{ network }} { {% if 'route-map' in network_data %}route-map {{ network_data['route-map'] }}{% endif %} } {% endfor %} } {% endif %} {% if as_data['address-family'].get('ipv6-unicast',None) %} ipv6-unicast { redistribute { {% for redistribute, redist_data in as_data['address-family']['ipv6-unicast'].get('redistribute',{}).items() %} {{ redistribute }} { {% if 'route-map' in redist_data %}route-map {{ redist_data['route-map'] }}{% endif %} } {% endfor %} } {% for network, network_data in as_data['address-family']['ipv6-unicast'].get('network',{}).items() %} network {{ network }} { {% if 'route-map' in network_data %}route-map {{ network_data['route-map'] }}{% endif %} } {% endfor %} } {% endif %} } {% endif %} {% for neighbor, neighbor_data in as_data.get('neighbor',{}).items() %} {{ 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 %} } /* -=-=-=-=-=-=-=-=-=-=-=-=-=- POLICY -=-=-=-=-=-=-=-=-=-=-=-=-=- */ policy { prefix-list hphr-NO-IPv4 { rule 1 { prefix 0.0.0.0/0 le 32 action deny } } prefix-list hphr-ALL-IPv4 { rule 1 { prefix 0.0.0.0/0 le 32 action permit } } prefix-list hphr-DEFAULT-IPv4 { rule 1 { prefix 0.0.0.0/0 action permit } rule 2 { prefix 0.0.0.0/0 le 32 action deny } } prefix-list hphr-DFZ-IPv4 { rule 100 { prefix 192.168.0.0/16 description "RFC1918" le 32 action deny } rule 101 { prefix 172.16.0.0/12 description "RFC1918" le 32 action deny } rule 102 { prefix 10.0.0.0/8 description "RFC1918" le 32 action deny } rule 103 { prefix 169.254.0.0/16 description "link-local" le 32 action deny } rule 104 { prefix 100.64.0.0/10 description "CGNAT" le 32 action deny } rule 105 { prefix 127.0.0.0/8 description "loopback" le 32 action deny } rule 106 { prefix 192.0.0.0/24 description "IETF protocol assignments" le 32 action deny } rule 107 { prefix 192.0.2.0/24 description "TEST-NET-1" le 32 action deny } rule 108 { prefix 198.18.0.0/15 description "Network interconnect device benchmark testing" le 32 action deny } rule 109 { prefix 198.51.100.0/24 description "TEST-NET-2" le 32 action deny } rule 110 { prefix 203.0.113.0/24 description "TEST-NET-3" le 32 action deny } rule 111 { prefix 224.0.0.0/4 description "multicast" le 32 action deny } rule 112 { prefix 240.0.0.0/4 description "reserved" le 32 action deny } rule 1000 { prefix 0.0.0.0/0 le 24 action permit } rule 65535 { prefix 0.0.0.0/0 le 32 action deny } } prefix-list hphr-DFZ-LONG-IPv4 { rule 100 { prefix 192.168.0.0/16 description "RFC1918" le 32 action deny } rule 101 { prefix 172.16.0.0/12 description "RFC1918" le 32 action deny } rule 102 { prefix 10.0.0.0/8 description "RFC1918" le 32 action deny } rule 103 { prefix 169.254.0.0/16 description "link-local" le 32 action deny } rule 104 { prefix 100.64.0.0/10 description "CGNAT" le 32 action deny } rule 105 { prefix 127.0.0.0/8 description "loopback" le 32 action deny } rule 106 { prefix 192.0.0.0/24 description "IETF protocol assignments" le 32 action deny } rule 107 { prefix 192.0.2.0/24 description "TEST-NET-1" le 32 action deny } rule 108 { prefix 198.18.0.0/15 description "Network interconnect device benchmark testing" le 32 action deny } rule 109 { prefix 198.51.100.0/24 description "TEST-NET-2" le 32 action deny } rule 110 { prefix 203.0.113.0/24 description "TEST-NET-3" le 32 action deny } rule 111 { prefix 224.0.0.0/4 description "multicast" le 32 action deny } rule 112 { prefix 240.0.0.0/4 description "reserved" le 32 action deny } rule 1000 { prefix 0.0.0.0/0 le 32 action permit } } prefix-list hphr-DFZ-DEFAULT-IPv4 { rule 10 { prefix 0.0.0.0/0 action permit } rule 100 { prefix 192.168.0.0/16 description "RFC1918" le 32 action deny } rule 101 { prefix 172.16.0.0/12 description "RFC1918" le 32 action deny } rule 102 { prefix 10.0.0.0/8 description "RFC1918" le 32 action deny } rule 103 { prefix 169.254.0.0/16 description "link-local" le 32 action deny } rule 104 { prefix 100.64.0.0/10 description "CGNAT" le 32 action deny } rule 105 { prefix 127.0.0.0/8 description "loopback" le 32 action deny } rule 106 { prefix 192.0.0.0/24 description "IETF protocol assignments" le 32 action deny } rule 107 { prefix 192.0.2.0/24 description "TEST-NET-1" le 32 action deny } rule 108 { prefix 198.18.0.0/15 description "Network interconnect device benchmark testing" le 32 action deny } rule 109 { prefix 198.51.100.0/24 description "TEST-NET-2" le 32 action deny } rule 110 { prefix 203.0.113.0/24 description "TEST-NET-3" le 32 action deny } rule 111 { prefix 224.0.0.0/4 description "multicast" le 32 action deny } rule 112 { prefix 240.0.0.0/4 description "reserved" le 32 action deny } rule 1000 { prefix 0.0.0.0/0 le 24 action permit } rule 65535 { prefix 0.0.0.0/0 le 32 action deny } } prefix-list hphr-DFZ-DEFAULT-LONG-IPv4 { rule 10 { prefix 0.0.0.0/0 action permit } rule 100 { prefix 192.168.0.0/16 description "RFC1918" le 32 action deny } rule 101 { prefix 172.16.0.0/12 description "RFC1918" le 32 action deny } rule 102 { prefix 10.0.0.0/8 description "RFC1918" le 32 action deny } rule 103 { prefix 169.254.0.0/16 description "link-local" le 32 action deny } rule 104 { prefix 100.64.0.0/10 description "CGNAT" le 32 action deny } rule 105 { prefix 127.0.0.0/8 description "loopback" le 32 action deny } rule 106 { prefix 192.0.0.0/24 description "IETF protocol assignments" le 32 action deny } rule 107 { prefix 192.0.2.0/24 description "TEST-NET-1" le 32 action deny } rule 108 { prefix 198.18.0.0/15 description "Network interconnect device benchmark testing" le 32 action deny } rule 109 { prefix 198.51.100.0/24 description "TEST-NET-2" le 32 action deny } rule 110 { prefix 203.0.113.0/24 description "TEST-NET-3" le 32 action deny } rule 111 { prefix 224.0.0.0/4 description "multicast" le 32 action deny } rule 112 { prefix 240.0.0.0/4 description "reserved" le 32 action deny } rule 1000 { prefix 0.0.0.0/0 le 32 action permit } } prefix-list6 hphr-NO-IPv6 { rule 1 { prefix ::/0 le 128 action deny } } prefix-list6 hphr-ALL-IPv6 { rule 1 { prefix ::/0 le 128 action permit } } prefix-list6 hphr-DEFAULT-IPv6 { rule 1 { prefix ::/0 action permit } rule 2 { prefix ::/0 le 128 action deny } } prefix-list6 hphr-DFZ-IPv6 { rule 100 { prefix ::/128 description "not self" action deny } rule 101 { prefix ::1/128 description "self" action deny } rule 102 { prefix ::ffff:0:0/96 description "IPv4-mapped" le 128 action deny } rule 103 { prefix ::/96 description "IPv4-compatible" le 128 action deny } rule 104 { prefix 100::/64 description "RTBH addresses" le 128 action deny } rule 105 { prefix 2001:10::/28 description "ORCHID addresses" le 128 action deny } rule 106 { prefix 2001:db8::/32 description "documentation prefix" le 128 action deny } rule 107 { prefix fc00::/7 description "ULA address" le 128 action deny } rule 108 { prefix fe80::/10 description "link-local" le 128 action deny } rule 109 { prefix fec0::/10 description "site-local" le 128 action deny } rule 110 { prefix ff0e::/16 description "global multicast" le 64 action permit } rule 111 { prefix ff00::/8 description "multicast" le 128 action deny } rule 1000 { prefix ::/0 le 64 action permit } } prefix-list6 hphr-DFZ-LONG-IPv6 { rule 100 { prefix ::/128 description "not self" action deny } rule 101 { prefix ::1/128 description "self" action deny } rule 102 { prefix ::ffff:0:0/96 description "IPv4-mapped" le 128 action deny } rule 103 { prefix ::/96 description "IPv4-compatible" le 128 action deny } rule 104 { prefix 100::/64 description "RTBH addresses" le 128 action deny } rule 105 { prefix 2001:10::/28 description "ORCHID addresses" le 128 action deny } rule 106 { prefix 2001:db8::/32 description "documentation prefix" le 128 action deny } rule 107 { prefix fc00::/7 description "ULA address" le 128 action deny } rule 108 { prefix fe80::/10 description "link-local" le 128 action deny } rule 109 { prefix fec0::/10 description "site-local" le 128 action deny } rule 110 { prefix ff0e::/16 description "global multicast" le 64 action permit } rule 111 { prefix ff00::/8 description "multicast" le 128 action deny } rule 1000 { prefix ::/0 le 128 action permit } } prefix-list6 hphr-DFZ-DEFAULT-IPv6 { rule 10 { prefix ::/0 action permit } rule 100 { prefix ::/128 description "not self" action deny } rule 101 { prefix ::1/128 description "self" action deny } rule 102 { prefix ::ffff:0:0/96 description "IPv4-mapped" le 128 action deny } rule 103 { prefix ::/96 description "IPv4-compatible" le 128 action deny } rule 104 { prefix 100::/64 description "RTBH addresses" le 128 action deny } rule 105 { prefix 2001:10::/28 description "ORCHID addresses" le 128 action deny } rule 106 { prefix 2001:db8::/32 description "documentation prefix" le 128 action deny } rule 107 { prefix fc00::/7 description "ULA address" le 128 action deny } rule 108 { prefix fe80::/10 description "link-local" le 128 action deny } rule 109 { prefix fec0::/10 description "site-local" le 128 action deny } rule 110 { prefix ff0e::/16 description "global multicast" le 64 action permit } rule 111 { prefix ff00::/8 description "multicast" le 128 action deny } rule 1000 { prefix ::/0 le 64 action permit } } prefix-list6 hphr-DFZ-DEFAULT-LONG-IPv6 { rule 10 { prefix ::/0 action permit } rule 100 { prefix ::/128 description "not self" action deny } rule 101 { prefix ::1/128 description "self" action deny } rule 102 { prefix ::ffff:0:0/96 description "IPv4-mapped" le 128 action deny } rule 103 { prefix ::/96 description "IPv4-compatible" le 128 action deny } rule 104 { prefix 100::/64 description "RTBH addresses" le 128 action deny } rule 105 { prefix 2001:10::/28 description "ORCHID addresses" le 128 action deny } rule 106 { prefix 2001:db8::/32 description "documentation prefix" le 128 action deny } rule 107 { prefix fc00::/7 description "ULA address" le 128 action deny } rule 108 { prefix fe80::/10 description "link-local" le 128 action deny } rule 109 { prefix fec0::/10 description "site-local" le 128 action deny } rule 110 { prefix ff0e::/16 description "global multicast" le 64 action permit } rule 111 { prefix ff00::/8 description "multicast" le 128 action deny } rule 1000 { prefix ::/0 le 128 action permit } } prefix-list hphr-BLACKHOLE-IPv4 { rule 1 { prefix 0.0.0.0/0 ge 32 le 32 action permit } } prefix-list6 hphr-BLACKHOLE-IPv6 { rule 1 { prefix ::/0 ge 64 le 128 action permit } } route-map hphr-BLACKHOLE-IPv4 { rule 1 { match { ip { address { prefix-list hphr-BLACKHOLE-IPv4 } } } action permit set { ip-next-hop {{ salt['pillar.get']('protocols:static:blackhole:IPv4') }} } } } route-map hphr-BLACKHOLE-IPv6 { rule 1 { match { ipv6 { address { prefix-list hphr-BLACKHOLE-IPv6 } } } action permit set { ipv6-next-hop { global {{ salt['pillar.get']('protocols:static:blackhole:IPv6') }} } } } } {% for community_list_name, cm_data in pillar['policy']['community-list'].items() %} community-list {{ community_list_name }} { {% for group in cm_data %} rule {{ loop.index }} { regex "{{ group['community'] }}" action permit } {% endfor %} } {% endfor %} {% for route_map_name, af_pg in pillar['policy']['route-map'].items() %}{% for af, prefix_groups in af_pg.items() %} route-map {{ route_map_name }}-{{ af }} { {% for group in prefix_groups %} rule {{ loop.index }} { match { {% if 'match-prefix-list' in group %} {% if af=="IPv4" %}ip{% elif af=="IPv6" %}ipv6{% endif %} { address { prefix-list {{ group['match-prefix-list'] }} } } {% endif %} {% if 'match-community' in group %} community { community-list {{ group['match-community'] }} } {% endif %} {% if 'match-rpki' in group %} rpki {{ group['match-rpki'] }} {% endif %} } action {{ group.get('action','permit') }} {% if 'on-match' in group %} on-match { {{ group['on-match'] }} } {% endif %} {% if 'call' in group %} call {{ group['call'] }} {% endif %} {% if 'continue' in group %} continue {% if group['continue'] == 'next' %}{{ loop.index+1 }}{% else %}{{ group['continue'] }}{% endif %} {% endif %} set { {% if 'add-community' in group %}community "additive {{ group['add-community'] }}"{% elif 'set-community' in group %}community {{ group['set-community'] }}{% endif %} {% if 'set-local-preference' in group %}local-preference {{ group['set-local-preference'] }}{% endif %} } } {% endfor %} } {% endfor %}{% endfor %} {% if 'community_affects_route_maps' in pillar and 'site_codes' in pillar and 'community_affects_prepend_asn' in pillar %} {% for route_map_prefix,community_suffixes in pillar.get('community_affects',{}).items() %} {% for digit in "01239" %} community-list community_affects_65XX{{ digit }}_{{ route_map_prefix }} { {% for community_suffix in ["0"] + community_suffixes %} {% set loop_parent = loop %} {% for site_code in ['00'] + pillar['site_codes'] %} rule {{ loop_parent.index0 * 10 + loop.index }} { action 'permit' regex 65{{ site_code }}{{ digit }}:{{ community_suffix }} } {% endfor %} {% endfor %} } {% endfor %} {% for af in ['IPv4','IPv6'] %} {% for rm in pillar['community_affects_route_maps'] %} route-map {{ route_map_prefix }}-{{ rm }}-{{ af }} { rule {{ loop.index*10 }} { match { community { community-list community_affects_65XX0_{{ route_map_prefix }} } } action deny } rule {{ loop.index*10 + 1 }} { match { community { community-list community_affects_65XX1_{{ route_map_prefix }} } } set { as-path-prepend "{{ pillar['community_affects_prepend_asn'] }}" } call {{ rm }}-{{ af }} action permit } rule {{ loop.index*10 + 2 }} { match { community { community-list community_affects_65XX2_{{ route_map_prefix }} } } set { as-path-prepend "{{ pillar['community_affects_prepend_asn'] }} {{ pillar['community_affects_prepend_asn'] }}" } call {{ rm }}-{{ af }} action permit } rule {{ loop.index*10 + 3 }} { match { community { community-list community_affects_65XX3_{{ route_map_prefix }} } } set { as-path-prepend "{{ pillar['community_affects_prepend_asn'] }} {{ pillar['community_affects_prepend_asn'] }} {{ pillar['community_affects_prepend_asn'] }}" } call {{ rm }}-{{ af }} action permit } rule {{ loop.index*10 + 9 }} { match { community { community-list community_affects_65XX9_{{ route_map_prefix }} } } set { community "additive no-export" } call {{ rm }}-{{ af }} action permit } rule 65535 { match { {% if af == "IPv4" %} ip { address { prefix-list hphr-DFZ-IPv4 } } {% elif af == "IPv6" %} ipv6 { address { prefix-list hphr-DFZ-IPv6 } } {% endif %} } call {{ rm }}-{{ af }} action permit } } {% endfor %} {% endfor %} {% endfor %} {% endif %} {% for prefix_list_name, prefix_data in salt['pillar.get']("policy:prefix-list",{}).items() %} prefix-list {{ prefix_list_name }} { {% if 'bgpq3' in prefix_data %} {% set jsonblob = salt['cmd.run']('/tmp/bgpq3 -m 24 -R 24 -A -4 -j ' + prefix_data["bgpq3"]["IPv4"], env=env_exec)|load_json %} {% for prefix in jsonblob.NN %} rule {{ loop.index }} { action permit prefix {{ prefix['prefix'] }} {% if prefix_data['bgpq3'].get('most-specific',False) %} le 32 {% else %} {% if prefix.get('less-equal',None) != None %}le {{ prefix['less-equal'] }}{% endif %} {% if prefix.get('greater-equal',None) != None %}ge {{ prefix['greater-equal'] }}{% endif %} {% endif %} } {% endfor %} {% elif 'static' in prefix_data %} {% for prefix in prefix_data['static']['prefixes'] %}{% if "." in prefix %} rule {{ loop.index }} { {% if prefix.get('description',None) != None %}description '{{ prefix['description'].replace("'","\\'") }}'{% endif %} 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 %} } {% endif %}{% endfor %} {% endif %} rule 65535 { prefix 0.0.0.0/0 le 32 action deny } } {% 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 -m 24 -R 24 -A -4 -S ' + prefix_data["sources"] + ' -j ' + prefix_data["as-set"], env=env_exec)|load_json %} {% 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 %} {% set jsonblob = salt['cmd.run']('/tmp/bgpq3 -m 48 -R 48 -A -6 -j ' + prefix_data["bgpq3"]["IPv6"], env=env_exec)|load_json %} {% for prefix in jsonblob.NN %} rule {{ loop.index }} { action permit prefix {{ prefix['prefix'] }} {% if prefix_data['bgpq3'].get('most-specific',False) %} le 128 {% else %} {% if prefix.get('less-equal',None) != None %}le {{ prefix['less-equal'] }}{% endif %} {#% if prefix.get('greater-equal',None) != None %}ge {{ prefix['greater-equal'] }}{% endif %#} {% endif %} } {% endfor %} {% elif 'static' in prefix_data %} {% for prefix in prefix_data['static']['prefixes'] %}{% if ":" in prefix %} {% if prefix.get('description',None) != None %}description '{{ prefix['description'].replace("'","\\'") }}'{% endif %} 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 %} } {% endif %}{% endfor %} {% endif %} rule 65535 { prefix ::/0 le 128 action deny } } {% 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 -m 48 -R 48 -A -6 -S ' + prefix_data["sources"] + ' -j ' + prefix_data["as-set"], env=env_exec)|load_json %} {% 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 -=-=-=-=-=-=-=-=-=-=-=-=-=- */ service { lldp { {% for iface_name, iface_data in salt['pillar.get']('service:lldp:interface',{}).items() %} interface {{ iface_name }} { } {% endfor %} management-address {{ pillar['service']['lldp']['management-address'] }} } salt-minion { id {{ grains['fqdn'] }} master {{ pillar['service']['salt-minion']['master'] }} } snmp { {% for cty_name, cty_data in salt['pillar.get']('service:snmp:community',{}).items() %} community {{ cty_name }} { } {% endfor %} trap-source {{ pillar['service']['snmp']['trap-source'] }} listen-address {{ pillar['service']['snmp']['trap-source'] }} {% for trap_target, trap_data in salt['pillar.get']('service:snmp:trap-target',{}).items() %} trap-target {{ trap_target }} { } {% endfor %} {% if salt['pillar.get']('service:snmp:vrf') %}vrf {{ salt['pillar.get']('service:snmp:vrf') }}{% endif %} } ssh { listen-address {{ pillar['service']['ssh']['listen-address'] }} {% if salt['pillar.get']('service:ssh:vrf') %}vrf {{ salt['pillar.get']('service:ssh:vrf') }}{% endif %} ciphers chacha20-poly1305@openssh.com ciphers aes256-gcm@openssh.com ciphers aes128-gcm@openssh.com ciphers aes256-ctr ciphers aes192-ctr ciphers aes128-ctr key-exchange curve25519-sha256@libssh.org key-exchange ecdh-sha2-nistp521 key-exchange ecdh-sha2-nistp384 key-exchange ecdh-sha2-nistp256 key-exchange diffie-hellman-group-exchange-sha256 mac hmac-sha2-512-etm@openssh.com mac hmac-sha2-256-etm@openssh.com mac umac-128-etm@openssh.com mac hmac-sha2-512 mac hmac-sha2-256 mac umac-128@openssh.com } } /* -=-=-=-=-=-=-=-=-=-=-=-=-=- SYSTEM -=-=-=-=-=-=-=-=-=-=-=-=-=- */ system { config-management { commit-revisions 100 } console { device ttyS0 { speed 115200 } device ttyS1 { speed 115200 } } flow-accounting { {% for iface_name, iface_data in pillar['netbox']['interfaces'].items() %}{% if salt['pillar.get']('interfaces:'+iface_name+':netflow') %} interface {{ iface_name }} {% endif %}{% endfor %} netflow { sampling-rate 1 {% for server in pillar['netflow']['servers'] %} server {{ server.split(":")[0] }} { port {{ server.split(":")[1] }} } {% endfor %} version 9 } } host-name {{ grains['fqdn'] }} ip { multipath { layer4-hashing } } ipv6 { multipath { layer4-hashing } } login { {% if 'radius' in pillar %} {% if salt['pillar.get']('radius:old',False) %} {% for server, server_data in salt['pillar.get']('radius:server',{}).items() %} radius-server {{ server }} { port {{ server_data.get('port',1812) }} secret {{ server_data.get('key',server_data.get('secret','')) }} timeout {{ server_data.get('timeout',2) }} } {% endfor %} {% if 'source-address' in salt['pillar.get']('radius',{}) %} radius-source-address {{ salt['pillar.get']('radius:source-address') }} {% endif %} {% else %} radius { {% if salt['pillar.get']('radius:vrf') %}vrf {{ salt['pillar.get']('radius:vrf') }}{% endif %} {% for server, server_data in salt['pillar.get']('radius:server',{}).items() %} server {{ server }} { key {{ server_data.get('key',server_data.get('secret','')) }} } {% endfor %} source-address {{ salt['pillar.get']('radius:source-address') }} } {% endif %} {% endif %} {% for user, user_data in pillar['users'].items() %} user {{ user }} { {% if 'authentication' in user_data %} authentication { {% if 'encrypted-password' in user_data['authentication'] %} encrypted-password {{ user_data['authentication']['encrypted-password'] }} plaintext-password "" {% else %} plaintext-password '{{ user_data['authentication']['plaintext-password'] }}' {% endif %} {% for key, key_data in user_data['authentication'].get('public-keys',{}).items() %} public-keys {{ key }} { key {{ key_data['key'] }} type {{ key_data.get('type','ssh-rsa') }} } {% endfor %} } {% endif %} level {{ user_data.get('level','operator') }} } {% endfor %} } {% for nameserver in pillar['nameservers'] %} name-server {{ nameserver }} {% endfor %} ntp { {% for ntp_server, ntp_data in pillar['ntp'].items() %} server {{ ntp_server }} { } {% endfor %} } options { ctrl-alt-del-action ignore reboot-on-panic true beep-if-fully-booted } sysctl { all net.ipv4.conf.all.log_martians { value 0 } all net.ipv4.conf.all.rp_filter { value 2 } all net.ipv4.conf.default.rp_filter { value 2 } {% for sysctl, value in salt['pillar.get']('system:sysctl:custom', {}).items() %} custom {{ sysctl }} { value {{ value }} } {% endfor %} } syslog { global { facility all { level info } facility protocols { level debug } } } time-zone UTC } /* Warning: Do not remove the following line. */ /* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@3:ssh@1:system@11:vrrp@2:vyos-accel-ppp@1:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ /* Release version: 1.2.0-rolling+201904240337 */