summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md15
-rw-r--r--.github/workflows/cleanup-mirror-pr-branch.yml26
-rw-r--r--.github/workflows/package-smoketest.yml4
-rw-r--r--.github/workflows/trigger-pr-mirror-repo-sync.yml32
-rw-r--r--data/templates/accel-ppp/pppoe.config.j23
-rw-r--r--data/templates/dns-dynamic/ddclient.conf.j21
-rw-r--r--data/templates/dns-dynamic/override.conf.j25
-rw-r--r--data/templates/firewall/nftables-zone.j256
-rw-r--r--data/templates/frr/zebra.segment_routing.frr.j23
-rw-r--r--data/templates/prometheus/blackbox_exporter.service.j221
-rw-r--r--data/templates/prometheus/blackbox_exporter.yml.j223
-rw-r--r--data/templates/prometheus/node_exporter.service.j25
-rw-r--r--data/templates/ssh/sshd_config.j24
-rw-r--r--data/templates/telegraf/telegraf.j22
-rw-r--r--debian/control6
-rw-r--r--debian/vyos-1x.install1
-rw-r--r--[-rwxr-xr-x]interface-definitions/firewall.xml.in53
-rw-r--r--interface-definitions/high-availability.xml.in17
-rw-r--r--interface-definitions/include/bgp/protocol-common-config.xml.i10
-rw-r--r--interface-definitions/include/generic-interface-broadcast.xml.i2
-rw-r--r--interface-definitions/include/generic-interface-multi-broadcast.xml.i2
-rw-r--r--interface-definitions/include/generic-interface-multi-wildcard.xml.i2
-rw-r--r--interface-definitions/include/generic-interface-multi.xml.i2
-rw-r--r--interface-definitions/include/generic-interface.xml.i2
-rw-r--r--interface-definitions/include/monitoring/blackbox-exporter-module-commons.xml.i39
-rw-r--r--interface-definitions/include/static/static-route-interface.xml.i17
-rw-r--r--interface-definitions/include/static/static-route.xml.i2
-rw-r--r--interface-definitions/include/static/static-route6.xml.i2
-rw-r--r--interface-definitions/include/version/firewall-version.xml.i2
-rw-r--r--interface-definitions/interfaces_ethernet.xml.in6
-rw-r--r--interface-definitions/pki.xml.in24
-rw-r--r--interface-definitions/protocols_failover.xml.in2
-rw-r--r--interface-definitions/protocols_segment-routing.xml.in19
-rw-r--r--interface-definitions/service_dhcpv6-server.xml.in32
-rw-r--r--interface-definitions/service_monitoring_prometheus.xml.in89
-rw-r--r--interface-definitions/service_ndp-proxy.xml.in12
-rw-r--r--interface-definitions/service_pppoe-server.xml.in6
-rw-r--r--interface-definitions/service_ssh.xml.in8
-rw-r--r--op-mode-definitions/monitor-log.xml.in6
-rwxr-xr-xop-mode-definitions/show-log.xml.in6
-rw-r--r--python/vyos/frrender.py50
-rw-r--r--python/vyos/ifconfig/ethernet.py173
-rw-r--r--python/vyos/ifconfig/interface.py12
-rw-r--r--python/vyos/utils/network.py4
-rw-r--r--smoketest/scripts/cli/base_interfaces_test.py4
-rw-r--r--smoketest/scripts/cli/base_vyostest_shim.py47
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py96
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bonding.py5
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_ethernet.py46
-rwxr-xr-xsmoketest/scripts/cli/test_policy.py14
-rw-r--r--smoketest/scripts/cli/test_policy_local-route.py5
-rwxr-xr-xsmoketest/scripts/cli/test_policy_route.py5
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_babel.py13
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bfd.py21
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py117
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_isis.py65
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_mpls.py13
-rw-r--r--smoketest/scripts/cli/test_protocols_openfabric.py25
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospf.py60
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospfv3.py37
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_pim.py21
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_pim6.py16
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rip.py11
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ripng.py9
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rpki.py9
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_segment-routing.py110
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static.py56
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_dynamic.py18
-rwxr-xr-xsmoketest/scripts/cli/test_service_monitoring_prometheus.py81
-rwxr-xr-xsmoketest/scripts/cli/test_service_ssh.py115
-rwxr-xr-xsmoketest/scripts/cli/test_system_ip.py14
-rwxr-xr-xsmoketest/scripts/cli/test_system_ipv6.py14
-rwxr-xr-xsmoketest/scripts/cli/test_vrf.py41
-rwxr-xr-xsrc/conf_mode/firewall.py72
-rwxr-xr-xsrc/conf_mode/interfaces_openvpn.py28
-rwxr-xr-xsrc/conf_mode/service_monitoring_prometheus.py63
-rwxr-xr-xsrc/conf_mode/service_ssh.py57
-rw-r--r--src/etc/skel/.bashrc3
-rw-r--r--src/etc/udev/rules.d/90-vyos-serial.rules2
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/16-to-170
-rwxr-xr-xsrc/migration-scripts/firewall/17-to-1841
-rw-r--r--src/op_mode/tech_support.py19
-rw-r--r--src/op_mode/zone.py11
-rwxr-xr-xsrc/services/vyos-configd16
-rwxr-xr-xsrc/services/vyos-domain-resolver (renamed from src/helpers/vyos-domain-resolver.py)14
-rw-r--r--src/systemd/vyos-domain-resolver.service4
86 files changed, 1569 insertions, 657 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index cd348ead7..caabab3d9 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,7 +1,7 @@
<!-- All PR should follow this template to allow a clean and transparent review -->
<!-- Text placed between these delimiters is considered a comment and is not rendered -->
-## Change Summary
+## Change summary
<!--- Provide a general summary of your changes in the Title above -->
## Types of changes
@@ -24,13 +24,7 @@ the box, please use [x]
## Related PR(s)
<!-- Link here any PRs in other repositories that are required by this PR -->
-## Component(s) name
-<!-- A rather incomplete list of components: ethernet, wireguard, bgp, mpls, ldp, l2tp, dhcp ... -->
-
-## Proposed changes
-<!--- Describe your changes in detail -->
-
-## How to test
+## How to test / Smoketest result
<!---
Please describe in detail how you tested your changes. Include details of your testing
environment, and the tests you ran. When pasting configs, logs, shell output, backtraces,
@@ -38,10 +32,9 @@ and other large chunks of text, surround this text with triple backtics
```
like this
```
--->
-## Smoketest result
-<!-- Provide the output of the smoketest
+Or provide the output of the smoketest
+
```
$ /usr/libexec/vyos/tests/smoke/cli/test_xxx_feature.py
test_01_simple_options (__main__.TestFeature.test_01_simple_options) ... ok
diff --git a/.github/workflows/cleanup-mirror-pr-branch.yml b/.github/workflows/cleanup-mirror-pr-branch.yml
index c5de9ab73..bbe6aa2f2 100644
--- a/.github/workflows/cleanup-mirror-pr-branch.yml
+++ b/.github/workflows/cleanup-mirror-pr-branch.yml
@@ -5,31 +5,11 @@ on:
types: [closed]
branches:
- current
- workflow_dispatch:
- inputs:
- branch:
- description: 'Branch to delete'
- required: true
permissions:
contents: write
jobs:
- delete_branch:
- if: ${{ (github.event_name == 'workflow_dispatch' || startsWith(github.event.pull_request.head.ref, 'mirror/')) && github.repository_owner != 'vyos' }}
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: Delete branch
- run: |
- branch=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.branch || github.event.pull_request.head.ref }}
- if [[ $branch != mirror/* ]]; then
- echo "Branch name to clean must start with 'mirror/'"
- exit 1
- fi
- repo=${{ github.repository }}
- git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
- git push origin --delete $branch
+ call-delete-branch:
+ uses: vyos/.github/.github/workflows/cleanup-mirror-pr-branch.yml@current
+ secrets: inherit
diff --git a/.github/workflows/package-smoketest.yml b/.github/workflows/package-smoketest.yml
index d352bd3cb..ae34ea2f0 100644
--- a/.github/workflows/package-smoketest.yml
+++ b/.github/workflows/package-smoketest.yml
@@ -64,7 +64,9 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: vyos-${{ steps.version.outputs.build_version }}
- path: build/live-image-amd64.hybrid.iso
+ path: |
+ build/live-image-amd64.hybrid.iso
+ build/manifest.json
test_smoketest_cli:
needs: build_iso
diff --git a/.github/workflows/trigger-pr-mirror-repo-sync.yml b/.github/workflows/trigger-pr-mirror-repo-sync.yml
index 9653c2dca..d5e8ce3b4 100644
--- a/.github/workflows/trigger-pr-mirror-repo-sync.yml
+++ b/.github/workflows/trigger-pr-mirror-repo-sync.yml
@@ -6,33 +6,7 @@ on:
branches:
- current
-env:
- GH_TOKEN: ${{ secrets.PAT }}
-
-concurrency:
- group: trigger-pr-mirror-repo-sync-${{ github.event.pull_request.base.ref }}
- cancel-in-progress: false
jobs:
- trigger-mirror-pr-repo-sync:
- if: ${{ github.repository_owner == 'vyos' }}
- runs-on: ubuntu-latest
- permissions:
- pull-requests: write
- contents: write
-
- steps:
- - name: Bullfrog Secure Runner
- uses: bullfrogsec/bullfrog@v0
- with:
- egress-policy: audit
-
- - name: Trigger repo sync
- shell: bash
- run: |
- echo "Triggering sync workflow for ${{ secrets.REMOTE_OWNER }}/${{ secrets.REMOTE_REPO }}"
- echo "Triggering sync workflow with PAT ${{ secrets.PAT }}"
- curl -X POST \
- -H "Accept: application/vnd.github.everest-preview+json" \
- -H "Authorization: Bearer ${{ secrets.PAT }}" \
- https://api.github.com/repos/${{ secrets.REMOTE_OWNER }}/${{ secrets.REMOTE_REPO }}/actions/workflows/mirror-pr-and-sync.yml/dispatches \
- -d '{"ref":"git-actions", "inputs": {"pr_number": "${{ github.event.pull_request.number }}", "sync_branch": "${{ github.event.pull_request.base.ref }}"}}'
+ call-trigger-mirror-pr-repo-sync:
+ uses: vyos/.github/.github/workflows/trigger-pr-mirror-repo-sync.yml@current
+ secrets: inherit
diff --git a/data/templates/accel-ppp/pppoe.config.j2 b/data/templates/accel-ppp/pppoe.config.j2
index cf952c687..2c4871a6b 100644
--- a/data/templates/accel-ppp/pppoe.config.j2
+++ b/data/templates/accel-ppp/pppoe.config.j2
@@ -61,6 +61,9 @@ interface={{ iface }}
{% for vlan in iface_config.vlan %}
interface=re:^{{ iface }}\.{{ vlan | range_to_regex }}$
{% endfor %}
+{% if iface_config.combined is vyos_defined %}
+interface={{ iface }}
+{% endif %}
{% if iface_config.vlan_mon is vyos_defined %}
vlan-mon={{ iface }},{{ iface_config.vlan | join(',') }}
{% endif %}
diff --git a/data/templates/dns-dynamic/ddclient.conf.j2 b/data/templates/dns-dynamic/ddclient.conf.j2
index 5538ea56c..23aad4cb8 100644
--- a/data/templates/dns-dynamic/ddclient.conf.j2
+++ b/data/templates/dns-dynamic/ddclient.conf.j2
@@ -24,7 +24,6 @@ if{{ ipv }}={{ address }}, \
daemon={{ interval }}
syslog=yes
ssl=yes
-pid={{ config_file | replace('.conf', '.pid') }}
cache={{ config_file | replace('.conf', '.cache') }}
{# ddclient default (web=dyndns) doesn't support ssl and results in process lockup #}
web=googledomains
diff --git a/data/templates/dns-dynamic/override.conf.j2 b/data/templates/dns-dynamic/override.conf.j2
index 4a6851cef..c0edd8f05 100644
--- a/data/templates/dns-dynamic/override.conf.j2
+++ b/data/templates/dns-dynamic/override.conf.j2
@@ -1,10 +1,11 @@
{% set vrf_command = 'ip vrf exec ' ~ vrf ~ ' ' if vrf is vyos_defined else '' %}
[Unit]
ConditionPathExists={{ config_file }}
+Wants=
After=vyos-router.service
[Service]
-PIDFile={{ config_file | replace('.conf', '.pid') }}
EnvironmentFile=
ExecStart=
-ExecStart={{ vrf_command }}/usr/bin/ddclient -file {{ config_file }}
+ExecStart={{ vrf_command }}/usr/bin/ddclient --file {{ config_file }} --foreground
+Restart=always
diff --git a/data/templates/firewall/nftables-zone.j2 b/data/templates/firewall/nftables-zone.j2
index e78725079..645a38706 100644
--- a/data/templates/firewall/nftables-zone.j2
+++ b/data/templates/firewall/nftables-zone.j2
@@ -8,7 +8,14 @@
{% endif %}
{% for zone_name, zone_conf in zone.items() %}
{% if 'local_zone' not in zone_conf %}
- oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE_{{ zone_name }}
+{% if 'interface' in zone_conf.member %}
+ oifname { {{ zone_conf.member.interface | join(',') }} } counter jump VZONE_{{ zone_name }}
+{% endif %}
+{% if 'vrf' in zone_conf.member %}
+{% for vrf_name in zone_conf.member.vrf %}
+ oifname { {{ zone_conf['vrf_interfaces'][vrf_name] }} } counter jump VZONE_{{ zone_name }}
+{% endfor %}
+{% endif %}
{% endif %}
{% endfor %}
}
@@ -40,8 +47,15 @@
iifname lo counter return
{% if zone_conf.from is vyos_defined %}
{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall[fw_name] is vyos_defined %}
- iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
- iifname { {{ zone[from_zone].interface | join(",") }} } counter return
+
+{% if 'interface' in zone[from_zone].member %}
+ iifname { {{ zone[from_zone].member.interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ iifname { {{ zone[from_zone].member.interface | join(",") }} } counter return
+{% endif %}
+{% if 'vrf' in zone[from_zone].member %}
+ iifname { {{ zone[from_zone].member.vrf | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ iifname { {{ zone[from_zone].member.vrf | join(",") }} } counter return
+{% endif %}
{% endfor %}
{% endif %}
{{ zone_conf | nft_default_rule('zone_' + zone_name, family) }}
@@ -50,23 +64,47 @@
oifname lo counter return
{% if zone_conf.from_local is vyos_defined %}
{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall[fw_name] is vyos_defined %}
- oifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
- oifname { {{ zone[from_zone].interface | join(",") }} } counter return
+{% if 'interface' in zone[from_zone].member %}
+ oifname { {{ zone[from_zone].member.interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ oifname { {{ zone[from_zone].member.interface | join(",") }} } counter return
+{% endif %}
+{% if 'vrf' in zone[from_zone].member %}
+{% for vrf_name in zone[from_zone].member.vrf %}
+ oifname { {{ zone[from_zone]['vrf_interfaces'][vrf_name] }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ oifname { {{ zone[from_zone]['vrf_interfaces'][vrf_name] }} } counter return
+{% endfor %}
+{% endif %}
{% endfor %}
{% endif %}
{{ zone_conf | nft_default_rule('zone_' + zone_name, family) }}
}
{% else %}
chain VZONE_{{ zone_name }} {
- iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6) }}
+{% if 'interface' in zone_conf.member %}
+ iifname { {{ zone_conf.member.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6) }}
+{% endif %}
+{% if 'vrf' in zone_conf.member %}
+ iifname { {{ zone_conf.member.vrf | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6) }}
+{% endif %}
{% if zone_conf.intra_zone_filtering is vyos_defined %}
- iifname { {{ zone_conf.interface | join(",") }} } counter return
+{% if 'interface' in zone_conf.member %}
+ iifname { {{ zone_conf.member.interface | join(",") }} } counter return
+{% endif %}
+{% if 'vrf' in zone_conf.member %}
+ iifname { {{ zone_conf.member.vrf | join(",") }} } counter return
+{% endif %}
{% endif %}
{% if zone_conf.from is vyos_defined %}
{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall[fw_name] is vyos_defined %}
{% if zone[from_zone].local_zone is not defined %}
- iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
- iifname { {{ zone[from_zone].interface | join(",") }} } counter return
+{% if 'interface' in zone[from_zone].member %}
+ iifname { {{ zone[from_zone].member.interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ iifname { {{ zone[from_zone].member.interface | join(",") }} } counter return
+{% endif %}
+{% if 'vrf' in zone[from_zone].member %}
+ iifname { {{ zone[from_zone].member.vrf | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ iifname { {{ zone[from_zone].member.vrf | join(",") }} } counter return
+{% endif %}
{% endif %}
{% endfor %}
{% endif %}
diff --git a/data/templates/frr/zebra.segment_routing.frr.j2 b/data/templates/frr/zebra.segment_routing.frr.j2
index 7b12fcdd0..718d47d8f 100644
--- a/data/templates/frr/zebra.segment_routing.frr.j2
+++ b/data/templates/frr/zebra.segment_routing.frr.j2
@@ -11,6 +11,9 @@ segment-routing
{% if locator_config.behavior_usid is vyos_defined %}
behavior usid
{% endif %}
+{% if locator_config.format is vyos_defined %}
+ format {{ locator_config.format }}
+{% endif %}
exit
!
{% endfor %}
diff --git a/data/templates/prometheus/blackbox_exporter.service.j2 b/data/templates/prometheus/blackbox_exporter.service.j2
new file mode 100644
index 000000000..e93030246
--- /dev/null
+++ b/data/templates/prometheus/blackbox_exporter.service.j2
@@ -0,0 +1,21 @@
+{% set vrf_command = 'ip vrf exec ' ~ vrf ~ ' runuser -u node_exporter -- ' if vrf is vyos_defined else '' %}
+[Unit]
+Description=Blackbox Exporter
+Documentation=https://github.com/prometheus/blackbox_exporter
+After=network.target
+
+[Service]
+{% if vrf is not vyos_defined %}
+User=node_exporter
+{% endif %}
+ExecStart={{ vrf_command }}/usr/sbin/blackbox_exporter \
+{% if listen_address is vyos_defined %}
+{% for address in listen_address %}
+ --web.listen-address={{ address }}:{{ port }} \
+{% endfor %}
+{% else %}
+ --web.listen-address=:{{ port }} \
+{% endif %}
+ --config.file=/run/blackbox_exporter/config.yml
+[Install]
+WantedBy=multi-user.target
diff --git a/data/templates/prometheus/blackbox_exporter.yml.j2 b/data/templates/prometheus/blackbox_exporter.yml.j2
new file mode 100644
index 000000000..ba2eecd77
--- /dev/null
+++ b/data/templates/prometheus/blackbox_exporter.yml.j2
@@ -0,0 +1,23 @@
+modules:
+{% if modules is defined and modules.dns is defined and modules.dns.name is defined %}
+{% for module_name, module_config in modules.dns.name.items() %}
+ {{ module_name }}:
+ prober: dns
+ timeout: {{ module_config.timeout }}s
+ dns:
+ query_name: "{{ module_config.query_name }}"
+ query_type: "{{ module_config.query_type }}"
+ preferred_ip_protocol: "{{ module_config.preferred_ip_protocol | replace('v', '') }}"
+ ip_protocol_fallback: {{ 'true' if module_config.ip_protocol_fallback is vyos_defined else 'false' }}
+{% endfor %}
+{% endif %}
+{% if modules is defined and modules.icmp is vyos_defined and modules.icmp.name is vyos_defined %}
+{% for module_name, module_config in modules.icmp.name.items() %}
+ {{ module_name }}:
+ prober: icmp
+ timeout: {{ module_config.timeout }}s
+ icmp:
+ preferred_ip_protocol: "{{ module_config.preferred_ip_protocol | replace('v', '') }}"
+ ip_protocol_fallback: {{ 'true' if module_config.ip_protocol_fallback is vyos_defined else 'false' }}
+{% endfor %}
+{% endif %} \ No newline at end of file
diff --git a/data/templates/prometheus/node_exporter.service.j2 b/data/templates/prometheus/node_exporter.service.j2
index 62e7e6774..135439bd6 100644
--- a/data/templates/prometheus/node_exporter.service.j2
+++ b/data/templates/prometheus/node_exporter.service.j2
@@ -16,5 +16,10 @@ ExecStart={{ vrf_command }}/usr/sbin/node_exporter \
{% else %}
--web.listen-address=:{{ port }}
{% endif %}
+{% if collectors is vyos_defined %}
+{% if collectors.textfile is vyos_defined %}
+ --collector.textfile.directory=/run/node_exporter/collector
+{% endif %}
+{% endif %}
[Install]
WantedBy=multi-user.target
diff --git a/data/templates/ssh/sshd_config.j2 b/data/templates/ssh/sshd_config.j2
index 2cf0494c4..7e44efae8 100644
--- a/data/templates/ssh/sshd_config.j2
+++ b/data/templates/ssh/sshd_config.j2
@@ -110,3 +110,7 @@ ClientAliveInterval {{ client_keepalive_interval }}
{% if rekey.data is vyos_defined %}
RekeyLimit {{ rekey.data }}M {{ rekey.time + 'M' if rekey.time is vyos_defined }}
{% endif %}
+
+{% if trusted_user_ca_key is vyos_defined %}
+TrustedUserCAKeys /etc/ssh/trusted_user_ca_key
+{% endif %}
diff --git a/data/templates/telegraf/telegraf.j2 b/data/templates/telegraf/telegraf.j2
index 535e3a347..043fc6878 100644
--- a/data/templates/telegraf/telegraf.j2
+++ b/data/templates/telegraf/telegraf.j2
@@ -52,7 +52,7 @@
password = "{{ loki.authentication.password }}"
{% endif %}
{% if loki.metric_name_label is vyos_defined %}
-metric_name_label = "{{ loki.metric_name_label }}"
+ metric_name_label = "{{ loki.metric_name_label }}"
{% endif %}
### End Loki ###
{% endif %}
diff --git a/debian/control b/debian/control
index 08b86356a..a0d475d56 100644
--- a/debian/control
+++ b/debian/control
@@ -40,7 +40,8 @@ Pre-Depends:
libpam-runtime [amd64],
libnss-tacplus [amd64],
libpam-tacplus [amd64],
- libpam-radius-auth [amd64]
+ libpam-radius-auth (= 1.5.0-cl3u7) [amd64],
+ libnss-mapuser (= 1.1.0-cl3u3) [amd64]
Depends:
## Fundamentals
${python3:Depends} (>= 3.10),
@@ -241,6 +242,9 @@ Depends:
# For "service monitoring prometheus frr-exporter"
frr-exporter,
# End "service monitoring prometheus frr-exporter"
+# For "service monitoring prometheus blackbox-exporter"
+ blackbox-exporter,
+# End "service monitoring prometheus blackbox-exporter"
# For "service monitoring telegraf"
telegraf (>= 1.20),
# End "service monitoring telegraf"
diff --git a/debian/vyos-1x.install b/debian/vyos-1x.install
index d5dd3bcec..5fcff959a 100644
--- a/debian/vyos-1x.install
+++ b/debian/vyos-1x.install
@@ -1,5 +1,6 @@
etc/bash_completion.d
etc/commit
+etc/cron.d
etc/default
etc/dhcp
etc/ipsec.d
diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in
index 07c88f799..e4fe9a508 100755..100644
--- a/interface-definitions/firewall.xml.in
+++ b/interface-definitions/firewall.xml.in
@@ -16,15 +16,7 @@
</properties>
<children>
#include <include/generic-description.xml.i>
- <leafNode name="interface">
- <properties>
- <help>Interfaces to use this flowtable</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <multi/>
- </properties>
- </leafNode>
+ #include <include/generic-interface-multi.xml.i>
<leafNode name="offload">
<properties>
<help>Offloading method</help>
@@ -155,15 +147,7 @@
<constraintErrorMessage>Name of firewall group can only contain alphanumeric letters, hyphen, underscores and dot</constraintErrorMessage>
</properties>
<children>
- <leafNode name="interface">
- <properties>
- <help>Interface-group member</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <multi/>
- </properties>
- </leafNode>
+ #include <include/generic-interface-multi.xml.i>
<leafNode name="include">
<properties>
<help>Include another interface-group</help>
@@ -464,24 +448,27 @@
</node>
</children>
</tagNode>
- <leafNode name="interface">
+ <node name="member">
<properties>
<help>Interface associated with zone</help>
- <valueHelp>
- <format>txt</format>
- <description>Interface associated with zone</description>
- </valueHelp>
- <valueHelp>
- <format>vrf</format>
- <description>VRF associated with zone</description>
- </valueHelp>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- <path>vrf name</path>
- </completionHelp>
- <multi/>
</properties>
- </leafNode>
+ <children>
+ #include <include/generic-interface-multi.xml.i>
+ <leafNode name="vrf">
+ <properties>
+ <help>VRF associated with zone</help>
+ <valueHelp>
+ <format>vrf</format>
+ <description>VRF associated with zone</description>
+ </valueHelp>
+ <completionHelp>
+ <path>vrf name</path>
+ </completionHelp>
+ <multi/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<node name="intra-zone-filtering">
<properties>
<help>Intra-zone filtering</help>
diff --git a/interface-definitions/high-availability.xml.in b/interface-definitions/high-availability.xml.in
index 7108aa06c..6cf6237ca 100644
--- a/interface-definitions/high-availability.xml.in
+++ b/interface-definitions/high-availability.xml.in
@@ -247,22 +247,7 @@
<help>Disable track state of main interface</help>
</properties>
</leafNode>
- <leafNode name="interface">
- <properties>
- <help>Interface name state check</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces --broadcast</script>
- </completionHelp>
- <valueHelp>
- <format>txt</format>
- <description>Interface name</description>
- </valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
- <multi/>
- </properties>
- </leafNode>
+ #include <include/generic-interface-multi-broadcast.xml.i>
</children>
</node>
#include <include/vrrp-transition-script.xml.i>
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index 0f05625a7..4953251c5 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -721,15 +721,7 @@
<help>Apply local policy routing to interface</help>
</properties>
<children>
- <leafNode name="interface">
- <properties>
- <help>Interface</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <multi/>
- </properties>
- </leafNode>
+ #include <include/generic-interface-multi.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/include/generic-interface-broadcast.xml.i b/interface-definitions/include/generic-interface-broadcast.xml.i
index e37e75012..52a4a2717 100644
--- a/interface-definitions/include/generic-interface-broadcast.xml.i
+++ b/interface-definitions/include/generic-interface-broadcast.xml.i
@@ -1,7 +1,7 @@
<!-- include start from generic-interface-broadcast.xml.i -->
<leafNode name="interface">
<properties>
- <help>Interface to use</help>
+ <help>Interface</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces --broadcast</script>
</completionHelp>
diff --git a/interface-definitions/include/generic-interface-multi-broadcast.xml.i b/interface-definitions/include/generic-interface-multi-broadcast.xml.i
index ed13cf2cf..65ca1ffab 100644
--- a/interface-definitions/include/generic-interface-multi-broadcast.xml.i
+++ b/interface-definitions/include/generic-interface-multi-broadcast.xml.i
@@ -1,7 +1,7 @@
<!-- include start from generic-interface-multi-broadcast.xml.i -->
<leafNode name="interface">
<properties>
- <help>Interface to use</help>
+ <help>Interface</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces --broadcast</script>
</completionHelp>
diff --git a/interface-definitions/include/generic-interface-multi-wildcard.xml.i b/interface-definitions/include/generic-interface-multi-wildcard.xml.i
index 6c846a795..cd65028ac 100644
--- a/interface-definitions/include/generic-interface-multi-wildcard.xml.i
+++ b/interface-definitions/include/generic-interface-multi-wildcard.xml.i
@@ -1,7 +1,7 @@
<!-- include start from generic-interface-multi-wildcard.xml.i -->
<leafNode name="interface">
<properties>
- <help>Interface to use</help>
+ <help>Interface</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
diff --git a/interface-definitions/include/generic-interface-multi.xml.i b/interface-definitions/include/generic-interface-multi.xml.i
index cfc77af3a..a4329cba7 100644
--- a/interface-definitions/include/generic-interface-multi.xml.i
+++ b/interface-definitions/include/generic-interface-multi.xml.i
@@ -1,7 +1,7 @@
<!-- include start from generic-interface-multi.xml.i -->
<leafNode name="interface">
<properties>
- <help>Interface to use</help>
+ <help>Interface</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
diff --git a/interface-definitions/include/generic-interface.xml.i b/interface-definitions/include/generic-interface.xml.i
index 65f5bfbb8..cf6fb9151 100644
--- a/interface-definitions/include/generic-interface.xml.i
+++ b/interface-definitions/include/generic-interface.xml.i
@@ -1,7 +1,7 @@
<!-- include start from generic-interface.xml.i -->
<leafNode name="interface">
<properties>
- <help>Interface to use</help>
+ <help>Interface</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
diff --git a/interface-definitions/include/monitoring/blackbox-exporter-module-commons.xml.i b/interface-definitions/include/monitoring/blackbox-exporter-module-commons.xml.i
new file mode 100644
index 000000000..a97eb5232
--- /dev/null
+++ b/interface-definitions/include/monitoring/blackbox-exporter-module-commons.xml.i
@@ -0,0 +1,39 @@
+<!-- include start from monitoring/blackbox-module-commons.xml.i -->
+<leafNode name="timeout">
+ <properties>
+ <help>Timeout in seconds for the probe request</help>
+ <valueHelp>
+ <format>u32:1-60</format>
+ <description>Timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-60"/>
+ </constraint>
+ <constraintErrorMessage>Timeout must be between 1 and 60 seconds</constraintErrorMessage>
+ </properties>
+ <defaultValue>5</defaultValue>
+</leafNode>
+<leafNode name="preferred-ip-protocol">
+ <properties>
+ <help>Preferred IP protocol for this module</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>Prefer IPv4</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>Prefer IPv6</description>
+ </valueHelp>
+ <constraint>
+ <regex>(ipv4|ipv6)</regex>
+ </constraint>
+ </properties>
+ <defaultValue>ip6</defaultValue>
+</leafNode>
+<leafNode name="ip-protocol-fallback">
+ <properties>
+ <help>Allow fallback to other IP protocol if necessary</help>
+ <valueless/>
+ </properties>
+</leafNode>
+<!-- include end --> \ No newline at end of file
diff --git a/interface-definitions/include/static/static-route-interface.xml.i b/interface-definitions/include/static/static-route-interface.xml.i
deleted file mode 100644
index cb5436847..000000000
--- a/interface-definitions/include/static/static-route-interface.xml.i
+++ /dev/null
@@ -1,17 +0,0 @@
-<!-- include start from static/static-route-interface.xml.i -->
-<leafNode name="interface">
- <properties>
- <help>Gateway interface name</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <valueHelp>
- <format>txt</format>
- <description>Gateway interface name</description>
- </valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
- </properties>
-</leafNode>
-<!-- include end -->
diff --git a/interface-definitions/include/static/static-route.xml.i b/interface-definitions/include/static/static-route.xml.i
index fd7366286..c261874f5 100644
--- a/interface-definitions/include/static/static-route.xml.i
+++ b/interface-definitions/include/static/static-route.xml.i
@@ -49,7 +49,7 @@
<children>
#include <include/generic-disable-node.xml.i>
#include <include/static/static-route-distance.xml.i>
- #include <include/static/static-route-interface.xml.i>
+ #include <include/generic-interface.xml.i>
#include <include/static/static-route-vrf.xml.i>
<node name="bfd">
<properties>
diff --git a/interface-definitions/include/static/static-route6.xml.i b/interface-definitions/include/static/static-route6.xml.i
index 6fcc18b8a..a3d972d39 100644
--- a/interface-definitions/include/static/static-route6.xml.i
+++ b/interface-definitions/include/static/static-route6.xml.i
@@ -49,7 +49,7 @@
<children>
#include <include/generic-disable-node.xml.i>
#include <include/static/static-route-distance.xml.i>
- #include <include/static/static-route-interface.xml.i>
+ #include <include/generic-interface.xml.i>
#include <include/static/static-route-segments.xml.i>
#include <include/static/static-route-vrf.xml.i>
<node name="bfd">
diff --git a/interface-definitions/include/version/firewall-version.xml.i b/interface-definitions/include/version/firewall-version.xml.i
index a15cf0eec..1a8098297 100644
--- a/interface-definitions/include/version/firewall-version.xml.i
+++ b/interface-definitions/include/version/firewall-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/firewall-version.xml.i -->
-<syntaxVersion component='firewall' version='17'></syntaxVersion>
+<syntaxVersion component='firewall' version='18'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/interfaces_ethernet.xml.in b/interface-definitions/interfaces_ethernet.xml.in
index 89f990d41..b3559a626 100644
--- a/interface-definitions/interfaces_ethernet.xml.in
+++ b/interface-definitions/interfaces_ethernet.xml.in
@@ -56,6 +56,12 @@
</properties>
<defaultValue>auto</defaultValue>
</leafNode>
+ <leafNode name="switchdev">
+ <properties>
+ <help>Enables switchdev mode on interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
#include <include/interface/eapol.xml.i>
<node name="evpn">
<properties>
diff --git a/interface-definitions/pki.xml.in b/interface-definitions/pki.xml.in
index 5c0b735ef..161f20b33 100644
--- a/interface-definitions/pki.xml.in
+++ b/interface-definitions/pki.xml.in
@@ -202,30 +202,6 @@
</node>
</children>
</tagNode>
- <tagNode name="openssh">
- <properties>
- <help>OpenSSH public and private keys</help>
- </properties>
- <children>
- <node name="public">
- <properties>
- <help>Public key</help>
- </properties>
- <children>
- #include <include/pki/cli-public-key-base64.xml.i>
- </children>
- </node>
- <node name="private">
- <properties>
- <help>Private key</help>
- </properties>
- <children>
- #include <include/pki/cli-private-key-base64.xml.i>
- #include <include/pki/password-protected.xml.i>
- </children>
- </node>
- </children>
- </tagNode>
<node name="openvpn">
<properties>
<help>OpenVPN keys</help>
diff --git a/interface-definitions/protocols_failover.xml.in b/interface-definitions/protocols_failover.xml.in
index f70975949..fae9be76a 100644
--- a/interface-definitions/protocols_failover.xml.in
+++ b/interface-definitions/protocols_failover.xml.in
@@ -110,7 +110,7 @@
</leafNode>
</children>
</node>
- #include <include/static/static-route-interface.xml.i>
+ #include <include/generic-interface.xml.i>
<leafNode name="metric">
<properties>
<help>Route metric for this gateway</help>
diff --git a/interface-definitions/protocols_segment-routing.xml.in b/interface-definitions/protocols_segment-routing.xml.in
index c299f624e..688b253b6 100644
--- a/interface-definitions/protocols_segment-routing.xml.in
+++ b/interface-definitions/protocols_segment-routing.xml.in
@@ -126,6 +126,25 @@
</properties>
<defaultValue>24</defaultValue>
</leafNode>
+ <leafNode name="format">
+ <properties>
+ <help>SRv6 SID format</help>
+ <completionHelp>
+ <list>uncompressed-f4024 usid-f3216</list>
+ </completionHelp>
+ <valueHelp>
+ <format>uncompressed-f4024</format>
+ <description>Uncompressed f4024 format</description>
+ </valueHelp>
+ <valueHelp>
+ <format>usid-f3216</format>
+ <description>usid-f3216 format</description>
+ </valueHelp>
+ <constraint>
+ <regex>(uncompressed-f4024|usid-f3216)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
</children>
</tagNode>
</children>
diff --git a/interface-definitions/service_dhcpv6-server.xml.in b/interface-definitions/service_dhcpv6-server.xml.in
index cf14388e8..a6763a345 100644
--- a/interface-definitions/service_dhcpv6-server.xml.in
+++ b/interface-definitions/service_dhcpv6-server.xml.in
@@ -48,21 +48,7 @@
<children>
#include <include/generic-disable-node.xml.i>
#include <include/generic-description.xml.i>
- <leafNode name="interface">
- <properties>
- <help>Optional interface for this shared network to accept requests from</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <valueHelp>
- <format>txt</format>
- <description>Interface name</description>
- </valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/generic-interface.xml.i>
#include <include/dhcp/option-v6.xml.i>
<tagNode name="subnet">
<properties>
@@ -77,21 +63,7 @@
</properties>
<children>
#include <include/dhcp/option-v6.xml.i>
- <leafNode name="interface">
- <properties>
- <help>Optional interface for this subnet to accept requests from</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <valueHelp>
- <format>txt</format>
- <description>Interface name</description>
- </valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/generic-interface.xml.i>
<tagNode name="range">
<properties>
<help>Parameters setting ranges for assigning IPv6 addresses</help>
diff --git a/interface-definitions/service_monitoring_prometheus.xml.in b/interface-definitions/service_monitoring_prometheus.xml.in
index 24f31e15c..8bcebf5f3 100644
--- a/interface-definitions/service_monitoring_prometheus.xml.in
+++ b/interface-definitions/service_monitoring_prometheus.xml.in
@@ -21,6 +21,19 @@
<defaultValue>9100</defaultValue>
</leafNode>
#include <include/interface/vrf.xml.i>
+ <node name="collectors">
+ <properties>
+ <help>Collectors specific configuration</help>
+ </properties>
+ <children>
+ <leafNode name="textfile">
+ <properties>
+ <help>Enables textfile collector to read from /run/node_exporter/collector</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
</children>
</node>
<node name="frr-exporter">
@@ -36,6 +49,82 @@
#include <include/interface/vrf.xml.i>
</children>
</node>
+ <node name="blackbox-exporter">
+ <properties>
+ <help>Prometheus exporter for probing endpoints</help>
+ </properties>
+ <children>
+ #include <include/listen-address.xml.i>
+ #include <include/port-number.xml.i>
+ <leafNode name="port">
+ <defaultValue>9115</defaultValue>
+ </leafNode>
+ #include <include/interface/vrf.xml.i>
+ <node name="modules">
+ <properties>
+ <help>Configure blackbox exporter modules</help>
+ </properties>
+ <children>
+ <node name="dns">
+ <properties>
+ <help>Configure dns module</help>
+ </properties>
+ <children>
+ <tagNode name="name">
+ <properties>
+ <help>Name of the dns module</help>
+ </properties>
+ <children>
+ <leafNode name="query-name">
+ <properties>
+ <help>Name to be queried</help>
+ <constraint>
+ <validator name="fqdn"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="query-type">
+ <properties>
+ <help>DNS query type</help>
+ <valueHelp>
+ <format>ANY</format>
+ <description>Query any DNS record</description>
+ </valueHelp>
+ <valueHelp>
+ <format>A</format>
+ <description>Query IPv4 address record</description>
+ </valueHelp>
+ <valueHelp>
+ <format>AAAA</format>
+ <description>Query IPv6 address record</description>
+ </valueHelp>
+ </properties>
+ <defaultValue>ANY</defaultValue>
+ </leafNode>
+ #include <include/monitoring/blackbox-exporter-module-commons.xml.i>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+ <node name="icmp">
+ <properties>
+ <help>Configure icmp module</help>
+ </properties>
+ <children>
+ <tagNode name="name">
+ <properties>
+ <help>Name of the icmp module</help>
+ </properties>
+ <children>
+ #include <include/monitoring/blackbox-exporter-module-commons.xml.i>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
</children>
</node>
</children>
diff --git a/interface-definitions/service_ndp-proxy.xml.in b/interface-definitions/service_ndp-proxy.xml.in
index aabba3f4e..327ce89d5 100644
--- a/interface-definitions/service_ndp-proxy.xml.in
+++ b/interface-definitions/service_ndp-proxy.xml.in
@@ -111,17 +111,7 @@
</properties>
<defaultValue>static</defaultValue>
</leafNode>
- <leafNode name="interface">
- <properties>
- <help>Interface to forward Neighbor Solicitation message through. Required for "iface" mode</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/generic-interface.xml.i>
</children>
</tagNode>
</children>
diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in
index 0c99fd261..32215e9d2 100644
--- a/interface-definitions/service_pppoe-server.xml.in
+++ b/interface-definitions/service_pppoe-server.xml.in
@@ -63,6 +63,12 @@
</completionHelp>
</properties>
<children>
+ <leafNode name="combined">
+ <properties>
+ <help>Listen on both VLANs and the base interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
#include <include/accel-ppp/vlan.xml.i>
#include <include/accel-ppp/vlan-mon.xml.i>
</children>
diff --git a/interface-definitions/service_ssh.xml.in b/interface-definitions/service_ssh.xml.in
index 221e451d1..14d358c78 100644
--- a/interface-definitions/service_ssh.xml.in
+++ b/interface-definitions/service_ssh.xml.in
@@ -275,6 +275,14 @@
</constraint>
</properties>
</leafNode>
+ <node name="trusted-user-ca-key">
+ <properties>
+ <help>Trusted user CA key</help>
+ </properties>
+ <children>
+ #include <include/pki/ca-certificate.xml.i>
+ </children>
+ </node>
#include <include/vrf-multi.xml.i>
</children>
</node>
diff --git a/op-mode-definitions/monitor-log.xml.in b/op-mode-definitions/monitor-log.xml.in
index c9dc49b3a..b9ef8f48e 100644
--- a/op-mode-definitions/monitor-log.xml.in
+++ b/op-mode-definitions/monitor-log.xml.in
@@ -377,6 +377,12 @@
</properties>
<command>journalctl --no-hostname --boot --follow --unit vyos-configd.service</command>
</leafNode>
+ <leafNode name="vyos-domain-resolver">
+ <properties>
+ <help>Monitor last lines of VyOS domain resolver daemon log</help>
+ </properties>
+ <command>journalctl --no-hostname --boot --follow --unit vyos-domain-resolver.service</command>
+ </leafNode>
<node name="wireless">
<properties>
<help>Monitor last lines of Wireless interface log</help>
diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in
index 9dcebb6af..7ace50cc9 100755
--- a/op-mode-definitions/show-log.xml.in
+++ b/op-mode-definitions/show-log.xml.in
@@ -905,6 +905,12 @@
</properties>
<command>journalctl --no-hostname --boot --unit vyos-configd.service</command>
</leafNode>
+ <leafNode name="vyos-domain-resolver">
+ <properties>
+ <help>Show log for VyOS domain resolver daemon</help>
+ </properties>
+ <command>journalctl --no-hostname --boot --unit vyos-domain-resolver.service</command>
+ </leafNode>
<node name="wireless">
<properties>
<help>Show log for Wireless interface</help>
diff --git a/python/vyos/frrender.py b/python/vyos/frrender.py
index badc5d59f..544983b2c 100644
--- a/python/vyos/frrender.py
+++ b/python/vyos/frrender.py
@@ -218,11 +218,11 @@ def get_frrender_dict(conf, argv=None) -> dict:
# values present on the CLI - that's why we have if conf.exists()
eigrp_cli_path = ['protocols', 'eigrp']
if conf.exists(eigrp_cli_path):
- isis = conf.get_config_dict(eigrp_cli_path, key_mangling=('-', '_'),
- get_first_key=True,
- no_tag_node_value_mangle=True,
- with_recursive_defaults=True)
- dict.update({'eigrp' : isis})
+ eigrp = conf.get_config_dict(eigrp_cli_path, key_mangling=('-', '_'),
+ get_first_key=True,
+ no_tag_node_value_mangle=True,
+ with_recursive_defaults=True)
+ dict.update({'eigrp' : eigrp})
elif conf.exists_effective(eigrp_cli_path):
dict.update({'eigrp' : {'deleted' : ''}})
@@ -360,17 +360,24 @@ def get_frrender_dict(conf, argv=None) -> dict:
static = conf.get_config_dict(static_cli_path, key_mangling=('-', '_'),
get_first_key=True,
no_tag_node_value_mangle=True)
-
- # T3680 - get a list of all interfaces currently configured to use DHCP
- tmp = get_dhcp_interfaces(conf)
- if tmp: static.update({'dhcp' : tmp})
- tmp = get_pppoe_interfaces(conf)
- if tmp: static.update({'pppoe' : tmp})
-
dict.update({'static' : static})
elif conf.exists_effective(static_cli_path):
dict.update({'static' : {'deleted' : ''}})
+ # T3680 - get a list of all interfaces currently configured to use DHCP
+ tmp = get_dhcp_interfaces(conf)
+ if tmp:
+ if 'static' in dict:
+ dict['static'].update({'dhcp' : tmp})
+ else:
+ dict.update({'static' : {'dhcp' : tmp}})
+ tmp = get_pppoe_interfaces(conf)
+ if tmp:
+ if 'static' in dict:
+ dict['static'].update({'pppoe' : tmp})
+ else:
+ dict.update({'static' : {'pppoe' : tmp}})
+
# keep a re-usable list of dependent VRFs
dependent_vrfs_default = {}
if 'bgp' in dict:
@@ -534,17 +541,32 @@ def get_frrender_dict(conf, argv=None) -> dict:
dict.update({'vrf' : vrf})
+ if os.path.exists(frr_debug_enable):
+ import pprint
+ pprint.pprint(dict)
+
return dict
class FRRender:
+ cached_config_dict = {}
def __init__(self):
self._frr_conf = '/run/frr/config/vyos.frr.conf'
def generate(self, config_dict) -> None:
+ """
+ Generate FRR configuration file
+ Returns False if no changes to configuration were made, otherwise True
+ """
if not isinstance(config_dict, dict):
tmp = type(config_dict)
raise ValueError(f'Config must be of type "dict" and not "{tmp}"!')
+
+ if self.cached_config_dict == config_dict:
+ debug('FRR: NO CHANGES DETECTED')
+ return False
+ self.cached_config_dict = config_dict
+
def inline_helper(config_dict) -> str:
output = '!\n'
if 'babel' in config_dict and 'deleted' not in config_dict['babel']:
@@ -639,7 +661,7 @@ class FRRender:
debug(output)
write_file(self._frr_conf, output)
debug('FRR: RENDERING CONFIG COMPLETE')
- return None
+ return True
def apply(self, count_max=5):
count = 0
@@ -649,7 +671,7 @@ class FRRender:
debug(f'FRR: reloading configuration - tries: {count} | Python class ID: {id(self)}')
cmdline = '/usr/lib/frr/frr-reload.py --reload'
if os.path.exists(frr_debug_enable):
- cmdline += ' --debug'
+ cmdline += ' --debug --stdout'
rc, emsg = rc_cmd(f'{cmdline} {self._frr_conf}')
if rc != 0:
sleep(2)
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index 50dd0f396..d0c03dbe0 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -26,11 +26,13 @@ from vyos.utils.file import read_file
from vyos.utils.process import run
from vyos.utils.assertion import assert_list
+
@Interface.register
class EthernetIf(Interface):
"""
Abstraction of a Linux Ethernet Interface
"""
+
iftype = 'ethernet'
definition = {
**Interface.definition,
@@ -41,7 +43,7 @@ class EthernetIf(Interface):
'broadcast': True,
'bridgeable': True,
'eternal': '(lan|eth|eno|ens|enp|enx)[0-9]+$',
- }
+ },
}
@staticmethod
@@ -49,32 +51,35 @@ class EthernetIf(Interface):
run(f'ethtool --features {ifname} {option} {value}')
return False
- _command_set = {**Interface._command_set, **{
- 'gro': {
- 'validate': lambda v: assert_list(v, ['on', 'off']),
- 'possible': lambda i, v: EthernetIf.feature(i, 'gro', v),
- },
- 'gso': {
- 'validate': lambda v: assert_list(v, ['on', 'off']),
- 'possible': lambda i, v: EthernetIf.feature(i, 'gso', v),
- },
- 'hw-tc-offload': {
- 'validate': lambda v: assert_list(v, ['on', 'off']),
- 'possible': lambda i, v: EthernetIf.feature(i, 'hw-tc-offload', v),
- },
- 'lro': {
- 'validate': lambda v: assert_list(v, ['on', 'off']),
- 'possible': lambda i, v: EthernetIf.feature(i, 'lro', v),
- },
- 'sg': {
- 'validate': lambda v: assert_list(v, ['on', 'off']),
- 'possible': lambda i, v: EthernetIf.feature(i, 'sg', v),
- },
- 'tso': {
- 'validate': lambda v: assert_list(v, ['on', 'off']),
- 'possible': lambda i, v: EthernetIf.feature(i, 'tso', v),
+ _command_set = {
+ **Interface._command_set,
+ **{
+ 'gro': {
+ 'validate': lambda v: assert_list(v, ['on', 'off']),
+ 'possible': lambda i, v: EthernetIf.feature(i, 'gro', v),
+ },
+ 'gso': {
+ 'validate': lambda v: assert_list(v, ['on', 'off']),
+ 'possible': lambda i, v: EthernetIf.feature(i, 'gso', v),
+ },
+ 'hw-tc-offload': {
+ 'validate': lambda v: assert_list(v, ['on', 'off']),
+ 'possible': lambda i, v: EthernetIf.feature(i, 'hw-tc-offload', v),
+ },
+ 'lro': {
+ 'validate': lambda v: assert_list(v, ['on', 'off']),
+ 'possible': lambda i, v: EthernetIf.feature(i, 'lro', v),
+ },
+ 'sg': {
+ 'validate': lambda v: assert_list(v, ['on', 'off']),
+ 'possible': lambda i, v: EthernetIf.feature(i, 'sg', v),
+ },
+ 'tso': {
+ 'validate': lambda v: assert_list(v, ['on', 'off']),
+ 'possible': lambda i, v: EthernetIf.feature(i, 'tso', v),
+ },
},
- }}
+ }
@staticmethod
def get_bond_member_allowed_options() -> list:
@@ -106,7 +111,7 @@ class EthernetIf(Interface):
'ring_buffer.rx',
'ring_buffer.tx',
'speed',
- 'hw_id'
+ 'hw_id',
]
return bond_allowed_sections
@@ -130,7 +135,11 @@ class EthernetIf(Interface):
self.set_admin_state('down')
# Remove all VLAN subinterfaces - filter with the VLAN dot
- for vlan in [x for x in Section.interfaces(self.iftype) if x.startswith(f'{self.ifname}.')]:
+ for vlan in [
+ x
+ for x in Section.interfaces(self.iftype)
+ if x.startswith(f'{self.ifname}.')
+ ]:
Interface(vlan).remove()
super().remove()
@@ -149,10 +158,12 @@ class EthernetIf(Interface):
ifname = self.config['ifname']
if enable not in ['on', 'off']:
- raise ValueError("Value out of range")
+ raise ValueError('Value out of range')
if not self.ethtool.check_flow_control():
- self._debug_msg(f'NIC driver does not support changing flow control settings!')
+ self._debug_msg(
+ 'NIC driver does not support changing flow control settings!'
+ )
return False
current = self.ethtool.get_flow_control()
@@ -180,12 +191,24 @@ class EthernetIf(Interface):
"""
ifname = self.config['ifname']
- if speed not in ['auto', '10', '100', '1000', '2500', '5000', '10000',
- '25000', '40000', '50000', '100000', '400000']:
- raise ValueError("Value out of range (speed)")
+ if speed not in [
+ 'auto',
+ '10',
+ '100',
+ '1000',
+ '2500',
+ '5000',
+ '10000',
+ '25000',
+ '40000',
+ '50000',
+ '100000',
+ '400000',
+ ]:
+ raise ValueError('Value out of range (speed)')
if duplex not in ['auto', 'full', 'half']:
- raise ValueError("Value out of range (duplex)")
+ raise ValueError('Value out of range (duplex)')
if not self.ethtool.check_speed_duplex(speed, duplex):
Warning(f'changing speed/duplex setting on "{ifname}" is unsupported!')
@@ -224,7 +247,9 @@ class EthernetIf(Interface):
# but they do not actually support it either.
# In that case it's probably better to ignore the error
# than end up with a broken config.
- print('Warning: could not set speed/duplex settings: operation not permitted!')
+ print(
+ 'Warning: could not set speed/duplex settings: operation not permitted!'
+ )
def set_gro(self, state):
"""
@@ -243,7 +268,9 @@ class EthernetIf(Interface):
if not fixed:
return self.set_interface('gro', 'on' if state else 'off')
else:
- print('Adapter does not support changing generic-receive-offload settings!')
+ print(
+ 'Adapter does not support changing generic-receive-offload settings!'
+ )
return False
def set_gso(self, state):
@@ -262,7 +289,9 @@ class EthernetIf(Interface):
if not fixed:
return self.set_interface('gso', 'on' if state else 'off')
else:
- print('Adapter does not support changing generic-segmentation-offload settings!')
+ print(
+ 'Adapter does not support changing generic-segmentation-offload settings!'
+ )
return False
def set_hw_tc_offload(self, state):
@@ -300,7 +329,9 @@ class EthernetIf(Interface):
if not fixed:
return self.set_interface('lro', 'on' if state else 'off')
else:
- print('Adapter does not support changing large-receive-offload settings!')
+ print(
+ 'Adapter does not support changing large-receive-offload settings!'
+ )
return False
def set_rps(self, state):
@@ -332,13 +363,15 @@ class EthernetIf(Interface):
for i in range(0, cpu_count, 32):
# Extract the next 32-bit chunk
chunk = (rps_cpus >> i) & 0xFFFFFFFF
- hex_chunks.append(f"{chunk:08x}")
+ hex_chunks.append(f'{chunk:08x}')
# Join the chunks with commas
- rps_cpus = ",".join(hex_chunks)
+ rps_cpus = ','.join(hex_chunks)
for i in range(queues):
- self._write_sysfs(f'/sys/class/net/{self.ifname}/queues/rx-{i}/rps_cpus', rps_cpus)
+ self._write_sysfs(
+ f'/sys/class/net/{self.ifname}/queues/rx-{i}/rps_cpus', rps_cpus
+ )
# send bitmask representation as hex string without leading '0x'
return True
@@ -348,10 +381,13 @@ class EthernetIf(Interface):
queues = len(glob(f'/sys/class/net/{self.ifname}/queues/rx-*'))
if state:
global_rfs_flow = 32768
- rfs_flow = int(global_rfs_flow/queues)
+ rfs_flow = int(global_rfs_flow / queues)
for i in range(0, queues):
- self._write_sysfs(f'/sys/class/net/{self.ifname}/queues/rx-{i}/rps_flow_cnt', rfs_flow)
+ self._write_sysfs(
+ f'/sys/class/net/{self.ifname}/queues/rx-{i}/rps_flow_cnt',
+ rfs_flow,
+ )
return True
@@ -392,7 +428,9 @@ class EthernetIf(Interface):
if not fixed:
return self.set_interface('tso', 'on' if state else 'off')
else:
- print('Adapter does not support changing tcp-segmentation-offload settings!')
+ print(
+ 'Adapter does not support changing tcp-segmentation-offload settings!'
+ )
return False
def set_ring_buffer(self, rx_tx, size):
@@ -417,39 +455,64 @@ class EthernetIf(Interface):
print(f'could not set "{rx_tx}" ring-buffer for {ifname}')
return output
+ def set_switchdev(self, enable):
+ ifname = self.config['ifname']
+ addr, code = self._popen(
+ f"ethtool -i {ifname} | grep bus-info | awk '{{print $2}}'"
+ )
+ if code != 0:
+ print(f'could not resolve PCIe address of {ifname}')
+ return
+
+ enabled = False
+ state, code = self._popen(
+ f"/sbin/devlink dev eswitch show pci/{addr} | awk '{{print $3}}'"
+ )
+ if code == 0 and state == 'switchdev':
+ enabled = True
+
+ if enable and not enabled:
+ output, code = self._popen(
+ f'/sbin/devlink dev eswitch set pci/{addr} mode switchdev'
+ )
+ if code != 0:
+ print(f'{ifname} does not support switchdev mode')
+ elif not enable and enabled:
+ self._cmd(f'/sbin/devlink dev eswitch set pci/{addr} mode legacy')
+
def update(self, config):
- """ General helper function which works on a dictionary retrived by
+ """General helper function which works on a dictionary retrived by
get_config_dict(). It's main intention is to consolidate the scattered
interface setup code and provide a single point of entry when workin
- on any interface. """
+ on any interface."""
# disable ethernet flow control (pause frames)
value = 'off' if 'disable_flow_control' in config else 'on'
self.set_flow_control(value)
# GRO (generic receive offload)
- self.set_gro(dict_search('offload.gro', config) != None)
+ self.set_gro(dict_search('offload.gro', config) is not None)
# GSO (generic segmentation offload)
- self.set_gso(dict_search('offload.gso', config) != None)
+ self.set_gso(dict_search('offload.gso', config) is not None)
# GSO (generic segmentation offload)
- self.set_hw_tc_offload(dict_search('offload.hw_tc_offload', config) != None)
+ self.set_hw_tc_offload(dict_search('offload.hw_tc_offload', config) is not None)
# LRO (large receive offload)
- self.set_lro(dict_search('offload.lro', config) != None)
+ self.set_lro(dict_search('offload.lro', config) is not None)
# RPS - Receive Packet Steering
- self.set_rps(dict_search('offload.rps', config) != None)
+ self.set_rps(dict_search('offload.rps', config) is not None)
# RFS - Receive Flow Steering
- self.set_rfs(dict_search('offload.rfs', config) != None)
+ self.set_rfs(dict_search('offload.rfs', config) is not None)
# scatter-gather option
- self.set_sg(dict_search('offload.sg', config) != None)
+ self.set_sg(dict_search('offload.sg', config) is not None)
# TSO (TCP segmentation offloading)
- self.set_tso(dict_search('offload.tso', config) != None)
+ self.set_tso(dict_search('offload.tso', config) is not None)
# Set physical interface speed and duplex
if 'speed_duplex_changed' in config:
@@ -463,6 +526,8 @@ class EthernetIf(Interface):
for rx_tx, size in config['ring_buffer'].items():
self.set_ring_buffer(rx_tx, size)
+ self.set_switchdev('switchdev' in config)
+
# call base class last
super().update(config)
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index cad1685a9..de821ab60 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -1423,11 +1423,13 @@ class Interface(Control):
tmp = get_interface_address(self.ifname)
if tmp and 'addr_info' in tmp:
for address_dict in tmp['addr_info']:
- # Only remove dynamic assigned addresses
- if 'dynamic' not in address_dict:
- continue
- address = address_dict['local']
- self.del_addr(address)
+ if address_dict['family'] == 'inet':
+ # Only remove dynamic assigned addresses
+ if 'dynamic' not in address_dict:
+ continue
+ address = address_dict['local']
+ prefixlen = address_dict['prefixlen']
+ self.del_addr(f'{address}/{prefixlen}')
# cleanup old config files
for file in [dhclient_config_file, systemd_override_file, dhclient_lease_file]:
diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py
index 8fce08de0..dc0c0a6d6 100644
--- a/python/vyos/utils/network.py
+++ b/python/vyos/utils/network.py
@@ -69,7 +69,9 @@ def get_vrf_members(vrf: str) -> list:
answer = json.loads(output)
for data in answer:
if 'ifname' in data:
- interfaces.append(data.get('ifname'))
+ # Skip PIM interfaces which appears in VRF
+ if 'pim' not in data.get('ifname'):
+ interfaces.append(data.get('ifname'))
except:
pass
return interfaces
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py
index 593b4b415..c19bfcfe2 100644
--- a/smoketest/scripts/cli/base_interfaces_test.py
+++ b/smoketest/scripts/cli/base_interfaces_test.py
@@ -19,6 +19,7 @@ from netifaces import AF_INET6
from netifaces import ifaddresses
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.defaults import directories
@@ -181,6 +182,9 @@ class BasicInterfaceTest:
section = Section.section(span)
cls.cli_set(cls, ['interfaces', section, span])
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
+
@classmethod
def tearDownClass(cls):
# Tear down mirror interfaces for SPAN (Switch Port Analyzer)
diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py
index d95071d1a..a54622700 100644
--- a/smoketest/scripts/cli/base_vyostest_shim.py
+++ b/smoketest/scripts/cli/base_vyostest_shim.py
@@ -18,7 +18,6 @@ import paramiko
import pprint
from time import sleep
-from time import time
from typing import Type
from vyos.configsession import ConfigSession
@@ -30,6 +29,14 @@ from vyos.utils.process import run
save_config = '/tmp/vyos-smoketest-save'
+# The commit process is not finished until all pending files from
+# VYATTA_CHANGES_ONLY_DIR are copied to VYATTA_ACTIVE_CONFIGURATION_DIR. This
+# is done inside libvyatta-cfg1 and the FUSE UnionFS part. On large non-
+# interactive commits FUSE UnionFS might not replicate the real state in time,
+# leading to errors when querying the working and effective configuration.
+# TO BE DELETED AFTER SWITCH TO IN MEMORY CONFIG
+CSTORE_GUARD_TIME = 4
+
# This class acts as shim between individual Smoketests developed for VyOS and
# the Python UnitTest framework. Before every test is loaded, we dump the current
# system configuration and reload it after the test - despite the test results.
@@ -44,7 +51,9 @@ class VyOSUnitTestSHIM:
# trigger the certain failure condition.
# Use "self.debug = True" in derived classes setUp() method
debug = False
- commit_guard = time()
+ # Time to wait after a commit to ensure the CStore is up to date
+ # only required for testcases using FRR
+ _commit_guard_time = 0
@classmethod
def setUpClass(cls):
cls._session = ConfigSession(os.getpid())
@@ -85,11 +94,12 @@ class VyOSUnitTestSHIM:
if self.debug:
print('commit')
self._session.commit()
- # during a commit there is a process opening commit_lock, and run() returns 0
+ # During a commit there is a process opening commit_lock, and run()
+ # returns 0
while run(f'sudo lsof -nP {commit_lock}') == 0:
sleep(0.250)
- # reset getFRRconfig() guard timer
- self.commit_guard = time()
+ # Wait for CStore completion for fast non-interactive commits
+ sleep(self._commit_guard_time)
def op_mode(self, path : list) -> None:
"""
@@ -104,20 +114,27 @@ class VyOSUnitTestSHIM:
pprint.pprint(out)
return out
- def getFRRconfig(self, string=None, end='$', endsection='^!', daemon='', guard_time=10, empty_retry=0):
- """ Retrieve current "running configuration" from FRR """
- # Sometimes FRR needs some time after reloading the configuration to
- # appear in vtysh. This is a workaround addiung a 10 second guard timer
- # between the last cli_commit() and the first read of FRR config via vtysh
- while (time() - self.commit_guard) < guard_time:
- sleep(0.250) # wait 250 milliseconds
- command = f'vtysh -c "show run {daemon} no-header"'
- if string: command += f' | sed -n "/^{string}{end}/,/{endsection}/p"'
+ def getFRRconfig(self, string=None, end='$', endsection='^!',
+ substring=None, endsubsection=None, empty_retry=0):
+ """
+ Retrieve current "running configuration" from FRR
+
+ string: search for a specific start string in the configuration
+ end: end of the section to search for (line ending)
+ endsection: end of the configuration
+ substring: search section under the result found by string
+ endsubsection: end of the subsection (usually something with "exit")
+ """
+ command = f'vtysh -c "show run no-header"'
+ if string:
+ command += f' | sed -n "/^{string}{end}/,/{endsection}/p"'
+ if substring and endsubsection:
+ command += f' | sed -n "/^{substring}/,/{endsubsection}/p"'
out = cmd(command)
if self.debug:
print(f'\n\ncommand "{command}" returned:\n')
pprint.pprint(out)
- if empty_retry:
+ if empty_retry > 0:
retry_count = 0
while not out and retry_count < empty_retry:
if self.debug and retry_count % 10 == 0:
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 6420afa38..10301831e 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -906,7 +906,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
def test_zone_basic(self):
self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'default-action', 'drop'])
self.cli_set(['firewall', 'ipv6', 'name', 'smoketestv6', 'default-action', 'drop'])
- self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'interface', 'eth0'])
+ self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'member', 'interface', 'eth0'])
self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'from', 'smoketest-local', 'firewall', 'name', 'smoketest'])
self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'intra-zone-filtering', 'firewall', 'ipv6-name', 'smoketestv6'])
self.cli_set(['firewall', 'zone', 'smoketest-local', 'local-zone'])
@@ -964,6 +964,98 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.verify_nftables(nftables_search, 'ip vyos_filter')
self.verify_nftables(nftables_search_v6, 'ip6 vyos_filter')
+ def test_zone_with_vrf(self):
+ self.cli_set(['firewall', 'ipv4', 'name', 'ZONE1-to-LOCAL', 'default-action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'ZONE2_to_ZONE1', 'default-action', 'continue'])
+ self.cli_set(['firewall', 'ipv6', 'name', 'LOCAL_to_ZONE2_v6', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'zone', 'LOCAL', 'from', 'ZONE1', 'firewall', 'name', 'ZONE1-to-LOCAL'])
+ self.cli_set(['firewall', 'zone', 'LOCAL', 'local-zone'])
+ self.cli_set(['firewall', 'zone', 'ZONE1', 'from', 'ZONE2', 'firewall', 'name', 'ZONE2_to_ZONE1'])
+ self.cli_set(['firewall', 'zone', 'ZONE1', 'member', 'interface', 'eth1'])
+ self.cli_set(['firewall', 'zone', 'ZONE1', 'member', 'interface', 'eth2'])
+ self.cli_set(['firewall', 'zone', 'ZONE1', 'member', 'vrf', 'VRF-1'])
+ self.cli_set(['firewall', 'zone', 'ZONE2', 'from', 'LOCAL', 'firewall', 'ipv6-name', 'LOCAL_to_ZONE2_v6'])
+ self.cli_set(['firewall', 'zone', 'ZONE2', 'member', 'interface', 'vtun66'])
+ self.cli_set(['firewall', 'zone', 'ZONE2', 'member', 'vrf', 'VRF-2'])
+
+ self.cli_set(['vrf', 'name', 'VRF-1', 'table', '101'])
+ self.cli_set(['vrf', 'name', 'VRF-2', 'table', '102'])
+ self.cli_set(['interfaces', 'ethernet', 'eth0', 'vrf', 'VRF-1'])
+ self.cli_set(['interfaces', 'vti', 'vti1', 'vrf', 'VRF-2'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ ['chain NAME_ZONE1-to-LOCAL'],
+ ['counter', 'accept', 'comment "NAM-ZONE1-to-LOCAL default-action accept"'],
+ ['chain NAME_ZONE2_to_ZONE1'],
+ ['counter', 'continue', 'comment "NAM-ZONE2_to_ZONE1 default-action continue"'],
+ ['chain VYOS_ZONE_FORWARD'],
+ ['type filter hook forward priority filter + 1'],
+ ['oifname { "eth1", "eth2" }', 'counter packets', 'jump VZONE_ZONE1'],
+ ['oifname "eth0"', 'counter packets', 'jump VZONE_ZONE1'],
+ ['oifname "vtun66"', 'counter packets', 'jump VZONE_ZONE2'],
+ ['oifname "vti1"', 'counter packets', 'jump VZONE_ZONE2'],
+ ['chain VYOS_ZONE_LOCAL'],
+ ['type filter hook input priority filter + 1'],
+ ['counter packets', 'jump VZONE_LOCAL_IN'],
+ ['chain VYOS_ZONE_OUTPUT'],
+ ['type filter hook output priority filter + 1'],
+ ['counter packets', 'jump VZONE_LOCAL_OUT'],
+ ['chain VZONE_LOCAL_IN'],
+ ['iifname { "eth1", "eth2" }', 'counter packets', 'jump NAME_ZONE1-to-LOCAL'],
+ ['iifname "VRF-1"', 'counter packets', 'jump NAME_ZONE1-to-LOCAL'],
+ ['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
+ ['chain VZONE_LOCAL_OUT'],
+ ['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
+ ['chain VZONE_ZONE1'],
+ ['iifname { "eth1", "eth2" }', 'counter packets', 'return'],
+ ['iifname "VRF-1"', 'counter packets', 'return'],
+ ['iifname "vtun66"', 'counter packets', 'jump NAME_ZONE2_to_ZONE1'],
+ ['iifname "vtun66"', 'counter packets', 'return'],
+ ['iifname "VRF-2"', 'counter packets', 'jump NAME_ZONE2_to_ZONE1'],
+ ['iifname "VRF-2"', 'counter packets', 'return'],
+ ['counter packets', 'drop', 'comment "zone_ZONE1 default-action drop"'],
+ ['chain VZONE_ZONE2'],
+ ['iifname "vtun66"', 'counter packets', 'return'],
+ ['iifname "VRF-2"', 'counter packets', 'return'],
+ ['counter packets', 'drop', 'comment "zone_ZONE2 default-action drop"']
+ ]
+
+ nftables_search_v6 = [
+ ['chain NAME6_LOCAL_to_ZONE2_v6'],
+ ['counter', 'drop', 'comment "NAM-LOCAL_to_ZONE2_v6 default-action drop"'],
+ ['chain VYOS_ZONE_FORWARD'],
+ ['type filter hook forward priority filter + 1'],
+ ['oifname { "eth1", "eth2" }', 'counter packets', 'jump VZONE_ZONE1'],
+ ['oifname "eth0"', 'counter packets', 'jump VZONE_ZONE1'],
+ ['oifname "vtun66"', 'counter packets', 'jump VZONE_ZONE2'],
+ ['oifname "vti1"', 'counter packets', 'jump VZONE_ZONE2'],
+ ['chain VYOS_ZONE_LOCAL'],
+ ['type filter hook input priority filter + 1'],
+ ['counter packets', 'jump VZONE_LOCAL_IN'],
+ ['chain VYOS_ZONE_OUTPUT'],
+ ['type filter hook output priority filter + 1'],
+ ['counter packets', 'jump VZONE_LOCAL_OUT'],
+ ['chain VZONE_LOCAL_IN'],
+ ['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
+ ['chain VZONE_LOCAL_OUT'],
+ ['oifname "vtun66"', 'counter packets', 'jump NAME6_LOCAL_to_ZONE2_v6'],
+ ['oifname "vti1"', 'counter packets', 'jump NAME6_LOCAL_to_ZONE2_v6'],
+ ['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
+ ['chain VZONE_ZONE1'],
+ ['iifname { "eth1", "eth2" }', 'counter packets', 'return'],
+ ['iifname "VRF-1"', 'counter packets', 'return'],
+ ['counter packets', 'drop', 'comment "zone_ZONE1 default-action drop"'],
+ ['chain VZONE_ZONE2'],
+ ['iifname "vtun66"', 'counter packets', 'return'],
+ ['iifname "VRF-2"', 'counter packets', 'return'],
+ ['counter packets', 'drop', 'comment "zone_ZONE2 default-action drop"']
+ ]
+
+ self.verify_nftables(nftables_search, 'ip vyos_filter')
+ self.verify_nftables(nftables_search_v6, 'ip6 vyos_filter')
+
def test_flow_offload(self):
self.cli_set(['interfaces', 'ethernet', 'eth0', 'vif', '10'])
self.cli_set(['firewall', 'flowtable', 'smoketest', 'interface', 'eth0.10'])
diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py
index 735e4f3c5..1a72f9dc4 100755
--- a/smoketest/scripts/cli/test_interfaces_bonding.py
+++ b/smoketest/scripts/cli/test_interfaces_bonding.py
@@ -24,7 +24,6 @@ from vyos.ifconfig.interface import Interface
from vyos.configsession import ConfigSessionError
from vyos.utils.network import get_interface_config
from vyos.utils.file import read_file
-from vyos.frrender import mgmt_daemon
class BondingInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
@@ -287,7 +286,7 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase):
id = '5'
for interface in self._interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' evpn mh es-id {id}', frrconfig)
self.assertIn(f' evpn mh es-df-pref {id}', frrconfig)
@@ -304,7 +303,7 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase):
id = '5'
for interface in self._interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' evpn mh es-sys-mac 00:12:34:56:78:0{id}', frrconfig)
self.assertIn(f' evpn mh uplink', frrconfig)
diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py
index c02ca613b..2b421e942 100755
--- a/smoketest/scripts/cli/test_interfaces_ethernet.py
+++ b/smoketest/scripts/cli/test_interfaces_ethernet.py
@@ -27,11 +27,11 @@ from netifaces import ifaddresses
from base_interfaces_test import BasicInterfaceTest
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.frrender import mgmt_daemon
-from vyos.utils.process import cmd
-from vyos.utils.process import popen
from vyos.utils.file import read_file
+from vyos.utils.network import is_intf_addr_assigned
from vyos.utils.network import is_ipv6_link_local
+from vyos.utils.process import cmd
+from vyos.utils.process import popen
class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
@@ -78,14 +78,18 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
continue
self.assertFalse(is_intf_addr_assigned(interface, addr['addr']))
# Ensure no VLAN interfaces are left behind
- tmp = [x for x in Section.interfaces('ethernet') if x.startswith(f'{interface}.')]
+ tmp = [
+ x
+ for x in Section.interfaces('ethernet')
+ if x.startswith(f'{interface}.')
+ ]
self.assertListEqual(tmp, [])
def test_offloading_rps(self):
# enable RPS on all available CPUs, RPS works with a CPU bitmask,
# where each bit represents a CPU (core/thread). The formula below
# expands to rps_cpus = 255 for a 8 core system
- rps_cpus = (1 << os.cpu_count()) -1
+ rps_cpus = (1 << os.cpu_count()) - 1
# XXX: we should probably reserve one core when the system is under
# high preasure so we can still have a core left for housekeeping.
@@ -101,7 +105,7 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
for interface in self._interfaces:
cpus = read_file(f'/sys/class/net/{interface}/queues/rx-0/rps_cpus')
# remove the nasty ',' separation on larger strings
- cpus = cpus.replace(',','')
+ cpus = cpus.replace(',', '')
cpus = int(cpus, 16)
self.assertEqual(f'{cpus:x}', f'{rps_cpus:x}')
@@ -117,12 +121,14 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
for interface in self._interfaces:
queues = len(glob(f'/sys/class/net/{interface}/queues/rx-*'))
- rfs_flow = int(global_rfs_flow/queues)
+ rfs_flow = int(global_rfs_flow / queues)
for i in range(0, queues):
- tmp = read_file(f'/sys/class/net/{interface}/queues/rx-{i}/rps_flow_cnt')
+ tmp = read_file(
+ f'/sys/class/net/{interface}/queues/rx-{i}/rps_flow_cnt'
+ )
self.assertEqual(int(tmp), rfs_flow)
- tmp = read_file(f'/proc/sys/net/core/rps_sock_flow_entries')
+ tmp = read_file('/proc/sys/net/core/rps_sock_flow_entries')
self.assertEqual(int(tmp), global_rfs_flow)
# delete configuration of RFS and check all values returned to default "0"
@@ -133,12 +139,13 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
for interface in self._interfaces:
queues = len(glob(f'/sys/class/net/{interface}/queues/rx-*'))
- rfs_flow = int(global_rfs_flow/queues)
+ rfs_flow = int(global_rfs_flow / queues)
for i in range(0, queues):
- tmp = read_file(f'/sys/class/net/{interface}/queues/rx-{i}/rps_flow_cnt')
+ tmp = read_file(
+ f'/sys/class/net/{interface}/queues/rx-{i}/rps_flow_cnt'
+ )
self.assertEqual(int(tmp), 0)
-
def test_non_existing_interface(self):
unknonw_interface = self._base_path + ['eth667']
self.cli_set(unknonw_interface)
@@ -213,15 +220,24 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
out = loads(out)
self.assertFalse(out[0]['autonegotiate'])
- def test_ethtool_evpn_uplink_tarcking(self):
+ def test_ethtool_evpn_uplink_tracking(self):
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'evpn', 'uplink'])
self.cli_commit()
for interface in self._interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', daemon=mgmt_daemon)
- self.assertIn(f' evpn mh uplink', frrconfig)
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ self.assertIn(' evpn mh uplink', frrconfig)
+
+ def test_switchdev(self):
+ interface = self._interfaces[0]
+ self.cli_set(self._base_path + [interface, 'switchdev'])
+
+ # check validate() - virtual interfaces do not support switchdev
+ # should print out warning that enabling failed
+
+ self.cli_delete(self._base_path + [interface, 'switchdev'])
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py
index 7ea1b610e..9d4fc0845 100755
--- a/smoketest/scripts/cli/test_policy.py
+++ b/smoketest/scripts/cli/test_policy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2025 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
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.utils.process import cmd
@@ -24,6 +25,17 @@ from vyos.utils.process import cmd
base_path = ['policy']
class TestPolicy(VyOSUnitTestSHIM.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ super(TestPolicy, cls).setUpClass()
+
+ # 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'])
+ # 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_commit()
diff --git a/smoketest/scripts/cli/test_policy_local-route.py b/smoketest/scripts/cli/test_policy_local-route.py
index 8d6ba40dc..a4239b8a1 100644
--- a/smoketest/scripts/cli/test_policy_local-route.py
+++ b/smoketest/scripts/cli/test_policy_local-route.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright (C) 2024-2025 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
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
interface = 'eth0'
mark = '100'
@@ -32,6 +33,8 @@ class TestPolicyLocalRoute(VyOSUnitTestSHIM.TestCase):
# Clear out current configuration to allow running this test on a live system
cls.cli_delete(cls, ['policy', 'local-route'])
cls.cli_delete(cls, ['policy', 'local-route6'])
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
cls.cli_set(cls, ['vrf', 'name', vrf_name, 'table', vrf_rt_id])
diff --git a/smoketest/scripts/cli/test_policy_route.py b/smoketest/scripts/cli/test_policy_route.py
index 672865eb0..53761b7d6 100755
--- a/smoketest/scripts/cli/test_policy_route.py
+++ b/smoketest/scripts/cli/test_policy_route.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2025 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
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
mark = '100'
conn_mark = '555'
@@ -36,6 +37,8 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
# Clear out current configuration to allow running this test on a live system
cls.cli_delete(cls, ['policy', 'route'])
cls.cli_delete(cls, ['policy', 'route6'])
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
cls.cli_set(cls, ['interfaces', 'ethernet', interface, 'address', interface_ip])
cls.cli_set(cls, ['protocols', 'static', 'table', table_id, 'route', '0.0.0.0/0', 'interface', interface])
diff --git a/smoketest/scripts/cli/test_protocols_babel.py b/smoketest/scripts/cli/test_protocols_babel.py
index 12f6ecf38..7ecf54600 100755
--- a/smoketest/scripts/cli/test_protocols_babel.py
+++ b/smoketest/scripts/cli/test_protocols_babel.py
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.ifconfig import Section
from vyos.frrender import babel_daemon
@@ -38,6 +39,8 @@ class TestProtocolsBABEL(VyOSUnitTestSHIM.TestCase):
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['policy', 'prefix-list'])
cls.cli_delete(cls, ['policy', 'prefix-list6'])
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
# always destroy the entire babel configuration to make the processes
@@ -62,7 +65,7 @@ class TestProtocolsBABEL(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig('router babel', endsection='^exit', daemon=babel_daemon)
+ frrconfig = self.getFRRconfig('router babel', endsection='^exit')
self.assertIn(f' babel diversity', frrconfig)
self.assertIn(f' babel diversity-factor {diversity_factor}', frrconfig)
self.assertIn(f' babel resend-delay {resend_delay}', frrconfig)
@@ -81,7 +84,7 @@ class TestProtocolsBABEL(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig('router babel', endsection='^exit', daemon=babel_daemon, empty_retry=5)
+ frrconfig = self.getFRRconfig('router babel', endsection='^exit', empty_retry=5)
for protocol in ipv4_protos:
self.assertIn(f' redistribute ipv4 {protocol}', frrconfig)
for protocol in ipv6_protos:
@@ -150,7 +153,7 @@ class TestProtocolsBABEL(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig('router babel', endsection='^exit', daemon=babel_daemon)
+ frrconfig = self.getFRRconfig('router babel', endsection='^exit')
self.assertIn(f' distribute-list {access_list_in4} in', frrconfig)
self.assertIn(f' distribute-list {access_list_out4} out', frrconfig)
self.assertIn(f' ipv6 distribute-list {access_list_in6} in', frrconfig)
@@ -198,11 +201,11 @@ class TestProtocolsBABEL(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig('router babel', endsection='^exit', daemon=babel_daemon)
+ frrconfig = self.getFRRconfig('router babel', endsection='^exit')
for interface in self._interfaces:
self.assertIn(f' network {interface}', frrconfig)
- iface_config = self.getFRRconfig(f'interface {interface}', endsection='^exit', daemon=babel_daemon)
+ iface_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' babel channel {channel}', iface_config)
self.assertIn(f' babel enable-timestamps', iface_config)
self.assertIn(f' babel update-interval {def_update_interval}', iface_config)
diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py
index 32e39e8f7..2205cd9de 100755
--- a/smoketest/scripts/cli/test_protocols_bfd.py
+++ b/smoketest/scripts/cli/test_protocols_bfd.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -17,12 +17,13 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
+
from vyos.configsession import ConfigSessionError
from vyos.frrender import bfd_daemon
from vyos.utils.process import process_named_running
base_path = ['protocols', 'bfd']
-frr_endsection = '^ exit'
dum_if = 'dum1001'
vrf_name = 'red'
@@ -87,6 +88,9 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(bfd_daemon)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
+
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
@@ -131,7 +135,7 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig('bfd', endsection='^exit', daemon=bfd_daemon)
+ frrconfig = self.getFRRconfig('bfd', endsection='^exit')
for peer, peer_config in peers.items():
tmp = f'peer {peer}'
if 'multihop' in peer_config:
@@ -144,8 +148,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
tmp += f' vrf {peer_config["vrf"]}'
self.assertIn(tmp, frrconfig)
- peerconfig = self.getFRRconfig(f' peer {peer}', end='', endsection=frr_endsection,
- daemon=bfd_daemon)
+ peerconfig = self.getFRRconfig('bfd', endsection='^exit', substring=f' peer {peer}',
+ endsubsection='^ exit')
if 'echo_mode' in peer_config:
self.assertIn(f'echo-mode', peerconfig)
if 'intv_echo' in peer_config:
@@ -207,7 +211,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
# Verify FRR bgpd configuration
for profile, profile_config in profiles.items():
- config = self.getFRRconfig(f' profile {profile}', endsection=frr_endsection)
+ config = self.getFRRconfig('bfd', endsection='^exit',
+ substring=f' profile {profile}', endsubsection='^ exit',)
if 'echo_mode' in profile_config:
self.assertIn(f' echo-mode', config)
if 'intv_echo' in profile_config:
@@ -229,8 +234,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
self.assertNotIn(f'shutdown', config)
for peer, peer_config in peers.items():
- peerconfig = self.getFRRconfig(f' peer {peer}', end='',
- endsection=frr_endsection, daemon=bfd_daemon)
+ peerconfig = self.getFRRconfig('bfd', endsection='^exit',
+ substring=f' peer {peer}', endsubsection='^ exit')
if 'profile' in peer_config:
self.assertIn(f' profile {peer_config["profile"]}', peerconfig)
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index cdf18a051..761eb8bfe 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -19,6 +19,7 @@ import unittest
from time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.ifconfig import Section
from vyos.configsession import ConfigSessionError
@@ -200,6 +201,9 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'action', 'deny'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'prefix', '2001:db8:2000::/64'])
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
+
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, ['policy', 'route-map'])
@@ -217,7 +221,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router bgp', endsection='^exit', daemon=bgp_daemon)
+ frrconfig = self.getFRRconfig('router bgp', endsection='^exit')
self.assertNotIn(f'router bgp', frrconfig)
# check process health and continuity
@@ -372,7 +376,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', daemon=bgp_daemon)
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' bgp router-id {router_id}', frrconfig)
self.assertIn(f' bgp allow-martian-nexthop', frrconfig)
@@ -398,18 +402,21 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertNotIn(f'bgp ebgp-requires-policy', frrconfig)
self.assertIn(f' no bgp suppress-duplicates', frrconfig)
- afiv4_config = self.getFRRconfig(' address-family ipv4 unicast',
- endsection='^ exit-address-family', daemon=bgp_daemon)
+ afiv4_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=' address-family ipv4 unicast',
+ endsubsection='^ exit-address-family')
self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config)
self.assertIn(f' maximum-paths ibgp {max_path_v4ibgp}', afiv4_config)
- afiv4_config = self.getFRRconfig(' address-family ipv4 labeled-unicast',
- endsection='^ exit-address-family', daemon=bgp_daemon)
+ afiv4_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=' address-family ipv4 labeled-unicast',
+ endsubsection='^ exit-address-family')
self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config)
self.assertIn(f' maximum-paths ibgp {max_path_v4ibgp}', afiv4_config)
- afiv6_config = self.getFRRconfig(' address-family ipv6 unicast',
- endsection='^ exit-address-family', daemon=bgp_daemon)
+ afiv6_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=' address-family ipv6 unicast',
+ endsubsection='^ exit-address-family')
self.assertIn(f' maximum-paths {max_path_v6}', afiv6_config)
self.assertIn(f' maximum-paths ibgp {max_path_v6ibgp}', afiv6_config)
@@ -516,7 +523,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit', daemon=bgp_daemon)
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
for peer, peer_config in neighbor_config.items():
@@ -621,7 +628,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit', daemon=bgp_daemon)
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
for peer, peer_config in peer_group_config.items():
@@ -670,7 +677,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit', daemon=bgp_daemon)
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv4 unicast', frrconfig)
@@ -716,7 +723,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit', daemon=bgp_daemon)
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv6 unicast', frrconfig)
# T2100: By default ebgp-requires-policy is disabled to keep VyOS
@@ -758,7 +765,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit', daemon=bgp_daemon)
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {peer_group} peer-group', frrconfig)
self.assertIn(f' neighbor {peer_group} remote-as {ASN}', frrconfig)
@@ -793,7 +800,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit', daemon=bgp_daemon)
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family l2vpn evpn', frrconfig)
self.assertIn(f' advertise-all-vni', frrconfig)
@@ -806,7 +813,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' flooding disable', frrconfig)
self.assertIn(f' mac-vrf soo {soo}', frrconfig)
for vni in vnis:
- vniconfig = self.getFRRconfig(f' vni {vni}', endsection='^exit-vni')
+ vniconfig = self.getFRRconfig(f' vni {vni}', endsection='^ exit-vni')
self.assertIn(f'vni {vni}', vniconfig)
self.assertIn(f' advertise-default-gw', vniconfig)
self.assertIn(f' advertise-svi-ip', vniconfig)
@@ -849,7 +856,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR distances configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
for family in verify_families:
self.assertIn(f'address-family {family}', frrconfig)
@@ -887,7 +894,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv6 unicast', frrconfig)
@@ -895,7 +902,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' import vrf {vrf}', frrconfig)
# Verify FRR bgpd configuration
- frr_vrf_config = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}')
+ frr_vrf_config = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}', endsection='^exit')
self.assertIn(f'router bgp {ASN} vrf {vrf}', frr_vrf_config)
self.assertIn(f' bgp router-id {router_id}', frr_vrf_config)
@@ -913,7 +920,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' bgp router-id {router_id}', frrconfig)
self.assertIn(f' bgp confederation identifier {confed_id}', frrconfig)
@@ -930,7 +937,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {interface} interface v6only remote-as {remote_asn}', frrconfig)
self.assertIn(f' address-family ipv6 unicast', frrconfig)
@@ -962,11 +969,13 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
for afi in ['ipv4', 'ipv6']:
- afi_config = self.getFRRconfig(f' address-family {afi} unicast', endsection='exit-address-family', daemon=bgp_daemon)
+ afi_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=f' address-family {afi} unicast',
+ endsubsection='^ exit-address-family')
self.assertIn(f'address-family {afi} unicast', afi_config)
self.assertIn(f' export vpn', afi_config)
self.assertIn(f' import vpn', afi_config)
@@ -1011,7 +1020,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {neighbor} peer-group {peer_group}', frrconfig)
self.assertIn(f' neighbor {peer_group} peer-group', frrconfig)
@@ -1036,7 +1045,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {neighbor} remote-as {remote_asn}', frrconfig)
self.assertIn(f' neighbor {neighbor} local-as {local_asn}', frrconfig)
@@ -1061,8 +1070,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
base_path + ['address-family', import_afi, 'import', 'vrf',
import_vrf])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
- frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f'address-family ipv4 unicast', frrconfig)
@@ -1084,8 +1093,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
base_path + ['address-family', import_afi, 'import', 'vrf',
import_vrf])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
- frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f'address-family ipv4 unicast', frrconfig)
self.assertIn(f' import vrf {import_vrf}', frrconfig)
@@ -1098,8 +1107,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
# Verify deleting existent vrf default if other vrfs were created
self.create_bgp_instances_for_import_test()
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
- frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f'router bgp {ASN} vrf {import_vrf}', frrconfig_vrf)
self.cli_delete(base_path)
@@ -1115,8 +1124,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
'vpn', 'export',
import_rd])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
- frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f'router bgp {ASN} vrf {import_vrf}', frrconfig_vrf)
self.assertIn(f'address-family ipv4 unicast', frrconfig_vrf)
@@ -1145,7 +1154,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
for interface in interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}')
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', frrconfig)
self.assertIn(f' mpls bgp forwarding', frrconfig)
@@ -1159,7 +1168,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
for interface in interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}')
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', frrconfig)
self.assertIn(f' mpls bgp forwarding', frrconfig)
self.cli_delete(['interfaces', 'ethernet', interface, 'vrf'])
@@ -1179,7 +1188,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path + ['address-family', 'ipv4-unicast', 'sid'])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' segment-routing srv6', frrconfig)
self.assertIn(f' locator {locator_name}', frrconfig)
@@ -1194,17 +1203,22 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' segment-routing srv6', frrconfig)
self.assertIn(f' locator {locator_name}', frrconfig)
- afiv4_config = self.getFRRconfig(' address-family ipv4 unicast')
+ afiv4_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=' address-family ipv4 unicast',
+ endsubsection='^ exit-address-family')
self.assertIn(f' sid vpn export {sid}', afiv4_config)
self.assertIn(f' nexthop vpn export {nexthop_ipv4}', afiv4_config)
- afiv6_config = self.getFRRconfig(' address-family ipv6 unicast')
+
+ afiv6_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=' address-family ipv6 unicast',
+ endsubsection='^ exit-address-family')
self.assertIn(f' sid vpn export {sid}', afiv6_config)
- self.assertIn(f' nexthop vpn export {nexthop_ipv6}', afiv4_config)
+ self.assertIn(f' nexthop vpn export {nexthop_ipv6}', afiv6_config)
def test_bgp_25_ipv4_labeled_unicast_peer_group(self):
pg_ipv4 = 'foo4'
@@ -1218,14 +1232,16 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {pg_ipv4} peer-group', frrconfig)
self.assertIn(f' neighbor {pg_ipv4} remote-as external', frrconfig)
self.assertIn(f' bgp listen range {ipv4_prefix} peer-group {pg_ipv4}', frrconfig)
self.assertIn(f' bgp labeled-unicast ipv4-explicit-null', frrconfig)
- afiv4_config = self.getFRRconfig(' address-family ipv4 labeled-unicast')
+ afiv4_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=' address-family ipv4 labeled-unicast',
+ endsubsection='^ exit-address-family')
self.assertIn(f' neighbor {pg_ipv4} activate', afiv4_config)
self.assertIn(f' neighbor {pg_ipv4} maximum-prefix {ipv4_max_prefix}', afiv4_config)
@@ -1242,14 +1258,16 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {pg_ipv6} peer-group', frrconfig)
self.assertIn(f' neighbor {pg_ipv6} remote-as external', frrconfig)
self.assertIn(f' bgp listen range {ipv6_prefix} peer-group {pg_ipv6}', frrconfig)
self.assertIn(f' bgp labeled-unicast ipv6-explicit-null', frrconfig)
- afiv6_config = self.getFRRconfig(' address-family ipv6 labeled-unicast')
+ afiv6_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=' address-family ipv6 labeled-unicast',
+ endsubsection='^ exit-address-family')
self.assertIn(f' neighbor {pg_ipv6} activate', afiv6_config)
self.assertIn(f' neighbor {pg_ipv6} maximum-prefix {ipv6_max_prefix}', afiv6_config)
@@ -1261,7 +1279,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['peer-group', 'peer1', 'remote-as', 'internal'])
self.cli_commit()
- conf = self.getFRRconfig(' address-family l2vpn evpn')
+ conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
+ substring=' address-family l2vpn evpn', endsubsection='^ exit-address-family')
self.assertIn('neighbor peer1 route-reflector-client', conf)
@@ -1300,7 +1319,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['neighbor', int_neighbors[1], 'remote-as', ASN])
self.cli_commit()
- conf = self.getFRRconfig(f'router bgp {ASN}')
+ conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
_common_config_check(conf)
# test add internal remote-as to external group
@@ -1315,7 +1334,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['neighbor', ext_neighbors[1], 'remote-as', f'{int(ASN) + 2}'])
self.cli_commit()
- conf = self.getFRRconfig(f'router bgp {ASN}')
+ conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
_common_config_check(conf)
self.assertIn(f'neighbor {ext_neighbors[1]} remote-as {int(ASN) + 2}', conf)
self.assertIn(f'neighbor {ext_neighbors[1]} peer-group {ext_pg_name}', conf)
@@ -1327,7 +1346,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['neighbor', ext_neighbors[1], 'remote-as', 'external'])
self.cli_commit()
- conf = self.getFRRconfig(f'router bgp {ASN}')
+ conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
_common_config_check(conf, include_ras=False)
self.assertIn(f'neighbor {int_neighbors[0]} remote-as internal', conf)
@@ -1352,7 +1371,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- conf = self.getFRRconfig(f'router bgp {ASN}')
+ conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'neighbor OVERLAY remote-as {int(ASN) + 1}', conf)
self.assertIn(f'neighbor OVERLAY local-as {int(ASN) + 1}', conf)
@@ -1405,7 +1424,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify bgpd bmp configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
self.assertIn(f'bmp mirror buffer-limit {mirror_buffer}', frrconfig)
self.assertIn(f'bmp targets {target_name}', frrconfig)
self.assertIn(f'bmp mirror', frrconfig)
diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py
index bde32a1ca..598250d28 100755
--- a/smoketest/scripts/cli/test_protocols_isis.py
+++ b/smoketest/scripts/cli/test_protocols_isis.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright (C) 2021-2025 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
@@ -17,13 +17,14 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
+
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.utils.process import process_named_running
from vyos.frrender import isis_daemon
base_path = ['protocols', 'isis']
-
domain = 'VyOS'
net = '49.0001.1921.6800.1002.00'
@@ -39,6 +40,8 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
# out the current configuration :)
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['vrf'])
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
# cleanup any possible VRF mess
@@ -51,11 +54,6 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(isis_daemon))
- def isis_base_config(self):
- self.cli_set(base_path + ['net', net])
- for interface in self._interfaces:
- self.cli_set(base_path + ['interface', interface])
-
def test_isis_01_redistribute(self):
prefix_list = 'EXPORT-ISIS'
route_map = 'EXPORT-ISIS'
@@ -73,7 +71,9 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
with self.assertRaises(ConfigSessionError):
self.cli_commit()
- self.isis_base_config()
+ self.cli_set(base_path + ['net', net])
+ for interface in self._interfaces:
+ self.cli_set(base_path + ['interface', interface])
self.cli_set(base_path + ['redistribute', 'ipv4', 'connected'])
# verify() - Redistribute level-1 or level-2 should be specified
@@ -88,14 +88,14 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' metric-style {metric_style}', tmp)
self.assertIn(f' log-adjacency-changes', tmp)
self.assertIn(f' redistribute ipv4 connected level-2 route-map {route_map}', tmp)
for interface in self._interfaces:
- tmp = self.getFRRconfig(f'interface {interface}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' ip router isis {domain}', tmp)
self.assertIn(f' ipv6 router isis {domain}', tmp)
@@ -124,11 +124,11 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR isisd configuration
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f'router isis {domain}', tmp)
self.assertIn(f' net {net}', tmp)
- tmp = self.getFRRconfig(f'router isis {domain} vrf {vrf}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain} vrf {vrf}', endsection='^exit')
self.assertIn(f'router isis {domain} vrf {vrf}', tmp)
self.assertIn(f' net {net}', tmp)
self.assertIn(f' advertise-high-metrics', tmp)
@@ -141,7 +141,10 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
metric = '50'
route_map = 'default-foo-'
- self.isis_base_config()
+ self.cli_set(base_path + ['net', net])
+ for interface in self._interfaces:
+ self.cli_set(base_path + ['interface', interface])
+
for afi in ['ipv4', 'ipv6']:
for level in ['level-1', 'level-2']:
self.cli_set(base_path + ['default-information', 'originate', afi, level, 'always'])
@@ -152,7 +155,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
for afi in ['ipv4', 'ipv6']:
@@ -160,11 +163,10 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
route_map_name = route_map + level + afi
self.assertIn(f' default-information originate {afi} {level} always route-map {route_map_name} metric {metric}', tmp)
-
def test_isis_05_password(self):
password = 'foo'
- self.isis_base_config()
+ self.cli_set(base_path + ['net', net])
for interface in self._interfaces:
self.cli_set(base_path + ['interface', interface, 'password', 'plaintext-password', f'{password}-{interface}'])
@@ -187,13 +189,13 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' domain-password clear {password}', tmp)
self.assertIn(f' area-password clear {password}', tmp)
for interface in self._interfaces:
- tmp = self.getFRRconfig(f'interface {interface}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' isis password clear {password}-{interface}', tmp)
def test_isis_06_spf_delay_bfd(self):
@@ -235,12 +237,12 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' spf-delay-ietf init-delay {init_delay} short-delay {short_delay} long-delay {long_delay} holddown {holddown} time-to-learn {time_to_learn}', tmp)
for interface in self._interfaces:
- tmp = self.getFRRconfig(f'interface {interface}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' ip router isis {domain}', tmp)
self.assertIn(f' ipv6 router isis {domain}', tmp)
self.assertIn(f' isis network {network}', tmp)
@@ -252,7 +254,6 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
global_block_high = "399"
local_block_low = "400"
local_block_high = "499"
- interface = 'lo'
maximum_stack_size = '5'
prefix_one = '192.168.0.1/32'
prefix_two = '192.168.0.2/32'
@@ -264,7 +265,9 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
prefix_four_value = '65000'
self.cli_set(base_path + ['net', net])
- self.cli_set(base_path + ['interface', interface])
+ for interface in self._interfaces:
+ self.cli_set(base_path + ['interface', interface])
+
self.cli_set(base_path + ['segment-routing', 'maximum-label-depth', maximum_stack_size])
self.cli_set(base_path + ['segment-routing', 'global-block', 'low-label-value', global_block_low])
self.cli_set(base_path + ['segment-routing', 'global-block', 'high-label-value', global_block_high])
@@ -283,7 +286,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' segment-routing on', tmp)
self.assertIn(f' segment-routing global-block {global_block_low} {global_block_high} local-block {local_block_low} {local_block_high}', tmp)
@@ -305,7 +308,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify main ISIS changes
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' mpls ldp-sync', tmp)
self.assertIn(f' mpls ldp-sync holddown {holddown}', tmp)
@@ -318,7 +321,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
for interface in self._interfaces:
# Verify interface changes for holddown
- tmp = self.getFRRconfig(f'interface {interface}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', tmp)
self.assertIn(f' ip router isis {domain}', tmp)
self.assertIn(f' ipv6 router isis {domain}', tmp)
@@ -332,7 +335,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
for interface in self._interfaces:
# Verify interface changes for disable
- tmp = self.getFRRconfig(f'interface {interface}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', tmp)
self.assertIn(f' ip router isis {domain}', tmp)
self.assertIn(f' ipv6 router isis {domain}', tmp)
@@ -355,7 +358,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
for level in ['level-1', 'level-2']:
self.cli_set(base_path + ['fast-reroute', 'lfa', 'remote', 'prefix-list', prefix_list, level])
self.cli_commit()
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' fast-reroute remote-lfa prefix-list {prefix_list} {level}', tmp)
self.cli_delete(base_path + ['fast-reroute'])
@@ -365,7 +368,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
for level in ['level-1', 'level-2']:
self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'load-sharing', 'disable', level])
self.cli_commit()
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' fast-reroute load-sharing disable {level}', tmp)
self.cli_delete(base_path + ['fast-reroute'])
@@ -376,7 +379,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
for level in ['level-1', 'level-2']:
self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'priority-limit', priority, level])
self.cli_commit()
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' fast-reroute priority-limit {priority} {level}', tmp)
self.cli_delete(base_path + ['fast-reroute'])
@@ -388,7 +391,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
for level in ['level-1', 'level-2']:
self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'tiebreaker', tiebreaker, 'index', index, level])
self.cli_commit()
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' fast-reroute lfa tiebreaker {tiebreaker} index {index} {level}', tmp)
self.cli_delete(base_path + ['fast-reroute'])
@@ -408,7 +411,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
for topology in topologies:
self.cli_set(base_path + ['topology', topology])
self.cli_commit()
- tmp = self.getFRRconfig(f'router isis {domain}', daemon=isis_daemon)
+ tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' topology {topology}', tmp)
diff --git a/smoketest/scripts/cli/test_protocols_mpls.py b/smoketest/scripts/cli/test_protocols_mpls.py
index 88528973d..654f2f099 100755
--- a/smoketest/scripts/cli/test_protocols_mpls.py
+++ b/smoketest/scripts/cli/test_protocols_mpls.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -17,6 +17,8 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
+
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.frrender import ldpd_daemon
@@ -72,10 +74,11 @@ class TestProtocolsMPLS(VyOSUnitTestSHIM.TestCase):
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(ldpd_daemon)
-
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_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)
@@ -106,12 +109,14 @@ class TestProtocolsMPLS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Validate configuration
- frrconfig = self.getFRRconfig('mpls ldp', daemon=ldpd_daemon)
+ frrconfig = self.getFRRconfig('mpls ldp', endsection='^exit')
self.assertIn(f'mpls ldp', frrconfig)
self.assertIn(f' router-id {router_id}', frrconfig)
# Validate AFI IPv4
- afiv4_config = self.getFRRconfig(' address-family ipv4', daemon=ldpd_daemon)
+ afiv4_config = self.getFRRconfig('mpls ldp', endsection='^exit',
+ substring=' address-family ipv4',
+ endsubsection='^ exit-address-family')
self.assertIn(f' discovery transport-address {transport_ipv4_addr}', afiv4_config)
for interface in interfaces:
self.assertIn(f' interface {interface}', afiv4_config)
diff --git a/smoketest/scripts/cli/test_protocols_openfabric.py b/smoketest/scripts/cli/test_protocols_openfabric.py
index f1372d7ab..323b6cd74 100644
--- a/smoketest/scripts/cli/test_protocols_openfabric.py
+++ b/smoketest/scripts/cli/test_protocols_openfabric.py
@@ -17,6 +17,8 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
+
from vyos.configsession import ConfigSessionError
from vyos.utils.process import process_named_running
from vyos.frrender import openfabric_daemon
@@ -40,6 +42,8 @@ class TestProtocolsOpenFabric(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)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
@@ -75,14 +79,14 @@ class TestProtocolsOpenFabric(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router openfabric {domain}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'router openfabric {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' log-adjacency-changes', tmp)
self.assertIn(f' set-overload-bit', tmp)
self.assertIn(f' fabric-tier {fabric_tier}', tmp)
self.assertIn(f' lsp-gen-interval {lsp_gen_interval}', tmp)
- tmp = self.getFRRconfig(f'interface {dummy_if}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'interface {dummy_if}', endsection='^exit')
self.assertIn(f' ip router openfabric {domain}', tmp)
self.assertIn(f' ipv6 router openfabric {domain}', tmp)
@@ -101,12 +105,12 @@ class TestProtocolsOpenFabric(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR openfabric configuration
- tmp = self.getFRRconfig(f'router openfabric {domain}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'router openfabric {domain}', endsection='^exit')
self.assertIn(f'router openfabric {domain}', tmp)
self.assertIn(f' net {net}', tmp)
# Verify interface configuration
- tmp = self.getFRRconfig(f'interface {interface}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' ip router openfabric {domain}', tmp)
# for lo interface 'openfabric passive' is implied
self.assertIn(f' openfabric passive', tmp)
@@ -137,11 +141,11 @@ class TestProtocolsOpenFabric(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router openfabric {domain}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'router openfabric {domain}', endsection='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' domain-password clear {password}', tmp)
- tmp = self.getFRRconfig(f'interface {dummy_if}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'interface {dummy_if}', endsection='^exit')
self.assertIn(f' openfabric password clear {password}-{dummy_if}', tmp)
def test_openfabric_multiple_domains(self):
@@ -165,22 +169,21 @@ class TestProtocolsOpenFabric(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR openfabric configuration
- tmp = self.getFRRconfig(f'router openfabric {domain}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'router openfabric {domain}', endsection='^exit')
self.assertIn(f'router openfabric {domain}', tmp)
self.assertIn(f' net {net}', tmp)
- tmp = self.getFRRconfig(f'router openfabric {domain_2}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'router openfabric {domain_2}', endsection='^exit')
self.assertIn(f'router openfabric {domain_2}', tmp)
self.assertIn(f' net {net}', tmp)
# Verify interface configuration
- tmp = self.getFRRconfig(f'interface {dummy_if}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'interface {dummy_if}', endsection='^exit')
self.assertIn(f' ip router openfabric {domain}', tmp)
self.assertIn(f' ipv6 router openfabric {domain}', tmp)
- tmp = self.getFRRconfig(f'interface {interface}', daemon=openfabric_daemon)
+ tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' ip router openfabric {domain_2}', tmp)
-
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py
index 599bf3930..77882737f 100755
--- a/smoketest/scripts/cli/test_protocols_ospf.py
+++ b/smoketest/scripts/cli/test_protocols_ospf.py
@@ -18,6 +18,7 @@ import unittest
from time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
@@ -45,6 +46,8 @@ class TestProtocolsOSPF(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)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
@classmethod
def tearDownClass(cls):
@@ -56,7 +59,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertNotIn(f'router ospf', frrconfig)
# check process health and continuity
@@ -68,7 +71,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
@@ -96,7 +99,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' compatible rfc1583', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth {bandwidth}', frrconfig)
@@ -112,7 +115,6 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.assertNotIn(f' area 10 range 10.0.1.0/24 not-advertise', frrconfig)
self.assertIn(f' area 10 range 10.0.2.0/24 not-advertise', frrconfig)
-
def test_ospf_03_access_list(self):
acl = '100'
seq = '10'
@@ -128,14 +130,13 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
for ptotocol in protocols:
self.assertIn(f' distribute-list {acl} out {ptotocol}', frrconfig) # defaults
self.cli_delete(['policy', 'access-list', acl])
-
def test_ospf_04_default_originate(self):
seq = '100'
metric = '50'
@@ -149,7 +150,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
self.assertIn(f' default-information originate metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -159,10 +160,9 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
-
def test_ospf_05_options(self):
global_distance = '128'
intra_area = '100'
@@ -201,7 +201,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' mpls-te on', frrconfig)
self.assertIn(f' mpls-te router-address 0.0.0.0', frrconfig) # default
@@ -224,7 +224,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['distance', 'ospf', 'inter-area', inter_area])
self.cli_commit()
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f' distance ospf intra-area {intra_area} inter-area {inter_area} external {external}', frrconfig)
# https://github.com/FRRouting/frr/issues/17011
@@ -247,7 +247,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
for neighbor in neighbors:
self.assertIn(f' neighbor {neighbor} priority {priority} poll-interval {poll_interval}', frrconfig) # default
@@ -266,7 +266,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
for protocol in redistribute:
self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -294,7 +294,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' area {area} shortcut {shortcut}', frrconfig)
self.assertIn(f' area {area} virtual-link {virtual_link} hello-interval {hello} retransmit-interval {retransmit} retransmit-window {window_default} transmit-delay {transmit} dead-interval {dead}', frrconfig)
@@ -326,13 +326,13 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
# commit changes
self.cli_commit()
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' passive-interface default', frrconfig)
for interface in interfaces:
# Can not use daemon for getFRRconfig() as bandwidth parameter belongs to zebra process
- config = self.getFRRconfig(f'interface {interface}')
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf authentication-key {password}', config)
self.assertIn(f' ip ospf bfd', config)
@@ -350,7 +350,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
for interface in interfaces:
# T5467: It must also be removed from FRR config
- frrconfig = self.getFRRconfig(f'interface {interface}', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertNotIn(f'interface {interface}', frrconfig)
# There should be no OSPF related command at all under the interface
self.assertNotIn(f' ip ospf', frrconfig)
@@ -371,11 +371,11 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', daemon=ospf_daemon)
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf area {area}', config)
@@ -398,17 +398,17 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
- frrconfig = self.getFRRconfig(f'router ospf vrf {vrf}', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig(f'router ospf vrf {vrf}', endsection='^exit')
self.assertIn(f'router ospf vrf {vrf}', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', endsection='^exit')
self.assertIn(f'interface {vrf_iface}', frrconfig)
self.assertIn(f' ip ospf area {area}', frrconfig)
@@ -418,7 +418,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# T5467: It must also be removed from FRR config
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', endsection='^exit')
self.assertNotIn(f'interface {vrf_iface}', frrconfig)
# There should be no OSPF related command at all under the interface
self.assertNotIn(f' ip ospf', frrconfig)
@@ -444,7 +444,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # default
self.assertIn(f' network {network} area {area}', frrconfig)
@@ -477,7 +477,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f' segment-routing on', frrconfig)
self.assertIn(f' segment-routing global-block {global_block_low} {global_block_high} local-block {local_block_low} {local_block_high}', frrconfig)
self.assertIn(f' segment-routing node-msd {maximum_stack_size}', frrconfig)
@@ -495,7 +495,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify main OSPF changes
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig)
self.assertIn(f' mpls ldp-sync holddown {holddown}', frrconfig)
@@ -508,7 +508,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
for interface in interfaces:
# Verify interface changes for holddown
- config = self.getFRRconfig(f'interface {interface}', daemon=ospf_daemon)
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf dead-interval 40', config)
self.assertIn(f' ip ospf mpls ldp-sync', config)
@@ -522,7 +522,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
for interface in interfaces:
# Verify interface changes for disable
- config = self.getFRRconfig(f'interface {interface}', daemon=ospf_daemon)
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf dead-interval 40', config)
self.assertNotIn(f' ip ospf mpls ldp-sync', config)
@@ -544,7 +544,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' capability opaque', frrconfig)
self.assertIn(f' graceful-restart grace-period {period}', frrconfig)
@@ -570,7 +570,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', daemon=ospf_daemon, empty_retry=60)
+ frrconfig = self.getFRRconfig('router ospf', endsection='^exit', empty_retry=60)
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' network {network} area {area1}', frrconfig)
diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py
index d961a4fdc..5da4c7c98 100755
--- a/smoketest/scripts/cli/test_protocols_ospfv3.py
+++ b/smoketest/scripts/cli/test_protocols_ospfv3.py
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
@@ -44,6 +45,8 @@ class TestProtocolsOSPFv3(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)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
@classmethod
def tearDownClass(cls):
@@ -54,7 +57,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertNotIn(f'router ospf6', frrconfig)
# check process health and continuity
@@ -81,7 +84,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' area {default_area} range {prefix}', frrconfig)
self.assertIn(f' ospf6 router-id {router_id}', frrconfig)
@@ -89,7 +92,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' area {default_area} export-list {acl_name}', frrconfig)
for interface in interfaces:
- if_config = self.getFRRconfig(f'interface {interface}', daemon=ospf6_daemon)
+ if_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'ipv6 ospf6 area {default_area}', if_config)
self.cli_delete(['policy', 'access-list6', acl_name])
@@ -110,7 +113,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' distance {dist_global}', frrconfig)
self.assertIn(f' distance ospf6 intra-area {dist_intra_area} inter-area {dist_inter_area} external {dist_external}', frrconfig)
@@ -134,7 +137,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
for protocol in redistribute:
self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -165,13 +168,13 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
cost = '100'
priority = '10'
for interface in interfaces:
- if_config = self.getFRRconfig(f'interface {interface}', daemon=ospf6_daemon)
+ if_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', if_config)
self.assertIn(f' ipv6 ospf6 bfd', if_config)
self.assertIn(f' ipv6 ospf6 bfd profile {bfd_profile}', if_config)
@@ -188,7 +191,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
for interface in interfaces:
- if_config = self.getFRRconfig(f'interface {interface}', daemon=ospf6_daemon)
+ if_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
# There should be no OSPF6 configuration at all after interface removal
self.assertNotIn(f' ipv6 ospf6', if_config)
@@ -204,7 +207,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' area {area_stub} stub', frrconfig)
self.assertIn(f' area {area_stub_nosum} stub no-summary', frrconfig)
@@ -230,7 +233,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' area {area_nssa} nssa', frrconfig)
self.assertIn(f' area {area_nssa_nosum} nssa default-information-originate no-summary', frrconfig)
@@ -250,7 +253,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' default-information originate metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -259,7 +262,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -285,15 +288,15 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' ospf6 router-id {router_id}', frrconfig)
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', endsection='^exit')
self.assertIn(f'interface {vrf_iface}', frrconfig)
self.assertIn(f' ipv6 ospf6 bfd', frrconfig)
- frrconfig = self.getFRRconfig(f'router ospf6 vrf {vrf}', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig(f'router ospf6 vrf {vrf}', endsection='^exit')
self.assertIn(f'router ospf6 vrf {vrf}', frrconfig)
self.assertIn(f' ospf6 router-id {router_id_vrf}', frrconfig)
@@ -303,7 +306,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# T5467: It must also be removed from FRR config
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', endsection='^exit')
self.assertNotIn(f'interface {vrf_iface}', frrconfig)
# There should be no OSPF related command at all under the interface
self.assertNotIn(f' ipv6 ospf6', frrconfig)
@@ -329,7 +332,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit', daemon=ospf6_daemon)
+ frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' graceful-restart grace-period {period}', frrconfig)
self.assertIn(f' graceful-restart helper planned-only', frrconfig)
diff --git a/smoketest/scripts/cli/test_protocols_pim.py b/smoketest/scripts/cli/test_protocols_pim.py
index 98b9d57aa..cc62769b3 100755
--- a/smoketest/scripts/cli/test_protocols_pim.py
+++ b/smoketest/scripts/cli/test_protocols_pim.py
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.frrender import pim_daemon
@@ -26,6 +27,16 @@ from vyos.utils.process import process_named_running
base_path = ['protocols', 'pim']
class TestProtocolsPIM(VyOSUnitTestSHIM.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ # call base-classes classmethod
+ super(TestProtocolsPIM, cls).setUpClass()
+ # ensure we can also run this test on a live system - so lets clean
+ # out the current configuration :)
+ cls.cli_delete(cls, base_path)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
+
def tearDown(self):
# pimd process must be running
self.assertTrue(process_named_running(pim_daemon))
@@ -57,11 +68,11 @@ class TestProtocolsPIM(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR pimd configuration
- frrconfig = self.getFRRconfig('router pim', endsection='^exit', daemon=pim_daemon)
+ frrconfig = self.getFRRconfig('router pim', endsection='^exit')
self.assertIn(f' rp {rp} {group}', frrconfig)
for interface in interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', daemon=pim_daemon)
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', frrconfig)
self.assertIn(f' ip pim', frrconfig)
self.assertIn(f' ip pim bfd', frrconfig)
@@ -108,7 +119,7 @@ class TestProtocolsPIM(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR pimd configuration
- frrconfig = self.getFRRconfig('router pim', endsection='^exit', daemon=pim_daemon)
+ frrconfig = self.getFRRconfig('router pim', endsection='^exit')
self.assertIn(f' no send-v6-secondary', frrconfig)
self.assertIn(f' rp {rp} {group}', frrconfig)
self.assertIn(f' register-suppress-time {register_suppress_time}', frrconfig)
@@ -170,11 +181,11 @@ class TestProtocolsPIM(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
- frrconfig = self.getFRRconfig(daemon=pim_daemon)
+ frrconfig = self.getFRRconfig()
self.assertIn(f'ip igmp watermark-warn {watermark_warning}', frrconfig)
for interface in interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', daemon=pim_daemon)
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', frrconfig)
self.assertIn(f' ip igmp', frrconfig)
self.assertIn(f' ip igmp version {version}', frrconfig)
diff --git a/smoketest/scripts/cli/test_protocols_pim6.py b/smoketest/scripts/cli/test_protocols_pim6.py
index f69eb4ae1..4ed8fcf7a 100755
--- a/smoketest/scripts/cli/test_protocols_pim6.py
+++ b/smoketest/scripts/cli/test_protocols_pim6.py
@@ -17,6 +17,8 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
+
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.frrender import pim6_daemon
@@ -34,6 +36,8 @@ class TestProtocolsPIMv6(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)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
@@ -52,7 +56,7 @@ class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase):
# Verify FRR pim6d configuration
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', daemon=pim6_daemon)
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ipv6 mld', config)
self.assertNotIn(f' ipv6 mld version 1', config)
@@ -65,7 +69,7 @@ class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase):
# Verify FRR pim6d configuration
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', daemon=pim6_daemon)
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ipv6 mld', config)
self.assertIn(f' ipv6 mld version 1', config)
@@ -88,7 +92,7 @@ class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase):
# Verify FRR pim6d configuration
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', daemon=pim6_daemon)
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ipv6 mld join-group ff18::1234', config)
@@ -100,7 +104,7 @@ class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase):
# Verify FRR pim6d configuration
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', daemon=pim6_daemon)
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ipv6 mld join-group ff38::5678 2001:db8::5678', config)
@@ -128,14 +132,14 @@ class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR pim6d configuration
- config = self.getFRRconfig('router pim6', endsection='^exit', daemon=pim6_daemon)
+ config = self.getFRRconfig('router pim6', endsection='^exit')
self.assertIn(f' join-prune-interval {join_prune_interval}', config)
self.assertIn(f' keep-alive-timer {keep_alive_timer}', config)
self.assertIn(f' packets {packets}', config)
self.assertIn(f' register-suppress-time {register_suppress_time}', config)
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', daemon=pim6_daemon)
+ config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' ipv6 pim drpriority {dr_priority}', config)
self.assertIn(f' ipv6 pim hello {hello}', config)
self.assertIn(f' no ipv6 pim bsm', config)
diff --git a/smoketest/scripts/cli/test_protocols_rip.py b/smoketest/scripts/cli/test_protocols_rip.py
index 33706a9c9..671ef8cd5 100755
--- a/smoketest/scripts/cli/test_protocols_rip.py
+++ b/smoketest/scripts/cli/test_protocols_rip.py
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.ifconfig import Section
from vyos.frrender import rip_daemon
@@ -39,6 +40,8 @@ class TestProtocolsRIP(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)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
cls.cli_set(cls, ['policy', 'access-list', acl_in, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'access-list', acl_in, 'rule', '10', 'source', 'any'])
@@ -66,7 +69,7 @@ class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router rip')
+ frrconfig = self.getFRRconfig('router rip', endsection='^exit')
self.assertNotIn(f'router rip', frrconfig)
# check process health and continuity
@@ -116,7 +119,7 @@ class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ripd configuration
- frrconfig = self.getFRRconfig('router rip')
+ frrconfig = self.getFRRconfig('router rip', endsection='^exit')
self.assertIn(f'router rip', frrconfig)
self.assertIn(f' distance {distance}', frrconfig)
self.assertIn(f' default-information originate', frrconfig)
@@ -175,10 +178,10 @@ class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR configuration
- frrconfig = self.getFRRconfig('router rip')
+ frrconfig = self.getFRRconfig('router rip', endsection='^exit')
self.assertIn(f'version {tx_version}', frrconfig)
- frrconfig = self.getFRRconfig(f'interface {interface}')
+ frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
self.assertIn(f' ip rip receive version {rx_version}', frrconfig)
self.assertIn(f' ip rip send version {tx_version}', frrconfig)
diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py
index b10df9679..d2066b825 100755
--- a/smoketest/scripts/cli/test_protocols_ripng.py
+++ b/smoketest/scripts/cli/test_protocols_ripng.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2025 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
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.ifconfig import Section
from vyos.frrender import ripng_daemon
@@ -40,6 +41,8 @@ class TestProtocolsRIPng(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)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
cls.cli_set(cls, ['policy', 'access-list6', acl_in, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'access-list6', acl_in, 'rule', '10', 'source', 'any'])
@@ -66,7 +69,7 @@ class TestProtocolsRIPng(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router ripng')
+ frrconfig = self.getFRRconfig('router ripng', endsection='^exit')
self.assertNotIn(f'router ripng', frrconfig)
# check process health and continuity
@@ -113,7 +116,7 @@ class TestProtocolsRIPng(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ripng')
+ frrconfig = self.getFRRconfig('router ripng', endsection='^exit')
self.assertIn(f'router ripng', frrconfig)
self.assertIn(f' default-information originate', frrconfig)
self.assertIn(f' default-metric {metric}', frrconfig)
diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py
index 23738717a..ef2f30d3e 100755
--- a/smoketest/scripts/cli/test_protocols_rpki.py
+++ b/smoketest/scripts/cli/test_protocols_rpki.py
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.frrender import bgp_daemon
@@ -111,12 +112,14 @@ 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)
+ # 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_commit()
- frrconfig = self.getFRRconfig('rpki')
+ frrconfig = self.getFRRconfig('rpki', endsection='^exit')
self.assertNotIn(f'rpki', frrconfig)
# check process health and continuity
@@ -153,7 +156,7 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR configuration
- frrconfig = self.getFRRconfig('rpki')
+ 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)
@@ -192,7 +195,7 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR configuration
- frrconfig = self.getFRRconfig('rpki')
+ frrconfig = self.getFRRconfig('rpki', endsection='^exit')
for cache_name, cache_config in cache.items():
port = cache_config['port']
preference = cache_config['preference']
diff --git a/smoketest/scripts/cli/test_protocols_segment-routing.py b/smoketest/scripts/cli/test_protocols_segment-routing.py
index 624985476..94c808733 100755
--- a/smoketest/scripts/cli/test_protocols_segment-routing.py
+++ b/smoketest/scripts/cli/test_protocols_segment-routing.py
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
@@ -26,6 +27,7 @@ from vyos.utils.system import sysctl_read
base_path = ['protocols', 'segment-routing']
+
class TestProtocolsSegmentRouting(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
@@ -36,6 +38,8 @@ class TestProtocolsSegmentRouting(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)
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
@@ -47,14 +51,64 @@ class TestProtocolsSegmentRouting(VyOSUnitTestSHIM.TestCase):
def test_srv6(self):
interfaces = Section.interfaces('ethernet', vlan=False)
locators = {
- 'foo' : { 'prefix' : '2001:a::/64' },
- 'foo' : { 'prefix' : '2001:b::/64', 'usid' : {} },
+ 'foo1': {'prefix': '2001:a::/64'},
+ 'foo2': {'prefix': '2001:b::/64', 'usid': {}},
+ 'foo3': {'prefix': '2001:c::/64', 'format': 'uncompressed-f4024'},
+ 'foo4': {
+ 'prefix': '2001:d::/48',
+ 'block-len': '32',
+ 'node-len': '16',
+ 'func-bits': '16',
+ 'usid': {},
+ 'format': 'usid-f3216',
+ },
}
for locator, locator_config in locators.items():
- self.cli_set(base_path + ['srv6', 'locator', locator, 'prefix', locator_config['prefix']])
+ self.cli_set(
+ base_path
+ + ['srv6', 'locator', locator, 'prefix', locator_config['prefix']]
+ )
+ if 'block-len' in locator_config:
+ self.cli_set(
+ base_path
+ + [
+ 'srv6',
+ 'locator',
+ locator,
+ 'block-len',
+ locator_config['block-len'],
+ ]
+ )
+ if 'node-len' in locator_config:
+ self.cli_set(
+ base_path
+ + [
+ 'srv6',
+ 'locator',
+ locator,
+ 'node-len',
+ locator_config['node-len'],
+ ]
+ )
+ if 'func-bits' in locator_config:
+ self.cli_set(
+ base_path
+ + [
+ 'srv6',
+ 'locator',
+ locator,
+ 'func-bits',
+ locator_config['func-bits'],
+ ]
+ )
if 'usid' in locator_config:
self.cli_set(base_path + ['srv6', 'locator', locator, 'behavior-usid'])
+ if 'format' in locator_config:
+ self.cli_set(
+ base_path
+ + ['srv6', 'locator', locator, 'format', locator_config['format']]
+ )
# verify() - SRv6 should be enabled on at least one interface!
with self.assertRaises(ConfigSessionError):
@@ -65,16 +119,33 @@ class TestProtocolsSegmentRouting(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
for interface in interfaces:
- self.assertEqual(sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1')
- self.assertEqual(sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '0') # default
-
- frrconfig = self.getFRRconfig(f'segment-routing', daemon=zebra_daemon)
- self.assertIn(f'segment-routing', frrconfig)
- self.assertIn(f' srv6', frrconfig)
- self.assertIn(f' locators', frrconfig)
+ self.assertEqual(
+ sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1'
+ )
+ self.assertEqual(
+ sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '0'
+ ) # default
+
+ frrconfig = self.getFRRconfig('segment-routing', endsection='^exit')
+ self.assertIn('segment-routing', frrconfig)
+ self.assertIn(' srv6', frrconfig)
+ self.assertIn(' locators', frrconfig)
for locator, locator_config in locators.items():
+ prefix = locator_config['prefix']
+ block_len = locator_config.get('block-len', '40')
+ node_len = locator_config.get('node-len', '24')
+ func_bits = locator_config.get('func-bits', '16')
+
self.assertIn(f' locator {locator}', frrconfig)
- self.assertIn(f' prefix {locator_config["prefix"]} block-len 40 node-len 24 func-bits 16', frrconfig)
+ self.assertIn(
+ f' prefix {prefix} block-len {block_len} node-len {node_len} func-bits {func_bits}',
+ frrconfig,
+ )
+
+ if 'format' in locator_config:
+ self.assertIn(f' format {locator_config["format"]}', frrconfig)
+ if 'usid' in locator_config:
+ self.assertIn(' behavior usid', frrconfig)
def test_srv6_sysctl(self):
interfaces = Section.interfaces('ethernet', vlan=False)
@@ -86,8 +157,12 @@ class TestProtocolsSegmentRouting(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
for interface in interfaces:
- self.assertEqual(sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1')
- self.assertEqual(sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '-1') # ignore
+ self.assertEqual(
+ sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1'
+ )
+ self.assertEqual(
+ sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '-1'
+ ) # ignore
# HMAC drop
for interface in interfaces:
@@ -96,8 +171,12 @@ class TestProtocolsSegmentRouting(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
for interface in interfaces:
- self.assertEqual(sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1')
- self.assertEqual(sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '1') # drop
+ self.assertEqual(
+ sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1'
+ )
+ self.assertEqual(
+ sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '1'
+ ) # drop
# Disable SRv6 on first interface
first_if = interfaces[-1]
@@ -106,5 +185,6 @@ class TestProtocolsSegmentRouting(VyOSUnitTestSHIM.TestCase):
self.assertEqual(sysctl_read(f'net.ipv6.conf.{first_if}.seg6_enabled'), '0')
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
index a2cde0237..79d6b3af4 100755
--- a/smoketest/scripts/cli/test_protocols_static.py
+++ b/smoketest/scripts/cli/test_protocols_static.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright (C) 2021-2025 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
@@ -14,14 +14,20 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
import unittest
+from time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv6
+from vyos.template import get_dhcp_router
from vyos.utils.network import get_interface_config
from vyos.utils.network import get_vrf_tableid
+from vyos.utils.process import process_named_running
+from vyos.xml_ref import default_value
base_path = ['protocols', 'static']
vrf_path = ['protocols', 'vrf']
@@ -163,16 +169,20 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsStatic, cls).setUpClass()
+ cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['vrf'])
- cls.cli_set(cls, ['vrf', 'name', 'black', 'table', '43210'])
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
@classmethod
def tearDownClass(cls):
+ cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['vrf'])
super(TestProtocolsStatic, cls).tearDownClass()
def tearDown(self):
self.cli_delete(base_path)
+ self.cli_delete(['vrf'])
self.cli_commit()
v4route = self.getFRRconfig('ip route', end='')
@@ -181,6 +191,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
self.assertFalse(v6route)
def test_01_static(self):
+ self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
for route, route_config in routes.items():
route_type = 'route'
if is_ipv6(route):
@@ -315,6 +326,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
self.assertIn(tmp, frrconfig)
def test_02_static_table(self):
+ self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
for table in tables:
for route, route_config in routes.items():
route_type = 'route'
@@ -409,6 +421,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
def test_03_static_vrf(self):
+ self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
# Create VRF instances and apply the static routes from above to FRR.
# Re-read the configured routes and match them if they are programmed
# properly. This also includes VRF leaking
@@ -567,5 +580,44 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
else:
self.assertIn(tmp, frrconfig)
+ def test_05_dhcp_default_route(self):
+ # When running via vyos-build under the QEmu environment a local DHCP
+ # server is available. This test verifies that the default route is set.
+ # When not running under the VyOS QEMU environment, this test is skipped.
+ if not os.path.exists('/tmp/vyos.smoketests.hint'):
+ self.skipTest('Not running under VyOS CI/CD QEMU environment!')
+
+ interface = 'eth0'
+ interface_path = ['interfaces', 'ethernet', interface]
+ default_distance = default_value(interface_path + ['dhcp-options', 'default-route-distance'])
+ self.cli_set(interface_path + ['address', 'dhcp'])
+ self.cli_commit()
+
+ # Wait for dhclient to receive IP address and default gateway
+ sleep(5)
+
+ router = get_dhcp_router(interface)
+ frrconfig = self.getFRRconfig('')
+ self.assertIn(rf'ip route 0.0.0.0/0 {router} {interface} tag 210 {default_distance}', frrconfig)
+
+ # T6991: Default route is missing when there is no "protocols static"
+ # CLI node entry
+ self.cli_delete(base_path)
+ # We can trigger a FRR reconfiguration and config re-rendering when
+ # we simply disable IPv6 forwarding
+ self.cli_set(['system', 'ipv6', 'disable-forwarding'])
+ self.cli_commit()
+
+ # Re-check FRR configuration that default route is still present
+ frrconfig = self.getFRRconfig('')
+ self.assertIn(rf'ip route 0.0.0.0/0 {router} {interface} tag 210 {default_distance}', frrconfig)
+
+ self.cli_delete(interface_path + ['address'])
+ self.cli_commit()
+
+ # Wait for dhclient to stop
+ while process_named_running('dhclient', cmdline=interface, timeout=10):
+ sleep(0.250)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py
index 3ce459e44..9fbc931de 100755
--- a/smoketest/scripts/cli/test_service_dns_dynamic.py
+++ b/smoketest/scripts/cli/test_service_dns_dynamic.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright (C) 2019-2025 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
@@ -38,13 +38,17 @@ ttl = '300'
interface = 'eth0'
class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
- def setUp(self):
- # Always start with a clean CLI instance
- self.cli_delete(base_path)
+ @classmethod
+ def setUpClass(cls):
+ super(TestServiceDDNS, cls).setUpClass()
+
+ # ensure we can also run this test on a live system - so lets clean
+ # out the current configuration :)
+ cls.cli_delete(cls, base_path)
def tearDown(self):
# Check for running process
- self.assertTrue(process_named_running(DDCLIENT_PNAME))
+ self.assertTrue(process_named_running(DDCLIENT_PNAME, timeout=10))
# Delete DDNS configuration
self.cli_delete(base_path)
@@ -336,8 +340,8 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
# Check for process in VRF
systemd_override = cmd(f'cat {DDCLIENT_SYSTEMD_UNIT}')
- self.assertIn(f'ExecStart=ip vrf exec {vrf_name} /usr/bin/ddclient -file {DDCLIENT_CONF}',
- systemd_override)
+ self.assertIn(f'ExecStart=ip vrf exec {vrf_name} /usr/bin/ddclient ' \
+ f'--file {DDCLIENT_CONF} --foreground', systemd_override)
# Check for process in VRF
proc = cmd(f'ip vrf pids {vrf_name}')
diff --git a/smoketest/scripts/cli/test_service_monitoring_prometheus.py b/smoketest/scripts/cli/test_service_monitoring_prometheus.py
index dae103e4b..6e7f8c808 100755
--- a/smoketest/scripts/cli/test_service_monitoring_prometheus.py
+++ b/smoketest/scripts/cli/test_service_monitoring_prometheus.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
@@ -22,12 +23,14 @@ from vyos.utils.file import read_file
NODE_EXPORTER_PROCESS_NAME = 'node_exporter'
FRR_EXPORTER_PROCESS_NAME = 'frr_exporter'
+BLACKBOX_EXPORTER_PROCESS_NAME = 'blackbox_exporter'
base_path = ['service', 'monitoring', 'prometheus']
listen_if = 'dum3421'
listen_ip = '192.0.2.1'
node_exporter_service_file = '/etc/systemd/system/node_exporter.service'
frr_exporter_service_file = '/etc/systemd/system/frr_exporter.service'
+blackbox_exporter_service_file = '/etc/systemd/system/blackbox_exporter.service'
class TestMonitoringPrometheus(VyOSUnitTestSHIM.TestCase):
@@ -53,6 +56,7 @@ class TestMonitoringPrometheus(VyOSUnitTestSHIM.TestCase):
def test_01_node_exporter(self):
self.cli_set(base_path + ['node-exporter', 'listen-address', listen_ip])
+ self.cli_set(base_path + ['node-exporter', 'collectors', 'textfile'])
# commit changes
self.cli_commit()
@@ -60,6 +64,11 @@ class TestMonitoringPrometheus(VyOSUnitTestSHIM.TestCase):
file_content = read_file(node_exporter_service_file)
self.assertIn(f'{listen_ip}:9100', file_content)
+ self.assertTrue(os.path.isdir('/run/node_exporter/collector'))
+ self.assertIn(
+ '--collector.textfile.directory=/run/node_exporter/collector', file_content
+ )
+
# Check for running process
self.assertTrue(process_named_running(NODE_EXPORTER_PROCESS_NAME))
@@ -75,6 +84,78 @@ class TestMonitoringPrometheus(VyOSUnitTestSHIM.TestCase):
# Check for running process
self.assertTrue(process_named_running(FRR_EXPORTER_PROCESS_NAME))
+ def test_03_blackbox_exporter(self):
+ self.cli_set(base_path + ['blackbox-exporter', 'listen-address', listen_ip])
+
+ # commit changes
+ self.cli_commit()
+
+ file_content = read_file(blackbox_exporter_service_file)
+ self.assertIn(f'{listen_ip}:9115', file_content)
+
+ # Check for running process
+ self.assertTrue(process_named_running(BLACKBOX_EXPORTER_PROCESS_NAME))
+
+ def test_04_blackbox_exporter_with_config(self):
+ self.cli_set(base_path + ['blackbox-exporter', 'listen-address', listen_ip])
+ self.cli_set(
+ base_path
+ + [
+ 'blackbox-exporter',
+ 'modules',
+ 'dns',
+ 'name',
+ 'dns_ip4',
+ 'preferred-ip-protocol',
+ 'ipv4',
+ ]
+ )
+ self.cli_set(
+ base_path
+ + [
+ 'blackbox-exporter',
+ 'modules',
+ 'dns',
+ 'name',
+ 'dns_ip4',
+ 'query-name',
+ 'vyos.io',
+ ]
+ )
+ self.cli_set(
+ base_path
+ + [
+ 'blackbox-exporter',
+ 'modules',
+ 'dns',
+ 'name',
+ 'dns_ip4',
+ 'query-type',
+ 'A',
+ ]
+ )
+ self.cli_set(
+ base_path
+ + [
+ 'blackbox-exporter',
+ 'modules',
+ 'icmp',
+ 'name',
+ 'icmp_ip6',
+ 'preferred-ip-protocol',
+ 'ipv6',
+ ]
+ )
+
+ # commit changes
+ self.cli_commit()
+
+ file_content = read_file(blackbox_exporter_service_file)
+ self.assertIn(f'{listen_ip}:9115', file_content)
+
+ # Check for running process
+ self.assertTrue(process_named_running(BLACKBOX_EXPORTER_PROCESS_NAME))
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_ssh.py b/smoketest/scripts/cli/test_service_ssh.py
index d8e325eee..fa08a5b32 100755
--- a/smoketest/scripts/cli/test_service_ssh.py
+++ b/smoketest/scripts/cli/test_service_ssh.py
@@ -33,16 +33,32 @@ from vyos.xml_ref import default_value
PROCESS_NAME = 'sshd'
SSHD_CONF = '/run/sshd/sshd_config'
base_path = ['service', 'ssh']
+pki_path = ['pki']
key_rsa = '/etc/ssh/ssh_host_rsa_key'
key_dsa = '/etc/ssh/ssh_host_dsa_key'
key_ed25519 = '/etc/ssh/ssh_host_ed25519_key'
+trusted_user_ca_key = '/etc/ssh/trusted_user_ca_key'
+
def get_config_value(key):
tmp = read_file(SSHD_CONF)
tmp = re.findall(f'\n?{key}\s+(.*)', tmp)
return tmp
+
+ca_root_cert_data = """
+MIIBcTCCARagAwIBAgIUDcAf1oIQV+6WRaW7NPcSnECQ/lUwCgYIKoZIzj0EAwIw
+HjEcMBoGA1UEAwwTVnlPUyBzZXJ2ZXIgcm9vdCBDQTAeFw0yMjAyMTcxOTQxMjBa
+Fw0zMjAyMTUxOTQxMjBaMB4xHDAaBgNVBAMME1Z5T1Mgc2VydmVyIHJvb3QgQ0Ew
+WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ0y24GzKQf4aM2Ir12tI9yITOIzAUj
+ZXyJeCmYI6uAnyAMqc4Q4NKyfq3nBi4XP87cs1jlC1P2BZ8MsjL5MdGWozIwMDAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRwC/YaieMEnjhYa7K3Flw/o0SFuzAK
+BggqhkjOPQQDAgNJADBGAiEAh3qEj8vScsjAdBy5shXzXDVVOKWCPTdGrPKnu8UW
+a2cCIQDlDgkzWmn5ujc5ATKz1fj+Se/aeqwh4QyoWCVTFLIxhQ==
+"""
+
+
class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
@@ -98,27 +114,27 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
# Check configured port
port = get_config_value('Port')[0]
- self.assertTrue("1234" in port)
+ self.assertTrue('1234' in port)
# Check DNS usage
dns = get_config_value('UseDNS')[0]
- self.assertTrue("no" in dns)
+ self.assertTrue('no' in dns)
# Check PasswordAuthentication
pwd = get_config_value('PasswordAuthentication')[0]
- self.assertTrue("no" in pwd)
+ self.assertTrue('no' in pwd)
# Check loglevel
loglevel = get_config_value('LogLevel')[0]
- self.assertTrue("VERBOSE" in loglevel)
+ self.assertTrue('VERBOSE' in loglevel)
# Check listen address
address = get_config_value('ListenAddress')[0]
- self.assertTrue("127.0.0.1" in address)
+ self.assertTrue('127.0.0.1' in address)
# Check keepalive
keepalive = get_config_value('ClientAliveInterval')[0]
- self.assertTrue("100" in keepalive)
+ self.assertTrue('100' in keepalive)
def test_ssh_multiple_listen_addresses(self):
# Check if SSH service can be configured and runs with multiple
@@ -197,7 +213,17 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
test_command = 'uname -a'
self.cli_set(base_path)
- self.cli_set(['system', 'login', 'user', test_user, 'authentication', 'plaintext-password', test_pass])
+ self.cli_set(
+ [
+ 'system',
+ 'login',
+ 'user',
+ test_user,
+ 'authentication',
+ 'plaintext-password',
+ test_pass,
+ ]
+ )
# commit changes
self.cli_commit()
@@ -210,7 +236,9 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
# Login with invalid credentials
with self.assertRaises(paramiko.ssh_exception.AuthenticationException):
- output, error = self.ssh_send_cmd(test_command, 'invalid_user', 'invalid_password')
+ output, error = self.ssh_send_cmd(
+ test_command, 'invalid_user', 'invalid_password'
+ )
self.cli_delete(['system', 'login', 'user', test_user])
self.cli_commit()
@@ -250,7 +278,7 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
sshguard_lines = [
f'THRESHOLD={threshold}',
f'BLOCK_TIME={block_time}',
- f'DETECTION_TIME={detect_time}'
+ f'DETECTION_TIME={detect_time}',
]
tmp_sshguard_conf = read_file(SSHGUARD_CONFIG)
@@ -268,12 +296,16 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
self.assertFalse(process_named_running(SSHGUARD_PROCESS))
-
# Network Device Collaborative Protection Profile
def test_ssh_ndcpp(self):
ciphers = ['aes128-cbc', 'aes128-ctr', 'aes256-cbc', 'aes256-ctr']
host_key_algs = ['sk-ssh-ed25519@openssh.com', 'ssh-rsa', 'ssh-ed25519']
- kexes = ['diffie-hellman-group14-sha1', 'ecdh-sha2-nistp256', 'ecdh-sha2-nistp384', 'ecdh-sha2-nistp521']
+ kexes = [
+ 'diffie-hellman-group14-sha1',
+ 'ecdh-sha2-nistp256',
+ 'ecdh-sha2-nistp384',
+ 'ecdh-sha2-nistp521',
+ ]
macs = ['hmac-sha1', 'hmac-sha2-256', 'hmac-sha2-512']
rekey_time = '60'
rekey_data = '1024'
@@ -293,22 +325,29 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
# commit changes
self.cli_commit()
- ssh_lines = ['Ciphers aes128-cbc,aes128-ctr,aes256-cbc,aes256-ctr',
- 'HostKeyAlgorithms sk-ssh-ed25519@openssh.com,ssh-rsa,ssh-ed25519',
- 'MACs hmac-sha1,hmac-sha2-256,hmac-sha2-512',
- 'KexAlgorithms diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521',
- 'RekeyLimit 1024M 60M'
- ]
+ ssh_lines = [
+ 'Ciphers aes128-cbc,aes128-ctr,aes256-cbc,aes256-ctr',
+ 'HostKeyAlgorithms sk-ssh-ed25519@openssh.com,ssh-rsa,ssh-ed25519',
+ 'MACs hmac-sha1,hmac-sha2-256,hmac-sha2-512',
+ 'KexAlgorithms diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521',
+ 'RekeyLimit 1024M 60M',
+ ]
tmp_sshd_conf = read_file(SSHD_CONF)
for line in ssh_lines:
self.assertIn(line, tmp_sshd_conf)
def test_ssh_pubkey_accepted_algorithm(self):
- algs = ['ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384',
- 'ecdsa-sha2-nistp521', 'ssh-dss', 'ssh-rsa', 'rsa-sha2-256',
- 'rsa-sha2-512'
- ]
+ algs = [
+ 'ssh-ed25519',
+ 'ecdsa-sha2-nistp256',
+ 'ecdsa-sha2-nistp384',
+ 'ecdsa-sha2-nistp521',
+ 'ssh-dss',
+ 'ssh-rsa',
+ 'rsa-sha2-256',
+ 'rsa-sha2-512',
+ ]
expected = 'PubkeyAcceptedAlgorithms '
for alg in algs:
@@ -320,6 +359,40 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
tmp_sshd_conf = read_file(SSHD_CONF)
self.assertIn(expected, tmp_sshd_conf)
+ def test_ssh_trusted_user_ca_key(self):
+ ca_cert_name = 'test_ca'
+
+ # set pki ca <ca_cert_name> certificate <ca_key_data>
+ # set service ssh trusted-user-ca-key ca-certificate <ca_cert_name>
+ self.cli_set(
+ pki_path
+ + [
+ 'ca',
+ ca_cert_name,
+ 'certificate',
+ ca_root_cert_data.replace('\n', ''),
+ ]
+ )
+ self.cli_set(
+ base_path + ['trusted-user-ca-key', 'ca-certificate', ca_cert_name]
+ )
+ self.cli_commit()
+
+ trusted_user_ca_key_config = get_config_value('TrustedUserCAKeys')
+ self.assertIn(trusted_user_ca_key, trusted_user_ca_key_config)
+
+ with open(trusted_user_ca_key, 'r') as file:
+ ca_key_contents = file.read()
+ self.assertIn(ca_root_cert_data, ca_key_contents)
+
+ self.cli_delete(base_path + ['trusted-user-ca-key'])
+ self.cli_delete(['pki', 'ca', ca_cert_name])
+ self.cli_commit()
+
+ # Verify the CA key is removed
+ trusted_user_ca_key_config = get_config_value('TrustedUserCAKeys')
+ self.assertNotIn(trusted_user_ca_key, trusted_user_ca_key_config)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py
index 7d730f7b2..5b6ef2046 100755
--- a/smoketest/scripts/cli/test_system_ip.py
+++ b/smoketest/scripts/cli/test_system_ip.py
@@ -20,8 +20,6 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.utils.system import sysctl_read
from vyos.xml_ref import default_value
-from vyos.frrender import mgmt_daemon
-from vyos.frrender import zebra_daemon
base_path = ['system', 'ip']
@@ -45,13 +43,13 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['disable-forwarding'])
self.cli_commit()
self.assertEqual(sysctl_read('net.ipv4.conf.all.forwarding'), '0')
- frrconfig = self.getFRRconfig('', end='', daemon=zebra_daemon)
+ frrconfig = self.getFRRconfig('', end='')
self.assertIn('no ip forwarding', frrconfig)
self.cli_delete(base_path + ['disable-forwarding'])
self.cli_commit()
self.assertEqual(sysctl_read('net.ipv4.conf.all.forwarding'), '1')
- frrconfig = self.getFRRconfig('', end='', daemon=zebra_daemon)
+ frrconfig = self.getFRRconfig('', end='')
self.assertNotIn('no ip forwarding', frrconfig)
def test_system_ip_multipath(self):
@@ -91,7 +89,7 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify route-map properly applied to FRR
- frrconfig = self.getFRRconfig('ip protocol', end='', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig('ip protocol', end='')
for protocol in protocols:
self.assertIn(f'ip protocol {protocol} route-map route-map-{protocol}', frrconfig)
@@ -102,7 +100,7 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify route-map properly applied to FRR
- frrconfig = self.getFRRconfig('ip protocol', end='', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig('ip protocol', end='')
self.assertNotIn(f'ip protocol', frrconfig)
def test_system_ip_protocol_non_existing_route_map(self):
@@ -121,13 +119,13 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['nht', 'no-resolve-via-default'])
self.cli_commit()
# Verify CLI config applied to FRR
- frrconfig = self.getFRRconfig('', end='', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig('', end='')
self.assertIn(f'no ip nht resolve-via-default', frrconfig)
self.cli_delete(base_path + ['nht', 'no-resolve-via-default'])
self.cli_commit()
# Verify CLI config removed to FRR
- frrconfig = self.getFRRconfig('', end='', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig('', end='')
self.assertNotIn(f'no ip nht resolve-via-default', frrconfig)
if __name__ == '__main__':
diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py
index ebf620204..26f281bb4 100755
--- a/smoketest/scripts/cli/test_system_ipv6.py
+++ b/smoketest/scripts/cli/test_system_ipv6.py
@@ -21,8 +21,6 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.utils.system import sysctl_read
from vyos.xml_ref import default_value
-from vyos.frrender import mgmt_daemon
-from vyos.frrender import zebra_daemon
base_path = ['system', 'ipv6']
@@ -46,13 +44,13 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['disable-forwarding'])
self.cli_commit()
self.assertEqual(sysctl_read('net.ipv6.conf.all.forwarding'), '0')
- frrconfig = self.getFRRconfig('', end='', daemon=zebra_daemon)
+ frrconfig = self.getFRRconfig('', end='')
self.assertIn('no ipv6 forwarding', frrconfig)
self.cli_delete(base_path + ['disable-forwarding'])
self.cli_commit()
self.assertEqual(sysctl_read('net.ipv6.conf.all.forwarding'), '1')
- frrconfig = self.getFRRconfig('', end='', daemon=zebra_daemon)
+ frrconfig = self.getFRRconfig('', end='')
self.assertNotIn('no ipv6 forwarding', frrconfig)
def test_system_ipv6_strict_dad(self):
@@ -109,7 +107,7 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify route-map properly applied to FRR
- frrconfig = self.getFRRconfig('ipv6 protocol', end='', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig('ipv6 protocol', end='')
for protocol in protocols:
# VyOS and FRR use a different name for OSPFv3 (IPv6)
if protocol == 'ospfv3':
@@ -123,7 +121,7 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify route-map properly applied to FRR
- frrconfig = self.getFRRconfig('ipv6 protocol', end='', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig('ipv6 protocol', end='')
self.assertNotIn(f'ipv6 protocol', frrconfig)
def test_system_ipv6_protocol_non_existing_route_map(self):
@@ -142,13 +140,13 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['nht', 'no-resolve-via-default'])
self.cli_commit()
# Verify CLI config applied to FRR
- frrconfig = self.getFRRconfig('', end='', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig('', end='')
self.assertIn(f'no ipv6 nht resolve-via-default', frrconfig)
self.cli_delete(base_path + ['nht', 'no-resolve-via-default'])
self.cli_commit()
# Verify CLI config removed to FRR
- frrconfig = self.getFRRconfig('', end='', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig('', end='')
self.assertNotIn(f'no ipv6 nht resolve-via-default', frrconfig)
if __name__ == '__main__':
diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py
index f4ed1a61f..30980f9ec 100755
--- a/smoketest/scripts/cli/test_vrf.py
+++ b/smoketest/scripts/cli/test_vrf.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright (C) 2020-2025 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
@@ -18,12 +18,13 @@ import re
import os
import unittest
-from base_vyostest_shim import VyOSUnitTestSHIM
from json import loads
from jmespath import search
+from base_vyostest_shim import VyOSUnitTestSHIM
+from base_vyostest_shim import CSTORE_GUARD_TIME
+
from vyos.configsession import ConfigSessionError
-from vyos.frrender import mgmt_daemon
from vyos.ifconfig import Interface
from vyos.ifconfig import Section
from vyos.utils.file import read_file
@@ -52,6 +53,10 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
else:
for tmp in Section.interfaces('ethernet', vlan=False):
cls._interfaces.append(tmp)
+
+ # Enable CSTORE guard time required by FRR related tests
+ cls._commit_guard_time = CSTORE_GUARD_TIME
+
# call base-classes classmethod
super(VRFTest, cls).setUpClass()
@@ -113,7 +118,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
regex = f'{table}\s+{vrf}\s+#\s+{description}'
self.assertTrue(re.findall(regex, iproute2_config))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
self.assertEqual(int(table), get_vrf_tableid(vrf))
@@ -234,7 +239,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
self.assertIn(f' ip route {prefix} {next_hop}', frrconfig)
@@ -318,7 +323,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
# Verify route-map properly applied to FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f'vrf {vrf}', frrconfig)
for protocol in v4_protocols:
self.assertIn(f' ip protocol {protocol} route-map route-map-{vrf}-{protocol}', frrconfig)
@@ -333,7 +338,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
# Verify route-map properly is removed from FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertNotIn(f' ip protocol', frrconfig)
def test_vrf_ip_ipv6_protocol_non_existing_route_map(self):
@@ -381,7 +386,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
# Verify route-map properly applied to FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f'vrf {vrf}', frrconfig)
for protocol in v6_protocols:
# VyOS and FRR use a different name for OSPFv3 (IPv6)
@@ -400,7 +405,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
# Verify route-map properly is removed from FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertNotIn(f' ipv6 protocol', frrconfig)
def test_vrf_vni_duplicates(self):
@@ -430,7 +435,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 1)
@@ -452,7 +457,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 1)
@@ -475,7 +480,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 2)
@@ -495,7 +500,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 2)
@@ -503,7 +508,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
# Verify purple VRF/VNI
self.assertTrue(interface_exists(purple))
table = str(int(table) + 10)
- frrconfig = self.getFRRconfig(f'vrf {purple}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {purple}', endsection='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Now delete all the VNIs
@@ -518,12 +523,12 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertNotIn('vni', frrconfig)
# Verify purple VNI remains
self.assertTrue(interface_exists(purple))
- frrconfig = self.getFRRconfig(f'vrf {purple}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {purple}', endsection='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
def test_vrf_ip_ipv6_nht(self):
@@ -541,7 +546,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
# Verify route-map properly applied to FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertIn(f'vrf {vrf}', frrconfig)
self.assertIn(f' no ip nht resolve-via-default', frrconfig)
self.assertIn(f' no ipv6 nht resolve-via-default', frrconfig)
@@ -556,7 +561,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
# Verify route-map properly is removed from FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon=mgmt_daemon)
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
self.assertNotIn(f' no ip nht resolve-via-default', frrconfig)
self.assertNotIn(f' no ipv6 nht resolve-via-default', frrconfig)
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index ffbd915a2..768bb127d 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -18,7 +18,6 @@ import os
import re
from sys import exit
-
from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import is_node_changed
@@ -34,6 +33,8 @@ from vyos.utils.dict import dict_search_recursive
from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
+from vyos.utils.network import get_vrf_members
+from vyos.utils.network import get_interface_vrf
from vyos import ConfigError
from vyos import airbag
from pathlib import Path
@@ -43,7 +44,6 @@ airbag.enable()
nftables_conf = '/run/nftables.conf'
domain_resolver_usage = '/run/use-vyos-domain-resolver-firewall'
-domain_resolver_usage_nat = '/run/use-vyos-domain-resolver-nat'
sysctl_file = r'/run/sysctl/10-vyos-firewall.conf'
@@ -134,6 +134,27 @@ def get_config(config=None):
fqdn_config_parse(firewall, 'firewall')
+ if not os.path.exists(nftables_conf):
+ firewall['first_install'] = True
+
+ if 'zone' in firewall:
+ for local_zone, local_zone_conf in firewall['zone'].items():
+ if 'local_zone' not in local_zone_conf:
+ # Get physical interfaces assigned to the zone if vrf is used:
+ if 'vrf' in local_zone_conf['member']:
+ local_zone_conf['vrf_interfaces'] = {}
+ for vrf_name in local_zone_conf['member']['vrf']:
+ local_zone_conf['vrf_interfaces'][vrf_name] = ','.join(get_vrf_members(vrf_name))
+ continue
+
+ local_zone_conf['from_local'] = {}
+
+ for zone, zone_conf in firewall['zone'].items():
+ if zone == local_zone or 'from' not in zone_conf:
+ continue
+ if local_zone in zone_conf['from']:
+ local_zone_conf['from_local'][zone] = zone_conf['from'][local_zone]
+
set_dependents('conntrack', conf)
return firewall
@@ -442,28 +463,45 @@ def verify(firewall):
local_zone = False
zone_interfaces = []
+ zone_vrf = []
if 'zone' in firewall:
for zone, zone_conf in firewall['zone'].items():
- if 'local_zone' not in zone_conf and 'interface' not in zone_conf:
+ if 'local_zone' not in zone_conf and 'member' not in zone_conf:
raise ConfigError(f'Zone "{zone}" has no interfaces and is not the local zone')
if 'local_zone' in zone_conf:
if local_zone:
raise ConfigError('There cannot be multiple local zones')
- if 'interface' in zone_conf:
+ if 'member' in zone_conf:
raise ConfigError('Local zone cannot have interfaces assigned')
if 'intra_zone_filtering' in zone_conf:
raise ConfigError('Local zone cannot use intra-zone-filtering')
local_zone = True
- if 'interface' in zone_conf:
- found_duplicates = [intf for intf in zone_conf['interface'] if intf in zone_interfaces]
+ if 'member' in zone_conf:
+ if 'interface' in zone_conf['member']:
+ for iface in zone_conf['member']['interface']:
+
+ if iface in zone_interfaces:
+ raise ConfigError(f'Interfaces cannot be assigned to multiple zones')
- if found_duplicates:
- raise ConfigError(f'Interfaces cannot be assigned to multiple zones')
+ iface_vrf = get_interface_vrf(iface)
+ if iface_vrf != 'default':
+ Warning(f"Interface {iface} assigned to zone {zone} is in VRF {iface_vrf}. This might not work as expected.")
+ zone_interfaces.append(iface)
- zone_interfaces += zone_conf['interface']
+ if 'vrf' in zone_conf['member']:
+ for vrf in zone_conf['member']['vrf']:
+ if vrf in zone_vrf:
+ raise ConfigError(f'VRF cannot be assigned to multiple zones')
+ zone_vrf.append(vrf)
+
+ if 'vrf_interfaces' in zone_conf:
+ for vrf_name, vrf_interfaces in zone_conf['vrf_interfaces'].items():
+ if not vrf_interfaces:
+ raise ConfigError(
+ f'VRF "{vrf_name}" cannot be a member of any zone. It does not contain any interfaces.')
if 'intra_zone_filtering' in zone_conf:
intra_zone = zone_conf['intra_zone_filtering']
@@ -499,22 +537,6 @@ def verify(firewall):
return None
def generate(firewall):
- if not os.path.exists(nftables_conf):
- firewall['first_install'] = True
-
- if 'zone' in firewall:
- for local_zone, local_zone_conf in firewall['zone'].items():
- if 'local_zone' not in local_zone_conf:
- continue
-
- local_zone_conf['from_local'] = {}
-
- for zone, zone_conf in firewall['zone'].items():
- if zone == local_zone or 'from' not in zone_conf:
- continue
- if local_zone in zone_conf['from']:
- local_zone_conf['from_local'][zone] = zone_conf['from'][local_zone]
-
render(nftables_conf, 'firewall/nftables.j2', firewall)
render(sysctl_file, 'firewall/sysctl-firewall.conf.j2', firewall)
return None
diff --git a/src/conf_mode/interfaces_openvpn.py b/src/conf_mode/interfaces_openvpn.py
index 8c1213e2b..a9b4e570d 100755
--- a/src/conf_mode/interfaces_openvpn.py
+++ b/src/conf_mode/interfaces_openvpn.py
@@ -32,6 +32,7 @@ from vyos.base import DeprecationWarning
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configdict import is_node_changed
+from vyos.configdiff import get_config_diff
from vyos.configverify import verify_vrf
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_mirror_redirect
@@ -94,6 +95,23 @@ def get_config(config=None):
if 'deleted' in openvpn:
return openvpn
+ if not is_node_changed(conf, base) and dict_search_args(openvpn, 'tls'):
+ diff = get_config_diff(conf)
+ if diff.get_child_nodes_diff(['pki'], recursive=True).get('add') == ['ca', 'certificate']:
+ crl_path = os.path.join(cfg_dir, f'{ifname}_crl.pem')
+ if os.path.exists(crl_path):
+ # do not restart service when changed only CRL and crl file already exist
+ openvpn.update({'no_restart_crl': True})
+ for rec in diff.get_child_nodes_diff(['pki', 'ca'], recursive=True).get('add'):
+ if diff.get_child_nodes_diff(['pki', 'ca', rec], recursive=True).get('add') != ['crl']:
+ openvpn.update({'no_restart_crl': False})
+ break
+ if openvpn.get('no_restart_crl'):
+ for rec in diff.get_child_nodes_diff(['pki', 'certificate'], recursive=True).get('add'):
+ if diff.get_child_nodes_diff(['pki', 'certificate', rec], recursive=True).get('add') != ['revoke']:
+ openvpn.update({'no_restart_crl': False})
+ break
+
if is_node_changed(conf, base + [ifname, 'openvpn-option']):
openvpn.update({'restart_required': {}})
if is_node_changed(conf, base + [ifname, 'enable-dco']):
@@ -786,10 +804,12 @@ def apply(openvpn):
# No matching OpenVPN process running - maybe it got killed or none
# existed - nevertheless, spawn new OpenVPN process
- action = 'reload-or-restart'
- if 'restart_required' in openvpn:
- action = 'restart'
- call(f'systemctl {action} openvpn@{interface}.service')
+
+ if not openvpn.get('no_restart_crl'):
+ action = 'reload-or-restart'
+ if 'restart_required' in openvpn:
+ action = 'restart'
+ call(f'systemctl {action} openvpn@{interface}.service')
o = VTunIf(**openvpn)
o.update(openvpn)
diff --git a/src/conf_mode/service_monitoring_prometheus.py b/src/conf_mode/service_monitoring_prometheus.py
index e0a9fc4ef..9a07d8593 100755
--- a/src/conf_mode/service_monitoring_prometheus.py
+++ b/src/conf_mode/service_monitoring_prometheus.py
@@ -26,15 +26,18 @@ from vyos.utils.process import call
from vyos import ConfigError
from vyos import airbag
-
airbag.enable()
node_exporter_service_file = '/etc/systemd/system/node_exporter.service'
node_exporter_systemd_service = 'node_exporter.service'
+node_exporter_collector_path = '/run/node_exporter/collector'
frr_exporter_service_file = '/etc/systemd/system/frr_exporter.service'
frr_exporter_systemd_service = 'frr_exporter.service'
+blackbox_exporter_service_file = '/etc/systemd/system/blackbox_exporter.service'
+blackbox_exporter_systemd_service = 'blackbox_exporter.service'
+
def get_config(config=None):
if config:
@@ -57,6 +60,12 @@ def get_config(config=None):
if tmp:
monitoring.update({'frr_exporter_restart_required': {}})
+ tmp = False
+ for node in ['vrf', 'config-file']:
+ tmp = tmp or is_node_changed(conf, base + ['blackbox-exporter', node])
+ if tmp:
+ monitoring.update({'blackbox_exporter_restart_required': {}})
+
return monitoring
@@ -70,6 +79,22 @@ def verify(monitoring):
if 'frr_exporter' in monitoring:
verify_vrf(monitoring['frr_exporter'])
+ if 'blackbox_exporter' in monitoring:
+ verify_vrf(monitoring['blackbox_exporter'])
+
+ if (
+ 'modules' in monitoring['blackbox_exporter']
+ and 'dns' in monitoring['blackbox_exporter']['modules']
+ and 'name' in monitoring['blackbox_exporter']['modules']['dns']
+ ):
+ for mod_name, mod_config in monitoring['blackbox_exporter']['modules'][
+ 'dns'
+ ]['name'].items():
+ if 'query_name' not in mod_config:
+ raise ConfigError(
+ f'query name not specified in dns module {mod_name}'
+ )
+
return None
@@ -84,6 +109,11 @@ def generate(monitoring):
if os.path.isfile(frr_exporter_service_file):
os.unlink(frr_exporter_service_file)
+ if not monitoring or 'blackbox_exporter' not in monitoring:
+ # Delete systemd files
+ if os.path.isfile(blackbox_exporter_service_file):
+ os.unlink(blackbox_exporter_service_file)
+
if not monitoring:
return None
@@ -94,6 +124,13 @@ def generate(monitoring):
'prometheus/node_exporter.service.j2',
monitoring['node_exporter'],
)
+ if (
+ 'collectors' in monitoring['node_exporter']
+ and 'textfile' in monitoring['node_exporter']['collectors']
+ ):
+ # Create textcollector folder
+ if not os.path.isdir(node_exporter_collector_path):
+ os.makedirs(node_exporter_collector_path)
if 'frr_exporter' in monitoring:
# Render frr_exporter service_file
@@ -103,6 +140,20 @@ def generate(monitoring):
monitoring['frr_exporter'],
)
+ if 'blackbox_exporter' in monitoring:
+ # Render blackbox_exporter service_file
+ render(
+ blackbox_exporter_service_file,
+ 'prometheus/blackbox_exporter.service.j2',
+ monitoring['blackbox_exporter'],
+ )
+ # Render blackbox_exporter config file
+ render(
+ '/run/blackbox_exporter/config.yml',
+ 'prometheus/blackbox_exporter.yml.j2',
+ monitoring['blackbox_exporter'],
+ )
+
return None
@@ -113,6 +164,8 @@ def apply(monitoring):
call(f'systemctl stop {node_exporter_systemd_service}')
if not monitoring or 'frr_exporter' not in monitoring:
call(f'systemctl stop {frr_exporter_systemd_service}')
+ if not monitoring or 'blackbox_exporter' not in monitoring:
+ call(f'systemctl stop {blackbox_exporter_systemd_service}')
if not monitoring:
return
@@ -133,6 +186,14 @@ def apply(monitoring):
call(f'systemctl {systemd_action} {frr_exporter_systemd_service}')
+ if 'blackbox_exporter' in monitoring:
+ # we need to restart the service if e.g. the VRF name changed
+ systemd_action = 'reload-or-restart'
+ if 'blackbox_exporter_restart_required' in monitoring:
+ systemd_action = 'restart'
+
+ call(f'systemctl {systemd_action} {blackbox_exporter_systemd_service}')
+
if __name__ == '__main__':
try:
diff --git a/src/conf_mode/service_ssh.py b/src/conf_mode/service_ssh.py
index 9abdd33dc..759f87bb2 100755
--- a/src/conf_mode/service_ssh.py
+++ b/src/conf_mode/service_ssh.py
@@ -23,10 +23,16 @@ from syslog import LOG_INFO
from vyos.config import Config
from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_pki_ca_certificate
from vyos.utils.process import call
from vyos.template import render
from vyos import ConfigError
from vyos import airbag
+from vyos.pki import find_chain
+from vyos.pki import encode_certificate
+from vyos.pki import load_certificate
+from vyos.utils.file import write_file
+
airbag.enable()
config_file = r'/run/sshd/sshd_config'
@@ -38,6 +44,9 @@ key_rsa = '/etc/ssh/ssh_host_rsa_key'
key_dsa = '/etc/ssh/ssh_host_dsa_key'
key_ed25519 = '/etc/ssh/ssh_host_ed25519_key'
+trusted_user_ca_key = '/etc/ssh/trusted_user_ca_key'
+
+
def get_config(config=None):
if config:
conf = config
@@ -47,10 +56,13 @@ def get_config(config=None):
if not conf.exists(base):
return None
- ssh = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ ssh = conf.get_config_dict(
+ base, key_mangling=('-', '_'), get_first_key=True, with_pki=True
+ )
tmp = is_node_changed(conf, base + ['vrf'])
- if tmp: ssh.update({'restart_required': {}})
+ if tmp:
+ ssh.update({'restart_required': {}})
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
@@ -62,20 +74,32 @@ def get_config(config=None):
# Ignore default XML values if config doesn't exists
# Delete key from dict
if not conf.exists(base + ['dynamic-protection']):
- del ssh['dynamic_protection']
+ del ssh['dynamic_protection']
return ssh
+
def verify(ssh):
if not ssh:
return None
if 'rekey' in ssh and 'data' not in ssh['rekey']:
- raise ConfigError(f'Rekey data is required!')
+ raise ConfigError('Rekey data is required!')
+
+ if 'trusted_user_ca_key' in ssh:
+ if 'ca_certificate' not in ssh['trusted_user_ca_key']:
+ raise ConfigError('CA certificate is required for TrustedUserCAKey')
+
+ ca_key_name = ssh['trusted_user_ca_key']['ca_certificate']
+ verify_pki_ca_certificate(ssh, ca_key_name)
+ pki_ca_cert = ssh['pki']['ca'][ca_key_name]
+ if 'certificate' not in pki_ca_cert or not pki_ca_cert['certificate']:
+ raise ConfigError(f"CA certificate '{ca_key_name}' is not valid or missing")
verify_vrf(ssh)
return None
+
def generate(ssh):
if not ssh:
if os.path.isfile(config_file):
@@ -95,6 +119,24 @@ def generate(ssh):
syslog(LOG_INFO, 'SSH ed25519 host key not found, generating new key!')
call(f'ssh-keygen -q -N "" -t ed25519 -f {key_ed25519}')
+ if 'trusted_user_ca_key' in ssh:
+ ca_key_name = ssh['trusted_user_ca_key']['ca_certificate']
+ pki_ca_cert = ssh['pki']['ca'][ca_key_name]
+
+ loaded_ca_cert = load_certificate(pki_ca_cert['certificate'])
+ loaded_ca_certs = {
+ load_certificate(c['certificate'])
+ for c in ssh['pki']['ca'].values()
+ if 'certificate' in c
+ }
+
+ ca_full_chain = find_chain(loaded_ca_cert, loaded_ca_certs)
+ write_file(
+ trusted_user_ca_key, '\n'.join(encode_certificate(c) for c in ca_full_chain)
+ )
+ elif os.path.exists(trusted_user_ca_key):
+ os.unlink(trusted_user_ca_key)
+
render(config_file, 'ssh/sshd_config.j2', ssh)
if 'dynamic_protection' in ssh:
@@ -103,12 +145,12 @@ def generate(ssh):
return None
+
def apply(ssh):
- systemd_service_ssh = 'ssh.service'
systemd_service_sshguard = 'sshguard.service'
if not ssh:
# SSH access is removed in the commit
- call(f'systemctl stop ssh@*.service')
+ call('systemctl stop ssh@*.service')
call(f'systemctl stop {systemd_service_sshguard}')
return None
@@ -122,13 +164,14 @@ def apply(ssh):
if 'restart_required' in ssh:
# this is only true if something for the VRFs changed, thus we
# stop all VRF services and only restart then new ones
- call(f'systemctl stop ssh@*.service')
+ call('systemctl stop ssh@*.service')
systemd_action = 'restart'
for vrf in ssh['vrf']:
call(f'systemctl {systemd_action} ssh@{vrf}.service')
return None
+
if __name__ == '__main__':
try:
c = get_config()
diff --git a/src/etc/skel/.bashrc b/src/etc/skel/.bashrc
index ba7d50003..f807f0c72 100644
--- a/src/etc/skel/.bashrc
+++ b/src/etc/skel/.bashrc
@@ -92,6 +92,9 @@ fi
#alias la='ls -A'
#alias l='ls -CF'
+# Disable iproute2 auto color
+alias ip="ip --color=never"
+
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
diff --git a/src/etc/udev/rules.d/90-vyos-serial.rules b/src/etc/udev/rules.d/90-vyos-serial.rules
index 30c1d3170..f86b2258f 100644
--- a/src/etc/udev/rules.d/90-vyos-serial.rules
+++ b/src/etc/udev/rules.d/90-vyos-serial.rules
@@ -8,7 +8,7 @@ SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci"
SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
# /dev/serial/by-path/, /dev/serial/by-id/ for USB devices
-KERNEL!="ttyUSB[0-9]*", GOTO="serial_end"
+KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="serial_end"
SUBSYSTEMS=="usb-serial", ENV{.ID_PORT}="$attr{port_number}"
diff --git a/src/migration-scripts/firewall/16-to-17 b/src/migration-scripts/firewall/16-to-17
index ad0706f04..ad0706f04 100755..100644
--- a/src/migration-scripts/firewall/16-to-17
+++ b/src/migration-scripts/firewall/16-to-17
diff --git a/src/migration-scripts/firewall/17-to-18 b/src/migration-scripts/firewall/17-to-18
new file mode 100755
index 000000000..34ce6aa07
--- /dev/null
+++ b/src/migration-scripts/firewall/17-to-18
@@ -0,0 +1,41 @@
+# Copyright (C) 2024-2025 VyOS maintainers and contributors
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# From
+# set firewall zone <zone> interface RED
+# set firewall zone <zone> interface eth0
+# To
+# set firewall zone <zone> member vrf RED
+# set firewall zone <zone> member interface eth0
+
+from vyos.configtree import ConfigTree
+
+base = ['firewall', 'zone']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for zone in config.list_nodes(base):
+ zone_iface_base = base + [zone, 'interface']
+ zone_member_base = base + [zone, 'member']
+ if config.exists(zone_iface_base):
+ for iface in config.return_values(zone_iface_base):
+ if config.exists(['vrf', 'name', iface]):
+ config.set(zone_member_base + ['vrf'], value=iface, replace=False)
+ else:
+ config.set(zone_member_base + ['interface'], value=iface, replace=False)
+ config.delete(zone_iface_base)
diff --git a/src/op_mode/tech_support.py b/src/op_mode/tech_support.py
index f60bb87ff..24ac0af1b 100644
--- a/src/op_mode/tech_support.py
+++ b/src/op_mode/tech_support.py
@@ -97,21 +97,22 @@ def _get_boot_config():
return strip_config_source(config)
def _get_config_scripts():
- from os import listdir
+ from os import walk
from os.path import join
from vyos.utils.file import read_file
scripts = []
dir = '/config/scripts'
- for f in listdir(dir):
- script = {}
- path = join(dir, f)
- data = read_file(path)
- script["path"] = path
- script["data"] = data
-
- scripts.append(script)
+ for dirpath, _, filenames in walk(dir):
+ for filename in filenames:
+ script = {}
+ path = join(dirpath, filename)
+ data = read_file(path)
+ script["path"] = path
+ script["data"] = data
+
+ scripts.append(script)
return scripts
diff --git a/src/op_mode/zone.py b/src/op_mode/zone.py
index 49fecdf28..df39549d2 100644
--- a/src/op_mode/zone.py
+++ b/src/op_mode/zone.py
@@ -56,10 +56,15 @@ def _convert_one_zone_data(zone: str, zone_config: dict) -> dict:
from_zone_dict['firewall_v6'] = dict_search(
'firewall.ipv6_name', from_zone_config)
list_of_rules.append(from_zone_dict)
+ zone_members =[]
+ interface_members = dict_search('member.interface', zone_config)
+ vrf_members = dict_search('member.vrf', zone_config)
+ zone_members += interface_members if interface_members is not None else []
+ zone_members += vrf_members if vrf_members is not None else []
zone_dict = {
'name': zone,
- 'interface': dict_search('interface', zone_config),
+ 'members': zone_members,
'type': 'LOCAL' if dict_search('local_zone',
zone_config) is not None else None,
}
@@ -126,7 +131,7 @@ def output_zone_list(zone_conf: dict) -> list:
if zone_conf['type'] == 'LOCAL':
zone_info.append('LOCAL')
else:
- zone_info.append("\n".join(zone_conf['interface']))
+ zone_info.append("\n".join(zone_conf['members']))
from_zone = []
firewall = []
@@ -175,7 +180,7 @@ def get_formatted_output(zone_policy: list) -> str:
:rtype: str
"""
headers = ["Zone",
- "Interfaces",
+ "Members",
"From Zone",
"Firewall IPv4",
"Firewall IPv6"
diff --git a/src/services/vyos-configd b/src/services/vyos-configd
index d558e8c26..b161fe6ba 100755
--- a/src/services/vyos-configd
+++ b/src/services/vyos-configd
@@ -211,9 +211,6 @@ def initialization(socket):
scripts_called = []
setattr(config, 'scripts_called', scripts_called)
- if not hasattr(config, 'frrender_cls'):
- setattr(config, 'frrender_cls', FRRender())
-
return config
@@ -312,8 +309,10 @@ if __name__ == '__main__':
remove_if_file(configd_env_file)
os.symlink(configd_env_set_file, configd_env_file)
- config = None
+ # We only need one long-lived instance of FRRender
+ frr = FRRender()
+ config = None
while True:
# Wait for next request from client
msg = socket.recv().decode()
@@ -332,10 +331,11 @@ if __name__ == '__main__':
scripts_called = getattr(config, 'scripts_called', [])
logger.debug(f'scripts_called: {scripts_called}')
- if hasattr(config, 'frrender_cls') and res == R_SUCCESS:
- frrender_cls = getattr(config, 'frrender_cls')
+ if res == R_SUCCESS:
tmp = get_frrender_dict(config)
- frrender_cls.generate(tmp)
- frrender_cls.apply()
+ if frr.generate(tmp):
+ # only apply a new FRR configuration if anything changed
+ # in comparison to the previous applied configuration
+ frr.apply()
else:
logger.critical(f'Unexpected message: {message}')
diff --git a/src/helpers/vyos-domain-resolver.py b/src/services/vyos-domain-resolver
index f5a1d9297..bc74a05d1 100755
--- a/src/helpers/vyos-domain-resolver.py
+++ b/src/services/vyos-domain-resolver
@@ -16,6 +16,7 @@
import json
import time
+import logging
from vyos.configdict import dict_merge
from vyos.configquery import ConfigTreeQuery
@@ -48,6 +49,11 @@ ipv6_tables = {
'ip6 raw'
}
+logger = logging.getLogger(__name__)
+logs_handler = logging.StreamHandler()
+logger.addHandler(logs_handler)
+logger.setLevel(logging.INFO)
+
def get_config(conf, node):
node_config = conf.get_config_dict(node, key_mangling=('-', '_'), get_first_key=True,
no_tag_node_value_mangle=True)
@@ -163,15 +169,15 @@ def update_fqdn(config, node):
nft_conf_str = "\n".join(conf_lines) + "\n"
code = run(f'nft --file -', input=nft_conf_str)
- print(f'Updated {count} sets in {node} - result: {code}')
+ logger.info(f'Updated {count} sets in {node} - result: {code}')
if __name__ == '__main__':
- print(f'VyOS domain resolver')
+ logger.info(f'VyOS domain resolver')
count = 1
while commit_in_progress():
if ( count % 60 == 0 ):
- print(f'Commit still in progress after {count}s - waiting')
+ logger.info(f'Commit still in progress after {count}s - waiting')
count += 1
time.sleep(1)
@@ -179,7 +185,7 @@ if __name__ == '__main__':
firewall = get_config(conf, base_firewall)
nat = get_config(conf, base_nat)
- print(f'interval: {timeout}s - cache: {cache}')
+ logger.info(f'interval: {timeout}s - cache: {cache}')
while True:
update_fqdn(firewall, 'firewall')
diff --git a/src/systemd/vyos-domain-resolver.service b/src/systemd/vyos-domain-resolver.service
index e63ae5e34..87a4748f4 100644
--- a/src/systemd/vyos-domain-resolver.service
+++ b/src/systemd/vyos-domain-resolver.service
@@ -6,7 +6,9 @@ ConditionPathExistsGlob=/run/use-vyos-domain-resolver*
[Service]
Type=simple
Restart=always
-ExecStart=/usr/bin/python3 -u /usr/libexec/vyos/vyos-domain-resolver.py
+ExecStart=/usr/bin/python3 -u /usr/libexec/vyos/services/vyos-domain-resolver
+SyslogIdentifier=vyos-domain-resolver
+SyslogFacility=daemon
StandardError=journal
StandardOutput=journal