diff options
author | Daniil Baturin <daniil@vyos.io> | 2025-06-12 15:20:21 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-06-12 15:20:21 +0100 |
commit | dcba87b2394b789c335b44856a8ae7bfea05353c (patch) | |
tree | 3789462504fe665ff59490527d10f5d0fd625b21 | |
parent | 71f4f8c55ae660ae39113981a44bd1cd7ef77394 (diff) | |
parent | 05d71332442b244f488792000bf93c96f12c9b46 (diff) | |
download | vyos-1x-dcba87b2394b789c335b44856a8ae7bfea05353c.tar.gz vyos-1x-dcba87b2394b789c335b44856a8ae7bfea05353c.zip |
Merge pull request #4497 from yzguy/T7432
T7432: RPKI VRF Support
-rw-r--r-- | data/templates/frr/rpki.frr.j2 | 28 | ||||
-rw-r--r-- | interface-definitions/include/rpki/protocol-common-config.xml.i | 87 | ||||
-rw-r--r-- | interface-definitions/protocols_rpki.xml.in | 86 | ||||
-rw-r--r-- | interface-definitions/vrf.xml.in | 9 | ||||
-rw-r--r-- | op-mode-definitions/include/rpki/vrf.xml.i | 11 | ||||
-rw-r--r-- | op-mode-definitions/rpki.xml.in | 57 | ||||
-rw-r--r-- | python/vyos/frrender.py | 17 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_rpki.py | 187 | ||||
-rwxr-xr-x | src/conf_mode/protocols_rpki.py | 17 |
9 files changed, 316 insertions, 183 deletions
diff --git a/data/templates/frr/rpki.frr.j2 b/data/templates/frr/rpki.frr.j2 index edf0ccaa2..e35f99766 100644 --- a/data/templates/frr/rpki.frr.j2 +++ b/data/templates/frr/rpki.frr.j2 @@ -1,8 +1,8 @@ -! +{% macro rpki_config(rpki) %} {# as FRR does not support deleting the entire rpki section we leave it in place even when it's empty #} rpki -{% if cache is vyos_defined %} -{% for peer, peer_config in cache.items() %} +{% if rpki.cache is vyos_defined %} +{% for peer, peer_config in rpki.cache.items() %} {# port is mandatory and preference uses a default value #} {% if peer_config.ssh.username is vyos_defined %} rpki cache ssh {{ peer | replace('_', '-') }} {{ peer_config.port }} {{ peer_config.ssh.username }} {{ peer_config.ssh.private_key_file }} {{ peer_config.ssh.public_key_file }}{{ ' source ' ~ peer_config.source_address if peer_config.source_address is vyos_defined }} preference {{ peer_config.preference }} @@ -11,14 +11,24 @@ rpki {% endif %} {% endfor %} {% endif %} -{% if expire_interval is vyos_defined %} - rpki expire_interval {{ expire_interval }} +{% if rpki.expire_interval is vyos_defined %} + rpki expire_interval {{ rpki.expire_interval }} {% endif %} -{% if polling_period is vyos_defined %} - rpki polling_period {{ polling_period }} +{% if rpki.polling_period is vyos_defined %} + rpki polling_period {{ rpki.polling_period }} {% endif %} -{% if retry_interval is vyos_defined %} - rpki retry_interval {{ retry_interval }} +{% if rpki.retry_interval is vyos_defined %} + rpki retry_interval {{ rpki.retry_interval }} {% endif %} exit +{# j2lint: disable=jinja-statements-delimeter #} +{%- endmacro -%} +! +{% if rpki.vrf is vyos_defined %} +vrf {{ rpki.vrf }} + {{ rpki_config(rpki) | indent(width=1) }} +exit-vrf +{% else %} +{{ rpki_config(rpki) }} +{% endif %} ! diff --git a/interface-definitions/include/rpki/protocol-common-config.xml.i b/interface-definitions/include/rpki/protocol-common-config.xml.i new file mode 100644 index 000000000..0b3356604 --- /dev/null +++ b/interface-definitions/include/rpki/protocol-common-config.xml.i @@ -0,0 +1,87 @@ +<!-- include start from rpki/protocol-common-config.xml.i --> +<tagNode name="cache"> + <properties> + <help>RPKI cache server address</help> + <valueHelp> + <format>ipv4</format> + <description>IP address of RPKI server</description> + </valueHelp> + <valueHelp> + <format>ipv6</format> + <description>IPv6 address of RPKI server</description> + </valueHelp> + <valueHelp> + <format>hostname</format> + <description>Fully qualified domain name of RPKI server</description> + </valueHelp> + <constraint> + <validator name="ip-address"/> + <validator name="fqdn"/> + </constraint> + </properties> + <children> + #include <include/port-number.xml.i> + <leafNode name="preference"> + <properties> + <help>Preference of the cache server</help> + <valueHelp> + <format>u32:1-255</format> + <description>Preference of the cache server</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-255"/> + </constraint> + </properties> + </leafNode> + #include <include/source-address-ipv4.xml.i> + <node name="ssh"> + <properties> + <help>RPKI SSH connection settings</help> + </properties> + <children> + #include <include/pki/openssh-key.xml.i> + #include <include/generic-username.xml.i> + </children> + </node> + </children> +</tagNode> +<leafNode name="expire-interval"> + <properties> + <help>Interval to wait before expiring the cache</help> + <valueHelp> + <format>u32:600-172800</format> + <description>Interval in seconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 600-172800"/> + </constraint> + </properties> + <defaultValue>7200</defaultValue> +</leafNode> +<leafNode name="polling-period"> + <properties> + <help>Cache polling interval</help> + <valueHelp> + <format>u32:1-86400</format> + <description>Interval in seconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-86400"/> + </constraint> + </properties> + <defaultValue>300</defaultValue> +</leafNode> +<leafNode name="retry-interval"> + <properties> + <help>Retry interval to connect to the cache server</help> + <valueHelp> + <format>u32:1-7200</format> + <description>Interval in seconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-7200"/> + </constraint> + </properties> + <defaultValue>600</defaultValue> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/protocols_rpki.xml.in b/interface-definitions/protocols_rpki.xml.in index 9e2e84717..a298cdbfd 100644 --- a/interface-definitions/protocols_rpki.xml.in +++ b/interface-definitions/protocols_rpki.xml.in @@ -8,91 +8,7 @@ <priority>819</priority> </properties> <children> - <tagNode name="cache"> - <properties> - <help>RPKI cache server address</help> - <valueHelp> - <format>ipv4</format> - <description>IP address of RPKI server</description> - </valueHelp> - <valueHelp> - <format>ipv6</format> - <description>IPv6 address of RPKI server</description> - </valueHelp> - <valueHelp> - <format>hostname</format> - <description>Fully qualified domain name of RPKI server</description> - </valueHelp> - <constraint> - <validator name="ip-address"/> - <validator name="fqdn"/> - </constraint> - </properties> - <children> - #include <include/port-number.xml.i> - <leafNode name="preference"> - <properties> - <help>Preference of the cache server</help> - <valueHelp> - <format>u32:1-255</format> - <description>Preference of the cache server</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-255"/> - </constraint> - </properties> - </leafNode> - #include <include/source-address-ipv4.xml.i> - <node name="ssh"> - <properties> - <help>RPKI SSH connection settings</help> - </properties> - <children> - #include <include/pki/openssh-key.xml.i> - #include <include/generic-username.xml.i> - </children> - </node> - </children> - </tagNode> - <leafNode name="expire-interval"> - <properties> - <help>Interval to wait before expiring the cache</help> - <valueHelp> - <format>u32:600-172800</format> - <description>Interval in seconds</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 600-172800"/> - </constraint> - </properties> - <defaultValue>7200</defaultValue> - </leafNode> - <leafNode name="polling-period"> - <properties> - <help>Cache polling interval</help> - <valueHelp> - <format>u32:1-86400</format> - <description>Interval in seconds</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-86400"/> - </constraint> - </properties> - <defaultValue>300</defaultValue> - </leafNode> - <leafNode name="retry-interval"> - <properties> - <help>Retry interval to connect to the cache server</help> - <valueHelp> - <format>u32:1-7200</format> - <description>Interval in seconds</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-7200"/> - </constraint> - </properties> - <defaultValue>600</defaultValue> - </leafNode> + #include <include/rpki/protocol-common-config.xml.i> </children> </node> </children> diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in index a20be995a..03128cb99 100644 --- a/interface-definitions/vrf.xml.in +++ b/interface-definitions/vrf.xml.in @@ -95,6 +95,15 @@ #include <include/ospfv3/protocol-common-config.xml.i> </children> </node> + <node name="rpki" owner="${vyos_conf_scripts_dir}/protocols_rpki.py $VAR(../../@)"> + <properties> + <help>Resource Public Key Infrastructure (RPKI)</help> + <priority>820</priority> + </properties> + <children> + #include <include/rpki/protocol-common-config.xml.i> + </children> + </node> <node name="static" owner="${vyos_conf_scripts_dir}/protocols_static.py $VAR(../../@)"> <properties> <help>Static Routing</help> diff --git a/op-mode-definitions/include/rpki/vrf.xml.i b/op-mode-definitions/include/rpki/vrf.xml.i new file mode 100644 index 000000000..5b6518fee --- /dev/null +++ b/op-mode-definitions/include/rpki/vrf.xml.i @@ -0,0 +1,11 @@ +<!-- include start from rpki/vrf.xml.i --> +<tagNode name="vrf"> + <properties> + <help>Virtual Routing and Forwarding (VRF)</help> + <completionHelp> + <path>vrf name</path> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<!-- include end --> diff --git a/op-mode-definitions/rpki.xml.in b/op-mode-definitions/rpki.xml.in index 9e0f83e20..4753cfb93 100644 --- a/op-mode-definitions/rpki.xml.in +++ b/op-mode-definitions/rpki.xml.in @@ -15,19 +15,28 @@ </completionHelp> </properties> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/rpki/vrf.xml.i> + </children> </tagNode> - <leafNode name="cache-connection"> + <node name="cache-connection"> <properties> <help>Show RPKI cache connections</help> </properties> - <command>vtysh -c "show rpki cache-connection"</command> - </leafNode> - <leafNode name="cache-server"> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/rpki/vrf.xml.i> + </children> + </node> + <node name="cache-server"> <properties> <help>Show RPKI cache servers information</help> </properties> - <command>vtysh -c "show rpki cache-server"</command> - </leafNode> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/rpki/vrf.xml.i> + </children> + </node> <tagNode name="prefix"> <properties> <help>Lookup IP prefix and optionally ASN in prefix table</help> @@ -45,27 +54,53 @@ </completionHelp> </properties> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $(echo $@ | sed -e "s/as-number //g")</command> + <children> + <tagNode name="vrf"> + <properties> + <help>Virtual Routing and Forwarding (VRF)</help> + <completionHelp> + <path>vrf name</path> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $(echo $@ | sed -e "s/as-number //g")</command> + </tagNode> + </children> </tagNode> + #include <include/rpki/vrf.xml.i> </children> </tagNode> - <leafNode name="prefix-table"> + <node name="prefix-table"> <properties> <help>Show RPKI-validated prefixes</help> </properties> - <command>vtysh -c "show rpki prefix-table"</command> - </leafNode> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/rpki/vrf.xml.i> + </children> + </node> </children> </node> </children> </node> <node name="reset"> <children> - <leafNode name="rpki"> + <node name="rpki"> <properties> <help>Reset RPKI</help> </properties> <command>vtysh -c "rpki reset"</command> - </leafNode> + <children> + <tagNode name="vrf"> + <properties> + <help>Reset RPKI in VRF</help> + <completionHelp> + <path>vrf name</path> + </completionHelp> + </properties> + <command>vtysh -c "rpki reset vrf $4"</command> + </tagNode> + </children> + </node> </children> </node> </interfaceDefinition> diff --git a/python/vyos/frrender.py b/python/vyos/frrender.py index 73d6dd5f0..d9e409cb4 100644 --- a/python/vyos/frrender.py +++ b/python/vyos/frrender.py @@ -543,6 +543,21 @@ def get_frrender_dict(conf, argv=None) -> dict: elif conf.exists_effective(ospfv3_vrf_path): vrf['name'][vrf_name]['protocols'].update({'ospfv3' : {'deleted' : ''}}) + # We need to check the CLI if the RPKI node is present and thus load in all the default + # values present on the CLI - that's why we have if conf.exists() + rpki_vrf_path = ['vrf', 'name', vrf_name, 'protocols', 'rpki'] + if 'rpki' in vrf_config.get('protocols', []): + rpki = conf.get_config_dict(rpki_vrf_path, key_mangling=('-', '_'), get_first_key=True, + with_pki=True, with_recursive_defaults=True) + rpki_ssh_key_base = '/run/frr/id_rpki' + for cache, cache_config in rpki.get('cache',{}).items(): + if 'ssh' in cache_config: + cache_config['ssh']['public_key_file'] = f'{rpki_ssh_key_base}_{cache}.pub' + cache_config['ssh']['private_key_file'] = f'{rpki_ssh_key_base}_{cache}' + vrf['name'][vrf_name]['protocols'].update({'rpki' : rpki}) + elif conf.exists_effective(rpki_vrf_path): + vrf['name'][vrf_name]['protocols'].update({'rpki' : {'deleted' : ''}}) + # We need to check the CLI if the static node is present and thus load in all the default # values present on the CLI - that's why we have if conf.exists() static_vrf_path = ['vrf', 'name', vrf_name, 'protocols', 'static'] @@ -675,7 +690,7 @@ class FRRender: output += render_to_string('frr/ripngd.frr.j2', config_dict['ripng']) output += '\n' if 'rpki' in config_dict and 'deleted' not in config_dict['rpki']: - output += render_to_string('frr/rpki.frr.j2', config_dict['rpki']) + output += render_to_string('frr/rpki.frr.j2', {'rpki': config_dict['rpki']}) output += '\n' if 'segment_routing' in config_dict and 'deleted' not in config_dict['segment_routing']: output += render_to_string('frr/zebra.segment_routing.frr.j2', config_dict['segment_routing']) diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py index 0addf7fee..5ea257088 100755 --- a/smoketest/scripts/cli/test_protocols_rpki.py +++ b/smoketest/scripts/cli/test_protocols_rpki.py @@ -25,6 +25,11 @@ from vyos.utils.file import read_file from vyos.utils.process import process_named_running base_path = ['protocols', 'rpki'] +base_frr_config_args = {'string': 'rpki', 'endsection': '^exit'} +vrf = 'blue' +vrf_path = ['vrf', 'name', vrf] +vrf_frr_config_args = {'string': f'vrf {vrf}', 'endsection':'^exit-vrf', + 'substring': ' rpki', 'endsubsection': '^ exit'} rpki_key_name = 'rpki-smoketest' rpki_key_type = 'ssh-rsa' @@ -112,14 +117,19 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): # ensure we can also run this test on a live system - so lets clean # out the current configuration :) cls.cli_delete(cls, base_path) + cls.cli_delete(cls, vrf_path) # Enable CSTORE guard time required by FRR related tests cls._commit_guard_time = CSTORE_GUARD_TIME def tearDown(self): self.cli_delete(base_path) + self.cli_delete(vrf_path) self.cli_commit() - frrconfig = self.getFRRconfig('rpki', endsection='^exit') + frrconfig = self.getFRRconfig(**base_frr_config_args) + self.assertNotIn(f'rpki', frrconfig) + + frrconfig = self.getFRRconfig(**vrf_frr_config_args) self.assertNotIn(f'rpki', frrconfig) # check process health and continuity @@ -144,27 +154,33 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): }, } - self.cli_set(base_path + ['expire-interval', expire_interval]) - self.cli_set(base_path + ['polling-period', polling_period]) - self.cli_set(base_path + ['retry-interval', retry_interval]) + for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args}, + {'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]: - for peer, peer_config in cache.items(): - self.cli_set(base_path + ['cache', peer, 'port', peer_config['port']]) - self.cli_set(base_path + ['cache', peer, 'preference', peer_config['preference']]) + if 'vrf' in test_set['path']: + self.cli_set(vrf_path + ['table', '1000']) - # commit changes - self.cli_commit() + self.cli_set(test_set['path'] + ['expire-interval', expire_interval]) + self.cli_set(test_set['path'] + ['polling-period', polling_period]) + self.cli_set(test_set['path'] + ['retry-interval', retry_interval]) + + for peer, peer_config in cache.items(): + self.cli_set(test_set['path'] + ['cache', peer, 'port', peer_config['port']]) + self.cli_set(test_set['path'] + ['cache', peer, 'preference', peer_config['preference']]) + + # commit changes + self.cli_commit() - # Verify FRR configuration - frrconfig = self.getFRRconfig('rpki', endsection='^exit') - self.assertIn(f'rpki expire_interval {expire_interval}', frrconfig) - self.assertIn(f'rpki polling_period {polling_period}', frrconfig) - self.assertIn(f'rpki retry_interval {retry_interval}', frrconfig) + # Verify FRR configuration + frrconfig = self.getFRRconfig(**test_set['frrargs']) + self.assertIn(f'rpki expire_interval {expire_interval}', frrconfig) + self.assertIn(f'rpki polling_period {polling_period}', frrconfig) + self.assertIn(f'rpki retry_interval {retry_interval}', frrconfig) - for peer, peer_config in cache.items(): - port = peer_config['port'] - preference = peer_config['preference'] - self.assertIn(f'rpki cache tcp {peer} {port} preference {preference}', frrconfig) + for peer, peer_config in cache.items(): + port = peer_config['port'] + preference = peer_config['preference'] + self.assertIn(f'rpki cache tcp {peer} {port} preference {preference}', frrconfig) def test_rpki_ssh(self): polling = '7200' @@ -185,28 +201,34 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub.replace('\n','')]) self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'type', rpki_key_type]) - for cache_name, cache_config in cache.items(): - self.cli_set(base_path + ['cache', cache_name, 'port', cache_config['port']]) - self.cli_set(base_path + ['cache', cache_name, 'preference', cache_config['preference']]) - self.cli_set(base_path + ['cache', cache_name, 'ssh', 'username', cache_config['username']]) - self.cli_set(base_path + ['cache', cache_name, 'ssh', 'key', rpki_key_name]) + for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args}, + {'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]: - # commit changes - self.cli_commit() + if 'vrf' in test_set['path']: + self.cli_set(vrf_path + ['table', '1000']) + + for cache_name, cache_config in cache.items(): + self.cli_set(test_set['path'] + ['cache', cache_name, 'port', cache_config['port']]) + self.cli_set(test_set['path'] + ['cache', cache_name, 'preference', cache_config['preference']]) + self.cli_set(test_set['path'] + ['cache', cache_name, 'ssh', 'username', cache_config['username']]) + self.cli_set(test_set['path'] + ['cache', cache_name, 'ssh', 'key', rpki_key_name]) + + # commit changes + self.cli_commit() - # Verify FRR configuration - frrconfig = self.getFRRconfig('rpki', endsection='^exit') - for cache_name, cache_config in cache.items(): - port = cache_config['port'] - preference = cache_config['preference'] - username = cache_config['username'] - self.assertIn(f'rpki cache ssh {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig) + # Verify FRR configuration + frrconfig = self.getFRRconfig(**test_set['frrargs']) + for cache_name, cache_config in cache.items(): + port = cache_config['port'] + preference = cache_config['preference'] + username = cache_config['username'] + self.assertIn(f'rpki cache ssh {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig) - # Verify content of SSH keys - tmp = read_file(f'/run/frr/id_rpki_{cache_name}') - self.assertIn(rpki_ssh_key.replace('\n',''), tmp) - tmp = read_file(f'/run/frr/id_rpki_{cache_name}.pub') - self.assertIn(rpki_ssh_pub.replace('\n',''), tmp) + # Verify content of SSH keys + tmp = read_file(f'/run/frr/id_rpki_{cache_name}') + self.assertIn(rpki_ssh_key.replace('\n',''), tmp) + tmp = read_file(f'/run/frr/id_rpki_{cache_name}.pub') + self.assertIn(rpki_ssh_pub.replace('\n',''), tmp) # Change OpenSSH key and verify it was properly written to filesystem self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key_replacement.replace('\n','')]) @@ -214,17 +236,21 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): # commit changes self.cli_commit() - for cache_name, cache_config in cache.items(): - port = cache_config['port'] - preference = cache_config['preference'] - username = cache_config['username'] - self.assertIn(f'rpki cache ssh {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig) + for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args}, + {'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]: - # Verify content of SSH keys - tmp = read_file(f'/run/frr/id_rpki_{cache_name}') - self.assertIn(rpki_ssh_key_replacement.replace('\n',''), tmp) - tmp = read_file(f'/run/frr/id_rpki_{cache_name}.pub') - self.assertIn(rpki_ssh_pub_replacement.replace('\n',''), tmp) + frrconfig = self.getFRRconfig(**test_set['frrargs']) + for cache_name, cache_config in cache.items(): + port = cache_config['port'] + preference = cache_config['preference'] + username = cache_config['username'] + self.assertIn(f'rpki cache ssh {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig) + + # Verify content of SSH keys + tmp = read_file(f'/run/frr/id_rpki_{cache_name}') + self.assertIn(rpki_ssh_key_replacement.replace('\n',''), tmp) + tmp = read_file(f'/run/frr/id_rpki_{cache_name}.pub') + self.assertIn(rpki_ssh_pub_replacement.replace('\n',''), tmp) self.cli_delete(['pki', 'openssh']) @@ -240,13 +266,19 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): }, } - for peer, peer_config in cache.items(): - self.cli_set(base_path + ['cache', peer, 'port', peer_config['port']]) - self.cli_set(base_path + ['cache', peer, 'preference', peer_config['preference']]) + for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args}, + {'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]: - # check validate() - preferences must be unique - with self.assertRaises(ConfigSessionError): - self.cli_commit() + if 'vrf' in test_set['path']: + self.cli_set(vrf_path + ['table', '1000']) + + for peer, peer_config in cache.items(): + self.cli_set(test_set['path'] + ['cache', peer, 'port', peer_config['port']]) + self.cli_set(test_set['path'] + ['cache', peer, 'preference', peer_config['preference']]) + + # check validate() - preferences must be unique + with self.assertRaises(ConfigSessionError): + self.cli_commit() def test_rpki_source_address(self): peer = '192.0.2.1' @@ -257,31 +289,38 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): self.cli_set(['interfaces', 'ethernet', 'eth0', 'address', f'{source_address}/24']) - # Configure a TCP cache server - self.cli_set(base_path + ['cache', peer, 'port', port]) - self.cli_set(base_path + ['cache', peer, 'preference', preference]) - self.cli_set(base_path + ['cache', peer, 'source-address', source_address]) - self.cli_commit() - # Verify FRR configuration - frrconfig = self.getFRRconfig('rpki') - self.assertIn(f'rpki cache tcp {peer} {port} source {source_address} preference {preference}', frrconfig) + for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args}, + {'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]: - self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key.replace('\n', '')]) - self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub.replace('\n', '')]) - self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'type', rpki_key_type]) + if 'vrf' in test_set['path']: + self.cli_set(vrf_path + ['table', '1000']) - # Configure a SSH cache server - self.cli_set(base_path + ['cache', peer, 'ssh', 'username', username]) - self.cli_set(base_path + ['cache', peer, 'ssh', 'key', rpki_key_name]) - self.cli_commit() + # Configure a TCP cache server + self.cli_set(test_set['path'] + ['cache', peer, 'port', port]) + self.cli_set(test_set['path'] + ['cache', peer, 'preference', preference]) + self.cli_set(test_set['path'] + ['cache', peer, 'source-address', source_address]) + self.cli_commit() + + # Verify FRR configuration + frrconfig = self.getFRRconfig(**test_set['frrargs']) + self.assertIn(f'rpki cache tcp {peer} {port} source {source_address} preference {preference}', frrconfig) + + self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key.replace('\n', '')]) + self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub.replace('\n', '')]) + self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'type', rpki_key_type]) + + # Configure a SSH cache server + self.cli_set(test_set['path'] + ['cache', peer, 'ssh', 'username', username]) + self.cli_set(test_set['path'] + ['cache', peer, 'ssh', 'key', rpki_key_name]) + self.cli_commit() - # Verify FRR configuration - frrconfig = self.getFRRconfig('rpki') - self.assertIn( - f'rpki cache ssh {peer} {port} {username} /run/frr/id_rpki_{peer} /run/frr/id_rpki_{peer}.pub source {source_address} preference {preference}', - frrconfig, - ) + # Verify FRR configuration + frrconfig = self.getFRRconfig(**test_set['frrargs']) + self.assertIn( + f'rpki cache ssh {peer} {port} {username} /run/frr/id_rpki_{peer} /run/frr/id_rpki_{peer}.pub source {source_address} preference {preference}', + frrconfig, + ) if __name__ == '__main__': diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py index ef0250e3d..054aa1c0e 100755 --- a/src/conf_mode/protocols_rpki.py +++ b/src/conf_mode/protocols_rpki.py @@ -18,6 +18,7 @@ import os from glob import glob from sys import exit +from sys import argv from vyos.config import Config from vyos.configverify import has_frr_protocol_in_dict @@ -39,13 +40,18 @@ def get_config(config=None): conf = config else: conf = Config() - return get_frrender_dict(conf) + return get_frrender_dict(conf, argv) def verify(config_dict): if not has_frr_protocol_in_dict(config_dict, 'rpki'): return None - rpki = config_dict['rpki'] + vrf = None + if 'vrf_context' in config_dict: + vrf = config_dict['vrf_context'] + + # eqivalent of the C foo ? 'a' : 'b' statement + rpki = vrf and config_dict['vrf']['name'][vrf]['protocols']['rpki'] or config_dict['rpki'] if 'cache' in rpki: preferences = [] @@ -79,7 +85,12 @@ def generate(config_dict): if not has_frr_protocol_in_dict(config_dict, 'rpki'): return None - rpki = config_dict['rpki'] + vrf = None + if 'vrf_context' in config_dict: + vrf = config_dict['vrf_context'] + + # eqivalent of the C foo ? 'a' : 'b' statement + rpki = vrf and config_dict['vrf']['name'][vrf]['protocols']['rpki'] or config_dict['rpki'] if 'cache' in rpki: for cache, cache_config in rpki['cache'].items(): |