From 6f0249e39164b9d59de6550337e2901e5ed9ebf1 Mon Sep 17 00:00:00 2001 From: DmitriyEshenko Date: Mon, 22 Nov 2021 20:55:06 +0000 Subject: tftp: T4012: Add TFTP VRF support --- data/templates/tftp-server/default.tmpl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'data') diff --git a/data/templates/tftp-server/default.tmpl b/data/templates/tftp-server/default.tmpl index 6b2d6a903..a7edf60ad 100644 --- a/data/templates/tftp-server/default.tmpl +++ b/data/templates/tftp-server/default.tmpl @@ -1,2 +1,7 @@ ### Autogenerated by tftp_server.py ### DAEMON_ARGS="--listen --user tftp --address {{ listen_address }} {{ "--create --umask 000" if allow_upload is defined }} --secure {{ directory }}" +{% if vrf is defined %} +VRF_ARGS="ip vrf exec {{ vrf }}" +{% else %} +VRF_ARGS="" +{% endif %} -- cgit v1.2.3 From 9d79e9dae21819a5f92c2394e9e8360344d50c94 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: bfd: T3753: fix Jinja2 "echo-interval" indention --- data/templates/frr/bfdd.frr.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'data') diff --git a/data/templates/frr/bfdd.frr.tmpl b/data/templates/frr/bfdd.frr.tmpl index 16f8be92c..c7528570f 100644 --- a/data/templates/frr/bfdd.frr.tmpl +++ b/data/templates/frr/bfdd.frr.tmpl @@ -27,7 +27,7 @@ bfd 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'] }} + echo-interval {{ peer_config.interval['echo-interval'] }} {% endif %} {% if peer_config['echo-mode'] is defined %} echo-mode -- cgit v1.2.3 From a54c9ccc02638b569994b629d5f67ffe32c92167 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: bfd: T3753: adjust to CLI options new in FRR 8.0 --- data/templates/frr/bfdd.frr.tmpl | 3 ++- smoketest/scripts/cli/test_protocols_bfd.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'data') diff --git a/data/templates/frr/bfdd.frr.tmpl b/data/templates/frr/bfdd.frr.tmpl index c7528570f..3fb1f47d6 100644 --- a/data/templates/frr/bfdd.frr.tmpl +++ b/data/templates/frr/bfdd.frr.tmpl @@ -7,7 +7,8 @@ bfd 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'] }} + echo transmit-interval {{ profile_config.interval['echo-interval'] }} + echo receive-interval {{ profile_config.interval['echo-interval'] }} {% endif %} {% if profile_config['echo-mode'] is defined %} echo-mode diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py index 297398d3c..46a019dfc 100755 --- a/smoketest/scripts/cli/test_protocols_bfd.py +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -113,7 +113,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): if 'echo_mode' in peer_config: self.assertIn(f'echo-mode', peerconfig) if 'intv_echo' in peer_config: - self.assertIn(f'echo-interval {peer_config["intv_echo"]}', peerconfig) + self.assertIn(f'echo receive-interval {peer_config["intv_echo"]}', peerconfig) + self.assertIn(f'echo transmit-interval {peer_config["intv_echo"]}', peerconfig) if 'intv_mult' in peer_config: self.assertIn(f'detect-multiplier {peer_config["intv_mult"]}', peerconfig) if 'intv_rx' in peer_config: @@ -153,7 +154,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): if 'echo_mode' in profile_config: self.assertIn(f'echo-mode', config) if 'intv_echo' in profile_config: - self.assertIn(f'echo-interval {profile_config["intv_echo"]}', config) + self.assertIn(f'echo receive-interval {profile_config["intv_echo"]}', config) + self.assertIn(f'echo transmit-interval {profile_config["intv_echo"]}', config) if 'intv_mult' in profile_config: self.assertIn(f'detect-multiplier {profile_config["intv_mult"]}', config) if 'intv_rx' in profile_config: -- cgit v1.2.3 From 2e9116e9661ce355dedf5f9d0a2afb1fdbedf786 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: ospf: T3753: adjust to CLI options new in FRR 8.0 --- data/templates/frr/ospfd.frr.tmpl | 13 ++++------ smoketest/scripts/cli/test_protocols_ospf.py | 39 +++++++--------------------- 2 files changed, 14 insertions(+), 38 deletions(-) (limited to 'data') diff --git a/data/templates/frr/ospfd.frr.tmpl b/data/templates/frr/ospfd.frr.tmpl index 90a6bbd56..f65bb6e74 100644 --- a/data/templates/frr/ospfd.frr.tmpl +++ b/data/templates/frr/ospfd.frr.tmpl @@ -49,6 +49,11 @@ 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 passive_interface_exclude is defined and passive_interface_exclude is not none %} +{% if iface in passive_interface_exclude %} + no ip ospf passive +{% endif %} +{% endif %} ! {% endfor %} {% endif %} @@ -163,14 +168,6 @@ router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} 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 %} - no passive-interface {{ interface }} -{% endfor %} -{% endif %} {% if redistribute is defined and redistribute is not none %} {% for protocol, protocols_options in redistribute.items() %} {% if protocol == 'table' %} diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index 0529eefbd..65bfd1824 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -189,31 +189,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): for neighbor in neighbors: self.assertIn(f' neighbor {neighbor} priority {priority} poll-interval {poll_interval}', frrconfig) # default - - def test_ospf_07_passive_interface(self): - self.cli_set(base_path + ['passive-interface', 'default']) - interfaces = Section.interfaces('ethernet') - for interface in interfaces: - self.cli_set(base_path + ['passive-interface-exclude', interface]) - - # commit changes - self.cli_commit() - - # Verify FRR ospfd configuration - frrconfig = self.getFRRconfig('router ospf') - try: - self.assertIn(f'router ospf', frrconfig) - self.assertIn(f' passive-interface default', frrconfig) # default - for interface in interfaces: - self.assertIn(f' no passive-interface {interface}', frrconfig) # default - except: - log.debug(frrconfig) - log.debug(cmd('sudo dmesg')) - log.debug(cmd('sudo cat /var/log/messages')) - log.debug(cmd('vtysh -c "show run"')) - self.fail('Now we can hopefully see why OSPF fails!') - - def test_ospf_08_redistribute(self): + def test_ospf_07_redistribute(self): metric = '15' metric_type = '1' redistribute = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static'] @@ -238,7 +214,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): log.debug(cmd('vtysh -c "show run"')) self.fail('Now we can hopefully see why OSPF fails!') - def test_ospf_09_virtual_link(self): + def test_ospf_08_virtual_link(self): networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'] area = '10' shortcut = 'enable' @@ -268,7 +244,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.assertIn(f' network {network} area {area}', frrconfig) - def test_ospf_10_interface_configuration(self): + def test_ospf_09_interface_configuration(self): interfaces = Section.interfaces('ethernet') password = 'vyos1234' bandwidth = '10000' @@ -276,6 +252,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): network = 'point-to-point' priority = '200' + self.cli_set(base_path + ['passive-interface', 'default']) for interface in interfaces: self.cli_set(base_path + ['interface', interface, 'authentication', 'plaintext-password', password]) self.cli_set(base_path + ['interface', interface, 'bandwidth', bandwidth]) @@ -284,6 +261,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['interface', interface, 'mtu-ignore']) self.cli_set(base_path + ['interface', interface, 'network', network]) self.cli_set(base_path + ['interface', interface, 'priority', priority]) + self.cli_set(base_path + ['passive-interface-exclude', interface]) # commit changes self.cli_commit() @@ -297,10 +275,11 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.assertIn(f' ip ospf mtu-ignore', config) self.assertIn(f' ip ospf network {network}', config) self.assertIn(f' ip ospf priority {priority}', config) + self.assertIn(f' no ip ospf passive', config) self.assertIn(f' bandwidth {bandwidth}', config) - def test_ospf_11_vrfs(self): + def test_ospf_10_vrfs(self): # It is safe to assume that when the basic VRF test works, all # other OSPF related features work, as we entirely inherit the CLI # templates and Jinja2 FRR template. @@ -331,7 +310,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf']) - def test_ospf_12_zebra_route_map(self): + def test_ospf_11_zebra_route_map(self): # Implemented because of T3328 self.cli_set(base_path + ['route-map', route_map]) # commit changes @@ -351,7 +330,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): frrconfig = self.getFRRconfig(zebra_route_map) self.assertNotIn(zebra_route_map, frrconfig) - def test_ospf_13_interface_area(self): + def test_ospf_12_interface_area(self): area = '0' interfaces = Section.interfaces('ethernet') -- cgit v1.2.3 From 09064990b9e3ed0a19c1ca4257b385f92d25af2a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: ospfv3: T3753: adjust to CLI options new in FRR 8.0 --- data/templates/frr/ospf6d.frr.tmpl | 8 ++-- interface-definitions/protocols-ospfv3.xml.in | 21 ++++++++++- smoketest/scripts/cli/test_protocols_ospfv3.py | 5 ++- src/migration-scripts/ospf/0-to-1 | 52 ++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 8 deletions(-) create mode 100755 src/migration-scripts/ospf/0-to-1 (limited to 'data') diff --git a/data/templates/frr/ospf6d.frr.tmpl b/data/templates/frr/ospf6d.frr.tmpl index a8c53738f..c6527ed6c 100644 --- a/data/templates/frr/ospf6d.frr.tmpl +++ b/data/templates/frr/ospf6d.frr.tmpl @@ -2,6 +2,9 @@ {% if interface is defined and interface is not none %} {% for iface, iface_config in interface.items() %} interface {{ iface }} +{% if iface_config.area is defined and iface_config.area is not none %} + ipv6 ospf6 area {{ iface_config.area }} +{% endif %} {% if iface_config.cost is defined and iface_config.cost is not none %} ipv6 ospf6 cost {{ iface_config.cost }} {% endif %} @@ -45,11 +48,6 @@ interface {{ iface }} 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 }} diff --git a/interface-definitions/protocols-ospfv3.xml.in b/interface-definitions/protocols-ospfv3.xml.in index fffeeb9a5..c7a94d58c 100644 --- a/interface-definitions/protocols-ospfv3.xml.in +++ b/interface-definitions/protocols-ospfv3.xml.in @@ -61,7 +61,6 @@ - #include Specify IPv6 prefix (border routers only) @@ -121,6 +120,26 @@ + + + Enable OSPF on this interface + + protocols ospfv3 area + + + u32 + OSPF area ID as decimal notation + + + ipv4 + OSPF area ID in IP address notation + + + + + + + #include #include diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py index c0673629e..8e12990d5 100755 --- a/smoketest/scripts/cli/test_protocols_ospfv3.py +++ b/smoketest/scripts/cli/test_protocols_ospfv3.py @@ -49,7 +49,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): interfaces = Section.interfaces('ethernet') for interface in interfaces: - self.cli_set(base_path + ['area', default_area, 'interface', interface]) + self.cli_set(base_path + ['interface', interface, 'area', default_area]) # commit changes self.cli_commit() @@ -63,7 +63,8 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): self.assertIn(f' area {default_area} export-list {acl_name}', frrconfig) for interface in interfaces: - self.assertIn(f' interface {interface} area {default_area}', frrconfig) + if_config = self.getFRRconfig(f'interface {interface}') + self.assertIn(f'ipv6 ospf6 area {default_area}', if_config) self.cli_delete(['policy', 'access-list6', acl_name]) diff --git a/src/migration-scripts/ospf/0-to-1 b/src/migration-scripts/ospf/0-to-1 new file mode 100755 index 000000000..ff3a84b2c --- /dev/null +++ b/src/migration-scripts/ospf/0-to-1 @@ -0,0 +1,52 @@ +#!/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 . + +# T3753: upgrade to FRR8 and move CLI options to better fit with the new FRR CLI + +from sys import argv +from vyos.configtree import ConfigTree + +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() + +ospfv3_base = ['protocols', 'ospfv3'] +config = ConfigTree(config_file) + +if config.exists(ospfv3_base): + area_base = ospfv3_base + ['area'] + if config.exists(area_base): + for area in config.list_nodes(area_base): + if not config.exists(area_base + [area, 'interface']): + continue + + for interface in config.return_values(area_base + [area, 'interface']): + config.set(ospfv3_base + ['interface', interface, 'area', area]) + config.set_tag(ospfv3_base + ['interface']) + + config.delete(area_base + [area, 'interface']) + +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 From 1c15e9de76f81383a32e60d2af54444dbb0474a1 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: ospf: T3753: adjust to CLI options new in FRR 8.0 FRR 7.5 router ospf passive-interface default no passive-interface eth0.202 Changed int FRR 8 to interface eth0.202 no ip ospf passive ! router ospf ospf router-id 172.18.254.202 log-adjacency-changes detail passive-interface default --- data/templates/frr/ospfd.frr.tmpl | 12 +++----- .../include/generic-disable-node.xml.i | 2 +- .../include/ospf/protocol-common-config.xml.i | 27 +++++++++--------- smoketest/scripts/cli/test_protocols_ospf.py | 17 +++++------ src/migration-scripts/ospf/0-to-1 | 33 ++++++++++++++++++++-- 5 files changed, 59 insertions(+), 32 deletions(-) (limited to 'data') diff --git a/data/templates/frr/ospfd.frr.tmpl b/data/templates/frr/ospfd.frr.tmpl index f65bb6e74..37d6f394b 100644 --- a/data/templates/frr/ospfd.frr.tmpl +++ b/data/templates/frr/ospfd.frr.tmpl @@ -49,10 +49,8 @@ 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 passive_interface_exclude is defined and passive_interface_exclude is not none %} -{% if iface in passive_interface_exclude %} - no ip ospf passive -{% endif %} +{% if iface_config.passive is defined %} + {{ 'no ' if iface_config.passive.disable is defined }}ip ospf passive {% endif %} ! {% endfor %} @@ -163,10 +161,8 @@ router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} ospf router-id {{ parameters.router_id }} {% endif %} {% endif %} -{% if passive_interface is defined and passive_interface is not none %} -{% for interface in passive_interface %} - passive-interface {{ interface }} -{% endfor %} +{% if passive_interface is defined and passive_interface.default is defined %} + passive-interface default {% endif %} {% if redistribute is defined and redistribute is not none %} {% for protocol, protocols_options in redistribute.items() %} diff --git a/interface-definitions/include/generic-disable-node.xml.i b/interface-definitions/include/generic-disable-node.xml.i index bb4fa5c4b..97a328ecc 100644 --- a/interface-definitions/include/generic-disable-node.xml.i +++ b/interface-definitions/include/generic-disable-node.xml.i @@ -1,7 +1,7 @@ - Temporary disable + Disable instance diff --git a/interface-definitions/include/ospf/protocol-common-config.xml.i b/interface-definitions/include/ospf/protocol-common-config.xml.i index 982e519a9..ac165a157 100644 --- a/interface-definitions/include/ospf/protocol-common-config.xml.i +++ b/interface-definitions/include/ospf/protocol-common-config.xml.i @@ -436,6 +436,14 @@ Must be broadcast, non-broadcast, point-to-multipoint or point-to-point + + + Suppress routing updates on an interface + + + #include + + #include @@ -597,26 +605,19 @@ #include -#include - + - Interface to exclude when using 'passive-interface default' + Suppress routing updates on an interface - + default - txt - Interface to exclude when suppressing routing updates - - - vlinkN - Virtual-link interface to exclude when suppressing routing updates + default + Default to suppress routing updates on all interfaces - - ^(vlink[0-9]+)$ + ^(default)$ - diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index 65bfd1824..3942219e7 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -254,14 +254,15 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['passive-interface', 'default']) for interface in interfaces: - self.cli_set(base_path + ['interface', interface, 'authentication', 'plaintext-password', password]) - self.cli_set(base_path + ['interface', interface, 'bandwidth', bandwidth]) - self.cli_set(base_path + ['interface', interface, 'bfd']) - self.cli_set(base_path + ['interface', interface, 'cost', cost]) - self.cli_set(base_path + ['interface', interface, 'mtu-ignore']) - self.cli_set(base_path + ['interface', interface, 'network', network]) - self.cli_set(base_path + ['interface', interface, 'priority', priority]) - self.cli_set(base_path + ['passive-interface-exclude', interface]) + base_interface = base_path + ['interface', interface] + self.cli_set(base_interface + ['authentication', 'plaintext-password', password]) + self.cli_set(base_interface + ['bandwidth', bandwidth]) + self.cli_set(base_interface + ['bfd']) + self.cli_set(base_interface + ['cost', cost]) + self.cli_set(base_interface + ['mtu-ignore']) + self.cli_set(base_interface + ['network', network]) + self.cli_set(base_interface + ['priority', priority]) + self.cli_set(base_interface + ['passive', 'disable']) # commit changes self.cli_commit() diff --git a/src/migration-scripts/ospf/0-to-1 b/src/migration-scripts/ospf/0-to-1 index ff3a84b2c..678569d9e 100755 --- a/src/migration-scripts/ospf/0-to-1 +++ b/src/migration-scripts/ospf/0-to-1 @@ -19,6 +19,24 @@ from sys import argv from vyos.configtree import ConfigTree +def ospf_passive_migration(config, ospf_base): + if config.exists(ospf_base): + if config.exists(ospf_base + ['passive-interface']): + default = False + for interface in config.return_values(ospf_base + ['passive-interface']): + if interface == 'default': + default = True + continue + config.set(ospf_base + ['interface', interface, 'passive']) + + config.delete(ospf_base + ['passive-interface']) + config.set(ospf_base + ['passive-interface'], value='default') + + if config.exists(ospf_base + ['passive-interface-exclude']): + for interface in config.return_values(ospf_base + ['passive-interface-exclude']): + config.set(ospf_base + ['interface', interface, 'passive', 'disable']) + config.delete(ospf_base + ['passive-interface-exclude']) + if (len(argv) < 1): print("Must specify file name!") exit(1) @@ -28,9 +46,9 @@ file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() -ospfv3_base = ['protocols', 'ospfv3'] config = ConfigTree(config_file) +ospfv3_base = ['protocols', 'ospfv3'] if config.exists(ospfv3_base): area_base = ospfv3_base + ['area'] if config.exists(area_base): @@ -39,11 +57,22 @@ if config.exists(ospfv3_base): continue for interface in config.return_values(area_base + [area, 'interface']): - config.set(ospfv3_base + ['interface', interface, 'area', area]) + config.set(ospfv3_base + ['interface', interface, 'area'], value=area) config.set_tag(ospfv3_base + ['interface']) config.delete(area_base + [area, 'interface']) +# Migrate OSPF syntax in default VRF +ospf_base = ['protocols', 'ospf'] +ospf_passive_migration(config, ospf_base) + +vrf_base = ['vrf', 'name'] +if config.exists(vrf_base): + for vrf in config.list_nodes(vrf_base): + vrf_ospf_base = vrf_base + [vrf, 'protocols', 'ospf'] + if config.exists(vrf_ospf_base): + ospf_passive_migration(config, vrf_ospf_base) + try: with open(file_name, 'w') as f: f.write(config.to_string()) -- cgit v1.2.3 From 32725123a2e98f3f417a94e4646721e97be1eaca Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: bfd: T3753: adjust to new FRR 8.1 syntax Every node in running config now has an explicit "exit" tag. --- data/templates/frr/bfdd.frr.tmpl | 11 +++++++---- src/conf_mode/protocols_bfd.py | 10 +++------- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'data') diff --git a/data/templates/frr/bfdd.frr.tmpl b/data/templates/frr/bfdd.frr.tmpl index 3fb1f47d6..c14939677 100644 --- a/data/templates/frr/bfdd.frr.tmpl +++ b/data/templates/frr/bfdd.frr.tmpl @@ -1,4 +1,4 @@ -! +{% if profile is defined or peer is defined %} bfd {% if profile is defined and profile is not none %} {% for profile_name, profile_config in profile.items() %} @@ -18,7 +18,8 @@ bfd {% else %} no shutdown {% endif %} - exit + exit + ! {% endfor %} {% endif %} {% if peer is defined and peer is not none %} @@ -38,8 +39,10 @@ bfd {% else %} no shutdown {% endif %} - exit + exit + ! {% endfor %} {% endif %} - end +exit ! +{% endif %} diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py index f698e30d9..94825ba10 100755 --- a/src/conf_mode/protocols_bfd.py +++ b/src/conf_mode/protocols_bfd.py @@ -16,8 +16,6 @@ import os -from sys import exit - from vyos.config import Config from vyos.configdict import dict_merge from vyos.template import is_ipv6 @@ -36,7 +34,6 @@ def get_config(config=None): conf = Config() base = ['protocols', 'bfd'] bfd = conf.get_config_dict(base, get_first_key=True) - # Bail out early if configuration tree does not exist if not conf.exists(base): return bfd @@ -89,9 +86,7 @@ def verify(bfd): def generate(bfd): if not bfd: - bfd['new_frr_config'] = '' return None - bfd['new_frr_config'] = render_to_string('frr/bfdd.frr.tmpl', bfd) def apply(bfd): @@ -100,8 +95,9 @@ def apply(bfd): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(bfd_daemon) - frr_cfg.modify_section('^bfd', '') - frr_cfg.add_before(frr.default_add_before, bfd['new_frr_config']) + frr_cfg.modify_section('^bfd', stop_pattern='^exit', remove_stop_mark=True) + if 'new_frr_config' in bfd: + frr_cfg.add_before(frr.default_add_before, bfd['new_frr_config']) frr_cfg.commit_configuration(bfd_daemon) return None -- cgit v1.2.3 From 262fec8868d09d7cdd1f939a9ec0c74ba0ecc7c5 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: ospf: T3753: adjust to new FRR 8.1 syntax Every node in running config now has an explicit "exit" tag --- data/templates/frr/ospfd.frr.tmpl | 2 ++ src/conf_mode/protocols_ospf.py | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'data') diff --git a/data/templates/frr/ospfd.frr.tmpl b/data/templates/frr/ospfd.frr.tmpl index 37d6f394b..a7b770f07 100644 --- a/data/templates/frr/ospfd.frr.tmpl +++ b/data/templates/frr/ospfd.frr.tmpl @@ -52,6 +52,7 @@ interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% if iface_config.passive is defined %} {{ 'no ' if iface_config.passive.disable is defined }}ip ospf passive {% endif %} +exit ! {% endfor %} {% endif %} @@ -182,4 +183,5 @@ router ospf {{ 'vrf ' + vrf if vrf is defined and vrf 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 %} +exit ! diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 71eb39205..255560e19 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -56,10 +56,10 @@ def get_config(config=None): # instead of the VRF instance. if vrf: ospf['vrf'] = vrf - # As we no re-use this Python handler for both VRF and non VRF instances for - # OSPF we need to find out if any interfaces changed so properly adjust - # the FRR configuration and not by acctident change interfaces from a - # different VRF. + # FRR has VRF support for different routing daemons. As interfaces belong + # to VRFs - or the global VRF, we need to check for changed interfaces so + # that they will be properly rendered for the FRR config. Also this eases + # removal of interfaces from the running configuration. interfaces_removed = node_changed(conf, base + ['interface']) if interfaces_removed: ospf['interface_removed'] = list(interfaces_removed) @@ -191,8 +191,6 @@ def verify(ospf): def generate(ospf): if not ospf or 'deleted' in ospf: - ospf['frr_ospfd_config'] = '' - ospf['frr_zebra_config'] = '' return None ospf['protocol'] = 'ospf' # required for frr/vrf.route-map.frr.tmpl @@ -209,8 +207,9 @@ def apply(ospf): # The route-map used for the FIB (zebra) is part of the zebra daemon frr_cfg.load_configuration(zebra_daemon) - frr_cfg.modify_section(r'(\s+)?ip protocol ospf route-map [-a-zA-Z0-9.]+$', '', '(\s|!)') - frr_cfg.add_before(frr.default_add_before, ospf['frr_zebra_config']) + frr_cfg.modify_section('(\s+)?ip protocol ospf route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') + if 'frr_zebra_config' in ospf: + frr_cfg.add_before(frr.default_add_before, ospf['frr_zebra_config']) frr_cfg.commit_configuration(zebra_daemon) # Generate empty helper string which can be ammended to FRR commands, it @@ -220,15 +219,16 @@ def apply(ospf): vrf = ' vrf ' + ospf['vrf'] frr_cfg.load_configuration(ospf_daemon) - frr_cfg.modify_section(f'^router ospf{vrf}$', '') + frr_cfg.modify_section(f'^router ospf{vrf}', stop_pattern='^exit', remove_stop_mark=True) for key in ['interface', 'interface_removed']: if key not in ospf: continue for interface in ospf[key]: - frr_cfg.modify_section(f'^interface {interface}{vrf}$', '') + frr_cfg.modify_section(f'^interface {interface}{vrf}', stop_pattern='^exit', remove_stop_mark=True) - frr_cfg.add_before(frr.default_add_before, ospf['frr_ospfd_config']) + if 'frr_ospfd_config' in ospf: + frr_cfg.add_before(frr.default_add_before, ospf['frr_ospfd_config']) frr_cfg.commit_configuration(ospf_daemon) # Save configuration to /run/frr/config/frr.conf -- cgit v1.2.3 From c65ee39e28422785734fd736eb15727ae9228b5a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: policy: T3753: adjust to new FRR 8.1 syntax Every node in running config now has an explicit "exit" tag --- data/templates/frr/policy.frr.tmpl | 7 +++---- smoketest/scripts/cli/test_policy.py | 2 +- src/conf_mode/policy.py | 18 ++++++------------ 3 files changed, 10 insertions(+), 17 deletions(-) (limited to 'data') diff --git a/data/templates/frr/policy.frr.tmpl b/data/templates/frr/policy.frr.tmpl index 51adc1902..d3d3957a5 100644 --- a/data/templates/frr/policy.frr.tmpl +++ b/data/templates/frr/policy.frr.tmpl @@ -1,4 +1,3 @@ -! {% if access_list is defined and access_list is not none %} {% for acl, acl_config in access_list.items() | natural_sort %} {% if acl_config.description is defined and acl_config.description is not none %} @@ -60,7 +59,7 @@ ipv6 access-list {{ acl }} seq {{ rule }} {{ rule_config.action }} {{ src }} {{ {% for acl, acl_config in as_path_list.items() | natural_sort %} {% if acl_config.rule is defined and acl_config.rule is not none %} {% for rule, rule_config in acl_config.rule.items() | natural_sort %} -bgp as-path access-list {{ acl }} {{ rule_config.action }} {{ rule_config.regex }} +bgp as-path access-list {{ acl }} seq {{ rule }} {{ rule_config.action }} {{ rule_config.regex }} {% endfor %} {% endif %} {% endfor %} @@ -314,9 +313,9 @@ route-map {{ route_map }} {{ rule_config.action }} {{ rule }} set weight {{ rule_config.set.weight }} {% endif %} {% endif %} -{% endfor %} +exit ! +{% endfor %} {% endif %} {% endfor %} {% endif %} -! diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py index 1286a768d..5844e1ec1 100755 --- a/smoketest/scripts/cli/test_policy.py +++ b/smoketest/scripts/cli/test_policy.py @@ -307,7 +307,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): continue for rule, rule_config in as_path_config['rule'].items(): - tmp = f'bgp as-path access-list {as_path}' + tmp = f'bgp as-path access-list {as_path} seq {rule}' if rule_config['action'] == 'permit': tmp += ' permit' else: diff --git a/src/conf_mode/policy.py b/src/conf_mode/policy.py index 5c592a599..5f9fcab9f 100755 --- a/src/conf_mode/policy.py +++ b/src/conf_mode/policy.py @@ -171,9 +171,7 @@ def verify(policy): def generate(policy): if not policy: - policy['new_frr_config'] = '' return None - policy['new_frr_config'] = render_to_string('frr/policy.frr.tmpl', policy) return None @@ -190,8 +188,9 @@ def apply(policy): frr_cfg.modify_section(r'^bgp community-list .*') frr_cfg.modify_section(r'^bgp extcommunity-list .*') frr_cfg.modify_section(r'^bgp large-community-list .*') - frr_cfg.modify_section(r'^route-map .*') - frr_cfg.add_before(frr.default_add_before, policy['new_frr_config']) + frr_cfg.modify_section(r'^route-map .*', stop_pattern='^exit', remove_stop_mark=True) + if 'new_frr_config' in policy: + frr_cfg.add_before(frr.default_add_before, policy['new_frr_config']) frr_cfg.commit_configuration(bgp_daemon) # The route-map used for the FIB (zebra) is part of the zebra daemon @@ -200,16 +199,11 @@ def apply(policy): frr_cfg.modify_section(r'^ipv6 access-list .*') frr_cfg.modify_section(r'^ip prefix-list .*') frr_cfg.modify_section(r'^ipv6 prefix-list .*') - frr_cfg.modify_section(r'^route-map .*') - frr_cfg.add_before(frr.default_add_before, policy['new_frr_config']) + frr_cfg.modify_section(r'^route-map .*', stop_pattern='^exit', remove_stop_mark=True) + if 'new_frr_config' in policy: + frr_cfg.add_before(frr.default_add_before, policy['new_frr_config']) frr_cfg.commit_configuration(zebra_daemon) - # If FRR config is blank, rerun the blank commit x times due to frr-reload - # behavior/bug not properly clearing out on one commit. - if policy['new_frr_config'] == '': - for a in range(5): - frr_cfg.commit_configuration(zebra_daemon) - # Save configuration to /run/frr/config/frr.conf frr.save_configuration() -- cgit v1.2.3 From 4e35c58c3ff85668797aa2413cd8af72ec29c830 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: bgp: T3753: adjust to new FRR 8.1 syntax --- data/templates/frr/bgpd.frr.tmpl | 3 +-- src/conf_mode/protocols_bgp.py | 12 ++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'data') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 61936bb56..fbdbafd6e 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -524,5 +524,4 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% if timers is defined and timers.keepalive is defined and timers.holdtime is defined %} timers bgp {{ timers.keepalive }} {{ timers.holdtime }} {% endif %} - end -! \ No newline at end of file +exit \ No newline at end of file diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 084198251..359bfff76 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -268,8 +268,6 @@ def verify(bgp): def generate(bgp): if not bgp or 'deleted' in bgp: - bgp['frr_bgpd_config'] = '' - bgp['frr_zebra_config'] = '' return None bgp['protocol'] = 'bgp' # required for frr/vrf.route-map.frr.tmpl @@ -287,8 +285,9 @@ def apply(bgp): # The route-map used for the FIB (zebra) is part of the zebra daemon frr_cfg.load_configuration(zebra_daemon) - frr_cfg.modify_section(r'(\s+)?ip protocol bgp route-map [-a-zA-Z0-9.]+$', '', '(\s|!)') - frr_cfg.add_before(frr.default_add_before, bgp['frr_zebra_config']) + frr_cfg.modify_section(r'(\s+)?ip protocol bgp route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') + if 'frr_zebra_config' in bgp: + frr_cfg.add_before(frr.default_add_before, bgp['frr_zebra_config']) frr_cfg.commit_configuration(zebra_daemon) # Generate empty helper string which can be ammended to FRR commands, it @@ -298,8 +297,9 @@ def apply(bgp): vrf = ' vrf ' + bgp['vrf'] frr_cfg.load_configuration(bgp_daemon) - frr_cfg.modify_section(f'^router bgp \d+{vrf}$', '') - frr_cfg.add_before(frr.default_add_before, bgp['frr_bgpd_config']) + frr_cfg.modify_section(f'^router bgp \d+{vrf}', stop_pattern='^exit', remove_stop_mark=True) + if 'frr_bgpd_config' in bgp: + frr_cfg.add_before(frr.default_add_before, bgp['frr_bgpd_config']) frr_cfg.commit_configuration(bgp_daemon) # Save configuration to /run/frr/config/frr.conf -- cgit v1.2.3 From f20c589da12810d5202b8f6eae262178467b60a4 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:01 +0100 Subject: ospfv3: T3753: adjust to new FRR 8.1 syntax --- data/templates/frr/ospf6d.frr.tmpl | 2 ++ src/conf_mode/protocols_ospfv3.py | 34 +++++++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 9 deletions(-) (limited to 'data') diff --git a/data/templates/frr/ospf6d.frr.tmpl b/data/templates/frr/ospf6d.frr.tmpl index c6527ed6c..5871b3d7a 100644 --- a/data/templates/frr/ospf6d.frr.tmpl +++ b/data/templates/frr/ospf6d.frr.tmpl @@ -41,6 +41,7 @@ interface {{ iface }} {% if iface_config.passive is defined %} ipv6 ospf6 passive {% endif %} +exit ! {% endfor %} {% endif %} @@ -87,4 +88,5 @@ router ospf6 redistribute {{ protocol }} {{ 'route-map ' + options.route_map if options.route_map is defined }} {% endfor %} {% endif %} +exit ! diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index bb05e65ac..374327798 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -20,6 +20,7 @@ from sys import exit from vyos.config import Config from vyos.configdict import dict_merge +from vyos.configdict import node_changed from vyos.configverify import verify_common_route_maps from vyos.template import render_to_string from vyos.ifconfig import Interface @@ -29,8 +30,6 @@ from vyos import frr from vyos import airbag airbag.enable() -frr_daemon = 'ospf6d' - def get_config(config=None): if config: conf = config @@ -39,8 +38,17 @@ def get_config(config=None): base = ['protocols', 'ospfv3'] ospfv3 = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + # FRR has VRF support for different routing daemons. As interfaces belong + # to VRFs - or the global VRF, we need to check for changed interfaces so + # that they will be properly rendered for the FRR config. Also this eases + # removal of interfaces from the running configuration. + interfaces_removed = node_changed(conf, base + ['interface']) + if interfaces_removed: + ospfv3['interface_removed'] = list(interfaces_removed) + # Bail out early if configuration tree does not exist if not conf.exists(base): + ospfv3.update({'deleted' : ''}) return ospfv3 # We also need some additional information from the config, prefix-lists @@ -70,21 +78,29 @@ def verify(ospfv3): return None def generate(ospfv3): - if not ospfv3: - ospfv3['new_frr_config'] = '' + if not ospfv3 or 'deleted' in ospfv3: return None ospfv3['new_frr_config'] = render_to_string('frr/ospf6d.frr.tmpl', ospfv3) return None def apply(ospfv3): + ospf6_daemon = 'ospf6d' + # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() - frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section(r'^interface \S+', '') - frr_cfg.modify_section('^router ospf6$', '') - frr_cfg.add_before(frr.default_add_before, ospfv3['new_frr_config']) - frr_cfg.commit_configuration(frr_daemon) + frr_cfg.load_configuration(ospf6_daemon) + frr_cfg.modify_section('^router ospf6', stop_pattern='^exit', remove_stop_mark=True) + + for key in ['interface', 'interface_removed']: + if key not in ospfv3: + continue + for interface in ospfv3[key]: + frr_cfg.modify_section(f'^interface {interface}', stop_pattern='^exit', remove_stop_mark=True) + + if 'new_frr_config' in ospfv3: + frr_cfg.add_before(frr.default_add_before, ospfv3['new_frr_config']) + frr_cfg.commit_configuration(ospf6_daemon) # Save configuration to /run/frr/config/frr.conf frr.save_configuration() -- cgit v1.2.3 From d1daf8e3c8a22e773ed0800ba2d9585a151ccb86 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:02 +0100 Subject: rip: T3753: adjust to new FRR 8.1 syntax --- data/templates/frr/ripd.frr.tmpl | 6 +++++- src/conf_mode/protocols_rip.py | 30 ++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) (limited to 'data') diff --git a/data/templates/frr/ripd.frr.tmpl b/data/templates/frr/ripd.frr.tmpl index cabc236f0..c44bb6d27 100644 --- a/data/templates/frr/ripd.frr.tmpl +++ b/data/templates/frr/ripd.frr.tmpl @@ -1,4 +1,3 @@ -! {# RIP key-chain definition #} {% if interface is defined and interface is not none %} {% for iface, iface_config in interface.items() %} @@ -9,7 +8,9 @@ key chain {{ iface }}-rip {% if key_options.password is defined and key_options.password is not none %} key-string {{ key_options.password }} {% endif %} + exit {% endfor %} +exit {% endif %} {% endfor %} {% endif %} @@ -31,6 +32,8 @@ interface {{ iface }} {% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} ip rip split-horizon poisoned-reverse {% endif %} +exit +! {% endfor %} {% endif %} ! @@ -89,6 +92,7 @@ router rip {% endif %} {% endif %} {% include 'frr/rip_ripng.frr.j2' %} +exit ! {% if route_map is defined and route_map is not none %} ip protocol rip route-map {{ route_map }} diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py index b7eaad745..96df41bdb 100755 --- a/src/conf_mode/protocols_rip.py +++ b/src/conf_mode/protocols_rip.py @@ -20,6 +20,7 @@ from sys import exit from vyos.config import Config from vyos.configdict import dict_merge +from vyos.configdict import node_changed from vyos.configverify import verify_common_route_maps from vyos.configverify import verify_access_list from vyos.configverify import verify_prefix_list @@ -39,8 +40,17 @@ def get_config(config=None): base = ['protocols', 'rip'] rip = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + # FRR has VRF support for different routing daemons. As interfaces belong + # to VRFs - or the global VRF, we need to check for changed interfaces so + # that they will be properly rendered for the FRR config. Also this eases + # removal of interfaces from the running configuration. + interfaces_removed = node_changed(conf, base + ['interface']) + if interfaces_removed: + rip['interface_removed'] = list(interfaces_removed) + # Bail out early if configuration tree does not exist if not conf.exists(base): + rip.update({'deleted' : ''}) return rip # We have gathered the dict representation of the CLI, but there are default @@ -89,12 +99,10 @@ def verify(rip): f'with "split-horizon disable" for "{interface}"!') def generate(rip): - if not rip: - rip['new_frr_config'] = '' + if not rip or 'deleted' in rip: return None rip['new_frr_config'] = render_to_string('frr/ripd.frr.tmpl', rip) - return None def apply(rip): @@ -106,15 +114,21 @@ def apply(rip): # The route-map used for the FIB (zebra) is part of the zebra daemon frr_cfg.load_configuration(zebra_daemon) - frr_cfg.modify_section(r'^ip protocol rip route-map [-a-zA-Z0-9.]+$', '') + frr_cfg.modify_section('^ip protocol rip route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') frr_cfg.commit_configuration(zebra_daemon) frr_cfg.load_configuration(rip_daemon) - frr_cfg.modify_section(r'key chain \S+', '') - frr_cfg.modify_section(r'interface \S+', '') - frr_cfg.modify_section('^router rip$', '') + frr_cfg.modify_section('^key chain \S+', stop_pattern='^exit', remove_stop_mark=True) + frr_cfg.modify_section('^router rip', stop_pattern='^exit', remove_stop_mark=True) + + for key in ['interface', 'interface_removed']: + if key not in rip: + continue + for interface in rip[key]: + frr_cfg.modify_section(f'^interface {interface}', stop_pattern='^exit', remove_stop_mark=True) - frr_cfg.add_before(frr.default_add_before, rip['new_frr_config']) + if 'new_frr_config' in rip: + frr_cfg.add_before(frr.default_add_before, rip['new_frr_config']) frr_cfg.commit_configuration(rip_daemon) # Save configuration to /run/frr/config/frr.conf -- cgit v1.2.3 From 1a96fb8a4424967f9d535df64c3119fc572d2f52 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:02 +0100 Subject: ripng: T3753: adjust to new FRR 8.1 syntax --- data/templates/frr/ripngd.frr.tmpl | 7 ++++++- smoketest/scripts/cli/test_protocols_ripng.py | 22 +++++++++++++++++++++- src/conf_mode/protocols_ripng.py | 24 ++++++++++++++++-------- 3 files changed, 43 insertions(+), 10 deletions(-) (limited to 'data') diff --git a/data/templates/frr/ripngd.frr.tmpl b/data/templates/frr/ripngd.frr.tmpl index 25df15121..ca7b9b5fb 100644 --- a/data/templates/frr/ripngd.frr.tmpl +++ b/data/templates/frr/ripngd.frr.tmpl @@ -1,4 +1,3 @@ -! {# Interface specific configuration #} {% if interface is defined and interface is not none %} {% for iface, iface_config in interface.items() %} @@ -9,6 +8,7 @@ interface {{ iface }} {% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} ipv6 rip split-horizon poisoned-reverse {% endif %} +exit {% endfor %} {% endif %} ! @@ -57,4 +57,9 @@ router ripng {% endif %} {% endif %} {% include 'frr/rip_ripng.frr.j2' %} +exit +! +{% if route_map is defined and route_map is not none %} +ipv6 protocol ripng route-map {{ route_map }} +{% endif %} ! diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py index 40585e778..53336a533 100755 --- a/smoketest/scripts/cli/test_protocols_ripng.py +++ b/smoketest/scripts/cli/test_protocols_ripng.py @@ -54,7 +54,7 @@ class TestProtocolsRIPng(VyOSUnitTestSHIM.TestCase): # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) - def test_ripng(self): + def test_ripng_01_parameters(self): metric = '8' interfaces = Section.interfaces('ethernet') aggregates = ['2001:db8:1000::/48', '2001:db8:2000::/48', '2001:db8:3000::/48'] @@ -121,5 +121,25 @@ class TestProtocolsRIPng(VyOSUnitTestSHIM.TestCase): proto = 'ospf6' self.assertIn(f' redistribute {proto} metric {metric} route-map {route_map}', frrconfig) + def test_ripng_02_zebra_route_map(self): + # Implemented because of T3328 + self.cli_set(base_path + ['route-map', route_map]) + # commit changes + self.cli_commit() + + # Verify FRR configuration + zebra_route_map = f'ipv6 protocol ripng route-map {route_map}' + frrconfig = self.getFRRconfig(zebra_route_map) + self.assertIn(zebra_route_map, frrconfig) + + # Remove the route-map again + self.cli_delete(base_path + ['route-map']) + # commit changes + self.cli_commit() + + # Verify FRR configuration + frrconfig = self.getFRRconfig(zebra_route_map) + self.assertNotIn(zebra_route_map, frrconfig) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/protocols_ripng.py b/src/conf_mode/protocols_ripng.py index eada236b5..d46a2216c 100755 --- a/src/conf_mode/protocols_ripng.py +++ b/src/conf_mode/protocols_ripng.py @@ -31,8 +31,6 @@ from vyos import frr from vyos import airbag airbag.enable() -frr_daemon = 'ripngd' - def get_config(config=None): if config: conf = config @@ -99,14 +97,24 @@ def generate(ripng): return None def apply(ripng): + ripng_daemon = 'ripngd' + zebra_daemon = 'zebra' + # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() - frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section(r'key chain \S+', '') - frr_cfg.modify_section(r'interface \S+', '') - frr_cfg.modify_section('router ripng', '') - frr_cfg.add_before(frr.default_add_before, ripng['new_frr_config']) - frr_cfg.commit_configuration(frr_daemon) + + # The route-map used for the FIB (zebra) is part of the zebra daemon + frr_cfg.load_configuration(zebra_daemon) + frr_cfg.modify_section('^ipv6 protocol ripng route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') + frr_cfg.commit_configuration(zebra_daemon) + + frr_cfg.load_configuration(ripng_daemon) + frr_cfg.modify_section('key chain \S+', stop_pattern='^exit', remove_stop_mark=True) + frr_cfg.modify_section('interface \S+', stop_pattern='^exit', remove_stop_mark=True) + frr_cfg.modify_section('^router ripng', stop_pattern='^exit', remove_stop_mark=True) + if 'new_frr_config' in ripng: + frr_cfg.add_before(frr.default_add_before, ripng['new_frr_config']) + frr_cfg.commit_configuration(ripng_daemon) # Save configuration to /run/frr/config/frr.conf frr.save_configuration() -- cgit v1.2.3 From 5f2e797d8f33b995afdfa02953f461ac6d2fc88c Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:02 +0100 Subject: rpki: T3753: adjust to new FRR 8.1 syntax --- data/templates/frr/rpki.frr.tmpl | 1 + smoketest/scripts/cli/test_protocols_rpki.py | 2 -- src/conf_mode/protocols_rpki.py | 17 +++++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'data') diff --git a/data/templates/frr/rpki.frr.tmpl b/data/templates/frr/rpki.frr.tmpl index fbdfa27c3..7f9823f6b 100644 --- a/data/templates/frr/rpki.frr.tmpl +++ b/data/templates/frr/rpki.frr.tmpl @@ -14,4 +14,5 @@ rpki {% if polling_period is defined and polling_period is not none %} rpki polling_period {{ polling_period }} {% endif %} +exit ! diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py index d9792ce8d..e5e45565b 100755 --- a/smoketest/scripts/cli/test_protocols_rpki.py +++ b/smoketest/scripts/cli/test_protocols_rpki.py @@ -36,8 +36,6 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Nothing RPKI specific should be left over in the config - # - # Disabled until T3266 is resolved # frrconfig = self.getFRRconfig('rpki') # self.assertNotIn('rpki', frrconfig) diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py index 0688e542f..41ce1f1fd 100755 --- a/src/conf_mode/protocols_rpki.py +++ b/src/conf_mode/protocols_rpki.py @@ -28,8 +28,6 @@ from vyos import frr from vyos import airbag airbag.enable() -frr_daemon = 'bgpd' - def get_config(config=None): if config: conf = config @@ -38,7 +36,9 @@ def get_config(config=None): base = ['protocols', 'rpki'] rpki = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + # Bail out early if configuration tree does not exist if not conf.exists(base): + rpki.update({'deleted' : ''}) return rpki # We have gathered the dict representation of the CLI, but there are default @@ -79,16 +79,21 @@ def verify(rpki): return None def generate(rpki): + if not rpki: + return rpki['new_frr_config'] = render_to_string('frr/rpki.frr.tmpl', rpki) return None def apply(rpki): + bgp_daemon = 'bgpd' + # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() - frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section('rpki', '') - frr_cfg.add_before(frr.default_add_before, rpki['new_frr_config']) - frr_cfg.commit_configuration(frr_daemon) + frr_cfg.load_configuration(bgp_daemon) + frr_cfg.modify_section('^rpki') + if 'new_frr_config' in rpki: + frr_cfg.add_before(frr.default_add_before, rpki['new_frr_config']) + frr_cfg.commit_configuration(bgp_daemon) return None -- cgit v1.2.3 From df37032ddf58afeff91cfa2b4b0e815a17d44243 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Nov 2021 10:32:02 +0100 Subject: isis: T3753: adjust to new FRR 8.1 syntax --- data/templates/frr/isisd.frr.tmpl | 91 ++++++++++++++-------------- smoketest/scripts/cli/test_protocols_isis.py | 3 +- src/conf_mode/protocols_isis.py | 22 +++---- 3 files changed, 59 insertions(+), 57 deletions(-) (limited to 'data') diff --git a/data/templates/frr/isisd.frr.tmpl b/data/templates/frr/isisd.frr.tmpl index 51ac40060..fc0799e02 100644 --- a/data/templates/frr/isisd.frr.tmpl +++ b/data/templates/frr/isisd.frr.tmpl @@ -1,4 +1,50 @@ ! +{% 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 }} + ip router isis VyOS + ipv6 router isis VyOS +{% if iface_config.bfd is defined %} + isis bfd +{% endif %} +{% if iface_config.network is defined and iface_config.network.point_to_point is defined %} + isis network point-to-point +{% endif %} +{% if iface_config.circuit_type is defined %} + isis circuit-type {{ iface_config.circuit_type }} +{% endif %} +{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} + isis hello-interval {{ iface_config.hello_interval }} +{% endif %} +{% if iface_config.hello_multiplier is defined and iface_config.hello_multiplier is not none %} + isis hello-multiplier {{ iface_config.hello_multiplier }} +{% endif %} +{% if iface_config.hello_padding is defined %} + isis hello padding +{% endif %} +{% if iface_config.metric is defined and iface_config.metric is not none %} + isis metric {{ iface_config.metric }} +{% endif %} +{% if iface_config.passive is defined %} + isis passive +{% endif %} +{% if iface_config.password is defined and iface_config.password.plaintext_password is defined and iface_config.password.plaintext_password is not none %} + isis password clear {{ iface_config.password.plaintext_password }} +{% endif %} +{% if iface_config.priority is defined and iface_config.priority is not none %} + isis priority {{ iface_config.priority }} +{% endif %} +{% if iface_config.psnp_interval is defined and iface_config.psnp_interval is not none %} + isis psnp-interval {{ iface_config.psnp_interval }} +{% endif %} +{% if iface_config.no_three_way_handshake is defined %} + no isis three-way-handshake +{% endif %} +exit +! +{% endfor %} +{% endif %} +! router isis VyOS {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} net {{ net }} {% if dynamic_hostname is defined %} @@ -151,48 +197,5 @@ router isis VyOS {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} is-type {{ level }} {% endif %} {% endif %} -! -{% 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 }} - ip router isis VyOS - ipv6 router isis VyOS -{% if iface_config.bfd is defined %} - isis bfd -{% endif %} -{% if iface_config.network is defined and iface_config.network.point_to_point is defined %} - isis network point-to-point -{% endif %} -{% if iface_config.circuit_type is defined %} - isis circuit-type {{ iface_config.circuit_type }} -{% endif %} -{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} - isis hello-interval {{ iface_config.hello_interval }} -{% endif %} -{% if iface_config.hello_multiplier is defined and iface_config.hello_multiplier is not none %} - isis hello-multiplier {{ iface_config.hello_multiplier }} -{% endif %} -{% if iface_config.hello_padding is defined %} - isis hello padding -{% endif %} -{% if iface_config.metric is defined and iface_config.metric is not none %} - isis metric {{ iface_config.metric }} -{% endif %} -{% if iface_config.passive is defined %} - isis passive -{% endif %} -{% if iface_config.password is defined and iface_config.password.plaintext_password is defined and iface_config.password.plaintext_password is not none %} - isis password clear {{ iface_config.password.plaintext_password }} -{% endif %} -{% if iface_config.priority is defined and iface_config.priority is not none %} - isis priority {{ iface_config.priority }} -{% endif %} -{% if iface_config.psnp_interval is defined and iface_config.psnp_interval is not none %} - isis psnp-interval {{ iface_config.psnp_interval }} -{% endif %} -{% if iface_config.no_three_way_handshake is defined %} - no isis three-way-handshake -{% endif %} -{% endfor %} -{% endif %} +exit ! \ No newline at end of file diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py index 949198ee6..e42040025 100755 --- a/smoketest/scripts/cli/test_protocols_isis.py +++ b/smoketest/scripts/cli/test_protocols_isis.py @@ -199,8 +199,6 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): def test_isis_06_spf_delay(self): - self.isis_base_config() - network = 'point-to-point' holddown = '10' init_delay = '50' @@ -208,6 +206,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): short_delay = '100' time_to_learn = '75' + self.cli_set(base_path + ['net', net]) for interface in self._interfaces: self.cli_set(base_path + ['interface', interface, 'network', network]) diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py index 120fc68a0..3a0c40dc6 100755 --- a/src/conf_mode/protocols_isis.py +++ b/src/conf_mode/protocols_isis.py @@ -56,10 +56,10 @@ def get_config(config=None): # instead of the VRF instance. if vrf: isis['vrf'] = vrf - # As we no re-use this Python handler for both VRF and non VRF instances for - # IS-IS we need to find out if any interfaces changed so properly adjust - # the FRR configuration and not by acctident change interfaces from a - # different VRF. + # FRR has VRF support for different routing daemons. As interfaces belong + # to VRFs - or the global VRF, we need to check for changed interfaces so + # that they will be properly rendered for the FRR config. Also this eases + # removal of interfaces from the running configuration. interfaces_removed = node_changed(conf, base + ['interface']) if interfaces_removed: isis['interface_removed'] = list(interfaces_removed) @@ -196,8 +196,6 @@ def verify(isis): def generate(isis): if not isis or 'deleted' in isis: - isis['frr_isisd_config'] = '' - isis['frr_zebra_config'] = '' return None isis['protocol'] = 'isis' # required for frr/vrf.route-map.frr.tmpl @@ -214,8 +212,9 @@ def apply(isis): # The route-map used for the FIB (zebra) is part of the zebra daemon frr_cfg.load_configuration(zebra_daemon) - frr_cfg.modify_section(r'(\s+)?ip protocol isis route-map [-a-zA-Z0-9.]+$', '', '(\s|!)') - frr_cfg.add_before(frr.default_add_before, isis['frr_zebra_config']) + frr_cfg.modify_section('(\s+)?ip protocol isis route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') + if 'frr_zebra_config' in isis: + frr_cfg.add_before(frr.default_add_before, isis['frr_zebra_config']) frr_cfg.commit_configuration(zebra_daemon) # Generate empty helper string which can be ammended to FRR commands, it @@ -225,15 +224,16 @@ def apply(isis): vrf = ' vrf ' + isis['vrf'] frr_cfg.load_configuration(isis_daemon) - frr_cfg.modify_section(f'^router isis VyOS{vrf}$', '') + frr_cfg.modify_section(f'^router isis VyOS{vrf}', stop_pattern='^exit', remove_stop_mark=True) for key in ['interface', 'interface_removed']: if key not in isis: continue for interface in isis[key]: - frr_cfg.modify_section(f'^interface {interface}{vrf}$', '') + frr_cfg.modify_section(f'^interface {interface}{vrf}', stop_pattern='^exit', remove_stop_mark=True) - frr_cfg.add_before(frr.default_add_before, isis['frr_isisd_config']) + if 'frr_isisd_config' in isis: + frr_cfg.add_before(frr.default_add_before, isis['frr_isisd_config']) frr_cfg.commit_configuration(isis_daemon) # Save configuration to /run/frr/config/frr.conf -- cgit v1.2.3 From 192903561e5d7211155554fe06c18673fa74e1ed Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 28 Nov 2021 10:00:57 +0100 Subject: ospfv3: T3928: add VRF support set vrf name foo protocols ospfv3 --- data/templates/frr/ospf6d.frr.tmpl | 4 +- .../include/ospfv3/protocol-common-config.xml.i | 241 +++++++++++++++++++++ interface-definitions/protocols-ospfv3.xml.in | 240 +------------------- interface-definitions/vrf.xml.in | 9 + smoketest/scripts/cli/test_protocols_ospfv3.py | 39 ++++ src/conf_mode/protocols_ospfv3.py | 46 +++- 6 files changed, 331 insertions(+), 248 deletions(-) create mode 100644 interface-definitions/include/ospfv3/protocol-common-config.xml.i (limited to 'data') diff --git a/data/templates/frr/ospf6d.frr.tmpl b/data/templates/frr/ospf6d.frr.tmpl index 5871b3d7a..10a6d9b4b 100644 --- a/data/templates/frr/ospf6d.frr.tmpl +++ b/data/templates/frr/ospf6d.frr.tmpl @@ -1,7 +1,7 @@ ! {% if interface is defined and interface is not none %} {% for iface, iface_config in interface.items() %} -interface {{ iface }} +interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% if iface_config.area is defined and iface_config.area is not none %} ipv6 ospf6 area {{ iface_config.area }} {% endif %} @@ -46,7 +46,7 @@ exit {% endfor %} {% endif %} ! -router ospf6 +router ospf6 {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% 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 %} diff --git a/interface-definitions/include/ospfv3/protocol-common-config.xml.i b/interface-definitions/include/ospfv3/protocol-common-config.xml.i new file mode 100644 index 000000000..a93939a34 --- /dev/null +++ b/interface-definitions/include/ospfv3/protocol-common-config.xml.i @@ -0,0 +1,241 @@ + + + + OSPFv3 Area + + u32 + Area ID as a decimal value + + + ipv4 + Area ID in IP address forma + + + + + + + + + + OSPFv3 Area type + + + + + Stub OSPFv3 area + + + + + Do not inject inter-area routes into the stub + + + + + + + + + + Name of export-list + + policy access-list6 + + + + + + Name of import-list + + policy access-list6 + + + + + + Specify IPv6 prefix (border routers only) + + ipv6net + Specify IPv6 prefix (border routers only) + + + + + + + + + Advertise this range + + + + + + Do not advertise this range + + + + + + + + + + Administrative distance + + + #include + + + OSPFv3 administrative distance + + + #include + + + + + + + Enable routing on an IPv6 interface + + + + + txt + Interface used for routing information exchange + + + + + + + + + Enable OSPF on this interface + + protocols ospfv3 area + + + u32 + OSPF area ID as decimal notation + + + ipv4 + OSPF area ID in IP address notation + + + + + + + + #include + #include + + + Interface MTU + + u32:1-65535 + Interface MTU + + + + + + + + + Instance Id (default: 0) + + u32:0-255 + Instance Id + + + + + + 0 + + + + Network type + + broadcast point-to-point + + + broadcast + Broadcast network type + + + point-to-point + Point-to-point network type + + + ^(broadcast|point-to-point)$ + + Must be broadcast or point-to-point + + + #include + + +#include + + + OSPFv3 specific parameters + + + #include + + + + + Redistribute information from another routing protocol + + + + + Redistribute BGP routes + + + #include + + + + + Redistribute connected routes + + + #include + + + + + Redistribute kernel routes + + + #include + + + + + Redistribute RIPNG routes + + + #include + + + + + Redistribute static routes + + + #include + + + + +#include + diff --git a/interface-definitions/protocols-ospfv3.xml.in b/interface-definitions/protocols-ospfv3.xml.in index c7a94d58c..2b98ffa7b 100644 --- a/interface-definitions/protocols-ospfv3.xml.in +++ b/interface-definitions/protocols-ospfv3.xml.in @@ -8,245 +8,7 @@ 620 - - - OSPFv3 Area - - u32 - Area ID as a decimal value - - - ipv4 - Area ID in IP address forma - - - - - - - - - - OSPFv3 Area type - - - - - Stub OSPFv3 area - - - - - Do not inject inter-area routes into the stub - - - - - - - - - - Name of export-list - - policy access-list6 - - - - - - Name of import-list - - policy access-list6 - - - - - - Specify IPv6 prefix (border routers only) - - ipv6net - Specify IPv6 prefix (border routers only) - - - - - - - - - Advertise this range - - - - - - Do not advertise this range - - - - - - - - - - Administrative distance - - - #include - - - OSPFv3 administrative distance - - - #include - - - - - - - Enable routing on an IPv6 interface - - - - - txt - Interface used for routing information exchange - - - - - - - - - Enable OSPF on this interface - - protocols ospfv3 area - - - u32 - OSPF area ID as decimal notation - - - ipv4 - OSPF area ID in IP address notation - - - - - - - - #include - #include - - - Interface MTU - - u32:1-65535 - Interface MTU - - - - - - - - - Instance Id (default: 0) - - u32:0-255 - Instance Id - - - - - - 0 - - - - Network type - - broadcast point-to-point - - - broadcast - Broadcast network type - - - point-to-point - Point-to-point network type - - - ^(broadcast|point-to-point)$ - - Must be broadcast or point-to-point - - - #include - - - #include - - - OSPFv3 specific parameters - - - #include - - - - - Redistribute information from another routing protocol - - - - - Redistribute BGP routes - - - #include - - - - - Redistribute connected routes - - - #include - - - - - Redistribute kernel routes - - - #include - - - - - Redistribute RIPNG routes - - - #include - - - - - Redistribute static routes - - - #include - - - - - #include + #include diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in index d6a602f53..14c31fa8a 100644 --- a/interface-definitions/vrf.xml.in +++ b/interface-definitions/vrf.xml.in @@ -60,6 +60,15 @@ #include + + + Open Shortest Path First (OSPF) for IPv6 + 621 + + + #include + + Static route parameters diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py index 8e12990d5..f0557f640 100755 --- a/smoketest/scripts/cli/test_protocols_ospfv3.py +++ b/smoketest/scripts/cli/test_protocols_ospfv3.py @@ -167,5 +167,44 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): self.assertIn(f' area {area_stub} stub', frrconfig) self.assertIn(f' area {area_stub_nosum} stub no-summary', frrconfig) + + def test_ospfv3_06_vrfs(self): + # It is safe to assume that when the basic VRF test works, all + # other OSPF related features work, as we entirely inherit the CLI + # templates and Jinja2 FRR template. + table = '1000' + vrf = 'blue' + vrf_base = ['vrf', 'name', vrf] + vrf_iface = 'eth1' + router_id = '1.2.3.4' + router_id_vrf = '1.2.3.5' + + self.cli_set(vrf_base + ['table', table]) + self.cli_set(vrf_base + ['protocols', 'ospfv3', 'interface', vrf_iface, 'bfd']) + self.cli_set(vrf_base + ['protocols', 'ospfv3', 'parameters', 'router-id', router_id_vrf]) + + self.cli_set(['interfaces', 'ethernet', vrf_iface, 'vrf', vrf]) + + # Also set a default VRF OSPF config + self.cli_set(base_path + ['parameters', 'router-id', router_id]) + self.cli_commit() + + # Verify FRR ospfd configuration + frrconfig = self.getFRRconfig('router ospf6') + self.assertIn(f'router ospf6', frrconfig) + self.assertIn(f' ospf6 router-id {router_id}', frrconfig) + + frrconfig = self.getFRRconfig(f'interface {vrf_iface} vrf {vrf}') + self.assertIn(f'interface {vrf_iface} vrf {vrf}', frrconfig) + self.assertIn(f' ipv6 ospf6 bfd', frrconfig) + + frrconfig = self.getFRRconfig(f'router ospf6 vrf {vrf}') + self.assertIn(f'router ospf6 vrf {vrf}', frrconfig) + self.assertIn(f' ospf6 router-id {router_id_vrf}', frrconfig) + + # cleanup + self.cli_delete(['vrf', 'name', vrf]) + self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf']) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index f1e490f48..d0460b830 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -17,6 +17,7 @@ import os from sys import exit +from sys import argv from vyos.config import Config from vyos.configdict import dict_merge @@ -24,6 +25,7 @@ from vyos.configdict import node_changed from vyos.configverify import verify_common_route_maps from vyos.template import render_to_string from vyos.ifconfig import Interface +from vyos.util import get_interface_config from vyos.xml import defaults from vyos import ConfigError from vyos import frr @@ -35,9 +37,22 @@ def get_config(config=None): conf = config else: conf = Config() - base = ['protocols', 'ospfv3'] + + vrf = None + if len(argv) > 1: + vrf = argv[1] + + base_path = ['protocols', 'ospfv3'] + + # eqivalent of the C foo ? 'a' : 'b' statement + base = vrf and ['vrf', 'name', vrf, 'protocols', 'ospfv3'] or base_path ospfv3 = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + # Assign the name of our VRF context. This MUST be done before the return + # statement below, else on deletion we will delete the default instance + # instead of the VRF instance. + if vrf: ospfv3['vrf'] = vrf + # FRR has VRF support for different routing daemons. As interfaces belong # to VRFs - or the global VRF, we need to check for changed interfaces so # that they will be properly rendered for the FRR config. Also this eases @@ -69,12 +84,22 @@ def verify(ospfv3): verify_common_route_maps(ospfv3) if 'interface' in ospfv3: - for ifname, if_config in ospfv3['interface'].items(): - if 'ifmtu' in if_config: - mtu = Interface(ifname).get_mtu() - if int(if_config['ifmtu']) > int(mtu): + for interface, interface_config in ospfv3['interface'].items(): + if 'ifmtu' in interface_config: + mtu = Interface(interface).get_mtu() + if int(interface_config['ifmtu']) > int(mtu): raise ConfigError(f'OSPFv3 ifmtu can not exceed physical MTU of "{mtu}"') + # If interface specific options are set, we must ensure that the + # interface is bound to our requesting VRF. Due to the VyOS + # priorities the interface is bound to the VRF after creation of + # the VRF itself, and before any routing protocol is configured. + if 'vrf' in ospfv3: + vrf = ospfv3['vrf'] + tmp = get_interface_config(interface) + if 'master' not in tmp or tmp['master'] != vrf: + raise ConfigError(f'Interface {interface} is not a member of VRF {vrf}!') + return None def generate(ospfv3): @@ -89,14 +114,21 @@ def apply(ospfv3): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() + + # Generate empty helper string which can be ammended to FRR commands, it + # will be either empty (default VRF) or contain the "vrf