summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Smith <adamsmith@yzguy.io>2024-12-31 13:43:55 -0500
committerAdam Smith <adamsmith@yzguy.io>2025-05-27 22:16:00 -0400
commit1fa28abc7035984af01fa4332f0ed6ed8f4fc044 (patch)
tree87e8e910fcf1af50e16013898fd5c7c986471248
parenta81ab0c6808080f521bfb673c61f90a744c625ff (diff)
downloadvyos-1x-1fa28abc7035984af01fa4332f0ed6ed8f4fc044.tar.gz
vyos-1x-1fa28abc7035984af01fa4332f0ed6ed8f4fc044.zip
T7432: RPKI VRF Support
-rw-r--r--data/templates/frr/rpki.frr.j228
-rw-r--r--interface-definitions/include/rpki/protocol-common-config.xml.i87
-rw-r--r--interface-definitions/protocols_rpki.xml.in86
-rw-r--r--interface-definitions/vrf.xml.in9
-rw-r--r--op-mode-definitions/include/rpki/vrf.xml.i11
-rw-r--r--op-mode-definitions/rpki.xml.in57
-rw-r--r--python/vyos/frrender.py17
-rwxr-xr-xsrc/conf_mode/protocols_rpki.py17
8 files changed, 203 insertions, 109 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/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():