From 8681a62fbb413ad3a613ebedb430919a940beef7 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 11 Aug 2021 21:11:48 +0200 Subject: bgp: evpn: T3739: add prefix-list match support FRR 7.5.1 supports: vyos(config-route-map)# match evpn default-route default EVPN type-5 route rd Route Distinguisher route-type Match route-type vni Match VNI This commit adds a proper VyOS CLI abstraction. --- data/templates/frr/policy.frr.tmpl | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'data/templates/frr') diff --git a/data/templates/frr/policy.frr.tmpl b/data/templates/frr/policy.frr.tmpl index b5649b44e..89bd558dc 100644 --- a/data/templates/frr/policy.frr.tmpl +++ b/data/templates/frr/policy.frr.tmpl @@ -165,6 +165,18 @@ route-map {{ route_map }} {{ rule_config.action }} {{ rule }} {% if rule_config.match.extcommunity is defined and rule_config.match.extcommunity is not none %} match extcommunity {{ rule_config.match.extcommunity }} {% endif %} +{% if rule_config.match.evpn is defined and rule_config.match.evpn.default_route is defined %} + match evpn default-route +{% endif %} +{% if rule_config.match.evpn is defined and rule_config.match.evpn.rd is defined and rule_config.match.evpn.rd is not none %} + match evpn rd {{ rule_config.match.evpn.rd }} +{% endif %} +{% if rule_config.match.evpn is defined and rule_config.match.evpn.route_type is defined and rule_config.match.evpn.route_type is not none %} + match evpn route-type {{ rule_config.match.evpn.route_type }} +{% endif %} +{% if rule_config.match.evpn is defined and rule_config.match.evpn.vni is defined and rule_config.match.evpn.vni is not none %} + match evpn vni {{ rule_config.match.evpn.vni }} +{% endif %} {% if rule_config.match.interface is defined and rule_config.match.interface is not none %} match interface {{ rule_config.match.interface }} {% endif %} -- cgit v1.2.3 From c7b8e12beb7c90a5531c81303fa4837bd9f51782 Mon Sep 17 00:00:00 2001 From: Viacheslav Date: Fri, 9 Jul 2021 14:01:52 +0000 Subject: policy: T3673: Add set large-comm-list-delete for route-map --- data/templates/frr/policy.frr.tmpl | 3 +++ interface-definitions/policy.xml.in | 12 ++++++++++++ 2 files changed, 15 insertions(+) (limited to 'data/templates/frr') diff --git a/data/templates/frr/policy.frr.tmpl b/data/templates/frr/policy.frr.tmpl index b5649b44e..57ab0f363 100644 --- a/data/templates/frr/policy.frr.tmpl +++ b/data/templates/frr/policy.frr.tmpl @@ -271,6 +271,9 @@ route-map {{ route_map }} {{ rule_config.action }} {{ rule }} {% if rule_config.set.large_community is defined and rule_config.set.large_community is not none %} set large-community {{ rule_config.set.large_community }} {% endif %} +{% if rule_config.set.large_comm_list_delete is defined and rule_config.set.large_comm_list_delete is not none %} + set large-comm-list {{ rule_config.set.large_comm_list_delete }} delete +{% endif %} {% if rule_config.set.local_preference is defined and rule_config.set.local_preference is not none %} set local-preference {{ rule_config.set.local_preference }} {% endif %} diff --git a/interface-definitions/policy.xml.in b/interface-definitions/policy.xml.in index 5a3c58fa8..02da76be4 100644 --- a/interface-definitions/policy.xml.in +++ b/interface-definitions/policy.xml.in @@ -1124,6 +1124,18 @@ + + + Delete BGP communities matching the large community-list + + policy large-community-list + + + txt + BGP large community-list + + + Border Gateway Protocol (BGP) local preference attribute -- cgit v1.2.3 From da94e0a736874d9a6420ec1aa754efcec684b390 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 13 Aug 2021 21:11:58 +0200 Subject: vrf: T3734: T3728: vni must be configured with a higher priority then bgpd When removing bgp (vrf) instances the assigned VRF vni must be deleted from FRR prior the removal of the bgp settings (T3734). This is now done by moving the CLI command "set vrf name red vni 1000" to a dedicated Python script with a priority higher then bgp. --- data/configd-include.json | 1 + data/templates/frr/vrf-vni.frr.tmpl | 7 ++++ data/templates/frr/vrf.frr.tmpl | 9 ----- interface-definitions/vrf.xml.in | 15 +++++++- src/conf_mode/vrf.py | 20 ---------- src/conf_mode/vrf_vni.py | 76 +++++++++++++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 30 deletions(-) create mode 100644 data/templates/frr/vrf-vni.frr.tmpl delete mode 100644 data/templates/frr/vrf.frr.tmpl create mode 100755 src/conf_mode/vrf_vni.py (limited to 'data/templates/frr') diff --git a/data/configd-include.json b/data/configd-include.json index 3b4e2925b..2d7ea149b 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -69,5 +69,6 @@ "vpn_pptp.py", "vpn_sstp.py", "vrf.py", +"vrf_vni.py", "vrrp.py" ] diff --git a/data/templates/frr/vrf-vni.frr.tmpl b/data/templates/frr/vrf-vni.frr.tmpl new file mode 100644 index 000000000..51d4ede1b --- /dev/null +++ b/data/templates/frr/vrf-vni.frr.tmpl @@ -0,0 +1,7 @@ +{% if vrf is defined and vrf is not none %} +vrf {{ vrf }} +{% if vni is defined and vni is not none %} + vni {{ vni }} +{% endif %} + exit-vrf +{% endif %} diff --git a/data/templates/frr/vrf.frr.tmpl b/data/templates/frr/vrf.frr.tmpl deleted file mode 100644 index 299c9719e..000000000 --- a/data/templates/frr/vrf.frr.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -{% if name is defined and name is not none %} -{% for vrf, vrf_config in name.items() %} -vrf {{ vrf }} -{% if vrf_config.vni is defined and vrf_config.vni is not none %} - vni {{ vrf_config.vni }} -{% endif %} - exit-vrf -{% endfor %} -{% endif %} diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in index 9d513945c..76d6df386 100644 --- a/interface-definitions/vrf.xml.in +++ b/interface-definitions/vrf.xml.in @@ -85,7 +85,20 @@ VRF routing table must be in range from 100 to 65535 - #include + + + Virtual Network Identifier + + 822 + + 0-16777214 + VXLAN virtual network identifier + + + + + + diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index c1cfc1dcb..919083ac4 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -24,7 +24,6 @@ from vyos.config import Config from vyos.configdict import node_changed from vyos.ifconfig import Interface from vyos.template import render -from vyos.template import render_to_string from vyos.util import call from vyos.util import cmd from vyos.util import dict_search @@ -32,12 +31,9 @@ from vyos.util import get_interface_config from vyos.util import popen from vyos.util import run from vyos import ConfigError -from vyos import frr from vyos import airbag airbag.enable() -frr_daemon = 'zebra' - config_file = r'/etc/iproute2/rt_tables.d/vyos-vrf.conf' def list_rules(): @@ -131,7 +127,6 @@ def verify(vrf): def generate(vrf): render(config_file, 'vrf/vrf.conf.tmpl', vrf) - vrf['new_frr_config'] = render_to_string('frr/vrf.frr.tmpl', vrf) # Render nftables zones config vrf['nft_vrf_zones'] = NamedTemporaryFile().name render(vrf['nft_vrf_zones'], 'firewall/nftables-vrf-zones.tmpl', vrf) @@ -242,21 +237,6 @@ def apply(vrf): if tmp == 0: cmd('nft delete table inet vrf_zones') - # T3694: Somehow we hit a priority inversion here as we need to remove the - # VRF assigned VNI before we can remove a BGP bound VRF instance. Maybe - # move this to an individual helper script that set's up the VNI for the - # given VRF after any routing protocol. - # - # # add configuration to FRR - # frr_cfg = frr.FRRConfig() - # frr_cfg.load_configuration(frr_daemon) - # frr_cfg.modify_section(f'^vrf [a-zA-Z-]*$', '') - # frr_cfg.add_before(r'(interface .*|line vty)', vrf['new_frr_config']) - # frr_cfg.commit_configuration(frr_daemon) - # - # # Save configuration to /run/frr/config/frr.conf - # frr.save_configuration() - return None if __name__ == '__main__': diff --git a/src/conf_mode/vrf_vni.py b/src/conf_mode/vrf_vni.py new file mode 100755 index 000000000..87ee8f2d1 --- /dev/null +++ b/src/conf_mode/vrf_vni.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020-2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from sys import argv +from sys import exit + +from vyos.config import Config +from vyos.template import render_to_string +from vyos import ConfigError +from vyos import frr +from vyos import airbag +airbag.enable() + +frr_daemon = 'zebra' + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + + # This script only works with a passed VRF name + if len(argv) < 1: + raise NotImplementedError + vrf = argv[1] + + # "assemble" dict - easier here then use a full blown get_config_dict() + # on a single leafNode + vni = { 'vrf' : vrf } + tmp = conf.return_value(['vrf', 'name', vrf, 'vni']) + if tmp: vni.update({ 'vni' : tmp }) + + return vni + +def verify(vni): + return None + +def generate(vni): + vni['new_frr_config'] = render_to_string('frr/vrf-vni.frr.tmpl', vni) + return None + +def apply(vni): + # add configuration to FRR + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + frr_cfg.modify_section(f'^vrf [a-zA-Z-]*$', '') + frr_cfg.add_before(r'(interface .*|line vty)', vni['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + # Save configuration to /run/frr/config/frr.conf + frr.save_configuration() + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) -- cgit v1.2.3 From e36a4e684b95c4fd1e9ab042270fafd95e697586 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 14 Aug 2021 18:13:50 +0200 Subject: ospf: T3236: use proper daemon named template file --- data/templates/frr/ospf.frr.tmpl | 179 ------------------------------------- data/templates/frr/ospf6d.frr.tmpl | 89 ++++++++++++++++++ data/templates/frr/ospfd.frr.tmpl | 179 +++++++++++++++++++++++++++++++++++++ data/templates/frr/ospfv3.frr.tmpl | 89 ------------------ src/conf_mode/protocols_ospf.py | 2 +- src/conf_mode/protocols_ospfv3.py | 4 +- 6 files changed, 271 insertions(+), 271 deletions(-) delete mode 100644 data/templates/frr/ospf.frr.tmpl create mode 100644 data/templates/frr/ospf6d.frr.tmpl create mode 100644 data/templates/frr/ospfd.frr.tmpl delete mode 100644 data/templates/frr/ospfv3.frr.tmpl (limited to 'data/templates/frr') diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospf.frr.tmpl deleted file mode 100644 index 36aa699a9..000000000 --- a/data/templates/frr/ospf.frr.tmpl +++ /dev/null @@ -1,179 +0,0 @@ -! -{% if interface is defined and interface is not none %} -{% for iface, iface_config in interface.items() %} -interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} -{% if iface_config.authentication is defined and iface_config.authentication is not none %} -{% if iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %} - ip ospf authentication-key {{ iface_config.authentication.plaintext_password }} -{% elif iface_config.authentication.md5 is defined %} - ip ospf authentication message-digest -{% if iface_config.authentication.md5.key_id is defined and iface_config.authentication.md5.key_id is not none %} -{% for key, key_config in iface_config.authentication.md5.key_id.items() %} - ip ospf message-digest-key {{ key }} md5 {{ key_config.md5_key }} -{% endfor %} -{% endif %} -{% endif %} -{% endif %} -{% if iface_config.cost is defined and iface_config.cost is not none %} - ip ospf cost {{ iface_config.cost }} -{% endif %} -{% if iface_config.priority is defined and iface_config.priority is not none %} - ip ospf priority {{ iface_config.priority }} -{% endif %} -{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} - ip ospf hello-interval {{ iface_config.hello_interval }} -{% endif %} -{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %} - ip ospf retransmit-interval {{ iface_config.retransmit_interval }} -{% endif %} -{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %} - ip ospf transmit-delay {{ iface_config.transmit_delay }} -{% endif %} -{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %} - ip ospf dead-interval {{ iface_config.dead_interval }} -{% elif iface_config.hello_multiplier is defined and iface_config.hello_multiplier is not none %} - ip ospf dead-interval minimal hello-multiplier {{ iface_config.hello_multiplier }} -{% endif %} -{% if iface_config.bfd is defined %} - ip ospf bfd -{% endif %} -{% if iface_config.mtu_ignore is defined %} - ip ospf mtu-ignore -{% endif %} -{% if iface_config.network is defined and iface_config.network is not none %} - ip ospf network {{ iface_config.network }} -{% endif %} -{% if iface_config.bandwidth is defined and iface_config.bandwidth is not none %} - bandwidth {{ iface_config.bandwidth }} -{% endif %} -! -{% endfor %} -{% endif %} -! -router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} -{% if access_list is defined and access_list is not none %} -{% for acl, acl_config in access_list.items() %} -{% for protocol in acl_config.export if acl_config.export is defined %} - distribute-list {{ acl }} out {{ protocol }} -{% endfor %} -{% endfor %} -{% endif %} -{% if area is defined and area is not none %} -{% for area_id, area_config in area.items() %} -{% if area_config.area_type is defined and area_config.area_type is not none %} -{% for type, type_config in area_config.area_type.items() if type != 'normal' %} - area {{ area_id }} {{ type }} {{ 'no-summary' if type_config.no_summary is defined }} -{% if type_config.default_cost is defined and type_config.default_cost is not none %} - area {{ area_id }} default-cost {{ type_config.default_cost }} -{% endif %} -{% endfor %} -{% endif %} -{% if area_config.authentication is defined and area_config.authentication is not none %} - area {{ area_id }} authentication {{ 'message-digest' if area_config.authentication == 'md5' }} -{% endif %} -{% for network in area_config.network if area_config.network is defined %} - network {{ network }} area {{ area_id }} -{% endfor %} -{% if area_config.range is defined and area_config.range is not none %} -{% for range, range_config in area_config.range.items() %} -{% if range_config.cost is defined and range_config.cost is not none %} - area {{ area_id }} range {{ range }} cost {{ range_config.cost }} -{% endif %} -{% if range_config.not_advertise is defined %} - area {{ area_id }} range {{ range }} not-advertise -{% endif %} -{% if range_config.substitute is defined and range_config.substitute is not none %} - area {{ area_id }} range {{ range }} substitute {{ range_config.substitute }} -{% endif %} -{% endfor %} -{% endif %} -{% if area_config.shortcut is defined and area_config.shortcut is not none %} - area {{ area_id }} shortcut {{ area_config.shortcut }} -{% endif %} -{% if area_config.virtual_link is defined and area_config.virtual_link is not none %} -{% for link, link_config in area_config.virtual_link.items() %} -{% if link_config.authentication is defined and link_config.authentication is not none %} -{% if link_config.authentication.plaintext_password is defined and link_config.authentication.plaintext_password is not none %} - area {{ area_id }} virtual-link {{ link }} authentication-key {{ link_config.authentication.plaintext_password }} -{% elif link_config.authentication.md5 is defined and link_config.authentication.md5.key_id is defined and link_config.authentication.md5.key_id is not none %} -{% for key, key_config in link_config.authentication.md5.key_id.items() %} - area {{ area_id }} virtual-link {{ link }} message-digest-key {{ key }} md5 {{ key_config.md5_key }} -{% endfor %} -{% endif %} -{% endif %} -{# The following values are default values #} - area {{ area_id }} virtual-link {{ link }} hello-interval {{ link_config.hello_interval }} retransmit-interval {{ link_config.retransmit_interval }} transmit-delay {{ link_config.transmit_delay }} dead-interval {{ link_config.dead_interval }} -{% endfor %} -{% endif %} -{% endfor %} -{% endif %} -{% if auto_cost is defined and auto_cost.reference_bandwidth is defined and auto_cost.reference_bandwidth is not none %} - auto-cost reference-bandwidth {{ auto_cost.reference_bandwidth }} -{% endif %} -{% if default_information is defined and default_information.originate is defined and default_information.originate is not none %} - default-information originate {{ 'always' if default_information.originate.always is defined }} {{ 'metric ' + default_information.originate.metric if default_information.originate.metric is defined }} {{ 'metric-type ' + default_information.originate.metric_type if default_information.originate.metric_type is defined }} {{ 'route-map ' + default_information.originate.route_map if default_information.originate.route_map is defined }} -{% endif %} -{% if default_metric is defined and default_metric is not none %} - default-metric {{ default_metric }} -{% endif %} -{% if distance is defined and distance is not none %} -{% if distance.global is defined and distance.global is not none %} - distance {{ distance.global }} -{% endif %} -{% if distance.ospf is defined and distance.ospf is not none %} - distance ospf {{ 'intra-area ' + distance.ospf.intra_area if distance.ospf.intra_area is defined }} {{ 'inter-area ' + distance.ospf.inter_area if distance.ospf.inter_area is defined }} {{ 'external ' + distance.ospf.external if distance.ospf.external is defined }} -{% endif %} -{% endif %} -{% if log_adjacency_changes is defined %} - log-adjacency-changes {{ "detail" if log_adjacency_changes.detail is defined }} -{% endif %} -{% if max_metric is defined and max_metric.router_lsa is defined and max_metric.router_lsa is not none %} -{% if max_metric.router_lsa.administrative is defined %} - max-metric router-lsa administrative -{% endif %} -{% if max_metric.router_lsa.on_shutdown is defined and max_metric.router_lsa.on_shutdown is not none %} - max-metric router-lsa on-shutdown {{ max_metric.router_lsa.on_shutdown }} -{% endif %} -{% if max_metric.router_lsa.on_startup is defined and max_metric.router_lsa.on_startup is not none %} - max-metric router-lsa on-startup {{ max_metric.router_lsa.on_startup }} -{% endif %} -{% endif %} -{% if mpls_te is defined and mpls_te.enable is defined %} - mpls-te on - mpls-te router-address {{ mpls_te.router_address }} -{% endif %} -{% if neighbor is defined and neighbor is not none%} -{% for address, address_config in neighbor.items() %} - neighbor {{ address }} {{ 'priority ' + address_config.priority if address_config.priority is defined }} {{ 'poll-interval ' + address_config.poll_interval if address_config.poll_interval is defined }} -{% endfor %} -{% endif %} -{% if parameters is defined and parameters is not none %} -{% if parameters.abr_type is defined and parameters.abr_type is not none %} - ospf abr-type {{ parameters.abr_type }} -{% endif %} -{% if parameters.router_id is defined and parameters.router_id is not none %} - ospf router-id {{ parameters.router_id }} -{% endif %} -{% endif %} -{% for interface in passive_interface if passive_interface is defined %} - passive-interface {{ interface }} -{% endfor %} -{% for interface in passive_interface_exclude if passive_interface_exclude is defined %} -{% if interface.startswith('vlink') %} -{% set interface = interface.upper() %} -{% endif %} - no passive-interface {{ interface }} -{% endfor %} -{% if redistribute is defined and redistribute is not none %} -{% for protocol, options in redistribute.items() %} - redistribute {{ protocol }} {{ 'metric ' + options.metric if options.metric is defined }} {{ 'metric-type ' + options.metric_type if options.metric_type is defined }} {{ 'route-map ' + options.route_map if options.route_map is defined }} -{% endfor %} -{% endif %} -{% if refresh is defined and refresh.timers is defined and refresh.timers is not none %} - refresh timer {{ refresh.timers }} -{% endif %} -{% if timers is defined and timers.throttle is defined and timers.throttle.spf is defined and timers.throttle.spf is not none %} -{# Timer values have default values #} - timers throttle spf {{ timers.throttle.spf.delay }} {{ timers.throttle.spf.initial_holdtime }} {{ timers.throttle.spf.max_holdtime }} -{% endif %} -! diff --git a/data/templates/frr/ospf6d.frr.tmpl b/data/templates/frr/ospf6d.frr.tmpl new file mode 100644 index 000000000..0026c0d2c --- /dev/null +++ b/data/templates/frr/ospf6d.frr.tmpl @@ -0,0 +1,89 @@ +! +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.cost is defined and iface_config.cost is not none %} + ipv6 ospf6 cost {{ iface_config.cost }} +{% endif %} +{% if iface_config.priority is defined and iface_config.priority is not none %} + ipv6 ospf6 priority {{ iface_config.priority }} +{% endif %} +{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} + ipv6 ospf6 hello-interval {{ iface_config.hello_interval }} +{% endif %} +{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %} + ipv6 ospf6 retransmit-interval {{ iface_config.retransmit_interval }} +{% endif %} +{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %} + ipv6 ospf6 transmit-delay {{ iface_config.transmit_delay }} +{% endif %} +{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %} + ipv6 ospf6 dead-interval {{ iface_config.dead_interval }} +{% endif %} +{% if iface_config.bfd is defined %} + ipv6 ospf6 bfd +{% endif %} +{% if iface_config.mtu_ignore is defined %} + ipv6 ospf6 mtu-ignore +{% endif %} +{% if iface_config.ifmtu is defined and iface_config.ifmtu is not none %} + ipv6 ospf6 ifmtu {{ iface_config.ifmtu }} +{% endif %} +{% if iface_config.network is defined and iface_config.network is not none %} + ipv6 ospf6 network {{ iface_config.network }} +{% endif %} +{% if iface_config.instance_id is defined and iface_config.instance_id is not none %} + ipv6 ospf6 instance-id {{ iface_config.instance_id }} +{% endif %} +{% if iface_config.passive is defined %} + ipv6 ospf6 passive +{% endif %} +! +{% endfor %} +{% endif %} +! +router ospf6 +{% if area is defined and area is not none %} +{% for area_id, area_config in area.items() %} +{% if area_config.interface is defined and area_config.interface is not none %} +{% for interface in area_config.interface %} + interface {{ interface }} area {{ area_id }} +{% endfor %} +{% endif %} +{% if area_config.area_type is defined and area_config.area_type is not none %} +{% for type, type_config in area_config.area_type.items() %} + area {{ area_id }} {{ type }} {{ 'no-summary' if type_config.no_summary is defined }} +{% endfor %} +{% endif %} +{% if area_config.range is defined and area_config.range is not none %} +{% for prefix, prefix_config in area_config.range.items() %} + area {{ area_id }} range {{ prefix }} {{ 'advertise' if prefix_config.advertise is defined }} {{ 'not-advertise' if prefix_config.not_advertise is defined }} +{% endfor %} +{% endif %} +{% if area_config.export_list is defined and area_config.export_list is not none %} + area {{ area_id }} export-list {{ area_config.export_list }} +{% endif %} +{% if area_config.import_list is defined and area_config.import_list is not none %} + area {{ area_id }} import-list {{ area_config.import_list }} +{% endif %} +{% endfor %} +{% endif %} +{% if distance is defined and distance is not none %} +{% if distance.global is defined and distance.global is not none %} + distance {{ distance.global }} +{% endif %} +{% if distance.ospfv3 is defined and distance.ospfv3 is not none %} + distance ospf6 {{ 'intra-area ' + distance.ospfv3.intra_area if distance.ospfv3.intra_area is defined }} {{ 'inter-area ' + distance.ospfv3.inter_area if distance.ospfv3.inter_area is defined }} {{ 'external ' + distance.ospfv3.external if distance.ospfv3.external is defined }} +{% endif %} +{% endif %} +{% if parameters is defined and parameters is not none %} +{% if parameters.router_id is defined and parameters.router_id is not none %} + ospf6 router-id {{ parameters.router_id }} +{% endif %} +{% endif %} +{% if redistribute is defined and redistribute is not none %} +{% for protocol, options in redistribute.items() %} + redistribute {{ protocol }} {{ 'route-map ' + options.route_map if options.route_map is defined }} +{% endfor %} +{% endif %} +! diff --git a/data/templates/frr/ospfd.frr.tmpl b/data/templates/frr/ospfd.frr.tmpl new file mode 100644 index 000000000..763d0666c --- /dev/null +++ b/data/templates/frr/ospfd.frr.tmpl @@ -0,0 +1,179 @@ +! +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} +{% if iface_config.authentication is defined and iface_config.authentication is not none %} +{% if iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %} + ip ospf authentication-key {{ iface_config.authentication.plaintext_password }} +{% elif iface_config.authentication.md5 is defined %} + ip ospf authentication message-digest +{% if iface_config.authentication.md5.key_id is defined and iface_config.authentication.md5.key_id is not none %} +{% for key, key_config in iface_config.authentication.md5.key_id.items() %} + ip ospf message-digest-key {{ key }} md5 {{ key_config.md5_key }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} +{% if iface_config.cost is defined and iface_config.cost is not none %} + ip ospf cost {{ iface_config.cost }} +{% endif %} +{% if iface_config.priority is defined and iface_config.priority is not none %} + ip ospf priority {{ iface_config.priority }} +{% endif %} +{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} + ip ospf hello-interval {{ iface_config.hello_interval }} +{% endif %} +{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %} + ip ospf retransmit-interval {{ iface_config.retransmit_interval }} +{% endif %} +{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %} + ip ospf transmit-delay {{ iface_config.transmit_delay }} +{% endif %} +{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %} + ip ospf dead-interval {{ iface_config.dead_interval }} +{% elif iface_config.hello_multiplier is defined and iface_config.hello_multiplier is not none %} + ip ospf dead-interval minimal hello-multiplier {{ iface_config.hello_multiplier }} +{% endif %} +{% if iface_config.bfd is defined %} + ip ospf bfd +{% endif %} +{% if iface_config.mtu_ignore is defined %} + ip ospf mtu-ignore +{% endif %} +{% if iface_config.network is defined and iface_config.network is not none %} + ip ospf network {{ iface_config.network }} +{% endif %} +{% if iface_config.bandwidth is defined and iface_config.bandwidth is not none %} + bandwidth {{ iface_config.bandwidth }} +{% endif %} +! +{% endfor %} +{% endif %} +! +router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} +{% if access_list is defined and access_list is not none %} +{% for acl, acl_config in access_list.items() %} +{% for protocol in acl_config.export if acl_config.export is defined %} + distribute-list {{ acl }} out {{ protocol }} +{% endfor %} +{% endfor %} +{% endif %} +{% if area is defined and area is not none %} +{% for area_id, area_config in area.items() %} +{% if area_config.area_type is defined and area_config.area_type is not none %} +{% for type, type_config in area_config.area_type.items() if type != 'normal' %} + area {{ area_id }} {{ type }} {{ 'no-summary' if type_config.no_summary is defined }} +{% if type_config.default_cost is defined and type_config.default_cost is not none %} + area {{ area_id }} default-cost {{ type_config.default_cost }} +{% endif %} +{% endfor %} +{% endif %} +{% if area_config.authentication is defined and area_config.authentication is not none %} + area {{ area_id }} authentication {{ 'message-digest' if area_config.authentication == 'md5' }} +{% endif %} +{% for network in area_config.network if area_config.network is defined %} + network {{ network }} area {{ area_id }} +{% endfor %} +{% if area_config.range is defined and area_config.range is not none %} +{% for range, range_config in area_config.range.items() %} +{% if range_config.cost is defined and range_config.cost is not none %} + area {{ area_id }} range {{ range }} cost {{ range_config.cost }} +{% endif %} +{% if range_config.not_advertise is defined %} + area {{ area_id }} range {{ range }} not-advertise +{% endif %} +{% if range_config.substitute is defined and range_config.substitute is not none %} + area {{ area_id }} range {{ range }} substitute {{ range_config.substitute }} +{% endif %} +{% endfor %} +{% endif %} +{% if area_config.shortcut is defined and area_config.shortcut is not none %} + area {{ area_id }} shortcut {{ area_config.shortcut }} +{% endif %} +{% if area_config.virtual_link is defined and area_config.virtual_link is not none %} +{% for link, link_config in area_config.virtual_link.items() %} +{% if link_config.authentication is defined and link_config.authentication is not none %} +{% if link_config.authentication.plaintext_password is defined and link_config.authentication.plaintext_password is not none %} + area {{ area_id }} virtual-link {{ link }} authentication-key {{ link_config.authentication.plaintext_password }} +{% elif link_config.authentication.md5 is defined and link_config.authentication.md5.key_id is defined and link_config.authentication.md5.key_id is not none %} +{% for key, key_config in link_config.authentication.md5.key_id.items() %} + area {{ area_id }} virtual-link {{ link }} message-digest-key {{ key }} md5 {{ key_config.md5_key }} +{% endfor %} +{% endif %} +{% endif %} +{# The following values are default values #} + area {{ area_id }} virtual-link {{ link }} hello-interval {{ link_config.hello_interval }} retransmit-interval {{ link_config.retransmit_interval }} transmit-delay {{ link_config.transmit_delay }} dead-interval {{ link_config.dead_interval }} +{% endfor %} +{% endif %} +{% endfor %} +{% endif %} +{% if auto_cost is defined and auto_cost.reference_bandwidth is defined and auto_cost.reference_bandwidth is not none %} + auto-cost reference-bandwidth {{ auto_cost.reference_bandwidth }} +{% endif %} +{% if default_information is defined and default_information.originate is defined and default_information.originate is not none %} + default-information originate {{ 'always' if default_information.originate.always is defined }} {{ 'metric ' + default_information.originate.metric if default_information.originate.metric is defined }} {{ 'metric-type ' + default_information.originate.metric_type if default_information.originate.metric_type is defined }} {{ 'route-map ' + default_information.originate.route_map if default_information.originate.route_map is defined }} +{% endif %} +{% if default_metric is defined and default_metric is not none %} + default-metric {{ default_metric }} +{% endif %} +{% if distance is defined and distance is not none %} +{% if distance.global is defined and distance.global is not none %} + distance {{ distance.global }} +{% endif %} +{% if distance.ospf is defined and distance.ospf is not none %} + distance ospf {{ 'intra-area ' + distance.ospf.intra_area if distance.ospf.intra_area is defined }} {{ 'inter-area ' + distance.ospf.inter_area if distance.ospf.inter_area is defined }} {{ 'external ' + distance.ospf.external if distance.ospf.external is defined }} +{% endif %} +{% endif %} +{% if log_adjacency_changes is defined %} + log-adjacency-changes {{ "detail" if log_adjacency_changes.detail is defined }} +{% endif %} +{% if max_metric is defined and max_metric.router_lsa is defined and max_metric.router_lsa is not none %} +{% if max_metric.router_lsa.administrative is defined %} + max-metric router-lsa administrative +{% endif %} +{% if max_metric.router_lsa.on_shutdown is defined and max_metric.router_lsa.on_shutdown is not none %} + max-metric router-lsa on-shutdown {{ max_metric.router_lsa.on_shutdown }} +{% endif %} +{% if max_metric.router_lsa.on_startup is defined and max_metric.router_lsa.on_startup is not none %} + max-metric router-lsa on-startup {{ max_metric.router_lsa.on_startup }} +{% endif %} +{% endif %} +{% if mpls_te is defined and mpls_te.enable is defined %} + mpls-te on + mpls-te router-address {{ mpls_te.router_address }} +{% endif %} +{% if neighbor is defined and neighbor is not none%} +{% for address, address_config in neighbor.items() %} + neighbor {{ address }} {{ 'priority ' + address_config.priority if address_config.priority is defined }} {{ 'poll-interval ' + address_config.poll_interval if address_config.poll_interval is defined }} +{% endfor %} +{% endif %} +{% if parameters is defined and parameters is not none %} +{% if parameters.abr_type is defined and parameters.abr_type is not none %} + ospf abr-type {{ parameters.abr_type }} +{% endif %} +{% if parameters.router_id is defined and parameters.router_id is not none %} + ospf router-id {{ parameters.router_id }} +{% endif %} +{% endif %} +{% for interface in passive_interface if passive_interface is defined and passive_interface == 'default' %} + passive-interface default +{% endfor %} +{% for interface in passive_interface_exclude if passive_interface_exclude is defined %} +{% if interface.startswith('vlink') %} +{% set interface = interface.upper() %} +{% endif %} + no passive-interface {{ interface }} +{% endfor %} +{% if redistribute is defined and redistribute is not none %} +{% for protocol, options in redistribute.items() %} + redistribute {{ protocol }} {{ 'metric ' + options.metric if options.metric is defined }} {{ 'metric-type ' + options.metric_type if options.metric_type is defined }} {{ 'route-map ' + options.route_map if options.route_map is defined }} +{% endfor %} +{% endif %} +{% if refresh is defined and refresh.timers is defined and refresh.timers is not none %} + refresh timer {{ refresh.timers }} +{% endif %} +{% if timers is defined and timers.throttle is defined and timers.throttle.spf is defined and timers.throttle.spf is not none %} +{# Timer values have default values #} + timers throttle spf {{ timers.throttle.spf.delay }} {{ timers.throttle.spf.initial_holdtime }} {{ timers.throttle.spf.max_holdtime }} +{% endif %} +! diff --git a/data/templates/frr/ospfv3.frr.tmpl b/data/templates/frr/ospfv3.frr.tmpl deleted file mode 100644 index 0026c0d2c..000000000 --- a/data/templates/frr/ospfv3.frr.tmpl +++ /dev/null @@ -1,89 +0,0 @@ -! -{% if interface is defined and interface is not none %} -{% for iface, iface_config in interface.items() %} -interface {{ iface }} -{% if iface_config.cost is defined and iface_config.cost is not none %} - ipv6 ospf6 cost {{ iface_config.cost }} -{% endif %} -{% if iface_config.priority is defined and iface_config.priority is not none %} - ipv6 ospf6 priority {{ iface_config.priority }} -{% endif %} -{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} - ipv6 ospf6 hello-interval {{ iface_config.hello_interval }} -{% endif %} -{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %} - ipv6 ospf6 retransmit-interval {{ iface_config.retransmit_interval }} -{% endif %} -{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %} - ipv6 ospf6 transmit-delay {{ iface_config.transmit_delay }} -{% endif %} -{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %} - ipv6 ospf6 dead-interval {{ iface_config.dead_interval }} -{% endif %} -{% if iface_config.bfd is defined %} - ipv6 ospf6 bfd -{% endif %} -{% if iface_config.mtu_ignore is defined %} - ipv6 ospf6 mtu-ignore -{% endif %} -{% if iface_config.ifmtu is defined and iface_config.ifmtu is not none %} - ipv6 ospf6 ifmtu {{ iface_config.ifmtu }} -{% endif %} -{% if iface_config.network is defined and iface_config.network is not none %} - ipv6 ospf6 network {{ iface_config.network }} -{% endif %} -{% if iface_config.instance_id is defined and iface_config.instance_id is not none %} - ipv6 ospf6 instance-id {{ iface_config.instance_id }} -{% endif %} -{% if iface_config.passive is defined %} - ipv6 ospf6 passive -{% endif %} -! -{% endfor %} -{% endif %} -! -router ospf6 -{% if area is defined and area is not none %} -{% for area_id, area_config in area.items() %} -{% if area_config.interface is defined and area_config.interface is not none %} -{% for interface in area_config.interface %} - interface {{ interface }} area {{ area_id }} -{% endfor %} -{% endif %} -{% if area_config.area_type is defined and area_config.area_type is not none %} -{% for type, type_config in area_config.area_type.items() %} - area {{ area_id }} {{ type }} {{ 'no-summary' if type_config.no_summary is defined }} -{% endfor %} -{% endif %} -{% if area_config.range is defined and area_config.range is not none %} -{% for prefix, prefix_config in area_config.range.items() %} - area {{ area_id }} range {{ prefix }} {{ 'advertise' if prefix_config.advertise is defined }} {{ 'not-advertise' if prefix_config.not_advertise is defined }} -{% endfor %} -{% endif %} -{% if area_config.export_list is defined and area_config.export_list is not none %} - area {{ area_id }} export-list {{ area_config.export_list }} -{% endif %} -{% if area_config.import_list is defined and area_config.import_list is not none %} - area {{ area_id }} import-list {{ area_config.import_list }} -{% endif %} -{% endfor %} -{% endif %} -{% if distance is defined and distance is not none %} -{% if distance.global is defined and distance.global is not none %} - distance {{ distance.global }} -{% endif %} -{% if distance.ospfv3 is defined and distance.ospfv3 is not none %} - distance ospf6 {{ 'intra-area ' + distance.ospfv3.intra_area if distance.ospfv3.intra_area is defined }} {{ 'inter-area ' + distance.ospfv3.inter_area if distance.ospfv3.inter_area is defined }} {{ 'external ' + distance.ospfv3.external if distance.ospfv3.external is defined }} -{% endif %} -{% endif %} -{% if parameters is defined and parameters is not none %} -{% if parameters.router_id is defined and parameters.router_id is not none %} - ospf6 router-id {{ parameters.router_id }} -{% endif %} -{% endif %} -{% if redistribute is defined and redistribute is not none %} -{% for protocol, options in redistribute.items() %} - redistribute {{ protocol }} {{ 'route-map ' + options.route_map if options.route_map is defined }} -{% endfor %} -{% endif %} -! diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 78c1c82bd..82126cb11 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -177,7 +177,7 @@ def generate(ospf): ospf['protocol'] = 'ospf' # required for frr/vrf.route-map.frr.tmpl ospf['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.tmpl', ospf) - ospf['frr_ospfd_config'] = render_to_string('frr/ospf.frr.tmpl', ospf) + ospf['frr_ospfd_config'] = render_to_string('frr/ospfd.frr.tmpl', ospf) return None def apply(ospf): diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index fef0f509b..536ffa690 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -65,7 +65,7 @@ def verify(ospfv3): if 'ifmtu' in if_config: mtu = Interface(ifname).get_mtu() if int(if_config['ifmtu']) > int(mtu): - raise ConfigError(f'OSPFv3 ifmtu cannot go beyond physical MTU of "{mtu}"') + raise ConfigError(f'OSPFv3 ifmtu can not exceed physical MTU of "{mtu}"') return None @@ -74,7 +74,7 @@ def generate(ospfv3): ospfv3['new_frr_config'] = '' return None - ospfv3['new_frr_config'] = render_to_string('frr/ospfv3.frr.tmpl', ospfv3) + ospfv3['new_frr_config'] = render_to_string('frr/ospf6d.frr.tmpl', ospfv3) return None def apply(ospfv3): -- cgit v1.2.3 From 6f87d8c910964fd0ebe9724183baa12861caa419 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Aug 2021 12:53:03 +0200 Subject: ospf: T3757: support to configure area at an interface level FRR supports configuring either network prefixes per area, or assign an interface to an area to participate in the routing process. This is already well known from other venders and supported by FRR. A valid VyOS OSPF configuration would then look like: vyos@vyos# show protocols ospf { interface dum0 { area 0 } interface eth0.201 { area 0 authentication { md5 { key-id 10 { md5-key vyos } } } dead-interval 40 hello-interval 10 priority 1 retransmit-interval 5 transmit-delay 1 } log-adjacency-changes { detail } parameters { abr-type cisco router-id 172.18.254.201 } passive-interface default passive-interface-exclude eth0.201 } --- data/templates/frr/ospfd.frr.tmpl | 9 ++++++--- .../include/ospf/protocol-common-config.xml.i | 17 +++++++++++++++++ src/conf_mode/protocols_ospf.py | 9 +++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/ospfd.frr.tmpl b/data/templates/frr/ospfd.frr.tmpl index 763d0666c..67b679d66 100644 --- a/data/templates/frr/ospfd.frr.tmpl +++ b/data/templates/frr/ospfd.frr.tmpl @@ -14,6 +14,12 @@ interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% endif %} {% endif %} {% endif %} +{% if iface_config.area is defined and iface_config.area is not none %} + ip ospf area {{ iface_config.area }} +{% endif %} +{% if iface_config.bandwidth is defined and iface_config.bandwidth is not none %} + bandwidth {{ iface_config.bandwidth }} +{% endif %} {% if iface_config.cost is defined and iface_config.cost is not none %} ip ospf cost {{ iface_config.cost }} {% endif %} @@ -43,9 +49,6 @@ interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% if iface_config.network is defined and iface_config.network is not none %} ip ospf network {{ iface_config.network }} {% endif %} -{% if iface_config.bandwidth is defined and iface_config.bandwidth is not none %} - bandwidth {{ iface_config.bandwidth }} -{% endif %} ! {% endfor %} {% endif %} diff --git a/interface-definitions/include/ospf/protocol-common-config.xml.i b/interface-definitions/include/ospf/protocol-common-config.xml.i index db39b1a86..c4ca613a4 100644 --- a/interface-definitions/include/ospf/protocol-common-config.xml.i +++ b/interface-definitions/include/ospf/protocol-common-config.xml.i @@ -361,6 +361,23 @@ + + + Enable OSPF on this interface + + u32 + OSPF area ID as decimal notation + + + ipv4 + OSPF area ID in IP address notation + + + + + + + #include #include #include diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 82126cb11..a21ea6c9f 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -157,6 +157,15 @@ def verify(ospf): raise ConfigError(f'Can not use hello-multiplier and dead-interval ' \ f'concurrently for {interface}!') + # One can not use the "network area " command and an + # per interface area assignment at the same time. FRR will error + # out using: "Please remove all network commands first." + if 'area' in ospf: + for area, area_config in ospf['area'].items(): + if 'network' in area_config: + raise ConfigError('Can not use OSPF interface area and area ' \ + 'network configuration at the same time!') + if 'vrf' in ospf: # If interface specific options are set, we must ensure that the # interface is bound to our requesting VRF. Due to the VyOS -- cgit v1.2.3 From ae1994f1452377bf523973f2048b52590bcbad8b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Aug 2021 14:54:57 +0200 Subject: ospf: T3236: improve Jinja2 template - always use if before a loop --- data/templates/frr/ospfd.frr.tmpl | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/ospfd.frr.tmpl b/data/templates/frr/ospfd.frr.tmpl index 67b679d66..be39519c3 100644 --- a/data/templates/frr/ospfd.frr.tmpl +++ b/data/templates/frr/ospfd.frr.tmpl @@ -158,15 +158,19 @@ router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} ospf router-id {{ parameters.router_id }} {% endif %} {% endif %} -{% for interface in passive_interface if passive_interface is defined and passive_interface == 'default' %} - passive-interface default -{% endfor %} -{% for interface in passive_interface_exclude if passive_interface_exclude is defined %} -{% if interface.startswith('vlink') %} +{% if passive_interface is defined and passive_interface is not none %} +{% for interface in passive_interface %} + passive-interface {{ interface }} +{% endfor %} +{% endif %} +{% if passive_interface_exclude is defined and passive_interface_exclude is not none %} +{% for interface in passive_interface_exclude if passive_interface_exclude is defined %} +{% if interface.startswith('vlink') %} {% set interface = interface.upper() %} -{% endif %} +{% endif %} no passive-interface {{ interface }} -{% endfor %} +{% endfor %} +{% endif %} {% if redistribute is defined and redistribute is not none %} {% for protocol, options in redistribute.items() %} redistribute {{ protocol }} {{ 'metric ' + options.metric if options.metric is defined }} {{ 'metric-type ' + options.metric_type if options.metric_type is defined }} {{ 'route-map ' + options.route_map if options.route_map is defined }} -- cgit v1.2.3 From 1faa8728239cc5309cdaa82453b886710ad83699 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Tue, 17 Aug 2021 19:09:47 +0200 Subject: bgp: T3759: add l3vpn import/export vpn command for IPv4/IPv6 AFI --- data/templates/frr/bgpd.frr.tmpl | 6 +++++ .../include/bgp/afi-export-import.xml.i | 28 ++++++++++++++++++++++ .../include/bgp/protocol-common-config.xml.i | 2 ++ smoketest/scripts/cli/test_protocols_bgp.py | 20 ++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 interface-definitions/include/bgp/afi-export-import.xml.i (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index aa297876b..a21a2fefe 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -308,6 +308,12 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% endfor %} {% endif %} {% endif %} +{% if afi_config.export is defined and afi_config.export.vpn is defined %} + export vpn +{% endif %} +{% if afi_config.import is defined and afi_config.import.vpn is defined %} + import vpn +{% endif %} {% if afi_config.local_install is defined and afi_config.local_install is not none %} {% for interface in afi_config.local_install.interface %} local-install {{ interface }} diff --git a/interface-definitions/include/bgp/afi-export-import.xml.i b/interface-definitions/include/bgp/afi-export-import.xml.i new file mode 100644 index 000000000..ad54c723e --- /dev/null +++ b/interface-definitions/include/bgp/afi-export-import.xml.i @@ -0,0 +1,28 @@ + + + + Export routes from this address-family + + + + + to/from default instance VPN RIB + + + + + + + + Import routes to this address-family + + + + + to/from default instance VPN RIB + + + + + + diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 7ec320b61..da32fcc52 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -478,6 +478,7 @@ + #include BGP network @@ -638,6 +639,7 @@ + #include Import BGP network/prefix into multicast IPv6 RIB diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index c3a2ffbf9..22e892e26 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -710,5 +710,25 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f'router bgp {ASN}', frrconfig) self.assertIn(f' neighbor {neighbor} solo', frrconfig) + def test_bgp_14_vpn(self): + remote_asn = str(int(ASN) + 150) + neighbor = '192.0.2.55' + + self.cli_set(base_path + ['local-as', ASN]) + # testing only one AFI is sufficient as it's generic code + self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'export', 'vpn']) + self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'import', 'vpn']) + + # commit changes + self.cli_commit() + + # Verify FRR bgpd configuration + frrconfig = self.getFRRconfig(f'router bgp {ASN}') + self.assertIn(f'router bgp {ASN}', frrconfig) + self.assertIn(f' address-family ipv6 unicast', frrconfig) + self.assertIn(f' export vpn', frrconfig) + self.assertIn(f' import vpn', frrconfig) + self.assertIn(f' exit-address-family', frrconfig) + if __name__ == '__main__': unittest.main(verbosity=2) \ No newline at end of file -- cgit v1.2.3 From 053f586fa7a5a69b3b6be81339c73d8550d67fc6 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Tue, 17 Aug 2021 22:05:21 +0200 Subject: bgp: T3759: add l3vpn "import vrf" commands --- data/templates/frr/bgpd.frr.tmpl | 9 +++++++- .../include/bgp/afi-export-import.xml.i | 13 +++++++++++ smoketest/scripts/cli/test_protocols_bgp.py | 25 ++++++++++++++++++---- src/conf_mode/protocols_bgp.py | 11 ++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index a21a2fefe..2f2e94ce0 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -311,8 +311,15 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% if afi_config.export is defined and afi_config.export.vpn is defined %} export vpn {% endif %} -{% if afi_config.import is defined and afi_config.import.vpn is defined %} +{% if afi_config.import is defined and afi_config.import is not none %} +{% if afi_config.import.vpn is defined %} import vpn +{% endif %} +{% if afi_config.import.vrf is defined and afi_config.import.vrf is not none %} +{% for vrf in afi_config.import.vrf %} + import vrf {{ vrf }} +{% endfor %} +{% endif %} {% endif %} {% if afi_config.local_install is defined and afi_config.local_install is not none %} {% for interface in afi_config.local_install.interface %} diff --git a/interface-definitions/include/bgp/afi-export-import.xml.i b/interface-definitions/include/bgp/afi-export-import.xml.i index ad54c723e..86817cdb3 100644 --- a/interface-definitions/include/bgp/afi-export-import.xml.i +++ b/interface-definitions/include/bgp/afi-export-import.xml.i @@ -23,6 +23,19 @@ + + + VRF to import from + + txt + VRF instance name + + + vrf name + + + + diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 22e892e26..7a470abf9 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -628,6 +628,9 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): # templates and Jinja2 FRR template. table = '1000' + self.cli_set(base_path + ['local-as', ASN]) + # testing only one AFI is sufficient as it's generic code + for vrf in vrfs: vrf_base = ['vrf', 'name', vrf] self.cli_set(vrf_base + ['table', table]) @@ -636,15 +639,26 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(vrf_base + ['protocols', 'bgp', 'route-map', route_map_in]) table = str(int(table) + 1000) + # import VRF routes do main RIB + self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'import', 'vrf', vrf]) + self.cli_commit() + # Verify FRR bgpd configuration + frrconfig = self.getFRRconfig(f'router bgp {ASN}') + self.assertIn(f'router bgp {ASN}', frrconfig) + self.assertIn(f' address-family ipv6 unicast', frrconfig) + + for vrf in vrfs: + self.assertIn(f' import vrf {vrf}', frrconfig) + # Verify FRR bgpd configuration - frrconfig = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}') - self.assertIn(f'router bgp {ASN} vrf {vrf}', frrconfig) - self.assertIn(f' bgp router-id {router_id}', frrconfig) + frr_vrf_config = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}') + self.assertIn(f'router bgp {ASN} vrf {vrf}', frr_vrf_config) + self.assertIn(f' bgp router-id {router_id}', frr_vrf_config) - # CCC: Currently this is not working as FRR() class does not support + # XXX: Currently this is not working as FRR() class does not support # route-maps for multiple vrfs because the modify_section() only works # on lines and not text blocks. # @@ -694,6 +708,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' neighbor {interface} activate', frrconfig) self.assertIn(f' exit-address-family', frrconfig) + def test_bgp_13_solo(self): remote_asn = str(int(ASN) + 150) neighbor = '192.0.2.55' @@ -710,9 +725,11 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f'router bgp {ASN}', frrconfig) self.assertIn(f' neighbor {neighbor} solo', frrconfig) + def test_bgp_14_vpn(self): remote_asn = str(int(ASN) + 150) neighbor = '192.0.2.55' + vrf_name = 'red' self.cli_set(base_path + ['local-as', ASN]) # testing only one AFI is sufficient as it's generic code diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index fb128db7b..7fc4a2247 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -23,6 +23,7 @@ from vyos.config import Config from vyos.configdict import dict_merge from vyos.configverify import verify_prefix_list from vyos.configverify import verify_route_map +from vyos.configverify import verify_vrf from vyos.template import is_ip from vyos.template import is_interface from vyos.template import render_to_string @@ -238,6 +239,16 @@ def verify(bgp): raise ConfigError('Missing mandatory configuration option for '\ f'{afi} administrative distance {key}!') + if afi in ['ipv4_unicast', 'ipv6_unicast']: + if 'import' in afi_config and 'vrf' in afi_config['import']: + # Check if VRF exists + verify_vrf(afi_config['import']['vrf']) + + # FRR error: please unconfigure vpn to vrf commands before + # using import vrf commands + if 'vpn' in afi_config['import'] or dict_search('export.vpn', afi_config) != None: + raise ConfigError('Please unconfigure VPN to VRF commands before '\ + 'using "import vrf" commands!') return None def generate(bgp): -- cgit v1.2.3 From 73c0e87109855f9b3372540b4ace03c6fb517c2a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 18 Aug 2021 11:12:08 +0200 Subject: bgp: T3759: add l3vpn "label vpn export" commands Add the following new commands: * set protocols bgp address-family ipv4-unicast label vpn export (auto | 0-1048575) * set protocols bgp address-family ipv6-unicast label vpn export (auto | 0-1048575) --- data/templates/frr/bgpd.frr.tmpl | 3 ++ interface-definitions/include/bgp/afi-label.xml.i | 36 ++++++++++++++++++++++ .../include/bgp/protocol-common-config.xml.i | 6 ++-- smoketest/scripts/cli/test_protocols_bgp.py | 7 +++-- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 interface-definitions/include/bgp/afi-label.xml.i (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 2f2e94ce0..3ee6a5cb3 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -321,6 +321,9 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% endfor %} {% endif %} {% endif %} +{% if afi_config.label is defined and afi_config.label.vpn is defined and afi_config.label.vpn.export is defined and afi_config.label.vpn.export is not none %} + label vpn export {{ afi_config.label.vpn.export }} +{% endif %} {% if afi_config.local_install is defined and afi_config.local_install is not none %} {% for interface in afi_config.local_install.interface %} local-install {{ interface }} diff --git a/interface-definitions/include/bgp/afi-label.xml.i b/interface-definitions/include/bgp/afi-label.xml.i new file mode 100644 index 000000000..f8cf57a9c --- /dev/null +++ b/interface-definitions/include/bgp/afi-label.xml.i @@ -0,0 +1,36 @@ + + + + Label value for VRF + + + + + Between current address-family and vpn + + + + + For routes leaked from current address-family to VPN + + auto + + + auto + Automatically assign a label + + + u32:0-1048575 + Label Value + + + + ^(auto)$ + + + + + + + + diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 6a4e1de3f..58e3c5798 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -94,6 +94,8 @@ #include + #include + #include BGP network @@ -115,7 +117,6 @@ #include - #include Redistribute routes from other protocols into BGP @@ -480,6 +481,8 @@ #include + #include + #include BGP network @@ -496,7 +499,6 @@ #include - #include Redistribute routes from other protocols into BGP diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 7a470abf9..d3d061229 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -730,11 +730,14 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): remote_asn = str(int(ASN) + 150) neighbor = '192.0.2.55' vrf_name = 'red' + label = 'auto' self.cli_set(base_path + ['local-as', ASN]) # testing only one AFI is sufficient as it's generic code - self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'export', 'vpn']) - self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'import', 'vpn']) + for afi in ['ipv4-unicast', 'ipv6-unicast']: + self.cli_set(base_path + ['address-family', afi, 'export', 'vpn']) + self.cli_set(base_path + ['address-family', afi, 'import', 'vpn']) + self.cli_set(base_path + ['address-family', afi, 'label', 'vpn', 'export', label]) # commit changes self.cli_commit() -- cgit v1.2.3 From 231095f95df129ef9e051ec218a1c3fe9e99cd98 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 18 Aug 2021 12:44:15 +0200 Subject: bgp: T2387: fix indention when writing address-family config --- data/templates/frr/bgpd.frr.tmpl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 3ee6a5cb3..60ec566b5 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -294,17 +294,17 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% if afi_config.advertise is defined and afi_config.advertise is not none %} {% for adv_afi, adv_afi_config in afi_config.advertise.items() %} {% if adv_afi_config.unicast is defined and adv_afi_config.unicast is not none %} - advertise {{ adv_afi }} unicast {{ 'route-map ' ~ adv_afi_config.unicast.route_map if adv_afi_config.unicast.route_map is defined }} + advertise {{ adv_afi }} unicast {{ 'route-map ' ~ adv_afi_config.unicast.route_map if adv_afi_config.unicast.route_map is defined }} {% endif %} {% endfor %} {% endif %} {% if afi_config.distance is defined and afi_config.distance is not none %} {% if afi_config.distance is defined and afi_config.distance.external is defined and afi_config.distance.internal is defined and afi_config.distance.local is defined %} - distance bgp {{ afi_config.distance.external }} {{ afi_config.distance.internal }} {{ afi_config.distance.local }} + distance bgp {{ afi_config.distance.external }} {{ afi_config.distance.internal }} {{ afi_config.distance.local }} {% endif %} {% if afi_config.distance.prefix is defined and afi_config.distance.prefix is not none %} {% for prefix in afi_config.distance.prefix %} - distance {{ afi_config.distance.prefix[prefix].distance }} {{ prefix }} + distance {{ afi_config.distance.prefix[prefix].distance }} {{ prefix }} {% endfor %} {% endif %} {% endif %} @@ -326,7 +326,7 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% endif %} {% if afi_config.local_install is defined and afi_config.local_install is not none %} {% for interface in afi_config.local_install.interface %} - local-install {{ interface }} + local-install {{ interface }} {% endfor %} {% endif %} {% if afi_config.advertise_all_vni is defined %} @@ -342,13 +342,13 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none advertise-svi-ip {% endif %} {% if afi_config.rt_auto_derive is defined %} - autort rfc8365-compatible + autort rfc8365-compatible {% endif %} {% if afi_config.flooding is defined and afi_config.flooding.disable is defined %} - flooding disable + flooding disable {% endif %} {% if afi_config.flooding is defined and afi_config.flooding.head_end_replication is defined %} - flooding head-end-replication + flooding head-end-replication {% endif %} {% if afi_config.rd is defined and afi_config.rd is not none %} rd {{ afi_config.rd }} -- cgit v1.2.3 From 1cc2ac26106f8efad6defaba9ba4d1296d75cf1f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 18 Aug 2021 12:47:01 +0200 Subject: bgp: T3759: add l3vpn "rd" route-distinguisher commands Add the following new commands: * set protocols bgp address-family ipv4-unicast rd vpn export * set protocols bgp address-family ipv6-unicast rd vpn export --- data/templates/frr/bgpd.frr.tmpl | 7 ++++-- interface-definitions/include/bgp/afi-rd.xml.i | 28 ++++++++++++++++++++++ .../include/bgp/protocol-common-config.xml.i | 2 ++ .../include/bgp/route-distinguisher.xml.i | 2 +- smoketest/scripts/cli/test_protocols_bgp.py | 16 +++++++++---- 5 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 interface-definitions/include/bgp/afi-rd.xml.i (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 60ec566b5..f3579ccd7 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -257,6 +257,9 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none address-family ipv6 flowspec {% elif afi == 'l2vpn_evpn' %} address-family l2vpn evpn +{% if afi_config.rd is defined and afi_config.rd is not none %} + rd {{ afi_config.rd }} +{% endif %} {% endif %} {% if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %} {% for ip in afi_config.aggregate_address %} @@ -350,8 +353,8 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% if afi_config.flooding is defined and afi_config.flooding.head_end_replication is defined %} flooding head-end-replication {% endif %} -{% if afi_config.rd is defined and afi_config.rd is not none %} - rd {{ afi_config.rd }} +{% if afi_config.rd is defined and afi_config.rd.vpn is defined and afi_config.rd.vpn.export is defined %} + rd vpn export {{ afi_config.rd.vpn.export }} {% endif %} {% if afi_config.route_target is defined and afi_config.route_target is not none %} {% if afi_config.route_target.both is defined and afi_config.route_target.both is not none %} diff --git a/interface-definitions/include/bgp/afi-rd.xml.i b/interface-definitions/include/bgp/afi-rd.xml.i new file mode 100644 index 000000000..c4d29268c --- /dev/null +++ b/interface-definitions/include/bgp/afi-rd.xml.i @@ -0,0 +1,28 @@ + + + + Specify route distinguisher + + + + + Between current address-family and VPN + + + + + For routes leaked from current address-family to VPN + + ASN:NN_OR_IP-ADDRESS:NN + Route Distinguisher, (x.x.x.x:yyy|xxxx:yyyy) + + + ^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$ + + + + + + + + diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 58e3c5798..53be8b553 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -117,6 +117,7 @@ #include + #include Redistribute routes from other protocols into BGP @@ -499,6 +500,7 @@ #include + #include Redistribute routes from other protocols into BGP diff --git a/interface-definitions/include/bgp/route-distinguisher.xml.i b/interface-definitions/include/bgp/route-distinguisher.xml.i index fdfbe7076..6d0aa3ef1 100644 --- a/interface-definitions/include/bgp/route-distinguisher.xml.i +++ b/interface-definitions/include/bgp/route-distinguisher.xml.i @@ -3,7 +3,7 @@ Route Distinguisher - txt + ASN:NN_OR_IP-ADDRESS:NN Route Distinguisher, (x.x.x.x:yyy|xxxx:yyyy) diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index d3d061229..4149b0bdd 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -731,6 +731,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): neighbor = '192.0.2.55' vrf_name = 'red' label = 'auto' + rd = f'{neighbor}:{ASN}' self.cli_set(base_path + ['local-as', ASN]) # testing only one AFI is sufficient as it's generic code @@ -739,16 +740,23 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['address-family', afi, 'import', 'vpn']) self.cli_set(base_path + ['address-family', afi, 'label', 'vpn', 'export', label]) + self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'rd', 'vpn', 'export', rd]) + # commit changes self.cli_commit() # Verify FRR bgpd configuration frrconfig = self.getFRRconfig(f'router bgp {ASN}') self.assertIn(f'router bgp {ASN}', frrconfig) - self.assertIn(f' address-family ipv6 unicast', frrconfig) - self.assertIn(f' export vpn', frrconfig) - self.assertIn(f' import vpn', frrconfig) - self.assertIn(f' exit-address-family', frrconfig) + for afi in ['ipv4', 'ipv6']: + self.assertIn(f' address-family {afi} unicast', frrconfig) + self.assertIn(f' export vpn', frrconfig) + self.assertIn(f' import vpn', frrconfig) + self.assertIn(f' label vpn export {label}', frrconfig) + self.assertIn(f' exit-address-family', frrconfig) + + self.assertIn(f' address-family ipv4 unicast', frrconfig) + self.assertIn(f' rd vpn export {rd}', frrconfig) if __name__ == '__main__': unittest.main(verbosity=2) \ No newline at end of file -- cgit v1.2.3 From ef3f17d7e7fb34c5309e3b3e80c398f6b95cebb1 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 18 Aug 2021 12:47:31 +0200 Subject: bgp: T3759: fix indention when writing address-family config --- data/templates/frr/bgpd.frr.tmpl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index f3579ccd7..51235e4cb 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -312,20 +312,20 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% endif %} {% endif %} {% if afi_config.export is defined and afi_config.export.vpn is defined %} - export vpn + export vpn {% endif %} {% if afi_config.import is defined and afi_config.import is not none %} {% if afi_config.import.vpn is defined %} - import vpn + import vpn {% endif %} {% if afi_config.import.vrf is defined and afi_config.import.vrf is not none %} {% for vrf in afi_config.import.vrf %} - import vrf {{ vrf }} + import vrf {{ vrf }} {% endfor %} {% endif %} {% endif %} {% if afi_config.label is defined and afi_config.label.vpn is defined and afi_config.label.vpn.export is defined and afi_config.label.vpn.export is not none %} - label vpn export {{ afi_config.label.vpn.export }} + label vpn export {{ afi_config.label.vpn.export }} {% endif %} {% if afi_config.local_install is defined and afi_config.local_install is not none %} {% for interface in afi_config.local_install.interface %} -- cgit v1.2.3 From cbf1998ae9529be43c2605a5b771363aa496ff40 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 18 Aug 2021 12:54:26 +0200 Subject: bgp: T3759: add l3vpn "route-target vpn" commands Add the following new commands: * set protocols bgp address-family ipv4-unicast route-target vpn both 1.1.1.1:100 * set protocols bgp address-family ipv4-unicast route-target vpn export 1.1.1.1:100 * set protocols bgp address-family ipv4-unicast route-target vpn import 1.1.1.1:100 --- data/templates/frr/bgpd.frr.tmpl | 21 +++++++++++++++++---- .../include/bgp/protocol-common-config.xml.i | 17 +++++++++++++++++ smoketest/scripts/cli/test_protocols_bgp.py | 6 ++++++ 3 files changed, 40 insertions(+), 4 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 51235e4cb..7adb007c8 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -357,14 +357,27 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none rd vpn export {{ afi_config.rd.vpn.export }} {% endif %} {% if afi_config.route_target is defined and afi_config.route_target is not none %} +{% if afi_config.route_target.vpn is defined and afi_config.route_target.vpn is not none %} +{% if afi_config.route_target.vpn.both is defined and afi_config.route_target.vpn.both is not none %} + route-target vpn both {{ afi_config.route_target.vpn.both }} +{% else %} +{% if afi_config.route_target.vpn.export is defined and afi_config.route_target.vpn.export is not none %} + route-target vpn export {{ afi_config.route_target.vpn.export }} +{% endif %} +{% if afi_config.route_target.vpn.import is defined and afi_config.route_target.vpn.import is not none %} + route-target vpn import {{ afi_config.route_target.vpn.import }} +{% endif %} +{% endif %} +{% endif %} {% if afi_config.route_target.both is defined and afi_config.route_target.both is not none %} route-target both {{ afi_config.route_target.both }} -{% endif %} -{% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} +{% else %} +{% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} route-target export {{ afi_config.route_target.export }} -{% endif %} -{% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} +{% endif %} +{% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} route-target import {{ afi_config.route_target.import }} +{% endif %} {% endif %} {% endif %} {% if afi_config.vni is defined and afi_config.vni is not none %} diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 53be8b553..6fb9adf93 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -118,6 +118,23 @@ #include + + + Specify route distinguisher + + + + + Between current address-family and VPN + + + #include + #include + #include + + + + Redistribute routes from other protocols into BGP diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 4149b0bdd..d1492e831 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -732,6 +732,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): vrf_name = 'red' label = 'auto' rd = f'{neighbor}:{ASN}' + rt_export = f'{neighbor}:1002' + rt_import = f'{neighbor}:1003' self.cli_set(base_path + ['local-as', ASN]) # testing only one AFI is sufficient as it's generic code @@ -741,6 +743,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['address-family', afi, 'label', 'vpn', 'export', label]) self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'rd', 'vpn', 'export', rd]) + self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'route-target', 'vpn', 'export', rt_export]) + self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'route-target', 'vpn', 'import', rt_import]) # commit changes self.cli_commit() @@ -757,6 +761,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' address-family ipv4 unicast', frrconfig) self.assertIn(f' rd vpn export {rd}', frrconfig) + self.assertIn(f' rt vpn export {rt_export}', frrconfig) + self.assertIn(f' rt vpn import {rt_import}', frrconfig) if __name__ == '__main__': unittest.main(verbosity=2) \ No newline at end of file -- cgit v1.2.3 From 522402ecb797222e69f6017a84d1b65cfdc5c70e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 18 Aug 2021 13:58:04 +0200 Subject: bgp: evpn: T1513: fix indention when writing address-family config --- data/templates/frr/bgpd.frr.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 7adb007c8..143960e6b 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -370,13 +370,13 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% endif %} {% endif %} {% if afi_config.route_target.both is defined and afi_config.route_target.both is not none %} - route-target both {{ afi_config.route_target.both }} + route-target both {{ afi_config.route_target.both }} {% else %} {% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} - route-target export {{ afi_config.route_target.export }} + route-target export {{ afi_config.route_target.export }} {% endif %} {% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} - route-target import {{ afi_config.route_target.import }} + route-target import {{ afi_config.route_target.import }} {% endif %} {% endif %} {% endif %} -- cgit v1.2.3 From f7e3f5562458da4d80b272f1524c27727799e57b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 20 Aug 2021 18:17:54 +0200 Subject: bgp: T3759: add IPv4/IPv6 unicast AFI route-map for VPN import/export This adds the following new commands: set protocols bgp address-family ipv4-unicast route-map vpn export foo-map-out set protocols bgp address-family ipv4-unicast route-map vpn import foo-map-in set protocols bgp address-family ipv6-unicast route-map vpn export foo-map-out set protocols bgp address-family ipv6-unicast route-map vpn import foo-map-in --- data/templates/frr/bgpd.frr.tmpl | 8 ++++++++ .../include/bgp/afi-route-map-vpn.xml.i | 17 +++++++++++++++++ .../include/bgp/protocol-common-config.xml.i | 2 ++ smoketest/scripts/cli/test_protocols_bgp.py | 2 ++ src/conf_mode/protocols_bgp.py | 5 +++++ 5 files changed, 34 insertions(+) create mode 100644 interface-definitions/include/bgp/afi-route-map-vpn.xml.i (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 143960e6b..96815836b 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -380,6 +380,14 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% endif %} {% endif %} {% endif %} +{% if afi_config.route_map is defined and afi_config.route_map.vpn is defined and afi_config.route_map.vpn is not none %} +{% if afi_config.route_map.vpn.export is defined and afi_config.route_map.vpn.export is not none %} + route-map vpn export {{ afi_config.route_map.vpn.export }} +{% endif %} +{% if afi_config.route_map.vpn.import is defined and afi_config.route_map.vpn.import is not none %} + route-map vpn import {{ afi_config.route_map.vpn.import }} +{% endif %} +{% endif %} {% if afi_config.vni is defined and afi_config.vni is not none %} {% for vni, vni_config in afi_config.vni.items() %} vni {{ vni }} diff --git a/interface-definitions/include/bgp/afi-route-map-vpn.xml.i b/interface-definitions/include/bgp/afi-route-map-vpn.xml.i new file mode 100644 index 000000000..e6be113c5 --- /dev/null +++ b/interface-definitions/include/bgp/afi-route-map-vpn.xml.i @@ -0,0 +1,17 @@ + + + + Route-map to filter route updates to/from this peer + + + + + Between current address-family and VPN + + + #include + + + + + diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 6fb9adf93..a971c52b8 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -118,6 +118,7 @@ #include + #include Specify route distinguisher @@ -518,6 +519,7 @@ #include + #include Redistribute routes from other protocols into BGP diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index dbe1a81d6..f535408db 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -751,6 +751,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' import vpn', afi_config) self.assertIn(f' label vpn export {label}', afi_config) self.assertIn(f' rd vpn export {rd}', afi_config) + self.assertIn(f' route-map vpn export {route_map_out}', afi_config) + self.assertIn(f' route-map vpn import {route_map_in}', afi_config) self.assertIn(f' exit-address-family', afi_config) afi_config = self.getFRRconfig(f' address-family ipv4 unicast', endsection='exit-address-family', daemon='bgpd') diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index bc7acaf6c..7d05eed9f 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -250,6 +250,11 @@ def verify(bgp): raise ConfigError('Please unconfigure VPN to VRF commands before '\ 'using "import vrf" commands!') + # Verify that the export/import route-maps do exist + for export_import in ['export', 'import']: + tmp = dict_search(f'route_map.vpn.{export_import}', afi_config) + if tmp: verify_route_map(tmp, bgp) + if afi in ['l2vpn_evpn'] and 'vrf' not in bgp: # Some L2VPN EVPN AFI options are only supported under VRF if 'vni' in afi_config: -- cgit v1.2.3 From 5141a8ca3a69108d20c8c82d1fa737f0e17ac974 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 20 Aug 2021 16:19:50 +0200 Subject: route: static: T2450: add next-hop interface on dhcp routes --- data/templates/frr/static_routes_macro.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/static_routes_macro.j2 b/data/templates/frr/static_routes_macro.j2 index f10b58047..3b432b49b 100644 --- a/data/templates/frr/static_routes_macro.j2 +++ b/data/templates/frr/static_routes_macro.j2 @@ -5,7 +5,7 @@ {% if prefix_config.dhcp_interface is defined and prefix_config.dhcp_interface is not none %} {% set next_hop = prefix_config.dhcp_interface | get_dhcp_router %} {% if next_hop is defined and next_hop is not none %} -{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} +{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ prefix_config.dhcp_interface }} {% endif %} {% endif %} {% if prefix_config.interface is defined and prefix_config.interface is not none %} -- cgit v1.2.3 From 91a4d57d429719cbb35fe38f31e1889645a5579a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 29 Aug 2021 10:55:46 +0200 Subject: isis: T3783: bugfix configuring spf-delay-ietf Mandatory FRR options for spf-delay-ietf did not get rendered in the Jinja2 template. --- data/templates/frr/isisd.frr.tmpl | 2 +- smoketest/scripts/cli/test_protocols_isis.py | 53 ++++++++++++++++++++++++++++ src/conf_mode/containers.py | 16 +++++++++ src/conf_mode/protocols_isis.py | 2 +- 4 files changed, 71 insertions(+), 2 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/isisd.frr.tmpl b/data/templates/frr/isisd.frr.tmpl index 6cfa076d0..51ac40060 100644 --- a/data/templates/frr/isisd.frr.tmpl +++ b/data/templates/frr/isisd.frr.tmpl @@ -100,7 +100,7 @@ router isis VyOS {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% endif %} {% endif %} {% if spf_delay_ietf is defined and spf_delay_ietf.init_delay is defined and spf_delay_ietf.init_delay is not none %} - spf-delay-ietf init-delay {{ spf_delay_ietf.init_delay }} + spf-delay-ietf init-delay {{ spf_delay_ietf.init_delay }} short-delay {{ spf_delay_ietf.short_delay }} long-delay {{ spf_delay_ietf.long_delay }} holddown {{ spf_delay_ietf.holddown }} time-to-learn {{ spf_delay_ietf.time_to_learn }} {% endif %} {% if area_password is defined and area_password is not none %} {% if area_password.md5 is defined and area_password.md5 is not none %} diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py index 9b6d4a4ec..8170f2b56 100755 --- a/smoketest/scripts/cli/test_protocols_isis.py +++ b/smoketest/scripts/cli/test_protocols_isis.py @@ -199,5 +199,58 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): self.assertIn(f' area-password clear {password}', tmp) + def test_isis_06_spf_delay(self): + self.isis_base_config() + + network = 'point-to-point' + holddown = '10' + init_delay = '50' + long_delay = '200' + short_delay = '100' + time_to_learn = '75' + + for interface in self._interfaces: + self.cli_set(base_path + ['interface', interface, 'network', network]) + + self.cli_set(base_path + ['spf-delay-ietf', 'holddown', holddown]) + # verify() - All types of spf-delay must be configured + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set(base_path + ['spf-delay-ietf', 'init-delay', init_delay]) + # verify() - All types of spf-delay must be configured + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set(base_path + ['spf-delay-ietf', 'long-delay', long_delay]) + # verify() - All types of spf-delay must be configured + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set(base_path + ['spf-delay-ietf', 'long-delay', long_delay]) + # verify() - All types of spf-delay must be configured + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set(base_path + ['spf-delay-ietf', 'short-delay', short_delay]) + # verify() - All types of spf-delay must be configured + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_set(base_path + ['spf-delay-ietf', 'time-to-learn', time_to_learn]) + + # Commit all changes + self.cli_commit() + + # Verify all changes + tmp = self.getFRRconfig(f'router isis {domain}') + self.assertIn(f' net {net}', tmp) + self.assertIn(f' spf-delay-ietf init-delay {init_delay} short-delay {short_delay} long-delay {long_delay} holddown {holddown} time-to-learn {time_to_learn}', tmp) + + for interface in self._interfaces: + tmp = self.getFRRconfig(f'interface {interface}') + self.assertIn(f' ip router isis {domain}', tmp) + self.assertIn(f' ipv6 router isis {domain}', tmp) + self.assertIn(f' isis network {network}', tmp) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/containers.py b/src/conf_mode/containers.py index 32320a4b2..3a93bf062 100755 --- a/src/conf_mode/containers.py +++ b/src/conf_mode/containers.py @@ -19,6 +19,7 @@ import json from ipaddress import ip_address from ipaddress import ip_network +from time import sleep from vyos.config import Config from vyos.configdict import dict_merge @@ -28,6 +29,9 @@ from vyos.util import cmd from vyos.util import run from vyos.util import read_file from vyos.util import write_file +from vyos.util import is_systemd_service_active +from vyos.util import is_systemd_service_running + from vyos.template import render from vyos.template import is_ipv4 from vyos.template import is_ipv6 @@ -199,6 +203,18 @@ def apply(container): for network in container['network_remove']: call(f'podman network rm --force {network}') + service_name = 'podman.service' + if 'network' in container or 'name' in container: + # Start podman if it's required and not yet running + if not is_systemd_service_active(service_name): + _cmd(f'systemctl start {service_name}') + # Wait for podman to be running + while not is_systemd_service_running(service_name): + sleep(0.250) + else: + _cmd(f'systemctl stop {service_name}') + + # Add network if 'network' in container: for network, network_config in container['network'].items(): diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py index 4cf0312e9..4505e2496 100755 --- a/src/conf_mode/protocols_isis.py +++ b/src/conf_mode/protocols_isis.py @@ -148,7 +148,7 @@ def verify(isis): exist_timers = set(required_timers).difference(set(exist_timers)) if len(exist_timers) > 0: - raise ConfigError('All types of delay must be specified: ' + ', '.join(exist_timers).replace('_', '-')) + raise ConfigError('All types of spf-delay must be configured. Missing: ' + ', '.join(exist_timers).replace('_', '-')) # If Redistribute set, but level don't set if 'redistribute' in isis: -- cgit v1.2.3 From 40bfaed4d1d427c33157136026944df80e02a5b6 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 29 Aug 2021 12:08:22 +0200 Subject: ospf: T3236: add possibility to redistribute "table" Add new CLI command: * "set protocols ospf redistribute table " --- data/templates/frr/ospfd.frr.tmpl | 10 ++++++++-- interface-definitions/include/ospf/metric-type.xml.i | 2 +- .../include/ospf/protocol-common-config.xml.i | 17 +++++++++++++++++ src/conf_mode/protocols_ospf.py | 14 +++++++++++++- 4 files changed, 39 insertions(+), 4 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/ospfd.frr.tmpl b/data/templates/frr/ospfd.frr.tmpl index be39519c3..90a6bbd56 100644 --- a/data/templates/frr/ospfd.frr.tmpl +++ b/data/templates/frr/ospfd.frr.tmpl @@ -172,8 +172,14 @@ router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% endfor %} {% endif %} {% if redistribute is defined and redistribute is not none %} -{% for protocol, options in redistribute.items() %} - redistribute {{ protocol }} {{ 'metric ' + options.metric if options.metric is defined }} {{ 'metric-type ' + options.metric_type if options.metric_type is defined }} {{ 'route-map ' + options.route_map if options.route_map is defined }} +{% for protocol, protocols_options in redistribute.items() %} +{% if protocol == 'table' %} +{% for table, table_options in protocols_options.items() %} + redistribute {{ protocol }} {{ table }} {{ 'metric ' + table_options.metric if table_options.metric is defined }} {{ 'metric-type ' + table_options.metric_type if table_options.metric_type is defined }} {{ 'route-map ' + table_options.route_map if table_options.route_map is defined }} +{% endfor %} +{% else %} + redistribute {{ protocol }} {{ 'metric ' + protocols_options.metric if protocols_options.metric is defined }} {{ 'metric-type ' + protocols_options.metric_type if protocols_options.metric_type is defined }} {{ 'route-map ' + protocols_options.route_map if protocols_options.route_map is defined }} +{% endif %} {% endfor %} {% endif %} {% if refresh is defined and refresh.timers is defined and refresh.timers is not none %} diff --git a/interface-definitions/include/ospf/metric-type.xml.i b/interface-definitions/include/ospf/metric-type.xml.i index 83dc24909..ef9fd8ac0 100644 --- a/interface-definitions/include/ospf/metric-type.xml.i +++ b/interface-definitions/include/ospf/metric-type.xml.i @@ -4,7 +4,7 @@ OSPF metric type for default routes (default: 2) u32:1-2 - Metric type for default routes + Set OSPF External Type 1/2 metrics diff --git a/interface-definitions/include/ospf/protocol-common-config.xml.i b/interface-definitions/include/ospf/protocol-common-config.xml.i index 546516a80..d8556ebf5 100644 --- a/interface-definitions/include/ospf/protocol-common-config.xml.i +++ b/interface-definitions/include/ospf/protocol-common-config.xml.i @@ -693,6 +693,23 @@ #include + + + Redistribute non-main Kernel Routing Table + + protocols static table + + + u32:1-200 + Policy route table number + + + + #include + #include + #include + + diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 06a29106d..92532fcb5 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -87,7 +87,13 @@ def get_config(config=None): del default_values['area']['area_type']['nssa'] if 'mpls_te' not in ospf: del default_values['mpls_te'] - for protocol in ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static']: + + for protocol in ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static', 'table']: + # table is a tagNode thus we need to clean out all occurances for the + # default values and load them in later individually + if protocol == 'table': + del default_values['redistribute']['table'] + continue if dict_search(f'redistribute.{protocol}', ospf) is None: del default_values['redistribute'][protocol] @@ -127,6 +133,12 @@ def get_config(config=None): ospf['interface'][interface] = dict_merge(default_values, ospf['interface'][interface]) + if 'redistribute' in ospf and 'table' in ospf['redistribute']: + default_values = defaults(base + ['redistribute', 'table']) + for table in ospf['redistribute']['table']: + ospf['redistribute']['table'][table] = dict_merge(default_values, + ospf['redistribute']['table'][table]) + # We also need some additional information from the config, prefix-lists # and route-maps for instance. They will be used in verify(). # -- cgit v1.2.3 From 5f1c1ae4770fe36b5290f34d2f3a248c6b1a0ddb Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 3 Sep 2021 20:44:42 +0200 Subject: bgp: T3798: add support for neighbor local-as replace-as --- data/templates/frr/bgpd.frr.tmpl | 5 +++-- interface-definitions/include/bgp/neighbor-local-as.xml.i | 12 +++++++++--- smoketest/scripts/cli/test_protocols_bgp.py | 8 +++++--- src/conf_mode/protocols_bgp.py | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 96815836b..4ac2127cb 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -46,8 +46,9 @@ neighbor {{ neighbor }} {{ graceful_restart }} {% endif %} {% if config.local_as is defined and config.local_as is not none %} -{% for local_asn in config.local_as %} - neighbor {{ neighbor }} local-as {{ local_asn }} {{ 'no-prepend' if config.local_as[local_asn].no_prepend is defined }} +{% for local_asn, local_asn_config in config.local_as.items() %} +{# There can be only one local-as value, this is checked in the Python code #} + neighbor {{ neighbor }} local-as {{ local_asn }} {{ 'no-prepend' if local_asn_config.no_prepend is defined }} {{ 'replace-as' if local_asn_config.replace_as is defined }} {% endfor %} {% endif %} {% if config.override_capability is defined %} diff --git a/interface-definitions/include/bgp/neighbor-local-as.xml.i b/interface-definitions/include/bgp/neighbor-local-as.xml.i index 28c6b72b6..8cf0167fd 100644 --- a/interface-definitions/include/bgp/neighbor-local-as.xml.i +++ b/interface-definitions/include/bgp/neighbor-local-as.xml.i @@ -1,10 +1,10 @@ - Local AS number [REQUIRED] + Specify alternate ASN for this BGP process u32:1-4294967294 - Local AS number + Autonomous System Number (ASN) @@ -13,7 +13,13 @@ - Disable prepending local-as to updates from EBGP peers + Disable prepending local-as from/to updates for eBGP peers + + + + + + Prepend only local-as from/to updates for eBGP peers diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index df9dc342b..05919abbc 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -165,7 +165,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): if 'multi_hop' in peer_config: self.assertIn(f' neighbor {peer} ebgp-multihop {peer_config["multi_hop"]}', frrconfig) if 'local_as' in peer_config: - self.assertIn(f' neighbor {peer} local-as {peer_config["local_as"]}', frrconfig) + self.assertIn(f' neighbor {peer} local-as {peer_config["local_as"]} no-prepend replace-as', frrconfig) if 'cap_over' in peer_config: self.assertIn(f' neighbor {peer} override-capability', frrconfig) if 'passive' in peer_config: @@ -284,7 +284,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): if 'multi_hop' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'ebgp-multihop', peer_config["multi_hop"]]) if 'local_as' in peer_config: - self.cli_set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"]]) + self.cli_set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"], 'no-prepend']) + self.cli_set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"], 'replace-as']) if 'cap_over' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'override-capability']) if 'passive' in peer_config: @@ -353,7 +354,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): if 'multi_hop' in config: self.cli_set(base_path + ['peer-group', peer_group, 'ebgp-multihop', config["multi_hop"]]) if 'local_as' in config: - self.cli_set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"]]) + self.cli_set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"], 'no-prepend']) + self.cli_set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"], 'replace-as']) if 'cap_over' in config: self.cli_set(base_path + ['peer-group', peer_group, 'override-capability']) if 'passive' in config: diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 7d05eed9f..e24fcef14 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -130,7 +130,7 @@ def verify(bgp): if 'local_as' in peer_config: if len(peer_config['local_as']) > 1: - raise ConfigError('Only one local-as number may be specified!') + raise ConfigError(f'Only one local-as number can be specified for peer "{peer}"!') # Neighbor local-as override can not be the same as the local-as # we use for this BGP instane! -- cgit v1.2.3 From dd210c92beeffae07f26dc72ab51d9a93219b582 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 4 Sep 2021 10:18:19 +0200 Subject: bgp: T3798: "replace-as" option can only be used when "no-prepend" is defined Commit 5f1c1ae4 ("bgp: T3798: add support for neighbor local-as replace-as") added support for a new CLI option when the local-as is changed for a specified neighbor or peer-group. There was an error in the CLI / design as the "replace-as" option can only be used when "no-prepend" is defined. Thus "no-prepend" became a and the new "replace-as" leafNode is now a child of "no-prepend". --- data/templates/frr/bgpd.frr.tmpl | 4 ++-- .../include/bgp/neighbor-local-as.xml.i | 19 ++++++++++--------- smoketest/scripts/cli/test_protocols_bgp.py | 6 ++---- src/conf_mode/protocols_bgp.py | 4 ++-- 4 files changed, 16 insertions(+), 17 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 4ac2127cb..987b922da 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -46,9 +46,9 @@ neighbor {{ neighbor }} {{ graceful_restart }} {% endif %} {% if config.local_as is defined and config.local_as is not none %} -{% for local_asn, local_asn_config in config.local_as.items() %} +{% for local_as, local_as_config in config.local_as.items() %} {# There can be only one local-as value, this is checked in the Python code #} - neighbor {{ neighbor }} local-as {{ local_asn }} {{ 'no-prepend' if local_asn_config.no_prepend is defined }} {{ 'replace-as' if local_asn_config.replace_as is defined }} + neighbor {{ neighbor }} local-as {{ local_as }} {{ 'no-prepend' if local_as_config.no_prepend is defined }} {{ 'replace-as' if local_as_config.no_prepend is defined and local_as_config.no_prepend.replace_as is defined }} {% endfor %} {% endif %} {% if config.override_capability is defined %} diff --git a/interface-definitions/include/bgp/neighbor-local-as.xml.i b/interface-definitions/include/bgp/neighbor-local-as.xml.i index 8cf0167fd..8868e3093 100644 --- a/interface-definitions/include/bgp/neighbor-local-as.xml.i +++ b/interface-definitions/include/bgp/neighbor-local-as.xml.i @@ -11,18 +11,19 @@ - + Disable prepending local-as from/to updates for eBGP peers - - - - - Prepend only local-as from/to updates for eBGP peers - - - + + + + Prepend only local-as from/to updates for eBGP peers + + + + + diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 05919abbc..29b5aa9d1 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -284,8 +284,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): if 'multi_hop' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'ebgp-multihop', peer_config["multi_hop"]]) if 'local_as' in peer_config: - self.cli_set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"], 'no-prepend']) - self.cli_set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"], 'replace-as']) + self.cli_set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"], 'no-prepend', 'replace-as']) if 'cap_over' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'override-capability']) if 'passive' in peer_config: @@ -354,8 +353,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): if 'multi_hop' in config: self.cli_set(base_path + ['peer-group', peer_group, 'ebgp-multihop', config["multi_hop"]]) if 'local_as' in config: - self.cli_set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"], 'no-prepend']) - self.cli_set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"], 'replace-as']) + self.cli_set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"], 'no-prepend', 'replace-as']) if 'cap_over' in config: self.cli_set(base_path + ['peer-group', peer_group, 'override-capability']) if 'passive' in config: diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index e24fcef14..68284e0f9 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -140,7 +140,7 @@ def verify(bgp): # ttl-security and ebgp-multihop can't be used in the same configration if 'ebgp_multihop' in peer_config and 'ttl_security' in peer_config: - raise ConfigError('You can\'t set both ebgp-multihop and ttl-security hops') + raise ConfigError('You can not set both ebgp-multihop and ttl-security hops') # Check if neighbor has both override capability and strict capability match configured at the same time. if 'override_capability' in peer_config and 'strict_capability_match' in peer_config: @@ -148,7 +148,7 @@ def verify(bgp): # Check spaces in the password if 'password' in peer_config and ' ' in peer_config['password']: - raise ConfigError('You can\'t use spaces in the password') + raise ConfigError('Whitespace is not allowed in passwords!') # Some checks can/must only be done on a neighbor and not a peer-group if neighbor == 'neighbor': -- cgit v1.2.3 From 993daec9296589f122737e0c210f31879fcb1dab Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 25 Sep 2021 16:56:39 +0200 Subject: bgp: T3657: add "neighbor fe80::202 interface source-interface 'eth1'" command --- data/templates/frr/bgpd.frr.tmpl | 3 +++ interface-definitions/include/bgp/protocol-common-config.xml.i | 1 + 2 files changed, 4 insertions(+) (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 987b922da..27a2b98a5 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -90,6 +90,9 @@ {% if config.interface.peer_group is defined and config.interface.peer_group is not none %} neighbor {{ neighbor }} interface peer-group {{ config.interface.peer_group }} {% endif %} +{% if config.interface.source_interface is defined and config.interface.source_interface is not none %} + neighbor {{ neighbor }} interface {{ config.interface.source_interface }} +{% endif %} {% if config.interface.v6only is defined and config.interface.v6only is not none %} {% if config.interface.v6only.peer_group is defined and config.interface.v6only.peer_group is not none %} neighbor {{ neighbor }} interface v6only peer-group {{ config.interface.v6only.peer_group }} diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 40b9a56de..30033bc50 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -974,6 +974,7 @@ #include #include + #include Enable BGP with v6 link-local only -- cgit v1.2.3 From 289a495c8f45322d58bd849aa8aca48cf0210b03 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Sep 2021 11:08:57 +0200 Subject: ospfv3: T3859: add "log-adjacency-changes" CLI command --- data/templates/frr/ospf6d.frr.tmpl | 3 +++ .../include/ospf/log-adjacency-changes.xml.i | 15 +++++++++++++++ .../include/ospf/protocol-common-config.xml.i | 14 +------------- interface-definitions/protocols-ospfv3.xml.in | 1 + 4 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 interface-definitions/include/ospf/log-adjacency-changes.xml.i (limited to 'data/templates/frr') diff --git a/data/templates/frr/ospf6d.frr.tmpl b/data/templates/frr/ospf6d.frr.tmpl index 0026c0d2c..a8c53738f 100644 --- a/data/templates/frr/ospf6d.frr.tmpl +++ b/data/templates/frr/ospf6d.frr.tmpl @@ -76,6 +76,9 @@ router ospf6 distance ospf6 {{ 'intra-area ' + distance.ospfv3.intra_area if distance.ospfv3.intra_area is defined }} {{ 'inter-area ' + distance.ospfv3.inter_area if distance.ospfv3.inter_area is defined }} {{ 'external ' + distance.ospfv3.external if distance.ospfv3.external is defined }} {% endif %} {% endif %} +{% if log_adjacency_changes is defined %} + log-adjacency-changes {{ "detail" if log_adjacency_changes.detail is defined }} +{% endif %} {% if parameters is defined and parameters is not none %} {% if parameters.router_id is defined and parameters.router_id is not none %} ospf6 router-id {{ parameters.router_id }} diff --git a/interface-definitions/include/ospf/log-adjacency-changes.xml.i b/interface-definitions/include/ospf/log-adjacency-changes.xml.i new file mode 100644 index 000000000..24c6cbe7a --- /dev/null +++ b/interface-definitions/include/ospf/log-adjacency-changes.xml.i @@ -0,0 +1,15 @@ + + + + Log adjacency state changes + + + + + Log all state changes + + + + + + diff --git a/interface-definitions/include/ospf/protocol-common-config.xml.i b/interface-definitions/include/ospf/protocol-common-config.xml.i index 0139296ec..80931ac15 100644 --- a/interface-definitions/include/ospf/protocol-common-config.xml.i +++ b/interface-definitions/include/ospf/protocol-common-config.xml.i @@ -435,19 +435,7 @@ - - - Log adjacency state changes - - - - - Log all state changes - - - - - +#include OSPF maximum and infinite-distance metric diff --git a/interface-definitions/protocols-ospfv3.xml.in b/interface-definitions/protocols-ospfv3.xml.in index 7b42c448d..99cfec661 100644 --- a/interface-definitions/protocols-ospfv3.xml.in +++ b/interface-definitions/protocols-ospfv3.xml.in @@ -186,6 +186,7 @@ #include + #include OSPFv3 specific parameters -- cgit v1.2.3 From f4732f348ff4b0a9d82ec698f4a8b3c6107f9101 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 27 Sep 2021 20:43:02 +0200 Subject: frr: T2175: rename daemon Jinja2 templates to match (d)aemon suffix --- data/templates/frr/bfd.frr.tmpl | 44 ----------------- data/templates/frr/bfdd.frr.tmpl | 44 +++++++++++++++++ data/templates/frr/rip.frr.tmpl | 96 ------------------------------------- data/templates/frr/ripd.frr.tmpl | 96 +++++++++++++++++++++++++++++++++++++ data/templates/frr/ripng.frr.tmpl | 60 ----------------------- data/templates/frr/ripngd.frr.tmpl | 60 +++++++++++++++++++++++ data/templates/frr/static.frr.tmpl | 49 ------------------- data/templates/frr/staticd.frr.tmpl | 49 +++++++++++++++++++ src/conf_mode/protocols_bfd.py | 2 +- src/conf_mode/protocols_rip.py | 2 +- src/conf_mode/protocols_ripng.py | 2 +- src/conf_mode/protocols_static.py | 2 +- 12 files changed, 253 insertions(+), 253 deletions(-) delete mode 100644 data/templates/frr/bfd.frr.tmpl create mode 100644 data/templates/frr/bfdd.frr.tmpl delete mode 100644 data/templates/frr/rip.frr.tmpl create mode 100644 data/templates/frr/ripd.frr.tmpl delete mode 100644 data/templates/frr/ripng.frr.tmpl create mode 100644 data/templates/frr/ripngd.frr.tmpl delete mode 100644 data/templates/frr/static.frr.tmpl create mode 100644 data/templates/frr/staticd.frr.tmpl (limited to 'data/templates/frr') diff --git a/data/templates/frr/bfd.frr.tmpl b/data/templates/frr/bfd.frr.tmpl deleted file mode 100644 index 16f8be92c..000000000 --- a/data/templates/frr/bfd.frr.tmpl +++ /dev/null @@ -1,44 +0,0 @@ -! -bfd -{% if profile is defined and profile is not none %} -{% for profile_name, profile_config in profile.items() %} - profile {{ profile_name }} - detect-multiplier {{ profile_config.interval.multiplier }} - receive-interval {{ profile_config.interval.receive }} - transmit-interval {{ profile_config.interval.transmit }} -{% if profile_config.interval['echo-interval'] is defined and profile_config.interval['echo-interval'] is not none %} - echo-interval {{ profile_config.interval['echo-interval'] }} -{% endif %} -{% if profile_config['echo-mode'] is defined %} - echo-mode -{% endif %} -{% if profile_config.shutdown is defined %} - shutdown -{% else %} - no shutdown -{% endif %} - exit -{% endfor %} -{% endif %} -{% if peer is defined and peer is not none %} -{% for peer_name, peer_config in peer.items() %} - peer {{ peer_name }}{{ ' multihop' if peer_config.multihop is defined }}{{ ' local-address ' + peer_config.source.address if peer_config.source is defined and peer_config.source.address is defined }}{{ ' interface ' + peer_config.source.interface if peer_config.source is defined and peer_config.source.interface is defined }} - detect-multiplier {{ peer_config.interval.multiplier }} - receive-interval {{ peer_config.interval.receive }} - transmit-interval {{ peer_config.interval.transmit }} -{% if peer_config.interval['echo-interval'] is defined and peer_config.interval['echo-interval'] is not none %} - echo-interval {{ peer_config.interval['echo-interval'] }} -{% endif %} -{% if peer_config['echo-mode'] is defined %} - echo-mode -{% endif %} -{% if peer_config.shutdown is defined %} - shutdown -{% else %} - no shutdown -{% endif %} - exit -{% endfor %} -{% endif %} - end -! diff --git a/data/templates/frr/bfdd.frr.tmpl b/data/templates/frr/bfdd.frr.tmpl new file mode 100644 index 000000000..16f8be92c --- /dev/null +++ b/data/templates/frr/bfdd.frr.tmpl @@ -0,0 +1,44 @@ +! +bfd +{% if profile is defined and profile is not none %} +{% for profile_name, profile_config in profile.items() %} + profile {{ profile_name }} + detect-multiplier {{ profile_config.interval.multiplier }} + receive-interval {{ profile_config.interval.receive }} + transmit-interval {{ profile_config.interval.transmit }} +{% if profile_config.interval['echo-interval'] is defined and profile_config.interval['echo-interval'] is not none %} + echo-interval {{ profile_config.interval['echo-interval'] }} +{% endif %} +{% if profile_config['echo-mode'] is defined %} + echo-mode +{% endif %} +{% if profile_config.shutdown is defined %} + shutdown +{% else %} + no shutdown +{% endif %} + exit +{% endfor %} +{% endif %} +{% if peer is defined and peer is not none %} +{% for peer_name, peer_config in peer.items() %} + peer {{ peer_name }}{{ ' multihop' if peer_config.multihop is defined }}{{ ' local-address ' + peer_config.source.address if peer_config.source is defined and peer_config.source.address is defined }}{{ ' interface ' + peer_config.source.interface if peer_config.source is defined and peer_config.source.interface is defined }} + detect-multiplier {{ peer_config.interval.multiplier }} + receive-interval {{ peer_config.interval.receive }} + transmit-interval {{ peer_config.interval.transmit }} +{% if peer_config.interval['echo-interval'] is defined and peer_config.interval['echo-interval'] is not none %} + echo-interval {{ peer_config.interval['echo-interval'] }} +{% endif %} +{% if peer_config['echo-mode'] is defined %} + echo-mode +{% endif %} +{% if peer_config.shutdown is defined %} + shutdown +{% else %} + no shutdown +{% endif %} + exit +{% endfor %} +{% endif %} + end +! diff --git a/data/templates/frr/rip.frr.tmpl b/data/templates/frr/rip.frr.tmpl deleted file mode 100644 index cabc236f0..000000000 --- a/data/templates/frr/rip.frr.tmpl +++ /dev/null @@ -1,96 +0,0 @@ -! -{# RIP key-chain definition #} -{% if interface is defined and interface is not none %} -{% for iface, iface_config in interface.items() %} -{% if iface_config.authentication is defined and iface_config.authentication.md5 is defined and iface_config.authentication.md5 is not none %} -key chain {{ iface }}-rip -{% for key_id, key_options in iface_config.authentication.md5.items() %} - key {{ key_id }} -{% if key_options.password is defined and key_options.password is not none %} - key-string {{ key_options.password }} -{% endif %} -{% endfor %} -{% endif %} -{% endfor %} -{% endif %} -! -{# Interface specific configuration #} -{% if interface is defined and interface is not none %} -{% for iface, iface_config in interface.items() %} -interface {{ iface }} -{% if iface_config.authentication is defined and iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %} - ip rip authentication mode text - ip rip authentication string {{ iface_config.authentication.plaintext_password }} -{% elif iface_config.authentication is defined and iface_config.authentication.md5 is defined and iface_config.authentication.md5 is not none %} - ip rip authentication key-chain {{ iface }}-rip - ip rip authentication mode md5 -{% endif %} -{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %} - no ip rip split-horizon -{% endif %} -{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} - ip rip split-horizon poisoned-reverse -{% endif %} -{% endfor %} -{% endif %} -! -router rip -{% if default_distance is defined and default_distance is not none %} - distance {{ default_distance }} -{% endif %} -{% if network_distance is defined and network_distance is not none %} -{% for network, network_config in network_distance.items() %} -{% if network_config.distance is defined and network_config.distance is not none %} - distance {{ network_config.distance }} {{ network }} -{% endif %} -{% endfor %} -{% endif %} -{% if neighbor is defined and neighbor is not none %} -{% for address in neighbor %} - neighbor {{ address }} -{% endfor %} -{% endif %} -{% if distribute_list is defined and distribute_list is not none %} -{% if distribute_list.access_list is defined and distribute_list.access_list is not none %} -{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} - distribute-list {{ distribute_list.access_list.in }} in -{% endif %} -{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %} - distribute-list {{ distribute_list.access_list.out }} out -{% endif %} -{% endif %} -{% if distribute_list.interface is defined and distribute_list.interface is not none %} -{% for interface, interface_config in distribute_list.interface.items() %} -{% if interface_config.access_list is defined and interface_config.access_list is not none %} -{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %} - distribute-list {{ interface_config.access_list.in }} in {{ interface }} -{% endif %} -{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %} - distribute-list {{ interface_config.access_list.out }} out {{ interface }} -{% endif %} -{% endif %} -{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %} -{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %} - distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }} -{% endif %} -{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %} - distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }} -{% endif %} -{% endif %} -{% endfor %} -{% endif %} -{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %} -{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %} - distribute-list prefix {{ distribute_list.prefix_list.in }} in -{% endif %} -{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %} - distribute-list prefix {{ distribute_list.prefix_list.out }} out -{% endif %} -{% endif %} -{% endif %} -{% include 'frr/rip_ripng.frr.j2' %} -! -{% if route_map is defined and route_map is not none %} -ip protocol rip route-map {{ route_map }} -{% endif %} -! diff --git a/data/templates/frr/ripd.frr.tmpl b/data/templates/frr/ripd.frr.tmpl new file mode 100644 index 000000000..cabc236f0 --- /dev/null +++ b/data/templates/frr/ripd.frr.tmpl @@ -0,0 +1,96 @@ +! +{# RIP key-chain definition #} +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +{% if iface_config.authentication is defined and iface_config.authentication.md5 is defined and iface_config.authentication.md5 is not none %} +key chain {{ iface }}-rip +{% for key_id, key_options in iface_config.authentication.md5.items() %} + key {{ key_id }} +{% if key_options.password is defined and key_options.password is not none %} + key-string {{ key_options.password }} +{% endif %} +{% endfor %} +{% endif %} +{% endfor %} +{% endif %} +! +{# Interface specific configuration #} +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.authentication is defined and iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %} + ip rip authentication mode text + ip rip authentication string {{ iface_config.authentication.plaintext_password }} +{% elif iface_config.authentication is defined and iface_config.authentication.md5 is defined and iface_config.authentication.md5 is not none %} + ip rip authentication key-chain {{ iface }}-rip + ip rip authentication mode md5 +{% endif %} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %} + no ip rip split-horizon +{% endif %} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} + ip rip split-horizon poisoned-reverse +{% endif %} +{% endfor %} +{% endif %} +! +router rip +{% if default_distance is defined and default_distance is not none %} + distance {{ default_distance }} +{% endif %} +{% if network_distance is defined and network_distance is not none %} +{% for network, network_config in network_distance.items() %} +{% if network_config.distance is defined and network_config.distance is not none %} + distance {{ network_config.distance }} {{ network }} +{% endif %} +{% endfor %} +{% endif %} +{% if neighbor is defined and neighbor is not none %} +{% for address in neighbor %} + neighbor {{ address }} +{% endfor %} +{% endif %} +{% if distribute_list is defined and distribute_list is not none %} +{% if distribute_list.access_list is defined and distribute_list.access_list is not none %} +{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} + distribute-list {{ distribute_list.access_list.in }} in +{% endif %} +{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %} + distribute-list {{ distribute_list.access_list.out }} out +{% endif %} +{% endif %} +{% if distribute_list.interface is defined and distribute_list.interface is not none %} +{% for interface, interface_config in distribute_list.interface.items() %} +{% if interface_config.access_list is defined and interface_config.access_list is not none %} +{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %} + distribute-list {{ interface_config.access_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %} + distribute-list {{ interface_config.access_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %} +{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %} + distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %} + distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %} +{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %} + distribute-list prefix {{ distribute_list.prefix_list.in }} in +{% endif %} +{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %} + distribute-list prefix {{ distribute_list.prefix_list.out }} out +{% endif %} +{% endif %} +{% endif %} +{% include 'frr/rip_ripng.frr.j2' %} +! +{% if route_map is defined and route_map is not none %} +ip protocol rip route-map {{ route_map }} +{% endif %} +! diff --git a/data/templates/frr/ripng.frr.tmpl b/data/templates/frr/ripng.frr.tmpl deleted file mode 100644 index 25df15121..000000000 --- a/data/templates/frr/ripng.frr.tmpl +++ /dev/null @@ -1,60 +0,0 @@ -! -{# Interface specific configuration #} -{% if interface is defined and interface is not none %} -{% for iface, iface_config in interface.items() %} -interface {{ iface }} -{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %} - no ipv6 rip split-horizon -{% endif %} -{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} - ipv6 rip split-horizon poisoned-reverse -{% endif %} -{% endfor %} -{% endif %} -! -router ripng -{% if aggregate_address is defined and aggregate_address is not none %} -{% for prefix in aggregate_address %} - aggregate-address {{ prefix }} -{% endfor %} -{% endif %} -{% if distribute_list is defined and distribute_list is not none %} -{% if distribute_list.access_list is defined and distribute_list.access_list is not none %} -{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} - ipv6 distribute-list {{ distribute_list.access_list.in }} in -{% endif %} -{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %} - ipv6 distribute-list {{ distribute_list.access_list.out }} out -{% endif %} -{% endif %} -{% if distribute_list.interface is defined and distribute_list.interface is not none %} -{% for interface, interface_config in distribute_list.interface.items() %} -{% if interface_config.access_list is defined and interface_config.access_list is not none %} -{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %} - ipv6 distribute-list {{ interface_config.access_list.in }} in {{ interface }} -{% endif %} -{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %} - ipv6 distribute-list {{ interface_config.access_list.out }} out {{ interface }} -{% endif %} -{% endif %} -{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %} -{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %} - ipv6 distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }} -{% endif %} -{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %} - ipv6 distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }} -{% endif %} -{% endif %} -{% endfor %} -{% endif %} -{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %} -{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %} - ipv6 distribute-list prefix {{ distribute_list.prefix_list.in }} in -{% endif %} -{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %} - ipv6 distribute-list prefix {{ distribute_list.prefix_list.out }} out -{% endif %} -{% endif %} -{% endif %} -{% include 'frr/rip_ripng.frr.j2' %} -! diff --git a/data/templates/frr/ripngd.frr.tmpl b/data/templates/frr/ripngd.frr.tmpl new file mode 100644 index 000000000..25df15121 --- /dev/null +++ b/data/templates/frr/ripngd.frr.tmpl @@ -0,0 +1,60 @@ +! +{# Interface specific configuration #} +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %} + no ipv6 rip split-horizon +{% endif %} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} + ipv6 rip split-horizon poisoned-reverse +{% endif %} +{% endfor %} +{% endif %} +! +router ripng +{% if aggregate_address is defined and aggregate_address is not none %} +{% for prefix in aggregate_address %} + aggregate-address {{ prefix }} +{% endfor %} +{% endif %} +{% if distribute_list is defined and distribute_list is not none %} +{% if distribute_list.access_list is defined and distribute_list.access_list is not none %} +{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} + ipv6 distribute-list {{ distribute_list.access_list.in }} in +{% endif %} +{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %} + ipv6 distribute-list {{ distribute_list.access_list.out }} out +{% endif %} +{% endif %} +{% if distribute_list.interface is defined and distribute_list.interface is not none %} +{% for interface, interface_config in distribute_list.interface.items() %} +{% if interface_config.access_list is defined and interface_config.access_list is not none %} +{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %} + ipv6 distribute-list {{ interface_config.access_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %} + ipv6 distribute-list {{ interface_config.access_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %} +{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %} + ipv6 distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %} + ipv6 distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %} +{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %} + ipv6 distribute-list prefix {{ distribute_list.prefix_list.in }} in +{% endif %} +{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %} + ipv6 distribute-list prefix {{ distribute_list.prefix_list.out }} out +{% endif %} +{% endif %} +{% endif %} +{% include 'frr/rip_ripng.frr.j2' %} +! diff --git a/data/templates/frr/static.frr.tmpl b/data/templates/frr/static.frr.tmpl deleted file mode 100644 index db59a44c2..000000000 --- a/data/templates/frr/static.frr.tmpl +++ /dev/null @@ -1,49 +0,0 @@ -{% from 'frr/static_routes_macro.j2' import static_routes %} -! -{% set ip_prefix = 'ip' %} -{% set ipv6_prefix = 'ipv6' %} -{% if vrf is defined and vrf is not none %} -{# We need to add an additional whitespace in front of the prefix #} -{# when VRFs are in use, thus we use a variable for prefix handling #} -{% set ip_prefix = ' ip' %} -{% set ipv6_prefix = ' ipv6' %} -vrf {{ vrf }} -{% endif %} -{# IPv4 routing #} -{% if route is defined and route is not none %} -{% for prefix, prefix_config in route.items() %} -{{ static_routes(ip_prefix, prefix, prefix_config) }} -{%- endfor -%} -{% endif %} -{# IPv6 routing #} -{% if route6 is defined and route6 is not none %} -{% for prefix, prefix_config in route6.items() %} -{{ static_routes(ipv6_prefix, prefix, prefix_config) }} -{%- endfor -%} -{% endif %} -{% if vrf is defined and vrf is not none %} - exit-vrf -{% endif %} -! -{# Policy route tables #} -{% if table is defined and table is not none %} -{% for table_id, table_config in table.items() %} -{% if table_config.route is defined and table_config.route is not none %} -{% for prefix, prefix_config in table_config.route.items() %} -{{ static_routes('ip', prefix, prefix_config, table_id) }} -{%- endfor -%} -{% endif %} -! -{% if table_config.route6 is defined and table_config.route6 is not none %} -{% for prefix, prefix_config in table_config.route6.items() %} -{{ static_routes('ipv6', prefix, prefix_config, table_id) }} -{%- endfor -%} -{% endif %} -! -{% endfor %} -{% endif %} -! -{% if route_map is defined and route_map is not none %} -ip protocol static route-map {{ route_map }} -! -{% endif %} diff --git a/data/templates/frr/staticd.frr.tmpl b/data/templates/frr/staticd.frr.tmpl new file mode 100644 index 000000000..db59a44c2 --- /dev/null +++ b/data/templates/frr/staticd.frr.tmpl @@ -0,0 +1,49 @@ +{% from 'frr/static_routes_macro.j2' import static_routes %} +! +{% set ip_prefix = 'ip' %} +{% set ipv6_prefix = 'ipv6' %} +{% if vrf is defined and vrf is not none %} +{# We need to add an additional whitespace in front of the prefix #} +{# when VRFs are in use, thus we use a variable for prefix handling #} +{% set ip_prefix = ' ip' %} +{% set ipv6_prefix = ' ipv6' %} +vrf {{ vrf }} +{% endif %} +{# IPv4 routing #} +{% if route is defined and route is not none %} +{% for prefix, prefix_config in route.items() %} +{{ static_routes(ip_prefix, prefix, prefix_config) }} +{%- endfor -%} +{% endif %} +{# IPv6 routing #} +{% if route6 is defined and route6 is not none %} +{% for prefix, prefix_config in route6.items() %} +{{ static_routes(ipv6_prefix, prefix, prefix_config) }} +{%- endfor -%} +{% endif %} +{% if vrf is defined and vrf is not none %} + exit-vrf +{% endif %} +! +{# Policy route tables #} +{% if table is defined and table is not none %} +{% for table_id, table_config in table.items() %} +{% if table_config.route is defined and table_config.route is not none %} +{% for prefix, prefix_config in table_config.route.items() %} +{{ static_routes('ip', prefix, prefix_config, table_id) }} +{%- endfor -%} +{% endif %} +! +{% if table_config.route6 is defined and table_config.route6 is not none %} +{% for prefix, prefix_config in table_config.route6.items() %} +{{ static_routes('ipv6', prefix, prefix_config, table_id) }} +{%- endfor -%} +{% endif %} +! +{% endfor %} +{% endif %} +! +{% if route_map is defined and route_map is not none %} +ip protocol static route-map {{ route_map }} +! +{% endif %} diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py index 348bae59f..539fd7b8e 100755 --- a/src/conf_mode/protocols_bfd.py +++ b/src/conf_mode/protocols_bfd.py @@ -92,7 +92,7 @@ def generate(bfd): bfd['new_frr_config'] = '' return None - bfd['new_frr_config'] = render_to_string('frr/bfd.frr.tmpl', bfd) + bfd['new_frr_config'] = render_to_string('frr/bfdd.frr.tmpl', bfd) def apply(bfd): # Save original configuration prior to starting any commit actions diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py index e56eb1f56..6b78f6f2d 100755 --- a/src/conf_mode/protocols_rip.py +++ b/src/conf_mode/protocols_rip.py @@ -93,7 +93,7 @@ def generate(rip): rip['new_frr_config'] = '' return None - rip['new_frr_config'] = render_to_string('frr/rip.frr.tmpl', rip) + rip['new_frr_config'] = render_to_string('frr/ripd.frr.tmpl', rip) return None diff --git a/src/conf_mode/protocols_ripng.py b/src/conf_mode/protocols_ripng.py index aaec5dacb..bc4954f63 100755 --- a/src/conf_mode/protocols_ripng.py +++ b/src/conf_mode/protocols_ripng.py @@ -95,7 +95,7 @@ def generate(ripng): ripng['new_frr_config'] = '' return None - ripng['new_frr_config'] = render_to_string('frr/ripng.frr.tmpl', ripng) + ripng['new_frr_config'] = render_to_string('frr/ripngd.frr.tmpl', ripng) return None def apply(ripng): diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index 338247e30..597fcc443 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -80,7 +80,7 @@ def verify(static): return None def generate(static): - static['new_frr_config'] = render_to_string('frr/static.frr.tmpl', static) + static['new_frr_config'] = render_to_string('frr/staticd.frr.tmpl', static) return None def apply(static): -- cgit v1.2.3 From a0202eaf489cfc59ee5358621ab674a5a515c978 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 27 Sep 2021 20:52:09 +0200 Subject: igmp: T2230: fix Jinja2 and FRR indention --- data/templates/frr/igmp.frr.tmpl | 60 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'data/templates/frr') diff --git a/data/templates/frr/igmp.frr.tmpl b/data/templates/frr/igmp.frr.tmpl index cdb7ee6cc..49b5aeaa5 100644 --- a/data/templates/frr/igmp.frr.tmpl +++ b/data/templates/frr/igmp.frr.tmpl @@ -1,41 +1,41 @@ ! {% for iface in old_ifaces %} interface {{ iface }} -{% for group in old_ifaces[iface].gr_join %} -{% if old_ifaces[iface].gr_join[group] %} -{% for source in old_ifaces[iface].gr_join[group] %} -no ip igmp join {{ group }} {{ source }} -{% endfor %} -{% else %} -no ip igmp join {{ group }} -{% endif %} -{% endfor %} -no ip igmp +{% for group in old_ifaces[iface].gr_join %} +{% if old_ifaces[iface].gr_join[group] %} +{% for source in old_ifaces[iface].gr_join[group] %} + no ip igmp join {{ group }} {{ source }} +{% endfor %} +{% else %} + no ip igmp join {{ group }} +{% endif %} +{% endfor %} + no ip igmp ! {% endfor %} {% for iface in ifaces %} interface {{ iface }} -{% if ifaces[iface].version %} -ip igmp version {{ ifaces[iface].version }} -{% else %} +{% if ifaces[iface].version %} + ip igmp version {{ ifaces[iface].version }} +{% else %} {# IGMP default version 3 #} -ip igmp -{% endif %} -{% if ifaces[iface].query_interval %} -ip igmp query-interval {{ ifaces[iface].query_interval }} -{% endif %} -{% if ifaces[iface].query_max_resp_time %} -ip igmp query-max-response-time {{ ifaces[iface].query_max_resp_time }} -{% endif %} -{% for group in ifaces[iface].gr_join %} -{% if ifaces[iface].gr_join[group] %} -{% for source in ifaces[iface].gr_join[group] %} -ip igmp join {{ group }} {{ source }} -{% endfor %} -{% else %} -ip igmp join {{ group }} -{% endif %} -{% endfor %} + ip igmp +{% endif %} +{% if ifaces[iface].query_interval %} + ip igmp query-interval {{ ifaces[iface].query_interval }} +{% endif %} +{% if ifaces[iface].query_max_resp_time %} + ip igmp query-max-response-time {{ ifaces[iface].query_max_resp_time }} +{% endif %} +{% for group in ifaces[iface].gr_join %} +{% if ifaces[iface].gr_join[group] %} +{% for source in ifaces[iface].gr_join[group] %} + ip igmp join {{ group }} {{ source }} +{% endfor %} +{% else %} + ip igmp join {{ group }} +{% endif %} +{% endfor %} ! {% endfor %} ! -- cgit v1.2.3 From 74a8c4b42b5ad31cdf34ddea07f83f7bff86be87 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 4 Oct 2021 22:25:19 +0200 Subject: bgp: T3741: "parameter default no-ipv4-unicast" is now a default option --- data/templates/frr/bgpd.frr.tmpl | 2 - .../include/bgp/protocol-common-config.xml.i | 6 -- smoketest/configs/bgp-small-ipv4-unicast | 77 ++++++++++++++++++++++ smoketest/scripts/cli/test_protocols_bgp.py | 3 - src/migration-scripts/bgp/1-to-2 | 77 ++++++++++++++++++++++ 5 files changed, 154 insertions(+), 11 deletions(-) create mode 100644 smoketest/configs/bgp-small-ipv4-unicast create mode 100755 src/migration-scripts/bgp/1-to-2 (limited to 'data/templates/frr') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 27a2b98a5..a35930c93 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -230,10 +230,8 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% else %} no bgp ebgp-requires-policy {% endif %} -{% if parameters is defined and parameters.default is defined and parameters.default.no_ipv4_unicast is defined %} {# Option must be set before any neighbor - see https://phabricator.vyos.net/T3463 #} no bgp default ipv4-unicast -{% endif %} {# Workaround for T2100 until we have decided about a migration script #} no bgp network import-check {% if address_family is defined and address_family is not none %} diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 30033bc50..2dfae517e 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -1253,12 +1253,6 @@ - - - Deactivate IPv4 unicast for a peer by default - - - diff --git a/smoketest/configs/bgp-small-ipv4-unicast b/smoketest/configs/bgp-small-ipv4-unicast new file mode 100644 index 000000000..a4dcd6218 --- /dev/null +++ b/smoketest/configs/bgp-small-ipv4-unicast @@ -0,0 +1,77 @@ +interfaces { + ethernet eth0 { + address 192.0.2.1 + address 2001:db8::1/64 + } + loopback lo { + } +} +protocols { + bgp 65001 { + address-family { + ipv4-unicast { + network 10.0.150.0/23 { + } + } + ipv6-unicast { + network 2001:db8:200::/40 { + } + } + } + neighbor 192.0.2.10 { + remote-as 65010 + } + neighbor 192.0.2.11 { + remote-as 65011 + } + neighbor 2001:db8::10 { + remote-as 65010 + } + neighbor 2001:db8::11 { + remote-as 65011 + } + parameters { + log-neighbor-changes + } + } +} +service { + ssh { + disable-host-validation + port 22 + } +} +system { + config-management { + commit-revisions 200 + } + console { + device ttyS0 { + speed 115200 + } + } + domain-name vyos.net + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 + plaintext-password "" + } + } + } + syslog { + global { + facility all { + level notice + } + facility protocols { + level debug + } + } + } +} + +/* 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:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.5 */ diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 29b5aa9d1..16284ed01 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -221,8 +221,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): # Default local preference (higher = more preferred, default value is 100) self.cli_set(base_path + ['parameters', 'default', 'local-pref', local_pref]) - # Deactivate IPv4 unicast for a peer by default - self.cli_set(base_path + ['parameters', 'default', 'no-ipv4-unicast']) self.cli_set(base_path + ['parameters', 'graceful-restart', 'stalepath-time', stalepath_time]) self.cli_set(base_path + ['parameters', 'graceful-shutdown']) self.cli_set(base_path + ['parameters', 'ebgp-requires-policy']) @@ -246,7 +244,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' bgp router-id {router_id}', frrconfig) self.assertIn(f' bgp log-neighbor-changes', frrconfig) self.assertIn(f' bgp default local-preference {local_pref}', frrconfig) - self.assertIn(f' no bgp default ipv4-unicast', frrconfig) self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig) self.assertIn(f' bgp graceful-shutdown', frrconfig) self.assertIn(f' bgp bestpath as-path multipath-relax', frrconfig) diff --git a/src/migration-scripts/bgp/1-to-2 b/src/migration-scripts/bgp/1-to-2 new file mode 100755 index 000000000..4c6d5ceb8 --- /dev/null +++ b/src/migration-scripts/bgp/1-to-2 @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# T3741: no-ipv4-unicast is now enabled by default + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree +from vyos.template import is_ipv4 + +if (len(argv) < 1): + print("Must specify file name!") + exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['protocols', 'bgp'] +config = ConfigTree(config_file) + +if not config.exists(base): + # Nothing to do + exit(0) + +# This is now a default option - simply delete it. +# As it was configured explicitly - we can also bail out early as we need to +# do nothing! +if config.exists(base + ['parameters', 'default', 'no-ipv4-unicast']): + config.delete(base + ['parameters', 'default', 'no-ipv4-unicast']) + + # Check if the "default" node is now empty, if so - remove it + if len(config.list_nodes(base + ['parameters', 'default'])) == 0: + config.delete(base + ['parameters', 'default']) + + # Check if the "default" node is now empty, if so - remove it + if len(config.list_nodes(base + ['parameters'])) == 0: + config.delete(base + ['parameters']) + + exit(0) + +# As we now install a new default option into BGP we need to migrate all +# existing BGP neighbors and restore the old behavior +if config.exists(base + ['neighbor']): + for neighbor in config.list_nodes(base + ['neighbor']): + peer_group = base + ['neighbor', neighbor, 'peer-group'] + if config.exists(peer_group): + peer_group_name = config.return_value(peer_group) + # peer group enables old behavior for neighbor - bail out + if config.exists(base + ['peer-group', peer_group_name, 'address-family', 'ipv4-unicast']): + continue + + afi_ipv4 = base + ['neighbor', neighbor, 'address-family', 'ipv4-unicast'] + if not config.exists(afi_ipv4): + config.set(afi_ipv4) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print(f'Failed to save the modified config: {e}') + exit(1) -- cgit v1.2.3