summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/package-smoketest.yml47
-rw-r--r--.gitignore2
-rw-r--r--Makefile19
-rw-r--r--data/configd-include.json115
-rw-r--r--data/templates/accel-ppp/pppoe.config.j25
-rw-r--r--data/templates/firewall/nftables.j22
-rw-r--r--data/templates/wifi/hostapd.conf.j23516
-rw-r--r--debian/control6
-rw-r--r--interface-definitions/interfaces_wireless.xml.in206
-rw-r--r--interface-definitions/service_pppoe-server.xml.in6
-rw-r--r--op-mode-definitions/generate_firewall_rule-resequence.xml.in29
-rw-r--r--op-mode-definitions/generate_nat64_rule-resequence.xml.in15
-rw-r--r--op-mode-definitions/generate_nat66_rule-resequence.xml.in15
-rw-r--r--op-mode-definitions/generate_nat_rule-resequence.xml.in15
-rw-r--r--op-mode-definitions/include/rule-resequence.xml.i30
-rw-r--r--python/vyos/base.py7
-rw-r--r--python/vyos/component_version.py248
-rw-r--r--python/vyos/compose_config.py12
-rw-r--r--python/vyos/configtree.py13
-rw-r--r--python/vyos/ethtool.py4
-rw-r--r--python/vyos/load_config.py31
-rw-r--r--python/vyos/migrate.py283
-rw-r--r--python/vyos/migrator.py226
-rw-r--r--python/vyos/utils/dict.py2
-rw-r--r--python/vyos/utils/system.py13
-rwxr-xr-xscripts/generate-configd-include-json.py34
-rwxr-xr-xsmoketest/bin/vyos-configtest9
-rwxr-xr-xsmoketest/bin/vyos-configtest-pki6
-rw-r--r--smoketest/config-tests/basic-api-service20
-rw-r--r--smoketest/config-tests/basic-vyos47
-rw-r--r--smoketest/config-tests/bgp-azure-ipsec-gateway231
-rw-r--r--smoketest/config-tests/bgp-bfd-communities201
-rw-r--r--smoketest/config-tests/bgp-big-as-cloud850
-rw-r--r--smoketest/config-tests/bgp-dmvpn-hub69
-rw-r--r--smoketest/config-tests/bgp-dmvpn-spoke75
-rw-r--r--smoketest/config-tests/bgp-evpn-l2vpn-leaf55
-rw-r--r--smoketest/config-tests/bgp-evpn-l2vpn-spine48
-rw-r--r--smoketest/config-tests/bgp-evpn-l3vpn-pe-router123
-rw-r--r--smoketest/config-tests/bgp-medium-confederation2
-rw-r--r--smoketest/config-tests/bgp-rpki43
-rw-r--r--smoketest/config-tests/bgp-small-internet-exchange209
-rw-r--r--smoketest/config-tests/bgp-small-ipv4-unicast32
-rw-r--r--smoketest/config-tests/cluster-basic21
-rw-r--r--smoketest/config-tests/container-simple16
-rw-r--r--smoketest/config-tests/dialup-router-complex740
-rw-r--r--smoketest/config-tests/dialup-router-medium-vpn17
-rw-r--r--smoketest/config-tests/dialup-router-wireguard-ipv6431
-rw-r--r--smoketest/config-tests/egp-igp-route-maps46
-rw-r--r--smoketest/config-tests/igmp-pim-small22
-rw-r--r--smoketest/config-tests/ipoe-server27
-rw-r--r--smoketest/config-tests/ipv6-disable31
-rw-r--r--smoketest/config-tests/isis-small44
-rw-r--r--smoketest/config-tests/nat-basic81
-rw-r--r--smoketest/config-tests/ospf-simple10
-rw-r--r--smoketest/config-tests/ospf-small82
-rw-r--r--smoketest/config-tests/pppoe-server47
-rw-r--r--smoketest/config-tests/qos-basic75
-rw-r--r--smoketest/config-tests/rip-router83
-rw-r--r--smoketest/config-tests/rpki-only14
-rw-r--r--smoketest/config-tests/tunnel-broker75
-rw-r--r--smoketest/config-tests/vpn-openconnect-sstp35
-rw-r--r--smoketest/config-tests/vrf-basic65
-rw-r--r--smoketest/config-tests/vrf-bgp-pppoe-underlay186
-rw-r--r--smoketest/config-tests/vrf-ospf59
-rw-r--r--smoketest/config-tests/wireless-basic2
-rw-r--r--smoketest/configs/basic-api-service2
-rw-r--r--smoketest/configs/bgp-dmvpn-hub5
-rw-r--r--smoketest/configs/bgp-evpn-l3vpn-pe-router2
-rw-r--r--smoketest/configs/bgp-rpki1
-rw-r--r--smoketest/configs/isis-small41
-rw-r--r--smoketest/configs/pppoe-server4
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_wireless.py106
-rwxr-xr-xsmoketest/scripts/cli/test_service_pppoe-server.py11
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_openconnect.py52
-rwxr-xr-xsrc/conf_mode/interfaces_wireless.py29
-rwxr-xr-xsrc/conf_mode/nat_cgnat.py110
-rwxr-xr-xsrc/helpers/add-system-version.py (renamed from src/helpers/system-versions-foot.py)14
-rwxr-xr-xsrc/helpers/run-config-migration.py128
-rwxr-xr-xsrc/helpers/vyos-load-config.py21
-rwxr-xr-xsrc/helpers/vyos-merge-config.py17
-rwxr-xr-xsrc/helpers/vyos-save-config.py15
-rwxr-xr-xsrc/helpers/vyos_net_name10
-rwxr-xr-xsrc/init/vyos-router4
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/0-to-172
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/1-to-2112
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/2-to-363
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/3-to-487
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/4-to-577
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/cluster/1-to-265
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/config-management/0-to-143
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack-sync/1-to-250
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack/1-to-240
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack/2-to-351
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack/3-to-456
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack/4-to-562
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/container/0-to-1102
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/container/1-to-256
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-relay/1-to-242
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/10-to-1152
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/4-to-5202
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/5-to-6132
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/6-to-794
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/7-to-898
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/8-to-982
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/9-to-1081
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/0-to-147
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/1-to-2100
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/2-to-3102
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/3-to-4101
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/4-to-5140
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-dynamic/0-to-1161
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-dynamic/1-to-285
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-dynamic/2-to-3134
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-dynamic/3-to-487
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-forwarding/0-to-149
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-forwarding/1-to-2111
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-forwarding/2-to-357
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-forwarding/3-to-454
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/10-to-11312
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/11-to-1288
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/12-to-13114
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/13-to-1464
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/14-to-1549
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/15-to-1639
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/5-to-6160
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/6-to-7444
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/7-to-884
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/8-to-9126
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/9-to-10104
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/flow-accounting/0-to-194
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/0-to-149
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/1-to-249
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/2-to-388
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/3-to-459
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/4-to-579
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/5-to-6156
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ids/0-to-174
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/0-to-1151
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/1-to-242
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/10-to-1143
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/11-to-1241
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/12-to-1342
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/13-to-1443
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/14-to-1542
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/15-to-1642
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/16-to-1743
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/17-to-1841
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/18-to-1945
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/19-to-2042
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/2-to-341
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/20-to-21199
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/21-to-2257
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/22-to-2347
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/23-to-2442
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/24-to-2543
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/25-to-26643
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/26-to-2767
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/27-to-2857
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/28-to-2963
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/29-to-3055
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/3-to-442
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/30-to-3195
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/31-to-3264
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/32-to-3353
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/4-to-536
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/5-to-641
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/6-to-742
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/7-to-842
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/8-to-941
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/9-to-1041
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipoe-server/1-to-2162
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipoe-server/2-to-374
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/10-to-11126
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/11-to-1256
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/12-to-1350
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/4-to-555
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/5-to-6140
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/6-to-760
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/7-to-8137
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/8-to-950
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/9-to-10223
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/isis/0-to-164
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/isis/1-to-255
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/isis/2-to-382
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/0-to-146
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/1-to-247
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/2-to-353
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/3-to-4262
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/4-to-5105
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/5-to-6176
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/6-to-766
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/7-to-888
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/8-to-950
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/lldp/0-to-148
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/lldp/1-to-254
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/monitoring/0-to-183
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat/4-to-547
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat/5-to-645
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat/6-to-791
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat/7-to-881
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat66/0-to-159
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat66/1-to-276
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat66/2-to-386
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ntp/0-to-142
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ntp/1-to-2101
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ntp/2-to-369
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openconnect/0-to-1203
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openconnect/1-to-249
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openconnect/2-to-356
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openvpn/0-to-142
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openvpn/1-to-227
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ospf/0-to-178
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ospf/1-to-2116
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pim/0-to-186
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/0-to-176
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/1-to-2111
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/2-to-370
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/3-to-4135
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/4-to-5115
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/5-to-680
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/6-to-798
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/7-to-858
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/0-to-147
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/1-to-247
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/2-to-345
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/3-to-448
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/4-to-549
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/5-to-663
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/6-to-7172
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/7-to-874
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/8-to-990
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/9-to-1066
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/0-to-143
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/1-to-248
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/2-to-398
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/3-to-453
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/4-to-582
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/qos/1-to-2282
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/10-to-1156
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/2-to-354
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/3-to-456
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/4-to-555
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/5-to-655
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/6-to-7185
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/7-to-877
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/8-to-992
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/9-to-1082
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/reverse-proxy/0-to-155
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/rip/0-to-156
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/rpki/0-to-189
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/rpki/1-to-296
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/salt/0-to-150
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/snmp/0-to-148
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/snmp/1-to-281
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/snmp/2-to-355
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ssh/0-to-142
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ssh/1-to-2118
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/0-to-149
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/1-to-247
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/2-to-349
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/3-to-4203
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/4-to-566
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/5-to-674
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/10-to-1144
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/11-to-1241
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/12-to-1371
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/13-to-1441
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/14-to-1541
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/15-to-1642
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/16-to-1748
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/17-to-1847
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/18-to-19151
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/19-to-2074
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/20-to-2150
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/21-to-2273
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/22-to-2359
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/23-to-2492
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/24-to-2561
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/25-to-2699
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/26-to-2755
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/6-to-774
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/7-to-842
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/8-to-942
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrf/0-to-1223
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrf/1-to-281
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrf/2-to-3149
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrrp/1-to-2346
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrrp/2-to-386
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrrp/3-to-461
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/webproxy/1-to-244
-rwxr-xr-xsrc/op_mode/firewall.py85
-rwxr-xr-xsrc/op_mode/generate_service_rule-resequence.py (renamed from src/op_mode/generate_firewall_rule-resequence.py)29
-rw-r--r--src/op_mode/show_techsupport_report.py23
-rw-r--r--src/tests/helper.py4
-rw-r--r--src/tests/test_config_diff.py2
-rw-r--r--src/tests/test_config_parser.py2
-rw-r--r--[-rwxr-xr-x]src/tests/test_configd_inspect.py (renamed from smoketest/scripts/cli/test_configd_inspect.py)21
-rw-r--r--src/tests/test_configverify.py4
-rw-r--r--src/tests/test_dependency_graph.py4
-rw-r--r--src/tests/test_dict_search.py4
-rw-r--r--[-rwxr-xr-x]src/tests/test_find_device_file.py7
-rw-r--r--src/tests/test_initial_setup.py2
-rw-r--r--src/tests/test_op_mode.py5
-rw-r--r--src/tests/test_task_scheduler.py4
-rw-r--r--src/tests/test_template.py2
-rw-r--r--src/tests/test_utils.py4
-rw-r--r--src/tests/test_utils_network.py7
307 files changed, 15380 insertions, 12081 deletions
diff --git a/.github/workflows/package-smoketest.yml b/.github/workflows/package-smoketest.yml
index 49bd91669..27272a6e2 100644
--- a/.github/workflows/package-smoketest.yml
+++ b/.github/workflows/package-smoketest.yml
@@ -1,13 +1,22 @@
-name: Package ISO Test
+name: VyOS ISO integration Test
on:
- pull_request:
+ pull_request_target:
branches:
- current
+ - circinus
+
+permissions:
+ pull-requests: write
+ contents: read
+
+env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed for PR comments
jobs:
build:
runs-on: ubuntu-24.04
+ timeout-minutes: 45
container:
image: vyos/vyos-build:current
options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged
@@ -24,9 +33,7 @@ jobs:
- name: Clone vyos-1x source code
uses: actions/checkout@v4
with:
- repository: vyos/vyos-1x
path: packages/vyos-1x
- fetch-tags: true # required for Debian package version
- name: Build vyos-1x package
run: |
cd packages/vyos-1x; dpkg-buildpackage -uc -us -tc -b
@@ -51,6 +58,7 @@ jobs:
cli-smoketests:
needs: build
runs-on: ubuntu-24.04
+ timeout-minutes: 180
container:
image: vyos/vyos-build:current
options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged
@@ -65,11 +73,21 @@ jobs:
name: vyos-${{ needs.build.outputs.build_version }}
path: build
- name: VyOS CLI smoketests
- run: ls -al; ls -al build; sudo make test
+ run: sudo make test
+ - name: Add PR comment
+ if: always()
+ uses: mshick/add-pr-comment@v2
+ with:
+ message-success: '👍 VyOS CLI smoketests finished successfully!'
+ message-failure: '❌ VyOS CLI smoketests failed!'
+ message-cancelled: '❌ VyOS CLI smoketests cancelled!'
+ allow-repeats: false
+ refresh-message-position: true
config-load-tests:
needs: build
runs-on: ubuntu-24.04
+ timeout-minutes: 90
container:
image: vyos/vyos-build:current
options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged
@@ -85,10 +103,20 @@ jobs:
path: build
- name: VyOS config tests
run: sudo make testc
+ - name: Add PR comment
+ if: always()
+ uses: mshick/add-pr-comment@v2
+ with:
+ message-success: '👍 VyOS config tests finished successfully!'
+ message-failure: '❌ VyOS config tests failed!'
+ message-cancelled: '❌ VyOS config tests cancelled!'
+ allow-repeats: false
+ refresh-message-position: true
raid1-install-test:
needs: build
runs-on: ubuntu-24.04
+ timeout-minutes: 20
container:
image: vyos/vyos-build:current
options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged
@@ -104,3 +132,12 @@ jobs:
path: build
- name: VyOS RAID1 install test
run: sudo make testraid
+ - name: Add PR comment
+ if: always()
+ uses: mshick/add-pr-comment@v2
+ with:
+ message-success: '👍 RAID1 Smoketests finished successfully!'
+ message-failure: '❌ RAID1 Smoketests failed!'
+ message-cancelled: '❌ RAID1 action cancelled!'
+ allow-repeats: false
+ refresh-message-position: true
diff --git a/.gitignore b/.gitignore
index 507daceee..01333d5b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -145,6 +145,8 @@ data/component-versions.json
# vyos-1x XML cache
python/vyos/xml_ref/cache.py
python/vyos/xml_ref/pkg_cache/*_cache.py
+# autogenerated vyos-configd JSON definition
+data/configd-include.json
# We do not use pip
Pipfile
diff --git a/Makefile b/Makefile
index 509b47858..06b4aaa6f 100644
--- a/Makefile
+++ b/Makefile
@@ -78,18 +78,7 @@ vyshim:
$(MAKE) -C $(SHIM_DIR)
.PHONY: all
-all: clean interface_definitions op_mode_definitions check test j2lint vyshim check_migration_scripts_executable
-
-.PHONY: check
-.ONESHELL:
-check:
- @echo "Checking which CLI scripts are not enabled to work with vyos-configd..."
- @for file in `ls src/conf_mode -I__pycache__`
- do
- if ! grep -q $$file data/configd-include.json; then
- echo "* $$file"
- fi
- done
+all: clean interface_definitions op_mode_definitions test j2lint vyshim generate-configd-include-json
.PHONY: clean
clean:
@@ -99,7 +88,7 @@ clean:
$(MAKE) -C $(SHIM_DIR) clean
.PHONY: test
-test:
+test: generate-configd-include-json
set -e; python3 -m compileall -q -x '/vmware-tools/scripts/, /ppp/' .
PYTHONPATH=python/ python3 -m "nose" --with-xunit src --with-coverage --cover-erase --cover-xml --cover-package src/conf_mode,src/op_mode,src/completion,src/helpers,src/validators,src/tests --verbose
@@ -127,6 +116,10 @@ unused-imports:
deb:
dpkg-buildpackage -uc -us -tc -b
+.PHONY: generate-configd-include-json
+generate-configd-include-json:
+ @scripts/generate-configd-include-json.py
+
.PHONY: schema
schema:
trang -I rnc -O rng schema/interface_definition.rnc schema/interface_definition.rng
diff --git a/data/configd-include.json b/data/configd-include.json
deleted file mode 100644
index 224a9c390..000000000
--- a/data/configd-include.json
+++ /dev/null
@@ -1,115 +0,0 @@
-[
-"container.py",
-"firewall.py",
-"high-availability.py",
-"interfaces_bonding.py",
-"interfaces_bridge.py",
-"interfaces_dummy.py",
-"interfaces_ethernet.py",
-"interfaces_geneve.py",
-"interfaces_input.py",
-"interfaces_l2tpv3.py",
-"interfaces_loopback.py",
-"interfaces_macsec.py",
-"interfaces_openvpn.py",
-"interfaces_pppoe.py",
-"interfaces_pseudo-ethernet.py",
-"interfaces_sstpc.py",
-"interfaces_tunnel.py",
-"interfaces_virtual-ethernet.py",
-"interfaces_vti.py",
-"interfaces_vxlan.py",
-"interfaces_wireguard.py",
-"interfaces_wireless.py",
-"interfaces_wwan.py",
-"load-balancing_reverse-proxy.py",
-"load-balancing_wan.py",
-"nat.py",
-"nat64.py",
-"nat66.py",
-"netns.py",
-"pki.py",
-"policy.py",
-"policy_route.py",
-"policy_local-route.py",
-"protocols_babel.py",
-"protocols_bfd.py",
-"protocols_bgp.py",
-"protocols_eigrp.py",
-"protocols_failover.py",
-"protocols_igmp-proxy.py",
-"protocols_isis.py",
-"protocols_mpls.py",
-"protocols_nhrp.py",
-"protocols_ospf.py",
-"protocols_ospfv3.py",
-"protocols_pim.py",
-"protocols_pim6.py",
-"protocols_rip.py",
-"protocols_ripng.py",
-"protocols_rpki.py",
-"protocols_segment-routing.py",
-"protocols_static.py",
-"protocols_static_arp.py",
-"protocols_static_multicast.py",
-"protocols_static_neighbor-proxy.py",
-"qos.py",
-"service_aws_glb.py",
-"service_broadcast-relay.py",
-"service_config-sync.py",
-"service_conntrack-sync.py",
-"service_console-server.py",
-"service_dhcp-relay.py",
-"service_dhcp-server.py",
-"service_dhcpv6-relay.py",
-"service_dhcpv6-server.py",
-"service_dns_dynamic.py",
-"service_dns_forwarding.py",
-"service_event-handler.py",
-"service_https.py",
-"service_ids_ddos-protection.py",
-"service_ipoe-server.py",
-"service_lldp.py",
-"service_mdns_repeater.py",
-"service_monitoring_telegraf.py",
-"service_monitoring_zabbix-agent.py",
-"service_ndp-proxy.py",
-"service_ntp.py",
-"service_pppoe-server.py",
-"service_router-advert.py",
-"service_salt-minion.py",
-"service_sla.py",
-"service_snmp.py",
-"service_ssh.py",
-"service_stunnel.py",
-"service_tftp-server.py",
-"service_webproxy.py",
-"system_acceleration.py",
-"system_config-management.py",
-"system_conntrack.py",
-"system_console.py",
-"system_flow-accounting.py",
-"system_frr.py",
-"system_host-name.py",
-"system_ip.py",
-"system_ipv6.py",
-"system_lcd.py",
-"system_login.py",
-"system_login_banner.py",
-"system_logs.py",
-"system_option.py",
-"system_proxy.py",
-"system_sflow.py",
-"system_sysctl.py",
-"system_syslog.py",
-"system_task-scheduler.py",
-"system_timezone.py",
-"system_update-check.py",
-"system_wireless.py",
-"vpn_ipsec.py",
-"vpn_l2tp.py",
-"vpn_openconnect.py",
-"vpn_pptp.py",
-"vpn_sstp.py",
-"vrf.py"
-]
diff --git a/data/templates/accel-ppp/pppoe.config.j2 b/data/templates/accel-ppp/pppoe.config.j2
index 6711f2ec9..73ffe0963 100644
--- a/data/templates/accel-ppp/pppoe.config.j2
+++ b/data/templates/accel-ppp/pppoe.config.j2
@@ -31,10 +31,13 @@ copy=1
level={{ log.level }}
{% endif %}
-{% if authentication.mode is vyos_defined("noauth") %}
[auth]
+{% if authentication.mode is vyos_defined("noauth") %}
noauth=1
{% endif %}
+{% if authentication.any_login is vyos_defined %}
+any-login=1
+{% endif %}
[client-ip-range]
0.0.0.0/0
diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2
index ee34f58fc..68a3bfd87 100644
--- a/data/templates/firewall/nftables.j2
+++ b/data/templates/firewall/nftables.j2
@@ -239,7 +239,7 @@ table ip6 vyos_filter {
{% for prior, conf in ipv6.output.items() %}
chain VYOS_IPV6_OUTPUT_{{ prior }} {
type filter hook output priority {{ prior }}; policy accept;
-{% if global_options.state_policy is vyos_defined %}
+{% if global_options.state_policy is vyos_defined and prior == 'filter' %}
jump VYOS_STATE_POLICY6
{% endif %}
{% if conf.rule is vyos_defined %}
diff --git a/data/templates/wifi/hostapd.conf.j2 b/data/templates/wifi/hostapd.conf.j2
index e1a08f7e4..0459fbc69 100644
--- a/data/templates/wifi/hostapd.conf.j2
+++ b/data/templates/wifi/hostapd.conf.j2
@@ -1,108 +1,58 @@
{# j2lint: disable=operator-enclosed-by-spaces #}
### Autogenerated by interfaces_wireless.py ###
+### hostapd.conf reference:
+### https://w1.fi/cgit/hostap/tree/hostapd/hostapd.conf?h=hostap_2_10&id=cff80b4f7d3c0a47c052e8187d671710f48939e4
+
{% if description is vyos_defined %}
# Description: {{ description }}
# User-friendly description of device; up to 32 octets encoded in UTF-8
device_name={{ description | truncate(32, True) }}
{% endif %}
-# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
-# management frames with the Host AP driver); wlan0 with many nl80211 drivers
-# Note: This attribute can be overridden by the values supplied with the '-i'
-# command line parameter.
interface={{ ifname }}
-
{% if is_bridge_member is vyos_defined %}
-# In case of atheros and nl80211 driver interfaces, an additional
-# configuration parameter, bridge, may be used to notify hostapd if the
-# interface is included in a bridge. This parameter is not used with Host AP
-# driver. If the bridge parameter is not set, the drivers will automatically
-# figure out the bridge interface (assuming sysfs is enabled and mounted to
-# /sys) and this parameter may not be needed.
-#
-# For nl80211, this parameter can be used to request the AP interface to be
-# added to the bridge automatically (brctl may refuse to do this before hostapd
-# has been started to change the interface mode). If needed, the bridge
-# interface is also created.
{# as there can only be one bridge interface it is save to loop #}
{% for bridge in is_bridge_member %}
bridge={{ bridge }}
{% endfor %}
-
-# WDS (4-address frame) mode with per-station virtual interfaces
-# (only supported with driver=nl80211)
-# This mode allows associated stations to use 4-address frames to allow layer 2
-# bridging to be used.
wds_sta=1
{% endif %}
-
-# Driver interface type (hostap/wired/none/nl80211/bsd);
-# default: hostap). nl80211 is used with all Linux mac80211 drivers.
-# Use driver=none if building hostapd as a standalone RADIUS server that does
-# not control any wireless/wired driver.
driver=nl80211
-
-# Levels (minimum value for logged events):
-# 0 = verbose debugging
-# 1 = debugging
-# 2 = informational messages
-# 3 = notification
-# 4 = warning
logger_syslog=-1
logger_syslog_level=0
logger_stdout=-1
logger_stdout_level=0
-
+{# regulatory domain and protocol stuff #}
{% if country_code %}
-# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
-# Set as needed to indicate country in which device is operating.
-# This can limit available channels and transmit power.
+{# Watch out for default value of "00" - World Regulatory Domain is set by "XX" in hostapd.conf #}
+{% if '00' in country_code %}
+country_code=XX
+{% else %}
country_code={{ country_code | upper }}
-
-# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
-# channels and transmit power levels based on the regulatory limits. The
-# country_code setting must be configured with the correct country for
-# IEEE 802.11d functions.
+{% endif %}
ieee80211d=1
{% endif %}
-
{% if ssid %}
-# SSID to be used in IEEE 802.11 management frames
ssid={{ ssid }}
{% endif %}
-
{% if channel %}
-# Channel number (IEEE 802.11)
-# (default: 0, i.e., not set)
-# Please note that some drivers do not use this value from hostapd and the
-# channel will need to be configured separately with iwconfig.
channel={{ channel }}
{% endif %}
-
{% if mode is vyos_defined %}
-# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
-# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
-# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
-# needs to be set to hw_mode a. For IEEE 802.11ax (HE) on 6 GHz this needs
-# to be set to hw_mode a. When using ACS (see channel parameter), a
-# special value "any" can be used to indicate that any support band can be used.
-# This special case is currently supported only with drivers with which
-# offloaded ACS is used.
{% if mode is vyos_defined('n') %}
hw_mode=g
{% elif mode is vyos_defined('ac') %}
hw_mode=a
ieee80211h=1
ieee80211ac=1
+{% elif mode is vyos_defined('ax') %}
+hw_mode=a
+ieee80211h=1
+ieee80211ax=1
{% else %}
hw_mode={{ mode }}
{% endif %}
{% endif %}
-
-# ieee80211w: Whether management frame protection (MFP) is enabled
-# 0 = disabled (default)
-# 1 = optional
-# 2 = required
{% if 'disabled' in mgmt_frame_protection %}
ieee80211w=0
{% elif 'optional' in mgmt_frame_protection %}
@@ -110,43 +60,14 @@ ieee80211w=1
{% elif 'required' in mgmt_frame_protection %}
ieee80211w=2
{% endif %}
-
-{% if capabilities is vyos_defined %}
-# ht_capab: HT capabilities (list of flags)
-# LDPC coding capability: [LDPC] = supported
-# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
-# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
-# with secondary channel above the primary channel
-# (20 MHz only if neither is set)
-# Note: There are limits on which channels can be used with HT40- and
-# HT40+. Following table shows the channels that may be available for
-# HT40- and HT40+ use per IEEE 802.11n Annex J:
-# freq HT40- HT40+
-# 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan)
-# 5 GHz 40,48,56,64 36,44,52,60
-# (depending on the location, not all of these channels may be available
-# for use)
-# Please note that 40 MHz channels may switch their primary and secondary
-# channels if needed or creation of 40 MHz channel maybe rejected based
-# on overlapping BSSes. These changes are done automatically when hostapd
-# is setting up the 40 MHz channel.
-# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
-# (SMPS disabled if neither is set)
-# HT-greenfield: [GF] (disabled if not set)
-# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
-# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
-# Tx STBC: [TX-STBC] (disabled if not set)
-# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial
-# streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC
-# disabled if none of these set
-# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set)
-# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
-# set)
-# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
-# 40 MHz intolerant [40-INTOLERANT] (not advertised if not set)
-# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
+{% if enable_bf_protection is vyos_defined %}
+beacon_prot=1
+{% else %}
+beacon_prot=0
+{% endif %}
+{# HT (802.11n 2.4GHz and 5GHz) #}
+{% if capabilities.ht is vyos_defined %}
{% set output = namespace(value='') %}
-
{% if capabilities.ht.fourtymhz_incapable is vyos_defined %}
{% set output.value = output.value ~ '[40-INTOLERANT]' %}
{% endif %}
@@ -177,174 +98,35 @@ ieee80211w=2
{% if capabilities.ht.smps is vyos_defined %}
{% set output.value = output.value ~ '[SMPS-' ~ capabilities.ht.smps | upper ~ ']' %}
{% endif %}
-
{% if capabilities.ht.channel_set_width is vyos_defined %}
{% for csw in capabilities.ht.channel_set_width %}
{% set output.value = output.value ~ '[' ~ csw | upper ~ ']' %}
{% endfor %}
{% endif %}
-
{% if capabilities.ht.short_gi is vyos_defined %}
{% for short_gi in capabilities.ht.short_gi %}
{% set output.value = output.value ~ '[SHORT-GI-' ~ short_gi | upper ~ ']' %}
{% endfor %}
{% endif %}
-
ht_capab={{ output.value }}
-
{% if capabilities.ht.auto_powersave is vyos_defined %}
-# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD]
-# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver)
uapsd_advertisement_enabled=1
{% endif %}
{% endif %}
-
-# Required for full HT and VHT functionality
-wme_enabled=1
-
-
{% if capabilities.require_ht is vyos_defined %}
-# Require stations to support HT PHY (reject association if they do not)
require_ht=1
{% endif %}
-
+{# VHT (802.11ac 5GHz) #}
{% if capabilities.vht is vyos_defined %}
-# vht_capab: VHT capabilities (list of flags)
-#
-# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
-# Indicates maximum MPDU length
-# 0 = 3895 octets (default)
-# 1 = 7991 octets
-# 2 = 11454 octets
-# 3 = reserved
-#
-# supported_chan_width: [VHT160] [VHT160-80PLUS80]
-# Indicates supported Channel widths
-# 0 = 160 MHz & 80+80 channel widths are not supported (default)
-# 1 = 160 MHz channel width is supported
-# 2 = 160 MHz & 80+80 channel widths are supported
-# 3 = reserved
-#
-# Rx LDPC coding capability: [RXLDPC]
-# Indicates support for receiving LDPC coded pkts
-# 0 = Not supported (default)
-# 1 = Supported
-#
-# Short GI for 80 MHz: [SHORT-GI-80]
-# Indicates short GI support for reception of packets transmitted with TXVECTOR
-# params format equal to VHT and CBW = 80Mhz
-# 0 = Not supported (default)
-# 1 = Supported
-#
-# Short GI for 160 MHz: [SHORT-GI-160]
-# Indicates short GI support for reception of packets transmitted with TXVECTOR
-# params format equal to VHT and CBW = 160Mhz
-# 0 = Not supported (default)
-# 1 = Supported
-#
-# Tx STBC: [TX-STBC-2BY1]
-# Indicates support for the transmission of at least 2x1 STBC
-# 0 = Not supported (default)
-# 1 = Supported
-#
-# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
-# Indicates support for the reception of PPDUs using STBC
-# 0 = Not supported (default)
-# 1 = support of one spatial stream
-# 2 = support of one and two spatial streams
-# 3 = support of one, two and three spatial streams
-# 4 = support of one, two, three and four spatial streams
-# 5,6,7 = reserved
-#
-# SU Beamformer Capable: [SU-BEAMFORMER]
-# Indicates support for operation as a single user beamformer
-# 0 = Not supported (default)
-# 1 = Supported
-#
-# SU Beamformee Capable: [SU-BEAMFORMEE]
-# Indicates support for operation as a single user beamformee
-# 0 = Not supported (default)
-# 1 = Supported
-#
-# Compressed Steering Number of Beamformer Antennas Supported:
-# [BF-ANTENNA-2] [BF-ANTENNA-3] [BF-ANTENNA-4]
-# Beamformee's capability indicating the maximum number of beamformer
-# antennas the beamformee can support when sending compressed beamforming
-# feedback
-# If SU beamformer capable, set to maximum value minus 1
-# else reserved (default)
-#
-# Number of Sounding Dimensions:
-# [SOUNDING-DIMENSION-2] [SOUNDING-DIMENSION-3] [SOUNDING-DIMENSION-4]
-# Beamformer's capability indicating the maximum value of the NUM_STS parameter
-# in the TXVECTOR of a VHT NDP
-# If SU beamformer capable, set to maximum value minus 1
-# else reserved (default)
-#
-# MU Beamformer Capable: [MU-BEAMFORMER]
-# Indicates support for operation as an MU beamformer
-# 0 = Not supported or sent by Non-AP STA (default)
-# 1 = Supported
-#
-# VHT TXOP PS: [VHT-TXOP-PS]
-# Indicates whether or not the AP supports VHT TXOP Power Save Mode
-# or whether or not the STA is in VHT TXOP Power Save mode
-# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS
-# mode
-# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save
-# mode
-#
-# +HTC-VHT Capable: [HTC-VHT]
-# Indicates whether or not the STA supports receiving a VHT variant HT Control
-# field.
-# 0 = Not supported (default)
-# 1 = supported
-#
-# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
-# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
-# This field is an integer in the range of 0 to 7.
-# The length defined by this field is equal to
-# 2 pow(13 ~ Maximum A-MPDU Length Exponent) -1 octets
-#
-# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
-# Indicates whether or not the STA supports link adaptation using VHT variant
-# HT Control field
-# If +HTC-VHTcapable is 1
-# 0 = (no feedback) if the STA does not provide VHT MFB (default)
-# 1 = reserved
-# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
-# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
-# STA provides unsolicited VHT MFB
-# Reserved if +HTC-VHTcapable is 0
-#
-# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
-# Indicates the possibility of Rx antenna pattern change
-# 0 = Rx antenna pattern might change during the lifetime of an association
-# 1 = Rx antenna pattern does not change during the lifetime of an association
-#
-# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
-# Indicates the possibility of Tx antenna pattern change
-# 0 = Tx antenna pattern might change during the lifetime of an association
-# 1 = Tx antenna pattern does not change during the lifetime of an
-
{% if capabilities.vht.center_channel_freq.freq_1 is vyos_defined %}
-# center freq = 5 GHz ~ (5 * index)
-# So index 42 gives center freq 5.210 GHz
-# which is channel 42 in 5G band
vht_oper_centr_freq_seg0_idx={{ capabilities.vht.center_channel_freq.freq_1 }}
{% endif %}
-
{% if capabilities.vht.center_channel_freq.freq_2 is vyos_defined %}
-# center freq = 5 GHz ~ (5 * index)
-# So index 159 gives center freq 5.795 GHz
-# which is channel 159 in 5G band
vht_oper_centr_freq_seg1_idx={{ capabilities.vht.center_channel_freq.freq_2 }}
{% endif %}
-
{% if capabilities.vht.channel_set_width is vyos_defined %}
vht_oper_chwidth={{ capabilities.vht.channel_set_width }}
{% endif %}
-
{% set output = namespace(value='') %}
{% if capabilities.vht.channel_set_width is vyos_defined('2') %}
{% set output.value = output.value ~ '[VHT160]' %}
@@ -405,136 +187,85 @@ vht_oper_chwidth={{ capabilities.vht.channel_set_width }}
{% endif %}
{% endif %}
{% endif %}
-
vht_capab={{ output.value }}
{% endif %}
-
-# ieee80211n: Whether IEEE 802.11n (HT) is enabled
-# 0 = disabled (default)
-# 1 = enabled
-# Note: You will also need to enable WMM for full HT functionality.
-# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
-{% if capabilities.require_vht is vyos_defined %}
+{# TODO: Research if require_(ht|vht|he) are mutually exclusive! #}
+{% if capabilities.require_vht is vyos_defined or capabilities.require_he is vyos_defined %}
+{% if capabilities.require_vht is vyos_defined %}
ieee80211n=0
-# Require stations to support VHT PHY (reject association if they do not)
require_vht=1
+{% endif %}
+{% if capabilities.require_he is vyos_defined %}
+ieee80211n=0
+require_he=1
+{% endif %}
{% else %}
-ieee80211n={{ '1' if 'n' in mode or 'ac' in mode else '0' }}
+ieee80211n={{ '1' if 'n' in mode or 'ac' in mode or 'ax' in mode else '0' }}
{% endif %}
-
+{# HE (802.11ax 6GHz) #}
+{% if capabilities.he is vyos_defined and mode in 'ax' %}
+{# For now, hard-code power levels for indoor-only AP #}
+he_6ghz_reg_pwr_type=0
+{# If we had an option to set indoor/outdoor/all environments for a reg domain, we would need to configure the country3 value as well! #}
+{# country3=0x4f #}
+{% if capabilities.he.center_channel_freq.freq_1 is vyos_defined %}
+he_oper_centr_freq_seg0_idx={{ capabilities.he.center_channel_freq.freq_1 }}
+{% endif %}
+{% if capabilities.he.center_channel_freq.freq_2 is vyos_defined %}
+he_oper_centr_freq_seg1_idx={{ capabilities.he.center_channel_freq.freq_2 }}
+{% endif %}
+{% if capabilities.he.channel_set_width is vyos_defined %}
+op_class={{ capabilities.he.channel_set_width }}
+{% endif %}
+{% if capabilities.he.bss_color is vyos_defined %}
+he_bss_color={{ capabilities.he.bss_color }}
+{% endif %}
+he_6ghz_rx_ant_pat={{ '1' if capabilities.he.antenna_pattern_fixed is vyos_defined else '0' }}
+he_su_beamformer={{ '1' if capabilities.he.beamform.single_user_beamformer is vyos_defined else '0' }}
+he_su_beamformee={{ '1' if capabilities.he.beamform.single_user_beamformee is vyos_defined else '0' }}
+he_mu_beamformer={{ '1' if capabilities.he.beamform.multi_user_beamformer is vyos_defined else '0' }}
+{% endif %}
+{# generic stuff #}
{% if disable_broadcast_ssid is vyos_defined %}
-# Send empty SSID in beacons and ignore probe request frames that do not
-# specify full SSID, i.e., require stations to know SSID.
-# default: disabled (0)
-# 1 = send empty (length=0) SSID in beacon and ignore probe request for
-# broadcast SSID
-# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
-# with some clients that do not support empty SSID) and ignore probe
-# requests for broadcast SSID
ignore_broadcast_ssid=1
{% endif %}
-
{% if type is vyos_defined('access-point') %}
-# Station MAC address-based authentication
-# Please note that this kind of access control requires a driver that uses
-# hostapd to take care of management frame processing and as such, this can be
-# used with driver=hostap or driver=nl80211, but not with driver=atheros.
-# 0 = accept unless in deny list
-# 1 = deny unless in accept list
-# 2 = use external RADIUS server (accept/deny lists are searched first)
macaddr_acl={{ '0' if security.station_address.mode is vyos_defined('accept') else '1' }}
-
-# Accept/deny lists are read from separate files (containing list of
-# MAC addresses, one per line). Use absolute path name to make sure that the
-# files can be read on SIGHUP configuration reloads.
accept_mac_file={{ hostapd_accept_station_conf }}
deny_mac_file={{ hostapd_deny_station_conf }}
{% endif %}
-
+{% if stationary_ap is vyos_defined %}
+stationary_ap=1
+{% endif %}
{% if max_stations is vyos_defined %}
-# Maximum number of stations allowed in station table. New stations will be
-# rejected after the station table is full. IEEE 802.11 has a limit of 2007
-# different association IDs, so this number should not be larger than that.
-# (default: 2007)
max_num_sta={{ max_stations }}
{% endif %}
-
{% if isolate_stations is vyos_defined %}
-# Client isolation can be used to prevent low-level bridging of frames between
-# associated stations in the BSS. By default, this bridging is allowed.
ap_isolate=1
{% endif %}
-
+{# enable_background_radar not yet supported by VyOS's version of hostapd
+{% if background_radar_detection is vyos_defined %}
+enable_background_radar=1
+{% endif %}
+ #}
{% if reduce_transmit_power is vyos_defined %}
-# Add Power Constraint element to Beacon and Probe Response frames
-# This config option adds Power Constraint element when applicable and Country
-# element is added. Power Constraint element is required by Transmit Power
-# Control. This can be used only with ieee80211d=1.
-# Valid values are 0..255.
local_pwr_constraint={{ reduce_transmit_power }}
{% endif %}
-
{% if expunge_failing_stations is vyos_defined %}
-# Disassociate stations based on excessive transmission failures or other
-# indications of connection loss. This depends on the driver capabilities and
-# may not be available with all drivers.
disassoc_low_ack=1
{% endif %}
-
-
{% if security.wep is vyos_defined %}
-# IEEE 802.11 specifies two authentication algorithms. hostapd can be
-# configured to allow both of these or only one. Open system authentication
-# should be used with IEEE 802.1X.
-# Bit fields of allowed authentication algorithms:
-# bit 0 = Open System Authentication
-# bit 1 = Shared Key Authentication (requires WEP)
auth_algs=2
-
-# WEP rekeying (disabled if key lengths are not set or are set to 0)
-# Key lengths for default/broadcast and individual/unicast keys:
-# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
-# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
wep_key_len_broadcast=5
wep_key_len_unicast=5
-
-# Static WEP key configuration
-#
-# The key number to use when transmitting.
-# It must be between 0 and 3, and the corresponding key must be set.
-# default: not set
wep_default_key=0
-
-# The WEP keys to use.
-# A key may be a quoted string or unquoted hexadecimal digits.
-# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
-# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
-# 128-bit (152-bit) WEP is used.
-# Only the default key must be supplied; the others are optional.
{% if security.wep.key is vyos_defined %}
{% for key in sec_wep_key %}
wep_key{{ loop.index -1 }}={{ security.wep.key }}
{% endfor %}
{% endif %}
-
-
{% elif security.wpa is vyos_defined %}
-##### WPA/IEEE 802.11i configuration ##########################################
-
-# Enable WPA. Setting this variable configures the AP to require WPA (either
-# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
-# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
-# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
-# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
-# RADIUS authentication server must be configured, and WPA-EAP must be included
-# in wpa_key_mgmt.
-# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
-# and/or WPA2 (full IEEE 802.11i/RSN):
-# bit0 = WPA
-# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
-# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2.
-# In other words, for WPA3, wpa 2 is used the configuration (and
-# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
+auth_algs=1
{% if security.wpa.mode is vyos_defined('wpa+wpa2') %}
wpa=3
{% elif security.wpa.mode is vyos_defined('wpa2') or security.wpa.mode is vyos_defined('wpa3') %}
@@ -542,122 +273,459 @@ wpa=2
{% elif security.wpa.mode is vyos_defined('wpa') %}
wpa=1
{% endif %}
-
{% if security.wpa.cipher is vyos_defined %}
-# Set of accepted cipher suites (encryption algorithms) for pairwise keys
-# (unicast packets). This is a space separated list of algorithms:
-# CCMP = AES in Counter mode with CBC-MAC (CCMP-128)
-# TKIP = Temporal Key Integrity Protocol
-# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key
-# GCMP = Galois/counter mode protocol (GCMP-128)
-# GCMP-256 = Galois/counter mode protocol with 256-bit key
-# Group cipher suite (encryption algorithm for broadcast and multicast frames)
-# is automatically selected based on this configuration. If only CCMP is
-# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
-# TKIP will be used as the group cipher. The optional group_cipher parameter can
-# be used to override this automatic selection.
-
-{% if security.wpa.mode is vyos_defined('wpa2') %}
-# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
+{% if security.wpa.mode is vyos_defined('wpa2') or security.wpa.mode is vyos_defined('wpa3') %}
rsn_pairwise={{ security.wpa.cipher | join(" ") }}
{% else %}
-# Pairwise cipher for WPA (v1) (default: TKIP)
wpa_pairwise={{ security.wpa.cipher | join(" ") }}
{% endif %}
{% endif %}
-
{% if security.wpa.group_cipher is vyos_defined %}
-# Optional override for automatic group cipher selection
-# This can be used to select a specific group cipher regardless of which
-# pairwise ciphers were enabled for WPA and RSN. It should be noted that
-# overriding the group cipher with an unexpected value can result in
-# interoperability issues and in general, this parameter is mainly used for
-# testing purposes.
-group_cipher={{ security.wpa.group_cipher | join(" ") }}
+group_cipher={{ security.wpa.group_cipher }}
+{% endif %}
+{% if security.wpa.group_mgmt_cipher is vyos_defined %}
+group_mgmt_cipher={{ security.wpa.group_mgmt_cipher }}
{% endif %}
-
{% if security.wpa.passphrase is vyos_defined %}
-# IEEE 802.11 specifies two authentication algorithms. hostapd can be
-# configured to allow both of these or only one. Open system authentication
-# should be used with IEEE 802.1X.
-# Bit fields of allowed authentication algorithms:
-# bit 0 = Open System Authentication
-# bit 1 = Shared Key Authentication (requires WEP)
-auth_algs=1
-
-# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
-# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
-# (8..63 characters) that will be converted to PSK. This conversion uses SSID
-# so the PSK changes when ASCII passphrase is used and the SSID is changed.
-wpa_passphrase={{ security.wpa.passphrase }}
-
-# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
-# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
-# added to enable SHA256-based stronger algorithms.
-# WPA-PSK = WPA-Personal / WPA2-Personal
-# WPA-PSK-SHA256 = WPA2-Personal using SHA256
-# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
-# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
-# SAE = SAE (WPA3-Personal)
-# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
{% if security.wpa.mode is vyos_defined('wpa3') %}
wpa_key_mgmt=SAE
+sae_password={{ security.wpa.passphrase }}
+extended_key_id=1
+wpa_gmk_rekey=86400
+wpa_group_rekey=86400
+wpa_group_update_count=4
{% else %}
wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256
+wpa_passphrase={{ security.wpa.passphrase }}
{% endif %}
-
{% elif security.wpa.radius is vyos_defined %}
-##### IEEE 802.1X-2004 related configuration ##################################
-# Require IEEE 802.1X authorization
ieee8021x=1
-
-# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
-# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
-# added to enable SHA256-based stronger algorithms.
-# WPA-PSK = WPA-Personal / WPA2-Personal
-# WPA-PSK-SHA256 = WPA2-Personal using SHA256
-# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
-# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
-# SAE = SAE (WPA3-Personal)
-# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
{% if security.wpa.mode is vyos_defined('wpa3') %}
wpa_key_mgmt=WPA-EAP-SUITE-B-192
{% else %}
wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256
{% endif %}
-
{% if security.wpa.radius.server is vyos_defined %}
-# RADIUS client forced local IP address for the access point
-# Normally the local IP address is determined automatically based on configured
-# IP addresses, but this field can be used to force a specific address to be
-# used, e.g., when the device has multiple IP addresses.
-# The own IP address of the access point (used as NAS-IP-Address)
{% if security.wpa.radius.source_address is vyos_defined %}
radius_client_addr={{ security.wpa.radius.source_address }}
own_ip_addr={{ security.wpa.radius.source_address }}
{% else %}
own_ip_addr=127.0.0.1
{% endif %}
-
{% for radius in security.wpa.radius.server if not radius.disabled %}
-# RADIUS authentication server
auth_server_addr={{ radius.server }}
auth_server_port={{ radius.port }}
auth_server_shared_secret={{ radius.key }}
-
{% if radius.acc_port %}
-# RADIUS accounting server
acct_server_addr={{ radius.server }}
acct_server_port={{ radius.acc_port }}
acct_server_shared_secret={{ radius.key }}
{% endif %}
{% endfor %}
{% else %}
-# Open system
auth_algs=1
{% endif %}
{% endif %}
{% endif %}
+tx_queue_data3_aifs=7
+tx_queue_data3_cwmin=15
+tx_queue_data3_cwmax=1023
+tx_queue_data3_burst=0
+tx_queue_data2_aifs=3
+tx_queue_data2_cwmin=15
+tx_queue_data2_cwmax=63
+tx_queue_data2_burst=0
+tx_queue_data1_aifs=1
+tx_queue_data1_cwmin=7
+tx_queue_data1_cwmax=15
+tx_queue_data1_burst=3.0
+tx_queue_data0_aifs=1
+tx_queue_data0_cwmin=3
+tx_queue_data0_cwmax=7
+tx_queue_data0_burst=1.5
+wme_enabled=1
+wmm_enabled=1
+wmm_ac_bk_cwmin=4
+wmm_ac_bk_cwmax=10
+wmm_ac_bk_aifs=7
+wmm_ac_bk_txop_limit=0
+wmm_ac_bk_acm=0
+wmm_ac_be_aifs=3
+wmm_ac_be_cwmin=4
+wmm_ac_be_cwmax=10
+wmm_ac_be_txop_limit=0
+wmm_ac_be_acm=0
+wmm_ac_vi_aifs=2
+wmm_ac_vi_cwmin=3
+wmm_ac_vi_cwmax=4
+wmm_ac_vi_txop_limit=94
+wmm_ac_vi_acm=0
+wmm_ac_vo_aifs=2
+wmm_ac_vo_cwmin=2
+wmm_ac_vo_cwmax=3
+wmm_ac_vo_txop_limit=47
+wmm_ac_vo_acm=0
+
+{#
+# hostapd.conf for hostapd 2.10
+# hostapd.conf reference:
+# https://w1.fi/cgit/hostap/tree/hostapd/hostapd.conf?h=hostap_2_10&id=cff80b4f7d3c0a47c052e8187d671710f48939e4
+
+##### hostapd configuration file ##############################################
+# Empty lines and lines starting with # are ignored
+
+# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
+# management frames with the Host AP driver); wlan0 with many nl80211 drivers
+# Note: This attribute can be overridden by the values supplied with the '-i'
+# command line parameter.
+interface=wlan0
+
+# In case of atheros and nl80211 driver interfaces, an additional
+# configuration parameter, bridge, may be used to notify hostapd if the
+# interface is included in a bridge. This parameter is not used with Host AP
+# driver. If the bridge parameter is not set, the drivers will automatically
+# figure out the bridge interface (assuming sysfs is enabled and mounted to
+# /sys) and this parameter may not be needed.
+#
+# For nl80211, this parameter can be used to request the AP interface to be
+# added to the bridge automatically (brctl may refuse to do this before hostapd
+# has been started to change the interface mode). If needed, the bridge
+# interface is also created.
+#bridge=br0
+
+# Driver interface type (hostap/wired/none/nl80211/bsd);
+# default: hostap). nl80211 is used with all Linux mac80211 drivers.
+# Use driver=none if building hostapd as a standalone RADIUS server that does
+# not control any wireless/wired driver.
+# driver=hostap
+
+# Driver interface parameters (mainly for development testing use)
+# driver_params=<params>
+
+# hostapd event logger configuration
+#
+# Two output method: syslog and stdout (only usable if not forking to
+# background).
+#
+# Module bitfield (ORed bitfield of modules that will be logged; -1 = all
+# modules):
+# bit 0 (1) = IEEE 802.11
+# bit 1 (2) = IEEE 802.1X
+# bit 2 (4) = RADIUS
+# bit 3 (8) = WPA
+# bit 4 (16) = driver interface
+# bit 6 (64) = MLME
+#
+# Levels (minimum value for logged events):
+# 0 = verbose debugging
+# 1 = debugging
+# 2 = informational messages
+# 3 = notification
+# 4 = warning
+#
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+
+# Interface for separate control program. If this is specified, hostapd
+# will create this directory and a UNIX domain socket for listening to requests
+# from external programs (CLI/GUI, etc.) for status information and
+# configuration. The socket file will be named based on the interface name, so
+# multiple hostapd processes/interfaces can be run at the same time if more
+# than one interface is used.
+# /var/run/hostapd is the recommended directory for sockets and by default,
+# hostapd_cli will use it when trying to connect with hostapd.
+ctrl_interface=/var/run/hostapd
+
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run hostapd as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, hostapd is configured to use gid 0 (root). If you
+# want to allow non-root users to use the control interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group.
+#
+# This variable can be a group name or gid.
+#ctrl_interface_group=wheel
+ctrl_interface_group=0
+
+
+##### IEEE 802.11 related configuration #######################################
+
+# SSID to be used in IEEE 802.11 management frames
+ssid=test
+# Alternative formats for configuring SSID
+# (double quoted string, hexdump, printf-escaped string)
+#ssid2="test"
+#ssid2=74657374
+#ssid2=P"hello\nthere"
+
+# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding
+#utf8_ssid=1
+
+# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
+# Set as needed to indicate country in which device is operating.
+# This can limit available channels and transmit power.
+# These two octets are used as the first two octets of the Country String
+# (dot11CountryString)
+#country_code=US
+
+# The third octet of the Country String (dot11CountryString)
+# This parameter is used to set the third octet of the country string.
+#
+# All environments of the current frequency band and country (default)
+#country3=0x20
+# Outdoor environment only
+#country3=0x4f
+# Indoor environment only
+#country3=0x49
+# Noncountry entity (country_code=XX)
+#country3=0x58
+# IEEE 802.11 standard Annex E table indication: 0x01 .. 0x1f
+# Annex E, Table E-4 (Global operating classes)
+#country3=0x04
+
+# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
+# channels and transmit power levels based on the regulatory limits. The
+# country_code setting must be configured with the correct country for
+# IEEE 802.11d functions.
+# (default: 0 = disabled)
+#ieee80211d=1
+
+# Enable IEEE 802.11h. This enables radar detection and DFS support if
+# available. DFS support is required on outdoor 5 GHz channels in most countries
+# of the world. This can be used only with ieee80211d=1.
+# (default: 0 = disabled)
+#ieee80211h=1
+
+# Add Power Constraint element to Beacon and Probe Response frames
+# This config option adds Power Constraint element when applicable and Country
+# element is added. Power Constraint element is required by Transmit Power
+# Control. This can be used only with ieee80211d=1.
+# Valid values are 0..255.
+#local_pwr_constraint=3
+
+# Set Spectrum Management subfield in the Capability Information field.
+# This config option forces the Spectrum Management bit to be set. When this
+# option is not set, the value of the Spectrum Management bit depends on whether
+# DFS or TPC is required by regulatory authorities. This can be used only with
+# ieee80211d=1 and local_pwr_constraint configured.
+#spectrum_mgmt_required=1
+
+# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
+# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
+# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
+# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs
+# to be set to hw_mode=a. When using ACS (see channel parameter), a
+# special value "any" can be used to indicate that any support band can be used.
+# This special case is currently supported only with drivers with which
+# offloaded ACS is used.
+# Default: IEEE 802.11b
+hw_mode=g
+
+# Channel number (IEEE 802.11)
+# (default: 0, i.e., not set)
+# Please note that some drivers do not use this value from hostapd and the
+# channel will need to be configured separately with iwconfig.
+#
+# If CONFIG_ACS build option is enabled, the channel can be selected
+# automatically at run time by setting channel=acs_survey or channel=0, both of
+# which will enable the ACS survey based algorithm.
+channel=1
+
+# Global operating class (IEEE 802.11, Annex E, Table E-4)
+# This option allows hostapd to specify the operating class of the channel
+# configured with the channel parameter. channel and op_class together can
+# uniquely identify channels across different bands, including the 6 GHz band.
+#op_class=131
+
+# ACS tuning - Automatic Channel Selection
+# See: https://wireless.wiki.kernel.org/en/users/documentation/acs
+#
+# You can customize the ACS survey algorithm with following variables:
+#
+# acs_num_scans requirement is 1..100 - number of scans to be performed that
+# are used to trigger survey data gathering of an underlying device driver.
+# Scans are passive and typically take a little over 100ms (depending on the
+# driver) on each available channel for given hw_mode. Increasing this value
+# means sacrificing startup time and gathering more data wrt channel
+# interference that may help choosing a better channel. This can also help fine
+# tune the ACS scan time in case a driver has different scan dwell times.
+#
+# acs_chan_bias is a space-separated list of <channel>:<bias> pairs. It can be
+# used to increase (or decrease) the likelihood of a specific channel to be
+# selected by the ACS algorithm. The total interference factor for each channel
+# gets multiplied by the specified bias value before finding the channel with
+# the lowest value. In other words, values between 0.0 and 1.0 can be used to
+# make a channel more likely to be picked while values larger than 1.0 make the
+# specified channel less likely to be picked. This can be used, e.g., to prefer
+# the commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default
+# behavior on 2.4 GHz band if no acs_chan_bias parameter is specified).
+#
+# Defaults:
+#acs_num_scans=5
+#acs_chan_bias=1:0.8 6:0.8 11:0.8
+
+# Channel list restriction. This option allows hostapd to select one of the
+# provided channels when a channel should be automatically selected.
+# Channel list can be provided as range using hyphen ('-') or individual
+# channels can be specified by space (' ') separated values
+# Default: all channels allowed in selected hw_mode
+#chanlist=100 104 108 112 116
+#chanlist=1 6 11-13
+
+# Frequency list restriction. This option allows hostapd to select one of the
+# provided frequencies when a frequency should be automatically selected.
+# Frequency list can be provided as range using hyphen ('-') or individual
+# frequencies can be specified by comma (',') separated values
+# Default: all frequencies allowed in selected hw_mode
+#freqlist=2437,5955,5975
+#freqlist=2437,5985-6105
+
+# Exclude DFS channels from ACS
+# This option can be used to exclude all DFS channels from the ACS channel list
+# in cases where the driver supports DFS channels.
+#acs_exclude_dfs=1
+
+# Include only preferred scan channels from 6 GHz band for ACS
+# This option can be used to include only preferred scan channels in the 6 GHz
+# band. This can be useful in particular for devices that operate only a 6 GHz
+# BSS without a collocated 2.4/5 GHz BSS.
+# Default behavior is to include all PSC and non-PSC channels.
+#acs_exclude_6ghz_non_psc=1
+
+# Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection.
+# (default 0, i.e., not constraint)
+#min_tx_power=20
+
+# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
+beacon_int=100
+
+# DTIM (delivery traffic information message) period (range 1..255):
+# number of beacons between DTIMs (1 = every beacon includes DTIM element)
+# (default: 2)
+dtim_period=2
+
+# Maximum number of stations allowed in station table. New stations will be
+# rejected after the station table is full. IEEE 802.11 has a limit of 2007
+# different association IDs, so this number should not be larger than that.
+# (default: 2007)
+max_num_sta=255
+
+# RTS/CTS threshold; -1 = disabled (default); range -1..65535
+# If this field is not included in hostapd.conf, hostapd will not control
+# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
+rts_threshold=-1
+
+# Fragmentation threshold; -1 = disabled (default); range -1, 256..2346
+# If this field is not included in hostapd.conf, hostapd will not control
+# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
+# it.
+fragm_threshold=-1
+
+# Rate configuration
+# Default is to enable all rates supported by the hardware. This configuration
+# item allows this list be filtered so that only the listed rates will be left
+# in the list. If the list is empty, all rates are used. This list can have
+# entries that are not in the list of rates the hardware supports (such entries
+# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
+# If this item is present, at least one rate have to be matching with the rates
+# hardware supports.
+# default: use the most common supported rate setting for the selected
+# hw_mode (i.e., this line can be removed from configuration file in most
+# cases)
+#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
+
+# Basic rate set configuration
+# List of rates (in 100 kbps) that are included in the basic rate set.
+# If this item is not included, usually reasonable default set is used.
+#basic_rates=10 20
+#basic_rates=10 20 55 110
+#basic_rates=60 120 240
+
+# Beacon frame TX rate configuration
+# This sets the TX rate that is used to transmit Beacon frames. If this item is
+# not included, the driver default rate (likely lowest rate) is used.
+# Legacy (CCK/OFDM rates):
+# beacon_rate=<legacy rate in 100 kbps>
+# HT:
+# beacon_rate=ht:<HT MCS>
+# VHT:
+# beacon_rate=vht:<VHT MCS>
+# HE:
+# beacon_rate=he:<HE MCS>
+#
+# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
+#beacon_rate=10
+
+# Short Preamble
+# This parameter can be used to enable optional use of short preamble for
+# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
+# This applies only to IEEE 802.11b-compatible networks and this should only be
+# enabled if the local hardware supports use of short preamble. If any of the
+# associated STAs do not support short preamble, use of short preamble will be
+# disabled (and enabled when such STAs disassociate) dynamically.
+# 0 = do not allow use of short preamble (default)
+# 1 = allow use of short preamble
+#preamble=1
+
+# Station MAC address -based authentication
+# Please note that this kind of access control requires a driver that uses
+# hostapd to take care of management frame processing and as such, this can be
+# used with driver=hostap or driver=nl80211, but not with driver=atheros.
+# 0 = accept unless in deny list
+# 1 = deny unless in accept list
+# 2 = use external RADIUS server (accept/deny lists are searched first)
+macaddr_acl=0
+
+# Accept/deny lists are read from separate files (containing list of
+# MAC addresses, one per line). Use absolute path name to make sure that the
+# files can be read on SIGHUP configuration reloads.
+#accept_mac_file=/etc/hostapd.accept
+#deny_mac_file=/etc/hostapd.deny
+
+# IEEE 802.11 specifies two authentication algorithms. hostapd can be
+# configured to allow both of these or only one. Open system authentication
+# should be used with IEEE 802.1X.
+# Bit fields of allowed authentication algorithms:
+# bit 0 = Open System Authentication
+# bit 1 = Shared Key Authentication (requires WEP)
+auth_algs=3
+
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+# broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+# with some clients that do not support empty SSID) and ignore probe
+# requests for broadcast SSID
+ignore_broadcast_ssid=0
+
+# Do not reply to broadcast Probe Request frames from unassociated STA if there
+# is no room for additional stations (max_num_sta). This can be used to
+# discourage a STA from trying to associate with this AP if the association
+# would be rejected due to maximum STA limit.
+# Default: 0 (disabled)
+#no_probe_resp_if_max_sta=0
+
+# Additional vendor specific elements for Beacon and Probe Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the Beacon and Probe Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#vendor_elements=dd0411223301
+
+# Additional vendor specific elements for (Re)Association Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the (Re)Association Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#assocresp_elements=dd0411223301
# TX queue parameters (EDCF / bursting)
# tx_queue_<queue name>_<param>
@@ -676,31 +744,48 @@ auth_algs=1
# to the clients.
#
# Low priority / AC_BK = background
-tx_queue_data3_aifs=7
-tx_queue_data3_cwmin=15
-tx_queue_data3_cwmax=1023
-tx_queue_data3_burst=0
+#tx_queue_data3_aifs=7
+#tx_queue_data3_cwmin=15
+#tx_queue_data3_cwmax=1023
+#tx_queue_data3_burst=0
# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
#
# Normal priority / AC_BE = best effort
-tx_queue_data2_aifs=3
-tx_queue_data2_cwmin=15
-tx_queue_data2_cwmax=63
-tx_queue_data2_burst=0
+#tx_queue_data2_aifs=3
+#tx_queue_data2_cwmin=15
+#tx_queue_data2_cwmax=63
+#tx_queue_data2_burst=0
# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
#
# High priority / AC_VI = video
-tx_queue_data1_aifs=1
-tx_queue_data1_cwmin=7
-tx_queue_data1_cwmax=15
-tx_queue_data1_burst=3.0
+#tx_queue_data1_aifs=1
+#tx_queue_data1_cwmin=7
+#tx_queue_data1_cwmax=15
+#tx_queue_data1_burst=3.0
# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
#
# Highest priority / AC_VO = voice
-tx_queue_data0_aifs=1
-tx_queue_data0_cwmin=3
-tx_queue_data0_cwmax=7
-tx_queue_data0_burst=1.5
+#tx_queue_data0_aifs=1
+#tx_queue_data0_cwmin=3
+#tx_queue_data0_cwmax=7
+#tx_queue_data0_burst=1.5
+# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
+
+# 802.1D Tag (= UP) to AC mappings
+# WMM specifies following mapping of data frames to different ACs. This mapping
+# can be configured using Linux QoS/tc and sch_pktpri.o module.
+# 802.1D Tag 802.1D Designation Access Category WMM Designation
+# 1 BK AC_BK Background
+# 2 - AC_BK Background
+# 0 BE AC_BE Best Effort
+# 3 EE AC_BE Best Effort
+# 4 CL AC_VI Video
+# 5 VI AC_VI Video
+# 6 VO AC_VO Voice
+# 7 NC AC_VO Voice
+# Data frames with no priority information: AC_BE
+# Management frames: AC_VO
+# PS-Poll frames: AC_BE
# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
# for 802.11a or 802.11g networks
@@ -716,7 +801,11 @@ tx_queue_data0_burst=1.5
# wmm_ac_??_{cwmin,cwmax} is 0..15 with cwmax >= cwmin.
#
wmm_enabled=1
-
+#
+# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD]
+# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver)
+#uapsd_advertisement_enabled=1
+#
# Low priority / AC_BK = background
wmm_ac_bk_cwmin=4
wmm_ac_bk_cwmax=10
@@ -747,3 +836,2586 @@ wmm_ac_vo_cwmin=2
wmm_ac_vo_cwmax=3
wmm_ac_vo_txop_limit=47
wmm_ac_vo_acm=0
+# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+
+# Enable Multi-AP functionality
+# 0 = disabled (default)
+# 1 = AP support backhaul BSS
+# 2 = AP support fronthaul BSS
+# 3 = AP supports both backhaul BSS and fronthaul BSS
+#multi_ap=0
+
+# Static WEP key configuration
+#
+# The key number to use when transmitting.
+# It must be between 0 and 3, and the corresponding key must be set.
+# default: not set
+#wep_default_key=0
+# The WEP keys to use.
+# A key may be a quoted string or unquoted hexadecimal digits.
+# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
+# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
+# 128-bit (152-bit) WEP is used.
+# Only the default key must be supplied; the others are optional.
+# default: not set
+#wep_key0=123456789a
+#wep_key1="vwxyz"
+#wep_key2=0102030405060708090a0b0c0d
+#wep_key3=".2.4.6.8.0.23"
+
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+#
+# The inactivity polling can be disabled to disconnect stations based on
+# inactivity timeout so that idle stations are more likely to be disconnected
+# even if they are still in range of the AP. This can be done by setting
+# skip_inactivity_poll to 1 (default 0).
+#skip_inactivity_poll=0
+
+# Disassociate stations based on excessive transmission failures or other
+# indications of connection loss. This depends on the driver capabilities and
+# may not be available with all drivers.
+#disassoc_low_ack=1
+
+# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
+# remain asleep). Default: 65535 (no limit apart from field size)
+#max_listen_interval=100
+
+# WDS (4-address frame) mode with per-station virtual interfaces
+# (only supported with driver=nl80211)
+# This mode allows associated stations to use 4-address frames to allow layer 2
+# bridging to be used.
+#wds_sta=1
+
+# If bridge parameter is set, the WDS STA interface will be added to the same
+# bridge by default. This can be overridden with the wds_bridge parameter to
+# use a separate bridge.
+#wds_bridge=wds-br0
+
+# Start the AP with beaconing disabled by default.
+#start_disabled=0
+
+# Client isolation can be used to prevent low-level bridging of frames between
+# associated stations in the BSS. By default, this bridging is allowed.
+#ap_isolate=1
+
+# BSS Load update period (in BUs)
+# This field is used to enable and configure adding a BSS Load element into
+# Beacon and Probe Response frames.
+#bss_load_update_period=50
+
+# Channel utilization averaging period (in BUs)
+# This field is used to enable and configure channel utilization average
+# calculation with bss_load_update_period. This should be in multiples of
+# bss_load_update_period for more accurate calculation.
+#chan_util_avg_period=600
+
+# Fixed BSS Load value for testing purposes
+# This field can be used to configure hostapd to add a fixed BSS Load element
+# into Beacon and Probe Response frames for testing purposes. The format is
+# <station count>:<channel utilization>:<available admission capacity>
+#bss_load_test=12:80:20000
+
+# Multicast to unicast conversion
+# Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and
+# IPv6 frames (possibly within 802.1Q). If enabled, such frames are to be sent
+# to each station separately, with the DA replaced by their own MAC address
+# rather than the group address.
+#
+# Note that this may break certain expectations of the receiver, such as the
+# ability to drop unicast IP packets received within multicast L2 frames, or the
+# ability to not send ICMP destination unreachable messages for packets received
+# in L2 multicast (which is required, but the receiver can't tell the difference
+# if this new option is enabled).
+#
+# This also doesn't implement the 802.11 DMS (directed multicast service).
+#
+#multicast_to_unicast=0
+
+# Send broadcast Deauthentication frame on AP start/stop
+# Default: 1 (enabled)
+#broadcast_deauth=1
+
+# Get notifications for received Management frames on control interface
+# Default: 0 (disabled)
+#notify_mgmt_frames=0
+
+##### IEEE 802.11n related configuration ######################################
+
+# ieee80211n: Whether IEEE 802.11n (HT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full HT functionality.
+# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
+#ieee80211n=1
+
+# disable_11n: Boolean (0/1) to disable HT for a specific BSS
+#disable_11n=0
+
+# ht_capab: HT capabilities (list of flags)
+# LDPC coding capability: [LDPC] = supported
+# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
+# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
+# with secondary channel above the primary channel
+# (20 MHz only if neither is set)
+# Note: There are limits on which channels can be used with HT40- and
+# HT40+. Following table shows the channels that may be available for
+# HT40- and HT40+ use per IEEE 802.11n Annex J:
+# freq HT40- HT40+
+# 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan)
+# 5 GHz 40,48,56,64 36,44,52,60
+# (depending on the location, not all of these channels may be available
+# for use)
+# Please note that 40 MHz channels may switch their primary and secondary
+# channels if needed or creation of 40 MHz channel maybe rejected based
+# on overlapping BSSes. These changes are done automatically when hostapd
+# is setting up the 40 MHz channel.
+# HT-greenfield: [GF] (disabled if not set)
+# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
+# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
+# Tx STBC: [TX-STBC] (disabled if not set)
+# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial
+# streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC
+# disabled if none of these set
+# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set)
+# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
+# set)
+# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
+# 40 MHz intolerant [40-INTOLERANT] (not advertised if not set)
+# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
+#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
+
+# Require stations to support HT PHY (reject association if they do not)
+#require_ht=1
+
+# If set non-zero, require stations to perform scans of overlapping
+# channels to test for stations which would be affected by 40 MHz traffic.
+# This parameter sets the interval in seconds between these scans. Setting this
+# to non-zero allows 2.4 GHz band AP to move dynamically to a 40 MHz channel if
+# no co-existence issues with neighboring devices are found.
+#obss_interval=0
+
+##### IEEE 802.11ac related configuration #####################################
+
+# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full VHT functionality.
+# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
+#ieee80211ac=1
+
+# disable_11ac: Boolean (0/1) to disable VHT for a specific BSS
+#disable_11ac=0
+
+# vht_capab: VHT capabilities (list of flags)
+#
+# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
+# Indicates maximum MPDU length
+# 0 = 3895 octets (default)
+# 1 = 7991 octets
+# 2 = 11454 octets
+# 3 = reserved
+#
+# supported_chan_width: [VHT160] [VHT160-80PLUS80]
+# Indicates supported Channel widths
+# 0 = 160 MHz & 80+80 channel widths are not supported (default)
+# 1 = 160 MHz channel width is supported
+# 2 = 160 MHz & 80+80 channel widths are supported
+# 3 = reserved
+#
+# Rx LDPC coding capability: [RXLDPC]
+# Indicates support for receiving LDPC coded pkts
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 80 MHz: [SHORT-GI-80]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 80Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 160 MHz: [SHORT-GI-160]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 160Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Tx STBC: [TX-STBC-2BY1]
+# Indicates support for the transmission of at least 2x1 STBC
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
+# Indicates support for the reception of PPDUs using STBC
+# 0 = Not supported (default)
+# 1 = support of one spatial stream
+# 2 = support of one and two spatial streams
+# 3 = support of one, two and three spatial streams
+# 4 = support of one, two, three and four spatial streams
+# 5,6,7 = reserved
+#
+# SU Beamformer Capable: [SU-BEAMFORMER]
+# Indicates support for operation as a single user beamformer
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# SU Beamformee Capable: [SU-BEAMFORMEE]
+# Indicates support for operation as a single user beamformee
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Compressed Steering Number of Beamformer Antennas Supported:
+# [BF-ANTENNA-2] [BF-ANTENNA-3] [BF-ANTENNA-4]
+# Beamformee's capability indicating the maximum number of beamformer
+# antennas the beamformee can support when sending compressed beamforming
+# feedback
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# Number of Sounding Dimensions:
+# [SOUNDING-DIMENSION-2] [SOUNDING-DIMENSION-3] [SOUNDING-DIMENSION-4]
+# Beamformer's capability indicating the maximum value of the NUM_STS parameter
+# in the TXVECTOR of a VHT NDP
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# MU Beamformer Capable: [MU-BEAMFORMER]
+# Indicates support for operation as an MU beamformer
+# 0 = Not supported or sent by Non-AP STA (default)
+# 1 = Supported
+#
+# VHT TXOP PS: [VHT-TXOP-PS]
+# Indicates whether or not the AP supports VHT TXOP Power Save Mode
+# or whether or not the STA is in VHT TXOP Power Save mode
+# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS
+# mode
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save
+# mode
+#
+# +HTC-VHT Capable: [HTC-VHT]
+# Indicates whether or not the STA supports receiving a VHT variant HT Control
+# field.
+# 0 = Not supported (default)
+# 1 = supported
+#
+# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
+# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
+# This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+#
+# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
+# Indicates whether or not the STA supports link adaptation using VHT variant
+# HT Control field
+# If +HTC-VHTcapable is 1
+# 0 = (no feedback) if the STA does not provide VHT MFB (default)
+# 1 = reserved
+# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
+# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
+# STA provides unsolicited VHT MFB
+# Reserved if +HTC-VHTcapable is 0
+#
+# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+#
+# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+#vht_capab=[SHORT-GI-80][HTC-VHT]
+#
+# Require stations to support VHT PHY (reject association if they do not)
+#require_vht=1
+
+# 0 = 20 or 40 MHz operating Channel width
+# 1 = 80 MHz channel width
+# 2 = 160 MHz channel width
+# 3 = 80+80 MHz channel width
+#vht_oper_chwidth=1
+#
+# center freq = 5 GHz + (5 * index)
+# So index 42 gives center freq 5.210 GHz
+# which is channel 42 in 5G band
+#
+#vht_oper_centr_freq_seg0_idx=42
+#
+# center freq = 5 GHz + (5 * index)
+# So index 159 gives center freq 5.795 GHz
+# which is channel 159 in 5G band
+#
+#vht_oper_centr_freq_seg1_idx=159
+
+# Workaround to use station's nsts capability in (Re)Association Response frame
+# This may be needed with some deployed devices as an interoperability
+# workaround for beamforming if the AP's capability is greater than the
+# station's capability. This is disabled by default and can be enabled by
+# setting use_sta_nsts=1.
+#use_sta_nsts=0
+
+##### IEEE 802.11ax related configuration #####################################
+
+#ieee80211ax: Whether IEEE 802.11ax (HE) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+#ieee80211ax=1
+
+# disable_11ax: Boolean (0/1) to disable HE for a specific BSS
+#disable_11ax=0
+
+#he_su_beamformer: HE single user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#he_su_beamformer=1
+
+#he_su_beamformee: HE single user beamformee support
+# 0 = not supported (default)
+# 1 = supported
+#he_su_beamformee=1
+
+#he_mu_beamformer: HE multiple user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#he_mu_beamformer=1
+
+# he_bss_color: BSS color (1-63)
+#he_bss_color=1
+
+# he_bss_color_partial: BSS color AID equation
+#he_bss_color_partial=0
+
+#he_default_pe_duration: The duration of PE field in an HE PPDU in us
+# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
+#he_default_pe_duration=0
+
+#he_twt_required: Whether TWT is required
+# 0 = not required (default)
+# 1 = required
+#he_twt_required=0
+
+#he_twt_responder: Whether TWT (HE) responder is enabled
+# 0 = disabled
+# 1 = enabled if supported by the driver (default)
+#he_twt_responder=1
+
+#he_rts_threshold: Duration of STA transmission
+# 0 = not set (default)
+# unsigned integer = duration in units of 16 us
+#he_rts_threshold=0
+
+#he_er_su_disable: Disable 242-tone HE ER SU PPDU reception by the AP
+# 0 = enable reception (default)
+# 1 = disable reception
+#he_er_su_disable=0
+
+# HE operating channel information; see matching vht_* parameters for details.
+# he_oper_centr_freq_seg0_idx field is used to indicate center frequency of 80
+# and 160 MHz bandwidth operation. In 80+80 MHz operation, it is the center
+# frequency of the lower frequency segment. he_oper_centr_freq_seg1_idx field
+# is used only with 80+80 MHz bandwidth operation and it is used to transmit
+# the center frequency of the second segment.
+# On the 6 GHz band the center freq calculation starts from 5.950 GHz offset.
+# For example idx=3 would result in 5965 MHz center frequency. In addition,
+# he_oper_chwidth is ignored, and the channel width is derived from the
+# configured operating class or center frequency indexes (see
+# IEEE P802.11ax/D6.1 Annex E, Table E-4).
+#he_oper_chwidth
+#he_oper_centr_freq_seg0_idx
+#he_oper_centr_freq_seg1_idx
+
+#he_basic_mcs_nss_set: Basic NSS/MCS set
+# 16-bit combination of 2-bit values of Max HE-MCS For 1..8 SS; each 2-bit
+# value having following meaning:
+# 0 = HE-MCS 0-7, 1 = HE-MCS 0-9, 2 = HE-MCS 0-11, 3 = not supported
+#he_basic_mcs_nss_set
+
+#he_mu_edca_qos_info_param_count
+#he_mu_edca_qos_info_q_ack
+#he_mu_edca_qos_info_queue_request=1
+#he_mu_edca_qos_info_txop_request
+#he_mu_edca_ac_be_aifsn=0
+#he_mu_edca_ac_be_ecwmin=15
+#he_mu_edca_ac_be_ecwmax=15
+#he_mu_edca_ac_be_timer=255
+#he_mu_edca_ac_bk_aifsn=0
+#he_mu_edca_ac_bk_aci=1
+#he_mu_edca_ac_bk_ecwmin=15
+#he_mu_edca_ac_bk_ecwmax=15
+#he_mu_edca_ac_bk_timer=255
+#he_mu_edca_ac_vi_ecwmin=15
+#he_mu_edca_ac_vi_ecwmax=15
+#he_mu_edca_ac_vi_aifsn=0
+#he_mu_edca_ac_vi_aci=2
+#he_mu_edca_ac_vi_timer=255
+#he_mu_edca_ac_vo_aifsn=0
+#he_mu_edca_ac_vo_aci=3
+#he_mu_edca_ac_vo_ecwmin=15
+#he_mu_edca_ac_vo_ecwmax=15
+#he_mu_edca_ac_vo_timer=255
+
+# Spatial Reuse Parameter Set
+#
+# SR Control field value
+# B0 = PSR Disallowed
+# B1 = Non-SRG OBSS PD SR Disallowed
+# B2 = Non-SRG Offset Present
+# B3 = SRG Information Present
+# B4 = HESIGA_Spatial_reuse_value15_allowed
+#he_spr_sr_control
+#
+# Non-SRG OBSS PD Max Offset (included if he_spr_sr_control B2=1)
+#he_spr_non_srg_obss_pd_max_offset
+
+# SRG OBSS PD Min Offset (included if he_spr_sr_control B3=1)
+#he_spr_srg_obss_pd_min_offset
+#
+# SRG OBSS PD Max Offset (included if he_spr_sr_control B3=1)
+#he_spr_srg_obss_pd_max_offset
+#
+# SPR SRG BSS Color (included if he_spr_sr_control B3=1)
+# This config represents SRG BSS Color Bitmap field of Spatial Reuse Parameter
+# Set element that indicates the BSS color values used by members of the
+# SRG of which the transmitting STA is a member. The value is in range of 0-63.
+#he_spr_srg_bss_colors=1 2 10 63
+#
+# SPR SRG Partial BSSID (included if he_spr_sr_control B3=1)
+# This config represents SRG Partial BSSID Bitmap field of Spatial Reuse
+# Parameter Set element that indicates the Partial BSSID values used by members
+# of the SRG of which the transmitting STA is a member. The value range
+# corresponds to one of the 64 possible values of BSSID[39:44], where the lowest
+# numbered bit corresponds to Partial BSSID value 0 and the highest numbered bit
+# corresponds to Partial BSSID value 63.
+#he_spr_srg_partial_bssid=0 1 3 63
+#
+#he_6ghz_max_mpdu: Maximum MPDU Length of HE 6 GHz band capabilities.
+# Indicates maximum MPDU length
+# 0 = 3895 octets
+# 1 = 7991 octets
+# 2 = 11454 octets (default)
+#he_6ghz_max_mpdu=2
+#
+#he_6ghz_max_ampdu_len_exp: Maximum A-MPDU Length Exponent of HE 6 GHz band
+# capabilities. Indicates the maximum length of A-MPDU pre-EOF padding that
+# the STA can receive. This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+# 0 = AMPDU length of 8k
+# 1 = AMPDU length of 16k
+# 2 = AMPDU length of 32k
+# 3 = AMPDU length of 65k
+# 4 = AMPDU length of 131k
+# 5 = AMPDU length of 262k
+# 6 = AMPDU length of 524k
+# 7 = AMPDU length of 1048k (default)
+#he_6ghz_max_ampdu_len_exp=7
+#
+#he_6ghz_rx_ant_pat: Rx Antenna Pattern Consistency of HE 6 GHz capability.
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+# (default)
+#he_6ghz_rx_ant_pat=1
+#
+#he_6ghz_tx_ant_pat: Tx Antenna Pattern Consistency of HE 6 GHz capability.
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+# (default)
+#he_6ghz_tx_ant_pat=1
+
+# Unsolicited broadcast Probe Response transmission settings
+# This is for the 6 GHz band only. If the interval is set to a non-zero value,
+# the AP schedules unsolicited broadcast Probe Response frames to be
+# transmitted for in-band discovery. Refer to
+# IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning.
+# Valid range: 0..20 TUs; default is 0 (disabled)
+#unsol_bcast_probe_resp_interval=0
+
+##### IEEE 802.1X-2004 related configuration ##################################
+
+# Require IEEE 802.1X authorization
+#ieee8021x=1
+
+# IEEE 802.1X/EAPOL version
+# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
+# version 2. However, there are many client implementations that do not handle
+# the new version number correctly (they seem to drop the frames completely).
+# In order to make hostapd interoperate with these clients, the version number
+# can be set to the older version (1) with this configuration value.
+# Note: When using MACsec, eapol_version shall be set to 3, which is
+# defined in IEEE Std 802.1X-2010.
+#eapol_version=2
+
+# Optional displayable message sent with EAP Request-Identity. The first \0
+# in this string will be converted to ASCII-0 (nul). This can be used to
+# separate network info (comma separated list of attribute=value pairs); see,
+# e.g., RFC 4284.
+#eap_message=hello
+#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
+
+# WEP rekeying (disabled if key lengths are not set or are set to 0)
+# Key lengths for default/broadcast and individual/unicast keys:
+# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
+# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
+#wep_key_len_broadcast=5
+#wep_key_len_unicast=5
+# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
+#wep_rekey_period=300
+
+# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
+# only broadcast keys are used)
+eapol_key_index_workaround=0
+
+# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
+# reauthentication).
+# Note: Reauthentications may enforce a disconnection, check the related
+# parameter wpa_deny_ptk0_rekey for details.
+#eap_reauth_period=3600
+
+# Use PAE group address (01:80:c2:00:00:03) instead of individual target
+# address when sending EAPOL frames with driver=wired. This is the most common
+# mechanism used in wired authentication, but it also requires that the port
+# is only used by one station.
+#use_pae_group_addr=1
+
+# EAP Re-authentication Protocol (ERP) authenticator (RFC 6696)
+#
+# Whether to initiate EAP authentication with EAP-Initiate/Re-auth-Start before
+# EAP-Identity/Request
+#erp_send_reauth_start=1
+#
+# Domain name for EAP-Initiate/Re-auth-Start. Omitted from the message if not
+# set (no local ER server). This is also used by the integrated EAP server if
+# ERP is enabled (eap_server_erp=1).
+#erp_domain=example.com
+
+##### MACsec ##################################################################
+
+# macsec_policy: IEEE 802.1X/MACsec options
+# This determines how sessions are secured with MACsec (only for MACsec
+# drivers).
+# 0: MACsec not in use (default)
+# 1: MACsec enabled - Should secure, accept key server's advice to
+# determine whether to use a secure session or not.
+#
+# macsec_integ_only: IEEE 802.1X/MACsec transmit mode
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 0: Encrypt traffic (default)
+# 1: Integrity only
+#
+# macsec_replay_protect: IEEE 802.1X/MACsec replay protection
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 0: Replay protection disabled (default)
+# 1: Replay protection enabled
+#
+# macsec_replay_window: IEEE 802.1X/MACsec replay protection window
+# This determines a window in which replay is tolerated, to allow receipt
+# of frames that have been misordered by the network.
+# This setting applies only when MACsec replay protection active, i.e.,
+# - macsec_replay_protect is enabled
+# - the key server has decided to enable MACsec
+# 0: No replay window, strict check (default)
+# 1..2^32-1: number of packets that could be misordered
+#
+# macsec_port: IEEE 802.1X/MACsec port
+# Port component of the SCI
+# Range: 1-65534 (default: 1)
+#
+# mka_priority (Priority of MKA Actor)
+# Range: 0..255 (default: 255)
+#
+# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
+# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
+# In this mode, instances of hostapd can act as MACsec peers. The peer
+# with lower priority will become the key server and start distributing SAKs.
+# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-byte (128-bit)
+# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits)
+# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string
+# (2..64 hex-digits)
+
+##### Integrated EAP server ###################################################
+
+# Optionally, hostapd can be configured to use an integrated EAP server
+# to process EAP authentication locally without need for an external RADIUS
+# server. This functionality can be used both as a local authentication server
+# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
+
+# Use integrated EAP server instead of external RADIUS authentication
+# server. This is also needed if hostapd is configured to act as a RADIUS
+# authentication server.
+eap_server=0
+
+# Path for EAP server user database
+# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
+# to use SQLite database instead of a text file.
+#eap_user_file=/etc/hostapd.eap_user
+
+# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#ca_cert=/etc/hostapd.ca.pem
+
+# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#server_cert=/etc/hostapd.server.pem
+
+# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
+# This may point to the same file as server_cert if both certificate and key
+# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
+# used by commenting out server_cert and specifying the PFX file as the
+# private_key.
+#private_key=/etc/hostapd.server.prv
+
+# Passphrase for private key
+#private_key_passwd=secret passphrase
+
+# An alternative server certificate and private key can be configured with the
+# following parameters (with values just like the parameters above without the
+# '2' suffix). The ca_cert file (in PEM encoding) is used to add the trust roots
+# for both server certificates and/or client certificates).
+#
+# The main use case for this alternative server certificate configuration is to
+# enable both RSA and ECC public keys. The server will pick which one to use
+# based on the client preferences for the cipher suite (in the TLS ClientHello
+# message). It should be noted that number of deployed EAP peer implementations
+# do not filter out the cipher suite list based on their local configuration and
+# as such, configuration of alternative types of certificates on the server may
+# result in interoperability issues.
+#server_cert2=/etc/hostapd.server-ecc.pem
+#private_key2=/etc/hostapd.server-ecc.prv
+#private_key_passwd2=secret passphrase
+
+
+# Server identity
+# EAP methods that provide mechanism for authenticated server identity delivery
+# use this value. If not set, "hostapd" is used as a default.
+#server_id=server.example.com
+
+# Enable CRL verification.
+# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
+# valid CRL signed by the CA is required to be included in the ca_cert file.
+# This can be done by using PEM format for CA certificate and CRL and
+# concatenating these into one file. Whenever CRL changes, hostapd needs to be
+# restarted to take the new CRL into use. Alternatively, crl_reload_interval can
+# be used to configure periodic updating of the loaded CRL information.
+# 0 = do not verify CRLs (default)
+# 1 = check the CRL of the user certificate
+# 2 = check all CRLs in the certificate path
+#check_crl=1
+
+# Specify whether to ignore certificate CRL validity time mismatches with
+# errors X509_V_ERR_CRL_HAS_EXPIRED and X509_V_ERR_CRL_NOT_YET_VALID.
+#
+# 0 = ignore errors
+# 1 = do not ignore errors (default)
+#check_crl_strict=1
+
+# CRL reload interval in seconds
+# This can be used to reload ca_cert file and the included CRL on every new TLS
+# session if difference between last reload and the current reload time in
+# seconds is greater than crl_reload_interval.
+# Note: If interval time is very short, CPU overhead may be negatively affected
+# and it is advised to not go below 300 seconds.
+# This is applicable only with check_crl values 1 and 2.
+# 0 = do not reload CRLs (default)
+# crl_reload_interval = 300
+
+# If check_cert_subject is set, the value of every field will be checked
+# against the DN of the subject in the client certificate. If the values do
+# not match, the certificate verification will fail, rejecting the user.
+# This option allows hostapd to match every individual field in the right order
+# against the DN of the subject in the client certificate.
+#
+# For example, check_cert_subject=C=US/O=XX/OU=ABC/OU=XYZ/CN=1234 will check
+# every individual DN field of the subject in the client certificate. If OU=XYZ
+# comes first in terms of the order in the client certificate (DN field of
+# client certificate C=US/O=XX/OU=XYZ/OU=ABC/CN=1234), hostapd will reject the
+# client because the order of 'OU' is not matching the specified string in
+# check_cert_subject.
+#
+# This option also allows '*' as a wildcard. This option has some limitation.
+# It can only be used as per the following example.
+#
+# For example, check_cert_subject=C=US/O=XX/OU=Production* and we have two
+# clients and DN of the subject in the first client certificate is
+# (C=US/O=XX/OU=Production Unit) and DN of the subject in the second client is
+# (C=US/O=XX/OU=Production Factory). In this case, hostapd will allow both
+# clients because the value of 'OU' field in both client certificates matches
+# 'OU' value in 'check_cert_subject' up to 'wildcard'.
+#
+# * (Allow all clients, e.g., check_cert_subject=*)
+#check_cert_subject=string
+
+# TLS Session Lifetime in seconds
+# This can be used to allow TLS sessions to be cached and resumed with an
+# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
+# (default: 0 = session caching and resumption disabled)
+#tls_session_lifetime=3600
+
+# TLS flags
+# [ALLOW-SIGN-RSA-MD5] = allow MD5-based certificate signatures (depending on
+# the TLS library, these may be disabled by default to enforce stronger
+# security)
+# [DISABLE-TIME-CHECKS] = ignore certificate validity time (this requests
+# the TLS library to accept certificates even if they are not currently
+# valid, i.e., have expired or have not yet become valid; this should be
+# used only for testing purposes)
+# [DISABLE-TLSv1.0] = disable use of TLSv1.0
+# [ENABLE-TLSv1.0] = explicitly enable use of TLSv1.0 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.1] = disable use of TLSv1.1
+# [ENABLE-TLSv1.1] = explicitly enable use of TLSv1.1 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.2] = disable use of TLSv1.2
+# [ENABLE-TLSv1.2] = explicitly enable use of TLSv1.2 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.3] = disable use of TLSv1.3
+# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
+#tls_flags=[flag1][flag2]...
+
+# Maximum number of EAP message rounds with data (default: 100)
+#max_auth_rounds=100
+
+# Maximum number of short EAP message rounds (default: 50)
+#max_auth_rounds_short=50
+
+# Cached OCSP stapling response (DER encoded)
+# If set, this file is sent as a certificate status response by the EAP server
+# if the EAP peer requests certificate status in the ClientHello message.
+# This cache file can be updated, e.g., by running following command
+# periodically to get an update from the OCSP responder:
+# openssl ocsp \
+# -no_nonce \
+# -CAfile /etc/hostapd.ca.pem \
+# -issuer /etc/hostapd.ca.pem \
+# -cert /etc/hostapd.server.pem \
+# -url http://ocsp.example.com:8888/ \
+# -respout /tmp/ocsp-cache.der
+#ocsp_stapling_response=/tmp/ocsp-cache.der
+
+# Cached OCSP stapling response list (DER encoded OCSPResponseList)
+# This is similar to ocsp_stapling_response, but the extended version defined in
+# RFC 6961 to allow multiple OCSP responses to be provided.
+#ocsp_stapling_response_multi=/tmp/ocsp-multi-cache.der
+
+# dh_file: File path to DH/DSA parameters file (in PEM format)
+# This is an optional configuration file for setting parameters for an
+# ephemeral DH key exchange. In most cases, the default RSA authentication does
+# not use this configuration. However, it is possible setup RSA to use
+# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
+# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
+# is in DSA parameters format, it will be automatically converted into DH
+# params. This parameter is required if anonymous EAP-FAST is used.
+# You can generate DH parameters file with OpenSSL, e.g.,
+# "openssl dhparam -out /etc/hostapd.dh.pem 2048"
+#dh_file=/etc/hostapd.dh.pem
+
+# OpenSSL cipher string
+#
+# This is an OpenSSL specific configuration option for configuring the default
+# ciphers. If not set, the value configured at build time ("DEFAULT:!EXP:!LOW"
+# by default) is used.
+# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
+# on cipher suite configuration. This is applicable only if hostapd is built to
+# use OpenSSL.
+#openssl_ciphers=DEFAULT:!EXP:!LOW
+
+# OpenSSL ECDH curves
+#
+# This is an OpenSSL specific configuration option for configuring the ECDH
+# curves for EAP-TLS/TTLS/PEAP/FAST server. If not set, automatic curve
+# selection is enabled. If set to an empty string, ECDH curve configuration is
+# not done (the exact library behavior depends on the library version).
+# Otherwise, this is a colon separated list of the supported curves (e.g.,
+# P-521:P-384:P-256). This is applicable only if hostapd is built to use
+# OpenSSL. This must not be used for Suite B cases since the same OpenSSL
+# parameter is set differently in those cases and this might conflict with that
+# design.
+#openssl_ecdh_curves=P-521:P-384:P-256
+
+# Fragment size for EAP methods
+#fragment_size=1400
+
+# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters
+# using the IANA repository for IKE (RFC 2409).
+#pwd_group=19
+
+# Configuration data for EAP-SIM database/authentication gateway interface.
+# This is a text string in implementation specific format. The example
+# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
+# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
+# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
+# database file can be described with an optional db=<path> parameter.
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
+
+# EAP-SIM DB request timeout
+# This parameter sets the maximum time to wait for a database request response.
+# The parameter value is in seconds.
+#eap_sim_db_timeout=1
+
+# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
+# random value. It is configured as a 16-octet value in hex format. It can be
+# generated, e.g., with the following command:
+# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' '
+#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f
+
+# EAP-FAST authority identity (A-ID)
+# A-ID indicates the identity of the authority that issues PACs. The A-ID
+# should be unique across all issuing servers. In theory, this is a variable
+# length field, but due to some existing implementations requiring A-ID to be
+# 16 octets in length, it is strongly recommended to use that length for the
+# field to provide interoperability with deployed peer implementations. This
+# field is configured in hex format.
+#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
+
+# EAP-FAST authority identifier information (A-ID-Info)
+# This is a user-friendly name for the A-ID. For example, the enterprise name
+# and server name in a human-readable format. This field is encoded as UTF-8.
+#eap_fast_a_id_info=test server
+
+# Enable/disable different EAP-FAST provisioning modes:
+#0 = provisioning disabled
+#1 = only anonymous provisioning allowed
+#2 = only authenticated provisioning allowed
+#3 = both provisioning modes allowed (default)
+#eap_fast_prov=3
+
+# EAP-FAST PAC-Key lifetime in seconds (hard limit)
+#pac_key_lifetime=604800
+
+# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard
+# limit). The server will generate a new PAC-Key when this number of seconds
+# (or fewer) of the lifetime remains.
+#pac_key_refresh_time=86400
+
+# EAP-TEAP authentication type
+# 0 = inner EAP (default)
+# 1 = Basic-Password-Auth
+# 2 = Do not require Phase 2 authentication if client can be authenticated
+# during Phase 1
+#eap_teap_auth=0
+
+# EAP-TEAP authentication behavior when using PAC
+# 0 = perform inner authentication (default)
+# 1 = skip inner authentication (inner EAP/Basic-Password-Auth)
+#eap_teap_pac_no_inner=0
+
+# EAP-TEAP behavior with Result TLV
+# 0 = include with Intermediate-Result TLV (default)
+# 1 = send in a separate message (for testing purposes)
+#eap_teap_separate_result=0
+
+# EAP-TEAP identities
+# 0 = allow any identity type (default)
+# 1 = require user identity
+# 2 = require machine identity
+# 3 = request user identity; accept either user or machine identity
+# 4 = request machine identity; accept either user or machine identity
+# 5 = require both user and machine identity
+#eap_teap_id=0
+
+# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
+# (default: 0 = disabled).
+#eap_sim_aka_result_ind=1
+
+# EAP-SIM and EAP-AKA identity options
+# 0 = do not use pseudonyms or fast reauthentication
+# 1 = use pseudonyms, but not fast reauthentication
+# 2 = do not use pseudonyms, but use fast reauthentication
+# 3 = use pseudonyms and use fast reauthentication (default)
+#eap_sim_id=3
+
+# Trusted Network Connect (TNC)
+# If enabled, TNC validation will be required before the peer is allowed to
+# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
+# EAP method is enabled, the peer will be allowed to connect without TNC.
+#tnc=1
+
+# EAP Re-authentication Protocol (ERP) - RFC 6696
+#
+# Whether to enable ERP on the EAP server.
+#eap_server_erp=1
+
+
+##### RADIUS client configuration #############################################
+# for IEEE 802.1X with external Authentication Server, IEEE 802.11
+# authentication with external ACL for MAC addresses, and accounting
+
+# The own IP address of the access point (used as NAS-IP-Address)
+own_ip_addr=127.0.0.1
+
+# NAS-Identifier string for RADIUS messages. When used, this should be unique
+# to the NAS within the scope of the RADIUS server. Please note that hostapd
+# uses a separate RADIUS client for each BSS and as such, a unique
+# nas_identifier value should be configured separately for each BSS. This is
+# particularly important for cases where RADIUS accounting is used
+# (Accounting-On/Off messages are interpreted as clearing all ongoing sessions
+# and that may get interpreted as applying to all BSSes if the same
+# NAS-Identifier value is used.) For example, a fully qualified domain name
+# prefixed with a unique identifier of the BSS (e.g., BSSID) can be used here.
+#
+# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
+# 48 octets long.
+#
+# It is mandatory to configure either own_ip_addr or nas_identifier to be
+# compliant with the RADIUS protocol. When using RADIUS accounting, it is
+# strongly recommended that nas_identifier is set to a unique value for each
+# BSS.
+#nas_identifier=ap.example.com
+
+# RADIUS client forced local IP address for the access point
+# Normally the local IP address is determined automatically based on configured
+# IP addresses, but this field can be used to force a specific address to be
+# used, e.g., when the device has multiple IP addresses.
+#radius_client_addr=127.0.0.1
+
+# RADIUS client forced local interface. Helps run properly with VRF
+# Default is none set which allows the network stack to pick the appropriate
+# interface automatically.
+# Example below binds to eth0
+#radius_client_dev=eth0
+
+# RADIUS authentication server
+#auth_server_addr=127.0.0.1
+#auth_server_port=1812
+#auth_server_shared_secret=secret
+
+# RADIUS accounting server
+#acct_server_addr=127.0.0.1
+#acct_server_port=1813
+#acct_server_shared_secret=secret
+
+# Secondary RADIUS servers; to be used if primary one does not reply to
+# RADIUS packets. These are optional and there can be more than one secondary
+# server listed.
+#auth_server_addr=127.0.0.2
+#auth_server_port=1812
+#auth_server_shared_secret=secret2
+#
+#acct_server_addr=127.0.0.2
+#acct_server_port=1813
+#acct_server_shared_secret=secret2
+
+# Retry interval for trying to return to the primary RADIUS server (in
+# seconds). RADIUS client code will automatically try to use the next server
+# when the current server is not replying to requests. If this interval is set,
+# primary server will be retried after configured amount of time even if the
+# currently used secondary server is still working.
+#radius_retry_primary_interval=600
+
+
+# Interim accounting update interval
+# If this is set (larger than 0) and acct_server is configured, hostapd will
+# send interim accounting updates every N seconds. Note: if set, this overrides
+# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this
+# value should not be configured in hostapd.conf, if RADIUS server is used to
+# control the interim interval.
+# This value should not be less 600 (10 minutes) and must not be less than
+# 60 (1 minute).
+#radius_acct_interim_interval=600
+
+# Request Chargeable-User-Identity (RFC 4372)
+# This parameter can be used to configure hostapd to request CUI from the
+# RADIUS server by including Chargeable-User-Identity attribute into
+# Access-Request packets.
+#radius_request_cui=1
+
+# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
+# is used for the stations. This information is parsed from following RADIUS
+# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
+# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
+# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
+# be used to set static client MAC address to VLAN ID mapping.
+# Dynamic VLAN mode is also used with VLAN ID assignment based on WPA/WPA2
+# passphrase from wpa_psk_file or vlan_id parameter from sae_password.
+# 0 = disabled (default); only VLAN IDs from accept_mac_file will be used
+# 1 = optional; use default interface if RADIUS server does not include VLAN ID
+# 2 = required; reject authentication if RADIUS server does not include VLAN ID
+#dynamic_vlan=0
+
+# Per-Station AP_VLAN interface mode
+# If enabled, each station is assigned its own AP_VLAN interface.
+# This implies per-station group keying and ebtables filtering of inter-STA
+# traffic (when passed through the AP).
+# If the sta is not assigned to any VLAN, then its AP_VLAN interface will be
+# added to the bridge given by the "bridge" configuration option (see above).
+# Otherwise, it will be added to the per-VLAN bridge.
+# 0 = disabled (default)
+# 1 = enabled
+#per_sta_vif=0
+
+# VLAN interface list for dynamic VLAN mode is read from a separate text file.
+# This list is used to map VLAN ID from the RADIUS server to a network
+# interface. Each station is bound to one interface in the same way as with
+# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
+# interface and the line must include VLAN ID and interface name separated by
+# white space (space or tab).
+# If no entries are provided by this file, the station is statically mapped
+# to <bss-iface>.<vlan-id> interfaces.
+# Each line can optionally also contain the name of a bridge to add the VLAN to
+#vlan_file=/etc/hostapd.vlan
+
+# Interface where 802.1q tagged packets should appear when a RADIUS server is
+# used to determine which VLAN a station is on. hostapd creates a bridge for
+# each VLAN. Then hostapd adds a VLAN interface (associated with the interface
+# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
+# to the bridge.
+#vlan_tagged_interface=eth0
+
+# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
+# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
+# and br%s.%d if a tagged interface is given, provided %s = tagged interface
+# and %d = VLAN ID.
+#vlan_bridge=brvlan
+
+# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
+# to know how to name it.
+# 0 = vlan<XXX>, e.g., vlan1
+# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1
+#vlan_naming=0
+
+# Arbitrary RADIUS attributes can be added into Access-Request and
+# Accounting-Request packets by specifying the contents of the attributes with
+# the following configuration parameters. There can be multiple of these to
+# add multiple attributes. These parameters can also be used to override some
+# of the attributes added automatically by hostapd.
+# Format: <attr_id>[:<syntax:value>]
+# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
+# syntax: s = string (UTF-8), d = integer, x = octet string
+# value: attribute value in format indicated by the syntax
+# If syntax and value parts are omitted, a null value (single 0x00 octet) is
+# used.
+#
+# Additional Access-Request attributes
+# radius_auth_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_auth_req_attr=126:s:Operator
+# Service-Type = Framed (2)
+#radius_auth_req_attr=6:d:2
+# Connect-Info = "testing" (this overrides the automatically generated value)
+#radius_auth_req_attr=77:s:testing
+# Same Connect-Info value set as a hexdump
+#radius_auth_req_attr=77:x:74657374696e67
+
+#
+# Additional Accounting-Request attributes
+# radius_acct_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_acct_req_attr=126:s:Operator
+
+# If SQLite support is included, path to a database from which additional
+# RADIUS request attributes are extracted based on the station MAC address.
+#
+# The schema for the radius_attributes table is:
+# id | sta | reqtype | attr : multi-key (sta, reqtype)
+# id = autonumber
+# sta = station MAC address in `11:22:33:44:55:66` format.
+# type = `auth` | `acct` | NULL (match any)
+# attr = existing config file format, e.g. `126:s:Test Operator`
+#radius_req_attr_sqlite=radius_attr.sqlite
+
+# Dynamic Authorization Extensions (RFC 5176)
+# This mechanism can be used to allow dynamic changes to user session based on
+# commands from a RADIUS server (or some other disconnect client that has the
+# needed session information). For example, Disconnect message can be used to
+# request an associated station to be disconnected.
+#
+# This is disabled by default. Set radius_das_port to non-zero UDP port
+# number to enable.
+#radius_das_port=3799
+#
+# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+# Format: <IP address> <shared secret>
+# IP address 0.0.0.0 can be used to allow requests from any address.
+#radius_das_client=192.168.1.123 shared secret here
+#
+# DAS Event-Timestamp time window in seconds
+#radius_das_time_window=300
+#
+# DAS require Event-Timestamp
+#radius_das_require_event_timestamp=1
+#
+# DAS require Message-Authenticator
+#radius_das_require_message_authenticator=1
+
+##### RADIUS authentication server configuration ##############################
+
+# hostapd can be used as a RADIUS authentication server for other hosts. This
+# requires that the integrated EAP server is also enabled and both
+# authentication services are sharing the same configuration.
+
+# File name of the RADIUS clients configuration for the RADIUS server. If this
+# commented out, RADIUS server is disabled.
+#radius_server_clients=/etc/hostapd.radius_clients
+
+# The UDP port number for the RADIUS authentication server
+#radius_server_auth_port=1812
+
+# The UDP port number for the RADIUS accounting server
+# Commenting this out or setting this to 0 can be used to disable RADIUS
+# accounting while still enabling RADIUS authentication.
+#radius_server_acct_port=1813
+
+# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
+#radius_server_ipv6=1
+
+
+##### WPA/IEEE 802.11i configuration ##########################################
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
+# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2.
+# In other words, for WPA3, wpa=2 is used the configuration (and
+# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
+#wpa=2
+
+# Extended Key ID support for Individually Addressed frames
+#
+# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
+# PTK rekeying with only a single Key ID 0 has. It can only be used when the
+# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
+#
+# 0 = force off, i.e., use only Key ID 0 (default)
+# 1 = enable and use Extended Key ID support when possible
+# 2 = identical to 1 but start with Key ID 1 when possible
+#extended_key_id=0
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+# wpa_psk (dot11RSNAConfigPSKValue)
+# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Optionally, WPA PSKs can be read from a separate text file (containing list
+# of (PSK,MAC address) pairs. This allows more than one PSK to be configured.
+# Use absolute path name to make sure that the files can be read on SIGHUP
+# configuration reloads.
+#wpa_psk_file=/etc/hostapd.wpa_psk
+
+# Optionally, WPA passphrase can be received from RADIUS authentication server
+# This requires macaddr_acl to be set to 2 (RADIUS)
+# 0 = disabled (default)
+# 1 = optional; use default passphrase/psk if RADIUS server does not include
+# Tunnel-Password
+# 2 = required; reject authentication if RADIUS server does not include
+# Tunnel-Password
+#wpa_psk_radius=0
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
+# added to enable SHA256-based stronger algorithms.
+# WPA-PSK = WPA-Personal / WPA2-Personal
+# WPA-PSK-SHA256 = WPA2-Personal using SHA256
+# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
+# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
+# SAE = SAE (WPA3-Personal)
+# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
+# FT-PSK = FT with passphrase/PSK
+# FT-EAP = FT with EAP
+# FT-EAP-SHA384 = FT with EAP using SHA384
+# FT-SAE = FT with SAE
+# FILS-SHA256 = Fast Initial Link Setup with SHA256
+# FILS-SHA384 = Fast Initial Link Setup with SHA384
+# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
+# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
+# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
+# DPP = Device Provisioning Protocol
+# OSEN = Hotspot 2.0 online signup with encryption
+# (dot11RSNAConfigAuthenticationSuitesTable)
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC (CCMP-128)
+# TKIP = Temporal Key Integrity Protocol
+# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key
+# GCMP = Galois/counter mode protocol (GCMP-128)
+# GCMP-256 = Galois/counter mode protocol with 256-bit key
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher. The optional group_cipher parameter can
+# be used to override this automatic selection.
+#
+# (dot11RSNAConfigPairwiseCiphersTable)
+# Pairwise cipher for WPA (v1) (default: TKIP)
+#wpa_pairwise=TKIP CCMP
+# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
+#rsn_pairwise=CCMP
+
+# Optional override for automatic group cipher selection
+# This can be used to select a specific group cipher regardless of which
+# pairwise ciphers were enabled for WPA and RSN. It should be noted that
+# overriding the group cipher with an unexpected value can result in
+# interoperability issues and in general, this parameter is mainly used for
+# testing purposes.
+#group_cipher=CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds. (dot11RSNAConfigGroupRekeyTime)
+# This defaults to 86400 seconds (once per day) when using CCMP/GCMP as the
+# group cipher and 600 seconds (once per 10 minutes) when using TKIP as the
+# group cipher.
+#wpa_group_rekey=86400
+
+# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
+# (dot11RSNAConfigGroupRekeyStrict)
+#wpa_strict_rekey=1
+
+# The number of times EAPOL-Key Message 1/2 in the RSN Group Key Handshake is
+#retried per GTK Handshake attempt. (dot11RSNAConfigGroupUpdateCount)
+# This value should only be increased when stations are constantly
+# deauthenticated during GTK rekeying with the log message
+# "group key handshake failed...".
+# You should consider to also increase wpa_pairwise_update_count then.
+# Range 1..4294967295; default: 4
+#wpa_group_update_count=4
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
+# PTK to mitigate some attacks against TKIP deficiencies.
+# Warning: PTK rekeying is buggy with many drivers/devices and with such
+# devices, the only secure method to rekey the PTK without Extended Key ID
+# support requires a disconnection. Check the related parameter
+# wpa_deny_ptk0_rekey for details.
+#wpa_ptk_rekey=600
+
+# Workaround for PTK rekey issues
+#
+# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually
+# Addressed Frames") can degrade the security and stability with some cards.
+# To avoid such issues hostapd can replace those PTK rekeys (including EAP
+# reauthentications) with disconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+# this operation without issues
+# 2 = never allow PTK0 rekeys
+#wpa_deny_ptk0_rekey=0
+
+# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
+# Handshake are retried per 4-Way Handshake attempt.
+# (dot11RSNAConfigPairwiseUpdateCount)
+# Range 1..4294967295; default: 4
+#wpa_pairwise_update_count=4
+
+# Workaround for key reinstallation attacks
+#
+# This parameter can be used to disable retransmission of EAPOL-Key frames that
+# are used to install keys (EAPOL-Key message 3/4 and group message 1/2). This
+# is similar to setting wpa_group_update_count=1 and
+# wpa_pairwise_update_count=1, but with no impact to message 1/4 and with
+# extended timeout on the response to avoid causing issues with stations that
+# may use aggressive power saving have very long time in replying to the
+# EAPOL-Key messages.
+#
+# This option can be used to work around key reinstallation attacks on the
+# station (supplicant) side in cases those station devices cannot be updated
+# for some reason. By removing the retransmissions the attacker cannot cause
+# key reinstallation with a delayed frame transmission. This is related to the
+# station side vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079,
+# CVE-2017-13080, and CVE-2017-13081.
+#
+# This workaround might cause interoperability issues and reduced robustness of
+# key negotiation especially in environments with heavy traffic load due to the
+# number of attempts to perform the key exchange is reduced significantly. As
+# such, this workaround is disabled by default (unless overridden in build
+# configuration). To enable this, set the parameter to 1.
+#wpa_disable_eapol_key_retries=1
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+# (dot11RSNAPreauthenticationEnabled)
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
+
+# ieee80211w: Whether management frame protection (MFP) is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+#ieee80211w=0
+# The most common configuration options for this based on the PMF (protected
+# management frames) certification program are:
+# PMF enabled: ieee80211w=1 and wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256
+# PMF required: ieee80211w=2 and wpa_key_mgmt=WPA-EAP-SHA256
+# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
+# WPA3-Personal-only mode: ieee80211w=2 and wpa_key_mgmt=SAE
+
+# Group management cipher suite
+# Default: AES-128-CMAC (BIP)
+# Other options (depending on driver support):
+# BIP-GMAC-128
+# BIP-GMAC-256
+# BIP-CMAC-256
+# Note: All the stations connecting to the BSS will also need to support the
+# selected cipher. The default AES-128-CMAC is the only option that is commonly
+# available in deployed devices.
+#group_mgmt_cipher=AES-128-CMAC
+
+# Beacon Protection (management frame protection for Beacon frames)
+# This depends on management frame protection being enabled (ieee80211w != 0)
+# and beacon protection support indication from the driver.
+# 0 = disabled (default)
+# 1 = enabled
+#beacon_prot=0
+
+# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
+# (maximum time to wait for a SA Query response)
+# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
+#assoc_sa_query_max_timeout=1000
+
+# Association SA Query retry timeout (in TU = 1.024 ms; for MFP)
+# (time between two subsequent SA Query requests)
+# dot11AssociationSAQueryRetryTimeout, 1...4294967295
+#assoc_sa_query_retry_timeout=201
+
+# ocv: Operating Channel Validation
+# This is a countermeasure against multi-channel on-path attacks.
+# Enabling this depends on the driver's support for OCV when the driver SME is
+# used. If hostapd SME is used, this will be enabled just based on this
+# configuration.
+# Enabling this automatically also enables ieee80211w, if not yet enabled.
+# 0 = disabled (default)
+# 1 = enabled
+# 2 = enabled in workaround mode - Allow STA that claims OCV capability to
+# connect even if the STA doesn't send OCI or negotiate PMF. This
+# workaround is to improve interoperability with legacy STAs which are
+# wrongly copying reserved bits of RSN capabilities from the AP's
+# RSNE into (Re)Association Request frames. When this configuration is
+# enabled, the AP considers STA is OCV capable only when the STA indicates
+# MFP capability in (Re)Association Request frames and sends OCI in
+# EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association
+# Request frame; otherwise, the AP disables OCV for the current connection
+# with the STA. Enabling this workaround mode reduced OCV protection to
+# some extend since it allows misbehavior to go through. As such, this
+# should be enabled only if interoperability with misbehaving STAs is
+# needed.
+#ocv=1
+
+# disable_pmksa_caching: Disable PMKSA caching
+# This parameter can be used to disable caching of PMKSA created through EAP
+# authentication. RSN preauthentication may still end up using PMKSA caching if
+# it is enabled (rsn_preauth=1).
+# 0 = PMKSA caching enabled (default)
+# 1 = PMKSA caching disabled
+#disable_pmksa_caching=0
+
+# okc: Opportunistic Key Caching (aka Proactive Key Caching)
+# Allow PMK cache to be shared opportunistically among configured interfaces
+# and BSSes (i.e., all configurations within a single hostapd process).
+# 0 = disabled (default)
+# 1 = enabled
+#okc=1
+
+# SAE password
+# This parameter can be used to set passwords for SAE. By default, the
+# wpa_passphrase value is used if this separate parameter is not used, but
+# wpa_passphrase follows the WPA-PSK constraints (8..63 characters) even though
+# SAE passwords do not have such constraints. If the BSS enabled both SAE and
+# WPA-PSK and both values are set, SAE uses the sae_password values and WPA-PSK
+# uses the wpa_passphrase value.
+#
+# Each sae_password entry is added to a list of available passwords. This
+# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value
+# starts with the password (dot11RSNAConfigPasswordCredential). That value can
+# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
+# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
+# addition, an optional VLAN ID specification can be used to bind the station
+# to the specified VLAN whenever the specific SAE password entry is used.
+#
+# If the peer MAC address is not included or is set to the wildcard address
+# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
+# specific peer MAC address is included, only a station with that MAC address
+# is allowed to use the entry.
+#
+# If the password identifier (with non-zero length) is included, the entry is
+# limited to be used only with that specified identifier.
+
+# The last matching (based on peer MAC address and identifier) entry is used to
+# select which password to use. Setting sae_password to an empty string has a
+# special meaning of removing all previously added entries.
+#
+# sae_password uses the following encoding:
+#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>]
+#[|pk=<m:ECPrivateKey-base64>][|id=<identifier>]
+# Examples:
+#sae_password=secret
+#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
+#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier
+#sae_password=example secret|vlanid=3|id=pw identifier
+
+# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
+# This parameter defines how many open SAE instances can be in progress at the
+# same time before the anti-clogging mechanism is taken into use.
+#sae_anti_clogging_threshold=5 (deprecated)
+#anti_clogging_threshold=5
+
+# Maximum number of SAE synchronization errors (dot11RSNASAESync)
+# The offending SAE peer will be disconnected if more than this many
+# synchronization errors happen.
+#sae_sync=5
+
+# Enabled SAE finite cyclic groups
+# SAE implementation are required to support group 19 (ECC group defined over a
+# 256-bit prime order field). This configuration parameter can be used to
+# specify a set of allowed groups. If not included, only the mandatory group 19
+# is enabled.
+# The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+# Note that groups 1, 2, 5, 22, 23, and 24 should not be used in production
+# purposes due limited security (see RFC 8247). Groups that are not as strong as
+# group 19 (ECC, NIST P-256) are unlikely to be useful for production use cases
+# since all implementations are required to support group 19.
+#sae_groups=19 20 21
+
+# Require MFP for all associations using SAE
+# This parameter can be used to enforce negotiation of MFP for all associations
+# that negotiate use of SAE. This is used in cases where SAE-capable devices are
+# known to be MFP-capable and the BSS is configured with optional MFP
+# (ieee80211w=1) for legacy support. The non-SAE stations can connect without
+# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
+#sae_require_mfp=0
+
+# SAE Confirm behavior
+# By default, AP will send out only SAE Commit message in response to a received
+# SAE Commit message. This parameter can be set to 1 to override that behavior
+# to send both SAE Commit and SAE Confirm messages without waiting for the STA
+# to send its SAE Confirm message first.
+#sae_confirm_immediate=0
+
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
+#sae_pwe=0
+
+# FILS Cache Identifier (16-bit value in hexdump format)
+#fils_cache_id=0011
+
+# FILS Realm Information
+# One or more FILS realms need to be configured when FILS is enabled. This list
+# of realms is used to define which realms (used in keyName-NAI by the client)
+# can be used with FILS shared key authentication for ERP.
+#fils_realm=example.com
+#fils_realm=example.org
+
+# FILS DH Group for PFS
+# 0 = PFS disabled with FILS shared key authentication (default)
+# 1-65535 DH Group to use for FILS PFS
+#fils_dh_group=0
+
+# OWE DH groups
+# OWE implementations are required to support group 19 (NIST P-256). All groups
+# that are supported by the implementation (e.g., groups 19, 20, and 21 when
+# using OpenSSL) are enabled by default. This configuration parameter can be
+# used to specify a limited set of allowed groups. The group values are listed
+# in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
+#owe_groups=19 20 21
+
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all OWE
+# groups. This was supposed to change to SHA384 for group 20 and SHA512 for
+# group 21. This parameter can be used to enable workaround for interoperability
+# with stations that use SHA256 with groups 20 and 21. By default (0) only the
+# appropriate hash function is accepted. When workaround is enabled (1), the
+# appropriate hash function is tried first and if that fails, SHA256-based PTK
+# derivation is attempted. This workaround can result in reduced security for
+# groups 20 and 21, but is required for interoperability with older
+# implementations. There is no impact to group 19 behavior. The workaround is
+# disabled by default and can be enabled by uncommenting the following line.
+#owe_ptk_workaround=1
+
+# OWE transition mode configuration
+# Pointer to the matching open/OWE BSS
+#owe_transition_bssid=<bssid>
+# SSID in same format as ssid2 described above.
+#owe_transition_ssid=<SSID>
+# Alternatively, OWE transition mode BSSID/SSID can be configured with a
+# reference to a BSS operated by this hostapd process.
+#owe_transition_ifname=<ifname>
+
+# DHCP server for FILS HLP
+# If configured, hostapd will act as a DHCP relay for all FILS HLP requests
+# that include a DHCPDISCOVER message and send them to the specific DHCP
+# server for processing. hostapd will then wait for a response from that server
+# before replying with (Re)Association Response frame that encapsulates this
+# DHCP response. own_ip_addr is used as the local address for the communication
+# with the DHCP server.
+#dhcp_server=127.0.0.1
+
+# DHCP server UDP port
+# Default: 67
+#dhcp_server_port=67
+
+# DHCP relay UDP port on the local device
+# Default: 67; 0 means not to bind any specific port
+#dhcp_relay_port=67
+
+# DHCP rapid commit proxy
+# If set to 1, this enables hostapd to act as a DHCP rapid commit proxy to
+# allow the rapid commit options (two message DHCP exchange) to be used with a
+# server that supports only the four message DHCP exchange. This is disabled by
+# default (= 0) and can be enabled by setting this to 1.
+#dhcp_rapid_commit_proxy=0
+
+# Wait time for FILS HLP (dot11HLPWaitTime) in TUs
+# default: 30 TUs (= 30.72 milliseconds)
+#fils_hlp_wait_time=30
+
+# FILS Discovery frame transmission minimum and maximum interval settings.
+# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery
+# frame transmission. These values use TUs as the unit and have allowed range
+# of 0-10000. fils_discovery_min_interval defaults to 20.
+#fils_discovery_min_interval=20
+#fils_discovery_max_interval=0
+
+# Transition Disable indication
+# The AP can notify authenticated stations to disable transition mode in their
+# network profiles when the network has completed transition steps, i.e., once
+# sufficiently large number of APs in the ESS have been updated to support the
+# more secure alternative. When this indication is used, the stations are
+# expected to automatically disable transition mode and less secure security
+# options. This includes use of WEP, TKIP (including use of TKIP as the group
+# cipher), and connections without PMF.
+# Bitmap bits:
+# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only
+# allow SAE to be used)
+# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE)
+# (default: 0 = do not include Transition Disable KDE)
+#transition_disable=0x01
+
+# PASN ECDH groups
+# PASN implementations are required to support group 19 (NIST P-256). If this
+# parameter is not set, only group 19 is supported by default. This
+# configuration parameter can be used to specify a limited set of allowed
+# groups. The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
+#pasn_groups=19 20 21
+
+# PASN comeback after time in TUs
+# In case the AP is temporarily unable to handle a PASN authentication exchange
+# due to a too large number of parallel operations, this value indicates to the
+# peer after how many TUs it can try the PASN exchange again.
+# (default: 10 TUs)
+#pasn_comeback_after=10
+
+##### IEEE 802.11r configuration ##############################################
+
+# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
+# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the
+# same SSID) between which a STA can use Fast BSS Transition.
+# 2-octet identifier as a hex string.
+#mobility_domain=a1b2
+
+# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID)
+# 1 to 48 octet identifier.
+# This is configured with nas_identifier (see RADIUS client section above).
+
+# Default lifetime of the PMK-R0 in seconds; range 60..4294967295
+# (default: 14 days / 1209600 seconds; 0 = disable timeout)
+# (dot11FTR0KeyLifetime)
+#ft_r0_key_lifetime=1209600
+
+# Maximum lifetime for PMK-R1; applied only if not zero
+# PMK-R1 is removed at latest after this limit.
+# Removing any PMK-R1 for expiry can be disabled by setting this to -1.
+# (default: 0)
+#r1_max_key_lifetime=0
+
+# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
+# 6-octet identifier as a hex string.
+# Defaults to BSSID.
+#r1_key_holder=000102030405
+
+# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
+# (dot11FTReassociationDeadline)
+#reassociation_deadline=1000
+
+# List of R0KHs in the same Mobility Domain
+# format: <MAC address> <NAS Identifier> <256-bit key as hex string>
+# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
+# address when requesting PMK-R1 key from the R0KH that the STA used during the
+# Initial Mobility Domain Association.
+#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
+#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
+# And so on.. One line per R0KH.
+# Wildcard entry:
+# Upon receiving a response from R0KH, it will be added to this list, so
+# subsequent requests won't be broadcast. If R0KH does not reply, it will be
+# temporarily blocked (see rkh_neg_timeout).
+#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
+
+# List of R1KHs in the same Mobility Domain
+# format: <MAC address> <R1KH-ID> <256-bit key as hex string>
+# This list is used to map R1KH-ID to a destination MAC address when sending
+# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
+# that can request PMK-R1 keys.
+#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
+#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
+# And so on.. One line per R1KH.
+# Wildcard entry:
+# Upon receiving a request from an R1KH not yet known, it will be added to this
+# list and thus will receive push notifications.
+#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff
+
+# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above)
+# Special values: 0 -> do not expire
+# Warning: do not cache implies no sequence number validation with wildcards
+#rkh_pos_timeout=86400 (default = 1 day)
+
+# Timeout (milliseconds) for requesting PMK-R1 from R0KH using PULL request
+# and number of retries.
+#rkh_pull_timeout=1000 (default = 1 second)
+#rkh_pull_retries=4 (default)
+
+# Timeout (seconds) for non replying R0KH (see wildcard entries above)
+# Special values: 0 -> do not cache
+# default: 60 seconds
+#rkh_neg_timeout=60
+
+# Note: The R0KH/R1KH keys used to be 128-bit in length before the message
+# format was changed. That shorter key length is still supported for backwards
+# compatibility of the configuration files. If such a shorter key is used, a
+# 256-bit key is derived from it. For new deployments, configuring the 256-bit
+# key is recommended.
+
+# Whether PMK-R1 push is enabled at R0KH
+# 0 = do not push PMK-R1 to all configured R1KHs (default)
+# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
+#pmk_r1_push=1
+
+# Whether to enable FT-over-DS
+# 0 = FT-over-DS disabled
+# 1 = FT-over-DS enabled (default)
+#ft_over_ds=1
+
+# Whether to generate FT response locally for PSK networks
+# This avoids use of PMK-R1 push/pull from other APs with FT-PSK networks as
+# the required information (PSK and other session data) is already locally
+# available.
+# 0 = disabled (default)
+# 1 = enabled
+#ft_psk_generate_local=0
+
+##### Neighbor table ##########################################################
+# Maximum number of entries kept in AP table (either for neighbor table or for
+# detecting Overlapping Legacy BSS Condition). The oldest entry will be
+# removed when adding a new entry that would make the list grow over this
+# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
+# enabled, so this field should not be set to 0 when using IEEE 802.11g.
+# default: 255
+#ap_table_max_size=255
+
+# Number of seconds of no frames received after which entries may be deleted
+# from the AP table. Since passive scanning is not usually performed frequently
+# this should not be set to very small value. In addition, there is no
+# guarantee that every scan cycle will receive beacon frames from the
+# neighboring APs.
+# default: 60
+#ap_table_expiration_time=3600
+
+# Maximum number of stations to track on the operating channel
+# This can be used to detect dualband capable stations before they have
+# associated, e.g., to provide guidance on which colocated BSS to use.
+# Default: 0 (disabled)
+#track_sta_max_num=100
+
+# Maximum age of a station tracking entry in seconds
+# Default: 180
+#track_sta_max_age=180
+
+# Do not reply to group-addressed Probe Request from a station that was seen on
+# another radio.
+# Default: Disabled
+#
+# This can be used with enabled track_sta_max_num configuration on another
+# interface controlled by the same hostapd process to restrict Probe Request
+# frame handling from replying to group-addressed Probe Request frames from a
+# station that has been detected to be capable of operating on another band,
+# e.g., to try to reduce likelihood of the station selecting a 2.4 GHz BSS when
+# the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
+#
+# Note: Enabling this can cause connectivity issues and increase latency for
+# discovering the AP.
+#no_probe_resp_if_seen_on=wlan1
+
+# Reject authentication from a station that was seen on another radio.
+# Default: Disabled
+#
+# This can be used with enabled track_sta_max_num configuration on another
+# interface controlled by the same hostapd process to reject authentication
+# attempts from a station that has been detected to be capable of operating on
+# another band, e.g., to try to reduce likelihood of the station selecting a
+# 2.4 GHz BSS when the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
+#
+# Note: Enabling this can cause connectivity issues and increase latency for
+# connecting with the AP.
+#no_auth_if_seen_on=wlan1
+
+##### Wi-Fi Protected Setup (WPS) #############################################
+
+# WPS state
+# 0 = WPS disabled (default)
+# 1 = WPS enabled, not configured
+# 2 = WPS enabled, configured
+#wps_state=2
+
+# Whether to manage this interface independently from other WPS interfaces
+# By default, a single hostapd process applies WPS operations to all configured
+# interfaces. This parameter can be used to disable that behavior for a subset
+# of interfaces. If this is set to non-zero for an interface, WPS commands
+# issued on that interface do not apply to other interfaces and WPS operations
+# performed on other interfaces do not affect this interface.
+#wps_independent=0
+
+# AP can be configured into a locked state where new WPS Registrar are not
+# accepted, but previously authorized Registrars (including the internal one)
+# can continue to add new Enrollees.
+#ap_setup_locked=1
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# This value is used as the UUID for the internal WPS Registrar. If the AP
+# is also using UPnP, this value should be set to the device's UPnP UUID.
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs
+# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the
+# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of
+# per-device PSKs is recommended as the more secure option (i.e., make sure to
+# set wpa_psk_file when using WPS with WPA-PSK).
+
+# When an Enrollee requests access to the network with PIN method, the Enrollee
+# PIN will need to be entered for the Registrar. PIN request notifications are
+# sent to hostapd ctrl_iface monitor. In addition, they can be written to a
+# text file that could be used, e.g., to populate the AP administration UI with
+# pending PIN requests. If the following variable is set, the PIN requests will
+# be written to the configured file.
+#wps_pin_requests=/var/run/hostapd_wps_pin_requests
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless AP
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=WAP
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+# default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+# 1-0050F204-1 (Computer / PC)
+# 1-0050F204-2 (Computer / Server)
+# 5-0050F204-1 (Storage / NAS)
+# 6-0050F204-1 (Network Infrastructure / AP)
+#device_type=6-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
+# Config Methods
+# List of the supported configuration methods
+# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
+# nfc_interface push_button keypad virtual_display physical_display
+# virtual_push_button physical_push_button
+#config_methods=label virtual_display virtual_push_button keypad
+
+# WPS capability discovery workaround for PBC with Windows 7
+# Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting
+# as a Registrar and using M1 from the AP. The config methods attribute in that
+# message is supposed to indicate only the configuration method supported by
+# the AP in Enrollee role, i.e., to add an external Registrar. For that case,
+# PBC shall not be used and as such, the PushButton config method is removed
+# from M1 by default. If pbc_in_m1=1 is included in the configuration file,
+# the PushButton config method is left in M1 (if included in config_methods
+# parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label
+# in the AP).
+#pbc_in_m1=1
+
+# Static access point PIN for initial configuration and adding Registrars
+# If not set, hostapd will not allow external WPS Registrars to control the
+# access point. The AP PIN can also be set at runtime with hostapd_cli
+# wps_ap_pin command. Use of temporary (enabled by user action) and random
+# AP PIN is much more secure than configuring a static AP PIN here. As such,
+# use of the ap_pin parameter is not recommended if the AP device has means for
+# displaying a random PIN.
+#ap_pin=12345670
+
+# Skip building of automatic WPS credential
+# This can be used to allow the automatically generated Credential attribute to
+# be replaced with pre-configured Credential(s).
+#skip_cred_build=1
+
+# Additional Credential attribute(s)
+# This option can be used to add pre-configured Credential attributes into M8
+# message when acting as a Registrar. If skip_cred_build=1, this data will also
+# be able to override the Credential attribute that would have otherwise been
+# automatically generated based on network configuration. This configuration
+# option points to an external file that much contain the WPS Credential
+# attribute(s) as binary data.
+#extra_cred=hostapd.cred
+
+# Credential processing
+# 0 = process received credentials internally (default)
+# 1 = do not process received credentials; just pass them over ctrl_iface to
+# external program(s)
+# 2 = process received credentials internally and pass them over ctrl_iface
+# to external program(s)
+# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and
+# extra_cred be used to provide the Credential data for Enrollees.
+#
+# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file
+# both for Credential processing and for marking AP Setup Locked based on
+# validation failures of AP PIN. An external program is responsible on updating
+# the configuration appropriately in this case.
+#wps_cred_processing=0
+
+# Whether to enable SAE (WPA3-Personal transition mode) automatically for
+# WPA2-PSK credentials received using WPS.
+# 0 = only add the explicitly listed WPA2-PSK configuration (default)
+# 1 = add both the WPA2-PSK and SAE configuration and enable PMF so that the
+# AP gets configured in WPA3-Personal transition mode (supports both
+# WPA2-Personal (PSK) and WPA3-Personal (SAE) clients).
+#wps_cred_add_sae=0
+
+# AP Settings Attributes for M7
+# By default, hostapd generates the AP Settings Attributes for M7 based on the
+# current configuration. It is possible to override this by providing a file
+# with pre-configured attributes. This is similar to extra_cred file format,
+# but the AP Settings attributes are not encapsulated in a Credential
+# attribute.
+#ap_settings=hostapd.ap_settings
+
+# Multi-AP backhaul BSS config
+# Used in WPS when multi_ap=2 or 3. Defines "backhaul BSS" credentials.
+# These are passed in WPS M8 instead of the normal (fronthaul) credentials
+# if the Enrollee has the Multi-AP subelement set. Backhaul SSID is formatted
+# like ssid2. The key is set like wpa_psk or wpa_passphrase.
+#multi_ap_backhaul_ssid="backhaul"
+#multi_ap_backhaul_wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#multi_ap_backhaul_wpa_passphrase=secret passphrase
+
+# WPS UPnP interface
+# If set, support for external Registrars is enabled.
+#upnp_iface=br0
+
+# Friendly Name (required for UPnP)
+# Short description for end use. Should be less than 64 characters.
+#friendly_name=WPS Access Point
+
+# Manufacturer URL (optional for UPnP)
+#manufacturer_url=http://www.example.com/
+
+# Model Description (recommended for UPnP)
+# Long description for end user. Should be less than 128 characters.
+#model_description=Wireless Access Point
+
+# Model URL (optional for UPnP)
+#model_url=http://www.example.com/model/
+
+# Universal Product Code (optional for UPnP)
+# 12-digit, all-numeric code that identifies the consumer package.
+#upc=123456789012
+
+# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band, ad = 60 GHz)
+# This value should be set according to RF band(s) supported by the AP if
+# hw_mode is not set. For dual band dual concurrent devices, this needs to be
+# set to ag to allow both RF bands to be advertized.
+#wps_rf_bands=ag
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When
+# these parameters are used, the AP is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
+# Application Extension attribute for Beacon and Probe Response frames
+# This parameter can be used to add application extension into WPS IE. The
+# contents of this parameter starts with 16-octet (32 hexdump characters) of
+# UUID to identify the specific application and that is followed by the actual
+# application specific data.
+#wps_application_ext=<hexdump>
+
+##### Wi-Fi Direct (P2P) ######################################################
+
+# Enable P2P Device management
+#manage_p2p=1
+
+# Allow cross connection
+#allow_cross_connection=1
+
+##### Device Provisioning Protocol (DPP) ######################################
+
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
+#dpp_connector
+#dpp_netaccesskey
+#dpp_netaccesskey_expiry
+#dpp_csign
+#dpp_controller
+
+# Configurator Connectivity indication
+# 0: no Configurator is currently connected (default)
+# 1: advertise that a Configurator is available
+#dpp_configurator_connectivity=0
+
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
+#### TDLS (IEEE 802.11z-2010) #################################################
+
+# Prohibit use of TDLS in this BSS
+#tdls_prohibit=1
+
+# Prohibit use of TDLS Channel Switching in this BSS
+#tdls_prohibit_chan_switch=1
+
+##### IEEE 802.11v-2011 #######################################################
+
+# Time advertisement
+# 0 = disabled (default)
+# 2 = UTC time at which the TSF timer is 0
+#time_advertisement=2
+
+# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004:
+# stdoffset[dst[offset][,start[/time],end[/time]]]
+#time_zone=EST5
+
+# WNM-Sleep Mode (extended sleep mode for stations)
+# 0 = disabled (default)
+# 1 = enabled (allow stations to use WNM-Sleep Mode)
+#wnm_sleep_mode=1
+
+# WNM-Sleep Mode GTK/IGTK workaround
+# Normally, WNM-Sleep Mode exit with management frame protection negotiated
+# would result in the current GTK/IGTK getting added into the WNM-Sleep Mode
+# Response frame. Some station implementations may have a vulnerability that
+# results in GTK/IGTK reinstallation based on this frame being replayed. This
+# configuration parameter can be used to disable that behavior and use EAPOL-Key
+# frames for GTK/IGTK update instead. This would likely be only used with
+# wpa_disable_eapol_key_retries=1 that enables a workaround for similar issues
+# with EAPOL-Key. This is related to station side vulnerabilities CVE-2017-13087
+# and CVE-2017-13088. To enable this AP-side workaround, set the parameter to 1.
+#wnm_sleep_mode_no_keys=0
+
+# BSS Transition Management
+# 0 = disabled (default)
+# 1 = enabled
+#bss_transition=1
+
+# Proxy ARP
+# 0 = disabled (default)
+# 1 = enabled
+#proxy_arp=1
+
+# IPv6 Neighbor Advertisement multicast-to-unicast conversion
+# This can be used with Proxy ARP to allow multicast NAs to be forwarded to
+# associated STAs using link layer unicast delivery.
+# 0 = disabled (default)
+# 1 = enabled
+#na_mcast_to_ucast=0
+
+##### IEEE 802.11u-2011 #######################################################
+
+# Enable Interworking service
+#interworking=1
+
+# Access Network Type
+# 0 = Private network
+# 1 = Private network with guest access
+# 2 = Chargeable public network
+# 3 = Free public network
+# 4 = Personal device network
+# 5 = Emergency services only network
+# 14 = Test or experimental
+# 15 = Wildcard
+#access_network_type=0
+
+# Whether the network provides connectivity to the Internet
+# 0 = Unspecified
+# 1 = Network provides connectivity to the Internet
+#internet=1
+
+# Additional Step Required for Access
+# Note: This is only used with open network, i.e., ASRA shall ne set to 0 if
+# RSN is used.
+#asra=0
+
+# Emergency services reachable
+#esr=0
+
+# Unauthenticated emergency service accessible
+#uesa=0
+
+# Venue Info (optional)
+# The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34.
+# Example values (group,type):
+# 0,0 = Unspecified
+# 1,7 = Convention Center
+# 1,13 = Coffee Shop
+# 2,0 = Unspecified Business
+# 7,1 Private Residence
+#venue_group=7
+#venue_type=1
+
+# Homogeneous ESS identifier (optional; dot11HESSID)
+# If set, this shall be identifical to one of the BSSIDs in the homogeneous
+# ESS and this shall be set to the same value across all BSSs in homogeneous
+# ESS.
+#hessid=02:03:04:05:06:07
+
+# Roaming Consortium List
+# Arbitrary number of Roaming Consortium OIs can be configured with each line
+# adding a new OI to the list. The first three entries are available through
+# Beacon and Probe Response frames. Any additional entry will be available only
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured as
+# a hexstring.
+#roaming_consortium=021122
+#roaming_consortium=2233445566
+
+# Venue Name information
+# This parameter can be used to configure one or more Venue Name Duples for
+# Venue Name ANQP information. Each entry has a two or three character language
+# code (ISO-639) separated by colon from the venue name string.
+# Note that venue_group and venue_type have to be set for Venue Name
+# information to be complete.
+#venue_name=eng:Example venue
+#venue_name=fin:Esimerkkipaikka
+# Alternative format for language:value strings:
+# (double quoted string, printf-escaped string)
+#venue_name=P"eng:Example\nvenue"
+
+# Venue URL information
+# This parameter can be used to configure one or more Venue URL Duples to
+# provide additional information corresponding to Venue Name information.
+# Each entry has a Venue Number value separated by colon from the Venue URL
+# string. Venue Number indicates the corresponding venue_name entry (1 = 1st
+# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name)
+#venue_url=1:http://www.example.com/info-eng
+#venue_url=2:http://www.example.com/info-fin
+
+# Network Authentication Type
+# This parameter indicates what type of network authentication is used in the
+# network.
+# format: <network auth type indicator (1-octet hex str)> [redirect URL]
+# Network Authentication Type Indicator values:
+# 00 = Acceptance of terms and conditions
+# 01 = On-line enrollment supported
+# 02 = http/https redirection
+# 03 = DNS redirection
+#network_auth_type=00
+#network_auth_type=02http://www.example.com/redirect/me/here/
+
+# IP Address Type Availability
+# format: <1-octet encoded value as hex str>
+# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3)
+# ipv4_type:
+# 0 = Address type not available
+# 1 = Public IPv4 address available
+# 2 = Port-restricted IPv4 address available
+# 3 = Single NATed private IPv4 address available
+# 4 = Double NATed private IPv4 address available
+# 5 = Port-restricted IPv4 address and single NATed IPv4 address available
+# 6 = Port-restricted IPv4 address and double NATed IPv4 address available
+# 7 = Availability of the address type is not known
+# ipv6_type:
+# 0 = Address type not available
+# 1 = Address type available
+# 2 = Availability of the address type not known
+#ipaddr_type_availability=14
+
+# Domain Name
+# format: <variable-octet str>[,<variable-octet str>]
+#domain_name=example.com,another.example.com,yet-another.example.com
+
+# 3GPP Cellular Network information
+# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
+#anqp_3gpp_cell_net=244,91;310,026;234,56
+
+# NAI Realm information
+# One or more realm can be advertised. Each nai_realm line adds a new realm to
+# the set. These parameters provide information for stations using Interworking
+# network selection to allow automatic connection to a network based on
+# credentials.
+# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
+# encoding:
+# 0 = Realm formatted in accordance with IETF RFC 4282
+# 1 = UTF-8 formatted character string that is not formatted in
+# accordance with IETF RFC 4282
+# NAI Realm(s): Semi-colon delimited NAI Realm(s)
+# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
+# EAP Method types, see:
+# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4
+# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
+# ID 2 = Non-EAP Inner Authentication Type
+# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
+# ID 3 = Inner authentication EAP Method Type
+# ID 5 = Credential Type
+# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
+# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
+# 10 = Vendor Specific
+#nai_realm=0,example.com;example.net
+# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
+# username/password
+#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+
+# Arbitrary ANQP-element configuration
+# Additional ANQP-elements with arbitrary values can be defined by specifying
+# their contents in raw format as a hexdump of the payload. Note that these
+# values will override ANQP-element contents that may have been specified in the
+# more higher layer configuration parameters listed above.
+# format: anqp_elem=<InfoID>:<hexdump of payload>
+# For example, AP Geospatial Location ANQP-element with unknown location:
+#anqp_elem=265:0000
+# For example, AP Civic Location ANQP-element with unknown location:
+#anqp_elem=266:000000
+
+# GAS Address 3 behavior
+# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default
+# based on GAS request Address3
+# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3
+# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases)
+#gas_address3=0
+
+# QoS Map Set configuration
+#
+# Comma delimited QoS Map Set in decimal values
+# (see IEEE Std 802.11-2012, 8.4.2.97)
+#
+# format:
+# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
+#
+# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
+# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
+# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
+# each UP starting from 0. If both low and high value are set to 255, the
+# corresponding UP is not used.
+#
+# default: not set
+#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255
+
+##### Hotspot 2.0 #############################################################
+
+# Enable Hotspot 2.0 support
+#hs20=1
+
+# Disable Downstream Group-Addressed Forwarding (DGAF)
+# This can be used to configure a network where no group-addressed frames are
+# allowed. The AP will not forward any group-address frames to the stations and
+# random GTKs are issued for each station to prevent associated stations from
+# forging such frames to other stations in the BSS.
+#disable_dgaf=1
+
+# OSU Server-Only Authenticated L2 Encryption Network
+#osen=1
+
+# ANQP Domain ID (0..65535)
+# An identifier for a set of APs in an ESS that share the same common ANQP
+# information. 0 = Some of the ANQP information is unique to this AP (default).
+#anqp_domain_id=1234
+
+# Deauthentication request timeout
+# If the RADIUS server indicates that the station is not allowed to connect to
+# the BSS/ESS, the AP can allow the station some time to download a
+# notification page (URL included in the message). This parameter sets that
+# timeout in seconds.
+#hs20_deauth_req_timeout=60
+
+# Operator Friendly Name
+# This parameter can be used to configure one or more Operator Friendly Name
+# Duples. Each entry has a two or three character language code (ISO-639)
+# separated by colon from the operator friendly name string.
+#hs20_oper_friendly_name=eng:Example operator
+#hs20_oper_friendly_name=fin:Esimerkkioperaattori
+
+# Connection Capability
+# This can be used to advertise what type of IP traffic can be sent through the
+# hotspot (e.g., due to firewall allowing/blocking protocols/ports).
+# format: <IP Protocol>:<Port Number>:<Status>
+# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP
+# Port Number: 0..65535
+# Status: 0 = Closed, 1 = Open, 2 = Unknown
+# Each hs20_conn_capab line is added to the list of advertised tuples.
+#hs20_conn_capab=1:0:2
+#hs20_conn_capab=6:22:1
+#hs20_conn_capab=17:5060:0
+
+# WAN Metrics
+# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD>
+# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity
+# (encoded as two hex digits)
+# Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state
+# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps;
+# 1..4294967295; 0 = unknown
+# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps
+# 1..4294967295; 0 = unknown
+# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%)
+# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%)
+# Load Measurement Duration: Duration for measuring downlink/uplink load in
+# tenths of a second (1..65535); 0 if load cannot be determined
+#hs20_wan_metrics=01:8000:1000:80:240:3000
+
+# Operating Class Indication
+# List of operating classes the BSSes in this ESS use. The Global operating
+# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that
+# can be used in this.
+# format: hexdump of operating class octets
+# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz
+# channels 36-48):
+#hs20_operating_class=5173
+
+# Terms and Conditions information
+#
+# hs20_t_c_filename contains the Terms and Conditions filename that the AP
+# indicates in RADIUS Access-Request messages.
+#hs20_t_c_filename=terms-and-conditions
+#
+# hs20_t_c_timestamp contains the Terms and Conditions timestamp that the AP
+# indicates in RADIUS Access-Request messages. Usually, this contains the number
+# of seconds since January 1, 1970 00:00 UTC showing the time when the file was
+# last modified.
+#hs20_t_c_timestamp=1234567
+#
+# hs20_t_c_server_url contains a template for the Terms and Conditions server
+# URL. This template is used to generate the URL for a STA that needs to
+# acknowledge Terms and Conditions. Unlike the other hs20_t_c_* parameters, this
+# parameter is used on the authentication server, not the AP.
+# Macros:
+# @1@ = MAC address of the STA (colon separated hex octets)
+#hs20_t_c_server_url=https://example.com/t_and_c?addr=@1@&ap=123
+
+# OSU and Operator icons
+# <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path>
+#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png
+#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png
+
+# OSU SSID (see ssid2 for format description)
+# This is the SSID used for all OSU connections to all the listed OSU Providers.
+#osu_ssid="example"
+
+# OSU Providers
+# One or more sets of following parameter. Each OSU provider is started by the
+# mandatory osu_server_uri item. The other parameters add information for the
+# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN
+# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI
+# value for OSEN authentication when using a shared BSS (Single SSID) for OSU.
+#
+#osu_server_uri=https://example.com/osu/
+#osu_friendly_name=eng:Example operator
+#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
+#osu_nai=anonymous@example.com
+#osu_nai2=anonymous@example.com
+#osu_method_list=1 0
+#osu_icon=icon32
+#osu_icon=icon64
+#osu_service_desc=eng:Example services
+#osu_service_desc=fin:Esimerkkipalveluja
+#
+#osu_server_uri=...
+
+# Operator Icons
+# Operator icons are specified using references to the hs20_icon entries
+# (Name subfield). This information, if present, is advertsised in the
+# Operator Icon Metadata ANQO-element.
+#operator_icon=icon32
+#operator_icon=icon64
+
+##### Multiband Operation (MBO) ###############################################
+#
+# MBO enabled
+# 0 = disabled (default)
+# 1 = enabled
+#mbo=1
+#
+# Cellular data connection preference
+# 0 = Excluded - AP does not want STA to use the cellular data connection
+# 1 = AP prefers the STA not to use cellular data connection
+# 255 = AP prefers the STA to use cellular data connection
+#mbo_cell_data_conn_pref=1
+
+##### Optimized Connectivity Experience (OCE) #################################
+#
+# Enable OCE specific features (bitmap)
+# BIT(0) - Reserved
+# Set BIT(1) (= 2) to enable OCE in STA-CFON mode
+# Set BIT(2) (= 4) to enable OCE in AP mode
+# Default is 0 = OCE disabled
+#oce=0
+
+# RSSI-based association rejection
+#
+# Reject STA association if RSSI is below given threshold (in dBm)
+# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
+# Note: This rejection happens based on a signal strength detected while
+# receiving a single frame and as such, there is significant risk of the value
+# not being accurate and this resulting in valid stations being rejected. As
+# such, this functionality is not recommended to be used for purposes other than
+# testing.
+#rssi_reject_assoc_rssi=-75
+#
+# Association retry delay in seconds allowed by the STA if RSSI has not met the
+# threshold (range: 0..255, default=30).
+#rssi_reject_assoc_timeout=30
+
+# Ignore Probe Request frames if RSSI is below given threshold (in dBm)
+# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
+#rssi_ignore_probe_request=-75
+
+##### Fast Session Transfer (FST) support #####################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_FST is set while compiling hostapd. They allow this interface
+# to be a part of FST setup.
+#
+# FST is the transfer of a session from a channel to another channel, in the
+# same or different frequency bands.
+#
+# For detals, see IEEE Std 802.11ad-2012.
+
+# Identifier of an FST Group the interface belongs to.
+#fst_group_id=bond0
+
+# Interface priority within the FST Group.
+# Announcing a higher priority for an interface means declaring it more
+# preferable for FST switch.
+# fst_priority is in 1..255 range with 1 being the lowest priority.
+#fst_priority=100
+
+# Default LLT value for this interface in milliseconds. The value used in case
+# no value provided during session setup. Default is 50 ms.
+# fst_llt is in 1..4294967 range (due to spec limitation, see 10.32.2.2
+# Transitioning between states).
+#fst_llt=100
+
+##### Radio measurements / location ###########################################
+
+# The content of a LCI measurement subelement
+#lci=<Hexdump of binary data of the LCI report>
+
+# The content of a location civic measurement subelement
+#civic=<Hexdump of binary data of the location civic report>
+
+# Enable neighbor report via radio measurements
+#rrm_neighbor_report=1
+
+# Enable beacon report via radio measurements
+#rrm_beacon_report=1
+
+# Publish fine timing measurement (FTM) responder functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_initiator=0
+#
+# Stationary AP config indicates that the AP doesn't move hence location data
+# can be considered as always up to date. If configured, LCI data will be sent
+# as a radio measurement even if the request doesn't contain a max age element
+# that allows sending of such data. Default: 0.
+#stationary_ap=0
+
+# Enable reduced neighbor reporting (RNR)
+#rnr=0
+
+##### Airtime policy configuration ###########################################
+
+# Set the airtime policy operating mode:
+# 0 = disabled (default)
+# 1 = static config
+# 2 = per-BSS dynamic config
+# 3 = per-BSS limit mode
+#airtime_mode=0
+
+# Interval (in milliseconds) to poll the kernel for updated station activity in
+# dynamic and limit modes
+#airtime_update_interval=200
+
+# Static configuration of station weights (when airtime_mode=1). Kernel default
+# weight is 256; set higher for larger airtime share, lower for smaller share.
+# Each entry is a MAC address followed by a weight.
+#airtime_sta_weight=02:01:02:03:04:05 256
+#airtime_sta_weight=02:01:02:03:04:06 512
+
+# Per-BSS airtime weight. In multi-BSS mode, set for each BSS and hostapd will
+# configure station weights to enforce the correct ratio between BSS weights
+# depending on the number of active stations. The *ratios* between different
+# BSSes is what's important, not the absolute numbers.
+# Must be set for all BSSes if airtime_mode=2 or 3, has no effect otherwise.
+#airtime_bss_weight=1
+
+# Whether the current BSS should be limited (when airtime_mode=3).
+#
+# If set, the BSS weight ratio will be applied in the case where the current BSS
+# would exceed the share defined by the BSS weight ratio. E.g., if two BSSes are
+# set to the same weights, and one is set to limited, the limited BSS will get
+# no more than half the available airtime, but if the non-limited BSS has more
+# stations active, that *will* be allowed to exceed its half of the available
+# airtime.
+#airtime_bss_limit=1
+
+##### EDMG support ############################################################
+#
+# Enable EDMG capability for AP mode in the 60 GHz band. Default value is false.
+# To configure channel bonding for an EDMG AP use edmg_channel below.
+# If enable_edmg is set and edmg_channel is not set, EDMG CB1 will be
+# configured.
+#enable_edmg=1
+#
+# Configure channel bonding for AP mode in the 60 GHz band.
+# This parameter is relevant only if enable_edmg is set.
+# Default value is 0 (no channel bonding).
+#edmg_channel=9
+
+##### TESTING OPTIONS #########################################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow
+# testing some scenarios that are otherwise difficult to reproduce.
+#
+# Ignore probe requests sent to hostapd with the given probability, must be a
+# floating point number in the range [0, 1).
+#ignore_probe_probability=0.0
+#
+# Ignore authentication frames with the given probability
+#ignore_auth_probability=0.0
+#
+# Ignore association requests with the given probability
+#ignore_assoc_probability=0.0
+#
+# Ignore reassociation requests with the given probability
+#ignore_reassoc_probability=0.0
+#
+# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
+#corrupt_gtk_rekey_mic_probability=0.0
+#
+# Include only ECSA IE without CSA IE where possible
+# (channel switch operating class is needed)
+#ecsa_ie_only=0
+
+##### Multiple BSSID support ##################################################
+#
+# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
+# interfaces). Other BSSIDs can be added by using separator 'bss' with
+# default interface name to be allocated for the data packets of the new BSS.
+#
+# hostapd will generate BSSID mask based on the BSSIDs that are
+# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
+# not the case, the MAC address of the radio must be changed before starting
+# hostapd (ifconfig wlan0 hw ether <MAC addr>). If a BSSID is configured for
+# every secondary BSS, this limitation is not applied at hostapd and other
+# masks may be used if the driver supports them (e.g., swap the locally
+# administered bit)
+#
+# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
+# specified using the 'bssid' parameter.
+# If an explicit BSSID is specified, it must be chosen such that it:
+# - results in a valid MASK that covers it and the dev_addr
+# - is not the same as the MAC address of the radio
+# - is not the same as any other explicitly specified BSSID
+#
+# Alternatively, the 'use_driver_iface_addr' parameter can be used to request
+# hostapd to use the driver auto-generated interface address (e.g., to use the
+# exact MAC addresses allocated to the device).
+#
+# Not all drivers support multiple BSSes. The exact mechanism for determining
+# the driver capabilities is driver specific. With the current (i.e., a recent
+# kernel) drivers using nl80211, this information can be checked with "iw list"
+# (search for "valid interface combinations").
+#
+# Please note that hostapd uses some of the values configured for the first BSS
+# as the defaults for the following BSSes. However, it is recommended that all
+# BSSes include explicit configuration of all relevant configuration items.
+#
+#bss=wlan0_0
+#ssid=test2
+# most of the above items can be used here (apart from radio interface specific
+# items, like channel)
+
+#bss=wlan0_1
+#bssid=00:13:10:95:fe:0b
+# ...
+#}
diff --git a/debian/control b/debian/control
index 2e99bdc28..883e08649 100644
--- a/debian/control
+++ b/debian/control
@@ -19,12 +19,18 @@ Build-Depends:
python3-xmltodict,
# For running tests
python3-coverage,
+ python3-hurry.filesize,
+ python3-netaddr,
python3-netifaces,
python3-nose,
python3-jinja2,
+ python3-paramiko,
+ python3-passlib,
python3-psutil,
python3-requests,
python3-setuptools,
+ python3-tabulate,
+ python3-zmq,
quilt,
whois
Standards-Version: 3.9.6
diff --git a/interface-definitions/interfaces_wireless.xml.in b/interface-definitions/interfaces_wireless.xml.in
index b3fc2302d..0a62b3255 100644
--- a/interface-definitions/interfaces_wireless.xml.in
+++ b/interface-definitions/interfaces_wireless.xml.in
@@ -27,7 +27,7 @@
<children>
<node name="ht">
<properties>
- <help>HT (High Throughput) settings</help>
+ <help>High Throughput (HT) settings</help>
</properties>
<children>
<leafNode name="40mhz-incapable">
@@ -38,7 +38,7 @@
</leafNode>
<leafNode name="auto-powersave">
<properties>
- <help>Enable WMM-PS unscheduled automatic power aave delivery [U-APSD]</help>
+ <help>Enable WMM-PS unscheduled automatic power save delivery [U-APSD]</help>
<valueless/>
</properties>
</leafNode>
@@ -184,25 +184,13 @@
</node>
<leafNode name="require-ht">
<properties>
- <help>Require stations to support HT PHY (reject association if they do not)</help>
- <completionHelp>
- <script>echo If you reject non-HT, you also disable 802.11g</script>
- </completionHelp>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="require-vht">
- <properties>
- <help>Require stations to support VHT PHY (reject association if they do not)</help>
- <completionHelp>
- <script>echo If you reject non-VHT, you also disable 802.11n</script>
- </completionHelp>
+ <help>Require stations to support HT PHY</help>
<valueless/>
</properties>
</leafNode>
<node name="vht">
<properties>
- <help>VHT (Very High Throughput) settings</help>
+ <help>Very High Throughput (VHT) settings</help>
</properties>
<children>
<leafNode name="antenna-count">
@@ -225,7 +213,7 @@
</leafNode>
<leafNode name="beamform">
<properties>
- <help>Beamforming capabilities</help>
+ <help>VHT beamforming capabilities</help>
<completionHelp>
<list>single-user-beamformer single-user-beamformee multi-user-beamformer multi-user-beamformee</list>
</completionHelp>
@@ -274,7 +262,7 @@
<help>VHT operating channel center frequency - center freq 2 (for use with the 80+80 mode)</help>
<valueHelp>
<format>u32:34-173</format>
- <description>5Ghz (802.11 a/h/j/n/ac) center channel index (use 58 for primary 80MHz channel 52)</description>
+ <description>5Ghz (802.11 ac) center channel index (use 58 for secondary 80MHz channel 52)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 34-173"/>
@@ -428,6 +416,133 @@
</leafNode>
</children>
</node>
+ <leafNode name="require-vht">
+ <properties>
+ <help>Require stations to support VHT PHY</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <node name="he">
+ <properties>
+ <help>High Efficiency (HE) settings</help>
+ </properties>
+ <children>
+ <leafNode name="channel-set-width">
+ <properties>
+ <help>HE operating channel width</help>
+ <completionHelp>
+ <!--
+ op_modes drawn from:
+ https://w1.fi/cgit/hostap/tree/src/common/ieee802_11_common.c?id=195cc3d919503fb0d699d9a56a58a72602b25f51#n1525
+ 802.11ax (WiFi-6e - HE) can use up to 160MHz bandwidth channels
+ -->
+ <list>131 132 133 134 135</list>
+ </completionHelp>
+ <valueHelp>
+ <format>131</format>
+ <description>20 MHz channel width</description>
+ </valueHelp>
+ <valueHelp>
+ <format>132</format>
+ <description>40 MHz channel width</description>
+ </valueHelp>
+ <valueHelp>
+ <format>133</format>
+ <description>80 MHz channel width</description>
+ </valueHelp>
+ <valueHelp>
+ <format>134</format>
+ <description>160 MHz channel width</description>
+ </valueHelp>
+ <valueHelp>
+ <format>135</format>
+ <description>80+80 MHz channel width</description>
+ </valueHelp>
+ <constraint>
+ <regex>(131|132|133|134|135)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ <node name="center-channel-freq">
+ <properties>
+ <help>HE operating channel center frequency</help>
+ </properties>
+ <children>
+ <leafNode name="freq-1">
+ <properties>
+ <help>HE operating channel center frequency - center freq 1 (for use with 80, 80+80 and 160 modes)</help>
+ <valueHelp>
+ <format>u32:1-233</format>
+ <description>6Ghz (802.11 ax) center channel index (use 3 (at 40MHz), 7 (at 80MHz) or 15 (at 160MHz) for primary channel 1)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-233"/>
+ </constraint>
+ <constraintErrorMessage>Channel center value must be between 1 and 233</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="freq-2">
+ <properties>
+ <help>HE operating channel center frequency - center freq 2 (for use with the 80+80 mode)</help>
+ <valueHelp>
+ <format>u32:1-233</format>
+ <description>6Ghz (802.11 ax) center channel index (use 23 (at 80MHz) for secondary channel 17)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-233"/>
+ </constraint>
+ <constraintErrorMessage>Channel center value must be between 1 and 233</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="antenna-pattern-fixed">
+ <properties>
+ <help>Tell the AP that antenna positions are fixed and will not change during the lifetime of an association</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <node name="beamform">
+ <properties>
+ <help>HE beamforming capabilities</help>
+ </properties>
+ <children>
+ <leafNode name="single-user-beamformer">
+ <properties>
+ <help>Support for operation as single user beamformer</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="single-user-beamformee">
+ <properties>
+ <help>Support for operation as single user beamformee</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="multi-user-beamformer">
+ <properties>
+ <help>Support for operation as multi user beamformer</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="bss-color">
+ <properties>
+ <help>BSS coloring helps to prevent channel jamming when multiple APs use the same channels</help>
+ <constraint>
+ <validator name="numeric" argument="--range 1-63"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="require-he">
+ <properties>
+ <help>Require stations to support HE PHY</help>
+ <valueless/>
+ </properties>
+ </leafNode>
</children>
</node>
<leafNode name="channel">
@@ -445,8 +560,12 @@
<format>u32:34-173</format>
<description>5Ghz (802.11 a/h/j/n/ac) Channel</description>
</valueHelp>
+ <valueHelp>
+ <format>u32:1-233</format>
+ <description>6Ghz (802.11 ax) Channel</description>
+ </valueHelp>
<constraint>
- <validator name="numeric" argument="--range 0-0 --range 1-14 --range 34-173"/>
+ <validator name="numeric" argument="--range 0-0 --range 1-14 --range 34-173 --range 1-233"/>
</constraint>
</properties>
<defaultValue>0</defaultValue>
@@ -492,6 +611,12 @@
<constraintErrorMessage>Number of stations must be between 1 and 2007</constraintErrorMessage>
</properties>
</leafNode>
+ <leafNode name="stationary-ap">
+ <properties>
+ <help>Stationary AP config indicates that the AP doesn't move.</help>
+ <valueless/>
+ </properties>
+ </leafNode>
<leafNode name="mgmt-frame-protection">
<properties>
<help>Management Frame Protection (MFP) according to IEEE 802.11w</help>
@@ -508,7 +633,7 @@
</valueHelp>
<valueHelp>
<format>required</format>
- <description>MFP enforced</description>
+ <description>MFP enforced (mandatory for WPA3)</description>
</valueHelp>
<constraint>
<regex>(disabled|optional|required)</regex>
@@ -516,11 +641,18 @@
</properties>
<defaultValue>disabled</defaultValue>
</leafNode>
+ <leafNode name="enable-bf-protection">
+ <properties>
+ <help>Beacon Protection: management frame protection for Beacon frames, requires Management Frame Protection (MFP)</help>
+ <valueless/>
+ </properties>
+ <defaultValue>disabled</defaultValue>
+ </leafNode>
<leafNode name="mode">
<properties>
<help>Wireless radio mode</help>
<completionHelp>
- <list>a b g n ac</list>
+ <list>a b g n ac ax</list>
</completionHelp>
<valueHelp>
<format>a</format>
@@ -542,12 +674,24 @@
<format>ac</format>
<description>802.11ac - 1300 Mbits/sec</description>
</valueHelp>
+ <valueHelp>
+ <format>ax</format>
+ <description>802.11ax (6GHz only for now)</description>
+ </valueHelp>
<constraint>
- <regex>(a|b|g|n|ac)</regex>
+ <regex>(a|b|g|n|ac|ax)</regex>
</constraint>
</properties>
<defaultValue>g</defaultValue>
</leafNode>
+ <!-- background_radar_detection not yet supported by VyOS's hostapd
+ <leafNode name="background-radar-detection">
+ <properties>
+ <help>Enabling background radar detection feature allows CAC to be run on dedicated radio RF chains while the radio(s) are otherwise running normal AP activities on other channels.</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ -->
#include <include/interface/mirror.xml.i>
<leafNode name="physical-device">
<properties>
@@ -711,9 +855,21 @@
<regex>(GCMP-256|GCMP|CCMP-256|CCMP|TKIP)</regex>
</constraint>
<constraintErrorMessage>Invalid group cipher selection</constraintErrorMessage>
- <multi/>
</properties>
</leafNode>
+ <leafNode name="group-mgmt-cipher">
+ <properties>
+ <help>Group management cipher suite. All the stations connecting to the BSS will also need to support the selected cipher</help>
+ <completionHelp>
+ <list>AES-128-CMAC BIP-CMAC-256 BIP-GMAC-128 BIP-GMAC-256</list>
+ </completionHelp>
+ <constraint>
+ <regex>(AES-128-CMAC|BIP-CMAC-256|BIP-GMAC-128|BIP-GMAC-256)</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid group management cipher selection</constraintErrorMessage>
+ </properties>
+ <defaultValue>AES-128-CMAC</defaultValue>
+ </leafNode>
<leafNode name="mode">
<properties>
<help>WPA mode</help>
@@ -732,6 +888,10 @@
<format>wpa+wpa2</format>
<description>Allow both WPA and WPA2</description>
</valueHelp>
+ <valueHelp>
+ <format>wpa3</format>
+ <description>WPA3 (required for 802.11ax, you must also set mgmt-frame-protection as required)</description>
+ </valueHelp>
<constraint>
<regex>(wpa|wpa2|wpa\+wpa2|wpa3)</regex>
</constraint>
diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in
index 81228938f..7cb1ec06e 100644
--- a/interface-definitions/service_pppoe-server.xml.in
+++ b/interface-definitions/service_pppoe-server.xml.in
@@ -47,6 +47,12 @@
</leafNode>
</children>
</node>
+ <leafNode name="any-login">
+ <properties>
+ <help>Authentication with any login</help>
+ <valueless/>
+ </properties>
+ </leafNode>
</children>
</node>
<tagNode name="interface">
diff --git a/op-mode-definitions/generate_firewall_rule-resequence.xml.in b/op-mode-definitions/generate_firewall_rule-resequence.xml.in
index 66078deb9..ef81579fa 100644
--- a/op-mode-definitions/generate_firewall_rule-resequence.xml.in
+++ b/op-mode-definitions/generate_firewall_rule-resequence.xml.in
@@ -7,34 +7,7 @@
<help>Firewall</help>
</properties>
<children>
- <node name="rule-resequence">
- <properties>
- <help>Resequence the firewall rules</help>
- </properties>
- <command>${vyos_op_scripts_dir}/generate_firewall_rule-resequence.py</command>
- <children>
- <tagNode name="start">
- <properties>
- <help>Set the first sequence number</help>
- <completionHelp>
- <list>1-1000</list>
- </completionHelp>
- </properties>
- <command>${vyos_op_scripts_dir}/generate_firewall_rule-resequence.py --start $5</command>
- <children>
- <tagNode name="step">
- <properties>
- <help>Step between rules</help>
- <completionHelp>
- <list>1-1000</list>
- </completionHelp>
- </properties>
- <command>${vyos_op_scripts_dir}/generate_firewall_rule-resequence.py --start $5 --step $7</command>
- </tagNode>
- </children>
- </tagNode>
- </children>
- </node>
+ #include <include/rule-resequence.xml.i>
</children>
</node>
</children>
diff --git a/op-mode-definitions/generate_nat64_rule-resequence.xml.in b/op-mode-definitions/generate_nat64_rule-resequence.xml.in
new file mode 100644
index 000000000..399253b37
--- /dev/null
+++ b/op-mode-definitions/generate_nat64_rule-resequence.xml.in
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="generate">
+ <children>
+ <node name="nat64">
+ <properties>
+ <help>Network Address Translation (NAT64)</help>
+ </properties>
+ <children>
+ #include <include/rule-resequence.xml.i>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/generate_nat66_rule-resequence.xml.in b/op-mode-definitions/generate_nat66_rule-resequence.xml.in
new file mode 100644
index 000000000..d7159cf60
--- /dev/null
+++ b/op-mode-definitions/generate_nat66_rule-resequence.xml.in
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="generate">
+ <children>
+ <node name="nat66">
+ <properties>
+ <help>Network Prefix Translation (NAT66/NPTv6)</help>
+ </properties>
+ <children>
+ #include <include/rule-resequence.xml.i>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/generate_nat_rule-resequence.xml.in b/op-mode-definitions/generate_nat_rule-resequence.xml.in
new file mode 100644
index 000000000..e32a89e08
--- /dev/null
+++ b/op-mode-definitions/generate_nat_rule-resequence.xml.in
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="generate">
+ <children>
+ <node name="nat">
+ <properties>
+ <help>Network Address Translation (NAT)</help>
+ </properties>
+ <children>
+ #include <include/rule-resequence.xml.i>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/include/rule-resequence.xml.i b/op-mode-definitions/include/rule-resequence.xml.i
new file mode 100644
index 000000000..987bf634e
--- /dev/null
+++ b/op-mode-definitions/include/rule-resequence.xml.i
@@ -0,0 +1,30 @@
+<!-- included start from show-nht.xml.i -->
+<node name="rule-resequence">
+ <properties>
+ <help>Resequence rules</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/generate_service_rule-resequence.py --service $2</command>
+ <children>
+ <tagNode name="start">
+ <properties>
+ <help>Set the first sequence number</help>
+ <completionHelp>
+ <list>1-1000</list>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/generate_service_rule-resequence.py --service $2 --start $5</command>
+ <children>
+ <tagNode name="step">
+ <properties>
+ <help>Step between rules</help>
+ <completionHelp>
+ <list>1-1000</list>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/generate_service_rule-resequence.py --service $2 --start $5 --step $7</command>
+ </tagNode>
+ </children>
+ </tagNode>
+ </children>
+</node>
+<!-- included end -->
diff --git a/python/vyos/base.py b/python/vyos/base.py
index 054b1d837..ca96d96ce 100644
--- a/python/vyos/base.py
+++ b/python/vyos/base.py
@@ -63,3 +63,10 @@ class ConfigError(Exception):
message = fill(message, width=72)
# Call the base class constructor with the parameters it needs
super().__init__(message)
+
+class MigrationError(Exception):
+ def __init__(self, message):
+ # Reformat the message and trim it to 72 characters in length
+ message = fill(message, width=72)
+ # Call the base class constructor with the parameters it needs
+ super().__init__(message)
diff --git a/python/vyos/component_version.py b/python/vyos/component_version.py
index 9662ebfcf..0c305e5e0 100644
--- a/python/vyos/component_version.py
+++ b/python/vyos/component_version.py
@@ -1,4 +1,4 @@
-# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -35,133 +35,173 @@ VyOS 1.2:
import os
import re
import sys
-import fileinput
+from dataclasses import dataclass
+from dataclasses import replace
+from typing import Optional
from vyos.xml_ref import component_version
+from vyos.utils.file import write_file
from vyos.version import get_version
from vyos.defaults import directories
DEFAULT_CONFIG_PATH = os.path.join(directories['config'], 'config.boot')
-def from_string(string_line, vintage='vyos'):
- """
- Get component version dictionary from string.
- Return empty dictionary if string contains no config information
- or raise error if component version string malformed.
- """
- version_dict = {}
-
- if vintage == 'vyos':
- if re.match(r'// vyos-config-version:.+', string_line):
- if not re.match(r'// vyos-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s*', string_line):
- raise ValueError(f"malformed configuration string: {string_line}")
+REGEX_WARN_VYOS = r'(// Warning: Do not remove the following line.)'
+REGEX_WARN_VYATTA = r'(/\* Warning: Do not remove the following line. \*/)'
+REGEX_COMPONENT_VERSION_VYOS = r'// vyos-config-version:\s+"([\w@:-]+)"\s*'
+REGEX_COMPONENT_VERSION_VYATTA = r'/\* === vyatta-config-version:\s+"([\w@:-]+)"\s+=== \*/'
+REGEX_RELEASE_VERSION_VYOS = r'// Release version:\s+(\S*)\s*'
+REGEX_RELEASE_VERSION_VYATTA = r'/\* Release version:\s+(\S*)\s*\*/'
- for pair in re.findall(r'([\w,-]+)@(\d+)', string_line):
- version_dict[pair[0]] = int(pair[1])
-
- elif vintage == 'vyatta':
- if re.match(r'/\* === vyatta-config-version:.+=== \*/$', string_line):
- if not re.match(r'/\* === vyatta-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s+=== \*/$', string_line):
- raise ValueError(f"malformed configuration string: {string_line}")
+CONFIG_FILE_VERSION = """\
+// Warning: Do not remove the following line.
+// vyos-config-version: "{}"
+// Release version: {}
+"""
- for pair in re.findall(r'([\w,-]+)@(\d+)', string_line):
- version_dict[pair[0]] = int(pair[1])
+warn_filter_vyos = re.compile(REGEX_WARN_VYOS)
+warn_filter_vyatta = re.compile(REGEX_WARN_VYATTA)
+
+regex_filter = { 'vyos': dict(zip(['component', 'release'],
+ [re.compile(REGEX_COMPONENT_VERSION_VYOS),
+ re.compile(REGEX_RELEASE_VERSION_VYOS)])),
+ 'vyatta': dict(zip(['component', 'release'],
+ [re.compile(REGEX_COMPONENT_VERSION_VYATTA),
+ re.compile(REGEX_RELEASE_VERSION_VYATTA)])) }
+
+@dataclass
+class VersionInfo:
+ component: Optional[dict[str,int]] = None
+ release: str = get_version()
+ vintage: str = 'vyos'
+ config_body: Optional[str] = None
+ footer_lines: Optional[list[str]] = None
+
+ def component_is_none(self) -> bool:
+ return bool(self.component is None)
+
+ def config_body_is_none(self) -> bool:
+ return bool(self.config_body is None)
+
+ def update_footer(self):
+ f = CONFIG_FILE_VERSION.format(component_to_string(self.component),
+ self.release)
+ self.footer_lines = f.splitlines()
+
+ def update_syntax(self):
+ self.vintage = 'vyos'
+ self.update_footer()
+
+ def update_release(self, release: str):
+ self.release = release
+ self.update_footer()
+
+ def update_component(self, key: str, version: int):
+ if not isinstance(version, int):
+ raise ValueError('version must be int')
+ if self.component is None:
+ self.component = {}
+ self.component[key] = version
+ self.component = dict(sorted(self.component.items(), key=lambda x: x[0]))
+ self.update_footer()
+
+ def update_config_body(self, config_str: str):
+ self.config_body = config_str
+
+ def write_string(self) -> str:
+ config_body = '' if self.config_body is None else self.config_body
+ footer_lines = [] if self.footer_lines is None else self.footer_lines
+
+ return config_body + '\n' + '\n'.join(footer_lines) + '\n'
+
+ def write(self, config_file):
+ string = self.write_string()
+ try:
+ write_file(config_file, string)
+ except Exception as e:
+ raise ValueError(e) from e
+
+def component_to_string(component: dict) -> str:
+ l = [f'{k}@{v}' for k, v in sorted(component.items(), key=lambda x: x[0])]
+ return ':'.join(l)
+
+def component_from_string(string: str) -> dict:
+ return {k: int(v) for k, v in re.findall(r'([\w,-]+)@(\d+)', string)}
+
+def version_info_from_file(config_file) -> VersionInfo:
+ version_info = VersionInfo()
+ try:
+ with open(config_file) as f:
+ config_str = f.read()
+ except OSError:
+ return None
+
+ if len(parts := warn_filter_vyos.split(config_str)) > 1:
+ vintage = 'vyos'
+ elif len(parts := warn_filter_vyatta.split(config_str)) > 1:
+ vintage = 'vyatta'
else:
- raise ValueError("Unknown config string vintage")
+ version_info.config_body = parts[0] if parts else None
+ return version_info
- return version_dict
+ version_info.vintage = vintage
+ version_info.config_body = parts[0]
+ version_lines = ''.join(parts[1:]).splitlines()
+ version_lines = [k for k in version_lines if k]
+ if len(version_lines) != 3:
+ raise ValueError(f'Malformed version strings: {version_lines}')
-def from_file(config_file_name=DEFAULT_CONFIG_PATH, vintage='vyos'):
- """
- Get component version dictionary parsing config file line by line
- """
- with open(config_file_name, 'r') as f:
- for line_in_config in f:
- version_dict = from_string(line_in_config, vintage=vintage)
- if version_dict:
- return version_dict
+ m = regex_filter[vintage]['component'].match(version_lines[1])
+ if not m:
+ raise ValueError(f'Malformed component string: {version_lines[1]}')
+ version_info.component = component_from_string(m.group(1))
- # no version information
- return {}
+ m = regex_filter[vintage]['release'].match(version_lines[2])
+ if not m:
+ raise ValueError(f'Malformed component string: {version_lines[2]}')
+ version_info.release = m.group(1)
-def from_system():
- """
- Get system component version dict.
- """
- return component_version()
+ version_info.footer_lines = version_lines
-def format_string(ver: dict) -> str:
- """
- Version dict to string.
- """
- keys = list(ver)
- keys.sort()
- l = []
- for k in keys:
- v = ver[k]
- l.append(f'{k}@{v}')
- sep = ':'
- return sep.join(l)
-
-def version_footer(ver: dict, vintage='vyos') -> str:
- """
- Version footer as string.
- """
- ver_str = format_string(ver)
- release = get_version()
- if vintage == 'vyos':
- ret_str = (f'// Warning: Do not remove the following line.\n'
- + f'// vyos-config-version: "{ver_str}"\n'
- + f'// Release version: {release}\n')
- elif vintage == 'vyatta':
- ret_str = (f'/* Warning: Do not remove the following line. */\n'
- + f'/* === vyatta-config-version: "{ver_str}" === */\n'
- + f'/* Release version: {release} */\n')
- else:
- raise ValueError("Unknown config string vintage")
+ return version_info
- return ret_str
-
-def system_footer(vintage='vyos') -> str:
+def version_info_from_system() -> VersionInfo:
"""
- System version footer as string.
+ Return system component versions.
"""
- ver_d = from_system()
- return version_footer(ver_d, vintage=vintage)
+ d = component_version()
+ sort_d = dict(sorted(d.items(), key=lambda x: x[0]))
+ version_info = VersionInfo(
+ component = sort_d,
+ release = get_version(),
+ vintage = 'vyos'
+ )
+
+ return version_info
-def write_version_footer(ver: dict, file_name, vintage='vyos'):
+def version_info_copy(v: VersionInfo) -> VersionInfo:
"""
- Write version footer to file.
+ Make a copy of dataclass.
"""
- footer = version_footer(ver=ver, vintage=vintage)
- if file_name:
- with open(file_name, 'a') as f:
- f.write(footer)
- else:
- sys.stdout.write(footer)
+ return replace(v)
-def write_system_footer(file_name, vintage='vyos'):
+def version_info_prune_component(x: VersionInfo, y: VersionInfo) -> VersionInfo:
"""
- Write system version footer to file.
+ In place pruning of component keys of x not in y.
"""
- ver_d = from_system()
- return write_version_footer(ver_d, file_name=file_name, vintage=vintage)
+ x.component = { k: v for k,v in x.component.items() if k in y.component }
-def remove_footer(file_name):
+def add_system_version(config_str: str = None, out_file: str = None):
"""
- Remove old version footer.
+ Wrap config string with system version and write to out_file.
+ For convenience, calling with no argument will write system version
+ string to stdout, for use in bash scripts.
"""
- for line in fileinput.input(file_name, inplace=True):
- if re.match(r'/\* Warning:.+ \*/$', line):
- continue
- if re.match(r'/\* === vyatta-config-version:.+=== \*/$', line):
- continue
- if re.match(r'/\* Release version:.+ \*/$', line):
- continue
- if re.match('// vyos-config-version:.+', line):
- continue
- if re.match('// Warning:.+', line):
- continue
- if re.match('// Release version:.+', line):
- continue
- sys.stdout.write(line)
+ version_info = version_info_from_system()
+ if config_str is not None:
+ version_info.update_config_body(config_str)
+ version_info.update_footer()
+ if out_file is not None:
+ version_info.write(out_file)
+ else:
+ sys.stdout.write(version_info.write_string())
diff --git a/python/vyos/compose_config.py b/python/vyos/compose_config.py
index efa28babe..79a8718c5 100644
--- a/python/vyos/compose_config.py
+++ b/python/vyos/compose_config.py
@@ -17,12 +17,13 @@
config.
"""
+import traceback
from pathlib import Path
from typing import TypeAlias, Union, Callable
from vyos.configtree import ConfigTree
from vyos.configtree import deep_copy as ct_deep_copy
-from vyos.utils.system import load_as_module
+from vyos.utils.system import load_as_module_source
ConfigObj: TypeAlias = Union[str, ConfigTree]
@@ -54,7 +55,8 @@ class ComposeConfig:
try:
func(self.config_tree)
except Exception as e:
- self.config_tree = self.checkpoint
+ if self.checkpoint_file is not None:
+ self.config_tree = self.checkpoint
raise ComposeConfigError(e) from e
def apply_file(self, func_file: str, func_name: str):
@@ -62,7 +64,7 @@ class ComposeConfig:
"""
try:
mod_name = Path(func_file).stem.replace('-', '_')
- mod = load_as_module(mod_name, func_file)
+ mod = load_as_module_source(mod_name, func_file)
func = getattr(mod, func_name)
except Exception as e:
raise ComposeConfigError(f'Error with {func_file}: {e}') from e
@@ -70,7 +72,9 @@ class ComposeConfig:
try:
self.apply_func(func)
except ComposeConfigError as e:
- raise ComposeConfigError(f'Error in {func_file}: {e}') from e
+ msg = str(e)
+ tb = f'{traceback.format_exc()}'
+ raise ComposeConfigError(f'Error in {func_file}: {msg}\n{tb}') from e
def to_string(self, with_version=False) -> str:
"""Return the rendered config tree.
diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py
index afd6e030b..5775070e2 100644
--- a/python/vyos/configtree.py
+++ b/python/vyos/configtree.py
@@ -15,6 +15,7 @@
import os
import re
import json
+import logging
from ctypes import cdll, c_char_p, c_void_p, c_int, c_bool
@@ -161,6 +162,8 @@ class ConfigTree(object):
self.__version = ''
self.__migration = os.environ.get('VYOS_MIGRATION')
+ if self.__migration:
+ self.migration_log = logging.getLogger('vyos.migrate')
def __del__(self):
if self.__config is not None:
@@ -215,7 +218,7 @@ class ConfigTree(object):
self.__set_add_value(self.__config, path_str, str(value).encode())
if self.__migration:
- print(f"- op: set path: {path} value: {value} replace: {replace}")
+ self.migration_log.info(f"- op: set path: {path} value: {value} replace: {replace}")
def delete(self, path):
check_path(path)
@@ -226,7 +229,7 @@ class ConfigTree(object):
raise ConfigTreeError(f"Path doesn't exist: {path}")
if self.__migration:
- print(f"- op: delete path: {path}")
+ self.migration_log.info(f"- op: delete path: {path}")
def delete_value(self, path, value):
check_path(path)
@@ -242,7 +245,7 @@ class ConfigTree(object):
raise ConfigTreeError()
if self.__migration:
- print(f"- op: delete_value path: {path} value: {value}")
+ self.migration_log.info(f"- op: delete_value path: {path} value: {value}")
def rename(self, path, new_name):
check_path(path)
@@ -258,7 +261,7 @@ class ConfigTree(object):
raise ConfigTreeError("Path [{}] doesn't exist".format(path))
if self.__migration:
- print(f"- op: rename old_path: {path} new_path: {new_path}")
+ self.migration_log.info(f"- op: rename old_path: {path} new_path: {new_path}")
def copy(self, old_path, new_path):
check_path(old_path)
@@ -275,7 +278,7 @@ class ConfigTree(object):
raise ConfigTreeError(msg)
if self.__migration:
- print(f"- op: copy old_path: {old_path} new_path: {new_path}")
+ self.migration_log.info(f"- op: copy old_path: {old_path} new_path: {new_path}")
def exists(self, path):
check_path(path)
diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py
index d45c9c272..80bb56fa2 100644
--- a/python/vyos/ethtool.py
+++ b/python/vyos/ethtool.py
@@ -16,6 +16,7 @@
import re
from json import loads
+from vyos.utils.network import interface_exists
from vyos.utils.process import popen
# These drivers do not support using ethtool to change the speed, duplex, or
@@ -64,6 +65,9 @@ class Ethtool:
def __init__(self, ifname):
# Get driver used for interface
+ if not interface_exists(ifname):
+ raise ValueError(f'Interface "{ifname}" does not exist!')
+
out, _ = popen(f'ethtool --driver {ifname}')
driver = re.search(r'driver:\s(\w+)', out)
if driver:
diff --git a/python/vyos/load_config.py b/python/vyos/load_config.py
index af563614d..b910a2f92 100644
--- a/python/vyos/load_config.py
+++ b/python/vyos/load_config.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -28,9 +28,7 @@ from typing import Union, Literal, TypeAlias, get_type_hints, get_args
from vyos.config import Config
from vyos.configtree import ConfigTree, DiffTree
from vyos.configsource import ConfigSourceSession, VyOSError
-from vyos.component_version import from_string as version_from_string
-from vyos.component_version import from_system as version_from_system
-from vyos.migrator import Migrator, VirtualMigrator, MigratorError
+from vyos.migrate import ConfigMigrate, ConfigMigrateError
from vyos.utils.process import popen, DEVNULL
Variety: TypeAlias = Literal['explicit', 'batch', 'tree', 'legacy']
@@ -51,20 +49,6 @@ def get_proposed_config(config_file: str = None) -> ConfigTree:
config_str = Path(config_file).read_text()
return ConfigTree(config_str)
-def migration_needed(config_obj: ConfigObj) -> bool:
- """Check if a migration is needed for the config object.
- """
- if not isinstance(config_obj, ConfigTree):
- atree = get_proposed_config(config_obj)
- else:
- atree = config_obj
- version_str = atree.get_version_string()
- if not version_str:
- return True
- aversion = version_from_string(version_str.splitlines()[1])
- bversion = version_from_system()
- return aversion != bversion
-
def check_session(strict: bool, switch: Variety) -> None:
"""Check if we are in a config session, with no uncommitted changes, if
strict. This is not needed for legacy load, as these checks are
@@ -128,12 +112,10 @@ def migrate(config_obj: ConfigObj) -> ConfigObj:
else:
config_file = config_obj
- virtual_migration = VirtualMigrator(config_file)
- migration = Migrator(config_file)
+ config_migrate = ConfigMigrate(config_file)
try:
- virtual_migration.run()
- migration.run()
- except MigratorError as e:
+ config_migrate.run()
+ except ConfigMigrateError as e:
raise LoadConfigError(e) from e
else:
if isinstance(config_obj, ConfigTree):
@@ -193,8 +175,7 @@ def load(config_obj: ConfigObj, strict: bool = True,
check_session(strict, switch)
- if migration_needed(config_obj):
- config_obj = migrate(config_obj)
+ config_obj = migrate(config_obj)
func = getattr(thismod, f'load_{switch}')
func(config_obj)
diff --git a/python/vyos/migrate.py b/python/vyos/migrate.py
new file mode 100644
index 000000000..9d1613676
--- /dev/null
+++ b/python/vyos/migrate.py
@@ -0,0 +1,283 @@
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
+
+import os
+import re
+import json
+import logging
+from pathlib import Path
+from grp import getgrnam
+
+from vyos.component_version import VersionInfo
+from vyos.component_version import version_info_from_system
+from vyos.component_version import version_info_from_file
+from vyos.component_version import version_info_copy
+from vyos.component_version import version_info_prune_component
+from vyos.compose_config import ComposeConfig
+from vyos.compose_config import ComposeConfigError
+from vyos.configtree import ConfigTree
+from vyos.defaults import directories as default_dir
+from vyos.defaults import component_version_json
+
+
+log_file = Path(default_dir['config']).joinpath('vyos-migrate.log')
+
+class ConfigMigrateError(Exception):
+ """Raised on error in config migration."""
+
+class ConfigMigrate:
+ # pylint: disable=too-many-instance-attributes
+ # the number is reasonable in this case
+ def __init__(self, config_file: str, force=False,
+ output_file: str = None, checkpoint_file: str = None):
+ self.config_file: str = config_file
+ self.force: bool = force
+ self.system_version: VersionInfo = version_info_from_system()
+ self.file_version: VersionInfo = version_info_from_file(self.config_file)
+ self.compose = None
+ self.output_file = output_file
+ self.checkpoint_file = checkpoint_file
+ self.logger = None
+ self.config_modified = True
+
+ if self.file_version is None:
+ raise ConfigMigrateError(f'failed to read config file {self.config_file}')
+
+ def migration_needed(self) -> bool:
+ return self.system_version.component != self.file_version.component
+
+ def release_update_needed(self) -> bool:
+ return self.system_version.release != self.file_version.release
+
+ def syntax_update_needed(self) -> bool:
+ return self.system_version.vintage != self.file_version.vintage
+
+ def update_release(self):
+ """
+ Update config file release version.
+ """
+ self.file_version.update_release(self.system_version.release)
+
+ def update_syntax(self):
+ """
+ Update config file syntax.
+ """
+ self.file_version.update_syntax()
+
+ @staticmethod
+ def normalize_config_body(version_info: VersionInfo):
+ """
+ This is an interim workaround for the cosmetic issue of node
+ ordering when composing operations on the internal config_tree:
+ ordering is performed on parsing, hence was maintained in the old
+ system which would parse/write on each application of a migration
+ script (~200). Here, we will take the cost of one extra parsing to
+ reorder before save, for easier review.
+ """
+ if not version_info.config_body_is_none():
+ ct = ConfigTree(version_info.config_body)
+ version_info.update_config_body(ct.to_string())
+
+ def write_config(self):
+ if self.output_file is not None:
+ config_file = self.output_file
+ else:
+ config_file = self.config_file
+
+ try:
+ self.file_version.write(config_file)
+ except ValueError as e:
+ raise ConfigMigrateError(f'failed to write {config_file}: {e}') from e
+
+ def init_logger(self):
+ self.logger = logging.getLogger(__name__)
+ self.logger.setLevel(logging.DEBUG)
+
+ fh = ConfigMigrate.group_perm_file_handler(log_file,
+ group='vyattacfg',
+ mode='w')
+ fh.setLevel(logging.INFO)
+ fh_formatter = logging.Formatter('%(message)s')
+ fh.setFormatter(fh_formatter)
+ self.logger.addHandler(fh)
+ ch = logging.StreamHandler()
+ ch.setLevel(logging.WARNING)
+ ch_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
+ ch.setFormatter(ch_formatter)
+ self.logger.addHandler(ch)
+
+ @staticmethod
+ def group_perm_file_handler(filename, group=None, mode='a'):
+ # pylint: disable=consider-using-with
+ if group is None:
+ return logging.FileHandler(filename, mode)
+ gid = getgrnam(group).gr_gid
+ if not os.path.exists(filename):
+ open(filename, 'a').close()
+ os.chown(filename, -1, gid)
+ os.chmod(filename, 0o664)
+ return logging.FileHandler(filename, mode)
+
+ @staticmethod
+ def sort_function():
+ """
+ Define sort function for migration files as tuples (n, m) for file
+ n-to-m.
+ """
+ numbers = re.compile(r'(\d+)')
+ def func(p: Path):
+ parts = numbers.split(p.stem)
+ return list(map(int, parts[1::2]))
+ return func
+
+ @staticmethod
+ def file_ext(file_path: Path) -> str:
+ """
+ Return an identifier from file name for checkpoint file extension.
+ """
+ return f'{file_path.parent.stem}_{file_path.stem}'
+
+ def run_migration_scripts(self):
+ """
+ Call migration files iteratively.
+ """
+ os.environ['VYOS_MIGRATION'] = '1'
+
+ self.init_logger()
+ self.logger.info("List of applied migration modules:")
+
+ components = list(self.system_version.component)
+ components.sort()
+
+ # T4382: 'bgp' needs to follow 'quagga':
+ if 'bgp' in components and 'quagga' in components:
+ components.insert(components.index('quagga'),
+ components.pop(components.index('bgp')))
+
+ revision: VersionInfo = version_info_copy(self.file_version)
+ # prune retired, for example, zone-policy
+ version_info_prune_component(revision, self.system_version)
+
+ migrate_dir = Path(default_dir['migrate'])
+ sort_func = ConfigMigrate.sort_function()
+
+ for key in components:
+ p = migrate_dir.joinpath(key)
+ script_list = list(p.glob('*-to-*'))
+ script_list = sorted(script_list, key=sort_func)
+
+ if not self.file_version.component_is_none() and not self.force:
+ start = self.file_version.component.get(key, 0)
+ script_list = list(filter(lambda x, st=start: sort_func(x)[0] >= st,
+ script_list))
+
+ if not script_list: # no applicable migration scripts
+ revision.update_component(key, self.system_version.component[key])
+ continue
+
+ for file in script_list:
+ f = file.as_posix()
+ self.logger.info(f'applying {f}')
+ try:
+ self.compose.apply_file(f, func_name='migrate')
+ except ComposeConfigError as e:
+ self.logger.error(e)
+ if self.checkpoint_file:
+ check = f'{self.checkpoint_file}_{ConfigMigrate.file_ext(file)}'
+ revision.update_config_body(self.compose.to_string())
+ ConfigMigrate.normalize_config_body(revision)
+ revision.write(check)
+ break
+ else:
+ revision.update_component(key, sort_func(file)[1])
+
+ revision.update_config_body(self.compose.to_string())
+ ConfigMigrate.normalize_config_body(revision)
+ self.file_version = version_info_copy(revision)
+
+ if revision.component != self.system_version.component:
+ raise ConfigMigrateError(f'incomplete migration: check {log_file} for error')
+
+ del os.environ['VYOS_MIGRATION']
+
+ def save_json_record(self):
+ """
+ Write component versions to a json file
+ """
+ version_file = component_version_json
+
+ try:
+ with open(version_file, 'w') as f:
+ f.write(json.dumps(self.system_version.component,
+ indent=2, sort_keys=True))
+ except OSError:
+ pass
+
+ def load_config(self):
+ """
+ Instantiate a ComposeConfig object with the config string.
+ """
+
+ self.compose = ComposeConfig(self.file_version.config_body, self.checkpoint_file)
+
+ def run(self):
+ """
+ If migration needed, run migration scripts and update config file.
+ If only release version update needed, update release version.
+ """
+ # save system component versions in json file for reference
+ self.save_json_record()
+
+ if not self.migration_needed():
+ if self.release_update_needed():
+ self.update_release()
+ self.write_config()
+ else:
+ self.config_modified = False
+ return
+
+ if self.syntax_update_needed():
+ self.update_syntax()
+ self.write_config()
+
+ self.load_config()
+
+ self.run_migration_scripts()
+
+ self.update_release()
+ self.write_config()
+
+ def run_script(self, test_script: str):
+ """
+ Run a single migration script. For testing this simply provides the
+ body for loading and writing the result; the component string is not
+ updated.
+ """
+
+ self.load_config()
+ self.init_logger()
+
+ os.environ['VYOS_MIGRATION'] = '1'
+
+ try:
+ self.compose.apply_file(test_script, func_name='migrate')
+ except ComposeConfigError as e:
+ self.logger.error(f'config-migration error in {test_script}: {e}')
+ else:
+ self.file_version.update_config_body(self.compose.to_string())
+
+ del os.environ['VYOS_MIGRATION']
+
+ self.write_config()
diff --git a/python/vyos/migrator.py b/python/vyos/migrator.py
deleted file mode 100644
index 872682bc0..000000000
--- a/python/vyos/migrator.py
+++ /dev/null
@@ -1,226 +0,0 @@
-# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io>
-#
-# 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/>.
-
-import sys
-import os
-import json
-import logging
-
-import vyos.defaults
-import vyos.component_version as component_version
-from vyos.utils.process import cmd
-
-log_file = os.path.join(vyos.defaults.directories['config'], 'vyos-migrate.log')
-
-class MigratorError(Exception):
- pass
-
-class Migrator(object):
- def __init__(self, config_file, force=False, set_vintage='vyos'):
- self._config_file = config_file
- self._force = force
- self._set_vintage = set_vintage
- self._config_file_vintage = None
- self._changed = False
-
- def init_logger(self):
- self.logger = logging.getLogger(__name__)
- self.logger.setLevel(logging.DEBUG)
-
- # on adding the file handler, allow write permission for cfg_group;
- # restore original umask on exit
- mask = os.umask(0o113)
- fh = logging.FileHandler(log_file)
- formatter = logging.Formatter('%(message)s')
- fh.setFormatter(formatter)
- self.logger.addHandler(fh)
- os.umask(mask)
-
- def read_config_file_versions(self):
- """
- Get component versions from config file footer and set vintage;
- return empty dictionary if config string is missing.
- """
- cfg_file = self._config_file
- component_versions = {}
-
- cfg_versions = component_version.from_file(cfg_file, vintage='vyatta')
-
- if cfg_versions:
- self._config_file_vintage = 'vyatta'
- component_versions = cfg_versions
-
- cfg_versions = component_version.from_file(cfg_file, vintage='vyos')
-
- if cfg_versions:
- self._config_file_vintage = 'vyos'
- component_versions = cfg_versions
-
- return component_versions
-
- def update_vintage(self):
- old_vintage = self._config_file_vintage
-
- if self._set_vintage:
- self._config_file_vintage = self._set_vintage
-
- if self._config_file_vintage not in ['vyatta', 'vyos']:
- raise MigratorError("Unknown vintage.")
-
- if self._config_file_vintage == old_vintage:
- return False
- else:
- return True
-
- def run_migration_scripts(self, config_file_versions, system_versions):
- """
- Run migration scripts iteratively, until config file version equals
- system component version.
- """
- os.environ['VYOS_MIGRATION'] = '1'
- self.init_logger()
-
- self.logger.info("List of executed migration scripts:")
-
- cfg_versions = config_file_versions
- sys_versions = system_versions
-
- sys_keys = list(sys_versions.keys())
- sys_keys.sort()
-
- # XXX 'bgp' needs to follow 'quagga':
- if 'bgp' in sys_keys and 'quagga' in sys_keys:
- sys_keys.insert(sys_keys.index('quagga'),
- sys_keys.pop(sys_keys.index('bgp')))
-
- rev_versions = {}
-
- for key in sys_keys:
- sys_ver = sys_versions[key]
- if key in cfg_versions:
- cfg_ver = cfg_versions[key]
- else:
- cfg_ver = 0
-
- migrate_script_dir = os.path.join(
- vyos.defaults.directories['migrate'], key)
-
- while cfg_ver < sys_ver:
- next_ver = cfg_ver + 1
-
- migrate_script = os.path.join(migrate_script_dir,
- '{}-to-{}'.format(cfg_ver, next_ver))
-
- try:
- out = cmd([migrate_script, self._config_file])
- self.logger.info(f'{migrate_script}')
- if out: self.logger.info(out)
- except FileNotFoundError:
- pass
- except Exception as err:
- print("\nMigration script error: {0}: {1}."
- "".format(migrate_script, err))
- sys.exit(1)
-
- cfg_ver = next_ver
- rev_versions[key] = cfg_ver
-
- del os.environ['VYOS_MIGRATION']
- return rev_versions
-
- def write_config_file_versions(self, cfg_versions):
- """
- Write new versions string.
- """
- if self._config_file_vintage == 'vyatta':
- component_version.write_version_footer(cfg_versions,
- self._config_file,
- vintage='vyatta')
-
- if self._config_file_vintage == 'vyos':
- component_version.write_version_footer(cfg_versions,
- self._config_file,
- vintage='vyos')
-
- def save_json_record(self, component_versions: dict):
- """
- Write component versions to a json file
- """
- mask = os.umask(0o113)
- version_file = vyos.defaults.component_version_json
- try:
- with open(version_file, 'w') as f:
- f.write(json.dumps(component_versions, indent=2, sort_keys=True))
- except OSError:
- pass
- finally:
- os.umask(mask)
-
- def run(self):
- """
- Gather component versions from config file and system.
- Run migration scripts.
- Update vintage ('vyatta' or 'vyos'), if needed.
- If changed, remove old versions string from config file, and
- write new versions string.
- """
- cfg_file = self._config_file
-
- cfg_versions = self.read_config_file_versions()
- if self._force:
- # This will force calling all migration scripts:
- cfg_versions = {}
-
- sys_versions = component_version.from_system()
-
- # save system component versions in json file for easy reference
- self.save_json_record(sys_versions)
-
- rev_versions = self.run_migration_scripts(cfg_versions, sys_versions)
-
- if rev_versions != cfg_versions:
- self._changed = True
-
- if self.update_vintage():
- self._changed = True
-
- if not self._changed:
- return
-
- component_version.remove_footer(cfg_file)
-
- self.write_config_file_versions(rev_versions)
-
- def config_changed(self):
- return self._changed
-
-class VirtualMigrator(Migrator):
- def run(self):
- cfg_file = self._config_file
-
- cfg_versions = self.read_config_file_versions()
- if not cfg_versions:
- return
-
- if self.update_vintage():
- self._changed = True
-
- if not self._changed:
- return
-
- component_version.remove_footer(cfg_file)
-
- self.write_config_file_versions(cfg_versions)
-
diff --git a/python/vyos/utils/dict.py b/python/vyos/utils/dict.py
index 062ab9c81..1eb6abcd5 100644
--- a/python/vyos/utils/dict.py
+++ b/python/vyos/utils/dict.py
@@ -34,7 +34,7 @@ def colon_separated_to_dict(data_string, uniquekeys=False):
otherwise they are always lists of strings.
"""
import re
- key_value_re = re.compile('([^:]+)\s*\:\s*(.*)')
+ key_value_re = re.compile(r'([^:]+)\s*\:\s*(.*)')
data_raw = re.split('\n', data_string)
diff --git a/python/vyos/utils/system.py b/python/vyos/utils/system.py
index f427032a4..fca93d118 100644
--- a/python/vyos/utils/system.py
+++ b/python/vyos/utils/system.py
@@ -99,6 +99,18 @@ def load_as_module(name: str, path: str):
spec.loader.exec_module(mod)
return mod
+def load_as_module_source(name: str, path: str):
+ """ Necessary modification of load_as_module for files without *.py
+ extension """
+ import importlib.util
+ from importlib.machinery import SourceFileLoader
+
+ loader = SourceFileLoader(name, path)
+ spec = importlib.util.spec_from_loader(name, loader)
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+ return mod
+
def get_uptime_seconds():
""" Returns system uptime in seconds """
from re import search
@@ -127,4 +139,3 @@ def get_load_averages():
res[15] = float(matches["fifteen"]) / core_count
return res
-
diff --git a/scripts/generate-configd-include-json.py b/scripts/generate-configd-include-json.py
new file mode 100755
index 000000000..b4b627fce
--- /dev/null
+++ b/scripts/generate-configd-include-json.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+# Copyright (C) 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
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+from jinja2 import Template
+
+conf_scripts = 'src/conf_mode'
+configd_include = 'data/configd-include.json'
+
+configd_template = Template("""[
+{% for file in files %}
+"{{ file }}"{{ "," if not loop.last else "" }}
+{% endfor %}
+]
+""", trim_blocks=True)
+
+files = [f for f in os.listdir(conf_scripts) if os.path.isfile(f'{conf_scripts}/{f}')]
+files = sorted(files)
+
+tmp = {'files' : files}
+with open(configd_include, 'w') as f:
+ f.write(configd_template.render(tmp))
diff --git a/smoketest/bin/vyos-configtest b/smoketest/bin/vyos-configtest
index c1b602737..fbf4055ad 100755
--- a/smoketest/bin/vyos-configtest
+++ b/smoketest/bin/vyos-configtest
@@ -55,7 +55,7 @@ def make_test_function(filename, test_path=None):
if test_path:
config_commands = self.session.show(['configuration', 'commands'])
-
+
with open(test_path, 'r') as f:
for line in f.readlines():
if not line or line.startswith("#"):
@@ -83,9 +83,10 @@ if __name__ == '__main__':
test_path = os.path.join(config_test_dir, config)
if not os.path.exists(test_path):
- test_path = None
- else:
- log.info(f'Loaded migration result test for config "{config}"')
+ log.error(f'Missing migration result test for config "{config}"')
+ sys.exit(1)
+
+ log.info(f'Loaded migration result test for config "{config}"')
test_func = make_test_function(config, test_path)
diff --git a/smoketest/bin/vyos-configtest-pki b/smoketest/bin/vyos-configtest-pki
index e753193e9..0f9ecdd41 100755
--- a/smoketest/bin/vyos-configtest-pki
+++ b/smoketest/bin/vyos-configtest-pki
@@ -25,9 +25,9 @@ from vyos.pki import encode_dh_parameters
from vyos.pki import encode_private_key
from vyos.utils.file import write_file
-subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos'}
-ca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos CA'}
-subca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos SubCA'}
+subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'VyOS'}
+ca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'VyOS CA'}
+subca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'VyOS SubCA'}
ca_cert = '/config/auth/ovpn_test_ca.pem'
ca_key = '/config/auth/ovpn_test_ca.key'
diff --git a/smoketest/config-tests/basic-api-service b/smoketest/config-tests/basic-api-service
index dc54929b9..3f796f35d 100644
--- a/smoketest/config-tests/basic-api-service
+++ b/smoketest/config-tests/basic-api-service
@@ -1,16 +1,28 @@
set interfaces ethernet eth0 address '192.0.2.1/31'
set interfaces ethernet eth0 address '2001:db8::1234/64'
+set interfaces ethernet eth0 offload gro
set interfaces loopback lo
-set service ntp server time1.vyos.net
-set service ntp server time2.vyos.net
-set service ntp server time3.vyos.net
set service https allow-client address '172.16.0.0/12'
set service https allow-client address '192.168.0.0/16'
set service https allow-client address '10.0.0.0/8'
set service https allow-client address '2001:db8::/32'
set service https api keys id 1 key 'S3cur3'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service ntp server time3.vyos.net
set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
set system login user vyos authentication plaintext-password ''
-set system console device ttyS0 speed '115200'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/basic-vyos b/smoketest/config-tests/basic-vyos
index d676c663d..6ff28ec2e 100644
--- a/smoketest/config-tests/basic-vyos
+++ b/smoketest/config-tests/basic-vyos
@@ -1,5 +1,14 @@
set interfaces ethernet eth0 address '192.168.0.1/24'
set interfaces ethernet eth0 address 'fe88::1/56'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 offload gro
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth2 duplex 'auto'
+set interfaces ethernet eth2 offload gro
+set interfaces ethernet eth2 speed 'auto'
set interfaces ethernet eth2 vif 100 address '100.100.0.1/24'
set interfaces ethernet eth2 vif-s 200 address '100.64.200.254/24'
set interfaces ethernet eth2 vif-s 200 vif-c 201 address '100.64.201.254/24'
@@ -19,17 +28,6 @@ set protocols static arp interface eth2.200.201 address 100.64.201.20 mac '00:50
set protocols static arp interface eth2.200.202 address 100.64.202.30 mac '00:50:00:00:00:30'
set protocols static arp interface eth2.200.202 address 100.64.202.40 mac '00:50:00:00:00:40'
set protocols static route 0.0.0.0/0 next-hop 100.64.0.1
-set service ssh ciphers 'aes128-ctr'
-set service ssh ciphers 'aes192-ctr'
-set service ssh ciphers 'aes256-ctr'
-set service ssh ciphers 'chacha20-poly1305@openssh.com'
-set service ssh ciphers 'rijndael-cbc@lysator.liu.se'
-set service ssh key-exchange 'curve25519-sha256@libssh.org'
-set service ssh key-exchange 'diffie-hellman-group1-sha1'
-set service ssh key-exchange 'diffie-hellman-group-exchange-sha1'
-set service ssh key-exchange 'diffie-hellman-group-exchange-sha256'
-set service ssh listen-address '192.168.0.1'
-set service ssh port '22'
set service dhcp-server shared-network-name LAN authoritative
set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option default-router '192.168.0.1'
set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option domain-name 'vyos.net'
@@ -66,19 +64,40 @@ set service dns forwarding allow-from '192.168.0.0/16'
set service dns forwarding cache-size '10000'
set service dns forwarding dnssec 'off'
set service dns forwarding listen-address '192.168.0.1'
+set service ssh ciphers 'aes128-ctr'
+set service ssh ciphers 'aes192-ctr'
+set service ssh ciphers 'aes256-ctr'
+set service ssh ciphers 'chacha20-poly1305@openssh.com'
+set service ssh ciphers 'rijndael-cbc@lysator.liu.se'
+set service ssh key-exchange 'curve25519-sha256@libssh.org'
+set service ssh key-exchange 'diffie-hellman-group1-sha1'
+set service ssh key-exchange 'diffie-hellman-group-exchange-sha1'
+set service ssh key-exchange 'diffie-hellman-group-exchange-sha256'
+set service ssh listen-address '192.168.0.1'
+set service ssh port '22'
set system config-management commit-revisions '100'
set system conntrack ignore ipv4 rule 1 destination address '192.0.2.2'
set system conntrack ignore ipv4 rule 1 source address '192.0.2.1'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
set system name-server '192.168.0.1'
-set system syslog global facility auth level 'info'
-set system syslog global preserve-fqdn
set system syslog console facility all level 'emerg'
set system syslog console facility mail level 'info'
+set system syslog global facility all level 'info'
+set system syslog global facility auth level 'info'
+set system syslog global facility local7 level 'debug'
+set system syslog global preserve-fqdn
set system syslog host syslog.vyos.net facility auth level 'warning'
set system syslog host syslog.vyos.net facility local7 level 'notice'
set system syslog host syslog.vyos.net format octet-counted
set system syslog host syslog.vyos.net port '8000'
-set system console device ttyS0 speed '115200'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/bgp-azure-ipsec-gateway b/smoketest/config-tests/bgp-azure-ipsec-gateway
new file mode 100644
index 000000000..bbd7b961f
--- /dev/null
+++ b/smoketest/config-tests/bgp-azure-ipsec-gateway
@@ -0,0 +1,231 @@
+set firewall global-options all-ping 'enable'
+set firewall global-options broadcast-ping 'disable'
+set firewall global-options ip-src-route 'disable'
+set firewall global-options ipv6-receive-redirects 'disable'
+set firewall global-options ipv6-src-route 'disable'
+set firewall global-options log-martians 'disable'
+set firewall global-options receive-redirects 'disable'
+set firewall global-options send-redirects 'enable'
+set firewall global-options source-validation 'disable'
+set firewall global-options syn-cookies 'enable'
+set firewall global-options twa-hazards-protection 'disable'
+set high-availability vrrp group DMZ-VLAN-3962 address 192.168.34.36/27
+set high-availability vrrp group DMZ-VLAN-3962 interface 'eth1'
+set high-availability vrrp group DMZ-VLAN-3962 preempt-delay '180'
+set high-availability vrrp group DMZ-VLAN-3962 priority '200'
+set high-availability vrrp group DMZ-VLAN-3962 vrid '62'
+set interfaces ethernet eth0 address '192.0.2.189/27'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 address '192.168.34.37/27'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 offload gro
+set interfaces ethernet eth1 speed 'auto'
+set interfaces loopback lo
+set interfaces vti vti31 ip adjust-mss '1350'
+set interfaces vti vti32 ip adjust-mss '1350'
+set interfaces vti vti41 ip adjust-mss '1350'
+set interfaces vti vti42 ip adjust-mss '1350'
+set interfaces vti vti51 ip adjust-mss '1350'
+set interfaces vti vti52 ip adjust-mss '1350'
+set policy prefix-list AZURE-BGP-IPv4-in description 'Prefixes received from Azure'
+set policy prefix-list AZURE-BGP-IPv4-in rule 100 action 'permit'
+set policy prefix-list AZURE-BGP-IPv4-in rule 100 le '32'
+set policy prefix-list AZURE-BGP-IPv4-in rule 100 prefix '100.64.0.0/10'
+set policy prefix-list ONPREM-BGP-IPv4-out description 'Prefixes allowed to be announced into Azure'
+set policy prefix-list ONPREM-BGP-IPv4-out rule 100 action 'permit'
+set policy prefix-list ONPREM-BGP-IPv4-out rule 100 prefix '10.0.0.0/8'
+set policy prefix-list ONPREM-BGP-IPv4-out rule 200 action 'permit'
+set policy prefix-list ONPREM-BGP-IPv4-out rule 200 prefix '172.16.0.0/12'
+set policy prefix-list ONPREM-BGP-IPv4-out rule 300 action 'permit'
+set policy prefix-list ONPREM-BGP-IPv4-out rule 300 prefix '192.168.0.0/16'
+set protocols bgp address-family ipv4-unicast network 10.0.0.0/8
+set protocols bgp address-family ipv4-unicast network 172.16.0.0/12
+set protocols bgp address-family ipv4-unicast network 192.168.0.0/16
+set protocols bgp neighbor 100.66.8.36 peer-group 'AZURE'
+set protocols bgp neighbor 100.66.8.36 remote-as '64517'
+set protocols bgp neighbor 100.66.8.37 peer-group 'AZURE'
+set protocols bgp neighbor 100.66.8.37 remote-as '64517'
+set protocols bgp neighbor 100.66.24.36 peer-group 'AZURE'
+set protocols bgp neighbor 100.66.24.36 remote-as '64513'
+set protocols bgp neighbor 100.66.24.37 peer-group 'AZURE'
+set protocols bgp neighbor 100.66.24.37 remote-as '64513'
+set protocols bgp neighbor 100.66.40.36 peer-group 'AZURE'
+set protocols bgp neighbor 100.66.40.36 remote-as '64515'
+set protocols bgp neighbor 100.66.40.37 peer-group 'AZURE'
+set protocols bgp neighbor 100.66.40.37 remote-as '64515'
+set protocols bgp neighbor 192.168.34.38 address-family ipv4-unicast nexthop-self
+set protocols bgp neighbor 192.168.34.38 address-family ipv4-unicast soft-reconfiguration inbound
+set protocols bgp neighbor 192.168.34.38 capability dynamic
+set protocols bgp neighbor 192.168.34.38 password 'VyOSR0xx123'
+set protocols bgp neighbor 192.168.34.38 remote-as '65522'
+set protocols bgp neighbor 192.168.34.38 update-source 'eth1'
+set protocols bgp peer-group AZURE address-family ipv4-unicast maximum-prefix '50'
+set protocols bgp peer-group AZURE address-family ipv4-unicast prefix-list export 'ONPREM-BGP-IPv4-out'
+set protocols bgp peer-group AZURE address-family ipv4-unicast prefix-list import 'AZURE-BGP-IPv4-in'
+set protocols bgp peer-group AZURE ebgp-multihop '2'
+set protocols bgp peer-group AZURE update-source 'eth1'
+set protocols bgp system-as '65522'
+set protocols bgp timers holdtime '30'
+set protocols bgp timers keepalive '5'
+set protocols static route 0.0.0.0/0 next-hop 192.168.34.33
+set protocols static route 51.105.0.0/16 next-hop 192.0.2.161
+set protocols static route 52.143.0.0/16 next-hop 192.0.2.161
+set protocols static route 100.66.8.36/32 interface vti31
+set protocols static route 100.66.8.36/32 interface vti32
+set protocols static route 100.66.8.37/32 interface vti31
+set protocols static route 100.66.8.37/32 interface vti32
+set protocols static route 100.66.24.36/32 interface vti41
+set protocols static route 100.66.24.36/32 interface vti42
+set protocols static route 100.66.24.37/32 interface vti41
+set protocols static route 100.66.24.37/32 interface vti42
+set protocols static route 100.66.40.36/32 interface vti51
+set protocols static route 100.66.40.36/32 interface vti52
+set protocols static route 100.66.40.37/32 interface vti51
+set protocols static route 100.66.40.37/32 interface vti52
+set protocols static route 195.137.175.0/24 next-hop 192.0.2.161
+set protocols static route 212.23.159.0/26 next-hop 192.0.2.161
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 192.0.2.254
+set service snmp v3 engineid 'ff42'
+set service snmp v3 group default mode 'ro'
+set service snmp v3 group default seclevel 'priv'
+set service snmp v3 group default view 'default'
+set service snmp v3 user VyOS auth encrypted-password '1ad73f4620b8c0dd2de066622f875b161a14adad'
+set service snmp v3 user VyOS auth type 'sha'
+set service snmp v3 user VyOS group 'default'
+set service snmp v3 user VyOS privacy encrypted-password '1ad73f4620b8c0dd2de066622f875b16'
+set service snmp v3 user VyOS privacy type 'aes'
+set service snmp v3 view default oid 1
+set service ssh disable-host-validation
+set service ssh port '22'
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system flow-accounting interface 'eth1'
+set system flow-accounting interface 'vti31'
+set system flow-accounting interface 'vti32'
+set system flow-accounting interface 'vti41'
+set system flow-accounting interface 'vti42'
+set system flow-accounting interface 'vti51'
+set system flow-accounting interface 'vti52'
+set system flow-accounting netflow server 10.0.1.1 port '2055'
+set system flow-accounting netflow source-address '192.168.34.37'
+set system flow-accounting netflow version '10'
+set system flow-accounting syslog-facility 'daemon'
+set system host-name 'azure-gw-01'
+set system login radius server 192.0.2.253 key 'secret1234'
+set system login radius server 192.0.2.253 port '1812'
+set system login radius server 192.0.2.253 timeout '2'
+set system login radius server 192.0.2.254 key 'secret1234'
+set system login radius server 192.0.2.254 port '1812'
+set system login radius server 192.0.2.254 timeout '2'
+set system login radius source-address '192.168.34.37'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system logs logrotate messages max-size '20'
+set system logs logrotate messages rotate '10'
+set system name-server '192.0.2.254'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system syslog host 10.0.9.188 facility all level 'info'
+set system syslog host 10.0.9.188 protocol 'udp'
+set system time-zone 'Europe/Berlin'
+set vpn ipsec authentication psk peer_51-105-0-1 id '51.105.0.1'
+set vpn ipsec authentication psk peer_51-105-0-1 id '192.0.2.189'
+set vpn ipsec authentication psk peer_51-105-0-1 secret 'averysecretpsktowardsazure'
+set vpn ipsec authentication psk peer_51-105-0-2 id '51.105.0.2'
+set vpn ipsec authentication psk peer_51-105-0-2 id '192.0.2.189'
+set vpn ipsec authentication psk peer_51-105-0-2 secret 'averysecretpsktowardsazure'
+set vpn ipsec authentication psk peer_51-105-0-3 id '51.105.0.3'
+set vpn ipsec authentication psk peer_51-105-0-3 id '192.0.2.189'
+set vpn ipsec authentication psk peer_51-105-0-3 secret 'averysecretpsktowardsazure'
+set vpn ipsec authentication psk peer_51-105-0-4 id '51.105.0.4'
+set vpn ipsec authentication psk peer_51-105-0-4 id '192.0.2.189'
+set vpn ipsec authentication psk peer_51-105-0-4 secret 'averysecretpsktowardsazure'
+set vpn ipsec authentication psk peer_51-105-0-5 id '51.105.0.5'
+set vpn ipsec authentication psk peer_51-105-0-5 id '192.0.2.189'
+set vpn ipsec authentication psk peer_51-105-0-5 secret 'averysecretpsktowardsazure'
+set vpn ipsec authentication psk peer_51-105-0-6 id '51.105.0.6'
+set vpn ipsec authentication psk peer_51-105-0-6 id '192.0.2.189'
+set vpn ipsec authentication psk peer_51-105-0-6 secret 'averysecretpsktowardsazure'
+set vpn ipsec esp-group ESP-AZURE lifetime '27000'
+set vpn ipsec esp-group ESP-AZURE mode 'tunnel'
+set vpn ipsec esp-group ESP-AZURE pfs 'disable'
+set vpn ipsec esp-group ESP-AZURE proposal 1 encryption 'aes256'
+set vpn ipsec esp-group ESP-AZURE proposal 1 hash 'sha1'
+set vpn ipsec ike-group IKE-AZURE close-action 'none'
+set vpn ipsec ike-group IKE-AZURE dead-peer-detection action 'restart'
+set vpn ipsec ike-group IKE-AZURE dead-peer-detection interval '2'
+set vpn ipsec ike-group IKE-AZURE dead-peer-detection timeout '15'
+set vpn ipsec ike-group IKE-AZURE key-exchange 'ikev2'
+set vpn ipsec ike-group IKE-AZURE lifetime '27000'
+set vpn ipsec ike-group IKE-AZURE proposal 1 dh-group '2'
+set vpn ipsec ike-group IKE-AZURE proposal 1 encryption 'aes256'
+set vpn ipsec ike-group IKE-AZURE proposal 1 hash 'sha1'
+set vpn ipsec interface 'eth0'
+set vpn ipsec log level '2'
+set vpn ipsec log subsystem 'ike'
+set vpn ipsec site-to-site peer peer_51-105-0-1 authentication mode 'pre-shared-secret'
+set vpn ipsec site-to-site peer peer_51-105-0-1 authentication remote-id '51.105.0.1'
+set vpn ipsec site-to-site peer peer_51-105-0-1 connection-type 'respond'
+set vpn ipsec site-to-site peer peer_51-105-0-1 default-esp-group 'ESP-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-1 ike-group 'IKE-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-1 ikev2-reauth 'inherit'
+set vpn ipsec site-to-site peer peer_51-105-0-1 local-address '192.0.2.189'
+set vpn ipsec site-to-site peer peer_51-105-0-1 remote-address '51.105.0.1'
+set vpn ipsec site-to-site peer peer_51-105-0-1 vti bind 'vti51'
+set vpn ipsec site-to-site peer peer_51-105-0-2 authentication mode 'pre-shared-secret'
+set vpn ipsec site-to-site peer peer_51-105-0-2 authentication remote-id '51.105.0.2'
+set vpn ipsec site-to-site peer peer_51-105-0-2 connection-type 'respond'
+set vpn ipsec site-to-site peer peer_51-105-0-2 default-esp-group 'ESP-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-2 ike-group 'IKE-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-2 ikev2-reauth 'inherit'
+set vpn ipsec site-to-site peer peer_51-105-0-2 local-address '192.0.2.189'
+set vpn ipsec site-to-site peer peer_51-105-0-2 remote-address '51.105.0.2'
+set vpn ipsec site-to-site peer peer_51-105-0-2 vti bind 'vti52'
+set vpn ipsec site-to-site peer peer_51-105-0-3 authentication mode 'pre-shared-secret'
+set vpn ipsec site-to-site peer peer_51-105-0-3 authentication remote-id '51.105.0.3'
+set vpn ipsec site-to-site peer peer_51-105-0-3 connection-type 'respond'
+set vpn ipsec site-to-site peer peer_51-105-0-3 ike-group 'IKE-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-3 ikev2-reauth 'inherit'
+set vpn ipsec site-to-site peer peer_51-105-0-3 local-address '192.0.2.189'
+set vpn ipsec site-to-site peer peer_51-105-0-3 remote-address '51.105.0.3'
+set vpn ipsec site-to-site peer peer_51-105-0-3 vti bind 'vti32'
+set vpn ipsec site-to-site peer peer_51-105-0-3 vti esp-group 'ESP-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-4 authentication mode 'pre-shared-secret'
+set vpn ipsec site-to-site peer peer_51-105-0-4 authentication remote-id '51.105.0.4'
+set vpn ipsec site-to-site peer peer_51-105-0-4 connection-type 'respond'
+set vpn ipsec site-to-site peer peer_51-105-0-4 ike-group 'IKE-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-4 ikev2-reauth 'inherit'
+set vpn ipsec site-to-site peer peer_51-105-0-4 local-address '192.0.2.189'
+set vpn ipsec site-to-site peer peer_51-105-0-4 remote-address '51.105.0.4'
+set vpn ipsec site-to-site peer peer_51-105-0-4 vti bind 'vti31'
+set vpn ipsec site-to-site peer peer_51-105-0-4 vti esp-group 'ESP-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-5 authentication mode 'pre-shared-secret'
+set vpn ipsec site-to-site peer peer_51-105-0-5 authentication remote-id '51.105.0.5'
+set vpn ipsec site-to-site peer peer_51-105-0-5 connection-type 'respond'
+set vpn ipsec site-to-site peer peer_51-105-0-5 ike-group 'IKE-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-5 ikev2-reauth 'inherit'
+set vpn ipsec site-to-site peer peer_51-105-0-5 local-address '192.0.2.189'
+set vpn ipsec site-to-site peer peer_51-105-0-5 remote-address '51.105.0.5'
+set vpn ipsec site-to-site peer peer_51-105-0-5 vti bind 'vti42'
+set vpn ipsec site-to-site peer peer_51-105-0-5 vti esp-group 'ESP-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-6 authentication mode 'pre-shared-secret'
+set vpn ipsec site-to-site peer peer_51-105-0-6 authentication remote-id '51.105.0.6'
+set vpn ipsec site-to-site peer peer_51-105-0-6 connection-type 'respond'
+set vpn ipsec site-to-site peer peer_51-105-0-6 ike-group 'IKE-AZURE'
+set vpn ipsec site-to-site peer peer_51-105-0-6 ikev2-reauth 'inherit'
+set vpn ipsec site-to-site peer peer_51-105-0-6 local-address '192.0.2.189'
+set vpn ipsec site-to-site peer peer_51-105-0-6 remote-address '51.105.0.6'
+set vpn ipsec site-to-site peer peer_51-105-0-6 vti bind 'vti41'
+set vpn ipsec site-to-site peer peer_51-105-0-6 vti esp-group 'ESP-AZURE'
diff --git a/smoketest/config-tests/bgp-bfd-communities b/smoketest/config-tests/bgp-bfd-communities
new file mode 100644
index 000000000..6eee0137e
--- /dev/null
+++ b/smoketest/config-tests/bgp-bfd-communities
@@ -0,0 +1,201 @@
+set interfaces ethernet eth0 address '192.0.2.100/25'
+set interfaces ethernet eth0 address '2001:db8::ffff/64'
+set interfaces ethernet eth0 offload gro
+set interfaces loopback lo
+set policy large-community-list ANYCAST_ALL rule 10 action 'permit'
+set policy large-community-list ANYCAST_ALL rule 10 description 'Allow all anycast from anywhere'
+set policy large-community-list ANYCAST_ALL rule 10 regex '4242420696:100:.*'
+set policy large-community-list ANYCAST_INT rule 10 action 'permit'
+set policy large-community-list ANYCAST_INT rule 10 description 'Allow all anycast from int'
+set policy large-community-list ANYCAST_INT rule 10 regex '4242420696:100:1'
+set policy prefix-list BGP-BACKBONE-IN description 'Inbound backbone routes from other sites'
+set policy prefix-list BGP-BACKBONE-IN rule 10 action 'deny'
+set policy prefix-list BGP-BACKBONE-IN rule 10 description 'Block default route'
+set policy prefix-list BGP-BACKBONE-IN rule 10 prefix '0.0.0.0/0'
+set policy prefix-list BGP-BACKBONE-IN rule 20 action 'deny'
+set policy prefix-list BGP-BACKBONE-IN rule 20 description 'Block int primary'
+set policy prefix-list BGP-BACKBONE-IN rule 20 ge '21'
+set policy prefix-list BGP-BACKBONE-IN rule 20 prefix '192.168.0.0/20'
+set policy prefix-list BGP-BACKBONE-IN rule 30 action 'deny'
+set policy prefix-list BGP-BACKBONE-IN rule 30 description 'Block loopbacks'
+set policy prefix-list BGP-BACKBONE-IN rule 30 ge '25'
+set policy prefix-list BGP-BACKBONE-IN rule 30 prefix '192.168.253.0/24'
+set policy prefix-list BGP-BACKBONE-IN rule 40 action 'deny'
+set policy prefix-list BGP-BACKBONE-IN rule 40 description 'Block backbone peering'
+set policy prefix-list BGP-BACKBONE-IN rule 40 ge '25'
+set policy prefix-list BGP-BACKBONE-IN rule 40 prefix '192.168.254.0/24'
+set policy prefix-list BGP-BACKBONE-IN rule 999 action 'permit'
+set policy prefix-list BGP-BACKBONE-IN rule 999 description 'Allow everything else'
+set policy prefix-list BGP-BACKBONE-IN rule 999 ge '1'
+set policy prefix-list BGP-BACKBONE-IN rule 999 prefix '0.0.0.0/0'
+set policy prefix-list BGP-BACKBONE-OUT description 'Outbound backbone routes to other sites'
+set policy prefix-list BGP-BACKBONE-OUT rule 10 action 'permit'
+set policy prefix-list BGP-BACKBONE-OUT rule 10 description 'Int primary'
+set policy prefix-list BGP-BACKBONE-OUT rule 10 ge '23'
+set policy prefix-list BGP-BACKBONE-OUT rule 10 prefix '192.168.0.0/20'
+set policy prefix-list GLOBAL description 'Globally redistributed routes'
+set policy prefix-list GLOBAL rule 10 action 'permit'
+set policy prefix-list GLOBAL rule 10 prefix '192.168.100.1/32'
+set policy prefix-list GLOBAL rule 20 action 'permit'
+set policy prefix-list GLOBAL rule 20 prefix '192.168.7.128/25'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 description 'Inbound backbone routes from other sites'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 10 action 'deny'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 10 description 'Block default route'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 10 prefix '::/0'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 20 action 'deny'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 20 description 'Block int primary'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 20 ge '53'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 20 prefix 'fd52:d62e:8011::/52'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 30 action 'deny'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 30 description 'Block peering and stuff'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 30 ge '53'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 30 prefix 'fd52:d62e:8011:f000::/52'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 999 action 'permit'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 999 description 'Allow everything else'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 999 ge '1'
+set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 999 prefix '::/0'
+set policy prefix-list6 BGP-BACKBONE-OUT-V6 description 'Outbound backbone routes to other sites'
+set policy prefix-list6 BGP-BACKBONE-OUT-V6 rule 10 action 'permit'
+set policy prefix-list6 BGP-BACKBONE-OUT-V6 rule 10 ge '64'
+set policy prefix-list6 BGP-BACKBONE-OUT-V6 rule 10 prefix 'fd52:d62e:8011::/52'
+set policy prefix-list6 GLOBAL-V6 description 'Globally redistributed routes'
+set policy prefix-list6 GLOBAL-V6 rule 10 action 'permit'
+set policy prefix-list6 GLOBAL-V6 rule 10 ge '64'
+set policy prefix-list6 GLOBAL-V6 rule 10 prefix 'fd52:d62e:8011:2::/63'
+set policy route-map BGP-BACKBONE-IN rule 10 action 'permit'
+set policy route-map BGP-BACKBONE-IN rule 10 match ip address prefix-list 'BGP-BACKBONE-IN'
+set policy route-map BGP-BACKBONE-IN rule 20 action 'permit'
+set policy route-map BGP-BACKBONE-IN rule 20 match ipv6 address prefix-list 'BGP-BACKBONE-IN-V6'
+set policy route-map BGP-BACKBONE-IN rule 30 action 'permit'
+set policy route-map BGP-BACKBONE-IN rule 30 match large-community large-community-list 'ANYCAST_ALL'
+set policy route-map BGP-BACKBONE-OUT rule 10 action 'permit'
+set policy route-map BGP-BACKBONE-OUT rule 10 match ip address prefix-list 'BGP-BACKBONE-OUT'
+set policy route-map BGP-BACKBONE-OUT rule 20 action 'permit'
+set policy route-map BGP-BACKBONE-OUT rule 20 match ipv6 address prefix-list 'BGP-BACKBONE-OUT-V6'
+set policy route-map BGP-BACKBONE-OUT rule 30 action 'permit'
+set policy route-map BGP-BACKBONE-OUT rule 30 match large-community large-community-list 'ANYCAST_INT'
+set policy route-map BGP-BACKBONE-OUT rule 30 set as-path prepend '4242420666'
+set policy route-map BGP-REDISTRIBUTE rule 10 action 'permit'
+set policy route-map BGP-REDISTRIBUTE rule 10 description 'Prepend AS and allow VPN and modem'
+set policy route-map BGP-REDISTRIBUTE rule 10 match ip address prefix-list 'GLOBAL'
+set policy route-map BGP-REDISTRIBUTE rule 10 set as-path prepend '4242420666'
+set policy route-map BGP-REDISTRIBUTE rule 20 action 'permit'
+set policy route-map BGP-REDISTRIBUTE rule 20 description 'Allow VPN'
+set policy route-map BGP-REDISTRIBUTE rule 20 match ipv6 address prefix-list 'GLOBAL-V6'
+set protocols bfd peer 192.168.253.1 interval receive '50'
+set protocols bfd peer 192.168.253.1 interval transmit '50'
+set protocols bfd peer 192.168.253.1 multihop
+set protocols bfd peer 192.168.253.1 source address '192.168.253.3'
+set protocols bfd peer 192.168.253.2 interval receive '50'
+set protocols bfd peer 192.168.253.2 interval transmit '50'
+set protocols bfd peer 192.168.253.2 multihop
+set protocols bfd peer 192.168.253.2 source address '192.168.253.3'
+set protocols bfd peer 192.168.253.6 interval receive '50'
+set protocols bfd peer 192.168.253.6 interval transmit '50'
+set protocols bfd peer 192.168.253.6 multihop
+set protocols bfd peer 192.168.253.6 source address '192.168.253.3'
+set protocols bfd peer 192.168.253.7 interval receive '50'
+set protocols bfd peer 192.168.253.7 interval transmit '50'
+set protocols bfd peer 192.168.253.7 multihop
+set protocols bfd peer 192.168.253.7 source address '192.168.253.3'
+set protocols bfd peer 192.168.253.12 interval receive '100'
+set protocols bfd peer 192.168.253.12 interval transmit '100'
+set protocols bfd peer 192.168.253.12 multihop
+set protocols bfd peer 192.168.253.12 source address '192.168.253.3'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:1 interval receive '50'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:1 interval transmit '50'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:1 multihop
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:1 source address 'fd52:d62e:8011:fffe:192:168:253:3'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:2 interval receive '50'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:2 interval transmit '50'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:2 multihop
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:2 source address 'fd52:d62e:8011:fffe:192:168:253:3'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:6 interval receive '50'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:6 interval transmit '50'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:6 multihop
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:6 source address 'fd52:d62e:8011:fffe:192:168:253:3'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:7 interval receive '50'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:7 interval transmit '50'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:7 multihop
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:7 source address 'fd52:d62e:8011:fffe:192:168:253:3'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:12 interval receive '100'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:12 interval transmit '100'
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:12 multihop
+set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:12 source address 'fd52:d62e:8011:fffe:192:168:253:3'
+set protocols bgp address-family ipv4-unicast redistribute connected route-map 'BGP-REDISTRIBUTE'
+set protocols bgp address-family ipv4-unicast redistribute static route-map 'BGP-REDISTRIBUTE'
+set protocols bgp address-family ipv6-unicast redistribute connected route-map 'BGP-REDISTRIBUTE'
+set protocols bgp neighbor 192.168.253.1 peer-group 'INT'
+set protocols bgp neighbor 192.168.253.2 peer-group 'INT'
+set protocols bgp neighbor 192.168.253.6 peer-group 'DAL13'
+set protocols bgp neighbor 192.168.253.7 peer-group 'DAL13'
+set protocols bgp neighbor 192.168.253.12 address-family ipv4-unicast route-map export 'BGP-BACKBONE-OUT'
+set protocols bgp neighbor 192.168.253.12 address-family ipv4-unicast route-map import 'BGP-BACKBONE-IN'
+set protocols bgp neighbor 192.168.253.12 address-family ipv4-unicast soft-reconfiguration inbound
+set protocols bgp neighbor 192.168.253.12 bfd
+set protocols bgp neighbor 192.168.253.12 ebgp-multihop '2'
+set protocols bgp neighbor 192.168.253.12 remote-as '4242420669'
+set protocols bgp neighbor 192.168.253.12 update-source 'dum0'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:1 peer-group 'INTv6'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:2 peer-group 'INTv6'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:6 peer-group 'DAL13v6'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:7 peer-group 'DAL13v6'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 address-family ipv6-unicast route-map export 'BGP-BACKBONE-OUT'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 address-family ipv6-unicast route-map import 'BGP-BACKBONE-IN'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 address-family ipv6-unicast soft-reconfiguration inbound
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 bfd
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 ebgp-multihop '2'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 remote-as '4242420669'
+set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 update-source 'dum0'
+set protocols bgp parameters confederation identifier '4242420696'
+set protocols bgp parameters confederation peers '4242420668'
+set protocols bgp parameters confederation peers '4242420669'
+set protocols bgp parameters distance global external '220'
+set protocols bgp parameters distance global internal '220'
+set protocols bgp parameters distance global local '220'
+set protocols bgp parameters graceful-restart
+set protocols bgp peer-group DAL13 address-family ipv4-unicast route-map export 'BGP-BACKBONE-OUT'
+set protocols bgp peer-group DAL13 address-family ipv4-unicast route-map import 'BGP-BACKBONE-IN'
+set protocols bgp peer-group DAL13 address-family ipv4-unicast soft-reconfiguration inbound
+set protocols bgp peer-group DAL13 bfd
+set protocols bgp peer-group DAL13 ebgp-multihop '2'
+set protocols bgp peer-group DAL13 remote-as '4242420668'
+set protocols bgp peer-group DAL13 update-source 'dum0'
+set protocols bgp peer-group DAL13v6 address-family ipv6-unicast route-map export 'BGP-BACKBONE-OUT'
+set protocols bgp peer-group DAL13v6 address-family ipv6-unicast route-map import 'BGP-BACKBONE-IN'
+set protocols bgp peer-group DAL13v6 address-family ipv6-unicast soft-reconfiguration inbound
+set protocols bgp peer-group DAL13v6 bfd
+set protocols bgp peer-group DAL13v6 ebgp-multihop '2'
+set protocols bgp peer-group DAL13v6 remote-as '4242420668'
+set protocols bgp peer-group DAL13v6 update-source 'dum0'
+set protocols bgp peer-group INT address-family ipv4-unicast default-originate
+set protocols bgp peer-group INT address-family ipv4-unicast soft-reconfiguration inbound
+set protocols bgp peer-group INT bfd
+set protocols bgp peer-group INT remote-as '4242420666'
+set protocols bgp peer-group INT update-source 'dum0'
+set protocols bgp peer-group INTv6 address-family ipv6-unicast default-originate
+set protocols bgp peer-group INTv6 address-family ipv6-unicast soft-reconfiguration inbound
+set protocols bgp peer-group INTv6 bfd
+set protocols bgp peer-group INTv6 remote-as '4242420666'
+set protocols bgp peer-group INTv6 update-source 'dum0'
+set protocols bgp system-as '4242420666'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set system config-management commit-revisions '200'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/bgp-big-as-cloud b/smoketest/config-tests/bgp-big-as-cloud
new file mode 100644
index 000000000..8de0cdb02
--- /dev/null
+++ b/smoketest/config-tests/bgp-big-as-cloud
@@ -0,0 +1,850 @@
+set firewall global-options all-ping 'enable'
+set firewall global-options broadcast-ping 'disable'
+set firewall global-options ip-src-route 'disable'
+set firewall global-options ipv6-receive-redirects 'disable'
+set firewall global-options ipv6-src-route 'disable'
+set firewall global-options log-martians 'enable'
+set firewall global-options receive-redirects 'disable'
+set firewall global-options send-redirects 'enable'
+set firewall global-options source-validation 'disable'
+set firewall global-options syn-cookies 'enable'
+set firewall global-options twa-hazards-protection 'disable'
+set firewall group address-group bgp-peers-4 address '192.0.68.3'
+set firewall group address-group bgp-peers-4 address '192.0.68.2'
+set firewall group address-group bgp-peers-4 address '192.0.176.193'
+set firewall group address-group bgp-peers-4 address '192.0.52.0-192.0.52.255'
+set firewall group address-group bgp-peers-4 address '192.0.53.0-192.0.53.255'
+set firewall group address-group bgp-peers-4 address '192.0.16.209'
+set firewall group address-group bgp-peers-4 address '192.0.192.0-192.0.192.255'
+set firewall group address-group bgp-peers-4 address '192.0.193.0-192.0.193.255'
+set firewall group address-group bgp-peers-4 address '192.0.194.0-192.0.194.255'
+set firewall group address-group bgp-peers-4 address '192.0.195.0-192.0.195.255'
+set firewall group address-group bgp-peers-4 address '192.0.196.0-192.0.196.255'
+set firewall group address-group bgp-peers-4 address '192.0.197.0-192.0.197.255'
+set firewall group address-group bgp-peers-4 address '192.0.198.0-192.0.198.255'
+set firewall group address-group bgp-peers-4 address '192.0.199.0-192.0.199.255'
+set firewall group address-group vrrp-peers-4 address '192.0.68.3'
+set firewall group address-group vrrp-peers-4 address '192.0.160.3'
+set firewall group address-group vrrp-peers-4 address '192.0.98.3'
+set firewall group address-group vrrp-peers-4 address '192.0.71.131'
+set firewall group address-group vrrp-peers-4 address '192.0.84.67'
+set firewall group address-group vrrp-peers-4 address '192.0.71.195'
+set firewall group address-group vrrp-peers-4 address '192.0.71.115'
+set firewall group address-group vrrp-peers-4 address '192.0.70.195'
+set firewall group address-group vrrp-peers-4 address '192.0.70.179'
+set firewall group address-group vrrp-peers-4 address '192.0.70.163'
+set firewall group address-group vrrp-peers-4 address '192.0.70.147'
+set firewall group address-group vrrp-peers-4 address '192.0.70.131'
+set firewall group address-group vrrp-peers-4 address '192.0.70.19'
+set firewall group address-group vrrp-peers-4 address '192.0.70.3'
+set firewall group address-group vrrp-peers-4 address '192.0.71.99'
+set firewall group address-group vrrp-peers-4 address '192.0.68.67'
+set firewall group address-group vrrp-peers-4 address '192.0.71.67'
+set firewall group address-group vrrp-peers-4 address '192.0.71.3'
+set firewall group address-group vrrp-peers-4 address '192.0.68.35'
+set firewall group address-group vrrp-peers-4 address '192.0.68.131'
+set firewall group address-group vrrp-peers-4 address '192.0.69.2'
+set firewall group address-group vrrp-peers-4 address '192.0.70.35'
+set firewall group address-group vrrp-peers-4 address '192.0.70.67'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:c::3'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:1000::2e9'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::fb'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::fc'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::fd'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::2e'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::3d'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::4a'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::5e'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::7'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::11'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::18'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::20'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::22'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::31'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::58'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::64'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::a5'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::aa'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::ab'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::b0'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::b3'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::bd'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::c'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::d2'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::d3'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:838::1'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::1a27:5051:c09d'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::1a27:5051:c19d'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::20ad:0:1'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2306:0:1'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2ca:0:1'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2ca:0:2'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2ca:0:3'
+set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2ca:0:4'
+set firewall group ipv6-address-group vrrp-peers-6 address 'fe80::fe89:15cf'
+set firewall group ipv6-network-group AS64512-6 network '2001::/29'
+set firewall group network-group AS64512-4 network '192.0.68.0/22'
+set firewall group network-group AS64512-4 network '192.0.98.0/24'
+set firewall group network-group AS64512-4 network '192.0.160.0/24'
+set firewall group network-group AS64512-4 network '192.0.84.0/22'
+set firewall ipv4 name management-to-local-4 default-action 'reject'
+set firewall ipv4 name management-to-local-4 default-log
+set firewall ipv4 name management-to-local-4 rule 500 action 'return'
+set firewall ipv4 name management-to-local-4 rule 500 protocol 'icmp'
+set firewall ipv4 name management-to-local-4 rule 501 action 'return'
+set firewall ipv4 name management-to-local-4 rule 501 destination port '22'
+set firewall ipv4 name management-to-local-4 rule 501 protocol 'tcp'
+set firewall ipv4 name management-to-local-4 rule 502 action 'return'
+set firewall ipv4 name management-to-local-4 rule 502 destination port 'snmp'
+set firewall ipv4 name management-to-local-4 rule 502 protocol 'udp'
+set firewall ipv4 name management-to-peers-4 default-action 'reject'
+set firewall ipv4 name management-to-peers-4 default-log
+set firewall ipv4 name management-to-servers-4 default-action 'reject'
+set firewall ipv4 name management-to-servers-4 default-log
+set firewall ipv4 name peers-to-local-4 default-action 'reject'
+set firewall ipv4 name peers-to-local-4 default-log
+set firewall ipv4 name peers-to-local-4 rule 500 action 'return'
+set firewall ipv4 name peers-to-local-4 rule 500 protocol 'icmp'
+set firewall ipv4 name peers-to-local-4 rule 501 action 'return'
+set firewall ipv4 name peers-to-local-4 rule 501 protocol 'vrrp'
+set firewall ipv4 name peers-to-local-4 rule 501 source group address-group 'vrrp-peers-4'
+set firewall ipv4 name peers-to-local-4 rule 502 action 'return'
+set firewall ipv4 name peers-to-local-4 rule 502 destination port 'bgp'
+set firewall ipv4 name peers-to-local-4 rule 502 protocol 'tcp'
+set firewall ipv4 name peers-to-local-4 rule 502 source group address-group 'bgp-peers-4'
+set firewall ipv4 name peers-to-local-4 rule 503 action 'return'
+set firewall ipv4 name peers-to-local-4 rule 503 protocol 'tcp'
+set firewall ipv4 name peers-to-local-4 rule 503 source group address-group 'bgp-peers-4'
+set firewall ipv4 name peers-to-local-4 rule 503 source port 'bgp'
+set firewall ipv4 name peers-to-management-4 default-action 'reject'
+set firewall ipv4 name peers-to-management-4 default-log
+set firewall ipv4 name peers-to-servers-4 default-action 'reject'
+set firewall ipv4 name peers-to-servers-4 default-log
+set firewall ipv4 name peers-to-servers-4 rule 9990 action 'reject'
+set firewall ipv4 name peers-to-servers-4 rule 9990 source group network-group 'AS64512-4'
+set firewall ipv4 name peers-to-servers-4 rule 9999 action 'return'
+set firewall ipv4 name peers-to-servers-4 rule 9999 destination group network-group 'AS64512-4'
+set firewall ipv4 name servers-to-local-4 default-action 'reject'
+set firewall ipv4 name servers-to-local-4 default-log
+set firewall ipv4 name servers-to-local-4 rule 500 action 'return'
+set firewall ipv4 name servers-to-local-4 rule 500 protocol 'icmp'
+set firewall ipv4 name servers-to-local-4 rule 501 action 'return'
+set firewall ipv4 name servers-to-local-4 rule 501 protocol 'vrrp'
+set firewall ipv4 name servers-to-local-4 rule 501 source group address-group 'vrrp-peers-4'
+set firewall ipv4 name servers-to-local-4 rule 511 action 'return'
+set firewall ipv4 name servers-to-local-4 rule 511 protocol 'tcp_udp'
+set firewall ipv4 name servers-to-local-4 rule 511 source port '53'
+set firewall ipv4 name servers-to-management-4 default-action 'reject'
+set firewall ipv4 name servers-to-management-4 default-log
+set firewall ipv4 name servers-to-peers-4 default-action 'reject'
+set firewall ipv4 name servers-to-peers-4 default-log
+set firewall ipv4 name servers-to-peers-4 rule 51 action 'return'
+set firewall ipv4 name servers-to-peers-4 rule 51 source group network-group 'AS64512-4'
+set firewall ipv6 name management-to-local-6 default-action 'reject'
+set firewall ipv6 name management-to-local-6 default-log
+set firewall ipv6 name management-to-peers-6 default-action 'reject'
+set firewall ipv6 name management-to-peers-6 default-log
+set firewall ipv6 name management-to-servers-6 default-action 'reject'
+set firewall ipv6 name management-to-servers-6 default-log
+set firewall ipv6 name peers-to-local-6 default-action 'reject'
+set firewall ipv6 name peers-to-local-6 default-log
+set firewall ipv6 name peers-to-local-6 rule 500 action 'return'
+set firewall ipv6 name peers-to-local-6 rule 500 protocol 'ipv6-icmp'
+set firewall ipv6 name peers-to-local-6 rule 501 action 'return'
+set firewall ipv6 name peers-to-local-6 rule 501 protocol 'vrrp'
+set firewall ipv6 name peers-to-local-6 rule 501 source group address-group 'vrrp-peers-6'
+set firewall ipv6 name peers-to-local-6 rule 502 action 'return'
+set firewall ipv6 name peers-to-local-6 rule 502 destination port 'bgp'
+set firewall ipv6 name peers-to-local-6 rule 502 protocol 'tcp'
+set firewall ipv6 name peers-to-local-6 rule 502 source group address-group 'bgp-peers-6'
+set firewall ipv6 name peers-to-local-6 rule 503 action 'return'
+set firewall ipv6 name peers-to-local-6 rule 503 protocol 'tcp'
+set firewall ipv6 name peers-to-local-6 rule 503 source group address-group 'bgp-peers-6'
+set firewall ipv6 name peers-to-local-6 rule 503 source port 'bgp'
+set firewall ipv6 name peers-to-management-6 default-action 'reject'
+set firewall ipv6 name peers-to-management-6 default-log
+set firewall ipv6 name peers-to-servers-6 default-action 'reject'
+set firewall ipv6 name peers-to-servers-6 default-log
+set firewall ipv6 name peers-to-servers-6 rule 9990 action 'reject'
+set firewall ipv6 name peers-to-servers-6 rule 9990 source group network-group 'AS64512-6'
+set firewall ipv6 name peers-to-servers-6 rule 9999 action 'return'
+set firewall ipv6 name peers-to-servers-6 rule 9999 destination group network-group 'AS64512-6'
+set firewall ipv6 name servers-to-local-6 default-action 'reject'
+set firewall ipv6 name servers-to-local-6 default-log
+set firewall ipv6 name servers-to-local-6 rule 500 action 'return'
+set firewall ipv6 name servers-to-local-6 rule 500 protocol 'ipv6-icmp'
+set firewall ipv6 name servers-to-local-6 rule 501 action 'return'
+set firewall ipv6 name servers-to-local-6 rule 501 protocol 'vrrp'
+set firewall ipv6 name servers-to-local-6 rule 501 source group address-group 'vrrp-peers-6'
+set firewall ipv6 name servers-to-local-6 rule 511 action 'return'
+set firewall ipv6 name servers-to-local-6 rule 511 protocol 'tcp_udp'
+set firewall ipv6 name servers-to-local-6 rule 511 source port '53'
+set firewall ipv6 name servers-to-management-6 default-action 'reject'
+set firewall ipv6 name servers-to-management-6 default-log
+set firewall ipv6 name servers-to-peers-6 default-action 'reject'
+set firewall ipv6 name servers-to-peers-6 default-log
+set firewall ipv6 name servers-to-peers-6 rule 51 action 'return'
+set firewall ipv6 name servers-to-peers-6 rule 51 source group network-group 'AS64512-6'
+set firewall zone local default-action 'drop'
+set firewall zone local from management firewall ipv6-name 'management-to-local-6'
+set firewall zone local from management firewall name 'management-to-local-4'
+set firewall zone local from peers firewall ipv6-name 'peers-to-local-6'
+set firewall zone local from peers firewall name 'peers-to-local-4'
+set firewall zone local from servers firewall ipv6-name 'servers-to-local-6'
+set firewall zone local from servers firewall name 'servers-to-local-4'
+set firewall zone local local-zone
+set firewall zone management default-action 'reject'
+set firewall zone management from peers firewall ipv6-name 'peers-to-management-6'
+set firewall zone management from peers firewall name 'peers-to-management-4'
+set firewall zone management from servers firewall ipv6-name 'servers-to-management-6'
+set firewall zone management from servers firewall name 'servers-to-management-4'
+set firewall zone management interface 'eth0'
+set firewall zone peers default-action 'reject'
+set firewall zone peers from management firewall ipv6-name 'management-to-peers-6'
+set firewall zone peers from management firewall name 'management-to-peers-4'
+set firewall zone peers from servers firewall ipv6-name 'servers-to-peers-6'
+set firewall zone peers from servers firewall name 'servers-to-peers-4'
+set firewall zone peers interface 'eth0.4088'
+set firewall zone peers interface 'eth0.4089'
+set firewall zone peers interface 'eth0.11'
+set firewall zone peers interface 'eth0.838'
+set firewall zone peers interface 'eth0.886'
+set firewall zone servers default-action 'reject'
+set firewall zone servers from management firewall ipv6-name 'management-to-servers-6'
+set firewall zone servers from management firewall name 'management-to-servers-4'
+set firewall zone servers from peers firewall ipv6-name 'peers-to-servers-6'
+set firewall zone servers from peers firewall name 'peers-to-servers-4'
+set firewall zone servers interface 'eth0.1001'
+set firewall zone servers interface 'eth0.105'
+set firewall zone servers interface 'eth0.102'
+set firewall zone servers interface 'eth0.1019'
+set firewall zone servers interface 'eth0.1014'
+set firewall zone servers interface 'eth0.1020'
+set firewall zone servers interface 'eth0.1018'
+set firewall zone servers interface 'eth0.1013'
+set firewall zone servers interface 'eth0.1012'
+set firewall zone servers interface 'eth0.1011'
+set firewall zone servers interface 'eth0.1010'
+set firewall zone servers interface 'eth0.1009'
+set firewall zone servers interface 'eth0.1006'
+set firewall zone servers interface 'eth0.1005'
+set firewall zone servers interface 'eth0.1017'
+set firewall zone servers interface 'eth0.1016'
+set firewall zone servers interface 'eth0.1002'
+set firewall zone servers interface 'eth0.1015'
+set firewall zone servers interface 'eth0.1003'
+set firewall zone servers interface 'eth0.1004'
+set firewall zone servers interface 'eth0.1007'
+set firewall zone servers interface 'eth0.1008'
+set high-availability vrrp group 11-4 address 192.0.68.1/27
+set high-availability vrrp group 11-4 interface 'eth0.11'
+set high-availability vrrp group 11-4 priority '200'
+set high-availability vrrp group 11-4 vrid '4'
+set high-availability vrrp group 11-6 address 2001:db8:c::1/64
+set high-availability vrrp group 11-6 interface 'eth0.11'
+set high-availability vrrp group 11-6 priority '200'
+set high-availability vrrp group 11-6 vrid '6'
+set high-availability vrrp group 102-4 address 192.0.98.1/24
+set high-availability vrrp group 102-4 interface 'eth0.102'
+set high-availability vrrp group 102-4 priority '200'
+set high-availability vrrp group 102-4 vrid '4'
+set high-availability vrrp group 102-6 address 2001:db8:0:102::1/64
+set high-availability vrrp group 102-6 interface 'eth0.102'
+set high-availability vrrp group 102-6 priority '200'
+set high-availability vrrp group 102-6 vrid '6'
+set high-availability vrrp group 105-4 address 192.0.160.1/24
+set high-availability vrrp group 105-4 interface 'eth0.105'
+set high-availability vrrp group 105-4 priority '200'
+set high-availability vrrp group 105-4 vrid '4'
+set high-availability vrrp group 105-6 address 2001:db8:0:105::1/64
+set high-availability vrrp group 105-6 interface 'eth0.105'
+set high-availability vrrp group 105-6 priority '200'
+set high-availability vrrp group 105-6 vrid '6'
+set high-availability vrrp group 1001-4 address 192.0.68.33/27
+set high-availability vrrp group 1001-4 interface 'eth0.1001'
+set high-availability vrrp group 1001-4 priority '200'
+set high-availability vrrp group 1001-4 vrid '4'
+set high-availability vrrp group 1001-6 address 2001:db8:0:1001::1/64
+set high-availability vrrp group 1001-6 interface 'eth0.1001'
+set high-availability vrrp group 1001-6 priority '200'
+set high-availability vrrp group 1001-6 vrid '6'
+set high-availability vrrp group 1002-4 address 192.0.68.65/26
+set high-availability vrrp group 1002-4 interface 'eth0.1002'
+set high-availability vrrp group 1002-4 priority '200'
+set high-availability vrrp group 1002-4 vrid '4'
+set high-availability vrrp group 1002-6 address 2001:db8:0:1002::1/64
+set high-availability vrrp group 1002-6 interface 'eth0.1002'
+set high-availability vrrp group 1002-6 priority '200'
+set high-availability vrrp group 1002-6 vrid '6'
+set high-availability vrrp group 1003-4 address 192.0.68.129/25
+set high-availability vrrp group 1003-4 interface 'eth0.1003'
+set high-availability vrrp group 1003-4 priority '200'
+set high-availability vrrp group 1003-4 vrid '4'
+set high-availability vrrp group 1003-6 address 2001:db8:0:1003::1/64
+set high-availability vrrp group 1003-6 interface 'eth0.1003'
+set high-availability vrrp group 1003-6 priority '200'
+set high-availability vrrp group 1003-6 vrid '6'
+set high-availability vrrp group 1004-4 address 192.0.69.1/24
+set high-availability vrrp group 1004-4 interface 'eth0.1004'
+set high-availability vrrp group 1004-4 priority '200'
+set high-availability vrrp group 1004-4 vrid '4'
+set high-availability vrrp group 1004-6 address 2001:db8:0:1004::1/64
+set high-availability vrrp group 1004-6 interface 'eth0.1004'
+set high-availability vrrp group 1004-6 priority '200'
+set high-availability vrrp group 1004-6 vrid '6'
+set high-availability vrrp group 1005-4 address 192.0.70.1/28
+set high-availability vrrp group 1005-4 interface 'eth0.1005'
+set high-availability vrrp group 1005-4 priority '200'
+set high-availability vrrp group 1005-4 vrid '4'
+set high-availability vrrp group 1005-6 address 2001:db8:0:1005::1/64
+set high-availability vrrp group 1005-6 interface 'eth0.1005'
+set high-availability vrrp group 1005-6 priority '200'
+set high-availability vrrp group 1005-6 vrid '6'
+set high-availability vrrp group 1006-4 address 192.0.70.17/28
+set high-availability vrrp group 1006-4 interface 'eth0.1006'
+set high-availability vrrp group 1006-4 priority '200'
+set high-availability vrrp group 1006-4 vrid '4'
+set high-availability vrrp group 1006-6 address 2001:db8:0:1006::1/64
+set high-availability vrrp group 1006-6 interface 'eth0.1006'
+set high-availability vrrp group 1006-6 priority '200'
+set high-availability vrrp group 1006-6 vrid '6'
+set high-availability vrrp group 1007-4 address 192.0.70.33/27
+set high-availability vrrp group 1007-4 interface 'eth0.1007'
+set high-availability vrrp group 1007-4 priority '200'
+set high-availability vrrp group 1007-4 vrid '4'
+set high-availability vrrp group 1007-6 address 2001:db8:0:1007::1/64
+set high-availability vrrp group 1007-6 interface 'eth0.1007'
+set high-availability vrrp group 1007-6 priority '200'
+set high-availability vrrp group 1007-6 vrid '6'
+set high-availability vrrp group 1008-4 address 192.0.70.65/26
+set high-availability vrrp group 1008-4 interface 'eth0.1008'
+set high-availability vrrp group 1008-4 priority '200'
+set high-availability vrrp group 1008-4 vrid '4'
+set high-availability vrrp group 1008-6 address 2001:db8:0:1008::1/64
+set high-availability vrrp group 1008-6 interface 'eth0.1008'
+set high-availability vrrp group 1008-6 priority '200'
+set high-availability vrrp group 1008-6 vrid '6'
+set high-availability vrrp group 1009-4 address 192.0.70.129/28
+set high-availability vrrp group 1009-4 interface 'eth0.1009'
+set high-availability vrrp group 1009-4 priority '200'
+set high-availability vrrp group 1009-4 vrid '4'
+set high-availability vrrp group 1009-6 address 2001:db8:0:1009::1/64
+set high-availability vrrp group 1009-6 interface 'eth0.1009'
+set high-availability vrrp group 1009-6 priority '200'
+set high-availability vrrp group 1009-6 vrid '6'
+set high-availability vrrp group 1010-4 address 192.0.70.145/28
+set high-availability vrrp group 1010-4 interface 'eth0.1010'
+set high-availability vrrp group 1010-4 priority '200'
+set high-availability vrrp group 1010-4 vrid '4'
+set high-availability vrrp group 1010-6 address 2001:db8:0:1010::1/64
+set high-availability vrrp group 1010-6 interface 'eth0.1010'
+set high-availability vrrp group 1010-6 priority '200'
+set high-availability vrrp group 1010-6 vrid '6'
+set high-availability vrrp group 1011-4 address 192.0.70.161/28
+set high-availability vrrp group 1011-4 interface 'eth0.1011'
+set high-availability vrrp group 1011-4 priority '200'
+set high-availability vrrp group 1011-4 vrid '4'
+set high-availability vrrp group 1011-6 address 2001:db8:0:1011::1/64
+set high-availability vrrp group 1011-6 interface 'eth0.1011'
+set high-availability vrrp group 1011-6 priority '200'
+set high-availability vrrp group 1011-6 vrid '6'
+set high-availability vrrp group 1012-4 address 192.0.70.177/28
+set high-availability vrrp group 1012-4 interface 'eth0.1012'
+set high-availability vrrp group 1012-4 priority '200'
+set high-availability vrrp group 1012-4 vrid '4'
+set high-availability vrrp group 1012-6 address 2001:db8:0:1012::1/64
+set high-availability vrrp group 1012-6 interface 'eth0.1012'
+set high-availability vrrp group 1012-6 priority '200'
+set high-availability vrrp group 1012-6 vrid '6'
+set high-availability vrrp group 1013-4 address 192.0.70.193/27
+set high-availability vrrp group 1013-4 interface 'eth0.1013'
+set high-availability vrrp group 1013-4 priority '200'
+set high-availability vrrp group 1013-4 vrid '4'
+set high-availability vrrp group 1013-6 address 2001:db8:0:1013::1/64
+set high-availability vrrp group 1013-6 interface 'eth0.1013'
+set high-availability vrrp group 1013-6 priority '200'
+set high-availability vrrp group 1013-6 vrid '6'
+set high-availability vrrp group 1014-4 address 192.0.84.65/26
+set high-availability vrrp group 1014-4 interface 'eth0.1014'
+set high-availability vrrp group 1014-4 priority '200'
+set high-availability vrrp group 1014-4 vrid '4'
+set high-availability vrrp group 1014-6 address 2001:db8:0:1014::1/64
+set high-availability vrrp group 1014-6 interface 'eth0.1014'
+set high-availability vrrp group 1014-6 priority '200'
+set high-availability vrrp group 1014-6 vrid '6'
+set high-availability vrrp group 1015-4 address 192.0.71.1/26
+set high-availability vrrp group 1015-4 interface 'eth0.1015'
+set high-availability vrrp group 1015-4 priority '200'
+set high-availability vrrp group 1015-4 vrid '4'
+set high-availability vrrp group 1015-6 address 2001:db8:0:1015::1/64
+set high-availability vrrp group 1015-6 interface 'eth0.1015'
+set high-availability vrrp group 1015-6 priority '200'
+set high-availability vrrp group 1015-6 vrid '6'
+set high-availability vrrp group 1016-4 address 192.0.71.65/27
+set high-availability vrrp group 1016-4 interface 'eth0.1016'
+set high-availability vrrp group 1016-4 priority '200'
+set high-availability vrrp group 1016-4 vrid '4'
+set high-availability vrrp group 1016-6 address 2001:db8:0:1016::1/64
+set high-availability vrrp group 1016-6 interface 'eth0.1016'
+set high-availability vrrp group 1016-6 priority '200'
+set high-availability vrrp group 1016-6 vrid '6'
+set high-availability vrrp group 1017-4 address 192.0.71.97/28
+set high-availability vrrp group 1017-4 interface 'eth0.1017'
+set high-availability vrrp group 1017-4 priority '200'
+set high-availability vrrp group 1017-4 vrid '4'
+set high-availability vrrp group 1017-6 address 2001:db8:0:1017::1/64
+set high-availability vrrp group 1017-6 interface 'eth0.1017'
+set high-availability vrrp group 1017-6 priority '200'
+set high-availability vrrp group 1017-6 vrid '6'
+set high-availability vrrp group 1018-4 address 192.0.71.113/28
+set high-availability vrrp group 1018-4 interface 'eth0.1018'
+set high-availability vrrp group 1018-4 priority '200'
+set high-availability vrrp group 1018-4 vrid '4'
+set high-availability vrrp group 1018-6 address 2001:db8:0:1018::1/64
+set high-availability vrrp group 1018-6 interface 'eth0.1018'
+set high-availability vrrp group 1018-6 priority '200'
+set high-availability vrrp group 1018-6 vrid '6'
+set high-availability vrrp group 1019-4 address 192.0.71.129/26
+set high-availability vrrp group 1019-4 interface 'eth0.1019'
+set high-availability vrrp group 1019-4 priority '200'
+set high-availability vrrp group 1019-4 vrid '4'
+set high-availability vrrp group 1019-6 address 2001:db8:0:1019::1/64
+set high-availability vrrp group 1019-6 interface 'eth0.1019'
+set high-availability vrrp group 1019-6 priority '200'
+set high-availability vrrp group 1019-6 vrid '6'
+set high-availability vrrp group 1020-4 address 192.0.71.193/26
+set high-availability vrrp group 1020-4 interface 'eth0.1020'
+set high-availability vrrp group 1020-4 priority '200'
+set high-availability vrrp group 1020-4 vrid '4'
+set high-availability vrrp group 1020-6 address 2001:db8:0:1020::1/64
+set high-availability vrrp group 1020-6 interface 'eth0.1020'
+set high-availability vrrp group 1020-6 priority '200'
+set high-availability vrrp group 1020-6 vrid '6'
+set interfaces ethernet eth0 address '192.0.0.11/16'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth0 vif 11 address '192.0.68.2/27'
+set interfaces ethernet eth0 vif 11 address '2001:db8:c::2/64'
+set interfaces ethernet eth0 vif 102 address '192.0.98.2/24'
+set interfaces ethernet eth0 vif 102 address '2001:db8:0:102::2/64'
+set interfaces ethernet eth0 vif 105 address '192.0.160.2/24'
+set interfaces ethernet eth0 vif 105 address '2001:db8:0:105::2/64'
+set interfaces ethernet eth0 vif 838 address '192.0.16.210/30'
+set interfaces ethernet eth0 vif 838 address '2001:db8:838::2/64'
+set interfaces ethernet eth0 vif 886 address '192.0.193.224/21'
+set interfaces ethernet eth0 vif 886 address '2001:db8::3:669:0:1/64'
+set interfaces ethernet eth0 vif 1001 address '192.0.68.34/27'
+set interfaces ethernet eth0 vif 1001 address '2001:db8:0:1001::2/64'
+set interfaces ethernet eth0 vif 1002 address '192.0.68.66/26'
+set interfaces ethernet eth0 vif 1002 address '2001:db8:0:1002::2/64'
+set interfaces ethernet eth0 vif 1003 address '192.0.68.130/25'
+set interfaces ethernet eth0 vif 1003 address '2001:db8:0:1003::2/64'
+set interfaces ethernet eth0 vif 1004 address '192.0.69.2/24'
+set interfaces ethernet eth0 vif 1004 address '2001:db8:0:1004::2/64'
+set interfaces ethernet eth0 vif 1005 address '192.0.70.2/28'
+set interfaces ethernet eth0 vif 1005 address '2001:db8:0:1005::2/64'
+set interfaces ethernet eth0 vif 1006 address '192.0.70.18/28'
+set interfaces ethernet eth0 vif 1006 address '2001:db8:0:1006::2/64'
+set interfaces ethernet eth0 vif 1007 address '192.0.70.34/27'
+set interfaces ethernet eth0 vif 1007 address '2001:db8:0:1007::2/64'
+set interfaces ethernet eth0 vif 1008 address '192.0.70.66/26'
+set interfaces ethernet eth0 vif 1008 address '2001:db8:0:1008::2/64'
+set interfaces ethernet eth0 vif 1009 address '192.0.70.130/28'
+set interfaces ethernet eth0 vif 1009 address '2001:db8:0:1009::2/64'
+set interfaces ethernet eth0 vif 1010 address '192.0.70.146/28'
+set interfaces ethernet eth0 vif 1010 address '2001:db8:0:1010::2/64'
+set interfaces ethernet eth0 vif 1011 address '192.0.70.162/28'
+set interfaces ethernet eth0 vif 1011 address '2001:db8:0:1011::2/64'
+set interfaces ethernet eth0 vif 1012 address '192.0.70.178/28'
+set interfaces ethernet eth0 vif 1012 address '2001:db8:0:1012::2/64'
+set interfaces ethernet eth0 vif 1013 address '192.0.70.194/27'
+set interfaces ethernet eth0 vif 1013 address '2001:db8:0:1013::3/64'
+set interfaces ethernet eth0 vif 1014 address '192.0.84.66/26'
+set interfaces ethernet eth0 vif 1014 address '2001:db8:0:1014::2/64'
+set interfaces ethernet eth0 vif 1015 address '192.0.71.2/26'
+set interfaces ethernet eth0 vif 1015 address '2001:db8:0:1015::2/64'
+set interfaces ethernet eth0 vif 1016 address '192.0.71.66/27'
+set interfaces ethernet eth0 vif 1016 address '2001:db8:0:1016::2/64'
+set interfaces ethernet eth0 vif 1017 address '192.0.71.98/28'
+set interfaces ethernet eth0 vif 1017 address '2001:db8:0:1017::2/64'
+set interfaces ethernet eth0 vif 1018 address '192.0.71.114/28'
+set interfaces ethernet eth0 vif 1018 address '2001:db8:0:1018::2/64'
+set interfaces ethernet eth0 vif 1019 address '192.0.71.130/26'
+set interfaces ethernet eth0 vif 1019 address '2001:db8:0:1019::2/64'
+set interfaces ethernet eth0 vif 1020 address '192.0.71.194/26'
+set interfaces ethernet eth0 vif 1020 address '2001:db8:0:1020::2/64'
+set interfaces ethernet eth0 vif 4088 address '2001:db8:24::c7/64'
+set interfaces ethernet eth0 vif 4088 address '192.0.52.199/23'
+set interfaces ethernet eth0 vif 4089 address '192.0.176.194/30'
+set interfaces ethernet eth0 vif 4089 address '2001:db8:1000::2ea/126'
+set interfaces loopback lo
+set policy as-path-list AS64512 rule 10 action 'permit'
+set policy as-path-list AS64512 rule 10 regex '^$'
+set policy as-path-list AS64513-AS64514 rule 10 action 'permit'
+set policy as-path-list AS64513-AS64514 rule 10 regex '^64513 64514$'
+set policy prefix-list defaultV4 rule 10 action 'permit'
+set policy prefix-list defaultV4 rule 10 prefix '0.0.0.0/0'
+set policy prefix-list hostrouteV4 rule 10 action 'permit'
+set policy prefix-list hostrouteV4 rule 10 ge '32'
+set policy prefix-list hostrouteV4 rule 10 prefix '192.0.160.0/24'
+set policy prefix-list hostrouteV4 rule 20 action 'permit'
+set policy prefix-list hostrouteV4 rule 20 ge '32'
+set policy prefix-list hostrouteV4 rule 20 prefix '192.0.98.0/24'
+set policy prefix-list hostrouteV4 rule 30 action 'permit'
+set policy prefix-list hostrouteV4 rule 30 ge '32'
+set policy prefix-list hostrouteV4 rule 30 prefix '192.0.68.0/22'
+set policy prefix-list hostrouteV4 rule 40 action 'permit'
+set policy prefix-list hostrouteV4 rule 40 ge '32'
+set policy prefix-list hostrouteV4 rule 40 prefix '192.0.84.0/22'
+set policy prefix-list privateV4 rule 10 action 'permit'
+set policy prefix-list privateV4 rule 10 le '32'
+set policy prefix-list privateV4 rule 10 prefix '192.0.0.0/8'
+set policy prefix-list privateV4 rule 20 action 'permit'
+set policy prefix-list privateV4 rule 20 le '32'
+set policy prefix-list privateV4 rule 20 prefix '192.0.0.0/12'
+set policy prefix-list privateV4 rule 30 action 'permit'
+set policy prefix-list privateV4 rule 30 le '32'
+set policy prefix-list privateV4 rule 30 prefix '192.0.0.0/16'
+set policy prefix-list vyosV4 rule 10 action 'permit'
+set policy prefix-list vyosV4 rule 10 prefix '192.0.160.0/24'
+set policy prefix-list vyosV4 rule 20 action 'permit'
+set policy prefix-list vyosV4 rule 20 prefix '192.0.98.0/24'
+set policy prefix-list vyosV4 rule 30 action 'permit'
+set policy prefix-list vyosV4 rule 30 prefix '192.0.68.0/22'
+set policy prefix-list vyosV4 rule 40 action 'permit'
+set policy prefix-list vyosV4 rule 40 prefix '192.0.84.0/22'
+set policy prefix-list6 all6 rule 10 action 'permit'
+set policy prefix-list6 all6 rule 10 ge '4'
+set policy prefix-list6 all6 rule 10 prefix '2000::/3'
+set policy prefix-list6 hostrouteV6 rule 20 action 'permit'
+set policy prefix-list6 hostrouteV6 rule 20 ge '128'
+set policy prefix-list6 hostrouteV6 rule 20 prefix '2001:db8::/29'
+set policy prefix-list6 privateV6 rule 10 action 'permit'
+set policy prefix-list6 privateV6 rule 10 prefix 'fc00::/7'
+set policy prefix-list6 vyosV6 rule 20 action 'permit'
+set policy prefix-list6 vyosV6 rule 20 prefix '2001:db8::/29'
+set policy route-map ExportRouteMap rule 5 action 'permit'
+set policy route-map ExportRouteMap rule 5 match as-path 'AS64512'
+set policy route-map ExportRouteMap rule 5 match ip address prefix-list 'hostrouteV4'
+set policy route-map ExportRouteMap rule 5 set community replace '65000:666'
+set policy route-map ExportRouteMap rule 10 action 'permit'
+set policy route-map ExportRouteMap rule 10 match as-path 'AS64512'
+set policy route-map ExportRouteMap rule 10 match ip address prefix-list 'vyosV4'
+set policy route-map ExportRouteMap rule 15 action 'permit'
+set policy route-map ExportRouteMap rule 15 match as-path 'AS64512'
+set policy route-map ExportRouteMap rule 15 match ipv6 address prefix-list 'hostrouteV6'
+set policy route-map ExportRouteMap rule 15 set community replace '65000:666'
+set policy route-map ExportRouteMap rule 20 action 'permit'
+set policy route-map ExportRouteMap rule 20 match as-path 'AS64512'
+set policy route-map ExportRouteMap rule 20 match ipv6 address prefix-list 'vyosV6'
+set policy route-map ExportRouteMap rule 100 action 'deny'
+set policy route-map ExportRouteMapAS64513 rule 5 action 'permit'
+set policy route-map ExportRouteMapAS64513 rule 5 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64513 rule 5 match ip address prefix-list 'hostrouteV4'
+set policy route-map ExportRouteMapAS64513 rule 5 set community replace '64513:666'
+set policy route-map ExportRouteMapAS64513 rule 10 action 'permit'
+set policy route-map ExportRouteMapAS64513 rule 10 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64513 rule 10 match ip address prefix-list 'vyosV4'
+set policy route-map ExportRouteMapAS64513 rule 15 action 'permit'
+set policy route-map ExportRouteMapAS64513 rule 15 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64513 rule 15 match ipv6 address prefix-list 'hostrouteV6'
+set policy route-map ExportRouteMapAS64513 rule 15 set community replace '64513:666'
+set policy route-map ExportRouteMapAS64513 rule 20 action 'permit'
+set policy route-map ExportRouteMapAS64513 rule 20 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64513 rule 20 match ipv6 address prefix-list 'vyosV6'
+set policy route-map ExportRouteMapAS64513 rule 100 action 'deny'
+set policy route-map ExportRouteMapAS64515 rule 10 action 'permit'
+set policy route-map ExportRouteMapAS64515 rule 10 match ipv6 address prefix-list 'all6'
+set policy route-map ExportRouteMapAS64515 rule 20 action 'deny'
+set policy route-map ExportRouteMapAS64515 rule 20 match ip address prefix-list 'defaultV4'
+set policy route-map ExportRouteMapAS64515 rule 100 action 'deny'
+set policy route-map ExportRouteMapAS64516 rule 5 action 'permit'
+set policy route-map ExportRouteMapAS64516 rule 5 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64516 rule 5 match ip address prefix-list 'hostrouteV4'
+set policy route-map ExportRouteMapAS64516 rule 5 set community replace '65000:666'
+set policy route-map ExportRouteMapAS64516 rule 10 action 'permit'
+set policy route-map ExportRouteMapAS64516 rule 10 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64516 rule 10 match ip address prefix-list 'vyosV4'
+set policy route-map ExportRouteMapAS64516 rule 15 action 'permit'
+set policy route-map ExportRouteMapAS64516 rule 15 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64516 rule 15 match ipv6 address prefix-list 'hostrouteV6'
+set policy route-map ExportRouteMapAS64516 rule 15 set community replace '65000:666'
+set policy route-map ExportRouteMapAS64516 rule 20 action 'permit'
+set policy route-map ExportRouteMapAS64516 rule 20 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64516 rule 20 match ipv6 address prefix-list 'vyosV6'
+set policy route-map ExportRouteMapAS64516 rule 20 set as-path exclude '100 200 300'
+set policy route-map ExportRouteMapAS64516 rule 20 set as-path prepend '64512 64512 64512'
+set policy route-map ExportRouteMapAS64516 rule 100 action 'deny'
+set policy route-map ExportRouteMapAS64517 rule 5 action 'permit'
+set policy route-map ExportRouteMapAS64517 rule 5 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64517 rule 5 match ip address prefix-list 'hostrouteV4'
+set policy route-map ExportRouteMapAS64517 rule 5 set community replace '64517:666'
+set policy route-map ExportRouteMapAS64517 rule 10 action 'permit'
+set policy route-map ExportRouteMapAS64517 rule 10 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64517 rule 10 match ip address prefix-list 'vyosV4'
+set policy route-map ExportRouteMapAS64517 rule 15 action 'permit'
+set policy route-map ExportRouteMapAS64517 rule 15 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64517 rule 15 match ipv6 address prefix-list 'hostrouteV6'
+set policy route-map ExportRouteMapAS64517 rule 15 set community replace '64517:666'
+set policy route-map ExportRouteMapAS64517 rule 20 action 'permit'
+set policy route-map ExportRouteMapAS64517 rule 20 match as-path 'AS64512'
+set policy route-map ExportRouteMapAS64517 rule 20 match ipv6 address prefix-list 'vyosV6'
+set policy route-map ExportRouteMapAS64517 rule 100 action 'deny'
+set policy route-map ImportRouteMap rule 10 action 'deny'
+set policy route-map ImportRouteMap rule 10 match ip address prefix-list 'privateV4'
+set policy route-map ImportRouteMap rule 15 action 'deny'
+set policy route-map ImportRouteMap rule 15 match ipv6 address prefix-list 'privateV6'
+set policy route-map ImportRouteMap rule 20 action 'deny'
+set policy route-map ImportRouteMap rule 20 match ip address prefix-list 'vyosV4'
+set policy route-map ImportRouteMap rule 30 action 'deny'
+set policy route-map ImportRouteMap rule 30 match ipv6 address prefix-list 'vyosV6'
+set policy route-map ImportRouteMap rule 40 action 'deny'
+set policy route-map ImportRouteMap rule 40 match as-path 'AS64512'
+set policy route-map ImportRouteMap rule 50 action 'permit'
+set policy route-map ImportRouteMap rule 50 match as-path 'AS64513-AS64514'
+set policy route-map ImportRouteMap rule 50 set weight '10001'
+set policy route-map ImportRouteMap rule 65535 action 'permit'
+set protocols bgp address-family ipv4-unicast maximum-paths ebgp '8'
+set protocols bgp address-family ipv4-unicast maximum-paths ibgp '16'
+set protocols bgp address-family ipv4-unicast network 192.0.68.0/22
+set protocols bgp address-family ipv4-unicast network 192.0.84.0/22
+set protocols bgp address-family ipv4-unicast network 192.0.98.0/24
+set protocols bgp address-family ipv4-unicast network 192.0.160.0/24
+set protocols bgp address-family ipv4-unicast redistribute static route-map 'ExportRouteMap'
+set protocols bgp address-family ipv6-unicast network 2001:db8::/29
+set protocols bgp address-family ipv6-unicast redistribute static route-map 'ExportRouteMap'
+set protocols bgp neighbor 192.0.16.209 address-family ipv4-unicast route-map export 'ExportRouteMapAS64516'
+set protocols bgp neighbor 192.0.16.209 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.16.209 remote-as '64501'
+set protocols bgp neighbor 192.0.52.12 address-family ipv4-unicast maximum-prefix '300'
+set protocols bgp neighbor 192.0.52.12 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.12 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.12 remote-as '64511'
+set protocols bgp neighbor 192.0.52.17 address-family ipv4-unicast maximum-prefix '75'
+set protocols bgp neighbor 192.0.52.17 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.17 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.17 password 'vyosvyos'
+set protocols bgp neighbor 192.0.52.17 remote-as '64512'
+set protocols bgp neighbor 192.0.52.24 address-family ipv4-unicast maximum-prefix '300'
+set protocols bgp neighbor 192.0.52.24 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.24 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.24 remote-as '64513'
+set protocols bgp neighbor 192.0.52.32 address-family ipv4-unicast maximum-prefix '50'
+set protocols bgp neighbor 192.0.52.32 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.32 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.32 password 'vyosfoooo'
+set protocols bgp neighbor 192.0.52.32 remote-as '64514'
+set protocols bgp neighbor 192.0.52.34 address-family ipv4-unicast maximum-prefix '10'
+set protocols bgp neighbor 192.0.52.34 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.34 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.34 remote-as '64515'
+set protocols bgp neighbor 192.0.52.46 address-family ipv4-unicast maximum-prefix '10'
+set protocols bgp neighbor 192.0.52.46 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.46 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.46 remote-as '64516'
+set protocols bgp neighbor 192.0.52.49 address-family ipv4-unicast maximum-prefix '75'
+set protocols bgp neighbor 192.0.52.49 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.49 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.49 password 'secret'
+set protocols bgp neighbor 192.0.52.49 remote-as '64517'
+set protocols bgp neighbor 192.0.52.74 address-family ipv4-unicast maximum-prefix '15000'
+set protocols bgp neighbor 192.0.52.74 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.74 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.74 password 'secretvyos'
+set protocols bgp neighbor 192.0.52.74 remote-as '64518'
+set protocols bgp neighbor 192.0.52.94 address-family ipv4-unicast maximum-prefix '250'
+set protocols bgp neighbor 192.0.52.94 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.94 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.94 remote-as '64519'
+set protocols bgp neighbor 192.0.52.100 address-family ipv4-unicast maximum-prefix '50'
+set protocols bgp neighbor 192.0.52.100 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.100 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.100 remote-as '64520'
+set protocols bgp neighbor 192.0.52.119 address-family ipv4-unicast maximum-prefix '30'
+set protocols bgp neighbor 192.0.52.119 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.119 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.119 remote-as '64521'
+set protocols bgp neighbor 192.0.52.165 address-family ipv4-unicast maximum-prefix '50'
+set protocols bgp neighbor 192.0.52.165 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.165 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.165 remote-as '64522'
+set protocols bgp neighbor 192.0.52.170 address-family ipv4-unicast maximum-prefix '150000'
+set protocols bgp neighbor 192.0.52.170 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.170 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.170 remote-as '64523'
+set protocols bgp neighbor 192.0.52.171 address-family ipv4-unicast maximum-prefix '10000'
+set protocols bgp neighbor 192.0.52.171 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.171 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.171 remote-as '64524'
+set protocols bgp neighbor 192.0.52.179 address-family ipv4-unicast maximum-prefix '20'
+set protocols bgp neighbor 192.0.52.179 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.179 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.179 remote-as '64525'
+set protocols bgp neighbor 192.0.52.189 address-family ipv4-unicast maximum-prefix '1000'
+set protocols bgp neighbor 192.0.52.189 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.189 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.189 remote-as '64526'
+set protocols bgp neighbor 192.0.52.210 address-family ipv4-unicast maximum-prefix '15'
+set protocols bgp neighbor 192.0.52.210 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.210 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.210 remote-as '64527'
+set protocols bgp neighbor 192.0.52.211 address-family ipv4-unicast maximum-prefix '15'
+set protocols bgp neighbor 192.0.52.211 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.211 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.211 remote-as '64528'
+set protocols bgp neighbor 192.0.52.251 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.251 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.251 address-family ipv4-unicast weight '1010'
+set protocols bgp neighbor 192.0.52.251 remote-as '64529'
+set protocols bgp neighbor 192.0.52.252 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.52.252 address-family ipv4-unicast weight '1010'
+set protocols bgp neighbor 192.0.52.252 remote-as '64530'
+set protocols bgp neighbor 192.0.52.253 address-family ipv4-unicast route-map export 'ExportRouteMapAS64515'
+set protocols bgp neighbor 192.0.52.253 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.52.253 passive
+set protocols bgp neighbor 192.0.52.253 remote-as '64531'
+set protocols bgp neighbor 192.0.68.3 address-family ipv4-unicast nexthop-self
+set protocols bgp neighbor 192.0.68.3 address-family ipv4-unicast soft-reconfiguration inbound
+set protocols bgp neighbor 192.0.68.3 remote-as '64532'
+set protocols bgp neighbor 192.0.68.3 update-source '192.0.68.2'
+set protocols bgp neighbor 192.0.176.193 address-family ipv4-unicast route-map export 'ExportRouteMapAS64516'
+set protocols bgp neighbor 192.0.176.193 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.176.193 remote-as '64510'
+set protocols bgp neighbor 192.0.192.6 address-family ipv4-unicast maximum-prefix '100'
+set protocols bgp neighbor 192.0.192.6 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.192.6 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.192.6 remote-as '64502'
+set protocols bgp neighbor 192.0.192.157 address-family ipv4-unicast maximum-prefix '350000'
+set protocols bgp neighbor 192.0.192.157 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.192.157 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.192.157 remote-as '64503'
+set protocols bgp neighbor 192.0.192.228 address-family ipv4-unicast maximum-prefix '10000'
+set protocols bgp neighbor 192.0.192.228 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.192.228 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.192.228 remote-as '64504'
+set protocols bgp neighbor 192.0.193.157 address-family ipv4-unicast maximum-prefix '350000'
+set protocols bgp neighbor 192.0.193.157 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.193.157 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.193.157 remote-as '64505'
+set protocols bgp neighbor 192.0.193.202 address-family ipv4-unicast maximum-prefix '10000'
+set protocols bgp neighbor 192.0.193.202 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.193.202 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.193.202 remote-as '64506'
+set protocols bgp neighbor 192.0.193.223 address-family ipv4-unicast maximum-prefix '10000'
+set protocols bgp neighbor 192.0.193.223 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.193.223 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.193.223 remote-as '64507'
+set protocols bgp neighbor 192.0.194.161 address-family ipv4-unicast maximum-prefix '10000'
+set protocols bgp neighbor 192.0.194.161 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.194.161 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.194.161 remote-as '64508'
+set protocols bgp neighbor 192.0.194.171 address-family ipv4-unicast maximum-prefix '10000'
+set protocols bgp neighbor 192.0.194.171 address-family ipv4-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 192.0.194.171 address-family ipv4-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 192.0.194.171 remote-as '64509'
+set protocols bgp neighbor 2001:db8:24::2e address-family ipv6-unicast maximum-prefix '5'
+set protocols bgp neighbor 2001:db8:24::2e address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::2e address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::2e password 'vyossecret'
+set protocols bgp neighbor 2001:db8:24::2e remote-as '64535'
+set protocols bgp neighbor 2001:db8:24::4a address-family ipv6-unicast maximum-prefix '1000'
+set protocols bgp neighbor 2001:db8:24::4a address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::4a address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::4a remote-as '64536'
+set protocols bgp neighbor 2001:db8:24::5e address-family ipv6-unicast maximum-prefix '200'
+set protocols bgp neighbor 2001:db8:24::5e address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::5e address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::5e remote-as '64537'
+set protocols bgp neighbor 2001:db8:24::11 address-family ipv6-unicast maximum-prefix '20'
+set protocols bgp neighbor 2001:db8:24::11 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::11 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::11 remote-as '64538'
+set protocols bgp neighbor 2001:db8:24::18 address-family ipv6-unicast maximum-prefix '300'
+set protocols bgp neighbor 2001:db8:24::18 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::18 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::18 remote-as '64539'
+set protocols bgp neighbor 2001:db8:24::20 address-family ipv6-unicast maximum-prefix '10'
+set protocols bgp neighbor 2001:db8:24::20 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::20 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::20 remote-as '64540'
+set protocols bgp neighbor 2001:db8:24::22 address-family ipv6-unicast maximum-prefix '5'
+set protocols bgp neighbor 2001:db8:24::22 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::22 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::22 remote-as '64541'
+set protocols bgp neighbor 2001:db8:24::31 address-family ipv6-unicast maximum-prefix '20'
+set protocols bgp neighbor 2001:db8:24::31 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::31 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::31 remote-as '64542'
+set protocols bgp neighbor 2001:db8:24::58 address-family ipv6-unicast maximum-prefix '15'
+set protocols bgp neighbor 2001:db8:24::58 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::58 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::58 remote-as '64543'
+set protocols bgp neighbor 2001:db8:24::64 address-family ipv6-unicast maximum-prefix '10'
+set protocols bgp neighbor 2001:db8:24::64 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::64 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::64 password 'geheim'
+set protocols bgp neighbor 2001:db8:24::64 remote-as '64544'
+set protocols bgp neighbor 2001:db8:24::a5 address-family ipv6-unicast maximum-prefix '10'
+set protocols bgp neighbor 2001:db8:24::a5 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::a5 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::a5 remote-as '64545'
+set protocols bgp neighbor 2001:db8:24::aa address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::aa address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::aa remote-as '64546'
+set protocols bgp neighbor 2001:db8:24::ab address-family ipv6-unicast maximum-prefix '1800'
+set protocols bgp neighbor 2001:db8:24::ab address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::ab address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::ab remote-as '64547'
+set protocols bgp neighbor 2001:db8:24::b0 address-family ipv6-unicast maximum-prefix '5'
+set protocols bgp neighbor 2001:db8:24::b0 address-family ipv6-unicast route-map export 'ExportRouteMap'
+set protocols bgp neighbor 2001:db8:24::b0 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:24::b0 password 'secret123'
+set protocols bgp neighbor 2001:db8:24::b0 remote-as '64548'
+set protocols bgp neighbor 2001:db8:838::1 address-family ipv6-unicast route-map export 'ExportRouteMapAS64516'
+set protocols bgp neighbor 2001:db8:838::1 address-family ipv6-unicast route-map import 'ImportRouteMap'
+set protocols bgp neighbor 2001:db8:838::1 remote-as '64533'
+set protocols bgp neighbor 2001:db8:c::3 address-family ipv6-unicast nexthop-self
+set protocols bgp neighbor 2001:db8:c::3 address-family ipv6-unicast soft-reconfiguration inbound
+set protocols bgp neighbor 2001:db8:c::3 remote-as '64534'
+set protocols bgp neighbor 2001:db8:c::3 update-source '2001:db8:c::2'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp parameters router-id '192.0.68.2'
+set protocols bgp system-as '64500'
+set protocols static route 192.0.68.0/22 blackhole
+set protocols static route 192.0.84.0/22 blackhole
+set protocols static route 192.0.98.0/24 blackhole
+set protocols static route 192.0.160.0/24 blackhole
+set protocols static route6 2001:db8::/29 blackhole
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system flow-accounting disable-imt
+set system flow-accounting interface 'eth0.4088'
+set system flow-accounting interface 'eth0.4089'
+set system flow-accounting netflow engine-id '1'
+set system flow-accounting netflow server 192.0.2.55 port '2055'
+set system flow-accounting netflow version '9'
+set system flow-accounting sflow server 1.2.3.4 port '1234'
+set system flow-accounting syslog-facility 'daemon'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system name-server '2001:db8::1'
+set system name-server '2001:db8::2'
+set system name-server '192.0.2.1'
+set system name-server '192.0.2.2'
+set system syslog global facility all level 'all'
+set system syslog global preserve-fqdn
+set system time-zone 'Europe/Zurich'
diff --git a/smoketest/config-tests/bgp-dmvpn-hub b/smoketest/config-tests/bgp-dmvpn-hub
new file mode 100644
index 000000000..30521520a
--- /dev/null
+++ b/smoketest/config-tests/bgp-dmvpn-hub
@@ -0,0 +1,69 @@
+set interfaces ethernet eth0 address '100.64.10.1/31'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces loopback lo
+set interfaces tunnel tun0 address '192.168.254.62/26'
+set interfaces tunnel tun0 enable-multicast
+set interfaces tunnel tun0 encapsulation 'gre'
+set interfaces tunnel tun0 parameters ip key '1'
+set interfaces tunnel tun0 source-address '100.64.10.1'
+set protocols bgp address-family ipv4-unicast network 172.20.0.0/16
+set protocols bgp neighbor 192.168.254.1 peer-group 'DMVPN'
+set protocols bgp neighbor 192.168.254.1 remote-as '65001'
+set protocols bgp neighbor 192.168.254.2 peer-group 'DMVPN'
+set protocols bgp neighbor 192.168.254.2 remote-as '65002'
+set protocols bgp neighbor 192.168.254.3 peer-group 'DMVPN'
+set protocols bgp neighbor 192.168.254.3 remote-as '65003'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp peer-group DMVPN address-family ipv4-unicast
+set protocols bgp system-as '65000'
+set protocols bgp timers holdtime '30'
+set protocols bgp timers keepalive '10'
+set protocols nhrp tunnel tun0 cisco-authentication 'secret'
+set protocols nhrp tunnel tun0 holding-time '300'
+set protocols nhrp tunnel tun0 multicast 'dynamic'
+set protocols nhrp tunnel tun0 redirect
+set protocols nhrp tunnel tun0 shortcut
+set protocols static route 0.0.0.0/0 next-hop 100.64.10.0
+set protocols static route 172.20.0.0/16 blackhole distance '200'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service ntp server time3.vyos.net
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'cpe-4'
+set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
+set system login user vyos authentication plaintext-password ''
+set system name-server '1.1.1.1'
+set system name-server '8.8.8.8'
+set system name-server '9.9.9.9'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set vpn ipsec esp-group ESP-DMVPN lifetime '1800'
+set vpn ipsec esp-group ESP-DMVPN mode 'transport'
+set vpn ipsec esp-group ESP-DMVPN pfs 'dh-group2'
+set vpn ipsec esp-group ESP-DMVPN proposal 1 encryption 'aes256'
+set vpn ipsec esp-group ESP-DMVPN proposal 1 hash 'sha1'
+set vpn ipsec ike-group IKE-DMVPN close-action 'none'
+set vpn ipsec ike-group IKE-DMVPN key-exchange 'ikev1'
+set vpn ipsec ike-group IKE-DMVPN lifetime '3600'
+set vpn ipsec ike-group IKE-DMVPN proposal 1 dh-group '2'
+set vpn ipsec ike-group IKE-DMVPN proposal 1 encryption 'aes256'
+set vpn ipsec ike-group IKE-DMVPN proposal 1 hash 'sha1'
+set vpn ipsec interface 'eth0'
+set vpn ipsec profile NHRPVPN authentication mode 'pre-shared-secret'
+set vpn ipsec profile NHRPVPN authentication pre-shared-secret 'VyOS-topsecret'
+set vpn ipsec profile NHRPVPN bind tunnel 'tun0'
+set vpn ipsec profile NHRPVPN esp-group 'ESP-DMVPN'
+set vpn ipsec profile NHRPVPN ike-group 'IKE-DMVPN'
diff --git a/smoketest/config-tests/bgp-dmvpn-spoke b/smoketest/config-tests/bgp-dmvpn-spoke
new file mode 100644
index 000000000..d1c7bc7c0
--- /dev/null
+++ b/smoketest/config-tests/bgp-dmvpn-spoke
@@ -0,0 +1,75 @@
+set interfaces ethernet eth0 vif 7 description 'PPPoE-UPLINK'
+set interfaces ethernet eth1 address '172.17.1.1/24'
+set interfaces loopback lo
+set interfaces pppoe pppoe1 authentication password 'cpe-1'
+set interfaces pppoe pppoe1 authentication username 'cpe-1'
+set interfaces pppoe pppoe1 no-peer-dns
+set interfaces pppoe pppoe1 source-interface 'eth0.7'
+set interfaces tunnel tun0 address '192.168.254.1/26'
+set interfaces tunnel tun0 enable-multicast
+set interfaces tunnel tun0 encapsulation 'gre'
+set interfaces tunnel tun0 parameters ip key '1'
+set interfaces tunnel tun0 source-address '0.0.0.0'
+set nat source rule 10 log
+set nat source rule 10 outbound-interface name 'pppoe1'
+set nat source rule 10 source address '172.17.0.0/16'
+set nat source rule 10 translation address 'masquerade'
+set protocols bgp address-family ipv4-unicast network 172.17.0.0/16
+set protocols bgp neighbor 192.168.254.62 address-family ipv4-unicast
+set protocols bgp neighbor 192.168.254.62 remote-as '65000'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp system-as '65001'
+set protocols bgp timers holdtime '30'
+set protocols bgp timers keepalive '10'
+set protocols nhrp tunnel tun0 cisco-authentication 'secret'
+set protocols nhrp tunnel tun0 holding-time '300'
+set protocols nhrp tunnel tun0 map 192.168.254.62/26 nbma-address '100.64.10.1'
+set protocols nhrp tunnel tun0 map 192.168.254.62/26 register
+set protocols nhrp tunnel tun0 multicast 'nhs'
+set protocols nhrp tunnel tun0 redirect
+set protocols nhrp tunnel tun0 shortcut
+set protocols static route 172.17.0.0/16 blackhole distance '200'
+set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 option default-router '172.17.1.1'
+set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 option name-server '172.17.1.1'
+set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 range 0 start '172.17.1.100'
+set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 range 0 stop '172.17.1.200'
+set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 subnet-id '1'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service ntp server time3.vyos.net
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'cpe-1'
+set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
+set system login user vyos authentication plaintext-password ''
+set system name-server '1.1.1.1'
+set system name-server '8.8.8.8'
+set system name-server '9.9.9.9'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set vpn ipsec esp-group ESP-DMVPN lifetime '1800'
+set vpn ipsec esp-group ESP-DMVPN mode 'transport'
+set vpn ipsec esp-group ESP-DMVPN pfs 'dh-group2'
+set vpn ipsec esp-group ESP-DMVPN proposal 1 encryption 'aes256'
+set vpn ipsec esp-group ESP-DMVPN proposal 1 hash 'sha1'
+set vpn ipsec ike-group IKE-DMVPN close-action 'none'
+set vpn ipsec ike-group IKE-DMVPN key-exchange 'ikev1'
+set vpn ipsec ike-group IKE-DMVPN lifetime '3600'
+set vpn ipsec ike-group IKE-DMVPN proposal 1 dh-group '2'
+set vpn ipsec ike-group IKE-DMVPN proposal 1 encryption 'aes256'
+set vpn ipsec ike-group IKE-DMVPN proposal 1 hash 'sha1'
+set vpn ipsec interface 'pppoe1'
+set vpn ipsec profile NHRPVPN authentication mode 'pre-shared-secret'
+set vpn ipsec profile NHRPVPN authentication pre-shared-secret 'VyOS-topsecret'
+set vpn ipsec profile NHRPVPN bind tunnel 'tun0'
+set vpn ipsec profile NHRPVPN esp-group 'ESP-DMVPN'
+set vpn ipsec profile NHRPVPN ike-group 'IKE-DMVPN'
diff --git a/smoketest/config-tests/bgp-evpn-l2vpn-leaf b/smoketest/config-tests/bgp-evpn-l2vpn-leaf
new file mode 100644
index 000000000..315cb9e06
--- /dev/null
+++ b/smoketest/config-tests/bgp-evpn-l2vpn-leaf
@@ -0,0 +1,55 @@
+set interfaces bridge br100 member interface eth3
+set interfaces bridge br100 member interface vxlan100
+set interfaces dummy dum0 address '172.29.0.1/32'
+set interfaces ethernet eth0 address '2001:db8::41/64'
+set interfaces ethernet eth0 address '192.0.2.41/27'
+set interfaces ethernet eth0 description 'Out-of-Band Managament Port'
+set interfaces ethernet eth0 vrf 'MGMT'
+set interfaces ethernet eth1 address '172.29.1.1/31'
+set interfaces ethernet eth1 mtu '1600'
+set interfaces ethernet eth2 address '172.29.2.1/31'
+set interfaces ethernet eth2 mtu '1600'
+set interfaces ethernet eth2 offload gro
+set interfaces ethernet eth3 offload gro
+set interfaces loopback lo
+set interfaces vxlan vxlan100 mtu '1500'
+set interfaces vxlan vxlan100 parameters nolearning
+set interfaces vxlan vxlan100 port '8472'
+set interfaces vxlan vxlan100 source-address '172.29.0.1'
+set interfaces vxlan vxlan100 vni '100'
+set protocols bgp address-family ipv4-unicast maximum-paths ibgp '4'
+set protocols bgp address-family ipv4-unicast redistribute connected
+set protocols bgp address-family l2vpn-evpn advertise-all-vni
+set protocols bgp neighbor 172.29.1.0 peer-group 'evpn'
+set protocols bgp neighbor 172.29.2.0 peer-group 'evpn'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp peer-group evpn address-family ipv4-unicast nexthop-self
+set protocols bgp peer-group evpn address-family l2vpn-evpn nexthop-self
+set protocols bgp peer-group evpn remote-as '65010'
+set protocols bgp system-as '65010'
+set service lldp interface all
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp listen-address '192.0.2.41'
+set service ntp listen-address '2001:db8::41'
+set service ntp server 0.de.pool.ntp.org prefer
+set service ntp vrf 'MGMT'
+set service ssh disable-host-validation
+set service ssh vrf 'MGMT'
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set vrf name MGMT protocols static route 0.0.0.0/0 next-hop 192.0.2.62
+set vrf name MGMT protocols static route6 ::/0 next-hop 2001:db8::1
+set vrf name MGMT table '1000'
diff --git a/smoketest/config-tests/bgp-evpn-l2vpn-spine b/smoketest/config-tests/bgp-evpn-l2vpn-spine
new file mode 100644
index 000000000..dee29e021
--- /dev/null
+++ b/smoketest/config-tests/bgp-evpn-l2vpn-spine
@@ -0,0 +1,48 @@
+set interfaces ethernet eth0 address '192.0.2.51/27'
+set interfaces ethernet eth0 address '2001:db8::51/64'
+set interfaces ethernet eth0 description 'Out-of-Band Managament Port'
+set interfaces ethernet eth0 vrf 'MGMT'
+set interfaces ethernet eth1 address '172.29.1.0/31'
+set interfaces ethernet eth1 mtu '1600'
+set interfaces ethernet eth2 address '172.29.1.2/31'
+set interfaces ethernet eth2 mtu '1600'
+set interfaces ethernet eth2 offload gro
+set interfaces ethernet eth3 address '172.29.1.4/31'
+set interfaces ethernet eth3 mtu '1600'
+set interfaces ethernet eth3 offload gro
+set interfaces loopback lo
+set protocols bgp address-family ipv4-unicast maximum-paths ibgp '4'
+set protocols bgp address-family ipv4-unicast redistribute connected
+set protocols bgp listen range 172.29.1.0/24 peer-group 'evpn'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp peer-group evpn address-family ipv4-unicast route-reflector-client
+set protocols bgp peer-group evpn address-family l2vpn-evpn route-reflector-client
+set protocols bgp peer-group evpn capability dynamic
+set protocols bgp peer-group evpn remote-as '65010'
+set protocols bgp system-as '65010'
+set service lldp interface all
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp listen-address '192.0.2.51'
+set service ntp listen-address '2001:db8::51'
+set service ntp server 0.de.pool.ntp.org prefer
+set service ntp vrf 'MGMT'
+set service ssh disable-host-validation
+set service ssh vrf 'MGMT'
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set vrf name MGMT protocols static route 0.0.0.0/0 next-hop 192.0.2.62
+set vrf name MGMT protocols static route6 ::/0 next-hop 2001:db8::1
+set vrf name MGMT table '1000'
diff --git a/smoketest/config-tests/bgp-evpn-l3vpn-pe-router b/smoketest/config-tests/bgp-evpn-l3vpn-pe-router
new file mode 100644
index 000000000..7a2ec9f91
--- /dev/null
+++ b/smoketest/config-tests/bgp-evpn-l3vpn-pe-router
@@ -0,0 +1,123 @@
+set interfaces bridge br2000 address '10.1.1.1/24'
+set interfaces bridge br2000 description 'customer blue'
+set interfaces bridge br2000 member interface eth4
+set interfaces bridge br2000 member interface vxlan2000
+set interfaces bridge br2000 vrf 'blue'
+set interfaces bridge br3000 address '10.2.1.1/24'
+set interfaces bridge br3000 description 'customer red'
+set interfaces bridge br3000 member interface eth5
+set interfaces bridge br3000 member interface vxlan3000
+set interfaces bridge br3000 vrf 'red'
+set interfaces bridge br4000 address '10.3.1.1/24'
+set interfaces bridge br4000 description 'customer green'
+set interfaces bridge br4000 member interface eth6
+set interfaces bridge br4000 member interface vxlan4000
+set interfaces bridge br4000 vrf 'green'
+set interfaces dummy dum0 address '172.29.255.1/32'
+set interfaces ethernet eth0 address '192.0.2.59/27'
+set interfaces ethernet eth0 address '2001:db8:ffff::59/64'
+set interfaces ethernet eth0 description 'Out-of-Band Managament Port'
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth0 vrf 'mgmt'
+set interfaces ethernet eth1 address '172.29.0.2/31'
+set interfaces ethernet eth1 description 'link to pe2'
+set interfaces ethernet eth1 mtu '1600'
+set interfaces ethernet eth1 offload gro
+set interfaces ethernet eth2 disable
+set interfaces ethernet eth2 offload gro
+set interfaces ethernet eth3 address '172.29.0.6/31'
+set interfaces ethernet eth3 description 'link to pe3'
+set interfaces ethernet eth3 mtu '1600'
+set interfaces ethernet eth3 offload gro
+set interfaces ethernet eth4 description 'customer blue'
+set interfaces ethernet eth4 offload gro
+set interfaces ethernet eth5 description 'customer red'
+set interfaces ethernet eth5 offload gro
+set interfaces ethernet eth6 description 'customer green'
+set interfaces ethernet eth6 offload gro
+set interfaces loopback lo
+set interfaces vxlan vxlan2000 mtu '1500'
+set interfaces vxlan vxlan2000 parameters nolearning
+set interfaces vxlan vxlan2000 port '4789'
+set interfaces vxlan vxlan2000 source-address '172.29.255.1'
+set interfaces vxlan vxlan2000 vni '2000'
+set interfaces vxlan vxlan3000 mtu '1500'
+set interfaces vxlan vxlan3000 parameters nolearning
+set interfaces vxlan vxlan3000 port '4789'
+set interfaces vxlan vxlan3000 source-address '172.29.255.1'
+set interfaces vxlan vxlan3000 vni '3000'
+set interfaces vxlan vxlan4000 mtu '1500'
+set interfaces vxlan vxlan4000 parameters nolearning
+set interfaces vxlan vxlan4000 port '4789'
+set interfaces vxlan vxlan4000 source-address '172.29.255.1'
+set interfaces vxlan vxlan4000 vni '4000'
+set protocols bgp address-family l2vpn-evpn advertise ipv4 unicast
+set protocols bgp address-family l2vpn-evpn advertise-all-vni
+set protocols bgp neighbor 172.29.255.2 peer-group 'ibgp'
+set protocols bgp neighbor 172.29.255.3 peer-group 'ibgp'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp parameters router-id '172.29.255.1'
+set protocols bgp peer-group ibgp address-family l2vpn-evpn
+set protocols bgp peer-group ibgp remote-as '100'
+set protocols bgp peer-group ibgp update-source 'dum0'
+set protocols bgp system-as '100'
+set protocols ospf area 0 network '172.29.0.2/31'
+set protocols ospf area 0 network '172.29.0.6/31'
+set protocols ospf interface eth1 network 'point-to-point'
+set protocols ospf interface eth1 passive disable
+set protocols ospf interface eth3 network 'point-to-point'
+set protocols ospf interface eth3 passive disable
+set protocols ospf log-adjacency-changes detail
+set protocols ospf parameters abr-type 'cisco'
+set protocols ospf parameters router-id '172.29.255.1'
+set protocols ospf passive-interface 'default'
+set protocols ospf redistribute connected
+set service lldp interface all
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp listen-address '192.0.2.59'
+set service ntp listen-address '2001:db8:ffff::59'
+set service ntp server 192.0.2.251
+set service ntp server 192.0.2.252
+set service ntp server 2001:db8::251
+set service ntp server 2001:db8::252
+set service ntp vrf 'mgmt'
+set service ssh disable-host-validation
+set service ssh port '22'
+set service ssh vrf 'mgmt'
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system name-server '192.0.2.251'
+set system name-server '192.0.2.252'
+set system name-server '2001:db8::1'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set vrf name blue protocols bgp address-family ipv4-unicast redistribute connected
+set vrf name blue protocols bgp address-family l2vpn-evpn advertise ipv4 unicast
+set vrf name blue protocols bgp system-as '100'
+set vrf name blue table '2000'
+set vrf name blue vni '2000'
+set vrf name green protocols bgp address-family ipv4-unicast redistribute connected
+set vrf name green protocols bgp address-family l2vpn-evpn advertise ipv4 unicast
+set vrf name green protocols bgp system-as '100'
+set vrf name green table '4000'
+set vrf name green vni '4000'
+set vrf name mgmt protocols static route 0.0.0.0/0 next-hop 192.0.2.62
+set vrf name mgmt protocols static route6 ::/0 next-hop 2001:db8:ffff::1
+set vrf name mgmt table '1000'
+set vrf name red protocols bgp address-family ipv4-unicast redistribute connected
+set vrf name red protocols bgp address-family l2vpn-evpn advertise ipv4 unicast
+set vrf name red protocols bgp system-as '100'
+set vrf name red table '3000'
+set vrf name red vni '3000'
diff --git a/smoketest/config-tests/bgp-medium-confederation b/smoketest/config-tests/bgp-medium-confederation
index ea3c2d144..582e28047 100644
--- a/smoketest/config-tests/bgp-medium-confederation
+++ b/smoketest/config-tests/bgp-medium-confederation
@@ -1,7 +1,7 @@
set interfaces dummy dum0 address '1.1.1.1/32'
set interfaces dummy dum0 address '2001:db8::1/128'
-set interfaces ethernet eth0 address 'fd52:100:200:fffe::1/64'
set interfaces ethernet eth0 address '192.168.253.1/24'
+set interfaces ethernet eth0 address 'fd52:100:200:fffe::1/64'
set interfaces ethernet eth1
set interfaces ethernet eth2
set policy route-map BGP-IN rule 10 action 'permit'
diff --git a/smoketest/config-tests/bgp-rpki b/smoketest/config-tests/bgp-rpki
new file mode 100644
index 000000000..44e95ae98
--- /dev/null
+++ b/smoketest/config-tests/bgp-rpki
@@ -0,0 +1,43 @@
+set interfaces ethernet eth0 address '192.0.2.100/25'
+set interfaces ethernet eth0 address '2001:db8::ffff/64'
+set interfaces ethernet eth1 address '100.64.0.1/24'
+set interfaces loopback lo
+set policy route-map ebgp-transit-rpki rule 10 action 'deny'
+set policy route-map ebgp-transit-rpki rule 10 match rpki 'invalid'
+set policy route-map ebgp-transit-rpki rule 20 action 'permit'
+set policy route-map ebgp-transit-rpki rule 20 match rpki 'notfound'
+set policy route-map ebgp-transit-rpki rule 20 set local-preference '20'
+set policy route-map ebgp-transit-rpki rule 30 action 'permit'
+set policy route-map ebgp-transit-rpki rule 30 match rpki 'valid'
+set policy route-map ebgp-transit-rpki rule 30 set local-preference '100'
+set policy route-map ebgp-transit-rpki rule 40 action 'permit'
+set policy route-map ebgp-transit-rpki rule 40 set extcommunity rt '192.0.2.100:100'
+set policy route-map ebgp-transit-rpki rule 40 set extcommunity soo '64500:100'
+set protocols bgp neighbor 1.2.3.4 address-family ipv4-unicast nexthop-self
+set protocols bgp neighbor 1.2.3.4 address-family ipv4-unicast route-map import 'ebgp-transit-rpki'
+set protocols bgp neighbor 1.2.3.4 remote-as '10'
+set protocols bgp system-as '64500'
+set protocols rpki cache 192.0.2.10 port '3323'
+set protocols rpki cache 192.0.2.10 preference '1'
+set protocols static route 0.0.0.0/0 next-hop 192.0.2.1
+set protocols static route6 ::/0 next-hop 2001:db8::1
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set service ssh
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/bgp-small-internet-exchange b/smoketest/config-tests/bgp-small-internet-exchange
new file mode 100644
index 000000000..a9dce4dd5
--- /dev/null
+++ b/smoketest/config-tests/bgp-small-internet-exchange
@@ -0,0 +1,209 @@
+set interfaces ethernet eth0 address '192.0.2.100/25'
+set interfaces ethernet eth0 address '2001:db8:aaaa::ffff/64'
+set interfaces ethernet eth1 address '192.0.2.200/25'
+set interfaces ethernet eth1 address '2001:db8:bbbb::ffff/64'
+set interfaces loopback lo
+set policy as-path-list bogon-asns rule 10 action 'permit'
+set policy as-path-list bogon-asns rule 10 description 'RFC 7607'
+set policy as-path-list bogon-asns rule 10 regex '_0_'
+set policy as-path-list bogon-asns rule 20 action 'permit'
+set policy as-path-list bogon-asns rule 20 description 'RFC 4893'
+set policy as-path-list bogon-asns rule 20 regex '_23456_'
+set policy as-path-list bogon-asns rule 30 action 'permit'
+set policy as-path-list bogon-asns rule 30 description 'RFC 5398/6996/7300'
+set policy as-path-list bogon-asns rule 30 regex '_6449[6-9]_|_65[0-4][0-9][0-9]_|_655[0-4][0-9]_|_6555[0-1]_'
+set policy as-path-list bogon-asns rule 40 action 'permit'
+set policy as-path-list bogon-asns rule 40 description 'IANA reserved'
+set policy as-path-list bogon-asns rule 40 regex '_6555[2-9]_|_655[6-9][0-9]_|_65[6-9][0-9][0-9]_|_6[6-9][0-9][0-9][0-]_|_[7-9][0-9][0-9][0-9][0-9]_|_1[0-2][0-9][0-9][0-9][0-9]_|_130[0-9][0-9][0-9]_|_1310[0-6][0-9]_|_13107[01]_'
+set policy prefix-list IX-out-v4 rule 10 action 'permit'
+set policy prefix-list IX-out-v4 rule 10 prefix '10.0.0.0/23'
+set policy prefix-list IX-out-v4 rule 20 action 'permit'
+set policy prefix-list IX-out-v4 rule 20 prefix '10.0.128.0/23'
+set policy prefix-list bogon-v4 rule 10 action 'permit'
+set policy prefix-list bogon-v4 rule 10 le '32'
+set policy prefix-list bogon-v4 rule 10 prefix '0.0.0.0/8'
+set policy prefix-list bogon-v4 rule 20 action 'permit'
+set policy prefix-list bogon-v4 rule 20 le '32'
+set policy prefix-list bogon-v4 rule 20 prefix '10.0.0.0/8'
+set policy prefix-list bogon-v4 rule 30 action 'permit'
+set policy prefix-list bogon-v4 rule 30 le '32'
+set policy prefix-list bogon-v4 rule 30 prefix '100.64.0.0/10'
+set policy prefix-list bogon-v4 rule 40 action 'permit'
+set policy prefix-list bogon-v4 rule 40 le '32'
+set policy prefix-list bogon-v4 rule 40 prefix '127.0.0.0/8'
+set policy prefix-list bogon-v4 rule 50 action 'permit'
+set policy prefix-list bogon-v4 rule 50 le '32'
+set policy prefix-list bogon-v4 rule 50 prefix '169.254.0.0/16'
+set policy prefix-list bogon-v4 rule 60 action 'permit'
+set policy prefix-list bogon-v4 rule 60 le '32'
+set policy prefix-list bogon-v4 rule 60 prefix '172.16.0.0/12'
+set policy prefix-list bogon-v4 rule 70 action 'permit'
+set policy prefix-list bogon-v4 rule 70 le '32'
+set policy prefix-list bogon-v4 rule 70 prefix '192.0.2.0/24'
+set policy prefix-list bogon-v4 rule 80 action 'permit'
+set policy prefix-list bogon-v4 rule 80 le '32'
+set policy prefix-list bogon-v4 rule 80 prefix '192.88.99.0/24'
+set policy prefix-list bogon-v4 rule 90 action 'permit'
+set policy prefix-list bogon-v4 rule 90 le '32'
+set policy prefix-list bogon-v4 rule 90 prefix '192.168.0.0/16'
+set policy prefix-list bogon-v4 rule 100 action 'permit'
+set policy prefix-list bogon-v4 rule 100 le '32'
+set policy prefix-list bogon-v4 rule 100 prefix '198.18.0.0/15'
+set policy prefix-list bogon-v4 rule 110 action 'permit'
+set policy prefix-list bogon-v4 rule 110 le '32'
+set policy prefix-list bogon-v4 rule 110 prefix '198.51.100.0/24'
+set policy prefix-list bogon-v4 rule 120 action 'permit'
+set policy prefix-list bogon-v4 rule 120 le '32'
+set policy prefix-list bogon-v4 rule 120 prefix '203.0.113.0/24'
+set policy prefix-list bogon-v4 rule 130 action 'permit'
+set policy prefix-list bogon-v4 rule 130 le '32'
+set policy prefix-list bogon-v4 rule 130 prefix '224.0.0.0/4'
+set policy prefix-list bogon-v4 rule 140 action 'permit'
+set policy prefix-list bogon-v4 rule 140 le '32'
+set policy prefix-list bogon-v4 rule 140 prefix '240.0.0.0/4'
+set policy prefix-list prefix-filter-v4 rule 10 action 'permit'
+set policy prefix-list prefix-filter-v4 rule 10 ge '25'
+set policy prefix-list prefix-filter-v4 rule 10 prefix '0.0.0.0/0'
+set policy prefix-list6 IX-out-v6 rule 10 action 'permit'
+set policy prefix-list6 IX-out-v6 rule 10 prefix '2001:db8:100::/40'
+set policy prefix-list6 IX-out-v6 rule 20 action 'permit'
+set policy prefix-list6 IX-out-v6 rule 20 prefix '2001:db8:200::/40'
+set policy prefix-list6 bogon-v6 rule 10 action 'permit'
+set policy prefix-list6 bogon-v6 rule 10 description 'RFC 4291 IPv4-compatible, loopback, et al'
+set policy prefix-list6 bogon-v6 rule 10 le '128'
+set policy prefix-list6 bogon-v6 rule 10 prefix '::/8'
+set policy prefix-list6 bogon-v6 rule 20 action 'permit'
+set policy prefix-list6 bogon-v6 rule 20 description 'RFC 6666 Discard-Only'
+set policy prefix-list6 bogon-v6 rule 20 le '128'
+set policy prefix-list6 bogon-v6 rule 20 prefix '0100::/64'
+set policy prefix-list6 bogon-v6 rule 30 action 'permit'
+set policy prefix-list6 bogon-v6 rule 30 description 'RFC 5180 BMWG'
+set policy prefix-list6 bogon-v6 rule 30 le '128'
+set policy prefix-list6 bogon-v6 rule 30 prefix '2001:2::/48'
+set policy prefix-list6 bogon-v6 rule 40 action 'permit'
+set policy prefix-list6 bogon-v6 rule 40 description 'RFC 4843 ORCHID'
+set policy prefix-list6 bogon-v6 rule 40 le '128'
+set policy prefix-list6 bogon-v6 rule 40 prefix '2001:10::/28'
+set policy prefix-list6 bogon-v6 rule 50 action 'permit'
+set policy prefix-list6 bogon-v6 rule 50 description 'RFC 3849 documentation'
+set policy prefix-list6 bogon-v6 rule 50 le '128'
+set policy prefix-list6 bogon-v6 rule 50 prefix '2001:db8::/32'
+set policy prefix-list6 bogon-v6 rule 60 action 'permit'
+set policy prefix-list6 bogon-v6 rule 60 description 'RFC 7526 6to4 anycast relay'
+set policy prefix-list6 bogon-v6 rule 60 le '128'
+set policy prefix-list6 bogon-v6 rule 60 prefix '2002::/16'
+set policy prefix-list6 bogon-v6 rule 70 action 'permit'
+set policy prefix-list6 bogon-v6 rule 70 description 'RFC 3701 old 6bone'
+set policy prefix-list6 bogon-v6 rule 70 le '128'
+set policy prefix-list6 bogon-v6 rule 70 prefix '3ffe::/16'
+set policy prefix-list6 bogon-v6 rule 80 action 'permit'
+set policy prefix-list6 bogon-v6 rule 80 description 'RFC 4193 unique local unicast'
+set policy prefix-list6 bogon-v6 rule 80 le '128'
+set policy prefix-list6 bogon-v6 rule 80 prefix 'fc00::/7'
+set policy prefix-list6 bogon-v6 rule 90 action 'permit'
+set policy prefix-list6 bogon-v6 rule 90 description 'RFC 4291 link local unicast'
+set policy prefix-list6 bogon-v6 rule 90 le '128'
+set policy prefix-list6 bogon-v6 rule 90 prefix 'fe80::/10'
+set policy prefix-list6 bogon-v6 rule 100 action 'permit'
+set policy prefix-list6 bogon-v6 rule 100 description 'RFC 3879 old site local unicast'
+set policy prefix-list6 bogon-v6 rule 100 le '128'
+set policy prefix-list6 bogon-v6 rule 100 prefix 'fec0::/10'
+set policy prefix-list6 bogon-v6 rule 110 action 'permit'
+set policy prefix-list6 bogon-v6 rule 110 description 'RFC 4291 multicast'
+set policy prefix-list6 bogon-v6 rule 110 le '128'
+set policy prefix-list6 bogon-v6 rule 110 prefix 'ff00::/8'
+set policy prefix-list6 prefix-filter-v6 rule 10 action 'permit'
+set policy prefix-list6 prefix-filter-v6 rule 10 ge '49'
+set policy prefix-list6 prefix-filter-v6 rule 10 prefix '::/0'
+set policy route-map IX-in-v4 rule 5 action 'permit'
+set policy route-map IX-in-v4 rule 5 call 'eBGP-IN-v4'
+set policy route-map IX-in-v4 rule 5 on-match next
+set policy route-map IX-in-v4 rule 10 action 'permit'
+set policy route-map IX-in-v6 rule 5 action 'permit'
+set policy route-map IX-in-v6 rule 5 call 'eBGP-IN-v6'
+set policy route-map IX-in-v6 rule 5 on-match next
+set policy route-map IX-in-v6 rule 10 action 'permit'
+set policy route-map IX-out-v4 rule 10 action 'permit'
+set policy route-map IX-out-v4 rule 10 match ip address prefix-list 'IX-out-v4'
+set policy route-map IX-out-v6 rule 10 action 'permit'
+set policy route-map IX-out-v6 rule 10 match ipv6 address prefix-list 'IX-out-v6'
+set policy route-map eBGP-IN-v4 rule 10 action 'deny'
+set policy route-map eBGP-IN-v4 rule 10 match as-path 'bogon-asns'
+set policy route-map eBGP-IN-v4 rule 20 action 'deny'
+set policy route-map eBGP-IN-v4 rule 20 match ip address prefix-list 'bogon-v4'
+set policy route-map eBGP-IN-v4 rule 30 action 'deny'
+set policy route-map eBGP-IN-v4 rule 30 match ip address prefix-list 'prefix-filter-v4'
+set policy route-map eBGP-IN-v4 rule 40 action 'permit'
+set policy route-map eBGP-IN-v4 rule 40 set local-preference '100'
+set policy route-map eBGP-IN-v4 rule 40 set metric '0'
+set policy route-map eBGP-IN-v6 rule 10 action 'deny'
+set policy route-map eBGP-IN-v6 rule 10 match as-path 'bogon-asns'
+set policy route-map eBGP-IN-v6 rule 20 action 'deny'
+set policy route-map eBGP-IN-v6 rule 20 match ipv6 address prefix-list 'bogon-v6'
+set policy route-map eBGP-IN-v6 rule 30 action 'deny'
+set policy route-map eBGP-IN-v6 rule 30 match ipv6 address prefix-list 'prefix-filter-v6'
+set policy route-map eBGP-IN-v6 rule 31 action 'deny'
+set policy route-map eBGP-IN-v6 rule 31 match ipv6 nexthop address '2001:db8::1'
+set policy route-map eBGP-IN-v6 rule 40 action 'permit'
+set policy route-map eBGP-IN-v6 rule 40 set local-preference '100'
+set policy route-map eBGP-IN-v6 rule 40 set metric '0'
+set protocols bgp address-family ipv4-unicast network 10.0.0.0/23
+set protocols bgp address-family ipv4-unicast network 10.0.128.0/23
+set protocols bgp address-family ipv6-unicast network 2001:db8:100::/40
+set protocols bgp address-family ipv6-unicast network 2001:db8:200::/40
+set protocols bgp neighbor 192.0.2.1 description 'Peering: IX-1 (Route Server)'
+set protocols bgp neighbor 192.0.2.1 peer-group 'IXPeeringIPv4'
+set protocols bgp neighbor 192.0.2.1 remote-as '65020'
+set protocols bgp neighbor 192.0.2.2 description 'Peering: IX-1 (Route Server)'
+set protocols bgp neighbor 192.0.2.2 peer-group 'IXPeeringIPv4'
+set protocols bgp neighbor 192.0.2.2 remote-as '65020'
+set protocols bgp neighbor 192.0.2.3 description 'Peering: IX-1 (Route Server)'
+set protocols bgp neighbor 192.0.2.3 peer-group 'IXPeeringIPv4'
+set protocols bgp neighbor 192.0.2.3 remote-as '65020'
+set protocols bgp neighbor 192.0.2.129 description 'Peering: IX-2 (Route Server)'
+set protocols bgp neighbor 192.0.2.129 peer-group 'IXPeeringIPv4'
+set protocols bgp neighbor 192.0.2.129 remote-as '65030'
+set protocols bgp neighbor 192.0.2.130 description 'Peering: IX-2 (Route Server)'
+set protocols bgp neighbor 192.0.2.130 peer-group 'IXPeeringIPv4'
+set protocols bgp neighbor 192.0.2.130 remote-as '65030'
+set protocols bgp neighbor 2001:db8:aaaa::1 description 'Peering: IX-1 (Route Server)'
+set protocols bgp neighbor 2001:db8:aaaa::1 peer-group 'IXPeeringIPv6'
+set protocols bgp neighbor 2001:db8:aaaa::1 remote-as '65020'
+set protocols bgp neighbor 2001:db8:aaaa::2 description 'Peering: IX-1 (Route Server)'
+set protocols bgp neighbor 2001:db8:aaaa::2 peer-group 'IXPeeringIPv6'
+set protocols bgp neighbor 2001:db8:aaaa::2 remote-as '65020'
+set protocols bgp neighbor 2001:db8:bbbb::1 description 'Peering: IX-2 (Route Server)'
+set protocols bgp neighbor 2001:db8:bbbb::1 peer-group 'IXPeeringIPv6'
+set protocols bgp neighbor 2001:db8:bbbb::1 remote-as '65030'
+set protocols bgp neighbor 2001:db8:bbbb::2 description 'Peering: IX-2 (Route Server)'
+set protocols bgp neighbor 2001:db8:bbbb::2 peer-group 'IXPeeringIPv6'
+set protocols bgp neighbor 2001:db8:bbbb::2 remote-as '65030'
+set protocols bgp peer-group IXPeeringIPv4 address-family ipv4-unicast route-map export 'IX-out-v4'
+set protocols bgp peer-group IXPeeringIPv4 address-family ipv4-unicast soft-reconfiguration inbound
+set protocols bgp peer-group IXPeeringIPv6 address-family ipv6-unicast route-map export 'IX-out-v6'
+set protocols bgp peer-group IXPeeringIPv6 address-family ipv6-unicast soft-reconfiguration inbound
+set protocols bgp system-as '65000'
+set protocols static route 10.0.0.0/23 blackhole distance '250'
+set protocols static route 10.0.128.0/23 blackhole distance '250'
+set protocols static route6 2001:db8:100::/40 blackhole distance '250'
+set protocols static route6 2001:db8:200::/40 blackhole distance '250'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set service ssh
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/bgp-small-ipv4-unicast b/smoketest/config-tests/bgp-small-ipv4-unicast
new file mode 100644
index 000000000..b8c0e1246
--- /dev/null
+++ b/smoketest/config-tests/bgp-small-ipv4-unicast
@@ -0,0 +1,32 @@
+set interfaces ethernet eth0 address '192.0.2.1/24'
+set interfaces ethernet eth0 address '2001:db8::1/64'
+set interfaces loopback lo
+set protocols bgp address-family ipv4-unicast network 10.0.150.0/23
+set protocols bgp address-family ipv6-unicast network 2001:db8:200::/40
+set protocols bgp neighbor 192.0.2.10 address-family ipv4-unicast
+set protocols bgp neighbor 192.0.2.10 remote-as '65010'
+set protocols bgp neighbor 192.0.2.11 address-family ipv4-unicast
+set protocols bgp neighbor 192.0.2.11 remote-as '65011'
+set protocols bgp neighbor 2001:db8::10 address-family ipv4-unicast
+set protocols bgp neighbor 2001:db8::10 remote-as '65010'
+set protocols bgp neighbor 2001:db8::11 address-family ipv4-unicast
+set protocols bgp neighbor 2001:db8::11 remote-as '65011'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp system-as '65001'
+set service ssh disable-host-validation
+set service ssh port '22'
+set system config-management commit-revisions '200'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'notice'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/cluster-basic b/smoketest/config-tests/cluster-basic
new file mode 100644
index 000000000..744c117eb
--- /dev/null
+++ b/smoketest/config-tests/cluster-basic
@@ -0,0 +1,21 @@
+set high-availability vrrp group VyOS address 192.0.2.10/24
+set high-availability vrrp group VyOS address 192.0.2.20/24
+set high-availability vrrp group VyOS advertise-interval '1'
+set high-availability vrrp group VyOS authentication password 'qwerty'
+set high-availability vrrp group VyOS authentication type 'plaintext-password'
+set high-availability vrrp group VyOS interface 'eth1'
+set high-availability vrrp group VyOS vrid '1'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 address '192.0.2.1/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set interfaces loopback lo
+set system config-management commit-revisions '100'
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Antarctica/South_Pole'
diff --git a/smoketest/config-tests/container-simple b/smoketest/config-tests/container-simple
index 5af365cf9..fcc665100 100644
--- a/smoketest/config-tests/container-simple
+++ b/smoketest/config-tests/container-simple
@@ -1,8 +1,3 @@
-set system config-management commit-revisions '50'
-set system host-name 'vyos'
-set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
-set system login user vyos authentication plaintext-password ''
-set system console device ttyS0 speed '115200'
set container name c01 allow-host-networks
set container name c01 capability 'net-bind-service'
set container name c01 capability 'net-raw'
@@ -11,4 +6,13 @@ set container name c02 allow-host-networks
set container name c02 allow-host-pid
set container name c02 capability 'sys-time'
set container name c02 image 'busybox:stable'
-set container name c02 sysctl parameter kernel.msgmax value '8192' \ No newline at end of file
+set container name c02 sysctl parameter kernel.msgmax value '8192'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set system config-management commit-revisions '50'
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
+set system login user vyos authentication plaintext-password ''
diff --git a/smoketest/config-tests/dialup-router-complex b/smoketest/config-tests/dialup-router-complex
new file mode 100644
index 000000000..4416ef82e
--- /dev/null
+++ b/smoketest/config-tests/dialup-router-complex
@@ -0,0 +1,740 @@
+set firewall global-options all-ping 'enable'
+set firewall global-options broadcast-ping 'disable'
+set firewall global-options ip-src-route 'disable'
+set firewall global-options ipv6-receive-redirects 'disable'
+set firewall global-options ipv6-src-route 'disable'
+set firewall global-options log-martians 'enable'
+set firewall global-options receive-redirects 'disable'
+set firewall global-options send-redirects 'enable'
+set firewall global-options source-validation 'disable'
+set firewall global-options syn-cookies 'enable'
+set firewall global-options timeout icmp '30'
+set firewall global-options timeout other '600'
+set firewall global-options timeout udp other '300'
+set firewall global-options timeout udp stream '300'
+set firewall global-options twa-hazards-protection 'disable'
+set firewall group address-group AUDIO-STREAM address '172.16.35.20'
+set firewall group address-group AUDIO-STREAM address '172.16.35.21'
+set firewall group address-group AUDIO-STREAM address '172.16.35.22'
+set firewall group address-group AUDIO-STREAM address '172.16.35.23'
+set firewall group address-group DMZ-RDP-SERVER address '172.16.33.40'
+set firewall group address-group DMZ-WEBSERVER address '172.16.36.10'
+set firewall group address-group DMZ-WEBSERVER address '172.16.36.40'
+set firewall group address-group DMZ-WEBSERVER address '172.16.36.20'
+set firewall group address-group DOMAIN-CONTROLLER address '172.16.100.10'
+set firewall group address-group DOMAIN-CONTROLLER address '172.16.100.20'
+set firewall group address-group MEDIA-STREAMING-CLIENTS address '172.16.35.241'
+set firewall group address-group MEDIA-STREAMING-CLIENTS address '172.16.35.242'
+set firewall group address-group MEDIA-STREAMING-CLIENTS address '172.16.35.243'
+set firewall group ipv6-network-group LOCAL-ADDRESSES network 'ff02::/64'
+set firewall group ipv6-network-group LOCAL-ADDRESSES network 'fe80::/10'
+set firewall group network-group SSH-IN-ALLOW network '192.0.2.0/24'
+set firewall group network-group SSH-IN-ALLOW network '10.0.0.0/8'
+set firewall group network-group SSH-IN-ALLOW network '172.16.0.0/12'
+set firewall group network-group SSH-IN-ALLOW network '192.168.0.0/16'
+set firewall group port-group SMART-TV-PORTS port '5005-5006'
+set firewall group port-group SMART-TV-PORTS port '80'
+set firewall group port-group SMART-TV-PORTS port '443'
+set firewall group port-group SMART-TV-PORTS port '3722'
+set firewall ipv4 name DMZ-GUEST default-action 'drop'
+set firewall ipv4 name DMZ-GUEST default-log
+set firewall ipv4 name DMZ-GUEST rule 1 action 'return'
+set firewall ipv4 name DMZ-GUEST rule 1 state 'established'
+set firewall ipv4 name DMZ-GUEST rule 1 state 'related'
+set firewall ipv4 name DMZ-GUEST rule 2 action 'drop'
+set firewall ipv4 name DMZ-GUEST rule 2 log
+set firewall ipv4 name DMZ-GUEST rule 2 state 'invalid'
+set firewall ipv4 name DMZ-LAN default-action 'drop'
+set firewall ipv4 name DMZ-LAN default-log
+set firewall ipv4 name DMZ-LAN rule 1 action 'return'
+set firewall ipv4 name DMZ-LAN rule 1 state 'established'
+set firewall ipv4 name DMZ-LAN rule 1 state 'related'
+set firewall ipv4 name DMZ-LAN rule 2 action 'drop'
+set firewall ipv4 name DMZ-LAN rule 2 log
+set firewall ipv4 name DMZ-LAN rule 2 state 'invalid'
+set firewall ipv4 name DMZ-LAN rule 100 action 'return'
+set firewall ipv4 name DMZ-LAN rule 100 description 'NTP and LDAP to AD DC'
+set firewall ipv4 name DMZ-LAN rule 100 destination group address-group 'DOMAIN-CONTROLLER'
+set firewall ipv4 name DMZ-LAN rule 100 destination port '123,389,636'
+set firewall ipv4 name DMZ-LAN rule 100 protocol 'tcp_udp'
+set firewall ipv4 name DMZ-LAN rule 300 action 'return'
+set firewall ipv4 name DMZ-LAN rule 300 destination group address-group 'DMZ-RDP-SERVER'
+set firewall ipv4 name DMZ-LAN rule 300 destination port '3389'
+set firewall ipv4 name DMZ-LAN rule 300 protocol 'tcp_udp'
+set firewall ipv4 name DMZ-LAN rule 300 source address '172.16.36.20'
+set firewall ipv4 name DMZ-LOCAL default-action 'drop'
+set firewall ipv4 name DMZ-LOCAL default-log
+set firewall ipv4 name DMZ-LOCAL rule 1 action 'return'
+set firewall ipv4 name DMZ-LOCAL rule 1 state 'established'
+set firewall ipv4 name DMZ-LOCAL rule 1 state 'related'
+set firewall ipv4 name DMZ-LOCAL rule 2 action 'drop'
+set firewall ipv4 name DMZ-LOCAL rule 2 log
+set firewall ipv4 name DMZ-LOCAL rule 2 state 'invalid'
+set firewall ipv4 name DMZ-LOCAL rule 50 action 'return'
+set firewall ipv4 name DMZ-LOCAL rule 50 destination address '172.16.254.30'
+set firewall ipv4 name DMZ-LOCAL rule 50 destination port '53'
+set firewall ipv4 name DMZ-LOCAL rule 50 protocol 'tcp_udp'
+set firewall ipv4 name DMZ-LOCAL rule 123 action 'return'
+set firewall ipv4 name DMZ-LOCAL rule 123 destination port '123'
+set firewall ipv4 name DMZ-LOCAL rule 123 protocol 'udp'
+set firewall ipv4 name DMZ-LOCAL rule 800 action 'drop'
+set firewall ipv4 name DMZ-LOCAL rule 800 description 'SSH anti brute force'
+set firewall ipv4 name DMZ-LOCAL rule 800 destination port 'ssh'
+set firewall ipv4 name DMZ-LOCAL rule 800 log
+set firewall ipv4 name DMZ-LOCAL rule 800 protocol 'tcp'
+set firewall ipv4 name DMZ-LOCAL rule 800 recent count '4'
+set firewall ipv4 name DMZ-LOCAL rule 800 recent time 'minute'
+set firewall ipv4 name DMZ-LOCAL rule 800 state 'new'
+set firewall ipv4 name DMZ-WAN default-action 'return'
+set firewall ipv4 name GUEST-DMZ default-action 'drop'
+set firewall ipv4 name GUEST-DMZ default-log
+set firewall ipv4 name GUEST-DMZ rule 1 action 'return'
+set firewall ipv4 name GUEST-DMZ rule 1 state 'established'
+set firewall ipv4 name GUEST-DMZ rule 1 state 'related'
+set firewall ipv4 name GUEST-DMZ rule 2 action 'drop'
+set firewall ipv4 name GUEST-DMZ rule 2 log
+set firewall ipv4 name GUEST-DMZ rule 2 state 'invalid'
+set firewall ipv4 name GUEST-DMZ rule 100 action 'return'
+set firewall ipv4 name GUEST-DMZ rule 100 destination port '80,443'
+set firewall ipv4 name GUEST-DMZ rule 100 protocol 'tcp'
+set firewall ipv4 name GUEST-IOT default-action 'drop'
+set firewall ipv4 name GUEST-IOT default-log
+set firewall ipv4 name GUEST-IOT rule 1 action 'return'
+set firewall ipv4 name GUEST-IOT rule 1 state 'established'
+set firewall ipv4 name GUEST-IOT rule 1 state 'related'
+set firewall ipv4 name GUEST-IOT rule 2 action 'drop'
+set firewall ipv4 name GUEST-IOT rule 2 log
+set firewall ipv4 name GUEST-IOT rule 2 state 'invalid'
+set firewall ipv4 name GUEST-IOT rule 100 action 'return'
+set firewall ipv4 name GUEST-IOT rule 100 description 'MEDIA-STREAMING-CLIENTS Devices to GUEST'
+set firewall ipv4 name GUEST-IOT rule 100 destination group address-group 'MEDIA-STREAMING-CLIENTS'
+set firewall ipv4 name GUEST-IOT rule 100 protocol 'tcp_udp'
+set firewall ipv4 name GUEST-IOT rule 110 action 'return'
+set firewall ipv4 name GUEST-IOT rule 110 description 'AUDIO-STREAM Devices to GUEST'
+set firewall ipv4 name GUEST-IOT rule 110 destination group address-group 'AUDIO-STREAM'
+set firewall ipv4 name GUEST-IOT rule 110 protocol 'tcp_udp'
+set firewall ipv4 name GUEST-IOT rule 200 action 'return'
+set firewall ipv4 name GUEST-IOT rule 200 description 'MCAST relay'
+set firewall ipv4 name GUEST-IOT rule 200 destination address '224.0.0.251'
+set firewall ipv4 name GUEST-IOT rule 200 destination port '5353'
+set firewall ipv4 name GUEST-IOT rule 200 protocol 'udp'
+set firewall ipv4 name GUEST-IOT rule 300 action 'return'
+set firewall ipv4 name GUEST-IOT rule 300 description 'BCAST relay'
+set firewall ipv4 name GUEST-IOT rule 300 destination port '1900'
+set firewall ipv4 name GUEST-IOT rule 300 protocol 'udp'
+set firewall ipv4 name GUEST-LAN default-action 'drop'
+set firewall ipv4 name GUEST-LAN default-log
+set firewall ipv4 name GUEST-LAN rule 1 action 'return'
+set firewall ipv4 name GUEST-LAN rule 1 state 'established'
+set firewall ipv4 name GUEST-LAN rule 1 state 'related'
+set firewall ipv4 name GUEST-LAN rule 2 action 'drop'
+set firewall ipv4 name GUEST-LAN rule 2 log
+set firewall ipv4 name GUEST-LAN rule 2 state 'invalid'
+set firewall ipv4 name GUEST-LOCAL default-action 'drop'
+set firewall ipv4 name GUEST-LOCAL default-log
+set firewall ipv4 name GUEST-LOCAL rule 1 action 'return'
+set firewall ipv4 name GUEST-LOCAL rule 1 state 'established'
+set firewall ipv4 name GUEST-LOCAL rule 1 state 'related'
+set firewall ipv4 name GUEST-LOCAL rule 2 action 'drop'
+set firewall ipv4 name GUEST-LOCAL rule 2 log
+set firewall ipv4 name GUEST-LOCAL rule 2 state 'invalid'
+set firewall ipv4 name GUEST-LOCAL rule 10 action 'return'
+set firewall ipv4 name GUEST-LOCAL rule 10 description 'DNS'
+set firewall ipv4 name GUEST-LOCAL rule 10 destination address '172.31.0.254'
+set firewall ipv4 name GUEST-LOCAL rule 10 destination port '53'
+set firewall ipv4 name GUEST-LOCAL rule 10 protocol 'tcp_udp'
+set firewall ipv4 name GUEST-LOCAL rule 11 action 'return'
+set firewall ipv4 name GUEST-LOCAL rule 11 description 'DHCP'
+set firewall ipv4 name GUEST-LOCAL rule 11 destination port '67'
+set firewall ipv4 name GUEST-LOCAL rule 11 protocol 'udp'
+set firewall ipv4 name GUEST-LOCAL rule 15 action 'return'
+set firewall ipv4 name GUEST-LOCAL rule 15 destination address '172.31.0.254'
+set firewall ipv4 name GUEST-LOCAL rule 15 protocol 'icmp'
+set firewall ipv4 name GUEST-LOCAL rule 200 action 'return'
+set firewall ipv4 name GUEST-LOCAL rule 200 description 'MCAST relay'
+set firewall ipv4 name GUEST-LOCAL rule 200 destination address '224.0.0.251'
+set firewall ipv4 name GUEST-LOCAL rule 200 destination port '5353'
+set firewall ipv4 name GUEST-LOCAL rule 200 protocol 'udp'
+set firewall ipv4 name GUEST-LOCAL rule 210 action 'return'
+set firewall ipv4 name GUEST-LOCAL rule 210 description 'AUDIO-STREAM Broadcast'
+set firewall ipv4 name GUEST-LOCAL rule 210 destination port '1900'
+set firewall ipv4 name GUEST-LOCAL rule 210 protocol 'udp'
+set firewall ipv4 name GUEST-WAN default-action 'drop'
+set firewall ipv4 name GUEST-WAN default-log
+set firewall ipv4 name GUEST-WAN rule 1 action 'return'
+set firewall ipv4 name GUEST-WAN rule 1 state 'established'
+set firewall ipv4 name GUEST-WAN rule 1 state 'related'
+set firewall ipv4 name GUEST-WAN rule 2 action 'drop'
+set firewall ipv4 name GUEST-WAN rule 2 log
+set firewall ipv4 name GUEST-WAN rule 2 state 'invalid'
+set firewall ipv4 name GUEST-WAN rule 25 action 'return'
+set firewall ipv4 name GUEST-WAN rule 25 description 'SMTP'
+set firewall ipv4 name GUEST-WAN rule 25 destination port '25,587'
+set firewall ipv4 name GUEST-WAN rule 25 protocol 'tcp'
+set firewall ipv4 name GUEST-WAN rule 53 action 'return'
+set firewall ipv4 name GUEST-WAN rule 53 destination port '53'
+set firewall ipv4 name GUEST-WAN rule 53 protocol 'tcp_udp'
+set firewall ipv4 name GUEST-WAN rule 60 action 'return'
+set firewall ipv4 name GUEST-WAN rule 60 source address '172.31.0.200'
+set firewall ipv4 name GUEST-WAN rule 80 action 'return'
+set firewall ipv4 name GUEST-WAN rule 80 source address '172.31.0.200'
+set firewall ipv4 name GUEST-WAN rule 100 action 'return'
+set firewall ipv4 name GUEST-WAN rule 100 protocol 'icmp'
+set firewall ipv4 name GUEST-WAN rule 110 action 'return'
+set firewall ipv4 name GUEST-WAN rule 110 description 'POP3'
+set firewall ipv4 name GUEST-WAN rule 110 destination port '110,995'
+set firewall ipv4 name GUEST-WAN rule 110 limit rate '10/minute'
+set firewall ipv4 name GUEST-WAN rule 110 protocol 'tcp'
+set firewall ipv4 name GUEST-WAN rule 123 action 'return'
+set firewall ipv4 name GUEST-WAN rule 123 description 'NTP Client'
+set firewall ipv4 name GUEST-WAN rule 123 destination port '123'
+set firewall ipv4 name GUEST-WAN rule 123 protocol 'udp'
+set firewall ipv4 name GUEST-WAN rule 143 action 'return'
+set firewall ipv4 name GUEST-WAN rule 143 description 'IMAP'
+set firewall ipv4 name GUEST-WAN rule 143 destination port '143,993'
+set firewall ipv4 name GUEST-WAN rule 143 protocol 'tcp'
+set firewall ipv4 name GUEST-WAN rule 200 action 'return'
+set firewall ipv4 name GUEST-WAN rule 200 destination port '80,443'
+set firewall ipv4 name GUEST-WAN rule 200 protocol 'tcp'
+set firewall ipv4 name GUEST-WAN rule 500 action 'return'
+set firewall ipv4 name GUEST-WAN rule 500 description 'L2TP IPSec'
+set firewall ipv4 name GUEST-WAN rule 500 destination port '500,4500'
+set firewall ipv4 name GUEST-WAN rule 500 protocol 'udp'
+set firewall ipv4 name GUEST-WAN rule 600 action 'return'
+set firewall ipv4 name GUEST-WAN rule 600 destination port '5222-5224'
+set firewall ipv4 name GUEST-WAN rule 600 protocol 'tcp'
+set firewall ipv4 name GUEST-WAN rule 601 action 'return'
+set firewall ipv4 name GUEST-WAN rule 601 destination port '3478-3497,4500,16384-16387,16393-16402'
+set firewall ipv4 name GUEST-WAN rule 601 protocol 'udp'
+set firewall ipv4 name GUEST-WAN rule 1000 action 'return'
+set firewall ipv4 name GUEST-WAN rule 1000 source address '172.31.0.184'
+set firewall ipv4 name IOT-GUEST default-action 'drop'
+set firewall ipv4 name IOT-GUEST default-log
+set firewall ipv4 name IOT-GUEST rule 1 action 'return'
+set firewall ipv4 name IOT-GUEST rule 1 state 'established'
+set firewall ipv4 name IOT-GUEST rule 1 state 'related'
+set firewall ipv4 name IOT-GUEST rule 2 action 'drop'
+set firewall ipv4 name IOT-GUEST rule 2 log
+set firewall ipv4 name IOT-GUEST rule 2 state 'invalid'
+set firewall ipv4 name IOT-GUEST rule 100 action 'return'
+set firewall ipv4 name IOT-GUEST rule 100 description 'MEDIA-STREAMING-CLIENTS Devices to IOT'
+set firewall ipv4 name IOT-GUEST rule 100 protocol 'tcp_udp'
+set firewall ipv4 name IOT-GUEST rule 100 source group address-group 'MEDIA-STREAMING-CLIENTS'
+set firewall ipv4 name IOT-GUEST rule 110 action 'return'
+set firewall ipv4 name IOT-GUEST rule 110 description 'AUDIO-STREAM Devices to IOT'
+set firewall ipv4 name IOT-GUEST rule 110 protocol 'tcp_udp'
+set firewall ipv4 name IOT-GUEST rule 110 source group address-group 'AUDIO-STREAM'
+set firewall ipv4 name IOT-GUEST rule 200 action 'return'
+set firewall ipv4 name IOT-GUEST rule 200 description 'MCAST relay'
+set firewall ipv4 name IOT-GUEST rule 200 destination address '224.0.0.251'
+set firewall ipv4 name IOT-GUEST rule 200 destination port '5353'
+set firewall ipv4 name IOT-GUEST rule 200 protocol 'udp'
+set firewall ipv4 name IOT-GUEST rule 300 action 'return'
+set firewall ipv4 name IOT-GUEST rule 300 description 'BCAST relay'
+set firewall ipv4 name IOT-GUEST rule 300 destination port '1900'
+set firewall ipv4 name IOT-GUEST rule 300 protocol 'udp'
+set firewall ipv4 name IOT-LAN default-action 'drop'
+set firewall ipv4 name IOT-LAN default-log
+set firewall ipv4 name IOT-LAN rule 1 action 'return'
+set firewall ipv4 name IOT-LAN rule 1 state 'established'
+set firewall ipv4 name IOT-LAN rule 1 state 'related'
+set firewall ipv4 name IOT-LAN rule 2 action 'drop'
+set firewall ipv4 name IOT-LAN rule 2 log
+set firewall ipv4 name IOT-LAN rule 2 state 'invalid'
+set firewall ipv4 name IOT-LAN rule 100 action 'return'
+set firewall ipv4 name IOT-LAN rule 100 description 'AppleTV to LAN'
+set firewall ipv4 name IOT-LAN rule 100 destination group port-group 'SMART-TV-PORTS'
+set firewall ipv4 name IOT-LAN rule 100 protocol 'tcp_udp'
+set firewall ipv4 name IOT-LAN rule 100 source group address-group 'MEDIA-STREAMING-CLIENTS'
+set firewall ipv4 name IOT-LAN rule 110 action 'return'
+set firewall ipv4 name IOT-LAN rule 110 description 'AUDIO-STREAM Devices to LAN'
+set firewall ipv4 name IOT-LAN rule 110 protocol 'tcp_udp'
+set firewall ipv4 name IOT-LAN rule 110 source group address-group 'AUDIO-STREAM'
+set firewall ipv4 name IOT-LOCAL default-action 'drop'
+set firewall ipv4 name IOT-LOCAL default-log
+set firewall ipv4 name IOT-LOCAL rule 1 action 'return'
+set firewall ipv4 name IOT-LOCAL rule 1 state 'established'
+set firewall ipv4 name IOT-LOCAL rule 1 state 'related'
+set firewall ipv4 name IOT-LOCAL rule 2 action 'drop'
+set firewall ipv4 name IOT-LOCAL rule 2 log
+set firewall ipv4 name IOT-LOCAL rule 2 state 'invalid'
+set firewall ipv4 name IOT-LOCAL rule 10 action 'return'
+set firewall ipv4 name IOT-LOCAL rule 10 description 'DNS'
+set firewall ipv4 name IOT-LOCAL rule 10 destination address '172.16.254.30'
+set firewall ipv4 name IOT-LOCAL rule 10 destination port '53'
+set firewall ipv4 name IOT-LOCAL rule 10 protocol 'tcp_udp'
+set firewall ipv4 name IOT-LOCAL rule 11 action 'return'
+set firewall ipv4 name IOT-LOCAL rule 11 description 'DHCP'
+set firewall ipv4 name IOT-LOCAL rule 11 destination port '67'
+set firewall ipv4 name IOT-LOCAL rule 11 protocol 'udp'
+set firewall ipv4 name IOT-LOCAL rule 15 action 'return'
+set firewall ipv4 name IOT-LOCAL rule 15 destination address '172.16.35.254'
+set firewall ipv4 name IOT-LOCAL rule 15 protocol 'icmp'
+set firewall ipv4 name IOT-LOCAL rule 200 action 'return'
+set firewall ipv4 name IOT-LOCAL rule 200 description 'MCAST relay'
+set firewall ipv4 name IOT-LOCAL rule 200 destination address '224.0.0.251'
+set firewall ipv4 name IOT-LOCAL rule 200 destination port '5353'
+set firewall ipv4 name IOT-LOCAL rule 200 protocol 'udp'
+set firewall ipv4 name IOT-LOCAL rule 201 action 'return'
+set firewall ipv4 name IOT-LOCAL rule 201 description 'MCAST relay'
+set firewall ipv4 name IOT-LOCAL rule 201 destination address '172.16.35.254'
+set firewall ipv4 name IOT-LOCAL rule 201 destination port '5353'
+set firewall ipv4 name IOT-LOCAL rule 201 protocol 'udp'
+set firewall ipv4 name IOT-LOCAL rule 210 action 'return'
+set firewall ipv4 name IOT-LOCAL rule 210 description 'AUDIO-STREAM Broadcast'
+set firewall ipv4 name IOT-LOCAL rule 210 destination port '1900,1902,6969'
+set firewall ipv4 name IOT-LOCAL rule 210 protocol 'udp'
+set firewall ipv4 name IOT-WAN default-action 'return'
+set firewall ipv4 name LAN-DMZ default-action 'drop'
+set firewall ipv4 name LAN-DMZ default-log
+set firewall ipv4 name LAN-DMZ rule 1 action 'return'
+set firewall ipv4 name LAN-DMZ rule 1 state 'established'
+set firewall ipv4 name LAN-DMZ rule 1 state 'related'
+set firewall ipv4 name LAN-DMZ rule 2 action 'drop'
+set firewall ipv4 name LAN-DMZ rule 2 log
+set firewall ipv4 name LAN-DMZ rule 2 state 'invalid'
+set firewall ipv4 name LAN-DMZ rule 22 action 'return'
+set firewall ipv4 name LAN-DMZ rule 22 description 'SSH into DMZ'
+set firewall ipv4 name LAN-DMZ rule 22 destination port '22'
+set firewall ipv4 name LAN-DMZ rule 22 protocol 'tcp'
+set firewall ipv4 name LAN-DMZ rule 100 action 'return'
+set firewall ipv4 name LAN-DMZ rule 100 destination group address-group 'DMZ-WEBSERVER'
+set firewall ipv4 name LAN-DMZ rule 100 destination port '22,80,443'
+set firewall ipv4 name LAN-DMZ rule 100 protocol 'tcp'
+set firewall ipv4 name LAN-GUEST default-action 'drop'
+set firewall ipv4 name LAN-GUEST default-log
+set firewall ipv4 name LAN-GUEST rule 1 action 'return'
+set firewall ipv4 name LAN-GUEST rule 1 state 'established'
+set firewall ipv4 name LAN-GUEST rule 1 state 'related'
+set firewall ipv4 name LAN-GUEST rule 2 action 'drop'
+set firewall ipv4 name LAN-GUEST rule 2 log
+set firewall ipv4 name LAN-GUEST rule 2 state 'invalid'
+set firewall ipv4 name LAN-IOT default-action 'return'
+set firewall ipv4 name LAN-LOCAL default-action 'return'
+set firewall ipv4 name LAN-WAN default-action 'return'
+set firewall ipv4 name LOCAL-DMZ default-action 'drop'
+set firewall ipv4 name LOCAL-DMZ default-log
+set firewall ipv4 name LOCAL-DMZ rule 1 action 'return'
+set firewall ipv4 name LOCAL-DMZ rule 1 state 'established'
+set firewall ipv4 name LOCAL-DMZ rule 1 state 'related'
+set firewall ipv4 name LOCAL-DMZ rule 2 action 'drop'
+set firewall ipv4 name LOCAL-DMZ rule 2 log
+set firewall ipv4 name LOCAL-DMZ rule 2 state 'invalid'
+set firewall ipv4 name LOCAL-GUEST default-action 'drop'
+set firewall ipv4 name LOCAL-GUEST default-log
+set firewall ipv4 name LOCAL-GUEST rule 1 action 'return'
+set firewall ipv4 name LOCAL-GUEST rule 1 state 'established'
+set firewall ipv4 name LOCAL-GUEST rule 1 state 'related'
+set firewall ipv4 name LOCAL-GUEST rule 2 action 'drop'
+set firewall ipv4 name LOCAL-GUEST rule 2 log
+set firewall ipv4 name LOCAL-GUEST rule 2 state 'invalid'
+set firewall ipv4 name LOCAL-GUEST rule 5 action 'return'
+set firewall ipv4 name LOCAL-GUEST rule 5 protocol 'icmp'
+set firewall ipv4 name LOCAL-GUEST rule 200 action 'return'
+set firewall ipv4 name LOCAL-GUEST rule 200 description 'MCAST relay'
+set firewall ipv4 name LOCAL-GUEST rule 200 destination address '224.0.0.251'
+set firewall ipv4 name LOCAL-GUEST rule 200 destination port '5353'
+set firewall ipv4 name LOCAL-GUEST rule 200 protocol 'udp'
+set firewall ipv4 name LOCAL-GUEST rule 300 action 'return'
+set firewall ipv4 name LOCAL-GUEST rule 300 description 'BCAST relay'
+set firewall ipv4 name LOCAL-GUEST rule 300 destination port '1900'
+set firewall ipv4 name LOCAL-GUEST rule 300 protocol 'udp'
+set firewall ipv4 name LOCAL-IOT default-action 'drop'
+set firewall ipv4 name LOCAL-IOT default-log
+set firewall ipv4 name LOCAL-IOT rule 1 action 'return'
+set firewall ipv4 name LOCAL-IOT rule 1 state 'established'
+set firewall ipv4 name LOCAL-IOT rule 1 state 'related'
+set firewall ipv4 name LOCAL-IOT rule 2 action 'drop'
+set firewall ipv4 name LOCAL-IOT rule 2 log
+set firewall ipv4 name LOCAL-IOT rule 2 state 'invalid'
+set firewall ipv4 name LOCAL-IOT rule 5 action 'return'
+set firewall ipv4 name LOCAL-IOT rule 5 protocol 'icmp'
+set firewall ipv4 name LOCAL-IOT rule 200 action 'return'
+set firewall ipv4 name LOCAL-IOT rule 200 description 'MCAST relay'
+set firewall ipv4 name LOCAL-IOT rule 200 destination address '224.0.0.251'
+set firewall ipv4 name LOCAL-IOT rule 200 destination port '5353'
+set firewall ipv4 name LOCAL-IOT rule 200 protocol 'udp'
+set firewall ipv4 name LOCAL-IOT rule 300 action 'return'
+set firewall ipv4 name LOCAL-IOT rule 300 description 'BCAST relay'
+set firewall ipv4 name LOCAL-IOT rule 300 destination port '1900,6969'
+set firewall ipv4 name LOCAL-IOT rule 300 protocol 'udp'
+set firewall ipv4 name LOCAL-LAN default-action 'return'
+set firewall ipv4 name LOCAL-WAN default-action 'drop'
+set firewall ipv4 name LOCAL-WAN default-log
+set firewall ipv4 name LOCAL-WAN rule 1 action 'return'
+set firewall ipv4 name LOCAL-WAN rule 1 state 'established'
+set firewall ipv4 name LOCAL-WAN rule 1 state 'related'
+set firewall ipv4 name LOCAL-WAN rule 2 action 'drop'
+set firewall ipv4 name LOCAL-WAN rule 2 log
+set firewall ipv4 name LOCAL-WAN rule 2 state 'invalid'
+set firewall ipv4 name LOCAL-WAN rule 10 action 'return'
+set firewall ipv4 name LOCAL-WAN rule 10 protocol 'icmp'
+set firewall ipv4 name LOCAL-WAN rule 50 action 'return'
+set firewall ipv4 name LOCAL-WAN rule 50 description 'DNS'
+set firewall ipv4 name LOCAL-WAN rule 50 destination port '53'
+set firewall ipv4 name LOCAL-WAN rule 50 protocol 'tcp_udp'
+set firewall ipv4 name LOCAL-WAN rule 80 action 'return'
+set firewall ipv4 name LOCAL-WAN rule 80 destination port '80,443'
+set firewall ipv4 name LOCAL-WAN rule 80 protocol 'tcp'
+set firewall ipv4 name LOCAL-WAN rule 123 action 'return'
+set firewall ipv4 name LOCAL-WAN rule 123 description 'NTP'
+set firewall ipv4 name LOCAL-WAN rule 123 destination port '123'
+set firewall ipv4 name LOCAL-WAN rule 123 protocol 'udp'
+set firewall ipv4 name WAN-DMZ default-action 'drop'
+set firewall ipv4 name WAN-DMZ default-log
+set firewall ipv4 name WAN-DMZ rule 1 action 'return'
+set firewall ipv4 name WAN-DMZ rule 1 state 'established'
+set firewall ipv4 name WAN-DMZ rule 1 state 'related'
+set firewall ipv4 name WAN-DMZ rule 2 action 'drop'
+set firewall ipv4 name WAN-DMZ rule 2 log
+set firewall ipv4 name WAN-DMZ rule 2 state 'invalid'
+set firewall ipv4 name WAN-DMZ rule 100 action 'return'
+set firewall ipv4 name WAN-DMZ rule 100 destination address '172.16.36.10'
+set firewall ipv4 name WAN-DMZ rule 100 destination port '80,443'
+set firewall ipv4 name WAN-DMZ rule 100 protocol 'tcp'
+set firewall ipv4 name WAN-GUEST default-action 'drop'
+set firewall ipv4 name WAN-GUEST default-log
+set firewall ipv4 name WAN-GUEST rule 1 action 'return'
+set firewall ipv4 name WAN-GUEST rule 1 state 'established'
+set firewall ipv4 name WAN-GUEST rule 1 state 'related'
+set firewall ipv4 name WAN-GUEST rule 2 action 'drop'
+set firewall ipv4 name WAN-GUEST rule 2 log
+set firewall ipv4 name WAN-GUEST rule 2 state 'invalid'
+set firewall ipv4 name WAN-GUEST rule 1000 action 'return'
+set firewall ipv4 name WAN-GUEST rule 1000 destination address '172.31.0.184'
+set firewall ipv4 name WAN-GUEST rule 8000 action 'return'
+set firewall ipv4 name WAN-GUEST rule 8000 destination address '172.31.0.200'
+set firewall ipv4 name WAN-GUEST rule 8000 destination port '10000'
+set firewall ipv4 name WAN-GUEST rule 8000 protocol 'udp'
+set firewall ipv4 name WAN-IOT default-action 'drop'
+set firewall ipv4 name WAN-IOT default-log
+set firewall ipv4 name WAN-IOT rule 1 action 'return'
+set firewall ipv4 name WAN-IOT rule 1 state 'established'
+set firewall ipv4 name WAN-IOT rule 1 state 'related'
+set firewall ipv4 name WAN-IOT rule 2 action 'drop'
+set firewall ipv4 name WAN-IOT rule 2 log
+set firewall ipv4 name WAN-IOT rule 2 state 'invalid'
+set firewall ipv4 name WAN-LAN default-action 'drop'
+set firewall ipv4 name WAN-LAN default-log
+set firewall ipv4 name WAN-LAN rule 1 action 'return'
+set firewall ipv4 name WAN-LAN rule 1 state 'established'
+set firewall ipv4 name WAN-LAN rule 1 state 'related'
+set firewall ipv4 name WAN-LAN rule 2 action 'drop'
+set firewall ipv4 name WAN-LAN rule 2 log
+set firewall ipv4 name WAN-LAN rule 2 state 'invalid'
+set firewall ipv4 name WAN-LAN rule 1000 action 'return'
+set firewall ipv4 name WAN-LAN rule 1000 destination address '172.16.33.40'
+set firewall ipv4 name WAN-LAN rule 1000 destination port '3389'
+set firewall ipv4 name WAN-LAN rule 1000 protocol 'tcp'
+set firewall ipv4 name WAN-LAN rule 1000 source group network-group 'SSH-IN-ALLOW'
+set firewall ipv4 name WAN-LOCAL default-action 'drop'
+set firewall ipv4 name WAN-LOCAL default-log
+set firewall ipv4 name WAN-LOCAL rule 1 action 'return'
+set firewall ipv4 name WAN-LOCAL rule 1 state 'established'
+set firewall ipv4 name WAN-LOCAL rule 1 state 'related'
+set firewall ipv4 name WAN-LOCAL rule 2 action 'drop'
+set firewall ipv4 name WAN-LOCAL rule 2 log
+set firewall ipv4 name WAN-LOCAL rule 2 state 'invalid'
+set firewall ipv4 name WAN-LOCAL rule 22 action 'return'
+set firewall ipv4 name WAN-LOCAL rule 22 destination port '22'
+set firewall ipv4 name WAN-LOCAL rule 22 protocol 'tcp'
+set firewall ipv4 name WAN-LOCAL rule 22 source group network-group 'SSH-IN-ALLOW'
+set firewall ipv6 name ALLOW-ALL-6 default-action 'return'
+set firewall ipv6 name ALLOW-BASIC-6 default-action 'drop'
+set firewall ipv6 name ALLOW-BASIC-6 default-log
+set firewall ipv6 name ALLOW-BASIC-6 rule 1 action 'return'
+set firewall ipv6 name ALLOW-BASIC-6 rule 1 state 'established'
+set firewall ipv6 name ALLOW-BASIC-6 rule 1 state 'related'
+set firewall ipv6 name ALLOW-BASIC-6 rule 2 action 'drop'
+set firewall ipv6 name ALLOW-BASIC-6 rule 2 state 'invalid'
+set firewall ipv6 name ALLOW-BASIC-6 rule 10 action 'return'
+set firewall ipv6 name ALLOW-BASIC-6 rule 10 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-BASIC-6 rule 15 action 'return'
+set firewall ipv6 name ALLOW-BASIC-6 rule 15 icmpv6 type '1'
+set firewall ipv6 name ALLOW-BASIC-6 rule 15 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-BASIC-6 rule 16 action 'return'
+set firewall ipv6 name ALLOW-BASIC-6 rule 16 icmpv6 code '1'
+set firewall ipv6 name ALLOW-BASIC-6 rule 16 icmpv6 type '1'
+set firewall ipv6 name ALLOW-BASIC-6 rule 16 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-BASIC-6 rule 17 action 'return'
+set firewall ipv6 name ALLOW-BASIC-6 rule 17 icmpv6 type-name 'destination-unreachable'
+set firewall ipv6 name ALLOW-BASIC-6 rule 17 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 default-action 'drop'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 default-log
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 1 action 'return'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 1 state 'established'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 1 state 'related'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 2 action 'drop'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 2 state 'invalid'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 10 action 'return'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 10 destination group network-group 'LOCAL-ADDRESSES'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 10 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 10 source address 'fe80::/10'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 20 action 'return'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 20 icmpv6 type-name 'echo-request'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 20 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 21 action 'return'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 21 icmpv6 type-name 'destination-unreachable'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 21 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 22 action 'return'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 22 icmpv6 type-name 'packet-too-big'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 22 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 23 action 'return'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 23 icmpv6 type-name 'time-exceeded'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 23 protocol 'ipv6-icmp'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 24 action 'return'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 24 icmpv6 type-name 'parameter-problem'
+set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 24 protocol 'ipv6-icmp'
+set firewall ipv6 name WAN-LOCAL-6 default-action 'drop'
+set firewall ipv6 name WAN-LOCAL-6 default-log
+set firewall ipv6 name WAN-LOCAL-6 rule 1 action 'return'
+set firewall ipv6 name WAN-LOCAL-6 rule 1 state 'established'
+set firewall ipv6 name WAN-LOCAL-6 rule 1 state 'related'
+set firewall ipv6 name WAN-LOCAL-6 rule 2 action 'drop'
+set firewall ipv6 name WAN-LOCAL-6 rule 2 state 'invalid'
+set firewall ipv6 name WAN-LOCAL-6 rule 10 action 'return'
+set firewall ipv6 name WAN-LOCAL-6 rule 10 destination address 'ff02::/64'
+set firewall ipv6 name WAN-LOCAL-6 rule 10 protocol 'ipv6-icmp'
+set firewall ipv6 name WAN-LOCAL-6 rule 10 source address 'fe80::/10'
+set firewall ipv6 name WAN-LOCAL-6 rule 50 action 'return'
+set firewall ipv6 name WAN-LOCAL-6 rule 50 description 'DHCPv6'
+set firewall ipv6 name WAN-LOCAL-6 rule 50 destination address 'fe80::/10'
+set firewall ipv6 name WAN-LOCAL-6 rule 50 destination port '546'
+set firewall ipv6 name WAN-LOCAL-6 rule 50 protocol 'udp'
+set firewall ipv6 name WAN-LOCAL-6 rule 50 source address 'fe80::/10'
+set firewall ipv6 name WAN-LOCAL-6 rule 50 source port '547'
+set firewall zone DMZ default-action 'drop'
+set firewall zone DMZ from GUEST firewall name 'GUEST-DMZ'
+set firewall zone DMZ from LAN firewall name 'LAN-DMZ'
+set firewall zone DMZ from LOCAL firewall name 'LOCAL-DMZ'
+set firewall zone DMZ from WAN firewall name 'WAN-DMZ'
+set firewall zone DMZ interface 'eth0.50'
+set firewall zone GUEST default-action 'drop'
+set firewall zone GUEST from DMZ firewall name 'DMZ-GUEST'
+set firewall zone GUEST from IOT firewall name 'IOT-GUEST'
+set firewall zone GUEST from LAN firewall name 'LAN-GUEST'
+set firewall zone GUEST from LOCAL firewall ipv6-name 'ALLOW-ALL-6'
+set firewall zone GUEST from LOCAL firewall name 'LOCAL-GUEST'
+set firewall zone GUEST from WAN firewall ipv6-name 'ALLOW-ESTABLISHED-6'
+set firewall zone GUEST from WAN firewall name 'WAN-GUEST'
+set firewall zone GUEST interface 'eth0.20'
+set firewall zone IOT default-action 'drop'
+set firewall zone IOT from GUEST firewall name 'GUEST-IOT'
+set firewall zone IOT from LAN firewall name 'LAN-IOT'
+set firewall zone IOT from LOCAL firewall name 'LOCAL-IOT'
+set firewall zone IOT from WAN firewall name 'WAN-IOT'
+set firewall zone IOT interface 'eth0.35'
+set firewall zone LAN default-action 'drop'
+set firewall zone LAN from DMZ firewall name 'DMZ-LAN'
+set firewall zone LAN from GUEST firewall name 'GUEST-LAN'
+set firewall zone LAN from IOT firewall name 'IOT-LAN'
+set firewall zone LAN from LOCAL firewall ipv6-name 'ALLOW-ALL-6'
+set firewall zone LAN from LOCAL firewall name 'LOCAL-LAN'
+set firewall zone LAN from WAN firewall ipv6-name 'ALLOW-ESTABLISHED-6'
+set firewall zone LAN from WAN firewall name 'WAN-LAN'
+set firewall zone LAN interface 'eth0.5'
+set firewall zone LAN interface 'eth0.10'
+set firewall zone LAN interface 'eth0.100'
+set firewall zone LAN interface 'eth0.201'
+set firewall zone LAN interface 'eth0.202'
+set firewall zone LAN interface 'eth0.203'
+set firewall zone LAN interface 'eth0.204'
+set firewall zone LOCAL default-action 'drop'
+set firewall zone LOCAL from DMZ firewall name 'DMZ-LOCAL'
+set firewall zone LOCAL from GUEST firewall ipv6-name 'ALLOW-ESTABLISHED-6'
+set firewall zone LOCAL from GUEST firewall name 'GUEST-LOCAL'
+set firewall zone LOCAL from IOT firewall name 'IOT-LOCAL'
+set firewall zone LOCAL from LAN firewall ipv6-name 'ALLOW-ALL-6'
+set firewall zone LOCAL from LAN firewall name 'LAN-LOCAL'
+set firewall zone LOCAL from WAN firewall ipv6-name 'WAN-LOCAL-6'
+set firewall zone LOCAL from WAN firewall name 'WAN-LOCAL'
+set firewall zone LOCAL local-zone
+set firewall zone WAN default-action 'drop'
+set firewall zone WAN from DMZ firewall name 'DMZ-WAN'
+set firewall zone WAN from GUEST firewall ipv6-name 'ALLOW-ALL-6'
+set firewall zone WAN from GUEST firewall name 'GUEST-WAN'
+set firewall zone WAN from IOT firewall name 'IOT-WAN'
+set firewall zone WAN from LAN firewall ipv6-name 'ALLOW-ALL-6'
+set firewall zone WAN from LAN firewall name 'LAN-WAN'
+set firewall zone WAN from LOCAL firewall ipv6-name 'ALLOW-ALL-6'
+set firewall zone WAN from LOCAL firewall name 'LOCAL-WAN'
+set firewall zone WAN interface 'pppoe0'
+set interfaces dummy dum0 address '172.16.254.30/32'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth0 vif 5 address '172.16.37.254/24'
+set interfaces ethernet eth0 vif 10 address '172.16.33.254/24'
+set interfaces ethernet eth0 vif 10 ip adjust-mss '1320'
+set interfaces ethernet eth0 vif 10 ipv6 adjust-mss '1300'
+set interfaces ethernet eth0 vif 20 address '172.31.0.254/24'
+set interfaces ethernet eth0 vif 35 address '172.16.35.254/24'
+set interfaces ethernet eth0 vif 50 address '172.16.36.254/24'
+set interfaces ethernet eth0 vif 100 address '172.16.100.254/24'
+set interfaces ethernet eth0 vif 201 address '172.18.201.254/24'
+set interfaces ethernet eth0 vif 202 address '172.18.202.254/24'
+set interfaces ethernet eth0 vif 203 address '172.18.203.254/24'
+set interfaces ethernet eth0 vif 204 address '172.18.204.254/24'
+set interfaces ethernet eth1 vif 7 description 'FTTH-PPPoE'
+set interfaces loopback lo address '172.16.254.30/32'
+set interfaces pppoe pppoe0 authentication password 'vyos'
+set interfaces pppoe pppoe0 authentication username 'vyos'
+set interfaces pppoe pppoe0 description 'FTTH 100/50MBit'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 address '1'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 sla-id '10'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.20 address '1'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.20 sla-id '20'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 length '56'
+set interfaces pppoe pppoe0 ip adjust-mss '1452'
+set interfaces pppoe pppoe0 ipv6 address autoconf
+set interfaces pppoe pppoe0 ipv6 adjust-mss '1432'
+set interfaces pppoe pppoe0 mtu '1492'
+set interfaces pppoe pppoe0 no-peer-dns
+set interfaces pppoe pppoe0 source-interface 'eth1.7'
+set nat destination rule 100 description 'HTTP(S)'
+set nat destination rule 100 destination port '80,443'
+set nat destination rule 100 inbound-interface name 'pppoe0'
+set nat destination rule 100 log
+set nat destination rule 100 protocol 'tcp'
+set nat destination rule 100 translation address '172.16.36.10'
+set nat destination rule 1000 destination port '3389'
+set nat destination rule 1000 disable
+set nat destination rule 1000 inbound-interface name 'pppoe0'
+set nat destination rule 1000 protocol 'tcp'
+set nat destination rule 1000 translation address '172.16.33.40'
+set nat destination rule 8000 destination port '10000'
+set nat destination rule 8000 inbound-interface name 'pppoe0'
+set nat destination rule 8000 log
+set nat destination rule 8000 protocol 'udp'
+set nat destination rule 8000 translation address '172.31.0.200'
+set nat source rule 100 log
+set nat source rule 100 outbound-interface name 'pppoe0'
+set nat source rule 100 source address '172.16.32.0/19'
+set nat source rule 100 translation address 'masquerade'
+set nat source rule 200 outbound-interface name 'pppoe0'
+set nat source rule 200 source address '172.16.100.0/24'
+set nat source rule 200 translation address 'masquerade'
+set nat source rule 300 outbound-interface name 'pppoe0'
+set nat source rule 300 source address '172.31.0.0/24'
+set nat source rule 300 translation address 'masquerade'
+set nat source rule 400 outbound-interface name 'pppoe0'
+set nat source rule 400 source address '172.18.200.0/21'
+set nat source rule 400 translation address 'masquerade'
+set protocols static route 10.0.0.0/8 blackhole distance '254'
+set protocols static route 169.254.0.0/16 blackhole distance '254'
+set protocols static route 172.16.0.0/12 blackhole distance '254'
+set protocols static route 192.168.0.0/16 blackhole distance '254'
+set protocols static route6 2000::/3 interface pppoe0
+set qos policy shaper QoS bandwidth '50mbit'
+set qos policy shaper QoS default bandwidth '100%'
+set qos policy shaper QoS default burst '15k'
+set qos policy shaper QoS default queue-limit '1000'
+set qos policy shaper QoS default queue-type 'fq-codel'
+set service dhcp-server shared-network-name BACKBONE authoritative
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 lease '86400'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option default-router '172.16.37.254'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-search 'vyos.net'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option name-server '172.16.254.30'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option ntp-server '172.16.254.30'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 start '172.16.37.120'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 stop '172.16.37.149'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1.wue3 ip-address '172.16.37.231'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1.wue3 mac '18:e8:29:6c:c3:a5'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 subnet-id '1'
+set service dhcp-server shared-network-name GUEST authoritative
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 lease '86400'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option default-router '172.31.0.254'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-search 'vyos.net'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option name-server '172.31.0.254'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 start '172.31.0.100'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 stop '172.31.0.199'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 static-mapping host01 ip-address '172.31.0.200'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 static-mapping host01 mac '00:50:00:00:00:01'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 static-mapping host02 ip-address '172.31.0.184'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 static-mapping host02 mac '00:50:00:00:00:02'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 subnet-id '2'
+set service dhcp-server shared-network-name IOT authoritative
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 lease '86400'
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option default-router '172.16.35.254'
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option domain-search 'vyos.net'
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option name-server '172.16.254.30'
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option ntp-server '172.16.254.30'
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 range 0 start '172.16.35.101'
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 range 0 stop '172.16.35.149'
+set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 subnet-id '3'
+set service dhcp-server shared-network-name LAN authoritative
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 lease '86400'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option default-router '172.16.33.254'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-search 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option name-server '172.16.254.30'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option ntp-server '172.16.254.30'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 start '172.16.33.100'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 stop '172.16.33.189'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 subnet-id '4'
+set service dns forwarding allow-from '172.16.0.0/12'
+set service dns forwarding cache-size '0'
+set service dns forwarding domain 16.172.in-addr.arpa addnta
+set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.10
+set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.20
+set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.110.30
+set service dns forwarding domain 16.172.in-addr.arpa recursion-desired
+set service dns forwarding domain 18.172.in-addr.arpa addnta
+set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.10
+set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.20
+set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.110.30
+set service dns forwarding domain 18.172.in-addr.arpa recursion-desired
+set service dns forwarding domain vyos.net addnta
+set service dns forwarding domain vyos.net name-server 172.16.100.10
+set service dns forwarding domain vyos.net name-server 172.16.100.20
+set service dns forwarding domain vyos.net name-server 172.16.110.30
+set service dns forwarding domain vyos.net recursion-desired
+set service dns forwarding ignore-hosts-file
+set service dns forwarding listen-address '172.16.254.30'
+set service dns forwarding listen-address '172.31.0.254'
+set service dns forwarding negative-ttl '60'
+set service lldp legacy-protocols cdp
+set service lldp snmp
+set service mdns repeater interface 'eth0.35'
+set service mdns repeater interface 'eth0.10'
+set service ntp allow-client address '172.16.0.0/12'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set service router-advert interface eth0.10 prefix ::/64 preferred-lifetime '2700'
+set service router-advert interface eth0.10 prefix ::/64 valid-lifetime '5400'
+set service router-advert interface eth0.20 prefix ::/64 preferred-lifetime '2700'
+set service router-advert interface eth0.20 prefix ::/64 valid-lifetime '5400'
+set service snmp community fooBar authorization 'ro'
+set service snmp community fooBar network '172.16.100.0/24'
+set service snmp contact 'VyOS maintainers and contributors <maintainers@vyos.io>'
+set service snmp listen-address 172.16.254.30 port '161'
+set service snmp location 'The Internet'
+set service ssh disable-host-validation
+set service ssh port '22'
+set system config-management commit-revisions '200'
+set system conntrack expect-table-size '2048'
+set system conntrack hash-size '32768'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system conntrack table-size '262144'
+set system conntrack timeout
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system name-server '172.16.254.30'
+set system option ctrl-alt-delete 'ignore'
+set system option reboot-on-panic
+set system option startup-beep
+set system syslog global facility all level 'debug'
+set system syslog global facility local7 level 'debug'
+set system syslog host 172.16.100.1 facility all level 'warning'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/dialup-router-medium-vpn b/smoketest/config-tests/dialup-router-medium-vpn
index 8c221707f..67af456f4 100644
--- a/smoketest/config-tests/dialup-router-medium-vpn
+++ b/smoketest/config-tests/dialup-router-medium-vpn
@@ -25,18 +25,12 @@ set high-availability vrrp sync-group failover-group member 'LAN'
set interfaces ethernet eth0 duplex 'auto'
set interfaces ethernet eth0 mtu '9000'
set interfaces ethernet eth0 offload gro
-set interfaces ethernet eth0 offload gso
-set interfaces ethernet eth0 offload sg
-set interfaces ethernet eth0 offload tso
set interfaces ethernet eth0 speed 'auto'
set interfaces ethernet eth1 address '192.168.0.250/24'
set interfaces ethernet eth1 duplex 'auto'
set interfaces ethernet eth1 ip source-validation 'strict'
set interfaces ethernet eth1 mtu '9000'
set interfaces ethernet eth1 offload gro
-set interfaces ethernet eth1 offload gso
-set interfaces ethernet eth1 offload sg
-set interfaces ethernet eth1 offload tso
set interfaces ethernet eth1 speed 'auto'
set interfaces loopback lo
set interfaces openvpn vtun0 encryption ncp-ciphers 'aes256'
@@ -130,6 +124,7 @@ set interfaces wireguard wg0 peer red persistent-keepalive '20'
set interfaces wireguard wg0 peer red preshared-key 'CumyXX7osvUT9AwnS+m2TEfCaL0Ptc2LfuZ78Sujuk8='
set interfaces wireguard wg0 peer red public-key 'ALGWvMJCKpHF2tVH3hEIHqUe9iFfAmZATUUok/WQzks='
set interfaces wireguard wg0 port '7777'
+set interfaces wireguard wg0 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0='
set interfaces wireguard wg1 address '10.89.90.2/30'
set interfaces wireguard wg1 ip adjust-mss '1380'
set interfaces wireguard wg1 peer sam address '192.0.2.45'
@@ -140,6 +135,7 @@ set interfaces wireguard wg1 peer sam port '1200'
set interfaces wireguard wg1 peer sam preshared-key 'XpFtzx2Z+nR8pBv9/sSf7I94OkZkVYTz0AeU5Q/QQUE='
set interfaces wireguard wg1 peer sam public-key 'v5zfKGvH6W/lfDXJ0en96lvKo1gfFxMUWxe02+Fj5BU='
set interfaces wireguard wg1 port '7778'
+set interfaces wireguard wg1 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0='
set nat destination rule 50 destination port '49371'
set nat destination rule 50 inbound-interface name 'pppoe0'
set nat destination rule 50 protocol 'tcp_udp'
@@ -295,9 +291,18 @@ set service ssh listen-address '192.168.0.1'
set service ssh listen-address '192.168.10.1'
set service ssh listen-address '192.168.0.250'
set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system ip arp table-size '1024'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
set system name-server '192.168.0.1'
set system name-server 'pppoe0'
set system option ctrl-alt-delete 'ignore'
diff --git a/smoketest/config-tests/dialup-router-wireguard-ipv6 b/smoketest/config-tests/dialup-router-wireguard-ipv6
index 814a62d55..ff4bf89c2 100644
--- a/smoketest/config-tests/dialup-router-wireguard-ipv6
+++ b/smoketest/config-tests/dialup-router-wireguard-ipv6
@@ -1,207 +1,3 @@
-set interfaces dummy dum0 address '172.16.254.30/32'
-set interfaces ethernet eth0 vif 10 address '172.16.33.254/24'
-set interfaces ethernet eth0 vif 10 address '172.16.40.254/24'
-set interfaces ethernet eth0 vif 5 address '172.16.37.254/24'
-set interfaces ethernet eth0 vif 50 address '172.16.36.254/24'
-set interfaces ethernet eth0 ring-buffer rx '256'
-set interfaces ethernet eth0 ring-buffer tx '256'
-set interfaces ethernet eth1 offload gro
-set interfaces ethernet eth1 offload gso
-set interfaces ethernet eth1 offload sg
-set interfaces ethernet eth1 offload tso
-set interfaces ethernet eth1 vif 20 address '172.31.0.254/24'
-set interfaces ethernet eth2 disable
-set interfaces ethernet eth2 offload gro
-set interfaces ethernet eth2 offload gso
-set interfaces ethernet eth2 offload sg
-set interfaces ethernet eth2 offload tso
-set interfaces ethernet eth3 offload gro
-set interfaces ethernet eth3 offload gso
-set interfaces ethernet eth3 offload sg
-set interfaces ethernet eth3 offload tso
-set interfaces ethernet eth3 ring-buffer rx '256'
-set interfaces ethernet eth3 ring-buffer tx '256'
-set interfaces ethernet eth3 vif 7
-set interfaces loopback lo address '172.16.254.30/32'
-set interfaces pppoe pppoe0 authentication password 'vyos'
-set interfaces pppoe pppoe0 authentication username 'vyos'
-set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 address '1'
-set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 sla-id '10'
-set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth1.20 address '1'
-set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth1.20 sla-id '20'
-set interfaces pppoe pppoe0 dhcpv6-options pd 0 length '56'
-set interfaces pppoe pppoe0 ip adjust-mss '1452'
-set interfaces pppoe pppoe0 ipv6 address autoconf
-set interfaces pppoe pppoe0 ipv6 adjust-mss '1432'
-set interfaces pppoe pppoe0 no-peer-dns
-set interfaces pppoe pppoe0 source-interface 'eth3.7'
-set interfaces wireguard wg100 address '172.16.252.128/31'
-set interfaces wireguard wg100 mtu '1500'
-set interfaces wireguard wg100 peer HR6 address '100.65.151.213'
-set interfaces wireguard wg100 peer HR6 allowed-ips '0.0.0.0/0'
-set interfaces wireguard wg100 peer HR6 port '10100'
-set interfaces wireguard wg100 port '10100'
-set interfaces wireguard wg200 address '172.16.252.130/31'
-set interfaces wireguard wg200 mtu '1500'
-set interfaces wireguard wg200 peer WH56 address '80.151.69.205'
-set interfaces wireguard wg200 peer WH56 allowed-ips '0.0.0.0/0'
-set interfaces wireguard wg200 peer WH56 port '10200'
-set interfaces wireguard wg200 port '10200'
-set interfaces wireguard wg666 address '172.29.0.1/31'
-set interfaces wireguard wg666 mtu '1500'
-set interfaces wireguard wg666 peer WH34 address '100.65.55.1'
-set interfaces wireguard wg666 peer WH34 allowed-ips '0.0.0.0/0'
-set interfaces wireguard wg666 peer WH34 port '10666'
-set interfaces wireguard wg666 port '10666'
-set protocols ospf area 0 network '172.16.37.0/24'
-set protocols ospf area 0 network '172.16.254.30/32'
-set protocols ospf area 0 network '172.18.202.0/24'
-set protocols ospf area 0 network '172.18.203.0/24'
-set protocols ospf area 0 network '172.18.204.0/24'
-set protocols ospf interface eth0.5 authentication md5 key-id 10 md5-key 'ospf'
-set protocols ospf interface eth0.5 dead-interval '40'
-set protocols ospf interface eth0.5 hello-interval '10'
-set protocols ospf interface eth0.5 passive disable
-set protocols ospf interface eth0.5 priority '1'
-set protocols ospf interface eth0.5 retransmit-interval '5'
-set protocols ospf interface eth0.5 transmit-delay '1'
-set protocols ospf log-adjacency-changes detail
-set protocols ospf parameters router-id '172.16.254.30'
-set protocols ospf default-information originate always
-set protocols ospf default-information originate metric-type '2'
-set protocols ospf redistribute connected metric-type '2'
-set protocols ospf redistribute connected route-map 'MAP-OSPF-CONNECTED'
-set protocols static route 10.0.0.0/8 blackhole distance '254'
-set protocols static route 169.254.0.0/16 blackhole distance '254'
-set protocols static route 172.16.0.0/12 blackhole distance '254'
-set protocols static route 172.16.32.0/21 blackhole
-set protocols static route 172.18.0.0/16 blackhole
-set protocols static route 172.29.0.2/31 next-hop 172.29.0.0
-set protocols static route 192.168.0.0/16 blackhole distance '254'
-set protocols static route 192.168.189.0/24 next-hop 172.29.0.0
-set protocols static route6 2000::/3 interface pppoe0
-set protocols bfd peer 172.16.252.129
-set protocols bfd peer 172.16.252.131
-set protocols bfd peer 172.18.254.201
-set protocols bgp address-family ipv4-unicast network 172.16.32.0/21
-set protocols bgp address-family ipv4-unicast network 172.16.100.0/24
-set protocols bgp address-family ipv4-unicast network 172.16.252.128/31
-set protocols bgp address-family ipv4-unicast network 172.16.252.130/31
-set protocols bgp address-family ipv4-unicast network 172.16.254.30/32
-set protocols bgp address-family ipv4-unicast network 172.18.0.0/16
-set protocols bgp neighbor 172.16.252.129 peer-group 'WIREGUARD'
-set protocols bgp neighbor 172.16.252.131 peer-group 'WIREGUARD'
-set protocols bgp neighbor 172.18.254.201 address-family ipv4-unicast nexthop-self
-set protocols bgp neighbor 172.18.254.201 bfd
-set protocols bgp neighbor 172.18.254.201 remote-as '64503'
-set protocols bgp neighbor 172.18.254.201 update-source 'dum0'
-set protocols bgp parameters log-neighbor-changes
-set protocols bgp peer-group WIREGUARD address-family ipv4-unicast soft-reconfiguration inbound
-set protocols bgp peer-group WIREGUARD bfd
-set protocols bgp peer-group WIREGUARD remote-as 'external'
-set protocols bgp system-as '64503'
-set protocols bgp timers holdtime '30'
-set protocols bgp timers keepalive '10'
-set service lldp legacy-protocols cdp
-set service lldp legacy-protocols edp
-set service lldp legacy-protocols fdp
-set service lldp legacy-protocols sonmp
-set service lldp snmp
-set service ntp allow-client address '172.16.0.0/12'
-set service ntp server time1.vyos.net
-set service ntp server time2.vyos.net
-set service dhcp-server shared-network-name BACKBONE authoritative
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 lease '86400'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option default-router '172.16.37.254'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-name 'vyos.net'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-search 'vyos.net'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option name-server '172.16.254.30'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option ntp-server '172.16.254.30'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 start '172.16.37.120'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 stop '172.16.37.149'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1 ip-address '172.16.37.231'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1 mac '02:00:00:00:ee:18'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP2 ip-address '172.16.37.232'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP2 mac '02:00:00:00:52:84'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP3 ip-address '172.16.37.233'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP3 mac '02:00:00:00:51:c0'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP4 ip-address '172.16.37.234'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP4 mac '02:00:00:00:e6:fc'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP5 ip-address '172.16.37.235'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP5 mac '02:00:00:00:c3:50'
-set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 subnet-id '1'
-set service dhcp-server shared-network-name GUEST authoritative
-set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 lease '86400'
-set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option default-router '172.31.0.254'
-set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-name 'vyos.net'
-set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-search 'vyos.net'
-set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option name-server '172.31.0.254'
-set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 start '172.31.0.101'
-set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 stop '172.31.0.199'
-set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 subnet-id '2'
-set service dhcp-server shared-network-name LAN authoritative
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 lease '86400'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option default-router '172.16.33.254'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-name 'vyos.net'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-search 'vyos.net'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option name-server '172.16.254.30'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option ntp-server '172.16.254.30'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 start '172.16.33.100'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 stop '172.16.33.189'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping four ip-address '172.16.33.214'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping four mac '02:00:00:00:c4:33'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping one ip-address '172.16.33.221'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping one mac '02:00:00:00:eb:a6'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping three ip-address '172.16.33.212'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping three mac '02:00:00:00:12:c7'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping two ip-address '172.16.33.211'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping two mac '02:00:00:00:58:90'
-set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 subnet-id '3'
-set service dns dynamic name service-vyos-pppoe0 address interface 'pppoe0'
-set service dns dynamic name service-vyos-pppoe0 host-name 'r1.vyos.net'
-set service dns dynamic name service-vyos-pppoe0 password 'vyos'
-set service dns dynamic name service-vyos-pppoe0 protocol 'dyndns2'
-set service dns dynamic name service-vyos-pppoe0 server 'dyndns.vyos.io'
-set service dns dynamic name service-vyos-pppoe0 username 'vyos-vyos'
-set service dns forwarding allow-from '172.16.0.0/12'
-set service dns forwarding domain 16.172.in-addr.arpa addnta
-set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.10
-set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.20
-set service dns forwarding domain 16.172.in-addr.arpa recursion-desired
-set service dns forwarding domain 18.172.in-addr.arpa addnta
-set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.10
-set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.20
-set service dns forwarding domain 18.172.in-addr.arpa recursion-desired
-set service dns forwarding domain vyos.net addnta
-set service dns forwarding domain vyos.net name-server 172.16.100.10
-set service dns forwarding domain vyos.net name-server 172.16.100.20
-set service dns forwarding domain vyos.net recursion-desired
-set service dns forwarding ignore-hosts-file
-set service dns forwarding listen-address '172.16.254.30'
-set service dns forwarding listen-address '172.31.0.254'
-set service dns forwarding negative-ttl '60'
-set service router-advert interface eth0.10 prefix ::/64 preferred-lifetime '2700'
-set service router-advert interface eth0.10 prefix ::/64 valid-lifetime '5400'
-set service router-advert interface eth1.20 prefix ::/64 preferred-lifetime '2700'
-set service router-advert interface eth1.20 prefix ::/64 valid-lifetime '5400'
-set service snmp community ro-community authorization 'ro'
-set service snmp community ro-community network '172.16.100.0/24'
-set service snmp contact 'VyOS'
-set service snmp listen-address 172.16.254.30 port '161'
-set service snmp location 'CLOUD'
-set system conntrack expect-table-size '2048'
-set system conntrack hash-size '32768'
-set system conntrack table-size '262144'
-set system domain-name 'vyos.net'
-set system host-name 'r1'
-set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
-set system login user vyos authentication plaintext-password ''
-set system option ctrl-alt-delete 'ignore'
-set system option performance 'latency'
-set system option startup-beep
-set system syslog global facility all level 'debug'
-set system syslog host 172.16.100.1 facility all level 'warning'
-set system console device ttyS0 speed '115200'
set firewall global-options all-ping 'enable'
set firewall global-options broadcast-ping 'disable'
set firewall global-options ip-src-route 'disable'
@@ -634,6 +430,67 @@ set firewall zone WAN from LOCAL firewall ipv6-name 'ALLOW-ALL-6'
set firewall zone WAN from LOCAL firewall name 'LOCAL-WAN'
set firewall zone WAN interface 'pppoe0'
set firewall zone WAN interface 'wg666'
+set interfaces dummy dum0 address '172.16.254.30/32'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth0 ring-buffer rx '256'
+set interfaces ethernet eth0 ring-buffer tx '256'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth0 vif 5 address '172.16.37.254/24'
+set interfaces ethernet eth0 vif 10 address '172.16.33.254/24'
+set interfaces ethernet eth0 vif 10 address '172.16.40.254/24'
+set interfaces ethernet eth0 vif 50 address '172.16.36.254/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 offload gro
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth1 vif 20 address '172.31.0.254/24'
+set interfaces ethernet eth2 disable
+set interfaces ethernet eth2 duplex 'auto'
+set interfaces ethernet eth2 offload gro
+set interfaces ethernet eth2 speed 'auto'
+set interfaces ethernet eth3 duplex 'auto'
+set interfaces ethernet eth3 offload gro
+set interfaces ethernet eth3 ring-buffer rx '256'
+set interfaces ethernet eth3 ring-buffer tx '256'
+set interfaces ethernet eth3 speed 'auto'
+set interfaces ethernet eth3 vif 7
+set interfaces loopback lo address '172.16.254.30/32'
+set interfaces pppoe pppoe0 authentication password 'vyos'
+set interfaces pppoe pppoe0 authentication username 'vyos'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 address '1'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 sla-id '10'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth1.20 address '1'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth1.20 sla-id '20'
+set interfaces pppoe pppoe0 dhcpv6-options pd 0 length '56'
+set interfaces pppoe pppoe0 ip adjust-mss '1452'
+set interfaces pppoe pppoe0 ipv6 address autoconf
+set interfaces pppoe pppoe0 ipv6 adjust-mss '1432'
+set interfaces pppoe pppoe0 no-peer-dns
+set interfaces pppoe pppoe0 source-interface 'eth3.7'
+set interfaces wireguard wg100 address '172.16.252.128/31'
+set interfaces wireguard wg100 mtu '1500'
+set interfaces wireguard wg100 peer HR6 address '100.65.151.213'
+set interfaces wireguard wg100 peer HR6 allowed-ips '0.0.0.0/0'
+set interfaces wireguard wg100 peer HR6 port '10100'
+set interfaces wireguard wg100 peer HR6 public-key 'yLpi+UZuI019bmWH2h5fX3gStbpPPPLgEoYMyrdkOnQ='
+set interfaces wireguard wg100 port '10100'
+set interfaces wireguard wg100 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0='
+set interfaces wireguard wg200 address '172.16.252.130/31'
+set interfaces wireguard wg200 mtu '1500'
+set interfaces wireguard wg200 peer WH56 address '80.151.69.205'
+set interfaces wireguard wg200 peer WH56 allowed-ips '0.0.0.0/0'
+set interfaces wireguard wg200 peer WH56 port '10200'
+set interfaces wireguard wg200 peer WH56 public-key 'XQbkj6vnKKBJfJQyThXysU0iGxCvEOEb31kpaZgkrD8='
+set interfaces wireguard wg200 port '10200'
+set interfaces wireguard wg200 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0='
+set interfaces wireguard wg666 address '172.29.0.1/31'
+set interfaces wireguard wg666 mtu '1500'
+set interfaces wireguard wg666 peer WH34 address '100.65.55.1'
+set interfaces wireguard wg666 peer WH34 allowed-ips '0.0.0.0/0'
+set interfaces wireguard wg666 peer WH34 port '10666'
+set interfaces wireguard wg666 peer WH34 public-key 'yaTN4+xAafKM04D+Baeg5GWfbdaw35TE9HQivwRgAk0='
+set interfaces wireguard wg666 port '10666'
+set interfaces wireguard wg666 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0='
set nat destination rule 8000 destination port '10000'
set nat destination rule 8000 inbound-interface name 'pppoe0'
set nat destination rule 8000 protocol 'udp'
@@ -667,8 +524,174 @@ set policy route-map MAP-OSPF-CONNECTED rule 20 action 'permit'
set policy route-map MAP-OSPF-CONNECTED rule 20 match interface 'eth0.10'
set policy route-map MAP-OSPF-CONNECTED rule 40 action 'permit'
set policy route-map MAP-OSPF-CONNECTED rule 40 match interface 'eth0.50'
+set protocols bfd peer 172.16.252.129
+set protocols bfd peer 172.16.252.131
+set protocols bfd peer 172.18.254.201
+set protocols bgp address-family ipv4-unicast network 172.16.32.0/21
+set protocols bgp address-family ipv4-unicast network 172.16.100.0/24
+set protocols bgp address-family ipv4-unicast network 172.16.252.128/31
+set protocols bgp address-family ipv4-unicast network 172.16.252.130/31
+set protocols bgp address-family ipv4-unicast network 172.16.254.30/32
+set protocols bgp address-family ipv4-unicast network 172.18.0.0/16
+set protocols bgp neighbor 172.16.252.129 peer-group 'WIREGUARD'
+set protocols bgp neighbor 172.16.252.131 peer-group 'WIREGUARD'
+set protocols bgp neighbor 172.18.254.201 address-family ipv4-unicast nexthop-self
+set protocols bgp neighbor 172.18.254.201 bfd
+set protocols bgp neighbor 172.18.254.201 remote-as '64503'
+set protocols bgp neighbor 172.18.254.201 update-source 'dum0'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp peer-group WIREGUARD address-family ipv4-unicast soft-reconfiguration inbound
+set protocols bgp peer-group WIREGUARD bfd
+set protocols bgp peer-group WIREGUARD remote-as 'external'
+set protocols bgp system-as '64503'
+set protocols bgp timers holdtime '30'
+set protocols bgp timers keepalive '10'
+set protocols ospf area 0 network '172.16.254.30/32'
+set protocols ospf area 0 network '172.16.37.0/24'
+set protocols ospf area 0 network '172.18.201.0/24'
+set protocols ospf area 0 network '172.18.202.0/24'
+set protocols ospf area 0 network '172.18.203.0/24'
+set protocols ospf area 0 network '172.18.204.0/24'
+set protocols ospf default-information originate always
+set protocols ospf default-information originate metric-type '2'
+set protocols ospf interface eth0.5 authentication md5 key-id 10 md5-key 'ospf'
+set protocols ospf interface eth0.5 dead-interval '40'
+set protocols ospf interface eth0.5 hello-interval '10'
+set protocols ospf interface eth0.5 passive disable
+set protocols ospf interface eth0.5 priority '1'
+set protocols ospf interface eth0.5 retransmit-interval '5'
+set protocols ospf interface eth0.5 transmit-delay '1'
+set protocols ospf log-adjacency-changes detail
+set protocols ospf parameters abr-type 'cisco'
+set protocols ospf parameters router-id '172.16.254.30'
+set protocols ospf passive-interface 'default'
+set protocols ospf redistribute connected metric-type '2'
+set protocols ospf redistribute connected route-map 'MAP-OSPF-CONNECTED'
+set protocols static route 10.0.0.0/8 blackhole distance '254'
+set protocols static route 169.254.0.0/16 blackhole distance '254'
+set protocols static route 172.16.0.0/12 blackhole distance '254'
+set protocols static route 172.16.32.0/21 blackhole
+set protocols static route 172.18.0.0/16 blackhole
+set protocols static route 172.29.0.2/31 next-hop 172.29.0.0
+set protocols static route 192.168.0.0/16 blackhole distance '254'
+set protocols static route 192.168.189.0/24 next-hop 172.29.0.0
+set protocols static route6 2000::/3 interface pppoe0
set qos policy shaper QoS bandwidth '50mbit'
set qos policy shaper QoS default bandwidth '100%'
set qos policy shaper QoS default burst '15k'
set qos policy shaper QoS default queue-limit '1000'
set qos policy shaper QoS default queue-type 'fq-codel'
+set service dhcp-server shared-network-name BACKBONE authoritative
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 lease '86400'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option default-router '172.16.37.254'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-search 'vyos.net'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option name-server '172.16.254.30'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option ntp-server '172.16.254.30'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 start '172.16.37.120'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 stop '172.16.37.149'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1 ip-address '172.16.37.231'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1 mac '02:00:00:00:ee:18'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP2 ip-address '172.16.37.232'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP2 mac '02:00:00:00:52:84'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP3 ip-address '172.16.37.233'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP3 mac '02:00:00:00:51:c0'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP4 ip-address '172.16.37.234'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP4 mac '02:00:00:00:e6:fc'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP5 ip-address '172.16.37.235'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP5 mac '02:00:00:00:c3:50'
+set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 subnet-id '1'
+set service dhcp-server shared-network-name GUEST authoritative
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 lease '86400'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option default-router '172.31.0.254'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-search 'vyos.net'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option name-server '172.31.0.254'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 start '172.31.0.101'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 stop '172.31.0.199'
+set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 subnet-id '2'
+set service dhcp-server shared-network-name LAN authoritative
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 lease '86400'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option default-router '172.16.33.254'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-search 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option name-server '172.16.254.30'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option ntp-server '172.16.254.30'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 start '172.16.33.100'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 stop '172.16.33.189'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping four ip-address '172.16.33.214'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping four mac '02:00:00:00:c4:33'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping one ip-address '172.16.33.221'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping one mac '02:00:00:00:eb:a6'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping three ip-address '172.16.33.212'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping three mac '02:00:00:00:12:c7'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping two ip-address '172.16.33.211'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping two mac '02:00:00:00:58:90'
+set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 subnet-id '3'
+set service dns dynamic name service-vyos-pppoe0 address interface 'pppoe0'
+set service dns dynamic name service-vyos-pppoe0 host-name 'r1.vyos.net'
+set service dns dynamic name service-vyos-pppoe0 password 'vyos'
+set service dns dynamic name service-vyos-pppoe0 protocol 'dyndns2'
+set service dns dynamic name service-vyos-pppoe0 server 'dyndns.vyos.io'
+set service dns dynamic name service-vyos-pppoe0 username 'vyos-vyos'
+set service dns forwarding allow-from '172.16.0.0/12'
+set service dns forwarding domain 16.172.in-addr.arpa addnta
+set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.10
+set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.20
+set service dns forwarding domain 16.172.in-addr.arpa recursion-desired
+set service dns forwarding domain 18.172.in-addr.arpa addnta
+set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.10
+set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.20
+set service dns forwarding domain 18.172.in-addr.arpa recursion-desired
+set service dns forwarding domain vyos.net addnta
+set service dns forwarding domain vyos.net name-server 172.16.100.10
+set service dns forwarding domain vyos.net name-server 172.16.100.20
+set service dns forwarding domain vyos.net recursion-desired
+set service dns forwarding ignore-hosts-file
+set service dns forwarding listen-address '172.16.254.30'
+set service dns forwarding listen-address '172.31.0.254'
+set service dns forwarding negative-ttl '60'
+set service lldp legacy-protocols cdp
+set service lldp legacy-protocols edp
+set service lldp legacy-protocols fdp
+set service lldp legacy-protocols sonmp
+set service lldp snmp
+set service ntp allow-client address '172.16.0.0/12'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service router-advert interface eth0.10 prefix ::/64 preferred-lifetime '2700'
+set service router-advert interface eth0.10 prefix ::/64 valid-lifetime '5400'
+set service router-advert interface eth1.20 prefix ::/64 preferred-lifetime '2700'
+set service router-advert interface eth1.20 prefix ::/64 valid-lifetime '5400'
+set service snmp community ro-community authorization 'ro'
+set service snmp community ro-community network '172.16.100.0/24'
+set service snmp contact 'VyOS'
+set service snmp listen-address 172.16.254.30 port '161'
+set service snmp location 'CLOUD'
+set service ssh disable-host-validation
+set service ssh port '22'
+set system config-management commit-revisions '200'
+set system conntrack expect-table-size '2048'
+set system conntrack hash-size '32768'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system conntrack table-size '262144'
+set system conntrack timeout
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system host-name 'r1'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system name-server '172.16.254.30'
+set system option ctrl-alt-delete 'ignore'
+set system option performance 'latency'
+set system option reboot-on-panic
+set system option startup-beep
+set system syslog global facility all level 'debug'
+set system syslog global facility local7 level 'debug'
+set system syslog host 172.16.100.1 facility all level 'warning'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/egp-igp-route-maps b/smoketest/config-tests/egp-igp-route-maps
new file mode 100644
index 000000000..fc46d25ff
--- /dev/null
+++ b/smoketest/config-tests/egp-igp-route-maps
@@ -0,0 +1,46 @@
+set interfaces ethernet eth0 address '192.0.2.1/25'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 address '192.0.2.129/25'
+set interfaces ethernet eth1 address '2001:db8::1234/64'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set interfaces loopback lo
+set policy route-map zebra-bgp rule 10 action 'permit'
+set policy route-map zebra-isis rule 10 action 'permit'
+set policy route-map zebra-ospf rule 10 action 'permit'
+set policy route-map zebra-ospfv3 rule 10 action 'permit'
+set policy route-map zebra-ripng rule 10 action 'permit'
+set policy route-map zebra-static rule 10 action 'permit'
+set protocols bgp system-as '100'
+set protocols isis interface eth0
+set protocols isis net '49.0001.1921.6800.1002.00'
+set protocols ospf area 0 network '192.0.2.0/25'
+set protocols ospf area 0 network '192.0.2.128/25'
+set protocols ospf interface eth0 passive disable
+set protocols ospf interface eth1 passive disable
+set protocols ospf log-adjacency-changes
+set protocols ospf parameters abr-type 'cisco'
+set protocols ospf parameters router-id '1.1.1.1'
+set protocols ospf passive-interface 'default'
+set protocols ospfv3 area 0
+set protocols ospfv3 interface eth1 area '0'
+set protocols ospfv3 parameters router-id '1.1.1.1'
+set protocols ripng interface eth1
+set protocols static
+set system config-management commit-revisions '100'
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system ip protocol bgp route-map 'zebra-bgp'
+set system ip protocol isis route-map 'zebra-isis'
+set system ip protocol ospf route-map 'zebra-ospf'
+set system ip protocol static route-map 'zebra-static'
+set system ipv6 protocol ospfv3 route-map 'zebra-ospfv3'
+set system ipv6 protocol ripng route-map 'zebra-ripng'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system logs logrotate messages max-size '1'
+set system logs logrotate messages rotate '5'
+set system name-server '192.168.0.1'
+set system syslog global facility all level 'info'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/igmp-pim-small b/smoketest/config-tests/igmp-pim-small
index 207c17d45..909c3d67b 100644
--- a/smoketest/config-tests/igmp-pim-small
+++ b/smoketest/config-tests/igmp-pim-small
@@ -1,5 +1,12 @@
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
set interfaces ethernet eth1 address '100.64.0.1/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
set interfaces ethernet eth2 address '172.16.0.2/24'
+set interfaces ethernet eth2 duplex 'auto'
+set interfaces ethernet eth2 offload gro
+set interfaces ethernet eth2 speed 'auto'
set protocols pim interface eth1 igmp join 224.1.0.0 source-address '1.1.1.1'
set protocols pim interface eth1 igmp join 224.1.0.0 source-address '1.1.1.2'
set protocols pim interface eth1 igmp query-interval '1000'
@@ -7,11 +14,24 @@ set protocols pim interface eth1 igmp query-max-response-time '30'
set protocols pim interface eth1 igmp version '2'
set protocols pim interface eth2
set protocols pim rp address 172.16.255.1 group '224.0.0.0/4'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
set service ntp server 0.pool.ntp.org
set service ntp server 1.pool.ntp.org
set service ntp server 2.pool.ntp.org
+set system config-management commit-revisions '200'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
set system domain-name 'vyos.io'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
set system login user vyos authentication plaintext-password ''
-set system console device ttyS0 speed '115200'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/ipoe-server b/smoketest/config-tests/ipoe-server
index fb32fdb14..f4a12f502 100644
--- a/smoketest/config-tests/ipoe-server
+++ b/smoketest/config-tests/ipoe-server
@@ -1,9 +1,10 @@
set interfaces ethernet eth0 address 'dhcp'
set interfaces ethernet eth1 address '192.168.0.1/24'
+set interfaces ethernet eth2 offload gro
set interfaces loopback lo
-set service ntp server time1.vyos.net
-set service ntp server time2.vyos.net
-set service ntp server time3.vyos.net
+set nat source rule 100 outbound-interface name 'eth0'
+set nat source rule 100 source address '192.168.0.0/24'
+set nat source rule 100 translation address 'masquerade'
set service ipoe-server authentication interface eth1 mac 08:00:27:2f:d8:06 rate-limit download '1000'
set service ipoe-server authentication interface eth1 mac 08:00:27:2f:d8:06 rate-limit upload '500'
set service ipoe-server authentication interface eth1 mac 08:00:27:2f:d8:06 vlan '100'
@@ -25,11 +26,23 @@ set service ipoe-server name-server '10.10.1.1'
set service ipoe-server name-server '10.10.1.2'
set service ipoe-server name-server '2001:db8:aaa::'
set service ipoe-server name-server '2001:db8:bbb::'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service ntp server time3.vyos.net
+set service ssh
set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system console device ttyS0 speed '115200'
-set nat source rule 100 outbound-interface name 'eth0'
-set nat source rule 100 source address '192.168.0.0/24'
-set nat source rule 100 translation address 'masquerade'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/ipv6-disable b/smoketest/config-tests/ipv6-disable
new file mode 100644
index 000000000..40e34fa0c
--- /dev/null
+++ b/smoketest/config-tests/ipv6-disable
@@ -0,0 +1,31 @@
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth0 vif 201 address '172.18.201.10/24'
+set interfaces ethernet eth0 vif 202 address '172.18.202.10/24'
+set interfaces ethernet eth0 vif 203 address '172.18.203.10/24'
+set interfaces ethernet eth0 vif 204 address '172.18.204.10/24'
+set protocols static route 0.0.0.0/0 next-hop 172.18.201.254 distance '10'
+set protocols static route 0.0.0.0/0 next-hop 172.18.202.254 distance '20'
+set protocols static route 0.0.0.0/0 next-hop 172.18.203.254 distance '30'
+set protocols static route 0.0.0.0/0 next-hop 172.18.204.254 distance '40'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 172.16.254.20
+set service ntp server 172.16.254.30
+set system config-management commit-revisions '200'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system name-server '172.16.254.20'
+set system name-server '172.16.254.30'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/isis-small b/smoketest/config-tests/isis-small
new file mode 100644
index 000000000..b322f4e29
--- /dev/null
+++ b/smoketest/config-tests/isis-small
@@ -0,0 +1,44 @@
+set interfaces dummy dum0 address '203.0.113.1/24'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 offload sg
+set interfaces ethernet eth0 offload tso
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 address '192.0.2.1/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 offload sg
+set interfaces ethernet eth1 offload tso
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth2 duplex 'auto'
+set interfaces ethernet eth2 offload sg
+set interfaces ethernet eth2 offload tso
+set interfaces ethernet eth2 speed 'auto'
+set interfaces ethernet eth3 duplex 'auto'
+set interfaces ethernet eth3 offload sg
+set interfaces ethernet eth3 offload tso
+set interfaces ethernet eth3 speed 'auto'
+set policy prefix-list EXPORT-ISIS rule 10 action 'permit'
+set policy prefix-list EXPORT-ISIS rule 10 prefix '203.0.113.0/24'
+set policy route-map EXPORT-ISIS rule 10 action 'permit'
+set policy route-map EXPORT-ISIS rule 10 match ip address prefix-list 'EXPORT-ISIS'
+set protocols isis interface eth1 bfd
+set protocols isis net '49.0001.1921.6800.1002.00'
+set protocols isis redistribute ipv4 connected level-2 route-map 'EXPORT-ISIS'
+set system config-management commit-revisions '200'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.io'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service ntp server time3.vyos.net
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/nat-basic b/smoketest/config-tests/nat-basic
index 9fea08b02..471add3b3 100644
--- a/smoketest/config-tests/nat-basic
+++ b/smoketest/config-tests/nat-basic
@@ -1,25 +1,17 @@
-set interfaces ethernet eth0 offload rps
+set interfaces bonding bond10 hash-policy 'layer3+4'
+set interfaces bonding bond10 member interface 'eth2'
+set interfaces bonding bond10 member interface 'eth3'
+set interfaces bonding bond10 mode '802.3ad'
+set interfaces bonding bond10 vif 50 address '192.168.189.1/24'
set interfaces ethernet eth0 disable
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth0 offload rps
set interfaces ethernet eth1 offload gro
-set interfaces ethernet eth1 offload gso
set interfaces ethernet eth1 offload rps
-set interfaces ethernet eth1 offload sg
-set interfaces ethernet eth1 offload tso
set interfaces ethernet eth2 offload gro
-set interfaces ethernet eth2 offload gso
set interfaces ethernet eth2 offload rps
-set interfaces ethernet eth2 offload sg
-set interfaces ethernet eth2 offload tso
set interfaces ethernet eth3 offload gro
-set interfaces ethernet eth3 offload gso
set interfaces ethernet eth3 offload rps
-set interfaces ethernet eth3 offload sg
-set interfaces ethernet eth3 offload tso
-set interfaces bonding bond10 hash-policy 'layer3+4'
-set interfaces bonding bond10 member interface 'eth2'
-set interfaces bonding bond10 member interface 'eth3'
-set interfaces bonding bond10 mode '802.3ad'
-set interfaces bonding bond10 vif 50 address '192.168.189.1/24'
set interfaces loopback lo
set interfaces pppoe pppoe7 authentication password 'vyos'
set interfaces pppoe pppoe7 authentication username 'vyos'
@@ -31,30 +23,6 @@ set interfaces pppoe pppoe7 ipv6 adjust-mss '1432'
set interfaces pppoe pppoe7 mtu '1492'
set interfaces pppoe pppoe7 no-peer-dns
set interfaces pppoe pppoe7 source-interface 'eth1'
-set service lldp interface eth1 disable
-set service ntp allow-client address '192.168.189.0/24'
-set service ntp server time1.vyos.net
-set service ntp server time2.vyos.net
-set service ntp listen-address '192.168.189.1'
-set service ssh dynamic-protection
-set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 lease '604800'
-set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option default-router '192.168.189.1'
-set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option domain-name 'vyos.net'
-set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option name-server '1.1.1.1'
-set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option name-server '9.9.9.9'
-set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 range 0 start '192.168.189.20'
-set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 range 0 stop '192.168.189.254'
-set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 subnet-id '1'
-set service router-advert interface bond10.50 prefix ::/64 preferred-lifetime '2700'
-set service router-advert interface bond10.50 prefix ::/64 valid-lifetime '5400'
-set system config-management commit-revisions '100'
-set system domain-name 'vyos.net'
-set system host-name 'R1'
-set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
-set system login user vyos authentication plaintext-password ''
-set system name-server '1.1.1.1'
-set system name-server '9.9.9.9'
-set system console device ttyS0 speed '115200'
set nat destination rule 1000 destination port '3389'
set nat destination rule 1000 inbound-interface name 'pppoe7'
set nat destination rule 1000 protocol 'tcp'
@@ -83,3 +51,38 @@ set nat source rule 50 translation port '10300'
set nat source rule 100 outbound-interface name 'pppoe7'
set nat source rule 100 source address '192.168.189.0/24'
set nat source rule 100 translation address 'masquerade'
+set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 lease '604800'
+set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option default-router '192.168.189.1'
+set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option name-server '1.1.1.1'
+set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option name-server '9.9.9.9'
+set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 range 0 start '192.168.189.20'
+set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 range 0 stop '192.168.189.254'
+set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 subnet-id '1'
+set service lldp interface all
+set service lldp interface eth1 disable
+set service ntp allow-client address '192.168.189.0/24'
+set service ntp listen-address '192.168.189.1'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service router-advert interface bond10.50 prefix ::/64 preferred-lifetime '2700'
+set service router-advert interface bond10.50 prefix ::/64 valid-lifetime '5400'
+set service ssh disable-host-validation
+set service ssh dynamic-protection
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system host-name 'R1'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system name-server '1.1.1.1'
+set system name-server '9.9.9.9'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/ospf-simple b/smoketest/config-tests/ospf-simple
index 13d5e7038..355709448 100644
--- a/smoketest/config-tests/ospf-simple
+++ b/smoketest/config-tests/ospf-simple
@@ -1,9 +1,11 @@
set interfaces ethernet eth0 vif 20 address '193.201.42.173/28'
set interfaces ethernet eth0 vif 666 address '10.66.66.1/24'
+set interfaces ethernet eth1
+set interfaces ethernet eth2
set interfaces loopback lo
-set protocols ospf area 0 network '10.66.66.0/24'
-set protocols ospf area 0 network '193.201.42.160/28'
set protocols ospf area 0 area-type normal
+set protocols ospf area 0 network '193.201.42.160/28'
+set protocols ospf area 0 network '10.66.66.0/24'
set protocols ospf interface eth0.20 cost '999'
set protocols ospf interface eth0.20 dead-interval '4'
set protocols ospf interface eth0.20 hello-interval '1'
@@ -14,7 +16,9 @@ set protocols ospf interface eth0.666 passive
set protocols ospf log-adjacency-changes detail
set protocols static route 0.0.0.0/0 next-hop 193.201.42.170 distance '130'
set system config-management commit-revisions '100'
+set system console device ttyS0 speed '115200'
set system host-name 'lab-vyos-r1'
set system login user vyos authentication encrypted-password '$6$R.OnGzfXSfl6J$Iba/hl9bmjBs0VPtZ2zdW.Snh/nHuvxUwi0R6ruypgW63iKEbicJH.uUst8xZCyByURblxRtjAC1lAnYfIt.b0'
set system login user vyos authentication plaintext-password ''
-set system console device ttyS0 speed '115200'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/ospf-small b/smoketest/config-tests/ospf-small
new file mode 100644
index 000000000..a7f8b682c
--- /dev/null
+++ b/smoketest/config-tests/ospf-small
@@ -0,0 +1,82 @@
+set interfaces dummy dum0 address '172.18.254.200/32'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth0 vif 201 address '172.18.201.9/24'
+set interfaces ethernet eth0 vif 202 address '172.18.202.9/24'
+set interfaces ethernet eth0 vif 203 address '172.18.203.9/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set protocols ospf area 0 network '172.18.201.0/24'
+set protocols ospf area 0 network '172.18.202.0/24'
+set protocols ospf area 0 network '172.18.203.0/24'
+set protocols ospf area 0 network '172.18.254.200/32'
+set protocols ospf interface eth0.201 authentication md5 key-id 10 md5-key 'OSPFVyOSNET'
+set protocols ospf interface eth0.201 dead-interval '40'
+set protocols ospf interface eth0.201 hello-interval '10'
+set protocols ospf interface eth0.201 passive disable
+set protocols ospf interface eth0.201 priority '1'
+set protocols ospf interface eth0.201 retransmit-interval '5'
+set protocols ospf interface eth0.201 transmit-delay '1'
+set protocols ospf interface eth0.202 authentication md5 key-id 10 md5-key 'OSPFVyOSNET'
+set protocols ospf interface eth0.202 dead-interval '40'
+set protocols ospf interface eth0.202 hello-interval '10'
+set protocols ospf interface eth0.202 passive disable
+set protocols ospf interface eth0.202 priority '1'
+set protocols ospf interface eth0.202 retransmit-interval '5'
+set protocols ospf interface eth0.202 transmit-delay '1'
+set protocols ospf interface eth0.203 authentication md5 key-id 10 md5-key 'OSPFVyOSNET'
+set protocols ospf interface eth0.203 dead-interval '40'
+set protocols ospf interface eth0.203 hello-interval '10'
+set protocols ospf interface eth0.203 passive disable
+set protocols ospf interface eth0.203 priority '1'
+set protocols ospf interface eth0.203 retransmit-interval '5'
+set protocols ospf interface eth0.203 transmit-delay '1'
+set protocols ospf log-adjacency-changes
+set protocols ospf parameters abr-type 'cisco'
+set protocols ospf parameters router-id '172.18.254.200'
+set protocols ospf passive-interface 'default'
+set protocols ospfv3 area 0.0.0.0
+set protocols ospfv3 interface eth0.201 area '0.0.0.0'
+set protocols ospfv3 interface eth0.201 bfd
+set protocols ospfv3 interface eth0.201 cost '40'
+set protocols ospfv3 interface eth0.202 area '0.0.0.0'
+set protocols ospfv3 interface eth0.202 bfd
+set protocols ospfv3 interface eth0.202 cost '40'
+set protocols ospfv3 interface eth0.203 area '0.0.0.0'
+set protocols ospfv3 interface eth0.203 bfd
+set protocols ospfv3 interface eth0.203 cost '40'
+set protocols ospfv3 interface eth1 area '0.0.0.0'
+set protocols ospfv3 interface eth1 bfd
+set protocols ospfv3 interface eth1 cost '60'
+set protocols ospfv3 interface eth1 mtu-ignore
+set protocols ospfv3 interface eth1 network 'broadcast'
+set protocols ospfv3 interface eth1 priority '20'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service ssh disable-host-validation
+set service ssh port '22'
+set system config-management commit-revisions '200'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system name-server '172.16.254.30'
+set system sysctl parameter net.ipv4.conf.eth0.tag value '1'
+set system sysctl parameter net.ipv4.conf.eth1.tag value '1'
+set system sysctl parameter net.ipv4.igmp_max_memberships value '5'
+set system sysctl parameter net.ipv4.ipfrag_time value '4'
+set system sysctl parameter net.mpls.default_ttl value '10'
+set system sysctl parameter net.mpls.ip_ttl_propagate value '0'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/pppoe-server b/smoketest/config-tests/pppoe-server
new file mode 100644
index 000000000..34fbea215
--- /dev/null
+++ b/smoketest/config-tests/pppoe-server
@@ -0,0 +1,47 @@
+set interfaces ethernet eth0 address 'dhcp'
+set interfaces ethernet eth1 address '192.168.0.1/24'
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth2 speed 'auto'
+set interfaces ethernet eth2 duplex 'auto'
+set interfaces loopback lo
+set nat source rule 100 outbound-interface name 'eth0'
+set nat source rule 100 source address '192.168.0.0/24'
+set nat source rule 100 translation address 'masquerade'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set service pppoe-server access-concentrator 'ACN'
+set service pppoe-server authentication local-users username foo password 'bar'
+set service pppoe-server authentication local-users username foo rate-limit download '20480'
+set service pppoe-server authentication local-users username foo rate-limit upload '10240'
+set service pppoe-server authentication mode 'local'
+set service pppoe-server client-ip-pool default-range-pool range '10.0.0.0/24'
+set service pppoe-server client-ip-pool default-range-pool range '10.0.1.0/24'
+set service pppoe-server client-ip-pool default-range-pool range '10.0.2.0/24'
+set service pppoe-server default-pool 'default-range-pool'
+set service pppoe-server gateway-address '192.168.0.2'
+set service pppoe-server interface eth1
+set service pppoe-server interface eth2 vlan '10'
+set service pppoe-server interface eth2 vlan '20'
+set service pppoe-server interface eth2 vlan '30-40'
+set service pppoe-server interface eth2 vlan '50-60'
+set service pppoe-server name-server '192.168.0.1'
+set service pppoe-server ppp-options disable-ccp
+set service ssh
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/qos-basic b/smoketest/config-tests/qos-basic
new file mode 100644
index 000000000..0e198b80c
--- /dev/null
+++ b/smoketest/config-tests/qos-basic
@@ -0,0 +1,75 @@
+set interfaces ethernet eth0 address '10.1.1.100/24'
+set interfaces ethernet eth1 address '10.2.1.1/24'
+set interfaces ethernet eth2 address '10.9.9.1/24'
+set interfaces ethernet eth2 vif 200
+set interfaces loopback lo
+set qos interface eth0 egress 'FS'
+set qos interface eth1 egress 'ISPC'
+set qos interface eth2 egress 'MY-HTB'
+set qos interface eth2.200 egress 'foo-emulate'
+set qos policy network-emulator foo-emulate bandwidth '300mbit'
+set qos policy shaper FS bandwidth 'auto'
+set qos policy shaper FS class 10 bandwidth '100%'
+set qos policy shaper FS class 10 burst '15k'
+set qos policy shaper FS class 10 match ADDRESS10 ip source address '172.17.1.2/32'
+set qos policy shaper FS class 10 queue-type 'fair-queue'
+set qos policy shaper FS class 20 bandwidth '100%'
+set qos policy shaper FS class 20 burst '15k'
+set qos policy shaper FS class 20 match ADDRESS20 ip source address '172.17.1.3/32'
+set qos policy shaper FS class 20 queue-type 'fair-queue'
+set qos policy shaper FS class 30 bandwidth '100%'
+set qos policy shaper FS class 30 burst '15k'
+set qos policy shaper FS class 30 match ADDRESS30 ip source address '172.17.1.4/32'
+set qos policy shaper FS class 30 queue-type 'fair-queue'
+set qos policy shaper FS default bandwidth '10%'
+set qos policy shaper FS default burst '15k'
+set qos policy shaper FS default ceiling '100%'
+set qos policy shaper FS default priority '7'
+set qos policy shaper FS default queue-type 'fair-queue'
+set qos policy shaper ISPC bandwidth '600mbit'
+set qos policy shaper ISPC default bandwidth '50%'
+set qos policy shaper ISPC default burst '768k'
+set qos policy shaper ISPC default ceiling '100%'
+set qos policy shaper ISPC default queue-type 'fq-codel'
+set qos policy shaper ISPC description 'Outbound Traffic Shaper - ISPC'
+set qos policy shaper MY-HTB bandwidth '10mbit'
+set qos policy shaper MY-HTB class 30 bandwidth '10%'
+set qos policy shaper MY-HTB class 30 burst '15k'
+set qos policy shaper MY-HTB class 30 ceiling '50%'
+set qos policy shaper MY-HTB class 30 match ADDRESS30 ip source address '10.1.1.0/24'
+set qos policy shaper MY-HTB class 30 priority '5'
+set qos policy shaper MY-HTB class 30 queue-type 'fair-queue'
+set qos policy shaper MY-HTB class 40 bandwidth '90%'
+set qos policy shaper MY-HTB class 40 burst '15k'
+set qos policy shaper MY-HTB class 40 ceiling '100%'
+set qos policy shaper MY-HTB class 40 match ADDRESS40 ip source address '10.2.1.0/24'
+set qos policy shaper MY-HTB class 40 priority '5'
+set qos policy shaper MY-HTB class 40 queue-type 'fair-queue'
+set qos policy shaper MY-HTB class 50 bandwidth '100%'
+set qos policy shaper MY-HTB class 50 burst '15k'
+set qos policy shaper MY-HTB class 50 match ADDRESS50 ipv6 source address '2001:db8::1/64'
+set qos policy shaper MY-HTB class 50 queue-type 'fair-queue'
+set qos policy shaper MY-HTB default bandwidth '10%'
+set qos policy shaper MY-HTB default burst '15k'
+set qos policy shaper MY-HTB default ceiling '100%'
+set qos policy shaper MY-HTB default priority '7'
+set qos policy shaper MY-HTB default queue-type 'fair-queue'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service ntp server time3.vyos.net
+set system config-management commit-revisions '10'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/rip-router b/smoketest/config-tests/rip-router
new file mode 100644
index 000000000..829aafbd5
--- /dev/null
+++ b/smoketest/config-tests/rip-router
@@ -0,0 +1,83 @@
+set interfaces dummy dum0 address '192.0.2.0/32'
+set interfaces ethernet eth0 address '172.18.202.10/24'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth1 vif 20
+set interfaces ethernet eth1 vif-s 200 vif-c 2000
+set interfaces ethernet eth1 vif-s 200 vif-c 3000
+set policy access-list6 198 rule 10 action 'permit'
+set policy access-list6 198 rule 10 source any
+set policy access-list6 199 rule 20 action 'deny'
+set policy access-list6 199 rule 20 source any
+set policy prefix-list6 bar-prefix rule 200 action 'deny'
+set policy prefix-list6 bar-prefix rule 200 prefix '2001:db8::/32'
+set policy prefix-list6 foo-prefix rule 100 action 'permit'
+set policy prefix-list6 foo-prefix rule 100 prefix '2001:db8::/32'
+set policy route-map FooBar123 rule 10 action 'permit'
+set protocols rip default-distance '20'
+set protocols rip default-information originate
+set protocols rip interface eth0 authentication md5 1 password 'VyOSsecure'
+set protocols rip interface eth0 split-horizon poison-reverse
+set protocols rip interface eth1.20 authentication plaintext-password 'VyOSsecure'
+set protocols rip interface eth1.20 split-horizon poison-reverse
+set protocols rip interface eth1.200 authentication md5 1 password 'VyOSsecure'
+set protocols rip interface eth1.200 split-horizon disable
+set protocols rip interface eth1.200.2000 authentication md5 1 password 'VyOSsecure'
+set protocols rip interface eth1.200.3000 split-horizon disable
+set protocols rip network '192.168.0.0/24'
+set protocols rip redistribute connected
+set protocols ripng aggregate-address '2001:db8:1000::/48'
+set protocols ripng default-information originate
+set protocols ripng default-metric '8'
+set protocols ripng distribute-list access-list in '198'
+set protocols ripng distribute-list access-list out '199'
+set protocols ripng distribute-list interface eth0 access-list in '198'
+set protocols ripng distribute-list interface eth0 access-list out '199'
+set protocols ripng distribute-list interface eth0 prefix-list in 'foo-prefix'
+set protocols ripng distribute-list interface eth0 prefix-list out 'bar-prefix'
+set protocols ripng distribute-list interface eth1 access-list in '198'
+set protocols ripng distribute-list interface eth1 access-list out '199'
+set protocols ripng distribute-list interface eth1 prefix-list in 'foo-prefix'
+set protocols ripng distribute-list interface eth1 prefix-list out 'bar-prefix'
+set protocols ripng distribute-list interface eth2 access-list in '198'
+set protocols ripng distribute-list interface eth2 access-list out '199'
+set protocols ripng distribute-list interface eth2 prefix-list in 'foo-prefix'
+set protocols ripng distribute-list interface eth2 prefix-list out 'bar-prefix'
+set protocols ripng distribute-list prefix-list in 'foo-prefix'
+set protocols ripng distribute-list prefix-list out 'bar-prefix'
+set protocols ripng interface eth0 split-horizon poison-reverse
+set protocols ripng interface eth1.20 split-horizon disable
+set protocols ripng interface eth1.200 split-horizon poison-reverse
+set protocols ripng interface eth1.200.3000 split-horizon poison-reverse
+set protocols ripng network '2001:db8:1000::/64'
+set protocols ripng network '2001:db8:1001::/64'
+set protocols ripng network '2001:db8:2000::/64'
+set protocols ripng network '2001:db8:2001::/64'
+set protocols ripng passive-interface 'default'
+set protocols ripng redistribute connected metric '8'
+set protocols ripng redistribute connected route-map 'FooBar123'
+set protocols ripng redistribute static metric '8'
+set protocols ripng redistribute static route-map 'FooBar123'
+set protocols ripng route '2001:db8:1000::/64'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set service ssh port '22'
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/rpki-only b/smoketest/config-tests/rpki-only
index 569463b12..dcbc7673d 100644
--- a/smoketest/config-tests/rpki-only
+++ b/smoketest/config-tests/rpki-only
@@ -1,5 +1,7 @@
set interfaces ethernet eth0 address '192.0.2.1/24'
set interfaces ethernet eth0 address '2001:db8::1/64'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
set interfaces loopback lo
set pki openssh rpki-5.6.7.8 private key 'b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEAweDyflDFR4qyEwETbJkZ2ZZc+sJNiDTvYpwGsWIkju49lJSxHe1xKf8FhwfyMu40Snt1yDlRmmmz4CsbLgbuZGMPvXG11e34+C0pSVUvpF6aqRTeLl1pDRK7Rnjgm3su+I8SRLQR4qbLG6VXWOFuVpwiqbExLaU0hFYTPNP+dArNpsWEEKsohk6pTXdhg3VzWp3vCMjl2JTshDa3lD7p2xISSAReEY0fnfEAmQzH4Z6DIwwGdFuMWoQIg+oFBM9ARrO2/FIjRsz6AecR/WeU72JEw4aJic1/cAJQA6PiQBHwkuo3Wll1tbpxeRZoB2NQG22ETyJLvhfTaooNLT9HpQAAA8joU5dM6FOXTAAAAAdzc2gtcnNhAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0elAAAAAwEAAQAAAQACkDlUjzfUhtJs6uY5WNrdJB5NmHUS+HQzzxFNlhkapK6+wKqI1UNaRUtq6iF7J+gcFf7MK2nXS098BsXguWm8fQzPuemoDvHsQhiaJhyvpSqRUrvPTB/f8t/0AhQiKiJIWgfpTaIw53inAGwjujNNxNm2eafHTThhCYxOkRT7rsT6bnSio6yeqPy5QHg7IKFztp5FXDUyiOS3aX3SvzQcDUkMXALdvzX50t1XIk+X48Rgkq72dL4VpV2oMNDu3hM6FqBUplf9Mv3s51FNSma/cibCQoVufrIfoqYjkNTjIpYFUcq4zZ0/KvgXgzSsy9VN/4TtbalrOuu7X/SHJbvhAAAAgGPFsXgONYQvXxCnK1dIueozgaZg1I/n522E2ZCOXBW4dYJVyNpppwRreDzuFzTDEe061MpNHfScjVBJCCulivFYWscL6oaGsryDbFxO3QmB4I98UBqrds2yan9/JGc6EYe299yvaHy7Y64+NC0+fN8H2RAZ61T4w10JrCaJRyvzAAAAgQDvBfuV1U7o9k/fbU+U7W2UYnWblpOZAMfi1XQP6IJJeyWs90PdTdXh+l0eIQrCawIiRJytNfxMmbD4huwTf77fWiyCcPznmALQ7ex/yJ+W5Z0V4dPGF3h7o1uiS236JhQ7mfcliCkhp/1PIklBIMPcCp0zl+s9wMv2hX7w1Pah9QAAAIEAz6YgU9Xute+J+dBwoWxEQ+igR6KE55Um7O9AvSrqnCm9r7lSFsXC2ErYOxoDSJ3yIBEV0b4XAGn6tbbVIs3jS8BnLHxclAHQecOx1PGn7PKbnPW0oJRq/X9QCIEelKYvlykpayn7uZooTXqcDaPZxfPpmPdye8chVJvdygi7kPEAAAAMY3BvQExSMS53dWUzAQIDBAUGBw=='
set pki openssh rpki-5.6.7.8 public key 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0el'
@@ -14,6 +16,7 @@ set policy route-map ROUTES-IN rule 30 action 'deny'
set policy route-map ROUTES-IN rule 30 match rpki 'invalid'
set protocols bgp neighbor 192.0.2.200 address-family ipv4-unicast route-map import 'ROUTES-IN'
set protocols bgp neighbor 192.0.2.200 remote-as '200'
+set protocols bgp neighbor 2001:db8::200 address-family ipv4-unicast
set protocols bgp neighbor 2001:db8::200 address-family ipv6-unicast route-map import 'ROUTES-IN'
set protocols bgp neighbor 2001:db8::200 remote-as '200'
set protocols bgp system-as '100'
@@ -23,8 +26,17 @@ set protocols rpki cache 5.6.7.8 port '2222'
set protocols rpki cache 5.6.7.8 preference '20'
set protocols rpki cache 5.6.7.8 ssh key 'rpki-5.6.7.8'
set protocols rpki cache 5.6.7.8 ssh username 'vyos'
+set system config-management commit-revisions '200'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
set system login user vyos authentication plaintext-password ''
set system syslog global facility all level 'debug'
-set system console device ttyS0 speed '115200'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/tunnel-broker b/smoketest/config-tests/tunnel-broker
new file mode 100644
index 000000000..ee6301c85
--- /dev/null
+++ b/smoketest/config-tests/tunnel-broker
@@ -0,0 +1,75 @@
+set interfaces dummy dum0 address '192.0.2.0/32'
+set interfaces dummy dum1 address '192.0.2.1/32'
+set interfaces dummy dum2 address '192.0.2.2/32'
+set interfaces dummy dum3 address '192.0.2.3/32'
+set interfaces dummy dum4 address '192.0.2.4/32'
+set interfaces ethernet eth0 address '172.18.202.10/24'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces l2tpv3 l2tpeth10 destination-port '5010'
+set interfaces l2tpv3 l2tpeth10 encapsulation 'ip'
+set interfaces l2tpv3 l2tpeth10 peer-session-id '110'
+set interfaces l2tpv3 l2tpeth10 peer-tunnel-id '10'
+set interfaces l2tpv3 l2tpeth10 remote '172.18.202.110'
+set interfaces l2tpv3 l2tpeth10 session-id '110'
+set interfaces l2tpv3 l2tpeth10 source-address '172.18.202.10'
+set interfaces l2tpv3 l2tpeth10 source-port '5010'
+set interfaces l2tpv3 l2tpeth10 tunnel-id '10'
+set interfaces l2tpv3 l2tpeth20 destination-port '5020'
+set interfaces l2tpv3 l2tpeth20 encapsulation 'ip'
+set interfaces l2tpv3 l2tpeth20 peer-session-id '120'
+set interfaces l2tpv3 l2tpeth20 peer-tunnel-id '20'
+set interfaces l2tpv3 l2tpeth20 remote '172.18.202.120'
+set interfaces l2tpv3 l2tpeth20 session-id '120'
+set interfaces l2tpv3 l2tpeth20 source-address '172.18.202.10'
+set interfaces l2tpv3 l2tpeth20 source-port '5020'
+set interfaces l2tpv3 l2tpeth20 tunnel-id '20'
+set interfaces l2tpv3 l2tpeth30 destination-port '5030'
+set interfaces l2tpv3 l2tpeth30 encapsulation 'ip'
+set interfaces l2tpv3 l2tpeth30 peer-session-id '130'
+set interfaces l2tpv3 l2tpeth30 peer-tunnel-id '30'
+set interfaces l2tpv3 l2tpeth30 remote '172.18.202.130'
+set interfaces l2tpv3 l2tpeth30 session-id '130'
+set interfaces l2tpv3 l2tpeth30 source-address '172.18.202.10'
+set interfaces l2tpv3 l2tpeth30 source-port '5030'
+set interfaces l2tpv3 l2tpeth30 tunnel-id '30'
+set interfaces tunnel tun100 address '172.16.0.1/30'
+set interfaces tunnel tun100 encapsulation 'gretap'
+set interfaces tunnel tun100 remote '192.0.2.100'
+set interfaces tunnel tun100 source-address '192.0.2.1'
+set interfaces tunnel tun200 address '172.16.0.5/30'
+set interfaces tunnel tun200 encapsulation 'gre'
+set interfaces tunnel tun200 remote '192.0.2.101'
+set interfaces tunnel tun200 source-interface 'eth0'
+set interfaces tunnel tun300 address '172.16.0.9/30'
+set interfaces tunnel tun300 encapsulation 'ipip'
+set interfaces tunnel tun300 remote '192.0.2.102'
+set interfaces tunnel tun300 source-address '192.0.2.2'
+set interfaces tunnel tun400 address '172.16.0.13/30'
+set interfaces tunnel tun400 encapsulation 'gretap'
+set interfaces tunnel tun400 remote '192.0.2.103'
+set interfaces tunnel tun400 source-address '192.0.2.3'
+set interfaces tunnel tun500 address '172.16.0.17/30'
+set interfaces tunnel tun500 encapsulation 'gre'
+set interfaces tunnel tun500 remote '192.0.2.104'
+set interfaces tunnel tun500 source-address '192.0.2.4'
+set protocols static route 0.0.0.0/0 next-hop 172.18.202.254
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
diff --git a/smoketest/config-tests/vpn-openconnect-sstp b/smoketest/config-tests/vpn-openconnect-sstp
new file mode 100644
index 000000000..28d7d5daa
--- /dev/null
+++ b/smoketest/config-tests/vpn-openconnect-sstp
@@ -0,0 +1,35 @@
+set interfaces ethernet eth0 address '192.168.150.1/24'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server time1.vyos.net
+set service ntp server time2.vyos.net
+set service ntp server time3.vyos.net
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set vpn openconnect authentication local-users username test password 'test'
+set vpn openconnect authentication mode local 'password'
+set vpn openconnect network-settings client-ip-settings subnet '192.168.160.0/24'
+set vpn openconnect ssl ca-certificate 'openconnect'
+set vpn openconnect ssl certificate 'openconnect'
+set vpn openconnect tls-version-min '1.0'
+set vpn sstp authentication local-users username test password 'test'
+set vpn sstp authentication mode 'local'
+set vpn sstp authentication protocols 'mschap-v2'
+set vpn sstp client-ip-pool default-range-pool range '192.168.170.0/24'
+set vpn sstp default-pool 'default-range-pool'
+set vpn sstp gateway-address '192.168.150.1'
+set vpn sstp port '8443'
+set vpn sstp ssl ca-certificate 'sstp'
+set vpn sstp ssl certificate 'sstp'
diff --git a/smoketest/config-tests/vrf-basic b/smoketest/config-tests/vrf-basic
new file mode 100644
index 000000000..1d2874a60
--- /dev/null
+++ b/smoketest/config-tests/vrf-basic
@@ -0,0 +1,65 @@
+set interfaces ethernet eth0 address '192.0.2.1/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth1 vrf 'green'
+set interfaces ethernet eth2 vrf 'red'
+set protocols static route 0.0.0.0/0 next-hop 192.0.2.254 distance '10'
+set protocols static table 10 route 1.0.0.0/8 interface eth0 distance '20'
+set protocols static table 10 route 2.0.0.0/8 interface eth0 distance '20'
+set protocols static table 10 route 3.0.0.0/8 interface eth0 distance '20'
+set protocols static table 20 route 4.0.0.0/8 interface eth0 distance '20'
+set protocols static table 20 route 5.0.0.0/8 interface eth0 distance '50'
+set protocols static table 20 route 6.0.0.0/8 interface eth0 distance '60'
+set protocols static table 20 route 11.0.0.0/8 next-hop 1.1.1.1 interface 'eth0'
+set protocols static table 20 route 12.0.0.0/8 next-hop 1.1.1.1 interface 'eth0'
+set protocols static table 20 route 13.0.0.0/8 next-hop 1.1.1.1 interface 'eth0'
+set protocols static table 20 route6 2001:db8:100::/40 interface eth1 distance '20'
+set protocols static table 20 route6 2001:db8::/40 interface eth1 distance '10'
+set protocols static table 30 route 14.0.0.0/8 next-hop 2.2.1.1 interface 'eth1'
+set protocols static table 30 route 15.0.0.0/8 next-hop 2.2.1.1 interface 'eth1'
+set protocols static table 30 route6 2001:db8:200::/40 interface eth1 distance '20'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Europe/Berlin'
+set vrf name green protocols static route 20.0.0.0/8 next-hop 1.1.1.1 interface 'eth1'
+set vrf name green protocols static route 20.0.0.0/8 next-hop 1.1.1.1 vrf 'default'
+set vrf name green protocols static route 21.0.0.0/8 next-hop 2.2.1.1 interface 'eth1'
+set vrf name green protocols static route 21.0.0.0/8 next-hop 2.2.1.1 vrf 'default'
+set vrf name green protocols static route 100.0.0.0/8 interface eth0 distance '200'
+set vrf name green protocols static route 100.0.0.0/8 interface eth0 vrf 'default'
+set vrf name green protocols static route 101.0.0.0/8 interface eth0 vrf 'default'
+set vrf name green protocols static route 101.0.0.0/8 interface eth1
+set vrf name green protocols static route6 2001:db8:100::/40 next-hop fe80::1 interface 'eth0'
+set vrf name green protocols static route6 2001:db8:100::/40 next-hop fe80::1 vrf 'default'
+set vrf name green protocols static route6 2001:db8:300::/40 interface eth1 distance '20'
+set vrf name green protocols static route6 2001:db8:300::/40 interface eth1 vrf 'default'
+set vrf name green table '1000'
+set vrf name red protocols static route 30.0.0.0/8 next-hop 1.1.1.1 interface 'eth1'
+set vrf name red protocols static route 40.0.0.0/8 next-hop 2.2.1.1 interface 'eth1'
+set vrf name red protocols static route 40.0.0.0/8 next-hop 2.2.1.1 vrf 'default'
+set vrf name red protocols static route 103.0.0.0/8 interface eth0 distance '201'
+set vrf name red protocols static route 103.0.0.0/8 interface eth0 vrf 'default'
+set vrf name red protocols static route 104.0.0.0/8 interface eth0 vrf 'default'
+set vrf name red protocols static route 104.0.0.0/8 interface eth1 vrf 'default'
+set vrf name red protocols static route6 2001:db8:100::/40 next-hop fe80::1 interface 'eth0'
+set vrf name red protocols static route6 2001:db8:100::/40 next-hop fe80::1 vrf 'default'
+set vrf name red protocols static route6 2001:db8:400::/40 interface eth1 distance '24'
+set vrf name red protocols static route6 2001:db8:400::/40 interface eth1 vrf 'default'
+set vrf name red table '2000'
diff --git a/smoketest/config-tests/vrf-bgp-pppoe-underlay b/smoketest/config-tests/vrf-bgp-pppoe-underlay
new file mode 100644
index 000000000..bd64c914a
--- /dev/null
+++ b/smoketest/config-tests/vrf-bgp-pppoe-underlay
@@ -0,0 +1,186 @@
+set interfaces bridge br50 address '192.168.0.1/24'
+set interfaces bridge br50 member interface eth0.50
+set interfaces bridge br50 member interface eth2
+set interfaces bridge br50 member interface eth3
+set interfaces dummy dum0 address '100.64.51.252/32'
+set interfaces dummy dum0 address '2001:db8:200:ffff::1/128'
+set interfaces dummy dum0 vrf 'vyos-test-01'
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth0 offload rps
+set interfaces ethernet eth0 ring-buffer rx '256'
+set interfaces ethernet eth0 ring-buffer tx '256'
+set interfaces ethernet eth0 vif 5 address '2001:db8:200:f0::114/64'
+set interfaces ethernet eth0 vif 5 address '100.64.50.121/28'
+set interfaces ethernet eth0 vif 5 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 10 address '2001:db8:200:10::ffff/64'
+set interfaces ethernet eth0 vif 10 address '2001:db8:200::ffff/64'
+set interfaces ethernet eth0 vif 10 address '100.64.50.62/26'
+set interfaces ethernet eth0 vif 10 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 15 address '100.64.50.78/28'
+set interfaces ethernet eth0 vif 15 address '2001:db8:200:15::ffff/64'
+set interfaces ethernet eth0 vif 15 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 50 description 'Member of bridge br50'
+set interfaces ethernet eth0 vif 110 address '100.64.51.190/27'
+set interfaces ethernet eth0 vif 110 address '100.64.51.158/28'
+set interfaces ethernet eth0 vif 110 address '2001:db8:200:101::ffff/64'
+set interfaces ethernet eth0 vif 110 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 410 address '100.64.51.206/28'
+set interfaces ethernet eth0 vif 410 address '2001:db8:200:104::ffff/64'
+set interfaces ethernet eth0 vif 410 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 500 address '100.64.51.238/28'
+set interfaces ethernet eth0 vif 500 address '2001:db8:200:50::ffff/64'
+set interfaces ethernet eth0 vif 500 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 520 address '100.64.50.190/28'
+set interfaces ethernet eth0 vif 520 address '2001:db8:200:520::ffff/64'
+set interfaces ethernet eth0 vif 520 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 666 address '2001:db8:200:ff::101:1/112'
+set interfaces ethernet eth0 vif 666 address '100.64.51.223/31'
+set interfaces ethernet eth0 vif 666 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 800 address '2001:db8:200:ff::104:1/112'
+set interfaces ethernet eth0 vif 800 address '100.64.51.212/31'
+set interfaces ethernet eth0 vif 800 vrf 'vyos-test-01'
+set interfaces ethernet eth0 vif 810 address '100.64.51.30/27'
+set interfaces ethernet eth0 vif 810 address '2001:db8:200:102::ffff/64'
+set interfaces ethernet eth0 vif 810 vrf 'vyos-test-01'
+set interfaces ethernet eth1 offload gro
+set interfaces ethernet eth1 offload rps
+set interfaces ethernet eth1 ring-buffer rx '256'
+set interfaces ethernet eth1 ring-buffer tx '256'
+set interfaces ethernet eth2 offload gro
+set interfaces ethernet eth3 offload gro
+set interfaces loopback lo
+set interfaces pppoe pppoe7 authentication password 'vyos'
+set interfaces pppoe pppoe7 authentication username 'vyos'
+set interfaces pppoe pppoe7 dhcpv6-options pd 0 interface br50 address '1'
+set interfaces pppoe pppoe7 dhcpv6-options pd 0 length '56'
+set interfaces pppoe pppoe7 ip adjust-mss '1452'
+set interfaces pppoe pppoe7 ipv6 address autoconf
+set interfaces pppoe pppoe7 ipv6 adjust-mss '1432'
+set interfaces pppoe pppoe7 mtu '1492'
+set interfaces pppoe pppoe7 no-peer-dns
+set interfaces pppoe pppoe7 source-interface 'eth1'
+set interfaces virtual-ethernet veth0 address '100.64.51.220/31'
+set interfaces virtual-ethernet veth0 address '2001:db8:200:ff::105:1/112'
+set interfaces virtual-ethernet veth0 description 'Core: connect vyos-test-01 and default VRF'
+set interfaces virtual-ethernet veth0 peer-name 'veth1'
+set interfaces virtual-ethernet veth1 address '100.64.51.221/31'
+set interfaces virtual-ethernet veth1 address '2001:db8:200:ff::105:2/112'
+set interfaces virtual-ethernet veth1 description 'Core: connect vyos-test-01 and default VRF'
+set interfaces virtual-ethernet veth1 peer-name 'veth0'
+set interfaces virtual-ethernet veth1 vrf 'vyos-test-01'
+set interfaces wireguard wg500 address '100.64.51.209/31'
+set interfaces wireguard wg500 mtu '1500'
+set interfaces wireguard wg500 peer A address '192.0.2.1'
+set interfaces wireguard wg500 peer A allowed-ips '0.0.0.0/0'
+set interfaces wireguard wg500 peer A port '5500'
+set interfaces wireguard wg500 peer A public-key 'KGSXF4QckzGe7f7CT+r6VZ5brOD/pVYk8yvrxOQ+X0Y='
+set interfaces wireguard wg500 port '5500'
+set interfaces wireguard wg500 private-key 'iLJh6Me6AdPJtNv3dgGhUbtyFxExxmNU4v0Fs6YE2Xc='
+set interfaces wireguard wg500 vrf 'vyos-test-01'
+set interfaces wireguard wg501 address '2001:db8:200:ff::102:2/112'
+set interfaces wireguard wg501 mtu '1500'
+set interfaces wireguard wg501 peer A address '2001:db8:300::1'
+set interfaces wireguard wg501 peer A allowed-ips '::/0'
+set interfaces wireguard wg501 peer A port '5501'
+set interfaces wireguard wg501 peer A public-key 'OF+1OJ+VfQ0Yw1mgVtQ2ion4CnAdy8Bvx7yEiO4+Pn8='
+set interfaces wireguard wg501 port '5501'
+set interfaces wireguard wg501 private-key '0MP5X0PW58O4q2LDpuIXgZ0ySyAoWH8/kdpvQccCbUU='
+set interfaces wireguard wg501 vrf 'vyos-test-01'
+set interfaces wireguard wg666 address '172.29.0.0/31'
+set interfaces wireguard wg666 mtu '1500'
+set interfaces wireguard wg666 peer B allowed-ips '0.0.0.0/0'
+set interfaces wireguard wg666 peer B public-key '2HT+RfwcqJMYNYzdmtmpem8Ht0dL37o31APHVwmh024='
+set interfaces wireguard wg666 port '50666'
+set interfaces wireguard wg666 private-key 'zvPnp2MLAoX7SotuHLFLDyy4sdlD7ttbD1xNEqA3mkU='
+set nat source rule 100 outbound-interface name 'pppoe7'
+set nat source rule 100 source address '192.168.0.0/24'
+set nat source rule 100 translation address 'masquerade'
+set policy prefix-list AS100-origin-v4 rule 10 action 'permit'
+set policy prefix-list AS100-origin-v4 rule 10 prefix '100.64.0.0/12'
+set policy prefix-list AS100-origin-v4 rule 100 action 'permit'
+set policy prefix-list AS100-origin-v4 rule 100 prefix '0.0.0.0/0'
+set policy prefix-list AS200-origin-v4 rule 10 action 'permit'
+set policy prefix-list AS200-origin-v4 rule 10 prefix '10.0.0.0/8'
+set policy prefix-list AS200-origin-v4 rule 20 action 'permit'
+set policy prefix-list AS200-origin-v4 rule 20 prefix '172.16.0.0/12'
+set policy prefix-list6 AS100-origin-v6 rule 10 action 'permit'
+set policy prefix-list6 AS100-origin-v6 rule 10 prefix '2001:db8:200::/40'
+set policy prefix-list6 AS200-origin-v6 rule 10 action 'permit'
+set policy prefix-list6 AS200-origin-v6 rule 10 prefix '2001:db8:100::/40'
+set protocols static route 100.64.50.0/23 next-hop 100.64.51.221
+set protocols static route 192.0.2.255/32 interface pppoe7
+set protocols static route6 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff/128 interface pppoe7
+set qos interface pppoe7 egress 'isp-out'
+set qos policy shaper isp-out bandwidth '38mbit'
+set qos policy shaper isp-out default bandwidth '100%'
+set qos policy shaper isp-out default burst '15k'
+set qos policy shaper isp-out default queue-limit '1000'
+set qos policy shaper isp-out default queue-type 'fq-codel'
+set service router-advert interface br50 prefix ::/64 preferred-lifetime '2700'
+set service router-advert interface br50 prefix ::/64 valid-lifetime '5400'
+set service router-advert interface eth0.500 default-preference 'high'
+set service router-advert interface eth0.500 name-server '2001:db8:200::1'
+set service router-advert interface eth0.500 name-server '2001:db8:200::2'
+set service router-advert interface eth0.500 prefix 2001:db8:200:50::/64 valid-lifetime 'infinity'
+set service router-advert interface eth0.520 default-preference 'high'
+set service router-advert interface eth0.520 name-server '2001:db8:200::1'
+set service router-advert interface eth0.520 name-server '2001:db8:200::2'
+set service router-advert interface eth0.520 prefix 2001:db8:200:520::/64 valid-lifetime 'infinity'
+set service ssh disable-host-validation
+set service ssh dynamic-protection allow-from '100.64.0.0/10'
+set service ssh dynamic-protection allow-from '2001:db8:200::/40'
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos.net'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system name-server '192.168.0.1'
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Europe/Berlin'
+set vrf bind-to-all
+set vrf name vyos-test-01 protocols bgp address-family ipv4-unicast network 100.64.50.0/23
+set vrf name vyos-test-01 protocols bgp address-family ipv6-unicast network 2001:db8:200:ffff::1/128
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.208 peer-group 'AS100v4'
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast default-originate
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast maximum-prefix '10'
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast prefix-list export 'AS100-origin-v4'
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast prefix-list import 'AS200-origin-v4'
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast soft-reconfiguration inbound
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 capability dynamic
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 remote-as '200'
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.251 peer-group 'AS100v4'
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.251 shutdown
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.254 peer-group 'AS100v4'
+set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.254 shutdown
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 address-family ipv6-unicast maximum-prefix '10'
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 address-family ipv6-unicast prefix-list export 'AS100-origin-v6'
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 address-family ipv6-unicast prefix-list import 'AS200-origin-v6'
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 address-family ipv6-unicast soft-reconfiguration inbound
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 capability dynamic
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 remote-as '200'
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ffff::2 peer-group 'AS100v6'
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ffff::2 shutdown
+set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ffff::a peer-group 'AS100v6'
+set vrf name vyos-test-01 protocols bgp peer-group AS100v4 address-family ipv4-unicast nexthop-self
+set vrf name vyos-test-01 protocols bgp peer-group AS100v4 capability dynamic
+set vrf name vyos-test-01 protocols bgp peer-group AS100v4 remote-as 'internal'
+set vrf name vyos-test-01 protocols bgp peer-group AS100v4 update-source 'dum0'
+set vrf name vyos-test-01 protocols bgp peer-group AS100v6 address-family ipv6-unicast nexthop-self
+set vrf name vyos-test-01 protocols bgp peer-group AS100v6 capability dynamic
+set vrf name vyos-test-01 protocols bgp peer-group AS100v6 remote-as 'internal'
+set vrf name vyos-test-01 protocols bgp peer-group AS100v6 update-source 'dum0'
+set vrf name vyos-test-01 protocols bgp system-as '100'
+set vrf name vyos-test-01 protocols static route 100.64.50.0/23 blackhole
+set vrf name vyos-test-01 protocols static route 100.64.51.32/27 next-hop 100.64.51.5
+set vrf name vyos-test-01 protocols static route 192.168.0.0/24 next-hop 100.64.51.220
+set vrf name vyos-test-01 protocols static route6 2001:db8:2fe:ffff::/64 next-hop 2001:db8:200:102::5
+set vrf name vyos-test-01 table '1000'
diff --git a/smoketest/config-tests/vrf-ospf b/smoketest/config-tests/vrf-ospf
new file mode 100644
index 000000000..fd14615e0
--- /dev/null
+++ b/smoketest/config-tests/vrf-ospf
@@ -0,0 +1,59 @@
+set interfaces ethernet eth0 address '192.0.2.1/24'
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth1 offload gro
+set interfaces ethernet eth1 vrf 'red'
+set interfaces ethernet eth2 offload gro
+set interfaces ethernet eth2 vrf 'blue'
+set protocols ospf area 0 network '192.0.2.0/24'
+set protocols ospf interface eth0 authentication md5 key-id 10 md5-key 'ospfkey'
+set protocols ospf interface eth0 passive disable
+set protocols ospf log-adjacency-changes
+set protocols ospf parameters abr-type 'cisco'
+set protocols ospf parameters router-id '1.2.3.4'
+set protocols ospf passive-interface 'default'
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 0.pool.ntp.org
+set service ntp server 1.pool.ntp.org
+set service ntp server 2.pool.ntp.org
+set system config-management commit-revisions '100'
+set system conntrack modules ftp
+set system conntrack modules h323
+set system conntrack modules nfs
+set system conntrack modules pptp
+set system conntrack modules sip
+set system conntrack modules sqlnet
+set system conntrack modules tftp
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Europe/Berlin'
+set vrf name blue protocols ospf area 0 network '172.18.201.0/24'
+set vrf name blue protocols ospf interface eth2 authentication md5 key-id 30 md5-key 'vyoskey456'
+set vrf name blue protocols ospf interface eth2 dead-interval '40'
+set vrf name blue protocols ospf interface eth2 hello-interval '10'
+set vrf name blue protocols ospf interface eth2 passive disable
+set vrf name blue protocols ospf interface eth2 priority '1'
+set vrf name blue protocols ospf interface eth2 retransmit-interval '5'
+set vrf name blue protocols ospf interface eth2 transmit-delay '1'
+set vrf name blue protocols ospf log-adjacency-changes
+set vrf name blue protocols ospf parameters abr-type 'cisco'
+set vrf name blue protocols ospf parameters router-id '5.6.7.8'
+set vrf name blue protocols ospf passive-interface 'default'
+set vrf name blue table '2000'
+set vrf name red protocols ospf area 0 network '172.18.202.0/24'
+set vrf name red protocols ospf interface eth1 authentication md5 key-id 20 md5-key 'vyoskey123'
+set vrf name red protocols ospf interface eth1 dead-interval '40'
+set vrf name red protocols ospf interface eth1 hello-interval '10'
+set vrf name red protocols ospf interface eth1 passive disable
+set vrf name red protocols ospf interface eth1 priority '1'
+set vrf name red protocols ospf interface eth1 retransmit-interval '5'
+set vrf name red protocols ospf interface eth1 transmit-delay '1'
+set vrf name red protocols ospf log-adjacency-changes
+set vrf name red protocols ospf parameters abr-type 'cisco'
+set vrf name red protocols ospf parameters router-id '9.10.11.12'
+set vrf name red protocols ospf passive-interface 'default'
+set vrf name red table '1000'
diff --git a/smoketest/config-tests/wireless-basic b/smoketest/config-tests/wireless-basic
index 77db29c2f..d9e6c8fac 100644
--- a/smoketest/config-tests/wireless-basic
+++ b/smoketest/config-tests/wireless-basic
@@ -20,6 +20,6 @@ set system console device ttyS0 speed '115200'
set system domain-name 'dev.vyos.net'
set system host-name 'WR1'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
-set system wireless country-code 'es'
set system syslog global facility all level 'info'
set system syslog global facility local7 level 'debug'
+set system wireless country-code 'es'
diff --git a/smoketest/configs/basic-api-service b/smoketest/configs/basic-api-service
index f997ccd73..d5364d3e6 100644
--- a/smoketest/configs/basic-api-service
+++ b/smoketest/configs/basic-api-service
@@ -3,8 +3,6 @@ interfaces {
address 192.0.2.1/31
address 2001:db8::1234/64
}
- ethernet eth1 {
- }
loopback lo {
}
}
diff --git a/smoketest/configs/bgp-dmvpn-hub b/smoketest/configs/bgp-dmvpn-hub
index fc5aadd8f..fc0be5e07 100644
--- a/smoketest/configs/bgp-dmvpn-hub
+++ b/smoketest/configs/bgp-dmvpn-hub
@@ -1,8 +1,12 @@
interfaces {
ethernet eth0 {
address 100.64.10.1/31
+ speed auto
+ duplex auto
}
ethernet eth1 {
+ speed auto
+ duplex auto
}
loopback lo {
}
@@ -171,4 +175,3 @@ vpn {
// Warning: Do not remove the following line.
// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
// Release version: 1.3.0-epa3
-
diff --git a/smoketest/configs/bgp-evpn-l3vpn-pe-router b/smoketest/configs/bgp-evpn-l3vpn-pe-router
index b1ca7fae3..c676463b8 100644
--- a/smoketest/configs/bgp-evpn-l3vpn-pe-router
+++ b/smoketest/configs/bgp-evpn-l3vpn-pe-router
@@ -38,7 +38,7 @@ interfaces {
ethernet eth0 {
address 192.0.2.59/27
address 2001:db8:ffff::59/64
- description "out-of-band management"
+ description "Out-of-Band Managament Port"
vrf mgmt
}
ethernet eth1 {
diff --git a/smoketest/configs/bgp-rpki b/smoketest/configs/bgp-rpki
index dffab4c69..5588f15c9 100644
--- a/smoketest/configs/bgp-rpki
+++ b/smoketest/configs/bgp-rpki
@@ -4,6 +4,7 @@ interfaces {
address 2001:db8::ffff/64
}
ethernet eth1 {
+ address 100.64.0.1/24
}
loopback lo {
}
diff --git a/smoketest/configs/isis-small b/smoketest/configs/isis-small
index 5a4201988..79a2f042f 100644
--- a/smoketest/configs/isis-small
+++ b/smoketest/configs/isis-small
@@ -4,19 +4,35 @@ interfaces {
}
ethernet eth0 {
duplex auto
+ offload {
+ sg
+ tso
+ }
speed auto
}
ethernet eth1 {
address 192.0.2.1/24
duplex auto
+ offload {
+ sg
+ tso
+ }
speed auto
}
ethernet eth2 {
duplex auto
+ offload {
+ sg
+ tso
+ }
speed auto
}
ethernet eth3 {
duplex auto
+ offload {
+ sg
+ tso
+ }
speed auto
}
}
@@ -41,9 +57,9 @@ policy {
}
}
protocols {
- isis FOO {
+ isis {
interface eth1 {
- bfd
+ bfd
}
net 49.0001.1921.6800.1002.00
redistribute {
@@ -61,6 +77,17 @@ system {
config-management {
commit-revisions 200
}
+ conntrack {
+ modules {
+ ftp
+ h323
+ nfs
+ pptp
+ sip
+ sqlnet
+ tftp
+ }
+ }
console {
device ttyS0 {
speed 115200
@@ -77,11 +104,11 @@ system {
}
}
ntp {
- server 0.pool.ntp.org {
+ server time1.vyos.net {
}
- server 1.pool.ntp.org {
+ server time2.vyos.net {
}
- server 2.pool.ntp.org {
+ server time3.vyos.net {
}
}
syslog {
@@ -99,5 +126,5 @@ system {
// Warning: Do not remove the following line.
-// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@1:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@18:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@7:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
-// Release version: 1.3.0-rc1
+// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
+// Release version: 1.3.0
diff --git a/smoketest/configs/pppoe-server b/smoketest/configs/pppoe-server
index ff5815e29..a01a45115 100644
--- a/smoketest/configs/pppoe-server
+++ b/smoketest/configs/pppoe-server
@@ -4,8 +4,12 @@ interfaces {
}
ethernet eth1 {
address 192.168.0.1/24
+ speed auto
+ duplex auto
}
ethernet eth2 {
+ speed auto
+ duplex auto
}
loopback lo {
}
diff --git a/smoketest/scripts/cli/test_interfaces_wireless.py b/smoketest/scripts/cli/test_interfaces_wireless.py
index 421ca7861..58aef0001 100755
--- a/smoketest/scripts/cli/test_interfaces_wireless.py
+++ b/smoketest/scripts/cli/test_interfaces_wireless.py
@@ -66,7 +66,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
cls._test_ipv6 = False
cls._test_vlan = False
- cls.cli_set(cls, wifi_cc_path + ['es'])
+ cls.cli_set(cls, wifi_cc_path + ['se'])
def test_wireless_add_single_ip_address(self):
# derived method to check if member interfaces are enslaved properly
@@ -84,7 +84,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
def test_wireless_hostapd_config(self):
# Only set the hostapd (access-point) options
- interface = 'wlan0'
+ interface = 'wlan1'
ssid = 'ssid'
self.cli_set(self._base_path + [interface, 'ssid', ssid])
@@ -297,9 +297,96 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
for key, value in vht_opt.items():
self.assertIn(value, tmp)
+ def test_wireless_hostapd_he_config(self):
+ # Only set the hostapd (access-point) options - HE mode for 802.11ax at 6GHz
+ interface = 'wlan1'
+ ssid = 'ssid'
+ channel = '1'
+ sae_pw = 'VyOSVyOSVyOS'
+ country = 'de'
+ bss_color = '37'
+ channel_set_width = '134'
+ center_channel_freq_1 = '15'
+
+ self.cli_set(wifi_cc_path + [country])
+ self.cli_set(self._base_path + [interface, 'ssid', ssid])
+ self.cli_set(self._base_path + [interface, 'type', 'access-point'])
+ self.cli_set(self._base_path + [interface, 'channel', channel])
+ self.cli_set(self._base_path + [interface, 'mode', 'ax'])
+ self.cli_set(self._base_path + [interface, 'security', 'wpa', 'mode', 'wpa3'])
+ self.cli_set(self._base_path + [interface, 'security', 'wpa', 'passphrase', sae_pw])
+ self.cli_set(self._base_path + [interface, 'security', 'wpa', 'cipher', 'CCMP'])
+ self.cli_set(self._base_path + [interface, 'security', 'wpa', 'cipher', 'GCMP'])
+ self.cli_set(self._base_path + [interface, 'enable-bf-protection'])
+ self.cli_set(self._base_path + [interface, 'mgmt-frame-protection', 'required'])
+ self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'bss-color', bss_color])
+ self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'channel-set-width', channel_set_width])
+ self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'center-channel-freq', 'freq-1', center_channel_freq_1])
+ self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'beamform', 'multi-user-beamformer'])
+ self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'beamform', 'single-user-beamformer'])
+
+ self.cli_commit()
+
+ #
+ # Validate Config
+ #
+ tmp = get_config_value(interface, 'interface')
+ self.assertEqual(interface, tmp)
+
+ # ssid
+ tmp = get_config_value(interface, 'ssid')
+ self.assertEqual(ssid, tmp)
+
+ # mode of operation resulting from [interface, 'mode', 'ax']
+ tmp = get_config_value(interface, 'hw_mode')
+ self.assertEqual('a', tmp)
+ tmp = get_config_value(interface, 'ieee80211h')
+ self.assertEqual('1', tmp)
+ tmp = get_config_value(interface, 'ieee80211ax')
+ self.assertEqual('1', tmp)
+
+ # channel and channel width
+ tmp = get_config_value(interface, 'channel')
+ self.assertEqual(channel, tmp)
+ tmp = get_config_value(interface, 'op_class')
+ self.assertEqual(channel_set_width, tmp)
+ tmp = get_config_value(interface, 'he_oper_centr_freq_seg0_idx')
+ self.assertEqual(center_channel_freq_1, tmp)
+
+ # Country code
+ tmp = get_config_value(interface, 'country_code')
+ self.assertEqual(country.upper(), tmp)
+
+ # BSS coloring
+ tmp = get_config_value(interface, 'he_bss_color')
+ self.assertEqual(bss_color, tmp)
+
+ # sae_password
+ tmp = get_config_value(interface, 'sae_password')
+ self.assertEqual(sae_pw, tmp)
+
+ # WPA3 and dependencies
+ tmp = get_config_value(interface, 'wpa')
+ self.assertEqual('2', tmp)
+ tmp = get_config_value(interface, 'rsn_pairwise')
+ self.assertEqual('CCMP GCMP', tmp)
+ tmp = get_config_value(interface, 'wpa_key_mgmt')
+ self.assertEqual('SAE', tmp)
+
+ # beamforming
+ tmp = get_config_value(interface, 'he_mu_beamformer')
+ self.assertEqual('1', tmp)
+ tmp = get_config_value(interface, 'he_su_beamformee')
+ self.assertEqual('0', tmp)
+ tmp = get_config_value(interface, 'he_mu_beamformer')
+ self.assertEqual('1', tmp)
+
+ # Check for running process
+ self.assertTrue(process_named_running('hostapd'))
+
def test_wireless_hostapd_wpa_config(self):
# Only set the hostapd (access-point) options
- interface = 'wlan0'
+ interface = 'wlan1'
phy = 'phy0'
ssid = 'VyOS-SMOKETEST'
channel = '1'
@@ -311,8 +398,12 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_set(self._base_path + [interface, 'type', 'access-point'])
self.cli_set(self._base_path + [interface, 'mode', mode])
- # Country-Code must be set
+ # SSID and country-code are already configured in self.setUpClass()
+ # Therefore, we must delete those here to check if commit will fail without it.
self.cli_delete(wifi_cc_path)
+ self.cli_delete(self._base_path + [interface, 'ssid'])
+
+ # Country-Code must be set
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(wifi_cc_path + [country])
@@ -322,7 +413,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_commit()
self.cli_set(self._base_path + [interface, 'ssid', ssid])
- # Channel must be set
+ # Channel must be set (defaults to channel 0)
self.cli_set(self._base_path + [interface, 'channel', channel])
self.cli_set(self._base_path + [interface, 'security', 'wpa', 'mode', 'wpa2'])
@@ -363,7 +454,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
self.assertTrue(process_named_running('hostapd'))
def test_wireless_access_point_bridge(self):
- interface = 'wlan0'
+ interface = 'wlan1'
ssid = 'VyOS-Test'
bridge = 'br42477'
@@ -373,6 +464,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_set(self._base_path + [interface, 'ssid', ssid])
self.cli_set(self._base_path + [interface, 'type', 'access-point'])
+ self.cli_set(self._base_path + [interface, 'channel', '1'])
self.cli_commit()
@@ -399,7 +491,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_delete(bridge_path)
def test_wireless_security_station_address(self):
- interface = 'wlan0'
+ interface = 'wlan1'
ssid = 'VyOS-ACL'
hostapd_accept_station_conf = f'/run/hostapd/{interface}_station_accept.conf'
diff --git a/smoketest/scripts/cli/test_service_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py
index 97c63d4cb..34e45a81a 100755
--- a/smoketest/scripts/cli/test_service_pppoe-server.py
+++ b/smoketest/scripts/cli/test_service_pppoe-server.py
@@ -177,6 +177,17 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
conf.read(self._config_file)
self.assertEqual(conf['pppoe']['pado-delay'], '10,20:200,30:300,-1:400')
+ def test_pppoe_server_any_login(self):
+ # Test configuration of local authentication for PPPoE server
+ self.basic_config()
+
+ self.set(['authentication', 'any-login'])
+ self.cli_commit()
+
+ # Validate configuration values
+ config = read_file(self._config_file)
+ self.assertIn('any-login=1', config)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_vpn_openconnect.py b/smoketest/scripts/cli/test_vpn_openconnect.py
index a2e426dc7..dcce229e2 100755
--- a/smoketest/scripts/cli/test_vpn_openconnect.py
+++ b/smoketest/scripts/cli/test_vpn_openconnect.py
@@ -106,32 +106,32 @@ n+vZdJAWTq76zAPT3n9FClo=
"""
ca_key_data = """
- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCg7Mjl6+rs8Bd
- kjqgl2QDuHfrH2mTDCeB7WuNTnIz0BPDtlmwIdqhU7LdCB/zUSABAa6LBe/Z/bK
- WCRKyq8fU2/4uWECe975IMXOfFdYT6KA78DROvOi32JZmln0LAXV+538eb+g19x
- NtoBhPO8igiNevfkV+nJehRK/41ATj+assTOv87vaSX7WqyaP/ZqkIdQD9Kc3cq
- B4JsYjkWcniHL9yk4oY3cjKK8PJ1pi4FqgFHt2hA+Ic+NvbAhc47K9otP8FM4jk
- Sii3MZfHA6Czb43BtbR+YEiWPzBhzE2bCuIgeRUumMF1Z+CAT6U7Cpx3XPh+Ac2
- RnDa8wKeQ1eqE1AgMBAAECggEAEDDaoqVqmMWsONoQiWRMr2h1RZvPxP7OpuKVW
- iF3XgrMOb9HZc+Ybpj1dC+NDMekvNaHhMuF2Lqz6UgjDjzzVMH/x4yfDwFWUqeb
- SxbglvGmVk4zg48JNkmArLT6GJQccD1XXjZZmqSOhagM4KalCpIdxfvgoZbTCa2
- xMSCLHS+1HCDcmpCoeXM6ZBPTn0NbjRDAqIzCwcq2veG7RSz040obk8h7nrdv7j
- hxRGmtPmPFzKgGLNn6GnL7AwYVMiidjj/ntvM4B1OMs9MwUYbtpg98TWcWyu+ZR
- akUrnVf9z2aIHCKyuJvke/PNqMgw+L8KV4/478XxWhXfl7K1F3nMQKBgQDRBUDY
- NFH0wC4MMWsA+RGwyz7RlzACChDJCMtA/agbW06gUoE9UYf8KtLQQQYljlLJHxH
- GD72QnuM+sowGGXnbD4BabA9TQiQUG5c6boznTy1uU1gt8T0Zl0mmC7vIMoMBVd
- 5bb0qrZvuR123kDGYn6crug9uvMIYSSlhGmBGTJQKBgQDFGC3vfkCyXzLoYy+RI
- s/rXgyBF1PUYQtyDgL0N811L0H7a8JhFnt4FvodUbxv2ob+1kIc9e3yXT6FsGyO
- 7IDOnqgeQKy74bYqVPZZuf1FOFb9fuxf00pn1FmhAF4OuSWkhVhrKkyrZwdD8Ar
- jLK253J94dogjdKAYfN1csaOA0QKBgD0zUZI8d4a3QoRVb+RACTr/t6v8nZTrR5
- DlX0XvP2qLKJFutuKyXaOrEkDh2R/j9T9oNncMos+WhikUdEVQ7koC1u0i2LXjF
- tdAYN4+Akmz+DRmeNoy2VYF4w2YP+pVR+B7OPkCtBVNuPkx3743Fy42mTGPMCKy
- jX8Lf59j5Tl1AoGBAI3sk2dZqozHMIlWovIH92CtIKP0gFD2cJ94p3fklvZDSWg
- aeKYg4lffc8uZB/AjlAH9ly3ziZx0uIjcOc/RTg96/+SI/dls9xgUhjCmVVJ692
- ki9GMsau/JYaEl+pTvjcOiocDJfNwQHJM3Tx+3FII59DtyXyXo3T/E6kHNSMeBA
- oGAR9M48DTspv9OH1S7X6yR6MtMY5ltsBmB3gPhQFxiDKBvARkIkAPqObQ9TG/V
- uOz2Purq0Oz7SHsY2jiFDd2KEGo6JfG61NDdIhiQC99ztSgt7NtvSCnX22SfVDW
- oFxSK+tek7tvDVXAXCNy4ZESMEUGJ6NDHImb80aF+xZ3wYKw=
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCg7Mjl6+rs8Bdk
+jqgl2QDuHfrH2mTDCeB7WuNTnIz0BPDtlmwIdqhU7LdCB/zUSABAa6LBe/Z/bKWC
+RKyq8fU2/4uWECe975IMXOfFdYT6KA78DROvOi32JZmln0LAXV+538eb+g19xNto
+BhPO8igiNevfkV+nJehRK/41ATj+assTOv87vaSX7WqyaP/ZqkIdQD9Kc3cqB4Js
+YjkWcniHL9yk4oY3cjKK8PJ1pi4FqgFHt2hA+Ic+NvbAhc47K9otP8FM4jkSii3M
+ZfHA6Czb43BtbR+YEiWPzBhzE2bCuIgeRUumMF1Z+CAT6U7Cpx3XPh+Ac2RnDa8w
+KeQ1eqE1AgMBAAECggEAEDDaoqVqmMWsONoQiWRMr2h1RZvPxP7OpuKVWiF3XgrM
+Ob9HZc+Ybpj1dC+NDMekvNaHhMuF2Lqz6UgjDjzzVMH/x4yfDwFWUqebSxbglvGm
+Vk4zg48JNkmArLT6GJQccD1XXjZZmqSOhagM4KalCpIdxfvgoZbTCa2xMSCLHS+1
+HCDcmpCoeXM6ZBPTn0NbjRDAqIzCwcq2veG7RSz040obk8h7nrdv7jhxRGmtPmPF
+zKgGLNn6GnL7AwYVMiidjj/ntvM4B1OMs9MwUYbtpg98TWcWyu+ZRakUrnVf9z2a
+IHCKyuJvke/PNqMgw+L8KV4/478XxWhXfl7K1F3nMQKBgQDRBUDYNFH0wC4MMWsA
++RGwyz7RlzACChDJCMtA/agbW06gUoE9UYf8KtLQQQYljlLJHxHGD72QnuM+sowG
+GXnbD4BabA9TQiQUG5c6boznTy1uU1gt8T0Zl0mmC7vIMoMBVd5bb0qrZvuR123k
+DGYn6crug9uvMIYSSlhGmBGTJQKBgQDFGC3vfkCyXzLoYy+RIs/rXgyBF1PUYQty
+DgL0N811L0H7a8JhFnt4FvodUbxv2ob+1kIc9e3yXT6FsGyO7IDOnqgeQKy74bYq
+VPZZuf1FOFb9fuxf00pn1FmhAF4OuSWkhVhrKkyrZwdD8ArjLK253J94dogjdKAY
+fN1csaOA0QKBgD0zUZI8d4a3QoRVb+RACTr/t6v8nZTrR5DlX0XvP2qLKJFutuKy
+XaOrEkDh2R/j9T9oNncMos+WhikUdEVQ7koC1u0i2LXjFtdAYN4+Akmz+DRmeNoy
+2VYF4w2YP+pVR+B7OPkCtBVNuPkx3743Fy42mTGPMCKyjX8Lf59j5Tl1AoGBAI3s
+k2dZqozHMIlWovIH92CtIKP0gFD2cJ94p3fklvZDSWgaeKYg4lffc8uZB/AjlAH9
+ly3ziZx0uIjcOc/RTg96/+SI/dls9xgUhjCmVVJ692ki9GMsau/JYaEl+pTvjcOi
+ocDJfNwQHJM3Tx+3FII59DtyXyXo3T/E6kHNSMeBAoGAR9M48DTspv9OH1S7X6yR
+6MtMY5ltsBmB3gPhQFxiDKBvARkIkAPqObQ9TG/VuOz2Purq0Oz7SHsY2jiFDd2K
+EGo6JfG61NDdIhiQC99ztSgt7NtvSCnX22SfVDWoFxSK+tek7tvDVXAXCNy4ZESM
+EUGJ6NDHImb80aF+xZ3wYKw=
"""
PROCESS_NAME = 'ocserv-main'
diff --git a/src/conf_mode/interfaces_wireless.py b/src/conf_mode/interfaces_wireless.py
index 998ff9dba..73944dc8b 100755
--- a/src/conf_mode/interfaces_wireless.py
+++ b/src/conf_mode/interfaces_wireless.py
@@ -104,6 +104,15 @@ def get_config(config=None):
tmp = {'security': {'wpa': {'cipher' : ['CCMP']}}}
elif wpa_mode == 'both':
tmp = {'security': {'wpa': {'cipher' : ['CCMP', 'TKIP']}}}
+ elif wpa_mode == 'wpa3':
+ # According to WiFi specs (https://www.wi-fi.org/file/wpa3-specification)
+ # section 3.5: WPA3-Enterprise 192-bit mode
+ # WiFi NICs which would be able to connect to WPA3-Enterprise managed
+ # networks MUST support GCMP-256.
+ # Reasoning: Provided that chipsets would most likely _not_ be
+ # "private user only", they all would come with built-in support
+ # for GCMP-256.
+ tmp = {'security': {'wpa': {'cipher' : ['CCMP', 'CCMP-256', 'GCMP', 'GCMP-256']}}}
if tmp: wifi = dict_merge(tmp, wifi)
@@ -143,6 +152,23 @@ def verify(wifi):
if 'channel' not in wifi:
raise ConfigError('Wireless channel must be configured!')
+ if 'capabilities' in wifi and 'he' in wifi['capabilities']:
+ if 'channel_set_width' not in wifi['capabilities']['he']:
+ raise ConfigError('Channel width must be configured!')
+
+ # op_modes drawn from:
+ # https://w1.fi/cgit/hostap/tree/src/common/ieee802_11_common.c?id=195cc3d919503fb0d699d9a56a58a72602b25f51#n1525
+ # 802.11ax (WiFi-6e - HE) can use up to 160MHz bandwidth channels
+ six_ghz_op_modes_he = ['131', '132', '133', '134', '135']
+ # 802.11be (WiFi-7 - EHT) can use up to 320MHz bandwidth channels
+ six_ghz_op_modes_eht = six_ghz_op_modes_he.append('137')
+ if 'security' in wifi and 'wpa' in wifi['security'] and 'mode' in wifi['security']['wpa']:
+ if wifi['security']['wpa']['mode'] == 'wpa3':
+ if 'he' in wifi['capabilities']:
+ if wifi['capabilities']['he']['channel_set_width'] in six_ghz_op_modes_he:
+ if 'mgmt_frame_protection' not in wifi or wifi['mgmt_frame_protection'] != 'required':
+ raise ConfigError('Management Frame Protection (MFP) is required with WPA3 at 6GHz! Consider also enabling Beacon Frame Protection (BFP) if your device supports it.')
+
if 'security' in wifi:
if {'wep', 'wpa'} <= set(wifi.get('security', {})):
raise ConfigError('Must either use WEP or WPA security!')
@@ -176,7 +202,8 @@ def verify(wifi):
if capabilities['vht']['beamform'] == 'single-user-beamformer':
if int(capabilities['vht']['antenna_count']) < 3:
- # Nasty Gotcha: see https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf lines 692-705
+ # Nasty Gotcha: see lines 708-721 in:
+ # https://w1.fi/cgit/hostap/tree/hostapd/hostapd.conf?h=hostap_2_10&id=cff80b4f7d3c0a47c052e8187d671710f48939e4#n708
raise ConfigError('Single-user beam former requires at least 3 antennas!')
if 'station_interfaces' in wifi and wifi['type'] == 'station':
diff --git a/src/conf_mode/nat_cgnat.py b/src/conf_mode/nat_cgnat.py
index 34ec64fce..3484e5873 100755
--- a/src/conf_mode/nat_cgnat.py
+++ b/src/conf_mode/nat_cgnat.py
@@ -119,37 +119,34 @@ class IPOperations:
+ [self.ip_network.broadcast_address]
]
- def get_prefix_by_ip_range(self):
+ def get_prefix_by_ip_range(self) -> list[ipaddress.IPv4Network]:
"""Return the common prefix for the address range
Example:
% ip = IPOperations('100.64.0.1-100.64.0.5')
% ip.get_prefix_by_ip_range()
- 100.64.0.0/29
+ [IPv4Network('100.64.0.1/32'), IPv4Network('100.64.0.2/31'), IPv4Network('100.64.0.4/31')]
"""
- if '-' in self.ip_prefix:
- ip_start, ip_end = self.ip_prefix.split('-')
- start_ip = ipaddress.IPv4Address(ip_start.strip())
- end_ip = ipaddress.IPv4Address(ip_end.strip())
-
- start_int = int(start_ip)
- end_int = int(end_ip)
-
- # XOR to find differing bits
- xor = start_int ^ end_int
-
- # Count the number of leading zeros in the XOR result to find the prefix length
- prefix_length = 32 - xor.bit_length()
-
- # Calculate the network address
- network_int = start_int & (0xFFFFFFFF << (32 - prefix_length))
- network_address = ipaddress.IPv4Address(network_int)
+ # We do not need to convert the IP range to network
+ # if it is already in network format
+ if self.ip_network:
+ return [self.ip_network]
+
+ # Raise an error if the IP range is not in the correct format
+ if '-' not in self.ip_prefix:
+ raise ValueError(
+ 'Invalid IP range format. Please provide the IP range in CIDR format or with "-" separator.'
+ )
+ # Split the IP range and convert it to IP address objects
+ range_start, range_end = self.ip_prefix.split('-')
+ range_start = ipaddress.IPv4Address(range_start)
+ range_end = ipaddress.IPv4Address(range_end)
- return f"{network_address}/{prefix_length}"
- return self.ip_prefix
+ # Return the summarized IP networks list
+ return list(ipaddress.summarize_address_range(range_start, range_end))
-def _delete_conntrack_entries(source_prefixes: list) -> None:
+def _delete_conntrack_entries(source_prefixes: list[ipaddress.IPv4Network]) -> None:
"""Delete all conntrack entries for the list of prefixes"""
for source_prefix in source_prefixes:
run(f'conntrack -D -s {source_prefix}')
@@ -224,15 +221,31 @@ def get_config(config=None):
with_recursive_defaults=True,
)
- if conf.exists(base) and is_node_changed(conf, base + ['pool']):
- config.update({'delete_conntrack_entries': {}})
+ effective_config = conf.get_config_dict(
+ base,
+ get_first_key=True,
+ key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ effective=True,
+ )
+
+ # Check if the pool configuration has changed
+ if not conf.exists(base) or is_node_changed(conf, base + ['pool']):
+ config['delete_conntrack_entries'] = {}
+
+ # add running config
+ if effective_config:
+ config['effective'] = effective_config
+
+ if not conf.exists(base):
+ config['deleted'] = {}
return config
def verify(config):
# bail out early - looks like removal from running config
- if not config:
+ if 'deleted' in config:
return None
if 'pool' not in config:
@@ -336,7 +349,7 @@ def verify(config):
def generate(config):
- if not config:
+ if 'deleted' in config:
return None
proto_maps = []
@@ -401,13 +414,38 @@ def generate(config):
def apply(config):
- if not config:
+ if 'deleted' in config:
# Cleanup cgnat
cmd('nft delete table ip cgnat')
if os.path.isfile(nftables_cgnat_config):
os.unlink(nftables_cgnat_config)
- return None
- cmd(f'nft --file {nftables_cgnat_config}')
+ else:
+ cmd(f'nft --file {nftables_cgnat_config}')
+
+ # Delete conntrack entries
+ # if the pool configuration has changed
+ if 'delete_conntrack_entries' in config and 'effective' in config:
+ # Prepare the list of internal pool prefixes
+ internal_pool_prefix_list: list[ipaddress.IPv4Network] = []
+
+ # Get effective rules configurations
+ for rule_config in config['effective'].get('rule', {}).values():
+ # Get effective internal pool configuration
+ internal_pool = rule_config['source']['pool']
+ # Find the internal IP ranges for the internal pool
+ internal_ip_ranges: list[str] = config['effective']['pool']['internal'][
+ internal_pool
+ ]['range']
+ # Get the IP prefixes for the internal IP range
+ for internal_range in internal_ip_ranges:
+ ip_prefix: list[ipaddress.IPv4Network] = IPOperations(
+ internal_range
+ ).get_prefix_by_ip_range()
+ # Add the IP prefixes to the list of all internal pool prefixes
+ internal_pool_prefix_list += ip_prefix
+
+ # Delete required sources for conntrack
+ _delete_conntrack_entries(internal_pool_prefix_list)
# Logging allocations
if 'log_allocation' in config:
@@ -420,23 +458,11 @@ def apply(config):
external_host, port_range = rest.split(' . ')
# Log the parsed data
logger.info(
- f"Internal host: {internal_host.lstrip()}, external host: {external_host}, Port range: {port_range}")
+ f'Internal host: {internal_host.lstrip()}, external host: {external_host}, Port range: {port_range}')
except ValueError as e:
# Log error message
logger.error(f"Error processing line '{allocation}': {e}")
- # Delete conntrack entries
- if 'delete_conntrack_entries' in config:
- internal_pool_prefix_list = []
- for rule, rule_config in config['rule'].items():
- internal_pool = rule_config['source']['pool']
- internal_ip_ranges: list = config['pool']['internal'][internal_pool]['range']
- for internal_range in internal_ip_ranges:
- ip_prefix = IPOperations(internal_range).get_prefix_by_ip_range()
- internal_pool_prefix_list.append(ip_prefix)
- # Deleta required sources for conntrack
- _delete_conntrack_entries(internal_pool_prefix_list)
-
if __name__ == '__main__':
try:
diff --git a/src/helpers/system-versions-foot.py b/src/helpers/add-system-version.py
index 9614f0d28..5270ee7d3 100755
--- a/src/helpers/system-versions-foot.py
+++ b/src/helpers/add-system-version.py
@@ -1,6 +1,6 @@
#!/usr/bin/python3
-# Copyright 2019, 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -15,14 +15,6 @@
# 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/>.
-import sys
-import vyos.defaults
-from vyos.component_version import write_system_footer
+from vyos.component_version import add_system_version
-sys.stdout.write("\n\n")
-if vyos.defaults.cfg_vintage == 'vyos':
- write_system_footer(None, vintage='vyos')
-elif vyos.defaults.cfg_vintage == 'vyatta':
- write_system_footer(None, vintage='vyatta')
-else:
- write_system_footer(None, vintage='vyos')
+add_system_version()
diff --git a/src/helpers/run-config-migration.py b/src/helpers/run-config-migration.py
index ce647ad0a..e6ce97363 100755
--- a/src/helpers/run-config-migration.py
+++ b/src/helpers/run-config-migration.py
@@ -1,86 +1,78 @@
-#!/usr/bin/python3
-
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019-2024 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 program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
#
-# This library is distributed in the hope that it will be useful,
+# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this library. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys
-import argparse
-import datetime
-
-from vyos.utils.process import cmd
-from vyos.migrator import Migrator, VirtualMigrator
-
-def main():
- argparser = argparse.ArgumentParser(
- formatter_class=argparse.RawTextHelpFormatter)
- argparser.add_argument('config_file', type=str,
- help="configuration file to migrate")
- argparser.add_argument('--force', action='store_true',
- help="Force calling of all migration scripts.")
- argparser.add_argument('--set-vintage', type=str,
- choices=['vyatta', 'vyos'],
- help="Set the format for the config version footer in config"
- " file:\n"
- "set to 'vyatta':\n"
- "(for '/* === vyatta-config-version ... */' format)\n"
- "or 'vyos':\n"
- "(for '// vyos-config-version ...' format).")
- argparser.add_argument('--virtual', action='store_true',
- help="Update the format of the trailing comments in"
- " config file,\nfrom 'vyatta' to 'vyos'; no migration"
- " scripts are run.")
- args = argparser.parse_args()
+import time
+from argparse import ArgumentParser
+from shutil import copyfile
- config_file_name = args.config_file
- force_on = args.force
- vintage = args.set_vintage
- virtual = args.virtual
+from vyos.migrate import ConfigMigrate
+from vyos.migrate import ConfigMigrateError
- if not os.access(config_file_name, os.R_OK):
- print("Read error: {}.".format(config_file_name))
- sys.exit(1)
+parser = ArgumentParser()
+parser.add_argument('config_file', type=str,
+ help="configuration file to migrate")
+parser.add_argument('--test-script', type=str,
+ help="test named script")
+parser.add_argument('--output-file', type=str,
+ help="write to named output file instead of config file")
+parser.add_argument('--force', action='store_true',
+ help="force run of all migration scripts")
- if not os.access(config_file_name, os.W_OK):
- print("Write error: {}.".format(config_file_name))
- sys.exit(1)
+args = parser.parse_args()
- separator = "."
- backup_file_name = separator.join([config_file_name,
- '{0:%Y-%m-%d-%H%M%S}'.format(datetime.datetime.now()),
- 'pre-migration'])
+config_file = args.config_file
+out_file = args.output_file
+test_script = args.test_script
+force = args.force
- cmd(f'cp -p {config_file_name} {backup_file_name}')
+if not os.access(config_file, os.R_OK):
+ print(f"Config file '{config_file}' not readable")
+ sys.exit(1)
- if not virtual:
- virtual_migration = VirtualMigrator(config_file_name)
- virtual_migration.run()
+if out_file is None:
+ if not os.access(config_file, os.W_OK):
+ print(f"Config file '{config_file}' not writeable")
+ sys.exit(1)
+else:
+ try:
+ open(out_file, 'w').close()
+ except OSError:
+ print(f"Output file '{out_file}' not writeable")
+ sys.exit(1)
- migration = Migrator(config_file_name, force=force_on)
- migration.run()
+config_migrate = ConfigMigrate(config_file, force=force, output_file=out_file)
- if not migration.config_changed():
- os.remove(backup_file_name)
- else:
- virtual_migration = VirtualMigrator(config_file_name,
- set_vintage=vintage)
+if test_script:
+ # run_script and exit
+ config_migrate.run_script(test_script)
+ sys.exit(0)
- virtual_migration.run()
+backup = None
+if out_file is None:
+ timestr = time.strftime("%Y%m%d-%H%M%S")
+ backup = f'{config_file}.{timestr}.pre-migration'
+ copyfile(config_file, backup)
- if not virtual_migration.config_changed():
- os.remove(backup_file_name)
+try:
+ config_migrate.run()
+except ConfigMigrateError as e:
+ print(f'Error: {e}')
+ sys.exit(1)
-if __name__ == '__main__':
- main()
+if backup is not None and not config_migrate.config_modified:
+ os.unlink(backup)
diff --git a/src/helpers/vyos-load-config.py b/src/helpers/vyos-load-config.py
index 4ec865454..16083fd41 100755
--- a/src/helpers/vyos-load-config.py
+++ b/src/helpers/vyos-load-config.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019 VyOS maintainers and contributors
+# Copyright (C) 2019-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
@@ -30,7 +30,8 @@ import tempfile
import vyos.defaults
import vyos.remote
from vyos.configsource import ConfigSourceSession, VyOSError
-from vyos.migrator import Migrator, VirtualMigrator, MigratorError
+from vyos.migrate import ConfigMigrate
+from vyos.migrate import ConfigMigrateError
class LoadConfig(ConfigSourceSession):
"""A subclass for calling 'loadFile'.
@@ -81,22 +82,16 @@ with tempfile.NamedTemporaryFile() as fp:
with open(fp.name, 'w') as fd:
fd.write(config_string)
- virtual_migration = VirtualMigrator(fp.name)
+ config_migrate = ConfigMigrate(fp.name)
try:
- virtual_migration.run()
- except MigratorError as err:
- sys.exit('{}'.format(err))
-
- migration = Migrator(fp.name)
- try:
- migration.run()
- except MigratorError as err:
- sys.exit('{}'.format(err))
+ config_migrate.run()
+ except ConfigMigrateError as err:
+ sys.exit(err)
try:
config.load_config(fp.name)
except VyOSError as err:
- sys.exit('{}'.format(err))
+ sys.exit(err)
if config.session_changed():
print("Load complete. Use 'commit' to make changes effective.")
diff --git a/src/helpers/vyos-merge-config.py b/src/helpers/vyos-merge-config.py
index 35424626e..5ef845ac2 100755
--- a/src/helpers/vyos-merge-config.py
+++ b/src/helpers/vyos-merge-config.py
@@ -22,7 +22,8 @@ import vyos.remote
from vyos.config import Config
from vyos.configtree import ConfigTree
-from vyos.migrator import Migrator, VirtualMigrator
+from vyos.migrate import ConfigMigrate
+from vyos.migrate import ConfigMigrateError
from vyos.utils.process import cmd
from vyos.utils.process import DEVNULL
@@ -61,15 +62,11 @@ with tempfile.NamedTemporaryFile() as file_to_migrate:
with open(file_to_migrate.name, 'w') as fd:
fd.write(config_file)
- virtual_migration = VirtualMigrator(file_to_migrate.name)
- virtual_migration.run()
-
- migration = Migrator(file_to_migrate.name)
- migration.run()
-
- if virtual_migration.config_changed() or migration.config_changed():
- with open(file_to_migrate.name, 'r') as fd:
- config_file = fd.read()
+ config_migrate = ConfigMigrate(file_to_migrate.name)
+ try:
+ config_migrate.run()
+ except ConfigMigrateError as e:
+ sys.exit(e)
merge_config_tree = ConfigTree(config_file)
diff --git a/src/helpers/vyos-save-config.py b/src/helpers/vyos-save-config.py
index 518bd9864..fa2ea0ce4 100755
--- a/src/helpers/vyos-save-config.py
+++ b/src/helpers/vyos-save-config.py
@@ -23,7 +23,7 @@ from argparse import ArgumentParser
from vyos.config import Config
from vyos.remote import urlc
-from vyos.component_version import system_footer
+from vyos.component_version import add_system_version
from vyos.defaults import directories
DEFAULT_CONFIG_PATH = os.path.join(directories['config'], 'config.boot')
@@ -50,14 +50,13 @@ if re.match(r'\w+:/', save_file):
config = Config()
ct = config.get_config_tree(effective=True)
+# pylint: disable=consider-using-with
write_file = save_file if remote_save is None else NamedTemporaryFile(delete=False).name
-with open(write_file, 'w') as f:
- # config_tree is None before boot configuration is complete;
- # automated saves should check boot_configuration_complete
- if ct is not None:
- f.write(ct.to_string())
- f.write("\n")
- f.write(system_footer())
+
+# config_tree is None before boot configuration is complete;
+# automated saves should check boot_configuration_complete
+config_str = None if ct is None else ct.to_string()
+add_system_version(config_str, write_file)
if json_file is not None and ct is not None:
try:
diff --git a/src/helpers/vyos_net_name b/src/helpers/vyos_net_name
index 8c0992414..518e204f9 100755
--- a/src/helpers/vyos_net_name
+++ b/src/helpers/vyos_net_name
@@ -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
@@ -26,7 +26,7 @@ from vyos.configtree import ConfigTree
from vyos.defaults import directories
from vyos.utils.process import cmd
from vyos.utils.boot import boot_configuration_complete
-from vyos.migrator import VirtualMigrator
+from vyos.migrate import ConfigMigrate
vyos_udev_dir = directories['vyos_udev_dir']
vyos_log_dir = '/run/udev/log'
@@ -147,8 +147,10 @@ def get_configfile_interfaces() -> dict:
with tempfile.NamedTemporaryFile() as fp:
with open(fp.name, 'w') as fd:
fd.write(config_file)
- virtual_migration = VirtualMigrator(fp.name)
- virtual_migration.run()
+ config_migrate = ConfigMigrate(fp.name)
+ if config_migrate.syntax_update_needed():
+ config_migrate.update_syntax()
+ config_migrate.write_config()
with open(fp.name) as fd:
config_file = fd.read()
diff --git a/src/init/vyos-router b/src/init/vyos-router
index 59004fdc1..8825cc16a 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -134,14 +134,14 @@ init_bootfile () {
if [ ! -r $DEFAULT_BOOTFILE ]; then
if [ -f $vyos_data_dir/config.boot.default ]; then
cp $vyos_data_dir/config.boot.default $DEFAULT_BOOTFILE
- $vyos_libexec_dir/system-versions-foot.py >> $DEFAULT_BOOTFILE
+ $vyos_libexec_dir/add-system-version.py >> $DEFAULT_BOOTFILE
fi
fi
if [ ! -r $BOOTFILE ] ; then
if [ -f $DEFAULT_BOOTFILE ]; then
cp $DEFAULT_BOOTFILE $BOOTFILE
else
- $vyos_libexec_dir/system-versions-foot.py > $BOOTFILE
+ $vyos_libexec_dir/add-system-version.py > $BOOTFILE
fi
chgrp ${GROUP} $BOOTFILE
chmod 660 $BOOTFILE
diff --git a/src/migration-scripts/bgp/0-to-1 b/src/migration-scripts/bgp/0-to-1
index 5b8e8a163..a2f3343d8 100755..100644
--- a/src/migration-scripts/bgp/0-to-1
+++ b/src/migration-scripts/bgp/0-to-1
@@ -1,60 +1,40 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3417: migrate BGP tagNode to node as we can only have one BGP process
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-base = ['protocols', 'bgp']
-config = ConfigTree(config_file)
-
-if not config.exists(base) or not config.is_tag(base):
- # Nothing to do
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ base = ['protocols', 'bgp']
-# Only one BGP process is supported, thus this operation is savea
-asn = config.list_nodes(base)
-bgp_base = base + asn
+ if not config.exists(base) or not config.is_tag(base):
+ # Nothing to do
+ return
-# We need a temporary copy of the config
-tmp_base = ['protocols', 'bgp2']
-config.copy(bgp_base, tmp_base)
+ # Only one BGP process is supported, thus this operation is savea
+ asn = config.list_nodes(base)
+ bgp_base = base + asn
-# Now it's save to delete the old configuration
-config.delete(base)
+ # We need a temporary copy of the config
+ tmp_base = ['protocols', 'bgp2']
+ config.copy(bgp_base, tmp_base)
-# Rename temporary copy to new final config and set new "local-as" option
-config.rename(tmp_base, 'bgp')
-config.set(base + ['local-as'], value=asn[0])
+ # Now it's save to delete the old configuration
+ config.delete(base)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # Rename temporary copy to new final config and set new "local-as" option
+ config.rename(tmp_base, 'bgp')
+ config.set(base + ['local-as'], value=asn[0])
diff --git a/src/migration-scripts/bgp/1-to-2 b/src/migration-scripts/bgp/1-to-2
index a40d86e67..c0fc3b05a 100755..100644
--- a/src/migration-scripts/bgp/1-to-2
+++ b/src/migration-scripts/bgp/1-to-2
@@ -1,84 +1,64 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3741: no-ipv4-unicast is now enabled by default
# T5937: Migrate IPv6 BGP Neighbor Peer Groups
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['protocols', 'bgp']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-base = ['protocols', 'bgp']
-config = ConfigTree(config_file)
+ # This is now a default option - simply delete it.
+ # As it was configured explicitly - we can also bail out early as we need to
+ # do nothing!
+ if config.exists(base + ['parameters', 'default', 'no-ipv4-unicast']):
+ config.delete(base + ['parameters', 'default', 'no-ipv4-unicast'])
-if not config.exists(base):
- # Nothing to do
- exit(0)
+ # Check if the "default" node is now empty, if so - remove it
+ if len(config.list_nodes(base + ['parameters', 'default'])) == 0:
+ config.delete(base + ['parameters', 'default'])
-# This is now a default option - simply delete it.
-# As it was configured explicitly - we can also bail out early as we need to
-# do nothing!
-if config.exists(base + ['parameters', 'default', 'no-ipv4-unicast']):
- config.delete(base + ['parameters', 'default', 'no-ipv4-unicast'])
+ # Check if the "default" node is now empty, if so - remove it
+ if len(config.list_nodes(base + ['parameters'])) == 0:
+ config.delete(base + ['parameters'])
+ else:
+ # As we now install a new default option into BGP we need to migrate all
+ # existing BGP neighbors and restore the old behavior
+ if config.exists(base + ['neighbor']):
+ for neighbor in config.list_nodes(base + ['neighbor']):
+ peer_group = base + ['neighbor', neighbor, 'peer-group']
+ if config.exists(peer_group):
+ peer_group_name = config.return_value(peer_group)
+ # peer group enables old behavior for neighbor - bail out
+ if config.exists(base + ['peer-group', peer_group_name, 'address-family', 'ipv4-unicast']):
+ continue
- # Check if the "default" node is now empty, if so - remove it
- if len(config.list_nodes(base + ['parameters', 'default'])) == 0:
- config.delete(base + ['parameters', 'default'])
+ afi_ipv4 = base + ['neighbor', neighbor, 'address-family', 'ipv4-unicast']
+ if not config.exists(afi_ipv4):
+ config.set(afi_ipv4)
- # Check if the "default" node is now empty, if so - remove it
- if len(config.list_nodes(base + ['parameters'])) == 0:
- config.delete(base + ['parameters'])
-else:
- # As we now install a new default option into BGP we need to migrate all
- # existing BGP neighbors and restore the old behavior
+ # Migrate IPv6 AFI peer-group
if config.exists(base + ['neighbor']):
for neighbor in config.list_nodes(base + ['neighbor']):
- peer_group = base + ['neighbor', neighbor, 'peer-group']
- if config.exists(peer_group):
- peer_group_name = config.return_value(peer_group)
- # peer group enables old behavior for neighbor - bail out
- if config.exists(base + ['peer-group', peer_group_name, 'address-family', 'ipv4-unicast']):
- continue
-
- afi_ipv4 = base + ['neighbor', neighbor, 'address-family', 'ipv4-unicast']
- if not config.exists(afi_ipv4):
- config.set(afi_ipv4)
-
-# Migrate IPv6 AFI peer-group
-if config.exists(base + ['neighbor']):
- for neighbor in config.list_nodes(base + ['neighbor']):
- tmp_path = base + ['neighbor', neighbor, 'address-family', 'ipv6-unicast', 'peer-group']
- if config.exists(tmp_path):
- peer_group = config.return_value(tmp_path)
- config.set(base + ['neighbor', neighbor, 'peer-group'], value=peer_group)
- config.delete(tmp_path)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ tmp_path = base + ['neighbor', neighbor, 'address-family', 'ipv6-unicast', 'peer-group']
+ if config.exists(tmp_path):
+ peer_group = config.return_value(tmp_path)
+ config.set(base + ['neighbor', neighbor, 'peer-group'], value=peer_group)
+ config.delete(tmp_path)
diff --git a/src/migration-scripts/bgp/2-to-3 b/src/migration-scripts/bgp/2-to-3
index 34d321a96..d8bc34db6 100755..100644
--- a/src/migration-scripts/bgp/2-to-3
+++ b/src/migration-scripts/bgp/2-to-3
@@ -1,51 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4257: Discussion on changing BGP autonomous system number syntax
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-# Check if BGP is even configured. Then check if local-as exists, then add the system-as, then remove the local-as. This is for global configuration.
-if config.exists(['protocols', 'bgp']):
- if config.exists(['protocols', 'bgp', 'local-as']):
- config.rename(['protocols', 'bgp', 'local-as'], 'system-as')
-
-# Check if vrf names are configured. Then check if local-as exists inside of a name, then add the system-as, then remove the local-as. This is for vrf configuration.
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- if config.exists(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as']):
- config.rename(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as'], 'system-as')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Check if BGP is even configured. Then check if local-as exists, then add the system-as, then remove the local-as. This is for global configuration.
+ if config.exists(['protocols', 'bgp']):
+ if config.exists(['protocols', 'bgp', 'local-as']):
+ config.rename(['protocols', 'bgp', 'local-as'], 'system-as')
+
+ # Check if vrf names are configured. Then check if local-as exists inside of a name, then add the system-as, then remove the local-as. This is for vrf configuration.
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ if config.exists(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as']):
+ config.rename(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as'], 'system-as')
diff --git a/src/migration-scripts/bgp/3-to-4 b/src/migration-scripts/bgp/3-to-4
index 894cdda2b..842aef0ce 100755..100644
--- a/src/migration-scripts/bgp/3-to-4
+++ b/src/migration-scripts/bgp/3-to-4
@@ -1,64 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-bgp_base = ['protocols', 'bgp']
-# Check if BGP is configured - if so, migrate the CLI node
-if config.exists(bgp_base):
- if config.exists(bgp_base + ['route-map']):
- tmp = config.return_value(bgp_base + ['route-map'])
-
- config.set(['system', 'ip', 'protocol', 'bgp', 'route-map'], value=tmp)
- config.set_tag(['system', 'ip', 'protocol'])
- config.delete(bgp_base + ['route-map'])
-
-
-# Check if vrf names are configured. Check if BGP is configured - if so, migrate
-# the CLI node(s)
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- vrf_base = ['vrf', 'name', vrf]
- if config.exists(vrf_base + ['protocols', 'bgp', 'route-map']):
- tmp = config.return_value(vrf_base + ['protocols', 'bgp', 'route-map'])
-
- config.set(vrf_base + ['ip', 'protocol', 'bgp', 'route-map'], value=tmp)
- config.set_tag(vrf_base + ['ip', 'protocol', 'bgp'])
- config.delete(vrf_base + ['protocols', 'bgp', 'route-map'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ bgp_base = ['protocols', 'bgp']
+ # Check if BGP is configured - if so, migrate the CLI node
+ if config.exists(bgp_base):
+ if config.exists(bgp_base + ['route-map']):
+ tmp = config.return_value(bgp_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'bgp', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(bgp_base + ['route-map'])
+
+
+ # Check if vrf names are configured. Check if BGP is configured - if so, migrate
+ # the CLI node(s)
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'bgp', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'bgp', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'bgp', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'bgp'])
+ config.delete(vrf_base + ['protocols', 'bgp', 'route-map'])
diff --git a/src/migration-scripts/bgp/4-to-5 b/src/migration-scripts/bgp/4-to-5
index c4eb9ec72..d779eb11e 100755..100644
--- a/src/migration-scripts/bgp/4-to-5
+++ b/src/migration-scripts/bgp/4-to-5
@@ -1,67 +1,46 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Delete 'protocols bgp address-family ipv6-unicast route-target vpn
# import/export', if 'protocols bgp address-family ipv6-unicast
# route-target vpn both' exists
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-bgp_base = ['protocols', 'bgp']
-# Delete 'import/export' in default vrf if 'both' exists
-if config.exists(bgp_base):
- for address_family in ['ipv4-unicast', 'ipv6-unicast']:
- rt_path = bgp_base + ['address-family', address_family, 'route-target',
- 'vpn']
- if config.exists(rt_path + ['both']):
- if config.exists(rt_path + ['import']):
- config.delete(rt_path + ['import'])
- if config.exists(rt_path + ['export']):
- config.delete(rt_path + ['export'])
-
-# Delete import/export in vrfs if both exists
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- vrf_base = ['vrf', 'name', vrf]
+def migrate(config: ConfigTree) -> None:
+ bgp_base = ['protocols', 'bgp']
+ # Delete 'import/export' in default vrf if 'both' exists
+ if config.exists(bgp_base):
for address_family in ['ipv4-unicast', 'ipv6-unicast']:
- rt_path = vrf_base + bgp_base + ['address-family', address_family,
- 'route-target', 'vpn']
+ rt_path = bgp_base + ['address-family', address_family, 'route-target',
+ 'vpn']
if config.exists(rt_path + ['both']):
if config.exists(rt_path + ['import']):
config.delete(rt_path + ['import'])
if config.exists(rt_path + ['export']):
config.delete(rt_path + ['export'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # Delete import/export in vrfs if both exists
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ for address_family in ['ipv4-unicast', 'ipv6-unicast']:
+ rt_path = vrf_base + bgp_base + ['address-family', address_family,
+ 'route-target', 'vpn']
+ if config.exists(rt_path + ['both']):
+ if config.exists(rt_path + ['import']):
+ config.delete(rt_path + ['import'])
+ if config.exists(rt_path + ['export']):
+ config.delete(rt_path + ['export'])
diff --git a/src/migration-scripts/cluster/1-to-2 b/src/migration-scripts/cluster/1-to-2
index a2e589155..5ca4531ea 100755..100644
--- a/src/migration-scripts/cluster/1-to-2
+++ b/src/migration-scripts/cluster/1-to-2
@@ -1,40 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
import re
import sys
from vyos.configtree import ConfigTree
+from vyos.base import MigrationError
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
if not config.exists(['cluster']):
# Cluster is not set -- nothing to do at all
- sys.exit(0)
+ return
# If at least one cluster group is defined, we have real work to do.
# If there are no groups, we remove the top-level cluster node at the end of this script anyway.
@@ -102,8 +90,9 @@ if __name__ == '__main__':
services["other"].append(s)
if services["other"]:
- print("Cluster config includes non-IP address services and cannot be migrated", file=sys.stderr)
- sys.exit(1)
+ err_str = "Cluster config includes non-IP address services and cannot be migrated"
+ print(err_str, file=sys.stderr)
+ raise MigrationError(err_str)
# Cluster allowed virtual IPs for different interfaces within a single group.
# VRRP groups are by definition bound to interfaces, so we cannot migrate such configurations.
@@ -123,14 +112,16 @@ if __name__ == '__main__':
if global_interface is not None:
ips.append({"ip": ip, "interface": global_interface})
else:
- print("Error: cluster has groups with IPs without interfaces and 'cluster interface' is not specified.", file=sys.stderr)
- sys.exit(1)
+ err_str = "Cluster group has addresses without interfaces and 'cluster interface' is not specified."
+ print(f'Error: {err_str}', file=sys.stderr)
+ raise MigrationError(err_str)
# Then we check if all addresses are for the same interface.
intfs_set = set(map(lambda i: i["interface"], ips))
if len(intfs_set) > 1:
- print("Error: cluster group has addresses for different interfaces", file=sys.stderr)
- sys.exit(1)
+ err_str = "Cluster group has addresses for different interfaces"
+ print(f'Error: {err_str}', file=sys.stderr)
+ raise MigrationError(err_str)
# If we got this far, the group is migratable.
@@ -143,8 +134,9 @@ if __name__ == '__main__':
# If there's already a VRRP group with exactly the same name,
# we probably shouldn't try to make up a unique name, just leave migration to the user...
if config.exists(vrrp_path):
- print("Error: VRRP group with the same name as a cluster group already exists", file=sys.stderr)
- sys.exit(1)
+ err_str = "VRRP group with the same name already exists"
+ print(f'Error: {err_str}', file=sys.stderr)
+ raise MigrationError(err_str)
config.set(vrrp_path + ['interface'], value=interface)
for a in addresses:
@@ -184,10 +176,3 @@ if __name__ == '__main__':
# Finally, clean up the old cluster node
config.delete(['cluster'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/config-management/0-to-1 b/src/migration-scripts/config-management/0-to-1
index 6528fd136..44c685630 100755..100644
--- a/src/migration-scripts/config-management/0-to-1
+++ b/src/migration-scripts/config-management/0-to-1
@@ -1,31 +1,24 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Add commit-revisions option if it doesn't exist
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if config.exists(['system', 'config-management', 'commit-revisions']):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if config.exists(['system', 'config-management', 'commit-revisions']):
+ # Nothing to do
+ return
config.set(['system', 'config-management', 'commit-revisions'], value='200')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/conntrack-sync/1-to-2 b/src/migration-scripts/conntrack-sync/1-to-2
index a8e1007f3..3e10e98c3 100755..100644
--- a/src/migration-scripts/conntrack-sync/1-to-2
+++ b/src/migration-scripts/conntrack-sync/1-to-2
@@ -1,44 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# VyOS 1.2 crux allowed configuring a lower or upper case loglevel. This
# is no longer supported as the input data is validated and will lead to
# an error. If user specifies an upper case logleve, make it lowercase
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'conntrack-sync']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
base_accept_proto = base + ['accept-protocol']
if config.exists(base_accept_proto):
tmp = config.return_value(base_accept_proto)
@@ -57,10 +44,3 @@ else:
base_cluster = base + ['failover-mechanism', 'cluster']
if config.exists(base_cluster):
config.delete(base_cluster)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/conntrack/1-to-2 b/src/migration-scripts/conntrack/1-to-2
index c4fe667fc..0a4fb3de9 100755..100644
--- a/src/migration-scripts/conntrack/1-to-2
+++ b/src/migration-scripts/conntrack/1-to-2
@@ -1,32 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Delete "set system conntrack modules gre" option
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['system', 'conntrack', 'modules', 'gre']):
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['system', 'conntrack', 'modules', 'gre']):
- # Nothing to do
- sys.exit(0)
-else:
# Delete abandoned node
config.delete(['system', 'conntrack', 'modules', 'gre'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/conntrack/2-to-3 b/src/migration-scripts/conntrack/2-to-3
index 6bb42be1e..5ad4e6350 100755..100644
--- a/src/migration-scripts/conntrack/2-to-3
+++ b/src/migration-scripts/conntrack/2-to-3
@@ -1,36 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Conntrack syntax version 3
# Enables all conntrack modules (previous default behaviour) and omits manually disabled modules.
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print('Must specify file name!')
- sys.exit(1)
-
-filename = sys.argv[1]
-
-with open(filename, 'r') as f:
- config = ConfigTree(f.read())
-
module_path = ['system', 'conntrack', 'modules']
-# Go over all conntrack modules available as of v1.3.0.
-for module in ['ftp', 'h323', 'nfs', 'pptp', 'sip', 'sqlnet', 'tftp']:
- # 'disable' is being phased out.
- if config.exists(module_path + [module, 'disable']):
- config.delete(module_path + [module])
- # If it wasn't manually 'disable'd, it was enabled by default.
- else:
- config.set(module_path + [module])
-
-try:
- if config.exists(module_path):
- with open(filename, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Go over all conntrack modules available as of v1.3.0.
+ for module in ['ftp', 'h323', 'nfs', 'pptp', 'sip', 'sqlnet', 'tftp']:
+ # 'disable' is being phased out.
+ if config.exists(module_path + [module, 'disable']):
+ config.delete(module_path + [module])
+ # If it wasn't manually 'disable'd, it was enabled by default.
+ else:
+ config.set(module_path + [module])
diff --git a/src/migration-scripts/conntrack/3-to-4 b/src/migration-scripts/conntrack/3-to-4
index e90c383af..679a260d5 100755..100644
--- a/src/migration-scripts/conntrack/3-to-4
+++ b/src/migration-scripts/conntrack/3-to-4
@@ -1,50 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Add support for IPv6 conntrack ignore, move existing nodes to `system conntrack ignore ipv4`
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'conntrack']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-if config.exists(base + ['ignore', 'rule']):
- config.set(base + ['ignore', 'ipv4'])
- config.copy(base + ['ignore', 'rule'], base + ['ignore', 'ipv4', 'rule'])
- config.delete(base + ['ignore', 'rule'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(base + ['ignore', 'rule']):
+ config.set(base + ['ignore', 'ipv4'])
+ config.copy(base + ['ignore', 'rule'], base + ['ignore', 'ipv4', 'rule'])
+ config.delete(base + ['ignore', 'rule'])
diff --git a/src/migration-scripts/conntrack/4-to-5 b/src/migration-scripts/conntrack/4-to-5
index d2e5fc5fa..775fe7480 100755..100644
--- a/src/migration-scripts/conntrack/4-to-5
+++ b/src/migration-scripts/conntrack/4-to-5
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5779: system conntrack timeout custom
# Before:
@@ -23,37 +22,18 @@
# Extend functionality to ipv6 and move ipv4 custom rules to new node:
# set system conntrack timeout custom [ipv4 | ipv6] rule <rule> ...
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'conntrack']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['timeout', 'custom', 'rule']):
- for rule in config.list_nodes(base + ['timeout', 'custom', 'rule']):
- if config.exists(base + ['timeout', 'custom', 'rule', rule, 'protocol', 'tcp']):
- config.set(base + ['timeout', 'custom', 'ipv4', 'rule'])
- config.copy(base + ['timeout', 'custom', 'rule', rule], base + ['timeout', 'custom', 'ipv4', 'rule', rule])
- config.delete(base + ['timeout', 'custom', 'rule'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['timeout', 'custom', 'rule']):
+ for rule in config.list_nodes(base + ['timeout', 'custom', 'rule']):
+ if config.exists(base + ['timeout', 'custom', 'rule', rule, 'protocol', 'tcp']):
+ config.set(base + ['timeout', 'custom', 'ipv4', 'rule'])
+ config.copy(base + ['timeout', 'custom', 'rule', rule], base + ['timeout', 'custom', 'ipv4', 'rule', rule])
+ config.delete(base + ['timeout', 'custom', 'rule'])
diff --git a/src/migration-scripts/container/0-to-1 b/src/migration-scripts/container/0-to-1
index 6b282e082..99102a5e6 100755..100644
--- a/src/migration-scripts/container/0-to-1
+++ b/src/migration-scripts/container/0-to-1
@@ -1,77 +1,65 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4870: change underlaying container filesystem from vfs to overlay
import os
import shutil
-import sys
from vyos.configtree import ConfigTree
from vyos.utils.process import call
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['container', 'name']
-config = ConfigTree(config_file)
-
-# Check if containers exist and we need to perform image manipulation
-if config.exists(base):
- for container in config.list_nodes(base):
- # Stop any given container first
- call(f'sudo systemctl stop vyos-container-{container}.service')
- # Export container image for later re-import to new filesystem. We store
- # the backup on a real disk as a tmpfs (like /tmp) could probably lack
- # memory if a host has too many containers stored.
- image_name = config.return_value(base + [container, 'image'])
- call(f'sudo podman image save --quiet --output /root/{container}.tar --format oci-archive {image_name}')
-# No need to adjust the strage driver online (this is only used for testing and
-# debugging on a live system) - it is already overlay2 when the migration script
-# is run during system update. But the specified driver in the image is actually
-# overwritten by the still present VFS filesystem on disk. Thus podman still
-# thinks it uses VFS until we delete the libpod directory under:
-# /usr/lib/live/mount/persistence/container/storage
-#call('sed -i "s/vfs/overlay2/g" /etc/containers/storage.conf /usr/share/vyos/templates/container/storage.conf.j2')
+def migrate(config: ConfigTree) -> None:
+ # Check if containers exist and we need to perform image manipulation
+ if config.exists(base):
+ for container in config.list_nodes(base):
+ # Stop any given container first
+ call(f'sudo systemctl stop vyos-container-{container}.service')
+ # Export container image for later re-import to new filesystem. We store
+ # the backup on a real disk as a tmpfs (like /tmp) could probably lack
+ # memory if a host has too many containers stored.
+ image_name = config.return_value(base + [container, 'image'])
+ call(f'sudo podman image save --quiet --output /root/{container}.tar --format oci-archive {image_name}')
-base_path = '/usr/lib/live/mount/persistence/container/storage'
-for dir in ['libpod', 'vfs', 'vfs-containers', 'vfs-images', 'vfs-layers']:
- if os.path.exists(f'{base_path}/{dir}'):
- shutil.rmtree(f'{base_path}/{dir}')
+ # No need to adjust the strage driver online (this is only used for testing and
+ # debugging on a live system) - it is already overlay2 when the migration script
+ # is run during system update. But the specified driver in the image is actually
+ # overwritten by the still present VFS filesystem on disk. Thus podman still
+ # thinks it uses VFS until we delete the libpod directory under:
+ # /usr/lib/live/mount/persistence/container/storage
+ #call('sed -i "s/vfs/overlay2/g" /etc/containers/storage.conf /usr/share/vyos/templates/container/storage.conf.j2')
-# Now all remaining information about VFS is gone and we operate in overlayfs2
-# filesystem mode. Time to re-import the images.
-if config.exists(base):
- for container in config.list_nodes(base):
- # Export container image for later re-import to new filesystem
- image_name = config.return_value(base + [container, 'image'])
- image_path = f'/root/{container}.tar'
- call(f'sudo podman image load --quiet --input {image_path}')
+ base_path = '/usr/lib/live/mount/persistence/container/storage'
+ for dir in ['libpod', 'vfs', 'vfs-containers', 'vfs-images', 'vfs-layers']:
+ if os.path.exists(f'{base_path}/{dir}'):
+ shutil.rmtree(f'{base_path}/{dir}')
- # Start any given container first
- call(f'sudo systemctl start vyos-container-{container}.service')
+ # Now all remaining information about VFS is gone and we operate in overlayfs2
+ # filesystem mode. Time to re-import the images.
+ if config.exists(base):
+ for container in config.list_nodes(base):
+ # Export container image for later re-import to new filesystem
+ image_name = config.return_value(base + [container, 'image'])
+ image_path = f'/root/{container}.tar'
+ call(f'sudo podman image load --quiet --input {image_path}')
- # Delete temporary container image
- if os.path.exists(image_path):
- os.unlink(image_path)
+ # Start any given container first
+ call(f'sudo systemctl start vyos-container-{container}.service')
+ # Delete temporary container image
+ if os.path.exists(image_path):
+ os.unlink(image_path)
diff --git a/src/migration-scripts/container/1-to-2 b/src/migration-scripts/container/1-to-2
index 408faf978..c12dd8ebb 100755..100644
--- a/src/migration-scripts/container/1-to-2
+++ b/src/migration-scripts/container/1-to-2
@@ -1,50 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6208: container: rename "cap-add" CLI node to "capability"
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['container', 'name']
-config = ConfigTree(config_file)
-# Check if containers exist and we need to perform image manipulation
-if not config.exists(base):
- # Nothing to do
- exit(0)
+def migrate(config: ConfigTree) -> None:
-for container in config.list_nodes(base):
- cap_path = base + [container, 'cap-add']
- if config.exists(cap_path):
- config.rename(cap_path, 'capability')
+ # Check if containers exist and we need to perform image manipulation
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ for container in config.list_nodes(base):
+ cap_path = base + [container, 'cap-add']
+ if config.exists(cap_path):
+ config.rename(cap_path, 'capability')
diff --git a/src/migration-scripts/dhcp-relay/1-to-2 b/src/migration-scripts/dhcp-relay/1-to-2
index 508bac6be..54cd8d6c0 100755..100644
--- a/src/migration-scripts/dhcp-relay/1-to-2
+++ b/src/migration-scripts/dhcp-relay/1-to-2
@@ -1,35 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Delete "set service dhcp-relay relay-options port" option
# Delete "set service dhcpv6-relay listen-port" option
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not (config.exists(['service', 'dhcp-relay', 'relay-options', 'port']) or config.exists(['service', 'dhcpv6-relay', 'listen-port'])):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not (config.exists(['service', 'dhcp-relay', 'relay-options', 'port']) or config.exists(['service', 'dhcpv6-relay', 'listen-port'])):
- # Nothing to do
- sys.exit(0)
-else:
# Delete abandoned node
config.delete(['service', 'dhcp-relay', 'relay-options', 'port'])
# Delete abandoned node
config.delete(['service', 'dhcpv6-relay', 'listen-port'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/dhcp-server/10-to-11 b/src/migration-scripts/dhcp-server/10-to-11
index a0dc96ad0..f54a4c7b7 100755..100644
--- a/src/migration-scripts/dhcp-server/10-to-11
+++ b/src/migration-scripts/dhcp-server/10-to-11
@@ -1,48 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6171: rename "service dhcp-server failover" to "service dhcp-server high-availability"
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-if config.exists(base + ['failover']):
- config.rename(base + ['failover'],'high-availability')
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1) \ No newline at end of file
+ if config.exists(base + ['failover']):
+ config.rename(base + ['failover'],'high-availability')
diff --git a/src/migration-scripts/dhcp-server/4-to-5 b/src/migration-scripts/dhcp-server/4-to-5
index d15e0baf5..a655515dc 100755..100644
--- a/src/migration-scripts/dhcp-server/4-to-5
+++ b/src/migration-scripts/dhcp-server/4-to-5
@@ -1,122 +1,118 @@
#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
+
# Removes boolean operator from:
# - "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable (true|false)"
# - "set service dhcp-server shared-network-name <xyz> authoritative (true|false)"
# - "set service dhcp-server disabled (true|false)"
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['service', 'dhcp-server']):
- # Nothing to do
- sys.exit(0)
-else:
- base = ['service', 'dhcp-server']
- # Make node "set service dhcp-server dynamic-dns-update enable (true|false)" valueless
- if config.exists(base + ['dynamic-dns-update']):
- bool_val = config.return_value(base + ['dynamic-dns-update', 'enable'])
-
- # Delete the node with the old syntax
- config.delete(base + ['dynamic-dns-update'])
- if str(bool_val) == 'true':
- # Enable dynamic-dns-update with new syntax
- config.set(base + ['dynamic-dns-update'], value=None)
-
- # Make node "set service dhcp-server disabled (true|false)" valueless
- if config.exists(base + ['disabled']):
- bool_val = config.return_value(base + ['disabled'])
-
- # Delete the node with the old syntax
- config.delete(base + ['disabled'])
- if str(bool_val) == 'true':
- # Now disable DHCP server with the new syntax
- config.set(base + ['disable'], value=None)
-
- # Make node "set service dhcp-server hostfile-update (enable|disable) valueless
- if config.exists(base + ['hostfile-update']):
- bool_val = config.return_value(base + ['hostfile-update'])
-
- # Delete the node with the old syntax incl. all subnodes
- config.delete(base + ['hostfile-update'])
- if str(bool_val) == 'enable':
- # Enable hostfile update with new syntax
- config.set(base + ['hostfile-update'], value=None)
-
- # Run this for every instance if 'shared-network-name'
- for network in config.list_nodes(base + ['shared-network-name']):
- base_network = base + ['shared-network-name', network]
- # format as tag node to avoid loading problems
- config.set_tag(base + ['shared-network-name'])
-
- # Run this for every specified 'subnet'
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['service', 'dhcp-server']):
+ # Nothing to do
+ return
+ else:
+ base = ['service', 'dhcp-server']
+ # Make node "set service dhcp-server dynamic-dns-update enable (true|false)" valueless
+ if config.exists(base + ['dynamic-dns-update']):
+ bool_val = config.return_value(base + ['dynamic-dns-update', 'enable'])
+
+ # Delete the node with the old syntax
+ config.delete(base + ['dynamic-dns-update'])
+ if str(bool_val) == 'true':
+ # Enable dynamic-dns-update with new syntax
+ config.set(base + ['dynamic-dns-update'], value=None)
+
+ # Make node "set service dhcp-server disabled (true|false)" valueless
+ if config.exists(base + ['disabled']):
+ bool_val = config.return_value(base + ['disabled'])
+
+ # Delete the node with the old syntax
+ config.delete(base + ['disabled'])
+ if str(bool_val) == 'true':
+ # Now disable DHCP server with the new syntax
+ config.set(base + ['disable'], value=None)
+
+ # Make node "set service dhcp-server hostfile-update (enable|disable) valueless
+ if config.exists(base + ['hostfile-update']):
+ bool_val = config.return_value(base + ['hostfile-update'])
+
+ # Delete the node with the old syntax incl. all subnodes
+ config.delete(base + ['hostfile-update'])
+ if str(bool_val) == 'enable':
+ # Enable hostfile update with new syntax
+ config.set(base + ['hostfile-update'], value=None)
+
+ # Run this for every instance if 'shared-network-name'
+ for network in config.list_nodes(base + ['shared-network-name']):
+ base_network = base + ['shared-network-name', network]
# format as tag node to avoid loading problems
- config.set_tag(base_network + ['subnet'])
+ config.set_tag(base + ['shared-network-name'])
- # Make node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable" valueless
- if config.exists(base_subnet + ['ip-forwarding', 'enable']):
- bool_val = config.return_value(base_subnet + ['ip-forwarding', 'enable'])
- # Delete the node with the old syntax
- config.delete(base_subnet + ['ip-forwarding'])
- if str(bool_val) == 'true':
- # Recreate node with new syntax
- config.set(base_subnet + ['ip-forwarding'], value=None)
-
- # Rename node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 start <172.16.0.4> stop <172.16.0.9>
- if config.exists(base_subnet + ['start']):
- # This is the new "range" id for DHCP lease ranges
- r_id = 0
- for range in config.list_nodes(base_subnet + ['start']):
- range_start = range
- range_stop = config.return_value(base_subnet + ['start', range_start, 'stop'])
+ # Run this for every specified 'subnet'
+ for subnet in config.list_nodes(base_network + ['subnet']):
+ base_subnet = base_network + ['subnet', subnet]
+ # format as tag node to avoid loading problems
+ config.set_tag(base_network + ['subnet'])
+ # Make node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable" valueless
+ if config.exists(base_subnet + ['ip-forwarding', 'enable']):
+ bool_val = config.return_value(base_subnet + ['ip-forwarding', 'enable'])
# Delete the node with the old syntax
- config.delete(base_subnet + ['start', range_start])
+ config.delete(base_subnet + ['ip-forwarding'])
+ if str(bool_val) == 'true':
+ # Recreate node with new syntax
+ config.set(base_subnet + ['ip-forwarding'], value=None)
+
+ # Rename node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 start <172.16.0.4> stop <172.16.0.9>
+ if config.exists(base_subnet + ['start']):
+ # This is the new "range" id for DHCP lease ranges
+ r_id = 0
+ for range in config.list_nodes(base_subnet + ['start']):
+ range_start = range
+ range_stop = config.return_value(base_subnet + ['start', range_start, 'stop'])
+
+ # Delete the node with the old syntax
+ config.delete(base_subnet + ['start', range_start])
+
+ # Create the node for the new syntax
+ # Note: range is a tag node, counter is its child, not a value
+ config.set(base_subnet + ['range', r_id])
+ config.set(base_subnet + ['range', r_id, 'start'], value=range_start)
+ config.set(base_subnet + ['range', r_id, 'stop'], value=range_stop)
+
+ # format as tag node to avoid loading problems
+ config.set_tag(base_subnet + ['range'])
+
+ # increment range id for possible next range definition
+ r_id += 1
- # Create the node for the new syntax
- # Note: range is a tag node, counter is its child, not a value
- config.set(base_subnet + ['range', r_id])
- config.set(base_subnet + ['range', r_id, 'start'], value=range_start)
- config.set(base_subnet + ['range', r_id, 'stop'], value=range_stop)
+ # Delete the node with the old syntax
+ config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'subnet', subnet, 'start'])
- # format as tag node to avoid loading problems
- config.set_tag(base_subnet + ['range'])
- # increment range id for possible next range definition
- r_id += 1
+ # Make node "set service dhcp-server shared-network-name <xyz> authoritative" valueless
+ if config.exists(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']):
+ authoritative = config.return_value(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
# Delete the node with the old syntax
- config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'subnet', subnet, 'start'])
+ config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
-
- # Make node "set service dhcp-server shared-network-name <xyz> authoritative" valueless
- if config.exists(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']):
- authoritative = config.return_value(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
-
- # Delete the node with the old syntax
- config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
-
- # Recreate node with new syntax - if required
- if authoritative == "enable":
- config.set(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ # Recreate node with new syntax - if required
+ if authoritative == "enable":
+ config.set(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
diff --git a/src/migration-scripts/dhcp-server/5-to-6 b/src/migration-scripts/dhcp-server/5-to-6
index f5c766a09..9404cd038 100755..100644
--- a/src/migration-scripts/dhcp-server/5-to-6
+++ b/src/migration-scripts/dhcp-server/5-to-6
@@ -1,87 +1,69 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T1968: allow multiple static-routes to be configured
# T3838: rename dns-server -> name-server
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base + ['shared-network-name']):
- # Nothing to do
- exit(0)
-
-# Run this for every instance if 'shared-network-name'
-for network in config.list_nodes(base + ['shared-network-name']):
- base_network = base + ['shared-network-name', network]
-
- if not config.exists(base_network + ['subnet']):
- continue
-
- # Run this for every specified 'subnet'
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
-
- # T1968: allow multiple static-routes to be configured
- if config.exists(base_subnet + ['static-route']):
- prefix = config.return_value(base_subnet + ['static-route', 'destination-subnet'])
- router = config.return_value(base_subnet + ['static-route', 'router'])
- config.delete(base_subnet + ['static-route'])
-
- config.set(base_subnet + ['static-route', prefix, 'next-hop'], value=router)
- config.set_tag(base_subnet + ['static-route'])
-
- # T3838: rename dns-server -> name-server
- if config.exists(base_subnet + ['dns-server']):
- config.rename(base_subnet + ['dns-server'], 'name-server')
-
-
- # T3672: ISC DHCP server only supports one failover peer
- if config.exists(base_subnet + ['failover']):
- # There can only be one failover configuration, if none is present
- # we add the first one
- if not config.exists(base + ['failover']):
- local = config.return_value(base_subnet + ['failover', 'local-address'])
- remote = config.return_value(base_subnet + ['failover', 'peer-address'])
- status = config.return_value(base_subnet + ['failover', 'status'])
- name = config.return_value(base_subnet + ['failover', 'name'])
-
- config.set(base + ['failover', 'remote'], value=remote)
- config.set(base + ['failover', 'source-address'], value=local)
- config.set(base + ['failover', 'status'], value=status)
- config.set(base + ['failover', 'name'], value=name)
-
- config.delete(base_subnet + ['failover'])
- config.set(base_subnet + ['enable-failover'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['shared-network-name']):
+ # Nothing to do
+ return
+
+ # Run this for every instance if 'shared-network-name'
+ for network in config.list_nodes(base + ['shared-network-name']):
+ base_network = base + ['shared-network-name', network]
+
+ if not config.exists(base_network + ['subnet']):
+ continue
+
+ # Run this for every specified 'subnet'
+ for subnet in config.list_nodes(base_network + ['subnet']):
+ base_subnet = base_network + ['subnet', subnet]
+
+ # T1968: allow multiple static-routes to be configured
+ if config.exists(base_subnet + ['static-route']):
+ prefix = config.return_value(base_subnet + ['static-route', 'destination-subnet'])
+ router = config.return_value(base_subnet + ['static-route', 'router'])
+ config.delete(base_subnet + ['static-route'])
+
+ config.set(base_subnet + ['static-route', prefix, 'next-hop'], value=router)
+ config.set_tag(base_subnet + ['static-route'])
+
+ # T3838: rename dns-server -> name-server
+ if config.exists(base_subnet + ['dns-server']):
+ config.rename(base_subnet + ['dns-server'], 'name-server')
+
+
+ # T3672: ISC DHCP server only supports one failover peer
+ if config.exists(base_subnet + ['failover']):
+ # There can only be one failover configuration, if none is present
+ # we add the first one
+ if not config.exists(base + ['failover']):
+ local = config.return_value(base_subnet + ['failover', 'local-address'])
+ remote = config.return_value(base_subnet + ['failover', 'peer-address'])
+ status = config.return_value(base_subnet + ['failover', 'status'])
+ name = config.return_value(base_subnet + ['failover', 'name'])
+
+ config.set(base + ['failover', 'remote'], value=remote)
+ config.set(base + ['failover', 'source-address'], value=local)
+ config.set(base + ['failover', 'status'], value=status)
+ config.set(base + ['failover', 'name'], value=name)
+
+ config.delete(base_subnet + ['failover'])
+ config.set(base_subnet + ['enable-failover'])
diff --git a/src/migration-scripts/dhcp-server/6-to-7 b/src/migration-scripts/dhcp-server/6-to-7
index e6c298a60..4e6583a31 100755..100644
--- a/src/migration-scripts/dhcp-server/6-to-7
+++ b/src/migration-scripts/dhcp-server/6-to-7
@@ -1,76 +1,58 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6079: Disable duplicate static mappings
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base + ['shared-network-name']):
- # Nothing to do
- exit(0)
-# Run this for every instance if 'shared-network-name'
-for network in config.list_nodes(base + ['shared-network-name']):
- base_network = base + ['shared-network-name', network]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['shared-network-name']):
+ # Nothing to do
+ return
- if not config.exists(base_network + ['subnet']):
- continue
+ # Run this for every instance if 'shared-network-name'
+ for network in config.list_nodes(base + ['shared-network-name']):
+ base_network = base + ['shared-network-name', network]
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
+ if not config.exists(base_network + ['subnet']):
+ continue
- if config.exists(base_subnet + ['static-mapping']):
- used_mac = []
- used_ip = []
+ for subnet in config.list_nodes(base_network + ['subnet']):
+ base_subnet = base_network + ['subnet', subnet]
- for mapping in config.list_nodes(base_subnet + ['static-mapping']):
- base_mapping = base_subnet + ['static-mapping', mapping]
+ if config.exists(base_subnet + ['static-mapping']):
+ used_mac = []
+ used_ip = []
- if config.exists(base_mapping + ['mac-address']):
- mac = config.return_value(base_mapping + ['mac-address'])
+ for mapping in config.list_nodes(base_subnet + ['static-mapping']):
+ base_mapping = base_subnet + ['static-mapping', mapping]
- if mac in used_mac:
- config.set(base_mapping + ['disable'])
- else:
- used_mac.append(mac)
+ if config.exists(base_mapping + ['mac-address']):
+ mac = config.return_value(base_mapping + ['mac-address'])
- if config.exists(base_mapping + ['ip-address']):
- ip = config.return_value(base_mapping + ['ip-address'])
+ if mac in used_mac:
+ config.set(base_mapping + ['disable'])
+ else:
+ used_mac.append(mac)
- if ip in used_ip:
- config.set(base_subnet + ['static-mapping', mapping, 'disable'])
- else:
- used_ip.append(ip)
+ if config.exists(base_mapping + ['ip-address']):
+ ip = config.return_value(base_mapping + ['ip-address'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if ip in used_ip:
+ config.set(base_subnet + ['static-mapping', mapping, 'disable'])
+ else:
+ used_ip.append(ip)
diff --git a/src/migration-scripts/dhcp-server/7-to-8 b/src/migration-scripts/dhcp-server/7-to-8
index ccf385a30..7fcb62e86 100755..100644
--- a/src/migration-scripts/dhcp-server/7-to-8
+++ b/src/migration-scripts/dhcp-server/7-to-8
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316: Migrate to Kea
# - global-parameters will not function
@@ -23,65 +22,48 @@
# - ping-check no longer supported
# - failover is default enabled on all subnets that exist on failover servers
-import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-if config.exists(base + ['host-decl-name']):
- config.delete(base + ['host-decl-name'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-if config.exists(base + ['global-parameters']):
- config.delete(base + ['global-parameters'])
+ if config.exists(base + ['host-decl-name']):
+ config.delete(base + ['host-decl-name'])
-if config.exists(base + ['shared-network-name']):
- for network in config.list_nodes(base + ['shared-network-name']):
- base_network = base + ['shared-network-name', network]
+ if config.exists(base + ['global-parameters']):
+ config.delete(base + ['global-parameters'])
- if config.exists(base_network + ['ping-check']):
- config.delete(base_network + ['ping-check'])
+ if config.exists(base + ['shared-network-name']):
+ for network in config.list_nodes(base + ['shared-network-name']):
+ base_network = base + ['shared-network-name', network]
- if config.exists(base_network + ['shared-network-parameters']):
- config.delete(base_network +['shared-network-parameters'])
+ if config.exists(base_network + ['ping-check']):
+ config.delete(base_network + ['ping-check'])
- if not config.exists(base_network + ['subnet']):
- continue
+ if config.exists(base_network + ['shared-network-parameters']):
+ config.delete(base_network +['shared-network-parameters'])
- # Run this for every specified 'subnet'
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
+ if not config.exists(base_network + ['subnet']):
+ continue
- if config.exists(base_subnet + ['enable-failover']):
- config.delete(base_subnet + ['enable-failover'])
+ # Run this for every specified 'subnet'
+ for subnet in config.list_nodes(base_network + ['subnet']):
+ base_subnet = base_network + ['subnet', subnet]
- if config.exists(base_subnet + ['ping-check']):
- config.delete(base_subnet + ['ping-check'])
+ if config.exists(base_subnet + ['enable-failover']):
+ config.delete(base_subnet + ['enable-failover'])
- if config.exists(base_subnet + ['subnet-parameters']):
- config.delete(base_subnet + ['subnet-parameters'])
+ if config.exists(base_subnet + ['ping-check']):
+ config.delete(base_subnet + ['ping-check'])
- if config.exists(base_subnet + ['static-mapping']):
- for mapping in config.list_nodes(base_subnet + ['static-mapping']):
- if config.exists(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters']):
- config.delete(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters'])
+ if config.exists(base_subnet + ['subnet-parameters']):
+ config.delete(base_subnet + ['subnet-parameters'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(base_subnet + ['static-mapping']):
+ for mapping in config.list_nodes(base_subnet + ['static-mapping']):
+ if config.exists(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters']):
+ config.delete(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters'])
diff --git a/src/migration-scripts/dhcp-server/8-to-9 b/src/migration-scripts/dhcp-server/8-to-9
index 151aa6d7b..5843e9fda 100755..100644
--- a/src/migration-scripts/dhcp-server/8-to-9
+++ b/src/migration-scripts/dhcp-server/8-to-9
@@ -1,65 +1,47 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316:
# - Adjust hostname to have valid FQDN characters only (underscores aren't allowed anymore)
# - Rename "service dhcp-server shared-network-name ... static-mapping <hostname> mac-address ..."
# to "service dhcp-server shared-network-name ... static-mapping <hostname> mac ..."
-import sys
import re
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
-for network in config.list_nodes(base):
- # Run this for every specified 'subnet'
- if config.exists(base + [network, 'subnet']):
- for subnet in config.list_nodes(base + [network, 'subnet']):
- base_subnet = base + [network, 'subnet', subnet]
- if config.exists(base_subnet + ['static-mapping']):
- for hostname in config.list_nodes(base_subnet + ['static-mapping']):
- base_mapping = base_subnet + ['static-mapping', hostname]
-
- # Rename the 'mac-address' node to 'mac'
- if config.exists(base_mapping + ['mac-address']):
- config.rename(base_mapping + ['mac-address'], 'mac')
-
- # Adjust hostname to have valid FQDN characters only
- new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname)
- if new_hostname != hostname:
- config.rename(base_mapping, new_hostname)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for network in config.list_nodes(base):
+ # Run this for every specified 'subnet'
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
+ if config.exists(base_subnet + ['static-mapping']):
+ for hostname in config.list_nodes(base_subnet + ['static-mapping']):
+ base_mapping = base_subnet + ['static-mapping', hostname]
+
+ # Rename the 'mac-address' node to 'mac'
+ if config.exists(base_mapping + ['mac-address']):
+ config.rename(base_mapping + ['mac-address'], 'mac')
+
+ # Adjust hostname to have valid FQDN characters only
+ new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname)
+ if new_hostname != hostname:
+ config.rename(base_mapping, new_hostname)
diff --git a/src/migration-scripts/dhcp-server/9-to-10 b/src/migration-scripts/dhcp-server/9-to-10
index a459b65b5..eda97550d 100755..100644
--- a/src/migration-scripts/dhcp-server/9-to-10
+++ b/src/migration-scripts/dhcp-server/9-to-10
@@ -1,41 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316:
# - Migrate dhcp options under new option node
# - Add subnet IDs to existing subnets
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
option_nodes = ['bootfile-name', 'bootfile-server', 'bootfile-size', 'captive-portal',
'client-prefix-length', 'default-router', 'domain-name', 'domain-search',
@@ -44,31 +28,30 @@ option_nodes = ['bootfile-name', 'bootfile-server', 'bootfile-size', 'captive-po
'tftp-server-name', 'time-offset', 'time-server', 'time-zone',
'vendor-option', 'wins-server', 'wpad-url']
-subnet_id = 1
-for network in config.list_nodes(base):
- for option in option_nodes:
- if config.exists(base + [network, option]):
- config.set(base + [network, 'option'])
- config.copy(base + [network, option], base + [network, 'option', option])
- config.delete(base + [network, option])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ subnet_id = 1
- if config.exists(base + [network, 'subnet']):
- for subnet in config.list_nodes(base + [network, 'subnet']):
- base_subnet = base + [network, 'subnet', subnet]
+ for network in config.list_nodes(base):
+ for option in option_nodes:
+ if config.exists(base + [network, option]):
+ config.set(base + [network, 'option'])
+ config.copy(base + [network, option], base + [network, 'option', option])
+ config.delete(base + [network, option])
- for option in option_nodes:
- if config.exists(base_subnet + [option]):
- config.set(base_subnet + ['option'])
- config.copy(base_subnet + [option], base_subnet + ['option', option])
- config.delete(base_subnet + [option])
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
- config.set(base_subnet + ['subnet-id'], value=subnet_id)
- subnet_id += 1
+ for option in option_nodes:
+ if config.exists(base_subnet + [option]):
+ config.set(base_subnet + ['option'])
+ config.copy(base_subnet + [option], base_subnet + ['option', option])
+ config.delete(base_subnet + [option])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.set(base_subnet + ['subnet-id'], value=subnet_id)
+ subnet_id += 1
diff --git a/src/migration-scripts/dhcpv6-server/0-to-1 b/src/migration-scripts/dhcpv6-server/0-to-1
index deae1ca29..fd9b2d739 100755..100644
--- a/src/migration-scripts/dhcpv6-server/0-to-1
+++ b/src/migration-scripts/dhcpv6-server/0-to-1
@@ -1,39 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# combine both sip-server-address and sip-server-name nodes to common sip-server
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['service', 'dhcpv6-server', 'shared-network-name']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['service', 'dhcpv6-server', 'shared-network-name']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
# we need to run this for every configured network
for network in config.list_nodes(base):
for subnet in config.list_nodes(base + [network, 'subnet']):
@@ -52,10 +42,3 @@ else:
# Write new CLI value for sip-server
for server in sip_server:
config.set(base + [network, 'subnet', subnet, 'sip-server'], value=server, replace=False)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/dhcpv6-server/1-to-2 b/src/migration-scripts/dhcpv6-server/1-to-2
index cc5a8900a..ad307495c 100755..100644
--- a/src/migration-scripts/dhcpv6-server/1-to-2
+++ b/src/migration-scripts/dhcpv6-server/1-to-2
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316: Migrate to Kea
# - Kea was meant to have support for key "prefix-highest" under PD which would allow an address range
@@ -20,67 +19,50 @@
# Ref: https://lists.isc.org/pipermail/kea-users/2022-November/003686.html
# - Remove prefix temporary value, convert to multi leafNode (https://kea.readthedocs.io/en/kea-2.2.0/arm/dhcp6-srv.html#dhcpv6-server-limitations)
-import sys
from vyos.configtree import ConfigTree
from vyos.utils.network import ipv6_prefix_length
-if (len(sys.argv) < 1):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcpv6-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-for network in config.list_nodes(base):
- if not config.exists(base + [network, 'subnet']):
- continue
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- for subnet in config.list_nodes(base + [network, 'subnet']):
- # Delete temporary value under address-range prefix, convert tagNode to leafNode multi
- if config.exists(base + [network, 'subnet', subnet, 'address-range', 'prefix']):
- prefix_base = base + [network, 'subnet', subnet, 'address-range', 'prefix']
- prefixes = config.list_nodes(prefix_base)
-
- config.delete(prefix_base)
+ for network in config.list_nodes(base):
+ if not config.exists(base + [network, 'subnet']):
+ continue
- for prefix in prefixes:
- config.set(prefix_base, value=prefix, replace=False)
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ # Delete temporary value under address-range prefix, convert tagNode to leafNode multi
+ if config.exists(base + [network, 'subnet', subnet, 'address-range', 'prefix']):
+ prefix_base = base + [network, 'subnet', subnet, 'address-range', 'prefix']
+ prefixes = config.list_nodes(prefix_base)
+
+ config.delete(prefix_base)
- if config.exists(base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']):
- prefix_base = base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']
+ for prefix in prefixes:
+ config.set(prefix_base, value=prefix, replace=False)
- config.set(prefix_base)
- config.set_tag(prefix_base)
+ if config.exists(base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']):
+ prefix_base = base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']
- for start in config.list_nodes(base + [network, 'subnet', subnet, 'prefix-delegation', 'start']):
- path = base + [network, 'subnet', subnet, 'prefix-delegation', 'start', start]
+ config.set(prefix_base)
+ config.set_tag(prefix_base)
- delegated_length = config.return_value(path + ['prefix-length'])
- stop = config.return_value(path + ['stop'])
+ for start in config.list_nodes(base + [network, 'subnet', subnet, 'prefix-delegation', 'start']):
+ path = base + [network, 'subnet', subnet, 'prefix-delegation', 'start', start]
- prefix_length = ipv6_prefix_length(start, stop)
+ delegated_length = config.return_value(path + ['prefix-length'])
+ stop = config.return_value(path + ['stop'])
- # This range could not be converted into a simple prefix length and must be skipped
- if not prefix_length:
- continue
+ prefix_length = ipv6_prefix_length(start, stop)
- config.set(prefix_base + [start, 'delegated-length'], value=delegated_length)
- config.set(prefix_base + [start, 'prefix-length'], value=prefix_length)
+ # This range could not be converted into a simple prefix length and must be skipped
+ if not prefix_length:
+ continue
- config.delete(base + [network, 'subnet', subnet, 'prefix-delegation', 'start'])
+ config.set(prefix_base + [start, 'delegated-length'], value=delegated_length)
+ config.set(prefix_base + [start, 'prefix-length'], value=prefix_length)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.delete(base + [network, 'subnet', subnet, 'prefix-delegation', 'start'])
diff --git a/src/migration-scripts/dhcpv6-server/2-to-3 b/src/migration-scripts/dhcpv6-server/2-to-3
index f4bdc1d1e..b44798d18 100755..100644
--- a/src/migration-scripts/dhcpv6-server/2-to-3
+++ b/src/migration-scripts/dhcpv6-server/2-to-3
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316:
# - Adjust hostname to have valid FQDN characters only (underscores aren't allowed anymore)
@@ -22,57 +21,40 @@
# - Rename "service dhcpv6-server shared-network-name ... static-mapping <hostname> mac-address ..."
# to "service dhcpv6-server shared-network-name ... static-mapping <hostname> mac ..."
-import sys
import re
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcpv6-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
-for network in config.list_nodes(base):
- # Run this for every specified 'subnet'
- if config.exists(base + [network, 'subnet']):
- for subnet in config.list_nodes(base + [network, 'subnet']):
- base_subnet = base + [network, 'subnet', subnet]
- if config.exists(base_subnet + ['static-mapping']):
- for hostname in config.list_nodes(base_subnet + ['static-mapping']):
- base_mapping = base_subnet + ['static-mapping', hostname]
- if config.exists(base_mapping + ['identifier']):
-
- # Adjust duid to comply with duid format (a:3:b:04:... => 0a:03:0b:04:...)
- duid = config.return_value(base_mapping + ['identifier'])
- new_duid = ':'.join(x.rjust(2,'0') for x in duid.split(':'))
- if new_duid != duid:
- config.set(base_mapping + ['identifier'], new_duid)
-
- # Rename the 'identifier' node to 'duid'
- config.rename(base_mapping + ['identifier'], 'duid')
-
- # Rename the 'mac-address' node to 'mac'
- if config.exists(base_mapping + ['mac-address']):
- config.rename(base_mapping + ['mac-address'], 'mac')
-
- # Adjust hostname to have valid FQDN characters only
- new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname)
- if new_hostname != hostname:
- config.rename(base_mapping, new_hostname)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for network in config.list_nodes(base):
+ # Run this for every specified 'subnet'
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
+ if config.exists(base_subnet + ['static-mapping']):
+ for hostname in config.list_nodes(base_subnet + ['static-mapping']):
+ base_mapping = base_subnet + ['static-mapping', hostname]
+ if config.exists(base_mapping + ['identifier']):
+
+ # Adjust duid to comply with duid format (a:3:b:04:... => 0a:03:0b:04:...)
+ duid = config.return_value(base_mapping + ['identifier'])
+ new_duid = ':'.join(x.rjust(2,'0') for x in duid.split(':'))
+ if new_duid != duid:
+ config.set(base_mapping + ['identifier'], new_duid)
+
+ # Rename the 'identifier' node to 'duid'
+ config.rename(base_mapping + ['identifier'], 'duid')
+
+ # Rename the 'mac-address' node to 'mac'
+ if config.exists(base_mapping + ['mac-address']):
+ config.rename(base_mapping + ['mac-address'], 'mac')
+
+ # Adjust hostname to have valid FQDN characters only
+ new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname)
+ if new_hostname != hostname:
+ config.rename(base_mapping, new_hostname)
diff --git a/src/migration-scripts/dhcpv6-server/3-to-4 b/src/migration-scripts/dhcpv6-server/3-to-4
index 7efc492a5..e38e36505 100755..100644
--- a/src/migration-scripts/dhcpv6-server/3-to-4
+++ b/src/migration-scripts/dhcpv6-server/3-to-4
@@ -1,89 +1,72 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316:
# - Add subnet IDs to existing subnets
# - Move options to option node
# - Migrate address-range to range tagNode
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcpv6-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
option_nodes = ['captive-portal', 'domain-search', 'name-server',
'nis-domain', 'nis-server', 'nisplus-domain', 'nisplus-server',
'sip-server', 'sntp-server', 'vendor-option']
-subnet_id = 1
-for network in config.list_nodes(base):
- if config.exists(base + [network, 'subnet']):
- for subnet in config.list_nodes(base + [network, 'subnet']):
- base_subnet = base + [network, 'subnet', subnet]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ subnet_id = 1
- if config.exists(base_subnet + ['address-range']):
- config.set(base_subnet + ['range'])
- config.set_tag(base_subnet + ['range'])
+ for network in config.list_nodes(base):
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
- range_id = 1
+ if config.exists(base_subnet + ['address-range']):
+ config.set(base_subnet + ['range'])
+ config.set_tag(base_subnet + ['range'])
- if config.exists(base_subnet + ['address-range', 'prefix']):
- for prefix in config.return_values(base_subnet + ['address-range', 'prefix']):
- config.set(base_subnet + ['range', range_id, 'prefix'], value=prefix)
+ range_id = 1
- range_id += 1
+ if config.exists(base_subnet + ['address-range', 'prefix']):
+ for prefix in config.return_values(base_subnet + ['address-range', 'prefix']):
+ config.set(base_subnet + ['range', range_id, 'prefix'], value=prefix)
- if config.exists(base_subnet + ['address-range', 'start']):
- for start in config.list_nodes(base_subnet + ['address-range', 'start']):
- stop = config.return_value(base_subnet + ['address-range', 'start', start, 'stop'])
+ range_id += 1
- config.set(base_subnet + ['range', range_id, 'start'], value=start)
- config.set(base_subnet + ['range', range_id, 'stop'], value=stop)
+ if config.exists(base_subnet + ['address-range', 'start']):
+ for start in config.list_nodes(base_subnet + ['address-range', 'start']):
+ stop = config.return_value(base_subnet + ['address-range', 'start', start, 'stop'])
- range_id += 1
+ config.set(base_subnet + ['range', range_id, 'start'], value=start)
+ config.set(base_subnet + ['range', range_id, 'stop'], value=stop)
- config.delete(base_subnet + ['address-range'])
+ range_id += 1
- for option in option_nodes:
- if config.exists(base_subnet + [option]):
- config.set(base_subnet + ['option'])
- config.copy(base_subnet + [option], base_subnet + ['option', option])
- config.delete(base_subnet + [option])
+ config.delete(base_subnet + ['address-range'])
- config.set(base_subnet + ['subnet-id'], value=subnet_id)
- subnet_id += 1
+ for option in option_nodes:
+ if config.exists(base_subnet + [option]):
+ config.set(base_subnet + ['option'])
+ config.copy(base_subnet + [option], base_subnet + ['option', option])
+ config.delete(base_subnet + [option])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.set(base_subnet + ['subnet-id'], value=subnet_id)
+ subnet_id += 1
diff --git a/src/migration-scripts/dhcpv6-server/4-to-5 b/src/migration-scripts/dhcpv6-server/4-to-5
index 55fda91b3..ad18e1a84 100755..100644
--- a/src/migration-scripts/dhcpv6-server/4-to-5
+++ b/src/migration-scripts/dhcpv6-server/4-to-5
@@ -1,91 +1,73 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5993: Check if subnet is locally accessible and assign interface to subnet
-import sys
from ipaddress import ip_network
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcpv6-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-def find_subnet_interface(subnet):
- subnet_net = ip_network(subnet)
-
- def check_addr(if_path):
- if config.exists(if_path + ['address']):
- for addr in config.return_values(if_path + ['address']):
- try:
- if ip_network(addr, strict=False) == subnet_net:
- return True
- except:
- pass # interface address was probably "dhcp" or other magic string
- return None
-
- for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- if_base = ['interfaces', iftype, ifname]
-
- if check_addr(if_base):
- return ifname
-
- if config.exists(if_base + ['vif']):
- for vif in config.list_nodes(if_base + ['vif']):
- if check_addr(if_base + ['vif', vif]):
- return f'{ifname}.{vif}'
-
- if config.exists(if_base + ['vif-s']):
- for vifs in config.list_nodes(if_base + ['vif-s']):
- if check_addr(if_base + ['vif-s', vifs]):
- return f'{ifname}.{vifs}'
-
- if config.exists(if_base + ['vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(if_base + ['vif-s', vifs, 'vif-c']):
- if check_addr(if_base + ['vif-s', vifs, 'vif-c', vifc]):
- return f'{ifname}.{vifs}.{vifc}'
-
- return False
-
-for network in config.list_nodes(base):
- if not config.exists(base + [network, 'subnet']):
- continue
-
- for subnet in config.list_nodes(base + [network, 'subnet']):
- subnet_interface = find_subnet_interface(subnet)
-
- if subnet_interface:
- config.set(base + [network, 'subnet', subnet, 'interface'], value=subnet_interface)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ def find_subnet_interface(subnet):
+ subnet_net = ip_network(subnet)
+
+ def check_addr(if_path):
+ if config.exists(if_path + ['address']):
+ for addr in config.return_values(if_path + ['address']):
+ try:
+ if ip_network(addr, strict=False) == subnet_net:
+ return True
+ except:
+ pass # interface address was probably "dhcp" or other magic string
+ return None
+
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ if_base = ['interfaces', iftype, ifname]
+
+ if check_addr(if_base):
+ return ifname
+
+ if config.exists(if_base + ['vif']):
+ for vif in config.list_nodes(if_base + ['vif']):
+ if check_addr(if_base + ['vif', vif]):
+ return f'{ifname}.{vif}'
+
+ if config.exists(if_base + ['vif-s']):
+ for vifs in config.list_nodes(if_base + ['vif-s']):
+ if check_addr(if_base + ['vif-s', vifs]):
+ return f'{ifname}.{vifs}'
+
+ if config.exists(if_base + ['vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(if_base + ['vif-s', vifs, 'vif-c']):
+ if check_addr(if_base + ['vif-s', vifs, 'vif-c', vifc]):
+ return f'{ifname}.{vifs}.{vifc}'
+
+ return False
+
+ for network in config.list_nodes(base):
+ if not config.exists(base + [network, 'subnet']):
+ continue
+
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ subnet_interface = find_subnet_interface(subnet)
+
+ if subnet_interface:
+ config.set(base + [network, 'subnet', subnet, 'interface'], value=subnet_interface)
diff --git a/src/migration-scripts/dns-dynamic/0-to-1 b/src/migration-scripts/dns-dynamic/0-to-1
index b7674a9c8..6a91b36af 100755..100644
--- a/src/migration-scripts/dns-dynamic/0-to-1
+++ b/src/migration-scripts/dns-dynamic/0-to-1
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5144:
# - migrate "service dns dynamic interface ..."
@@ -27,7 +26,6 @@
# - apply service protocol mapping upfront, they are not 'auto-detected' anymore
# - migrate web-options url to stricter format
-import sys
import re
from vyos.configtree import ConfigTree
@@ -45,84 +43,67 @@ service_protocol_mapping = {
'zoneedit': 'zoneedit1'
}
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
old_base_path = ['service', 'dns', 'dynamic', 'interface']
new_base_path = ['service', 'dns', 'dynamic', 'address']
-if not config.exists(old_base_path):
- # Nothing to do
- sys.exit(0)
-
-# Migrate "service dns dynamic interface"
-# to "service dns dynamic address"
-config.rename(old_base_path, new_base_path[-1])
-
-for address in config.list_nodes(new_base_path):
- # Migrate "service dns dynamic interface <interface> rfc2136 <config> record"
- # to "service dns dynamic address <address> rfc2136 <config> host-name"
- if config.exists(new_base_path + [address, 'rfc2136']):
- for rfc_cfg in config.list_nodes(new_base_path + [address, 'rfc2136']):
- if config.exists(new_base_path + [address, 'rfc2136', rfc_cfg, 'record']):
- config.rename(new_base_path + [address, 'rfc2136', rfc_cfg, 'record'], 'host-name')
-
- # Migrate "service dns dynamic interface <interface> service <config> login"
- # to "service dns dynamic address <address> service <config> username"
- if config.exists(new_base_path + [address, 'service']):
- for svc_cfg in config.list_nodes(new_base_path + [address, 'service']):
- if config.exists(new_base_path + [address, 'service', svc_cfg, 'login']):
- config.rename(new_base_path + [address, 'service', svc_cfg, 'login'], 'username')
- # Apply global 'ipv6-enable' to per <config> 'ip-version: ipv6'
- if config.exists(new_base_path + [address, 'ipv6-enable']):
- config.set(new_base_path + [address, 'service', svc_cfg, 'ip-version'], 'ipv6')
- config.delete(new_base_path + [address, 'ipv6-enable'])
- # Apply service protocol mapping upfront, they are not 'auto-detected' anymore
- if svc_cfg in service_protocol_mapping:
- config.set(new_base_path + [address, 'service', svc_cfg, 'protocol'],
- service_protocol_mapping.get(svc_cfg))
-
- # If use-web is set, then:
- # Move "service dns dynamic address <address> <service|rfc2136> <service> ..."
- # to "service dns dynamic address web <service|rfc2136> <service>-<address> ..."
- # Move "service dns dynamic address web use-web ..."
- # to "service dns dynamic address web web-options ..."
- # Note: The config is named <service>-<address> to avoid name conflict with old entries
- if config.exists(new_base_path + [address, 'use-web']):
- for svc_type in ['rfc2136', 'service']:
- if config.exists(new_base_path + [address, svc_type]):
- config.set(new_base_path + ['web', svc_type])
- config.set_tag(new_base_path + ['web', svc_type])
- for svc_cfg in config.list_nodes(new_base_path + [address, svc_type]):
- config.copy(new_base_path + [address, svc_type, svc_cfg],
- new_base_path + ['web', svc_type, f'{svc_cfg}-{address}'])
-
- # Multiple web-options were not supported, so copy only the first one
- # Also, migrate web-options url to stricter format and transition
- # checkip.dyndns.org to https://domains.google.com/checkip for better
- # TLS support (see: https://github.com/ddclient/ddclient/issues/597)
- if not config.exists(new_base_path + ['web', 'web-options']):
- config.copy(new_base_path + [address, 'use-web'], new_base_path + ['web', 'web-options'])
- if config.exists(new_base_path + ['web', 'web-options', 'url']):
- url = config.return_value(new_base_path + ['web', 'web-options', 'url'])
- if re.search("^(https?://)?checkip\.dyndns\.org", url):
- config.set(new_base_path + ['web', 'web-options', 'url'], 'https://domains.google.com/checkip')
- if not url.startswith(('http://', 'https://')):
- config.set(new_base_path + ['web', 'web-options', 'url'], f'https://{url}')
-
- config.delete(new_base_path + [address])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base_path):
+ # Nothing to do
+ return
+
+ # Migrate "service dns dynamic interface"
+ # to "service dns dynamic address"
+ config.rename(old_base_path, new_base_path[-1])
+
+ for address in config.list_nodes(new_base_path):
+ # Migrate "service dns dynamic interface <interface> rfc2136 <config> record"
+ # to "service dns dynamic address <address> rfc2136 <config> host-name"
+ if config.exists(new_base_path + [address, 'rfc2136']):
+ for rfc_cfg in config.list_nodes(new_base_path + [address, 'rfc2136']):
+ if config.exists(new_base_path + [address, 'rfc2136', rfc_cfg, 'record']):
+ config.rename(new_base_path + [address, 'rfc2136', rfc_cfg, 'record'], 'host-name')
+
+ # Migrate "service dns dynamic interface <interface> service <config> login"
+ # to "service dns dynamic address <address> service <config> username"
+ if config.exists(new_base_path + [address, 'service']):
+ for svc_cfg in config.list_nodes(new_base_path + [address, 'service']):
+ if config.exists(new_base_path + [address, 'service', svc_cfg, 'login']):
+ config.rename(new_base_path + [address, 'service', svc_cfg, 'login'], 'username')
+ # Apply global 'ipv6-enable' to per <config> 'ip-version: ipv6'
+ if config.exists(new_base_path + [address, 'ipv6-enable']):
+ config.set(new_base_path + [address, 'service', svc_cfg, 'ip-version'], 'ipv6')
+ config.delete(new_base_path + [address, 'ipv6-enable'])
+ # Apply service protocol mapping upfront, they are not 'auto-detected' anymore
+ if svc_cfg in service_protocol_mapping:
+ config.set(new_base_path + [address, 'service', svc_cfg, 'protocol'],
+ service_protocol_mapping.get(svc_cfg))
+
+ # If use-web is set, then:
+ # Move "service dns dynamic address <address> <service|rfc2136> <service> ..."
+ # to "service dns dynamic address web <service|rfc2136> <service>-<address> ..."
+ # Move "service dns dynamic address web use-web ..."
+ # to "service dns dynamic address web web-options ..."
+ # Note: The config is named <service>-<address> to avoid name conflict with old entries
+ if config.exists(new_base_path + [address, 'use-web']):
+ for svc_type in ['rfc2136', 'service']:
+ if config.exists(new_base_path + [address, svc_type]):
+ config.set(new_base_path + ['web', svc_type])
+ config.set_tag(new_base_path + ['web', svc_type])
+ for svc_cfg in config.list_nodes(new_base_path + [address, svc_type]):
+ config.copy(new_base_path + [address, svc_type, svc_cfg],
+ new_base_path + ['web', svc_type, f'{svc_cfg}-{address}'])
+
+ # Multiple web-options were not supported, so copy only the first one
+ # Also, migrate web-options url to stricter format and transition
+ # checkip.dyndns.org to https://domains.google.com/checkip for better
+ # TLS support (see: https://github.com/ddclient/ddclient/issues/597)
+ if not config.exists(new_base_path + ['web', 'web-options']):
+ config.copy(new_base_path + [address, 'use-web'], new_base_path + ['web', 'web-options'])
+ if config.exists(new_base_path + ['web', 'web-options', 'url']):
+ url = config.return_value(new_base_path + ['web', 'web-options', 'url'])
+ if re.search("^(https?://)?checkip\.dyndns\.org", url):
+ config.set(new_base_path + ['web', 'web-options', 'url'], 'https://domains.google.com/checkip')
+ if not url.startswith(('http://', 'https://')):
+ config.set(new_base_path + ['web', 'web-options', 'url'], f'https://{url}')
+
+ config.delete(new_base_path + [address])
diff --git a/src/migration-scripts/dns-dynamic/1-to-2 b/src/migration-scripts/dns-dynamic/1-to-2
index 8b599b57a..5dca9e32f 100755..100644
--- a/src/migration-scripts/dns-dynamic/1-to-2
+++ b/src/migration-scripts/dns-dynamic/1-to-2
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5708:
# - migrate "service dns dynamic timeout ..."
@@ -21,50 +20,32 @@
# - migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
# to "service dns dynamic address <interface> service <service> protocol dnsexit2"
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['service', 'dns', 'dynamic']
timeout_path = base_path + ['timeout']
address_path = base_path + ['address']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-
-# Migrate "service dns dynamic timeout ..."
-# to "service dns dynamic interval ..."
-if config.exists(timeout_path):
- config.rename(timeout_path, 'interval')
-
-# Remove "service dns dynamic address <interface> web-options ..." when <interface> != "web"
-for address in config.list_nodes(address_path):
- if config.exists(address_path + [address, 'web-options']) and address != 'web':
- config.delete(address_path + [address, 'web-options'])
-
-# Migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
-# to "service dns dynamic address <interface> service <service> protocol dnsexit2"
-for address in config.list_nodes(address_path):
- for svc_cfg in config.list_nodes(address_path + [address, 'service']):
- if config.exists(address_path + [address, 'service', svc_cfg, 'protocol']):
- protocol = config.return_value(address_path + [address, 'service', svc_cfg, 'protocol'])
- if protocol == 'dnsexit':
- config.set(address_path + [address, 'service', svc_cfg, 'protocol'], 'dnsexit2')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
+
+ # Migrate "service dns dynamic timeout ..."
+ # to "service dns dynamic interval ..."
+ if config.exists(timeout_path):
+ config.rename(timeout_path, 'interval')
+
+ # Remove "service dns dynamic address <interface> web-options ..." when <interface> != "web"
+ for address in config.list_nodes(address_path):
+ if config.exists(address_path + [address, 'web-options']) and address != 'web':
+ config.delete(address_path + [address, 'web-options'])
+
+ # Migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
+ # to "service dns dynamic address <interface> service <service> protocol dnsexit2"
+ for address in config.list_nodes(address_path):
+ for svc_cfg in config.list_nodes(address_path + [address, 'service']):
+ if config.exists(address_path + [address, 'service', svc_cfg, 'protocol']):
+ protocol = config.return_value(address_path + [address, 'service', svc_cfg, 'protocol'])
+ if protocol == 'dnsexit':
+ config.set(address_path + [address, 'service', svc_cfg, 'protocol'], 'dnsexit2')
diff --git a/src/migration-scripts/dns-dynamic/2-to-3 b/src/migration-scripts/dns-dynamic/2-to-3
index 4e0aa37d5..9aafc41a4 100755..100644
--- a/src/migration-scripts/dns-dynamic/2-to-3
+++ b/src/migration-scripts/dns-dynamic/2-to-3
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5791:
# - migrate "service dns dynamic address web web-options ..."
@@ -23,7 +22,6 @@
# to "service dns dynamic name <service> address <interface> ..."
# - normalize the all service names to conform with name constraints
-import sys
import re
from unicodedata import normalize
from vyos.configtree import ConfigTree
@@ -41,79 +39,61 @@ def normalize_name(name):
return name
-
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['service', 'dns', 'dynamic']
address_path = base_path + ['address']
name_path = base_path + ['name']
-if not config.exists(address_path):
- # Nothing to do
- sys.exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(address_path):
+ # Nothing to do
+ return
-# config.copy does not recursively create a path, so initialize the name path as tagged node
-if not config.exists(name_path):
- config.set(name_path)
- config.set_tag(name_path)
+ # config.copy does not recursively create a path, so initialize the name path as tagged node
+ if not config.exists(name_path):
+ config.set(name_path)
+ config.set_tag(name_path)
-for address in config.list_nodes(address_path):
+ for address in config.list_nodes(address_path):
- address_path_tag = address_path + [address]
+ address_path_tag = address_path + [address]
+
+ # Move web-option as a configuration in each service instead of top level web-option
+ if config.exists(address_path_tag + ['web-options']) and address == 'web':
+ for svc_type in ['service', 'rfc2136']:
+ if config.exists(address_path_tag + [svc_type]):
+ for svc_cfg in config.list_nodes(address_path_tag + [svc_type]):
+ config.copy(address_path_tag + ['web-options'],
+ address_path_tag + [svc_type, svc_cfg, 'web-options'])
+ config.delete(address_path_tag + ['web-options'])
- # Move web-option as a configuration in each service instead of top level web-option
- if config.exists(address_path_tag + ['web-options']) and address == 'web':
for svc_type in ['service', 'rfc2136']:
if config.exists(address_path_tag + [svc_type]):
+ # Set protocol to 'nsupdate' for RFC2136 configuration
+ if svc_type == 'rfc2136':
+ for rfc_cfg in config.list_nodes(address_path_tag + ['rfc2136']):
+ config.set(address_path_tag + ['rfc2136', rfc_cfg, 'protocol'], 'nsupdate')
+
+ # Add address as config value in each service before moving the service path
+ # And then copy the services from 'address <interface> service <service>'
+ # to 'name (service|rfc2136)-<service>-<address>'
+ # Note: The new service is named (service|rfc2136)-<service>-<address>
+ # to avoid name conflict with old entries
for svc_cfg in config.list_nodes(address_path_tag + [svc_type]):
- config.copy(address_path_tag + ['web-options'],
- address_path_tag + [svc_type, svc_cfg, 'web-options'])
- config.delete(address_path_tag + ['web-options'])
-
- for svc_type in ['service', 'rfc2136']:
- if config.exists(address_path_tag + [svc_type]):
- # Set protocol to 'nsupdate' for RFC2136 configuration
- if svc_type == 'rfc2136':
- for rfc_cfg in config.list_nodes(address_path_tag + ['rfc2136']):
- config.set(address_path_tag + ['rfc2136', rfc_cfg, 'protocol'], 'nsupdate')
-
- # Add address as config value in each service before moving the service path
- # And then copy the services from 'address <interface> service <service>'
- # to 'name (service|rfc2136)-<service>-<address>'
- # Note: The new service is named (service|rfc2136)-<service>-<address>
- # to avoid name conflict with old entries
- for svc_cfg in config.list_nodes(address_path_tag + [svc_type]):
- config.set(address_path_tag + [svc_type, svc_cfg, 'address'], address)
- config.copy(address_path_tag + [svc_type, svc_cfg],
- name_path + ['-'.join([svc_type, svc_cfg, address])])
-
-# Finally cleanup the old address path
-config.delete(address_path)
-
-# Normalize the all service names to conform with name constraints
-index = 1
-for name in config.list_nodes(name_path):
- new_name = normalize_name(name)
- if new_name != name:
- # Append index if there is still a name conflicts after normalization
- # For example, "foo-?(" and "foo-!)" both normalize to "foo-"
- if config.exists(name_path + [new_name]):
- new_name = f'{new_name}-{index}'
- index += 1
- config.rename(name_path + [name], new_name)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.set(address_path_tag + [svc_type, svc_cfg, 'address'], address)
+ config.copy(address_path_tag + [svc_type, svc_cfg],
+ name_path + ['-'.join([svc_type, svc_cfg, address])])
+
+ # Finally cleanup the old address path
+ config.delete(address_path)
+
+ # Normalize the all service names to conform with name constraints
+ index = 1
+ for name in config.list_nodes(name_path):
+ new_name = normalize_name(name)
+ if new_name != name:
+ # Append index if there is still a name conflicts after normalization
+ # For example, "foo-?(" and "foo-!)" both normalize to "foo-"
+ if config.exists(name_path + [new_name]):
+ new_name = f'{new_name}-{index}'
+ index += 1
+ config.rename(name_path + [name], new_name)
diff --git a/src/migration-scripts/dns-dynamic/3-to-4 b/src/migration-scripts/dns-dynamic/3-to-4
index b888a3b6b..c8e1ffeee 100755..100644
--- a/src/migration-scripts/dns-dynamic/3-to-4
+++ b/src/migration-scripts/dns-dynamic/3-to-4
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5966:
# - migrate "service dns dynamic name <service> address <interface>"
@@ -22,55 +21,37 @@
# to "service dns dynamic name <service> address web ..."
# when <interface> == 'web'
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['service', 'dns', 'dynamic', 'name']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-
-for service in config.list_nodes(base_path):
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
- service_path = base_path + [service]
+ for service in config.list_nodes(base_path):
- if config.exists(service_path + ['address']):
- address = config.return_value(service_path + ['address'])
- # 'address' is not a leaf node anymore, delete it first
- config.delete(service_path + ['address'])
+ service_path = base_path + [service]
- # When address is an interface (not 'web'), move it to 'address interface'
- if address != 'web':
- config.set(service_path + ['address', 'interface'], address)
+ if config.exists(service_path + ['address']):
+ address = config.return_value(service_path + ['address'])
+ # 'address' is not a leaf node anymore, delete it first
+ config.delete(service_path + ['address'])
- else: # address == 'web'
- # Relocate optional 'web-options' directly under 'address web'
- if config.exists(service_path + ['web-options']):
- # config.copy does not recursively create a path, so initialize it
- config.set(service_path + ['address'])
- config.copy(service_path + ['web-options'],
- service_path + ['address', 'web'])
- config.delete(service_path + ['web-options'])
+ # When address is an interface (not 'web'), move it to 'address interface'
+ if address != 'web':
+ config.set(service_path + ['address', 'interface'], address)
- # ensure that valueless 'address web' still exists even if there are no 'web-options'
- if not config.exists(service_path + ['address', 'web']):
- config.set(service_path + ['address', 'web'])
+ else: # address == 'web'
+ # Relocate optional 'web-options' directly under 'address web'
+ if config.exists(service_path + ['web-options']):
+ # config.copy does not recursively create a path, so initialize it
+ config.set(service_path + ['address'])
+ config.copy(service_path + ['web-options'],
+ service_path + ['address', 'web'])
+ config.delete(service_path + ['web-options'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ # ensure that valueless 'address web' still exists even if there are no 'web-options'
+ if not config.exists(service_path + ['address', 'web']):
+ config.set(service_path + ['address', 'web'])
diff --git a/src/migration-scripts/dns-forwarding/0-to-1 b/src/migration-scripts/dns-forwarding/0-to-1
index 7f4343652..264ffb40d 100755..100644
--- a/src/migration-scripts/dns-forwarding/0-to-1
+++ b/src/migration-scripts/dns-forwarding/0-to-1
@@ -1,50 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# This migration script will check if there is a allow-from directive configured
# for the dns forwarding service - if not, the node will be created with the old
# default values of 0.0.0.0/0 and ::/0
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+base = ['service', 'dns', 'forwarding']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree)-> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-base = ['service', 'dns', 'forwarding']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
if not config.exists(base + ['allow-from']):
config.set(base + ['allow-from'], value='0.0.0.0/0', replace=False)
config.set(base + ['allow-from'], value='::/0', replace=False)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/dns-forwarding/1-to-2 b/src/migration-scripts/dns-forwarding/1-to-2
index 7df2d47e2..15ed1e136 100755..100644
--- a/src/migration-scripts/dns-forwarding/1-to-2
+++ b/src/migration-scripts/dns-forwarding/1-to-2
@@ -1,19 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# This migration script will remove the deprecated 'listen-on' statement
# from the dns forwarding service and will add the corresponding
@@ -21,66 +19,49 @@
# on interface addresses and not on interface names.
from ipaddress import ip_interface
-from sys import argv, exit
from vyos.ifconfig import Interface
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'dns', 'forwarding']
-if not config.exists(base + ['listen-on']):
- # Nothing to do
- exit(0)
-listen_intf = config.return_values(base + ['listen-on'])
-# Delete node with abandoned command
-config.delete(base + ['listen-on'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['listen-on']):
+ # Nothing to do
+ return
-# retrieve interface addresses for every configured listen-on interface
-listen_addr = []
-for intf in listen_intf:
- # we need to evaluate the interface section before manipulating the 'intf' variable
- section = Interface.section(intf)
- if not section:
- raise ValueError(f'Invalid interface name {intf}')
+ listen_intf = config.return_values(base + ['listen-on'])
+ # Delete node with abandoned command
+ config.delete(base + ['listen-on'])
- # we need to treat vif and vif-s interfaces differently,
- # both "real interfaces" use dots for vlan identifiers - those
- # need to be exchanged with vif and vif-s identifiers
- if intf.count('.') == 1:
- # this is a regular VLAN interface
- intf = intf.split('.')[0] + ' vif ' + intf.split('.')[1]
- elif intf.count('.') == 2:
- # this is a QinQ VLAN interface
- intf = intf.split('.')[0] + ' vif-s ' + intf.split('.')[1] + ' vif-c ' + intf.split('.')[2]
+ # retrieve interface addresses for every configured listen-on interface
+ listen_addr = []
+ for intf in listen_intf:
+ # we need to evaluate the interface section before manipulating the 'intf' variable
+ section = Interface.section(intf)
+ if not section:
+ raise ValueError(f'Invalid interface name {intf}')
- # retrieve corresponding interface addresses in CIDR format
- # those need to be converted in pure IP addresses without network information
- path = ['interfaces', section, intf, 'address']
- try:
- for addr in config.return_values(path):
- listen_addr.append( ip_interface(addr).ip )
- except:
- # Some interface types do not use "address" option (e.g. OpenVPN)
- # and may not even have a fixed address
- print("Could not retrieve the address of the interface {} from the config".format(intf))
- print("You will need to update your DNS forwarding configuration manually")
+ # we need to treat vif and vif-s interfaces differently,
+ # both "real interfaces" use dots for vlan identifiers - those
+ # need to be exchanged with vif and vif-s identifiers
+ if intf.count('.') == 1:
+ # this is a regular VLAN interface
+ intf = intf.split('.')[0] + ' vif ' + intf.split('.')[1]
+ elif intf.count('.') == 2:
+ # this is a QinQ VLAN interface
+ intf = intf.split('.')[0] + ' vif-s ' + intf.split('.')[1] + ' vif-c ' + intf.split('.')[2]
-for addr in listen_addr:
- config.set(base + ['listen-address'], value=addr, replace=False)
+ # retrieve corresponding interface addresses in CIDR format
+ # those need to be converted in pure IP addresses without network information
+ path = ['interfaces', section, intf, 'address']
+ try:
+ for addr in config.return_values(path):
+ listen_addr.append( ip_interface(addr).ip )
+ except:
+ # Some interface types do not use "address" option (e.g. OpenVPN)
+ # and may not even have a fixed address
+ print("Could not retrieve the address of the interface {} from the config".format(intf))
+ print("You will need to update your DNS forwarding configuration manually")
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ for addr in listen_addr:
+ config.set(base + ['listen-address'], value=addr, replace=False)
diff --git a/src/migration-scripts/dns-forwarding/2-to-3 b/src/migration-scripts/dns-forwarding/2-to-3
index d7ff9e260..729c1f00a 100755..100644
--- a/src/migration-scripts/dns-forwarding/2-to-3
+++ b/src/migration-scripts/dns-forwarding/2-to-3
@@ -1,51 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Sets the new options "addnta" and "recursion-desired" for all
# 'dns forwarding domain' as this is usually desired
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'dns', 'forwarding']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-if config.exists(base + ['domain']):
- for domain in config.list_nodes(base + ['domain']):
- domain_base = base + ['domain', domain]
- config.set(domain_base + ['addnta'])
- config.set(domain_base + ['recursion-desired'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ if config.exists(base + ['domain']):
+ for domain in config.list_nodes(base + ['domain']):
+ domain_base = base + ['domain', domain]
+ config.set(domain_base + ['addnta'])
+ config.set(domain_base + ['recursion-desired'])
diff --git a/src/migration-scripts/dns-forwarding/3-to-4 b/src/migration-scripts/dns-forwarding/3-to-4
index 3d5316ed4..b02c0b7ca 100755..100644
--- a/src/migration-scripts/dns-forwarding/3-to-4
+++ b/src/migration-scripts/dns-forwarding/3-to-4
@@ -1,49 +1,31 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5115: migrate "service dns forwarding domain example.com server" to
# "service dns forwarding domain example.com name-server"
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'dns', 'forwarding', 'domain']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-for domain in config.list_nodes(base):
- if config.exists(base + [domain, 'server']):
- config.copy(base + [domain, 'server'], base + [domain, 'name-server'])
- config.delete(base + [domain, 'server'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ for domain in config.list_nodes(base):
+ if config.exists(base + [domain, 'server']):
+ config.copy(base + [domain, 'server'], base + [domain, 'name-server'])
+ config.delete(base + [domain, 'server'])
diff --git a/src/migration-scripts/firewall/10-to-11 b/src/migration-scripts/firewall/10-to-11
index 854d5a558..70a170940 100755..100644
--- a/src/migration-scripts/firewall/10-to-11
+++ b/src/migration-scripts/firewall/10-to-11
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5160: Firewall re-writing
@@ -37,171 +36,152 @@
# set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> action jump
# set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> jump-target <name>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-### Migration of state policies
-if config.exists(base + ['state-policy']):
- for state in config.list_nodes(base + ['state-policy']):
- action = config.return_value(base + ['state-policy', state, 'action'])
- config.set(base + ['global-options', 'state-policy', state, 'action'], value=action)
- if config.exists(base + ['state-policy', state, 'log']):
- config.set(base + ['global-options', 'state-policy', state, 'log'], value='enable')
- config.delete(base + ['state-policy'])
-
-## migration of global options:
-for option in ['all-ping', 'broadcast-ping', 'config-trap', 'ip-src-route', 'ipv6-receive-redirects', 'ipv6-src-route', 'log-martians',
- 'receive-redirects', 'resolver-cache', 'resolver-internal', 'send-redirects', 'source-validation', 'syn-cookies', 'twa-hazards-protection']:
- if config.exists(base + [option]):
- if option != 'config-trap':
- val = config.return_value(base + [option])
- config.set(base + ['global-options', option], value=val)
- config.delete(base + [option])
-
-### Migration of firewall name and ipv6-name
-### Also migrate legacy 'accept' behaviour
-if config.exists(base + ['name']):
- config.set(['firewall', 'ipv4', 'name'])
- config.set_tag(['firewall', 'ipv4', 'name'])
-
- for ipv4name in config.list_nodes(base + ['name']):
- config.copy(base + ['name', ipv4name], base + ['ipv4', 'name', ipv4name])
-
- if config.exists(base + ['ipv4', 'name', ipv4name, 'default-action']):
- action = config.return_value(base + ['ipv4', 'name', ipv4name, 'default-action'])
-
- if action == 'accept':
- config.set(base + ['ipv4', 'name', ipv4name, 'default-action'], value='return')
-
- if config.exists(base + ['ipv4', 'name', ipv4name, 'rule']):
- for rule_id in config.list_nodes(base + ['ipv4', 'name', ipv4name, 'rule']):
- action = config.return_value(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'])
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ ### Migration of state policies
+ if config.exists(base + ['state-policy']):
+ for state in config.list_nodes(base + ['state-policy']):
+ action = config.return_value(base + ['state-policy', state, 'action'])
+ config.set(base + ['global-options', 'state-policy', state, 'action'], value=action)
+ if config.exists(base + ['state-policy', state, 'log']):
+ config.set(base + ['global-options', 'state-policy', state, 'log'], value='enable')
+ config.delete(base + ['state-policy'])
+
+ ## migration of global options:
+ for option in ['all-ping', 'broadcast-ping', 'config-trap', 'ip-src-route', 'ipv6-receive-redirects', 'ipv6-src-route', 'log-martians',
+ 'receive-redirects', 'resolver-cache', 'resolver-internal', 'send-redirects', 'source-validation', 'syn-cookies', 'twa-hazards-protection']:
+ if config.exists(base + [option]):
+ if option != 'config-trap':
+ val = config.return_value(base + [option])
+ config.set(base + ['global-options', option], value=val)
+ config.delete(base + [option])
+
+ ### Migration of firewall name and ipv6-name
+ ### Also migrate legacy 'accept' behaviour
+ if config.exists(base + ['name']):
+ config.set(['firewall', 'ipv4', 'name'])
+ config.set_tag(['firewall', 'ipv4', 'name'])
+
+ for ipv4name in config.list_nodes(base + ['name']):
+ config.copy(base + ['name', ipv4name], base + ['ipv4', 'name', ipv4name])
+
+ if config.exists(base + ['ipv4', 'name', ipv4name, 'default-action']):
+ action = config.return_value(base + ['ipv4', 'name', ipv4name, 'default-action'])
if action == 'accept':
- config.set(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'], value='return')
+ config.set(base + ['ipv4', 'name', ipv4name, 'default-action'], value='return')
- config.delete(base + ['name'])
+ if config.exists(base + ['ipv4', 'name', ipv4name, 'rule']):
+ for rule_id in config.list_nodes(base + ['ipv4', 'name', ipv4name, 'rule']):
+ action = config.return_value(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'])
-if config.exists(base + ['ipv6-name']):
- config.set(['firewall', 'ipv6', 'name'])
- config.set_tag(['firewall', 'ipv6', 'name'])
+ if action == 'accept':
+ config.set(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'], value='return')
- for ipv6name in config.list_nodes(base + ['ipv6-name']):
- config.copy(base + ['ipv6-name', ipv6name], base + ['ipv6', 'name', ipv6name])
+ config.delete(base + ['name'])
- if config.exists(base + ['ipv6', 'name', ipv6name, 'default-action']):
- action = config.return_value(base + ['ipv6', 'name', ipv6name, 'default-action'])
+ if config.exists(base + ['ipv6-name']):
+ config.set(['firewall', 'ipv6', 'name'])
+ config.set_tag(['firewall', 'ipv6', 'name'])
- if action == 'accept':
- config.set(base + ['ipv6', 'name', ipv6name, 'default-action'], value='return')
+ for ipv6name in config.list_nodes(base + ['ipv6-name']):
+ config.copy(base + ['ipv6-name', ipv6name], base + ['ipv6', 'name', ipv6name])
- if config.exists(base + ['ipv6', 'name', ipv6name, 'rule']):
- for rule_id in config.list_nodes(base + ['ipv6', 'name', ipv6name, 'rule']):
- action = config.return_value(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'])
+ if config.exists(base + ['ipv6', 'name', ipv6name, 'default-action']):
+ action = config.return_value(base + ['ipv6', 'name', ipv6name, 'default-action'])
if action == 'accept':
- config.set(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'], value='return')
-
- config.delete(base + ['ipv6-name'])
-
-### Migration of firewall interface
-if config.exists(base + ['interface']):
- fwd_ipv4_rule = 5
- inp_ipv4_rule = 5
- fwd_ipv6_rule = 5
- inp_ipv6_rule = 5
- for direction in ['in', 'out', 'local']:
- for iface in config.list_nodes(base + ['interface']):
- if config.exists(base + ['interface', iface, direction]):
- if config.exists(base + ['interface', iface, direction, 'name']):
- target = config.return_value(base + ['interface', iface, direction, 'name'])
- if direction == 'in':
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv4', 'forward', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [fwd_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
- config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
- fwd_ipv4_rule = fwd_ipv4_rule + 5
- elif direction == 'out':
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv4', 'forward', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [fwd_ipv4_rule, 'outbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
- config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
- fwd_ipv4_rule = fwd_ipv4_rule + 5
- else:
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv4', 'input', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv4', 'input', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [inp_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [inp_ipv4_rule, 'action'], value='jump')
- config.set(new_base + [inp_ipv4_rule, 'jump-target'], value=target)
- inp_ipv4_rule = inp_ipv4_rule + 5
-
- if config.exists(base + ['interface', iface, direction, 'ipv6-name']):
- target = config.return_value(base + ['interface', iface, direction, 'ipv6-name'])
- if direction == 'in':
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv6', 'forward', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [fwd_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
- config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
- fwd_ipv6_rule = fwd_ipv6_rule + 5
- elif direction == 'out':
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv6', 'forward', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [fwd_ipv6_rule, 'outbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
- config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
- fwd_ipv6_rule = fwd_ipv6_rule + 5
- else:
- new_base = base + ['ipv6', 'input', 'filter', 'rule']
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv6', 'input', 'filter', 'default-action'], value='accept')
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [inp_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [inp_ipv6_rule, 'action'], value='jump')
- config.set(new_base + [inp_ipv6_rule, 'jump-target'], value=target)
- inp_ipv6_rule = inp_ipv6_rule + 5
-
- config.delete(base + ['interface'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.set(base + ['ipv6', 'name', ipv6name, 'default-action'], value='return')
+
+ if config.exists(base + ['ipv6', 'name', ipv6name, 'rule']):
+ for rule_id in config.list_nodes(base + ['ipv6', 'name', ipv6name, 'rule']):
+ action = config.return_value(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'])
+
+ if action == 'accept':
+ config.set(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'], value='return')
+
+ config.delete(base + ['ipv6-name'])
+
+ ### Migration of firewall interface
+ if config.exists(base + ['interface']):
+ fwd_ipv4_rule = 5
+ inp_ipv4_rule = 5
+ fwd_ipv6_rule = 5
+ inp_ipv6_rule = 5
+ for direction in ['in', 'out', 'local']:
+ for iface in config.list_nodes(base + ['interface']):
+ if config.exists(base + ['interface', iface, direction]):
+ if config.exists(base + ['interface', iface, direction, 'name']):
+ target = config.return_value(base + ['interface', iface, direction, 'name'])
+ if direction == 'in':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ elif direction == 'out':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv4_rule, 'outbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ else:
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'input', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'input', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [inp_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [inp_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [inp_ipv4_rule, 'jump-target'], value=target)
+ inp_ipv4_rule = inp_ipv4_rule + 5
+
+ if config.exists(base + ['interface', iface, direction, 'ipv6-name']):
+ target = config.return_value(base + ['interface', iface, direction, 'ipv6-name'])
+ if direction == 'in':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv6', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+ elif direction == 'out':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv6', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv6_rule, 'outbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+ else:
+ new_base = base + ['ipv6', 'input', 'filter', 'rule']
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'input', 'filter', 'default-action'], value='accept')
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [inp_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [inp_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [inp_ipv6_rule, 'jump-target'], value=target)
+ inp_ipv6_rule = inp_ipv6_rule + 5
+
+ config.delete(base + ['interface'])
diff --git a/src/migration-scripts/firewall/11-to-12 b/src/migration-scripts/firewall/11-to-12
index f9122e74c..80a74cca9 100755..100644
--- a/src/migration-scripts/firewall/11-to-12
+++ b/src/migration-scripts/firewall/11-to-12
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5681: Firewall re-writing. Simplify cli when mathcing interface
# From
@@ -22,50 +21,31 @@
# set firewall ... rule <rule> [inbound-interface | outboubd-interface] name <iface>
# set firewall ... rule <rule> [inbound-interface | outboubd-interface] group <iface_group>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-## Migration from base chains
-#if config.exists(base + ['interface', iface, direction]):
-for family in ['ipv4', 'ipv6']:
- if config.exists(base + [family]):
- for hook in ['forward', 'input', 'output', 'name']:
- if config.exists(base + [family, hook]):
- for priority in config.list_nodes(base + [family, hook]):
- if config.exists(base + [family, hook, priority, 'rule']):
- for rule in config.list_nodes(base + [family, hook, priority, 'rule']):
- for direction in ['inbound-interface', 'outbound-interface']:
- if config.exists(base + [family, hook, priority, 'rule', rule, direction]):
- if config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']):
- iface = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-name'])
- config.set(base + [family, hook, priority, 'rule', rule, direction, 'name'], value=iface)
- config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-name'])
- elif config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']):
- group = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-group'])
- config.set(base + [family, hook, priority, 'rule', rule, direction, 'group'], value=group)
- config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-group'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ ## Migration from base chains
+ #if config.exists(base + ['interface', iface, direction]):
+ for family in ['ipv4', 'ipv6']:
+ if config.exists(base + [family]):
+ for hook in ['forward', 'input', 'output', 'name']:
+ if config.exists(base + [family, hook]):
+ for priority in config.list_nodes(base + [family, hook]):
+ if config.exists(base + [family, hook, priority, 'rule']):
+ for rule in config.list_nodes(base + [family, hook, priority, 'rule']):
+ for direction in ['inbound-interface', 'outbound-interface']:
+ if config.exists(base + [family, hook, priority, 'rule', rule, direction]):
+ if config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']):
+ iface = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-name'])
+ config.set(base + [family, hook, priority, 'rule', rule, direction, 'name'], value=iface)
+ config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-name'])
+ elif config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']):
+ group = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-group'])
+ config.set(base + [family, hook, priority, 'rule', rule, direction, 'group'], value=group)
+ config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-group'])
diff --git a/src/migration-scripts/firewall/12-to-13 b/src/migration-scripts/firewall/12-to-13
index d72ba834d..d7b801cd3 100755..100644
--- a/src/migration-scripts/firewall/12-to-13
+++ b/src/migration-scripts/firewall/12-to-13
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5729: Switch to valueless whenever is possible.
# From
@@ -25,65 +24,46 @@
# set firewall ... rule <rule> state <state>
# Remove command if log=disable or <state>=disable
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-# State Policy logs:
-if config.exists(base + ['global-options', 'state-policy']):
- for state in config.list_nodes(base + ['global-options', 'state-policy']):
- if config.exists(base + ['global-options', 'state-policy', state, 'log']):
- log_value = config.return_value(base + ['global-options', 'state-policy', state, 'log'])
- config.delete(base + ['global-options', 'state-policy', state, 'log'])
- if log_value == 'enable':
- config.set(base + ['global-options', 'state-policy', state, 'log'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-for family in ['ipv4', 'ipv6', 'bridge']:
- if config.exists(base + [family]):
- for hook in ['forward', 'input', 'output', 'name']:
- if config.exists(base + [family, hook]):
- for priority in config.list_nodes(base + [family, hook]):
- if config.exists(base + [family, hook, priority, 'rule']):
- for rule in config.list_nodes(base + [family, hook, priority, 'rule']):
- # Log
- if config.exists(base + [family, hook, priority, 'rule', rule, 'log']):
- log_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'log'])
- config.delete(base + [family, hook, priority, 'rule', rule, 'log'])
- if log_value == 'enable':
- config.set(base + [family, hook, priority, 'rule', rule, 'log'])
- # State
- if config.exists(base + [family, hook, priority, 'rule', rule, 'state']):
- flag_enable = 'False'
- for state in ['established', 'invalid', 'new', 'related']:
- if config.exists(base + [family, hook, priority, 'rule', rule, 'state', state]):
- state_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'state', state])
- config.delete(base + [family, hook, priority, 'rule', rule, 'state', state])
- if state_value == 'enable':
- config.set(base + [family, hook, priority, 'rule', rule, 'state'], value=state, replace=False)
- flag_enable = 'True'
- if flag_enable == 'False':
- config.delete(base + [family, hook, priority, 'rule', rule, 'state'])
+ # State Policy logs:
+ if config.exists(base + ['global-options', 'state-policy']):
+ for state in config.list_nodes(base + ['global-options', 'state-policy']):
+ if config.exists(base + ['global-options', 'state-policy', state, 'log']):
+ log_value = config.return_value(base + ['global-options', 'state-policy', state, 'log'])
+ config.delete(base + ['global-options', 'state-policy', state, 'log'])
+ if log_value == 'enable':
+ config.set(base + ['global-options', 'state-policy', state, 'log'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for family in ['ipv4', 'ipv6', 'bridge']:
+ if config.exists(base + [family]):
+ for hook in ['forward', 'input', 'output', 'name']:
+ if config.exists(base + [family, hook]):
+ for priority in config.list_nodes(base + [family, hook]):
+ if config.exists(base + [family, hook, priority, 'rule']):
+ for rule in config.list_nodes(base + [family, hook, priority, 'rule']):
+ # Log
+ if config.exists(base + [family, hook, priority, 'rule', rule, 'log']):
+ log_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'log'])
+ config.delete(base + [family, hook, priority, 'rule', rule, 'log'])
+ if log_value == 'enable':
+ config.set(base + [family, hook, priority, 'rule', rule, 'log'])
+ # State
+ if config.exists(base + [family, hook, priority, 'rule', rule, 'state']):
+ flag_enable = 'False'
+ for state in ['established', 'invalid', 'new', 'related']:
+ if config.exists(base + [family, hook, priority, 'rule', rule, 'state', state]):
+ state_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'state', state])
+ config.delete(base + [family, hook, priority, 'rule', rule, 'state', state])
+ if state_value == 'enable':
+ config.set(base + [family, hook, priority, 'rule', rule, 'state'], value=state, replace=False)
+ flag_enable = 'True'
+ if flag_enable == 'False':
+ config.delete(base + [family, hook, priority, 'rule', rule, 'state'])
diff --git a/src/migration-scripts/firewall/13-to-14 b/src/migration-scripts/firewall/13-to-14
index f45ff0674..723b0aea2 100755..100644
--- a/src/migration-scripts/firewall/13-to-14
+++ b/src/migration-scripts/firewall/13-to-14
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5834: Rename 'enable-default-log' to 'default-log'
# From
@@ -22,38 +21,19 @@
# set firewall ... filter default-log
# set firewall ... name <name> default-log
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for family in ['ipv4', 'ipv6', 'bridge']:
- if config.exists(base + [family]):
- for hook in ['forward', 'input', 'output', 'name']:
- if config.exists(base + [family, hook]):
- for priority in config.list_nodes(base + [family, hook]):
- if config.exists(base + [family, hook, priority, 'enable-default-log']):
- config.rename(base + [family, hook, priority, 'enable-default-log'], 'default-log')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for family in ['ipv4', 'ipv6', 'bridge']:
+ if config.exists(base + [family]):
+ for hook in ['forward', 'input', 'output', 'name']:
+ if config.exists(base + [family, hook]):
+ for priority in config.list_nodes(base + [family, hook]):
+ if config.exists(base + [family, hook, priority, 'enable-default-log']):
+ config.rename(base + [family, hook, priority, 'enable-default-log'], 'default-log')
diff --git a/src/migration-scripts/firewall/14-to-15 b/src/migration-scripts/firewall/14-to-15
index 735839365..e4a2aaee4 100755..100644
--- a/src/migration-scripts/firewall/14-to-15
+++ b/src/migration-scripts/firewall/14-to-15
@@ -1,46 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5535: Migrate <set system ip disable-directed-broadcast> to <set firewall global-options directed-broadcas [enable|disable]
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['firewall']
-if config.exists(['system', 'ip', 'disable-directed-broadcast']):
- config.set(['firewall', 'global-options', 'directed-broadcast'], value='disable')
- config.delete(['system', 'ip', 'disable-directed-broadcast'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1) \ No newline at end of file
+def migrate(config: ConfigTree) -> None:
+ if config.exists(['system', 'ip', 'disable-directed-broadcast']):
+ config.set(['firewall', 'global-options', 'directed-broadcast'], value='disable')
+ config.delete(['system', 'ip', 'disable-directed-broadcast'])
diff --git a/src/migration-scripts/firewall/15-to-16 b/src/migration-scripts/firewall/15-to-16
index 28df1256e..8e28bba6f 100755..100644
--- a/src/migration-scripts/firewall/15-to-16
+++ b/src/migration-scripts/firewall/15-to-16
@@ -18,39 +18,20 @@
# from: set system conntrack timeout ..
# to: set firewall global-options timeout ...
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
firewall_base = ['firewall', 'global-options']
conntrack_base = ['system', 'conntrack', 'timeout']
-config = ConfigTree(config_file)
-
-if not config.exists(conntrack_base):
- # Nothing to do
- exit(0)
-for protocol in ['icmp', 'tcp', 'udp', 'other']:
- if config.exists(conntrack_base + [protocol]):
- if not config.exists(firewall_base + ['timeout']):
- config.set(firewall_base + ['timeout'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(conntrack_base):
+ # Nothing to do
+ return
- config.copy(conntrack_base + [protocol], firewall_base + ['timeout', protocol])
- config.delete(conntrack_base + [protocol])
+ for protocol in ['icmp', 'tcp', 'udp', 'other']:
+ if config.exists(conntrack_base + [protocol]):
+ if not config.exists(firewall_base + ['timeout']):
+ config.set(firewall_base + ['timeout'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.copy(conntrack_base + [protocol], firewall_base + ['timeout', protocol])
+ config.delete(conntrack_base + [protocol])
diff --git a/src/migration-scripts/firewall/5-to-6 b/src/migration-scripts/firewall/5-to-6
index e1eaea7a1..d01684787 100755..100644
--- a/src/migration-scripts/firewall/5-to-6
+++ b/src/migration-scripts/firewall/5-to-6
@@ -1,105 +1,85 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3090: migrate "firewall options interface <name> adjust-mss" to the
# individual interface.
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall', 'options', 'interface']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for interface in config.list_nodes(base):
- if config.exists(base + [interface, 'disable']):
- continue
- if config.exists(base + [interface, 'adjust-mss']):
- section = Section.section(interface)
- tmp = config.return_value(base + [interface, 'adjust-mss'])
-
- vlan = interface.split('.')
- base_interface_path = ['interfaces', section, vlan[0]]
-
- if len(vlan) == 1:
- # Normal interface, no VLAN
- config.set(base_interface_path + ['ip', 'adjust-mss'], value=tmp)
- elif len(vlan) == 2:
- # Regular VIF or VIF-S interface - we need to check the config
- vif = vlan[1]
- if config.exists(base_interface_path + ['vif', vif]):
- config.set(base_interface_path + ['vif', vif, 'ip', 'adjust-mss'], value=tmp)
- elif config.exists(base_interface_path + ['vif-s', vif]):
- config.set(base_interface_path + ['vif-s', vif, 'ip', 'adjust-mss'], value=tmp)
- elif len(vlan) == 3:
- # VIF-S interface with VIF-C subinterface
- vif_s = vlan[1]
- vif_c = vlan[2]
- config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ip', 'adjust-mss'], value=tmp)
- config.set_tag(base_interface_path + ['vif-s'])
- config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
-
- if config.exists(base + [interface, 'adjust-mss6']):
- section = Section.section(interface)
- tmp = config.return_value(base + [interface, 'adjust-mss6'])
-
- vlan = interface.split('.')
- base_interface_path = ['interfaces', section, vlan[0]]
-
- if len(vlan) == 1:
- # Normal interface, no VLAN
- config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp)
- elif len(vlan) == 2:
- # Regular VIF or VIF-S interface - we need to check the config
- vif = vlan[1]
- if config.exists(base_interface_path + ['vif', vif]):
- config.set(base_interface_path + ['vif', vif, 'ipv6', 'adjust-mss'], value=tmp)
- config.set_tag(base_interface_path + ['vif'])
- elif config.exists(base_interface_path + ['vif-s', vif]):
- config.set(base_interface_path + ['vif-s', vif, 'ipv6', 'adjust-mss'], value=tmp)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for interface in config.list_nodes(base):
+ if config.exists(base + [interface, 'disable']):
+ continue
+
+ if config.exists(base + [interface, 'adjust-mss']):
+ section = Section.section(interface)
+ tmp = config.return_value(base + [interface, 'adjust-mss'])
+
+ vlan = interface.split('.')
+ base_interface_path = ['interfaces', section, vlan[0]]
+
+ if len(vlan) == 1:
+ # Normal interface, no VLAN
+ config.set(base_interface_path + ['ip', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 2:
+ # Regular VIF or VIF-S interface - we need to check the config
+ vif = vlan[1]
+ if config.exists(base_interface_path + ['vif', vif]):
+ config.set(base_interface_path + ['vif', vif, 'ip', 'adjust-mss'], value=tmp)
+ elif config.exists(base_interface_path + ['vif-s', vif]):
+ config.set(base_interface_path + ['vif-s', vif, 'ip', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 3:
+ # VIF-S interface with VIF-C subinterface
+ vif_s = vlan[1]
+ vif_c = vlan[2]
+ config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ip', 'adjust-mss'], value=tmp)
config.set_tag(base_interface_path + ['vif-s'])
- elif len(vlan) == 3:
- # VIF-S interface with VIF-C subinterface
- vif_s = vlan[1]
- vif_c = vlan[2]
- config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ipv6', 'adjust-mss'], value=tmp)
- config.set_tag(base_interface_path + ['vif-s'])
- config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
-
-config.delete(['firewall', 'options'])
+ config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
+
+ if config.exists(base + [interface, 'adjust-mss6']):
+ section = Section.section(interface)
+ tmp = config.return_value(base + [interface, 'adjust-mss6'])
+
+ vlan = interface.split('.')
+ base_interface_path = ['interfaces', section, vlan[0]]
+
+ if len(vlan) == 1:
+ # Normal interface, no VLAN
+ config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 2:
+ # Regular VIF or VIF-S interface - we need to check the config
+ vif = vlan[1]
+ if config.exists(base_interface_path + ['vif', vif]):
+ config.set(base_interface_path + ['vif', vif, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif'])
+ elif config.exists(base_interface_path + ['vif-s', vif]):
+ config.set(base_interface_path + ['vif-s', vif, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif-s'])
+ elif len(vlan) == 3:
+ # VIF-S interface with VIF-C subinterface
+ vif_s = vlan[1]
+ vif_c = vlan[2]
+ config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif-s'])
+ config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.delete(['firewall', 'options'])
diff --git a/src/migration-scripts/firewall/6-to-7 b/src/migration-scripts/firewall/6-to-7
index 938044c6d..1afbc780b 100755..100644
--- a/src/migration-scripts/firewall/6-to-7
+++ b/src/migration-scripts/firewall/6-to-7
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T2199: Remove unavailable nodes due to XML/Python implementation using nftables
# monthdays: nftables does not have a monthdays equivalent
@@ -23,28 +22,11 @@
import re
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
max_len_description = 255
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
icmp_remove = ['any']
icmp_translations = {
@@ -107,216 +89,216 @@ icmpv6_translations = {
'unknown-option': [4, 2]
}
-v4_found = False
-v6_found = False
v4_groups = ["address-group", "network-group", "port-group"]
v6_groups = ["ipv6-address-group", "ipv6-network-group", "port-group"]
-translated_dict = {}
-if config.exists(base + ['group']):
- for group_type in config.list_nodes(base + ['group']):
- for group_name in config.list_nodes(base + ['group', group_type]):
- name_description = base + ['group', group_type, group_name, 'description']
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ v4_found = False
+ v6_found = False
+ translated_dict = {}
+
+ if config.exists(base + ['group']):
+ for group_type in config.list_nodes(base + ['group']):
+ for group_name in config.list_nodes(base + ['group', group_type]):
+ name_description = base + ['group', group_type, group_name, 'description']
+ if config.exists(name_description):
+ tmp = config.return_value(name_description)
+ config.set(name_description, value=tmp[:max_len_description])
+ if '+' in group_name:
+ replacement_string = "_"
+ if group_type in v4_groups and not v4_found:
+ v4_found = True
+ if group_type in v6_groups and not v6_found:
+ v6_found = True
+ new_group_name = group_name.replace('+', replacement_string)
+ while config.exists(base + ['group', group_type, new_group_name]):
+ replacement_string = replacement_string + "_"
+ new_group_name = group_name.replace('+', replacement_string)
+ translated_dict[group_name] = new_group_name
+ config.copy(base + ['group', group_type, group_name], base + ['group', group_type, new_group_name])
+ config.delete(base + ['group', group_type, group_name])
+
+ if config.exists(base + ['name']):
+ for name in config.list_nodes(base + ['name']):
+ name_description = base + ['name', name, 'description']
if config.exists(name_description):
tmp = config.return_value(name_description)
config.set(name_description, value=tmp[:max_len_description])
- if '+' in group_name:
- replacement_string = "_"
- if group_type in v4_groups and not v4_found:
- v4_found = True
- if group_type in v6_groups and not v6_found:
- v6_found = True
- new_group_name = group_name.replace('+', replacement_string)
- while config.exists(base + ['group', group_type, new_group_name]):
- replacement_string = replacement_string + "_"
- new_group_name = group_name.replace('+', replacement_string)
- translated_dict[group_name] = new_group_name
- config.copy(base + ['group', group_type, group_name], base + ['group', group_type, new_group_name])
- config.delete(base + ['group', group_type, group_name])
-
-if config.exists(base + ['name']):
- for name in config.list_nodes(base + ['name']):
- name_description = base + ['name', name, 'description']
- if config.exists(name_description):
- tmp = config.return_value(name_description)
- config.set(name_description, value=tmp[:max_len_description])
-
- if not config.exists(base + ['name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['name', name, 'rule']):
- rule_description = base + ['name', name, 'rule', rule, 'description']
- if config.exists(rule_description):
- tmp = config.return_value(rule_description)
- config.set(rule_description, value=tmp[:max_len_description])
-
- rule_recent = base + ['name', name, 'rule', rule, 'recent']
- rule_time = base + ['name', name, 'rule', rule, 'time']
- rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags']
- rule_icmp = base + ['name', name, 'rule', rule, 'icmp']
-
- if config.exists(rule_time + ['monthdays']):
- config.delete(rule_time + ['monthdays'])
-
- if config.exists(rule_time + ['utc']):
- config.delete(rule_time + ['utc'])
-
- if config.exists(rule_recent + ['time']):
- tmp = int(config.return_value(rule_recent + ['time']))
- unit = 'minute'
- if tmp > 600:
- unit = 'hour'
- elif tmp < 10:
- unit = 'second'
- config.set(rule_recent + ['time'], value=unit)
-
- if config.exists(rule_tcp_flags):
- tmp = config.return_value(rule_tcp_flags)
- config.delete(rule_tcp_flags)
- for flag in tmp.split(","):
- if flag[0] == '!':
- config.set(rule_tcp_flags + ['not', flag[1:].lower()])
- else:
- config.set(rule_tcp_flags + [flag.lower()])
-
- if config.exists(rule_icmp + ['type-name']):
- tmp = config.return_value(rule_icmp + ['type-name'])
- if tmp in icmp_remove:
- config.delete(rule_icmp + ['type-name'])
- elif tmp in icmp_translations:
- translate = icmp_translations[tmp]
- if isinstance(translate, str):
- config.set(rule_icmp + ['type-name'], value=translate)
- elif isinstance(translate, list):
+
+ if not config.exists(base + ['name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['name', name, 'rule']):
+ rule_description = base + ['name', name, 'rule', rule, 'description']
+ if config.exists(rule_description):
+ tmp = config.return_value(rule_description)
+ config.set(rule_description, value=tmp[:max_len_description])
+
+ rule_recent = base + ['name', name, 'rule', rule, 'recent']
+ rule_time = base + ['name', name, 'rule', rule, 'time']
+ rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags']
+ rule_icmp = base + ['name', name, 'rule', rule, 'icmp']
+
+ if config.exists(rule_time + ['monthdays']):
+ config.delete(rule_time + ['monthdays'])
+
+ if config.exists(rule_time + ['utc']):
+ config.delete(rule_time + ['utc'])
+
+ if config.exists(rule_recent + ['time']):
+ tmp = int(config.return_value(rule_recent + ['time']))
+ unit = 'minute'
+ if tmp > 600:
+ unit = 'hour'
+ elif tmp < 10:
+ unit = 'second'
+ config.set(rule_recent + ['time'], value=unit)
+
+ if config.exists(rule_tcp_flags):
+ tmp = config.return_value(rule_tcp_flags)
+ config.delete(rule_tcp_flags)
+ for flag in tmp.split(","):
+ if flag[0] == '!':
+ config.set(rule_tcp_flags + ['not', flag[1:].lower()])
+ else:
+ config.set(rule_tcp_flags + [flag.lower()])
+
+ if config.exists(rule_icmp + ['type-name']):
+ tmp = config.return_value(rule_icmp + ['type-name'])
+ if tmp in icmp_remove:
config.delete(rule_icmp + ['type-name'])
- config.set(rule_icmp + ['type'], value=translate[0])
- config.set(rule_icmp + ['code'], value=translate[1])
-
- for direction in ['destination', 'source']:
- if config.exists(base + ['name', name, 'rule', rule, direction]):
- if config.exists(base + ['name', name, 'rule', rule, direction, 'group']) and v4_found:
- for group_type in config.list_nodes(base + ['name', name, 'rule', rule, direction, 'group']):
- group_name = config.return_value(base + ['name', name, 'rule', rule, direction, 'group', group_type])
- if '+' in group_name:
- if group_name[0] == "!":
- new_group_name = "!" + translated_dict[group_name[1:]]
- else:
- new_group_name = translated_dict[group_name]
- config.set(base + ['name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
-
- pg_base = base + ['name', name, 'rule', rule, direction, 'group', 'port-group']
- proto_base = base + ['name', name, 'rule', rule, 'protocol']
- if config.exists(pg_base) and not config.exists(proto_base):
- config.set(proto_base, value='tcp_udp')
-
- if '+' in name:
- replacement_string = "_"
- new_name = name.replace('+', replacement_string)
- while config.exists(base + ['name', new_name]):
- replacement_string = replacement_string + "_"
+ elif tmp in icmp_translations:
+ translate = icmp_translations[tmp]
+ if isinstance(translate, str):
+ config.set(rule_icmp + ['type-name'], value=translate)
+ elif isinstance(translate, list):
+ config.delete(rule_icmp + ['type-name'])
+ config.set(rule_icmp + ['type'], value=translate[0])
+ config.set(rule_icmp + ['code'], value=translate[1])
+
+ for direction in ['destination', 'source']:
+ if config.exists(base + ['name', name, 'rule', rule, direction]):
+ if config.exists(base + ['name', name, 'rule', rule, direction, 'group']) and v4_found:
+ for group_type in config.list_nodes(base + ['name', name, 'rule', rule, direction, 'group']):
+ group_name = config.return_value(base + ['name', name, 'rule', rule, direction, 'group', group_type])
+ if '+' in group_name:
+ if group_name[0] == "!":
+ new_group_name = "!" + translated_dict[group_name[1:]]
+ else:
+ new_group_name = translated_dict[group_name]
+ config.set(base + ['name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
+
+ pg_base = base + ['name', name, 'rule', rule, direction, 'group', 'port-group']
+ proto_base = base + ['name', name, 'rule', rule, 'protocol']
+ if config.exists(pg_base) and not config.exists(proto_base):
+ config.set(proto_base, value='tcp_udp')
+
+ if '+' in name:
+ replacement_string = "_"
new_name = name.replace('+', replacement_string)
- config.copy(base + ['name', name], base + ['name', new_name])
- config.delete(base + ['name', name])
-
-if config.exists(base + ['ipv6-name']):
- for name in config.list_nodes(base + ['ipv6-name']):
- name_description = base + ['ipv6-name', name, 'description']
- if config.exists(name_description):
- tmp = config.return_value(name_description)
- config.set(name_description, value=tmp[:max_len_description])
-
- if not config.exists(base + ['ipv6-name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
- rule_description = base + ['ipv6-name', name, 'rule', rule, 'description']
- if config.exists(rule_description):
- tmp = config.return_value(rule_description)
- config.set(rule_description, value=tmp[:max_len_description])
-
- rule_recent = base + ['ipv6-name', name, 'rule', rule, 'recent']
- rule_time = base + ['ipv6-name', name, 'rule', rule, 'time']
- rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags']
- rule_icmp = base + ['ipv6-name', name, 'rule', rule, 'icmpv6']
-
- if config.exists(rule_time + ['monthdays']):
- config.delete(rule_time + ['monthdays'])
-
- if config.exists(rule_time + ['utc']):
- config.delete(rule_time + ['utc'])
-
- if config.exists(rule_recent + ['time']):
- tmp = int(config.return_value(rule_recent + ['time']))
- unit = 'minute'
- if tmp > 600:
- unit = 'hour'
- elif tmp < 10:
- unit = 'second'
- config.set(rule_recent + ['time'], value=unit)
-
- if config.exists(rule_tcp_flags):
- tmp = config.return_value(rule_tcp_flags)
- config.delete(rule_tcp_flags)
- for flag in tmp.split(","):
- if flag[0] == '!':
- config.set(rule_tcp_flags + ['not', flag[1:].lower()])
- else:
- config.set(rule_tcp_flags + [flag.lower()])
-
- if config.exists(base + ['ipv6-name', name, 'rule', rule, 'protocol']):
- tmp = config.return_value(base + ['ipv6-name', name, 'rule', rule, 'protocol'])
- if tmp == 'icmpv6':
- config.set(base + ['ipv6-name', name, 'rule', rule, 'protocol'], value='ipv6-icmp')
-
- if config.exists(rule_icmp + ['type']):
- tmp = config.return_value(rule_icmp + ['type'])
- type_code_match = re.match(r'^(\d+)(?:/(\d+))?$', tmp)
-
- if type_code_match:
- config.set(rule_icmp + ['type'], value=type_code_match[1])
- if type_code_match[2]:
- config.set(rule_icmp + ['code'], value=type_code_match[2])
- elif tmp in icmpv6_remove:
- config.delete(rule_icmp + ['type'])
- elif tmp in icmpv6_translations:
- translate = icmpv6_translations[tmp]
- if isinstance(translate, str):
+ while config.exists(base + ['name', new_name]):
+ replacement_string = replacement_string + "_"
+ new_name = name.replace('+', replacement_string)
+ config.copy(base + ['name', name], base + ['name', new_name])
+ config.delete(base + ['name', name])
+
+ if config.exists(base + ['ipv6-name']):
+ for name in config.list_nodes(base + ['ipv6-name']):
+ name_description = base + ['ipv6-name', name, 'description']
+ if config.exists(name_description):
+ tmp = config.return_value(name_description)
+ config.set(name_description, value=tmp[:max_len_description])
+
+ if not config.exists(base + ['ipv6-name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
+ rule_description = base + ['ipv6-name', name, 'rule', rule, 'description']
+ if config.exists(rule_description):
+ tmp = config.return_value(rule_description)
+ config.set(rule_description, value=tmp[:max_len_description])
+
+ rule_recent = base + ['ipv6-name', name, 'rule', rule, 'recent']
+ rule_time = base + ['ipv6-name', name, 'rule', rule, 'time']
+ rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags']
+ rule_icmp = base + ['ipv6-name', name, 'rule', rule, 'icmpv6']
+
+ if config.exists(rule_time + ['monthdays']):
+ config.delete(rule_time + ['monthdays'])
+
+ if config.exists(rule_time + ['utc']):
+ config.delete(rule_time + ['utc'])
+
+ if config.exists(rule_recent + ['time']):
+ tmp = int(config.return_value(rule_recent + ['time']))
+ unit = 'minute'
+ if tmp > 600:
+ unit = 'hour'
+ elif tmp < 10:
+ unit = 'second'
+ config.set(rule_recent + ['time'], value=unit)
+
+ if config.exists(rule_tcp_flags):
+ tmp = config.return_value(rule_tcp_flags)
+ config.delete(rule_tcp_flags)
+ for flag in tmp.split(","):
+ if flag[0] == '!':
+ config.set(rule_tcp_flags + ['not', flag[1:].lower()])
+ else:
+ config.set(rule_tcp_flags + [flag.lower()])
+
+ if config.exists(base + ['ipv6-name', name, 'rule', rule, 'protocol']):
+ tmp = config.return_value(base + ['ipv6-name', name, 'rule', rule, 'protocol'])
+ if tmp == 'icmpv6':
+ config.set(base + ['ipv6-name', name, 'rule', rule, 'protocol'], value='ipv6-icmp')
+
+ if config.exists(rule_icmp + ['type']):
+ tmp = config.return_value(rule_icmp + ['type'])
+ type_code_match = re.match(r'^(\d+)(?:/(\d+))?$', tmp)
+
+ if type_code_match:
+ config.set(rule_icmp + ['type'], value=type_code_match[1])
+ if type_code_match[2]:
+ config.set(rule_icmp + ['code'], value=type_code_match[2])
+ elif tmp in icmpv6_remove:
config.delete(rule_icmp + ['type'])
- config.set(rule_icmp + ['type-name'], value=translate)
- elif isinstance(translate, list):
- config.set(rule_icmp + ['type'], value=translate[0])
- config.set(rule_icmp + ['code'], value=translate[1])
- else:
- config.rename(rule_icmp + ['type'], 'type-name')
-
- for direction in ['destination', 'source']:
- if config.exists(base + ['ipv6-name', name, 'rule', rule, direction]):
- if config.exists(base + ['ipv6-name', name, 'rule', rule, direction, 'group']) and v6_found:
- for group_type in config.list_nodes(base + ['ipv6-name', name, 'rule', rule, direction, 'group']):
- group_name = config.return_value(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type])
- if '+' in group_name:
- if group_name[0] == "!":
- new_group_name = "!" + translated_dict[group_name[1:]]
- else:
- new_group_name = translated_dict[group_name]
- config.set(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
-
- pg_base = base + ['ipv6-name', name, 'rule', rule, direction, 'group', 'port-group']
- proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol']
- if config.exists(pg_base) and not config.exists(proto_base):
- config.set(proto_base, value='tcp_udp')
-
- if '+' in name:
- replacement_string = "_"
- new_name = name.replace('+', replacement_string)
- while config.exists(base + ['ipv6-name', new_name]):
- replacement_string = replacement_string + "_"
+ elif tmp in icmpv6_translations:
+ translate = icmpv6_translations[tmp]
+ if isinstance(translate, str):
+ config.delete(rule_icmp + ['type'])
+ config.set(rule_icmp + ['type-name'], value=translate)
+ elif isinstance(translate, list):
+ config.set(rule_icmp + ['type'], value=translate[0])
+ config.set(rule_icmp + ['code'], value=translate[1])
+ else:
+ config.rename(rule_icmp + ['type'], 'type-name')
+
+ for direction in ['destination', 'source']:
+ if config.exists(base + ['ipv6-name', name, 'rule', rule, direction]):
+ if config.exists(base + ['ipv6-name', name, 'rule', rule, direction, 'group']) and v6_found:
+ for group_type in config.list_nodes(base + ['ipv6-name', name, 'rule', rule, direction, 'group']):
+ group_name = config.return_value(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type])
+ if '+' in group_name:
+ if group_name[0] == "!":
+ new_group_name = "!" + translated_dict[group_name[1:]]
+ else:
+ new_group_name = translated_dict[group_name]
+ config.set(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
+
+ pg_base = base + ['ipv6-name', name, 'rule', rule, direction, 'group', 'port-group']
+ proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol']
+ if config.exists(pg_base) and not config.exists(proto_base):
+ config.set(proto_base, value='tcp_udp')
+
+ if '+' in name:
+ replacement_string = "_"
new_name = name.replace('+', replacement_string)
- config.copy(base + ['ipv6-name', name], base + ['ipv6-name', new_name])
- config.delete(base + ['ipv6-name', name])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ while config.exists(base + ['ipv6-name', new_name]):
+ replacement_string = replacement_string + "_"
+ new_name = name.replace('+', replacement_string)
+ config.copy(base + ['ipv6-name', name], base + ['ipv6-name', new_name])
+ config.delete(base + ['ipv6-name', name])
diff --git a/src/migration-scripts/firewall/7-to-8 b/src/migration-scripts/firewall/7-to-8
index bbaba113a..f46994ce2 100755..100644
--- a/src/migration-scripts/firewall/7-to-8
+++ b/src/migration-scripts/firewall/7-to-8
@@ -1,43 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T2199: Migrate interface firewall nodes to firewall interfaces <ifname> <direction> name/ipv6-name <name>
# T2199: Migrate zone-policy to firewall node
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
zone_base = ['zone-policy']
-config = ConfigTree(config_file)
-
-if not config.exists(base) and not config.exists(zone_base):
- # Nothing to do
- exit(0)
def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
if_path = ['interfaces', iftype, ifname]
@@ -63,33 +45,31 @@ def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
config.copy(if_path + ['firewall'], ['firewall', 'interface', ifname_full])
config.delete(if_path + ['firewall'])
-for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- migrate_interface(config, iftype, ifname)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base) and not config.exists(zone_base):
+ # Nothing to do
+ return
- if config.exists(['interfaces', iftype, ifname, 'vif']):
- for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
- migrate_interface(config, iftype, ifname, vif=vif)
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ migrate_interface(config, iftype, ifname)
- if config.exists(['interfaces', iftype, ifname, 'vif-s']):
- for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
- migrate_interface(config, iftype, ifname, vifs=vifs)
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ migrate_interface(config, iftype, ifname, vif=vif)
- if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ migrate_interface(config, iftype, ifname, vifs=vifs)
-if config.exists(zone_base + ['zone']):
- config.set(['firewall', 'zone'])
- config.set_tag(['firewall', 'zone'])
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
- for zone in config.list_nodes(zone_base + ['zone']):
- config.copy(zone_base + ['zone', zone], ['firewall', 'zone', zone])
- config.delete(zone_base)
+ if config.exists(zone_base + ['zone']):
+ config.set(['firewall', 'zone'])
+ config.set_tag(['firewall', 'zone'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for zone in config.list_nodes(zone_base + ['zone']):
+ config.copy(zone_base + ['zone', zone], ['firewall', 'zone', zone])
+ config.delete(zone_base)
diff --git a/src/migration-scripts/firewall/8-to-9 b/src/migration-scripts/firewall/8-to-9
index 6e019beb2..3c9e84662 100755..100644
--- a/src/migration-scripts/firewall/8-to-9
+++ b/src/migration-scripts/firewall/8-to-9
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4780: Add firewall interface group
# cli changes from:
@@ -20,69 +19,50 @@
# To
# set firewall [name | ipv6-name] <name> rule <number> [inbound-interface | outbound-interface] [interface-name | interface-group] <interface_name | interface_group>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['name']):
- for name in config.list_nodes(base + ['name']):
- if not config.exists(base + ['name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['name', name, 'rule']):
- rule_iiface = base + ['name', name, 'rule', rule, 'inbound-interface']
- rule_oiface = base + ['name', name, 'rule', rule, 'outbound-interface']
-
- if config.exists(rule_iiface):
- tmp = config.return_value(rule_iiface)
- config.delete(rule_iiface)
- config.set(rule_iiface + ['interface-name'], value=tmp)
-
- if config.exists(rule_oiface):
- tmp = config.return_value(rule_oiface)
- config.delete(rule_oiface)
- config.set(rule_oiface + ['interface-name'], value=tmp)
-
-
-if config.exists(base + ['ipv6-name']):
- for name in config.list_nodes(base + ['ipv6-name']):
- if not config.exists(base + ['ipv6-name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
- rule_iiface = base + ['ipv6-name', name, 'rule', rule, 'inbound-interface']
- rule_oiface = base + ['ipv6-name', name, 'rule', rule, 'outbound-interface']
-
- if config.exists(rule_iiface):
- tmp = config.return_value(rule_iiface)
- config.delete(rule_iiface)
- config.set(rule_iiface + ['interface-name'], value=tmp)
-
- if config.exists(rule_oiface):
- tmp = config.return_value(rule_oiface)
- config.delete(rule_oiface)
- config.set(rule_oiface + ['interface-name'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['name']):
+ for name in config.list_nodes(base + ['name']):
+ if not config.exists(base + ['name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['name', name, 'rule']):
+ rule_iiface = base + ['name', name, 'rule', rule, 'inbound-interface']
+ rule_oiface = base + ['name', name, 'rule', rule, 'outbound-interface']
+
+ if config.exists(rule_iiface):
+ tmp = config.return_value(rule_iiface)
+ config.delete(rule_iiface)
+ config.set(rule_iiface + ['interface-name'], value=tmp)
+
+ if config.exists(rule_oiface):
+ tmp = config.return_value(rule_oiface)
+ config.delete(rule_oiface)
+ config.set(rule_oiface + ['interface-name'], value=tmp)
+
+
+ if config.exists(base + ['ipv6-name']):
+ for name in config.list_nodes(base + ['ipv6-name']):
+ if not config.exists(base + ['ipv6-name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
+ rule_iiface = base + ['ipv6-name', name, 'rule', rule, 'inbound-interface']
+ rule_oiface = base + ['ipv6-name', name, 'rule', rule, 'outbound-interface']
+
+ if config.exists(rule_iiface):
+ tmp = config.return_value(rule_iiface)
+ config.delete(rule_iiface)
+ config.set(rule_iiface + ['interface-name'], value=tmp)
+
+ if config.exists(rule_oiface):
+ tmp = config.return_value(rule_oiface)
+ config.delete(rule_oiface)
+ config.set(rule_oiface + ['interface-name'], value=tmp)
diff --git a/src/migration-scripts/firewall/9-to-10 b/src/migration-scripts/firewall/9-to-10
index ce509a731..306a53a86 100755..100644
--- a/src/migration-scripts/firewall/9-to-10
+++ b/src/migration-scripts/firewall/9-to-10
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5050: Log options
# cli changes from:
@@ -20,58 +19,39 @@
# To
# set firewall [name | ipv6-name] <name> rule <number> log-options level <log_level>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['name']):
- for name in config.list_nodes(base + ['name']):
- if not config.exists(base + ['name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['name', name, 'rule']):
- log_options_base = base + ['name', name, 'rule', rule, 'log-options']
- rule_log_level = base + ['name', name, 'rule', rule, 'log-level']
-
- if config.exists(rule_log_level):
- tmp = config.return_value(rule_log_level)
- config.delete(rule_log_level)
- config.set(log_options_base + ['level'], value=tmp)
-
-if config.exists(base + ['ipv6-name']):
- for name in config.list_nodes(base + ['ipv6-name']):
- if not config.exists(base + ['ipv6-name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
- log_options_base = base + ['ipv6-name', name, 'rule', rule, 'log-options']
- rule_log_level = base + ['ipv6-name', name, 'rule', rule, 'log-level']
-
- if config.exists(rule_log_level):
- tmp = config.return_value(rule_log_level)
- config.delete(rule_log_level)
- config.set(log_options_base + ['level'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['name']):
+ for name in config.list_nodes(base + ['name']):
+ if not config.exists(base + ['name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['name', name, 'rule']):
+ log_options_base = base + ['name', name, 'rule', rule, 'log-options']
+ rule_log_level = base + ['name', name, 'rule', rule, 'log-level']
+
+ if config.exists(rule_log_level):
+ tmp = config.return_value(rule_log_level)
+ config.delete(rule_log_level)
+ config.set(log_options_base + ['level'], value=tmp)
+
+ if config.exists(base + ['ipv6-name']):
+ for name in config.list_nodes(base + ['ipv6-name']):
+ if not config.exists(base + ['ipv6-name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
+ log_options_base = base + ['ipv6-name', name, 'rule', rule, 'log-options']
+ rule_log_level = base + ['ipv6-name', name, 'rule', rule, 'log-level']
+
+ if config.exists(rule_log_level):
+ tmp = config.return_value(rule_log_level)
+ config.delete(rule_log_level)
+ config.set(log_options_base + ['level'], value=tmp)
diff --git a/src/migration-scripts/flow-accounting/0-to-1 b/src/migration-scripts/flow-accounting/0-to-1
index 0f790fd9c..77670e3ef 100755..100644
--- a/src/migration-scripts/flow-accounting/0-to-1
+++ b/src/migration-scripts/flow-accounting/0-to-1
@@ -1,69 +1,51 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4099: flow-accounting: sync "source-ip" and "source-address" between netflow
# and sflow ion CLI
# T4105: flow-accounting: drop "sflow agent-address auto"
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'flow-accounting']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# T4099
-tmp = base + ['netflow', 'source-ip']
-if config.exists(tmp):
- config.rename(tmp, 'source-address')
-
-# T4105
-tmp = base + ['sflow', 'agent-address']
-if config.exists(tmp):
- value = config.return_value(tmp)
- if value == 'auto':
- # delete the "auto"
- config.delete(tmp)
-
- # 1) check if BGP router-id is set
- # 2) check if OSPF router-id is set
- # 3) check if OSPFv3 router-id is set
- router_id = None
- for protocol in ['bgp', 'ospf', 'ospfv3']:
- if config.exists(['protocols', protocol, 'parameters', 'router-id']):
- router_id = config.return_value(['protocols', protocol, 'parameters', 'router-id'])
- break
- if router_id:
- config.set(tmp, value=router_id)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # T4099
+ tmp = base + ['netflow', 'source-ip']
+ if config.exists(tmp):
+ config.rename(tmp, 'source-address')
+
+ # T4105
+ tmp = base + ['sflow', 'agent-address']
+ if config.exists(tmp):
+ value = config.return_value(tmp)
+ if value == 'auto':
+ # delete the "auto"
+ config.delete(tmp)
+
+ # 1) check if BGP router-id is set
+ # 2) check if OSPF router-id is set
+ # 3) check if OSPFv3 router-id is set
+ router_id = None
+ for protocol in ['bgp', 'ospf', 'ospfv3']:
+ if config.exists(['protocols', protocol, 'parameters', 'router-id']):
+ router_id = config.return_value(['protocols', protocol, 'parameters', 'router-id'])
+ break
+ if router_id:
+ config.set(tmp, value=router_id)
diff --git a/src/migration-scripts/https/0-to-1 b/src/migration-scripts/https/0-to-1
index 23809f5ad..52fe3f2ad 100755..100644
--- a/src/migration-scripts/https/0-to-1
+++ b/src/migration-scripts/https/0-to-1
@@ -1,42 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# * Move server block directives under 'virtual-host' tag node, instead of
# relying on 'listen-address' tag node
-import sys
-
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+old_base = ['service', 'https', 'listen-address']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
-old_base = ['service', 'https', 'listen-address']
-if not config.exists(old_base):
- # Nothing to do
- sys.exit(0)
-else:
new_base = ['service', 'https', 'virtual-host']
config.set(new_base)
config.set_tag(new_base)
@@ -60,10 +48,3 @@ else:
index += 1
config.delete(old_base)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/https/1-to-2 b/src/migration-scripts/https/1-to-2
index 1a2cdc1e7..dad7ac1f0 100755..100644
--- a/src/migration-scripts/https/1-to-2
+++ b/src/migration-scripts/https/1-to-2
@@ -1,42 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# * Move 'api virtual-host' list to 'api-restrict virtual-host' so it
# is owned by service_https.py
-import sys
-
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+old_base = ['service', 'https', 'api', 'virtual-host']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
-old_base = ['service', 'https', 'api', 'virtual-host']
-if not config.exists(old_base):
- # Nothing to do
- sys.exit(0)
-else:
new_base = ['service', 'https', 'api-restrict', 'virtual-host']
config.set(new_base)
@@ -45,10 +33,3 @@ else:
config.set(new_base, value=name, replace=False)
config.delete(old_base)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/https/2-to-3 b/src/migration-scripts/https/2-to-3
index 2beba6d2b..1125caebf 100755..100644
--- a/src/migration-scripts/https/2-to-3
+++ b/src/migration-scripts/https/2-to-3
@@ -1,23 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# * Migrate system signed certificate to use PKI
-import sys
-
from vyos.configtree import ConfigTree
from vyos.pki import create_certificate
from vyos.pki import create_certificate_request
@@ -25,23 +22,9 @@ from vyos.pki import create_private_key
from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'https', 'certificates']
pki_base = ['pki']
-if not config.exists(base + ['system-generated-certificate']):
- sys.exit(0)
-
def wrapped_pem_to_config_value(pem):
out = []
for line in pem.strip().split("\n"):
@@ -50,37 +33,34 @@ def wrapped_pem_to_config_value(pem):
out.append(line)
return "".join(out)
-if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['system-generated-certificate']):
+ return
-valid_days = 365
-if config.exists(base + ['system-generated-certificate', 'lifetime']):
- valid_days = int(config.return_value(base + ['system-generated-certificate', 'lifetime']))
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
-key = create_private_key('rsa', 2048)
-subject = {'country': 'GB', 'state': 'N/A', 'locality': 'N/A', 'organization': 'VyOS', 'common_name': 'vyos'}
-cert_req = create_certificate_request(subject, key, ['vyos'])
-cert = create_certificate(cert_req, cert_req, key, valid_days)
+ valid_days = 365
+ if config.exists(base + ['system-generated-certificate', 'lifetime']):
+ valid_days = int(config.return_value(base + ['system-generated-certificate', 'lifetime']))
-if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', 'generated_https', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ key = create_private_key('rsa', 2048)
+ subject = {'country': 'GB', 'state': 'N/A', 'locality': 'N/A', 'organization': 'VyOS', 'common_name': 'vyos'}
+ cert_req = create_certificate_request(subject, key, ['vyos'])
+ cert = create_certificate(cert_req, cert_req, key, valid_days)
-if key:
- key_pem = encode_private_key(key)
- config.set(pki_base + ['certificate', 'generated_https', 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', 'generated_https', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
-if cert and key:
- config.set(base + ['certificate'], value='generated_https')
-else:
- print('Failed to migrate system-generated-certificate from https service')
+ if key:
+ key_pem = encode_private_key(key)
+ config.set(pki_base + ['certificate', 'generated_https', 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
-config.delete(base + ['system-generated-certificate'])
+ if cert and key:
+ config.set(base + ['certificate'], value='generated_https')
+ else:
+ print('Failed to migrate system-generated-certificate from https service')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.delete(base + ['system-generated-certificate'])
diff --git a/src/migration-scripts/https/3-to-4 b/src/migration-scripts/https/3-to-4
index b3cfca201..c01236cc6 100755..100644
--- a/src/migration-scripts/https/3-to-4
+++ b/src/migration-scripts/https/3-to-4
@@ -1,53 +1,34 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4768 rename node 'gql' to 'graphql'.
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
old_base = ['service', 'https', 'api', 'gql']
-if not config.exists(old_base):
- # Nothing to do
- sys.exit(0)
-
new_base = ['service', 'https', 'api', 'graphql']
-config.set(new_base)
-nodes = config.list_nodes(old_base)
-for node in nodes:
- config.copy(old_base + [node], new_base + [node])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
+
+ config.set(new_base)
-config.delete(old_base)
+ nodes = config.list_nodes(old_base)
+ for node in nodes:
+ config.copy(old_base + [node], new_base + [node])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.delete(old_base)
diff --git a/src/migration-scripts/https/4-to-5 b/src/migration-scripts/https/4-to-5
index 0dfb6ac19..0f1c7901f 100755..100644
--- a/src/migration-scripts/https/4-to-5
+++ b/src/migration-scripts/https/4-to-5
@@ -1,62 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5762: http: api: smoketests fail as they can not establish IPv6 connection
# to uvicorn backend server, always make the UNIX domain socket the
# default way of communication
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'https']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
-# Delete "socket" CLI option - we always use UNIX domain sockets for
-# NGINX <-> API server communication
-if config.exists(base + ['api', 'socket']):
- config.delete(base + ['api', 'socket'])
-
-# There is no need for an API service port, as UNIX domain sockets
-# are used
-if config.exists(base + ['api', 'port']):
- config.delete(base + ['api', 'port'])
-
-# rename listen-port -> port ver virtual-host
-if config.exists(base + ['virtual-host']):
- for vhost in config.list_nodes(base + ['virtual-host']):
- if config.exists(base + ['virtual-host', vhost, 'listen-port']):
- config.rename(base + ['virtual-host', vhost, 'listen-port'], 'port')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Delete "socket" CLI option - we always use UNIX domain sockets for
+ # NGINX <-> API server communication
+ if config.exists(base + ['api', 'socket']):
+ config.delete(base + ['api', 'socket'])
+
+ # There is no need for an API service port, as UNIX domain sockets
+ # are used
+ if config.exists(base + ['api', 'port']):
+ config.delete(base + ['api', 'port'])
+
+ # rename listen-port -> port ver virtual-host
+ if config.exists(base + ['virtual-host']):
+ for vhost in config.list_nodes(base + ['virtual-host']):
+ if config.exists(base + ['virtual-host', vhost, 'listen-port']):
+ config.rename(base + ['virtual-host', vhost, 'listen-port'], 'port')
diff --git a/src/migration-scripts/https/5-to-6 b/src/migration-scripts/https/5-to-6
index 72e9e31f7..6ef6976b6 100755..100644
--- a/src/migration-scripts/https/5-to-6
+++ b/src/migration-scripts/https/5-to-6
@@ -1,25 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5886: Add support for ACME protocol (LetsEncrypt), migrate https certbot
# to new "pki certificate" CLI tree
# T5902: Remove virtual-host
import os
-import sys
from vyos.configtree import ConfigTree
from vyos.defaults import directories
@@ -27,81 +25,65 @@ from vyos.utils.process import cmd
vyos_certbot_dir = directories['certbot']
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'https']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
-if config.exists(base + ['certificates', 'certbot']):
- # both domain-name and email must be set on CLI - ensured by previous verify()
- domain_names = config.return_values(base + ['certificates', 'certbot', 'domain-name'])
- email = config.return_value(base + ['certificates', 'certbot', 'email'])
- config.delete(base + ['certificates', 'certbot'])
-
- # Set default certname based on domain-name
- cert_name = 'https-' + domain_names[0].split('.')[0]
- # Overwrite certname from previous certbot calls if available
- # We can not use python code like os.scandir due to filesystem permissions.
- # This must be run as root
- certbot_live = f'{vyos_certbot_dir}/live/' # we need the trailing /
- if os.path.exists(certbot_live):
- tmp = cmd(f'sudo find {certbot_live} -maxdepth 1 -type d')
- tmp = tmp.split() # tmp = ['/config/auth/letsencrypt/live', '/config/auth/letsencrypt/live/router.vyos.net']
- tmp.remove(certbot_live)
- cert_name = tmp[0].replace(certbot_live, '')
- config.set(['pki', 'certificate', cert_name, 'acme', 'email'], value=email)
- config.set_tag(['pki', 'certificate'])
- for domain in domain_names:
- config.set(['pki', 'certificate', cert_name, 'acme', 'domain-name'], value=domain, replace=False)
-
- # Update Webserver certificate
- config.set(base + ['certificates', 'certificate'], value=cert_name)
-
-if config.exists(base + ['virtual-host']):
- allow_client = []
- listen_port = []
- listen_address = []
- for virtual_host in config.list_nodes(base + ['virtual-host']):
- allow_path = base + ['virtual-host', virtual_host, 'allow-client', 'address']
- if config.exists(allow_path):
- tmp = config.return_values(allow_path)
- allow_client.extend(tmp)
-
- port_path = base + ['virtual-host', virtual_host, 'port']
- if config.exists(port_path):
- tmp = config.return_value(port_path)
- listen_port.append(tmp)
-
- listen_address_path = base + ['virtual-host', virtual_host, 'listen-address']
- if config.exists(listen_address_path):
- tmp = config.return_value(listen_address_path)
- listen_address.append(tmp)
-
- config.delete(base + ['virtual-host'])
- for client in allow_client:
- config.set(base + ['allow-client', 'address'], value=client, replace=False)
-
- # clear listen-address if "all" were specified
- if '*' in listen_address:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['certificates', 'certbot']):
+ # both domain-name and email must be set on CLI - ensured by previous verify()
+ domain_names = config.return_values(base + ['certificates', 'certbot', 'domain-name'])
+ email = config.return_value(base + ['certificates', 'certbot', 'email'])
+ config.delete(base + ['certificates', 'certbot'])
+
+ # Set default certname based on domain-name
+ cert_name = 'https-' + domain_names[0].split('.')[0]
+ # Overwrite certname from previous certbot calls if available
+ # We can not use python code like os.scandir due to filesystem permissions.
+ # This must be run as root
+ certbot_live = f'{vyos_certbot_dir}/live/' # we need the trailing /
+ if os.path.exists(certbot_live):
+ tmp = cmd(f'sudo find {certbot_live} -maxdepth 1 -type d')
+ tmp = tmp.split() # tmp = ['/config/auth/letsencrypt/live', '/config/auth/letsencrypt/live/router.vyos.net']
+ tmp.remove(certbot_live)
+ cert_name = tmp[0].replace(certbot_live, '')
+
+ config.set(['pki', 'certificate', cert_name, 'acme', 'email'], value=email)
+ config.set_tag(['pki', 'certificate'])
+ for domain in domain_names:
+ config.set(['pki', 'certificate', cert_name, 'acme', 'domain-name'], value=domain, replace=False)
+
+ # Update Webserver certificate
+ config.set(base + ['certificates', 'certificate'], value=cert_name)
+
+ if config.exists(base + ['virtual-host']):
+ allow_client = []
+ listen_port = []
listen_address = []
- for address in listen_address:
- config.set(base + ['listen-address'], value=address, replace=False)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ for virtual_host in config.list_nodes(base + ['virtual-host']):
+ allow_path = base + ['virtual-host', virtual_host, 'allow-client', 'address']
+ if config.exists(allow_path):
+ tmp = config.return_values(allow_path)
+ allow_client.extend(tmp)
+
+ port_path = base + ['virtual-host', virtual_host, 'port']
+ if config.exists(port_path):
+ tmp = config.return_value(port_path)
+ listen_port.append(tmp)
+
+ listen_address_path = base + ['virtual-host', virtual_host, 'listen-address']
+ if config.exists(listen_address_path):
+ tmp = config.return_value(listen_address_path)
+ listen_address.append(tmp)
+
+ config.delete(base + ['virtual-host'])
+ for client in allow_client:
+ config.set(base + ['allow-client', 'address'], value=client, replace=False)
+
+ # clear listen-address if "all" were specified
+ if '*' in listen_address:
+ listen_address = []
+ for address in listen_address:
+ config.set(base + ['listen-address'], value=address, replace=False)
diff --git a/src/migration-scripts/ids/0-to-1 b/src/migration-scripts/ids/0-to-1
index 8b7850a1a..1b963e839 100755..100644
--- a/src/migration-scripts/ids/0-to-1
+++ b/src/migration-scripts/ids/0-to-1
@@ -1,56 +1,38 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
+# T4557: Migrate threshold and add new threshold types
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'ids', 'ddos-protection']
-config = ConfigTree(config_file)
-
-if not config.exists(base + ['threshold']):
- # Nothing to do
- exit(0)
-else:
- if config.exists(base + ['threshold', 'fps']):
- tmp = config.return_value(base + ['threshold', 'fps'])
- config.delete(base + ['threshold', 'fps'])
- config.set(base + ['threshold', 'general', 'fps'], value=tmp)
- if config.exists(base + ['threshold', 'mbps']):
- tmp = config.return_value(base + ['threshold', 'mbps'])
- config.delete(base + ['threshold', 'mbps'])
- config.set(base + ['threshold', 'general', 'mbps'], value=tmp)
- if config.exists(base + ['threshold', 'pps']):
- tmp = config.return_value(base + ['threshold', 'pps'])
- config.delete(base + ['threshold', 'pps'])
- config.set(base + ['threshold', 'general', 'pps'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['threshold']):
+ # Nothing to do
+ return
+ else:
+ if config.exists(base + ['threshold', 'fps']):
+ tmp = config.return_value(base + ['threshold', 'fps'])
+ config.delete(base + ['threshold', 'fps'])
+ config.set(base + ['threshold', 'general', 'fps'], value=tmp)
+ if config.exists(base + ['threshold', 'mbps']):
+ tmp = config.return_value(base + ['threshold', 'mbps'])
+ config.delete(base + ['threshold', 'mbps'])
+ config.set(base + ['threshold', 'general', 'mbps'], value=tmp)
+ if config.exists(base + ['threshold', 'pps']):
+ tmp = config.return_value(base + ['threshold', 'pps'])
+ config.delete(base + ['threshold', 'pps'])
+ config.set(base + ['threshold', 'general', 'pps'], value=tmp)
diff --git a/src/migration-scripts/interfaces/0-to-1 b/src/migration-scripts/interfaces/0-to-1
index 25f6842eb..7c135e76e 100755..100644
--- a/src/migration-scripts/interfaces/0-to-1
+++ b/src/migration-scripts/interfaces/0-to-1
@@ -1,11 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Change syntax of bridge interface
# - move interface based bridge-group to actual bridge (de-nest)
# - make stp and igmp-snooping nodes valueless
# https://vyos.dev/T1556
-import sys
from vyos.configtree import ConfigTree
def migrate_bridge(config, tree, intf):
@@ -36,83 +48,66 @@ def migrate_bridge(config, tree, intf):
config.delete(tree_bridge)
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'bridge']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
- else:
- #
- # make stp and igmp-snooping nodes valueless
- #
- for br in config.list_nodes(base):
- # STP: check if enabled
- if config.exists(base + [br, 'stp']):
- stp_val = config.return_value(base + [br, 'stp'])
- # STP: delete node with old syntax
- config.delete(base + [br, 'stp'])
- # STP: set new node - if enabled
- if stp_val == "true":
- config.set(base + [br, 'stp'], value=None)
-
- # igmp-snooping: check if enabled
- if config.exists(base + [br, 'igmp-snooping', 'querier']):
- igmp_val = config.return_value(base + [br, 'igmp-snooping', 'querier'])
- # igmp-snooping: delete node with old syntax
- config.delete(base + [br, 'igmp-snooping', 'querier'])
- # igmp-snooping: set new node - if enabled
- if igmp_val == "enable":
- config.set(base + [br, 'igmp', 'querier'], value=None)
-
- #
- # move interface based bridge-group to actual bridge (de-nest)
- #
- bridge_types = ['bonding', 'ethernet', 'l2tpv3', 'openvpn', 'vxlan', 'wireless']
- for type in bridge_types:
- if not config.exists(['interfaces', type]):
- continue
-
- for interface in config.list_nodes(['interfaces', type]):
- # check if bridge-group exists
- bridge_group = ['interfaces', type, interface]
- if config.exists(bridge_group + ['bridge-group']):
- migrate_bridge(config, bridge_group, interface)
-
- # We also need to migrate VLAN interfaces
- vlan_base = ['interfaces', type, interface, 'vif']
- if config.exists(vlan_base):
- for vlan in config.list_nodes(vlan_base):
- intf = "{}.{}".format(interface, vlan)
- migrate_bridge(config, vlan_base + [vlan], intf)
-
- # And then we have service VLANs (vif-s) interfaces
- vlan_base = ['interfaces', type, interface, 'vif-s']
- if config.exists(vlan_base):
- for vif_s in config.list_nodes(vlan_base):
- intf = "{}.{}".format(interface, vif_s)
- migrate_bridge(config, vlan_base + [vif_s], intf)
-
- # Every service VLAN can have multiple customer VLANs (vif-c)
- vlan_c = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
- if config.exists(vlan_c):
- for vif_c in config.list_nodes(vlan_c):
- intf = "{}.{}.{}".format(interface, vif_s, vif_c)
- migrate_bridge(config, vlan_c + [vif_c], intf)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ return
+
+ #
+ # make stp and igmp-snooping nodes valueless
+ #
+ for br in config.list_nodes(base):
+ # STP: check if enabled
+ if config.exists(base + [br, 'stp']):
+ stp_val = config.return_value(base + [br, 'stp'])
+ # STP: delete node with old syntax
+ config.delete(base + [br, 'stp'])
+ # STP: set new node - if enabled
+ if stp_val == "true":
+ config.set(base + [br, 'stp'], value=None)
+
+ # igmp-snooping: check if enabled
+ if config.exists(base + [br, 'igmp-snooping', 'querier']):
+ igmp_val = config.return_value(base + [br, 'igmp-snooping', 'querier'])
+ # igmp-snooping: delete node with old syntax
+ config.delete(base + [br, 'igmp-snooping', 'querier'])
+ # igmp-snooping: set new node - if enabled
+ if igmp_val == "enable":
+ config.set(base + [br, 'igmp', 'querier'], value=None)
+
+ #
+ # move interface based bridge-group to actual bridge (de-nest)
+ #
+ bridge_types = ['bonding', 'ethernet', 'l2tpv3', 'openvpn', 'vxlan', 'wireless']
+ for type in bridge_types:
+ if not config.exists(['interfaces', type]):
+ continue
+
+ for interface in config.list_nodes(['interfaces', type]):
+ # check if bridge-group exists
+ bridge_group = ['interfaces', type, interface]
+ if config.exists(bridge_group + ['bridge-group']):
+ migrate_bridge(config, bridge_group, interface)
+
+ # We also need to migrate VLAN interfaces
+ vlan_base = ['interfaces', type, interface, 'vif']
+ if config.exists(vlan_base):
+ for vlan in config.list_nodes(vlan_base):
+ intf = "{}.{}".format(interface, vlan)
+ migrate_bridge(config, vlan_base + [vlan], intf)
+
+ # And then we have service VLANs (vif-s) interfaces
+ vlan_base = ['interfaces', type, interface, 'vif-s']
+ if config.exists(vlan_base):
+ for vif_s in config.list_nodes(vlan_base):
+ intf = "{}.{}".format(interface, vif_s)
+ migrate_bridge(config, vlan_base + [vif_s], intf)
+
+ # Every service VLAN can have multiple customer VLANs (vif-c)
+ vlan_c = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
+ if config.exists(vlan_c):
+ for vif_c in config.list_nodes(vlan_c):
+ intf = "{}.{}.{}".format(interface, vif_s, vif_c)
+ migrate_bridge(config, vlan_c + [vif_c], intf)
diff --git a/src/migration-scripts/interfaces/1-to-2 b/src/migration-scripts/interfaces/1-to-2
index c95623c2b..ebf02b028 100755..100644
--- a/src/migration-scripts/interfaces/1-to-2
+++ b/src/migration-scripts/interfaces/1-to-2
@@ -1,28 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Change syntax of bond interface
# - move interface based bond-group to actual bond (de-nest)
# https://vyos.dev/T1614
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['interfaces', 'bonding']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
#
# move interface based bond-group to actual bond (de-nest)
#
@@ -54,10 +57,3 @@ else:
#
# so we simply disable arp_interval by setting it to 0 and miimon will take care about the link
config.set(base + [bond, 'arp-monitor', 'interval'], value='0')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/10-to-11 b/src/migration-scripts/interfaces/10-to-11
index cafaa3fa4..8a562f2d0 100755..100644
--- a/src/migration-scripts/interfaces/10-to-11
+++ b/src/migration-scripts/interfaces/10-to-11
@@ -1,41 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# rename WWAN (wirelessmodem) serial interface from non persistent ttyUSB2 to
# a bus like name, e.g. "usb0b1.3p1.3"
import os
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
+base = ['interfaces', 'wirelessmodem']
- config = ConfigTree(config_file)
- base = ['interfaces', 'wirelessmodem']
+def migrate(config: ConfigTree) -> None:
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
for wwan in config.list_nodes(base):
if config.exists(base + [wwan, 'device']):
@@ -46,10 +36,3 @@ if __name__ == '__main__':
device_file = os.path.realpath(os.path.join(root, file))
if os.path.basename(device_file) == device:
config.set(base + [wwan, 'device'], value=file, replace=True)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/11-to-12 b/src/migration-scripts/interfaces/11-to-12
index e9eb7f939..132cecbb7 100755..100644
--- a/src/migration-scripts/interfaces/11-to-12
+++ b/src/migration-scripts/interfaces/11-to-12
@@ -1,37 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - rename 'dhcpv6-options prefix-delegation' from single node to a new tag node
# 'dhcpv6-options pd 0'
# - delete 'sla-len' from CLI - value is calculated on demand
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
for type in config.list_nodes(['interfaces']):
for interface in config.list_nodes(['interfaces', type]):
# cache current config tree
@@ -49,10 +37,3 @@ if __name__ == '__main__':
sla_config = new_base + [pd, 'interface', tmp, 'sla-len']
if config.exists(sla_config):
config.delete(sla_config)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/12-to-13 b/src/migration-scripts/interfaces/12-to-13
index ef1d93903..585deb898 100755..100644
--- a/src/migration-scripts/interfaces/12-to-13
+++ b/src/migration-scripts/interfaces/12-to-13
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T2903: Change vif-s ethertype from numeric number to literal
# - 0x88a8 -> 802.1ad
@@ -20,20 +19,9 @@
# - T2905: Change WWAN "ondemand" node to "connect-on-demand" to have identical
# CLI nodes for both types of dialer interfaces
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
#
# T2903
#
@@ -61,11 +49,3 @@ if __name__ == '__main__':
for interface in config.list_nodes(wwan_base):
if config.exists(wwan_base + [interface, 'ondemand']):
config.rename(wwan_base + [interface, 'ondemand'], 'connect-on-demand')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
diff --git a/src/migration-scripts/interfaces/13-to-14 b/src/migration-scripts/interfaces/13-to-14
index b20d8b4db..45d8e3b5f 100755..100644
--- a/src/migration-scripts/interfaces/13-to-14
+++ b/src/migration-scripts/interfaces/13-to-14
@@ -1,39 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3043: rename Wireless interface security mode 'both' to 'wpa+wpa2'
# T3043: move "system wifi-regulatory-domain" to indicidual wireless interface
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wireless']
+
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
country_code = ''
cc_cli = ['system', 'wifi-regulatory-domain']
@@ -50,10 +40,3 @@ if __name__ == '__main__':
if country_code:
config.set(base + [wifi, 'country-code'], value=country_code)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/14-to-15 b/src/migration-scripts/interfaces/14-to-15
index e21251f86..d45d59bba 100755..100644
--- a/src/migration-scripts/interfaces/14-to-15
+++ b/src/migration-scripts/interfaces/14-to-15
@@ -1,39 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3048: remove smp-affinity node from ethernet and use tuned instead
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'ethernet']
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
migrate = False
for interface in config.list_nodes(base):
@@ -47,10 +36,3 @@ if __name__ == '__main__':
if migrate:
config.set(['system', 'options', 'performance'], value='throughput')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/15-to-16 b/src/migration-scripts/interfaces/15-to-16
index ae3441b9f..c9abdb5f8 100755..100644
--- a/src/migration-scripts/interfaces/15-to-16
+++ b/src/migration-scripts/interfaces/15-to-16
@@ -1,48 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# remove pppoe "ipv6 enable" option
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'pppoe']
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
for interface in config.list_nodes(base):
ipv6_enable = base + [interface, 'ipv6', 'enable']
if config.exists(ipv6_enable):
config.delete(ipv6_enable)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/16-to-17 b/src/migration-scripts/interfaces/16-to-17
index 75f160686..7d241ac68 100755..100644
--- a/src/migration-scripts/interfaces/16-to-17
+++ b/src/migration-scripts/interfaces/16-to-17
@@ -1,40 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Command line migration of port mirroring
# https://vyos.dev/T3089
-import sys
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'ethernet']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
+ return
for interface in config.list_nodes(base):
mirror_old_base = base + [interface, 'mirror']
@@ -43,10 +31,3 @@ if __name__ == '__main__':
if config.exists(mirror_old_base):
config.delete(mirror_old_base)
config.set(mirror_old_base + ['ingress'],intf[0])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/17-to-18 b/src/migration-scripts/interfaces/17-to-18
index 51486ac37..f45695a88 100755..100644
--- a/src/migration-scripts/interfaces/17-to-18
+++ b/src/migration-scripts/interfaces/17-to-18
@@ -1,37 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3043: Move "system wifi-regulatory-domain" to indicidual wireless interface.
# Country Code will be migratred from upper to lower case.
# T3140: Relax ethernet interface offload-options
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
# T3140: Cleanup ethernet offload-options, remove on/off value and use
# valueless nodes instead.
eth_base = ['interfaces', 'ethernet']
@@ -62,10 +50,3 @@ if __name__ == '__main__':
if config.exists(ccode):
tmp = config.return_value(ccode)
config.set(ccode, value=tmp.lower(), replace=True)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19
index c3209f250..ae1a07adb 100755..100644
--- a/src/migration-scripts/interfaces/18-to-19
+++ b/src/migration-scripts/interfaces/18-to-19
@@ -1,24 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
import os
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
def replace_nat_interfaces(config, old, new):
@@ -40,21 +36,11 @@ def replace_nat_interfaces(config, old, new):
config.set(conf_rule + ['outbound-interface'], value=new)
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wirelessmodem']
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
new_base = ['interfaces', 'wwan']
config.set(new_base)
@@ -98,10 +84,3 @@ if __name__ == '__main__':
# the new wwan interface use regular IP addressing
config.set(new_base + [interface, 'address'], value='dhcp')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20
index 05abae898..7ee6302e2 100755..100644
--- a/src/migration-scripts/interfaces/19-to-20
+++ b/src/migration-scripts/interfaces/19-to-20
@@ -1,34 +1,21 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
for type in ['tunnel', 'l2tpv3']:
base = ['interfaces', type]
if not config.exists(base):
@@ -52,10 +39,3 @@ if __name__ == '__main__':
remote_ip_path = base + [interface, 'remote-ip']
if config.exists(remote_ip_path):
config.rename(remote_ip_path, 'remote')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/2-to-3 b/src/migration-scripts/interfaces/2-to-3
index 15c3bc8be..695dcbf7a 100755..100644
--- a/src/migration-scripts/interfaces/2-to-3
+++ b/src/migration-scripts/interfaces/2-to-3
@@ -1,28 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Change syntax of openvpn encryption settings
# - move cipher from encryption to encryption cipher
# https://vyos.dev/T1704
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['interfaces', 'openvpn']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+
+ if not config.exists(base):
+ # Nothing to do
+ return
#
# move cipher from "encryption" to "encryption cipher"
#
@@ -35,9 +38,3 @@ else:
config.delete(['interfaces', 'openvpn', intf, 'encryption'])
# Add new syntax to config
config.set(['interfaces', 'openvpn', intf, 'encryption', 'cipher'], value=cipher)
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/20-to-21 b/src/migration-scripts/interfaces/20-to-21
index 14ad0fe4d..0b6895177 100755..100644
--- a/src/migration-scripts/interfaces/20-to-21
+++ b/src/migration-scripts/interfaces/20-to-21
@@ -1,120 +1,107 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3619: mirror Linux Kernel defaults for ethernet offloading options into VyOS
# CLI. See https://vyos.dev/T3619#102254 for all the details.
# T3787: Remove deprecated UDP fragmentation offloading option
-from sys import argv
-
from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
+from vyos.utils.network import interface_exists
base = ['interfaces', 'ethernet']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-
-for ifname in config.list_nodes(base):
- eth = Ethtool(ifname)
-
- # If GRO is enabled by the Kernel - we reflect this on the CLI. If GRO is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'gro'])
- enabled, fixed = eth.get_generic_receive_offload()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'gro'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'gro'])
-
- # If GSO is enabled by the Kernel - we reflect this on the CLI. If GSO is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'gso'])
- enabled, fixed = eth.get_generic_segmentation_offload()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'gso'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'gso'])
-
- # If LRO is enabled by the Kernel - we reflect this on the CLI. If LRO is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'lro'])
- enabled, fixed = eth.get_large_receive_offload()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'lro'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'lro'])
-
- # If SG is enabled by the Kernel - we reflect this on the CLI. If SG is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'sg'])
- enabled, fixed = eth.get_scatter_gather()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'sg'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'sg'])
-
- # If TSO is enabled by the Kernel - we reflect this on the CLI. If TSO is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'tso'])
- enabled, fixed = eth.get_tcp_segmentation_offload()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'tso'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'tso'])
-
- # Remove deprecated UDP fragmentation offloading option
- if config.exists(base + [ifname, 'offload', 'ufo']):
- config.delete(base + [ifname, 'offload', 'ufo'])
-
- # Also while processing the interface configuration, not all adapters support
- # changing the speed and duplex settings. If the desired speed and duplex
- # values do not work for the NIC driver, we change them back to the default
- # value of "auto" - which will be applied if the CLI node is deleted.
- speed_path = base + [ifname, 'speed']
- duplex_path = base + [ifname, 'duplex']
- # speed and duplex must always be set at the same time if not set to "auto"
- if config.exists(speed_path) and config.exists(duplex_path):
- speed = config.return_value(speed_path)
- duplex = config.return_value(duplex_path)
- if speed != 'auto' and duplex != 'auto':
- if not eth.check_speed_duplex(speed, duplex):
- config.delete(speed_path)
- config.delete(duplex_path)
-
- # Also while processing the interface configuration, not all adapters support
- # changing disabling flow-control - or change this setting. If disabling
- # flow-control is not supported by the NIC, we remove the setting from CLI
- flow_control_path = base + [ifname, 'disable-flow-control']
- if config.exists(flow_control_path):
- if not eth.check_flow_control():
- config.delete(flow_control_path)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ for ifname in config.list_nodes(base):
+ # Bail out early if interface vanished from system
+ if not interface_exists(ifname):
+ continue
+
+ eth = Ethtool(ifname)
+
+ # If GRO is enabled by the Kernel - we reflect this on the CLI. If GRO is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'gro'])
+ enabled, fixed = eth.get_generic_receive_offload()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'gro'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'gro'])
+
+ # If GSO is enabled by the Kernel - we reflect this on the CLI. If GSO is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'gso'])
+ enabled, fixed = eth.get_generic_segmentation_offload()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'gso'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'gso'])
+
+ # If LRO is enabled by the Kernel - we reflect this on the CLI. If LRO is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'lro'])
+ enabled, fixed = eth.get_large_receive_offload()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'lro'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'lro'])
+
+ # If SG is enabled by the Kernel - we reflect this on the CLI. If SG is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'sg'])
+ enabled, fixed = eth.get_scatter_gather()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'sg'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'sg'])
+
+ # If TSO is enabled by the Kernel - we reflect this on the CLI. If TSO is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'tso'])
+ enabled, fixed = eth.get_tcp_segmentation_offload()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'tso'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'tso'])
+
+ # Remove deprecated UDP fragmentation offloading option
+ if config.exists(base + [ifname, 'offload', 'ufo']):
+ config.delete(base + [ifname, 'offload', 'ufo'])
+
+ # Also while processing the interface configuration, not all adapters support
+ # changing the speed and duplex settings. If the desired speed and duplex
+ # values do not work for the NIC driver, we change them back to the default
+ # value of "auto" - which will be applied if the CLI node is deleted.
+ speed_path = base + [ifname, 'speed']
+ duplex_path = base + [ifname, 'duplex']
+ # speed and duplex must always be set at the same time if not set to "auto"
+ if config.exists(speed_path) and config.exists(duplex_path):
+ speed = config.return_value(speed_path)
+ duplex = config.return_value(duplex_path)
+ if speed != 'auto' and duplex != 'auto':
+ if not eth.check_speed_duplex(speed, duplex):
+ config.delete(speed_path)
+ config.delete(duplex_path)
+
+ # Also while processing the interface configuration, not all adapters support
+ # changing disabling flow-control - or change this setting. If disabling
+ # flow-control is not supported by the NIC, we remove the setting from CLI
+ flow_control_path = base + [ifname, 'disable-flow-control']
+ if config.exists(flow_control_path):
+ if not eth.check_flow_control():
+ config.delete(flow_control_path)
diff --git a/src/migration-scripts/interfaces/21-to-22 b/src/migration-scripts/interfaces/21-to-22
index 1838eb1c0..046eb10c6 100755..100644
--- a/src/migration-scripts/interfaces/21-to-22
+++ b/src/migration-scripts/interfaces/21-to-22
@@ -1,46 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-base = ['interfaces', 'tunnel']
-
-if not config.exists(base):
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ base = ['interfaces', 'tunnel']
-for interface in config.list_nodes(base):
- path = base + [interface, 'dhcp-interface']
- if config.exists(path):
- tmp = config.return_value(path)
- config.delete(path)
- config.set(base + [interface, 'source-interface'], value=tmp)
+ if not config.exists(base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for interface in config.list_nodes(base):
+ path = base + [interface, 'dhcp-interface']
+ if config.exists(path):
+ tmp = config.return_value(path)
+ config.delete(path)
+ config.set(base + [interface, 'source-interface'], value=tmp)
diff --git a/src/migration-scripts/interfaces/22-to-23 b/src/migration-scripts/interfaces/22-to-23
index 04e023e77..31f7fa2ff 100755..100644
--- a/src/migration-scripts/interfaces/22-to-23
+++ b/src/migration-scripts/interfaces/22-to-23
@@ -1,39 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# Deletes Wireguard peers if they have the same public key as the router has.
-import sys
+
from vyos.configtree import ConfigTree
from vyos.utils.network import is_wireguard_key_pair
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wireguard']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
+ return
+
for interface in config.list_nodes(base):
if not config.exists(base + [interface, 'private-key']):
continue
@@ -48,10 +38,3 @@ if __name__ == '__main__':
if not config.exists(peer_base + ['disable']) \
and is_wireguard_key_pair(private_key, peer_public_key):
config.set(peer_base + ['disable'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/23-to-24 b/src/migration-scripts/interfaces/23-to-24
index 8b21fce51..b72ceee49 100755..100644
--- a/src/migration-scripts/interfaces/23-to-24
+++ b/src/migration-scripts/interfaces/23-to-24
@@ -1,21 +1,18 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
def migrate_ospf(config, path, interface):
@@ -74,17 +71,7 @@ def migrate_ripng(config, path, interface):
if len(config.list_nodes(path[:-1])) == 0:
config.delete(path[:-1])
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
#
# Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0"
#
@@ -136,10 +123,3 @@ if __name__ == '__main__':
migrate_ripng(config, vif_s_ipv6_base, ifname)
migrate_ospf(config, vif_s_ip_base, ifname)
migrate_ospfv3(config, vif_s_ipv6_base, ifname)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/24-to-25 b/src/migration-scripts/interfaces/24-to-25
index 8fd79ecc6..9f8cc80ec 100755..100644
--- a/src/migration-scripts/interfaces/24-to-25
+++ b/src/migration-scripts/interfaces/24-to-25
@@ -1,41 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# A VTI interface also requires an IPSec configuration - VyOS 1.2 supported
# having a VTI interface in the CLI but no IPSec configuration - drop VTI
# configuration if this is the case for VyOS 1.4
-import sys
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'vti']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
+ return
ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
for interface in config.list_nodes(base):
@@ -51,10 +39,3 @@ if __name__ == '__main__':
break
if not found:
config.delete(base + [interface])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/25-to-26 b/src/migration-scripts/interfaces/25-to-26
index 9aa6ea5e3..7a4032d10 100755..100644
--- a/src/migration-scripts/interfaces/25-to-26
+++ b/src/migration-scripts/interfaces/25-to-26
@@ -1,24 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrate Wireguard to store keys in CLI
# Migrate EAPoL to PKI configuration
import os
-import sys
from vyos.configtree import ConfigTree
from vyos.pki import CERT_BEGIN
@@ -53,335 +51,318 @@ def read_file_for_pki(config_auth_path):
return output
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
AUTH_DIR = '/config/auth'
pki_base = ['pki']
-# OpenVPN
-base = ['interfaces', 'openvpn']
+def migrate(config: ConfigTree) -> None:
+ # OpenVPN
+ base = ['interfaces', 'openvpn']
+
+ if config.exists(base):
+ for interface in config.list_nodes(base):
+ x509_base = base + [interface, 'tls']
+ pki_name = f'openvpn_{interface}'
+
+ if config.exists(base + [interface, 'shared-secret-key-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'shared-secret-key-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_shared'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'shared-secret-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate shared-secret-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'shared-secret-key-file'])
+
+ if not config.exists(base + [interface, 'tls']):
+ continue
+
+ if config.exists(base + [interface, 'tls', 'auth-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'tls', 'auth-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_auth'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate auth-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'tls', 'auth-file'])
+
+ if config.exists(base + [interface, 'tls', 'crypt-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'tls', 'crypt-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_crypt'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate crypt-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'tls', 'crypt-file'])
+
+ ca_certs = {}
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ certs_str = f.read()
+ certs_data = certs_str.split(CERT_BEGIN)
+ index = 1
+ for cert_data in certs_data[1:]:
+ cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False)
+
+ if cert:
+ ca_certs[f'{pki_name}_{index}'] = cert
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False)
+ else:
+ print(f'Failed to migrate CA certificate on openvpn interface {interface}')
+
+ index += 1
+ else:
+ print(f'Failed to migrate CA certificate on openvpn interface {interface}')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['crl-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ crl_file = config.return_value(x509_base + ['crl-file'])
+ crl_path = os.path.join(AUTH_DIR, crl_file)
+ crl = None
+ crl_ca_name = None
+
+ if os.path.isfile(crl_path):
+ if not os.access(crl_path, os.R_OK):
+ run(f'sudo chmod 644 {crl_path}')
+
+ with open(crl_path, 'r') as f:
+ crl_data = f.read()
+ crl = load_crl(crl_data, wrap_tags=False)
+
+ for ca_name, ca_cert in ca_certs.items():
+ if verify_crl(crl, ca_cert):
+ crl_ca_name = ca_name
+ break
+
+ if crl and crl_ca_name:
+ crl_pem = encode_certificate(crl)
+ config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+ else:
+ print(f'Failed to migrate CRL on openvpn interface {interface}')
+
+ config.delete(x509_base + ['crl-file'])
+
+ if config.exists(x509_base + ['cert-file']):
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on openvpn interface {interface}')
+
+ config.delete(x509_base + ['cert-file'])
+
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on openvpn interface {interface}')
+
+ config.delete(x509_base + ['key-file'])
+
+ if config.exists(x509_base + ['dh-file']):
+ if not config.exists(pki_base + ['dh']):
+ config.set(pki_base + ['dh'])
+ config.set_tag(pki_base + ['dh'])
+
+ dh_file = config.return_value(x509_base + ['dh-file'])
+ dh_path = os.path.join(AUTH_DIR, dh_file)
+ dh = None
+
+ if os.path.isfile(dh_path):
+ if not os.access(dh_path, os.R_OK):
+ run(f'sudo chmod 644 {dh_path}')
+
+ with open(dh_path, 'r') as f:
+ dh_data = f.read()
+ dh = load_dh_parameters(dh_data, wrap_tags=False)
+
+ if dh:
+ dh_pem = encode_dh_parameters(dh)
+ config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem))
+ config.set(x509_base + ['dh-params'], value=pki_name)
+ else:
+ print(f'Failed to migrate DH parameters on openvpn interface {interface}')
+
+ config.delete(x509_base + ['dh-file'])
+
+ # Wireguard
+ base = ['interfaces', 'wireguard']
+
+ if config.exists(base):
+ for interface in config.list_nodes(base):
+ private_key_path = base + [interface, 'private-key']
+
+ key_file = 'default'
+ if config.exists(private_key_path):
+ key_file = config.return_value(private_key_path)
+
+ full_key_path = f'/config/auth/wireguard/{key_file}/private.key'
+
+ if not os.path.exists(full_key_path):
+ print(f'Could not find wireguard private key for migration on interface "{interface}"')
+ continue
+
+ with open(full_key_path, 'r') as f:
+ key_data = f.read().strip()
+ config.set(private_key_path, value=key_data)
+
+ for peer in config.list_nodes(base + [interface, 'peer']):
+ config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key')
+
+ # Ethernet EAPoL
+ base = ['interfaces', 'ethernet']
+
+ if config.exists(base):
+ for interface in config.list_nodes(base):
+ if not config.exists(base + [interface, 'eapol']):
+ continue
+
+ x509_base = base + [interface, 'eapol']
+ pki_name = f'eapol_{interface}'
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on eapol config for interface {interface}')
+
+ config.delete(x509_base + ['ca-cert-file'])
-if config.exists(base):
- for interface in config.list_nodes(base):
- x509_base = base + [interface, 'tls']
- pki_name = f'openvpn_{interface}'
+ if config.exists(x509_base + ['cert-file']):
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
- if config.exists(base + [interface, 'shared-secret-key-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
- key_file = config.return_value(base + [interface, 'shared-secret-key-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_shared'
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'shared-secret-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate shared-secret-key on openvpn interface {interface}')
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
- config.delete(base + [interface, 'shared-secret-key-file'])
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on eapol config for interface {interface}')
- if not config.exists(base + [interface, 'tls']):
- continue
+ config.delete(x509_base + ['cert-file'])
- if config.exists(base + [interface, 'tls', 'auth-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
-
- key_file = config.return_value(base + [interface, 'tls', 'auth-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_auth'
-
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate auth-key on openvpn interface {interface}')
-
- config.delete(base + [interface, 'tls', 'auth-file'])
-
- if config.exists(base + [interface, 'tls', 'crypt-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
-
- key_file = config.return_value(base + [interface, 'tls', 'crypt-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_crypt'
-
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate crypt-key on openvpn interface {interface}')
-
- config.delete(base + [interface, 'tls', 'crypt-file'])
-
- ca_certs = {}
-
- if config.exists(x509_base + ['ca-cert-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- certs_str = f.read()
- certs_data = certs_str.split(CERT_BEGIN)
- index = 1
- for cert_data in certs_data[1:]:
- cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False)
-
- if cert:
- ca_certs[f'{pki_name}_{index}'] = cert
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False)
- else:
- print(f'Failed to migrate CA certificate on openvpn interface {interface}')
-
- index += 1
- else:
- print(f'Failed to migrate CA certificate on openvpn interface {interface}')
-
- config.delete(x509_base + ['ca-cert-file'])
-
- if config.exists(x509_base + ['crl-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- crl_file = config.return_value(x509_base + ['crl-file'])
- crl_path = os.path.join(AUTH_DIR, crl_file)
- crl = None
- crl_ca_name = None
-
- if os.path.isfile(crl_path):
- if not os.access(crl_path, os.R_OK):
- run(f'sudo chmod 644 {crl_path}')
-
- with open(crl_path, 'r') as f:
- crl_data = f.read()
- crl = load_crl(crl_data, wrap_tags=False)
-
- for ca_name, ca_cert in ca_certs.items():
- if verify_crl(crl, ca_cert):
- crl_ca_name = ca_name
- break
-
- if crl and crl_ca_name:
- crl_pem = encode_certificate(crl)
- config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
- else:
- print(f'Failed to migrate CRL on openvpn interface {interface}')
-
- config.delete(x509_base + ['crl-file'])
-
- if config.exists(x509_base + ['cert-file']):
- if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on openvpn interface {interface}')
-
- config.delete(x509_base + ['cert-file'])
-
- if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on openvpn interface {interface}')
-
- config.delete(x509_base + ['key-file'])
-
- if config.exists(x509_base + ['dh-file']):
- if not config.exists(pki_base + ['dh']):
- config.set(pki_base + ['dh'])
- config.set_tag(pki_base + ['dh'])
-
- dh_file = config.return_value(x509_base + ['dh-file'])
- dh_path = os.path.join(AUTH_DIR, dh_file)
- dh = None
-
- if os.path.isfile(dh_path):
- if not os.access(dh_path, os.R_OK):
- run(f'sudo chmod 644 {dh_path}')
-
- with open(dh_path, 'r') as f:
- dh_data = f.read()
- dh = load_dh_parameters(dh_data, wrap_tags=False)
-
- if dh:
- dh_pem = encode_dh_parameters(dh)
- config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem))
- config.set(x509_base + ['dh-params'], value=pki_name)
- else:
- print(f'Failed to migrate DH parameters on openvpn interface {interface}')
-
- config.delete(x509_base + ['dh-file'])
-
-# Wireguard
-base = ['interfaces', 'wireguard']
-
-if config.exists(base):
- for interface in config.list_nodes(base):
- private_key_path = base + [interface, 'private-key']
-
- key_file = 'default'
- if config.exists(private_key_path):
- key_file = config.return_value(private_key_path)
-
- full_key_path = f'/config/auth/wireguard/{key_file}/private.key'
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
- if not os.path.exists(full_key_path):
- print(f'Could not find wireguard private key for migration on interface "{interface}"')
- continue
-
- with open(full_key_path, 'r') as f:
- key_data = f.read().strip()
- config.set(private_key_path, value=key_data)
-
- for peer in config.list_nodes(base + [interface, 'peer']):
- config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key')
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-# Ethernet EAPoL
-base = ['interfaces', 'ethernet']
-
-if config.exists(base):
- for interface in config.list_nodes(base):
- if not config.exists(base + [interface, 'eapol']):
- continue
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on eapol config for interface {interface}')
- x509_base = base + [interface, 'eapol']
- pki_name = f'eapol_{interface}'
-
- if config.exists(x509_base + ['ca-cert-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on eapol config for interface {interface}')
-
- config.delete(x509_base + ['ca-cert-file'])
-
- if config.exists(x509_base + ['cert-file']):
- if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on eapol config for interface {interface}')
-
- config.delete(x509_base + ['cert-file'])
-
- if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on eapol config for interface {interface}')
-
- config.delete(x509_base + ['key-file'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.delete(x509_base + ['key-file'])
diff --git a/src/migration-scripts/interfaces/26-to-27 b/src/migration-scripts/interfaces/26-to-27
index 429ab650f..3f58de02c 100755..100644
--- a/src/migration-scripts/interfaces/26-to-27
+++ b/src/migration-scripts/interfaces/26-to-27
@@ -1,52 +1,35 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4384: pppoe: replace default-route CLI option with common CLI nodes already
# present for DHCP
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-base = ['interfaces', 'pppoe']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-
-for ifname in config.list_nodes(base):
- tmp_config = base + [ifname, 'default-route']
- if config.exists(tmp_config):
- # Retrieve current config value
- value = config.return_value(tmp_config)
- # Delete old Config node
- config.delete(tmp_config)
- if value == 'none':
- config.set(base + [ifname, 'no-default-route'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ base = ['interfaces', 'pppoe']
+
+ if not config.exists(base):
+ return
+
+ for ifname in config.list_nodes(base):
+ tmp_config = base + [ifname, 'default-route']
+ if config.exists(tmp_config):
+ # Retrieve current config value
+ value = config.return_value(tmp_config)
+ # Delete old Config node
+ config.delete(tmp_config)
+ if value == 'none':
+ config.set(base + [ifname, 'no-default-route'])
diff --git a/src/migration-scripts/interfaces/27-to-28 b/src/migration-scripts/interfaces/27-to-28
index 9f5e93b5f..eb9363e39 100755..100644
--- a/src/migration-scripts/interfaces/27-to-28
+++ b/src/migration-scripts/interfaces/27-to-28
@@ -1,48 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4995: pppoe, wwan, sstpc-client rename "authentication user" CLI node
# to "authentication username"
-from sys import argv
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-for type in ['pppoe', 'sstpc-client', 'wwam']:
- base = ['interfaces', type]
- if not config.exists(base):
- continue
- for interface in config.list_nodes(base):
- auth_base = base + [interface, 'authentication', 'user']
- if config.exists(auth_base):
- config.rename(auth_base, 'username')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ for type in ['pppoe', 'sstpc-client', 'wwam']:
+ base = ['interfaces', type]
+ if not config.exists(base):
+ continue
+ for interface in config.list_nodes(base):
+ auth_base = base + [interface, 'authentication', 'user']
+ if config.exists(auth_base):
+ config.rename(auth_base, 'username')
diff --git a/src/migration-scripts/interfaces/28-to-29 b/src/migration-scripts/interfaces/28-to-29
index 0437977dc..886d49e2c 100755..100644
--- a/src/migration-scripts/interfaces/28-to-29
+++ b/src/migration-scripts/interfaces/28-to-29
@@ -1,52 +1,35 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5034: tunnel: rename "multicast enable" CLI node to "enable-multicast"
# valueless node.
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['interfaces', 'tunnel']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-
-for ifname in config.list_nodes(base):
- multicast_base = base + [ifname, 'multicast']
- if config.exists(multicast_base):
- tmp = config.return_value(multicast_base)
- print(tmp)
- # Delete old Config node
- config.delete(multicast_base)
- if tmp == 'enable':
- config.set(base + [ifname, 'enable-multicast'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ for ifname in config.list_nodes(base):
+ multicast_base = base + [ifname, 'multicast']
+ if config.exists(multicast_base):
+ tmp = config.return_value(multicast_base)
+ print(tmp)
+ # Delete old Config node
+ config.delete(multicast_base)
+ if tmp == 'enable':
+ config.set(base + [ifname, 'enable-multicast'])
diff --git a/src/migration-scripts/interfaces/29-to-30 b/src/migration-scripts/interfaces/29-to-30
index 80aad1d44..7b32d871e 100755..100644
--- a/src/migration-scripts/interfaces/29-to-30
+++ b/src/migration-scripts/interfaces/29-to-30
@@ -1,47 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5286: remove XDP support in favour of VPP
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
supports_xdp = ['bonding', 'ethernet']
-config = ConfigTree(config_file)
-
-for if_type in supports_xdp:
- base = ['interfaces', if_type]
- if not config.exists(base):
- continue
- for interface in config.list_nodes(base):
- if_base = base + [interface]
- if config.exists(if_base + ['xdp']):
- config.delete(if_base + ['xdp'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ for if_type in supports_xdp:
+ base = ['interfaces', if_type]
+ if not config.exists(base):
+ continue
+ for interface in config.list_nodes(base):
+ if_base = base + [interface]
+ if config.exists(if_base + ['xdp']):
+ config.delete(if_base + ['xdp'])
diff --git a/src/migration-scripts/interfaces/3-to-4 b/src/migration-scripts/interfaces/3-to-4
index c7fd7d01d..4e56200e1 100755..100644
--- a/src/migration-scripts/interfaces/3-to-4
+++ b/src/migration-scripts/interfaces/3-to-4
@@ -1,27 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Change syntax of wireless interfaces
# Migrate boolean nodes to valueless
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['interfaces', 'wireless']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
for wifi in config.list_nodes(base):
# as converting a node to bool is always the same, we can script it
to_bool_nodes = ['capabilities ht 40MHz-incapable',
@@ -88,10 +91,3 @@ else:
# delete old radius-server nodes
config.delete(base + [wifi, 'security', 'wpa', 'radius-server'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/30-to-31 b/src/migration-scripts/interfaces/30-to-31
index 894106ef4..7e509dd86 100755..100644
--- a/src/migration-scripts/interfaces/30-to-31
+++ b/src/migration-scripts/interfaces/30-to-31
@@ -1,71 +1,56 @@
#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-# Deletes Wireguard peers if they have the same public key as the router has.
+# 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/>.
+
+# T5254: Fixed changing ethernet when it is a bond member
import json
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import EthernetIf
from vyos.ifconfig import BondIf
from vyos.utils.dict import dict_to_paths_values
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['interfaces', 'bonding']
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
- base = ['interfaces', 'bonding']
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-for bond in config.list_nodes(base):
- member_base = base + [bond, 'member', 'interface']
- if config.exists(member_base):
- for interface in config.return_values(member_base):
- if_base = ['interfaces', 'ethernet', interface]
- if config.exists(if_base):
- config_ethernet = json.loads(config.get_subtree(if_base).to_json())
- eth_dict_paths = dict_to_paths_values(config_ethernet)
- for option_path, option_value in eth_dict_paths.items():
- # If option is allowed for changing then continue
- converted_path = option_path.replace('-','_')
- if converted_path in EthernetIf.get_bond_member_allowed_options():
- continue
- # if option is inherited from bond then continue
- if converted_path in BondIf.get_inherit_bond_options():
- continue
- option_path_list = option_path.split('.')
- config.delete(if_base + option_path_list)
- del option_path_list[-1]
- # delete empty node from config
- while len(option_path_list) > 0:
- if config.list_nodes(if_base + option_path_list):
- break
+ for bond in config.list_nodes(base):
+ member_base = base + [bond, 'member', 'interface']
+ if config.exists(member_base):
+ for interface in config.return_values(member_base):
+ if_base = ['interfaces', 'ethernet', interface]
+ if config.exists(if_base):
+ config_ethernet = json.loads(config.get_subtree(if_base).to_json())
+ eth_dict_paths = dict_to_paths_values(config_ethernet)
+ for option_path, option_value in eth_dict_paths.items():
+ # If option is allowed for changing then continue
+ converted_path = option_path.replace('-','_')
+ if converted_path in EthernetIf.get_bond_member_allowed_options():
+ continue
+ # if option is inherited from bond then continue
+ if converted_path in BondIf.get_inherit_bond_options():
+ continue
+ option_path_list = option_path.split('.')
config.delete(if_base + option_path_list)
del option_path_list[-1]
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # delete empty node from config
+ while len(option_path_list) > 0:
+ if config.list_nodes(if_base + option_path_list):
+ break
+ config.delete(if_base + option_path_list)
+ del option_path_list[-1]
diff --git a/src/migration-scripts/interfaces/31-to-32 b/src/migration-scripts/interfaces/31-to-32
index 0fc27b70a..24077ed24 100755..100644
--- a/src/migration-scripts/interfaces/31-to-32
+++ b/src/migration-scripts/interfaces/31-to-32
@@ -1,55 +1,37 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# T5671: change port to IANA assigned default port
# T5759: change default MTU 1450 -> 1500
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['interfaces', 'vxlan']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for vxlan in config.list_nodes(base):
- if config.exists(base + [vxlan, 'external']):
- config.delete(base + [vxlan, 'external'])
- config.set(base + [vxlan, 'parameters', 'external'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- if not config.exists(base + [vxlan, 'port']):
- config.set(base + [vxlan, 'port'], value='8472')
+ for vxlan in config.list_nodes(base):
+ if config.exists(base + [vxlan, 'external']):
+ config.delete(base + [vxlan, 'external'])
+ config.set(base + [vxlan, 'parameters', 'external'])
- if not config.exists(base + [vxlan, 'mtu']):
- config.set(base + [vxlan, 'mtu'], value='1450')
+ if not config.exists(base + [vxlan, 'port']):
+ config.set(base + [vxlan, 'port'], value='8472')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if not config.exists(base + [vxlan, 'mtu']):
+ config.set(base + [vxlan, 'mtu'], value='1450')
diff --git a/src/migration-scripts/interfaces/32-to-33 b/src/migration-scripts/interfaces/32-to-33
index caf588474..c7b1c5b36 100755..100644
--- a/src/migration-scripts/interfaces/32-to-33
+++ b/src/migration-scripts/interfaces/32-to-33
@@ -16,42 +16,25 @@
#
# T6318: WiFi country-code should be set system-wide instead of per-device
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['interfaces', 'wireless']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-installed = False
-for interface in config.list_nodes(base):
- cc_path = base + [interface, 'country-code']
- if config.exists(cc_path):
- tmp = config.return_value(cc_path)
- config.delete(cc_path)
-
- # There can be only ONE wireless country-code per device, everything
- # else makes no sense as a WIFI router can not operate in two
- # different countries
- if not installed:
- config.set(['system', 'wireless', 'country-code'], value=tmp)
- installed = True
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ installed = False
+ for interface in config.list_nodes(base):
+ cc_path = base + [interface, 'country-code']
+ if config.exists(cc_path):
+ tmp = config.return_value(cc_path)
+ config.delete(cc_path)
+
+ # There can be only ONE wireless country-code per device, everything
+ # else makes no sense as a WIFI router can not operate in two
+ # different countries
+ if not installed:
+ config.set(['system', 'wireless', 'country-code'], value=tmp)
+ installed = True
diff --git a/src/migration-scripts/interfaces/4-to-5 b/src/migration-scripts/interfaces/4-to-5
index 68d81e846..93fa7c393 100755..100644
--- a/src/migration-scripts/interfaces/4-to-5
+++ b/src/migration-scripts/interfaces/4-to-5
@@ -1,9 +1,21 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# De-nest PPPoE interfaces
# Migrate boolean nodes to valueless
-import sys
from vyos.configtree import ConfigTree
def migrate_dialer(config, tree, intf):
@@ -55,18 +67,7 @@ def migrate_dialer(config, tree, intf):
if config.exists(ipv6_ra):
config.delete(ipv6_ra)
-
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
pppoe_links = ['bonding', 'ethernet']
for link_type in pppoe_links:
@@ -103,10 +104,3 @@ if __name__ == '__main__':
# Add interface description that this is required for PPPoE
if not config.exists(vlan_if + ['description']):
config.set(vlan_if + ['description'], value='PPPoE link interface')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/5-to-6 b/src/migration-scripts/interfaces/5-to-6
index 9d9a49c2d..44c32ba63 100755..100644
--- a/src/migration-scripts/interfaces/5-to-6
+++ b/src/migration-scripts/interfaces/5-to-6
@@ -1,23 +1,21 @@
-#!/usr/bin/env python3
+# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrate IPv6 router advertisments from a nested interface configuration to
# a denested "service router-advert"
-import sys
from vyos.configtree import ConfigTree
def copy_rtradv(c, old_base, interface):
@@ -97,17 +95,7 @@ def copy_rtradv(c, old_base, interface):
if tmp == '0':
c.delete(new_base + ['link-mtu'])
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = sys.argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
# list all individual interface types like dummy, ethernet and so on
for if_type in config.list_nodes(['interfaces']):
base_if_type = ['interfaces', if_type]
@@ -124,10 +112,3 @@ if __name__ == '__main__':
old_base = vif_base + [vif, 'ipv6', 'router-advert']
vlan_name = f'{intf}.{vif}'
copy_rtradv(config, old_base, vlan_name)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/6-to-7 b/src/migration-scripts/interfaces/6-to-7
index 49b853d90..e60121eec 100755..100644
--- a/src/migration-scripts/interfaces/6-to-7
+++ b/src/migration-scripts/interfaces/6-to-7
@@ -1,39 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Remove network provider name from CLI and rather use provider APN from CLI
-import sys
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = sys.argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wirelessmodem']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
+ return
# list all individual wwan/wireless modem interfaces
for i in config.list_nodes(base):
@@ -54,10 +43,3 @@ if __name__ == '__main__':
# uniform CLI experience
if config.exists(iface + ['no-dns']):
config.rename(iface + ['no-dns'], 'no-peer-dns')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/7-to-8 b/src/migration-scripts/interfaces/7-to-8
index 9343a48a8..43ae320ab 100755..100644
--- a/src/migration-scripts/interfaces/7-to-8
+++ b/src/migration-scripts/interfaces/7-to-8
@@ -1,25 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Split WireGuard endpoint into address / port nodes to make use of common
# validators
import os
-from sys import exit, argv
from vyos.configtree import ConfigTree
from vyos.utils.permission import chown
from vyos.utils.permission import chmod_750
@@ -36,23 +34,14 @@ def migrate_default_keys():
os.rename(f'{kdir}/private.key', f'{location}/private.key')
os.rename(f'{kdir}/public.key', f'{location}/public.key')
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wireguard']
migrate_default_keys()
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
# list all individual wireguard interface isntance
for i in config.list_nodes(base):
@@ -68,10 +57,3 @@ if __name__ == '__main__':
# setup new nodes
config.set(base_peer + ['address'], value=address)
config.set(base_peer + ['port'], value=port)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/8-to-9 b/src/migration-scripts/interfaces/8-to-9
index 960962be7..bae1b34fa 100755..100644
--- a/src/migration-scripts/interfaces/8-to-9
+++ b/src/migration-scripts/interfaces/8-to-9
@@ -1,37 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Rename link nodes to source-interface for the following interface types:
# - vxlan
# - pseudo-ethernet
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
for if_type in ['vxlan', 'pseudo-ethernet']:
base = ['interfaces', if_type]
if not config.exists(base):
@@ -43,10 +31,3 @@ if __name__ == '__main__':
iface = base + [i]
if config.exists(iface + ['link']):
config.rename(iface + ['link'], 'source-interface')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/9-to-10 b/src/migration-scripts/interfaces/9-to-10
index e9b8cb784..cdfd7d432 100755..100644
--- a/src/migration-scripts/interfaces/9-to-10
+++ b/src/migration-scripts/interfaces/9-to-10
@@ -1,38 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - rename CLI node 'dhcpv6-options delgate' to 'dhcpv6-options prefix-delegation
# interface'
# - rename CLI node 'interface-id' for prefix-delegation to 'address' as it
# represents the local interface IPv6 address assigned by DHCPv6-PD
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
for intf_type in config.list_nodes(['interfaces']):
for intf in config.list_nodes(['interfaces', intf_type]):
# cache current config tree
@@ -55,10 +43,3 @@ if __name__ == '__main__':
# delete old noe
config.delete(base_path)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/ipoe-server/1-to-2 b/src/migration-scripts/ipoe-server/1-to-2
index 6a7111541..034eacb10 100755..100644
--- a/src/migration-scripts/ipoe-server/1-to-2
+++ b/src/migration-scripts/ipoe-server/1-to-2
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T4703: merge vlan-id and vlan-range to vlan CLI node
# L2|L3 -> l2|l3
@@ -28,87 +27,68 @@
# 1. The first pool that contains next-poll.
# 2. Else, the first pool in the list
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'ipoe-server']
-if not config.exists(base):
- exit(0)
-
-if config.exists(base + ['authentication', 'interface']):
- for interface in config.list_nodes(base + ['authentication', 'interface']):
- config.rename(base + ['authentication', 'interface', interface, 'mac-address'], 'mac')
-
- mac_base = base + ['authentication', 'interface', interface, 'mac']
- for mac in config.list_nodes(mac_base):
- vlan_config = mac_base + [mac, 'vlan-id']
- if config.exists(vlan_config):
- config.rename(vlan_config, 'vlan')
-
-for interface in config.list_nodes(base + ['interface']):
- base_path = base + ['interface', interface]
- for vlan in ['vlan-id', 'vlan-range']:
- if config.exists(base_path + [vlan]):
- for tmp in config.return_values(base_path + [vlan]):
- config.set(base_path + ['vlan'], value=tmp, replace=False)
- config.delete(base_path + [vlan])
-
- if config.exists(base_path + ['network-mode']):
- tmp = config.return_value(base_path + ['network-mode'])
- config.delete(base_path + ['network-mode'])
- # Change L2|L3 to lower case l2|l3
- config.set(base_path + ['mode'], value=tmp.lower())
-
-pool_base = base + ['client-ip-pool']
-if config.exists(pool_base):
- default_pool = ''
- gateway = ''
-
- #named pool migration
- namedpools_base = pool_base + ['name']
-
- for pool_name in config.list_nodes(namedpools_base):
- pool_path = namedpools_base + [pool_name]
- if config.exists(pool_path + ['subnet']):
- subnet = config.return_value(pool_path + ['subnet'])
- config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
- # Get netmask from subnet
- mask = subnet.split("/")[1]
- if config.exists(pool_path + ['next-pool']):
- next_pool = config.return_value(pool_path + ['next-pool'])
- config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
- if not default_pool:
- default_pool = pool_name
- if config.exists(pool_path + ['gateway-address']) and mask:
- gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}'
- config.set(base + ['gateway-address'], value=gateway, replace=False)
-
- if not default_pool and config.list_nodes(namedpools_base):
- default_pool = config.list_nodes(namedpools_base)[0]
-
- config.delete(namedpools_base)
-
- if default_pool:
- config.set(base + ['default-pool'], value=default_pool)
- # format as tag node
- config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if config.exists(base + ['authentication', 'interface']):
+ for interface in config.list_nodes(base + ['authentication', 'interface']):
+ config.rename(base + ['authentication', 'interface', interface, 'mac-address'], 'mac')
+
+ mac_base = base + ['authentication', 'interface', interface, 'mac']
+ for mac in config.list_nodes(mac_base):
+ vlan_config = mac_base + [mac, 'vlan-id']
+ if config.exists(vlan_config):
+ config.rename(vlan_config, 'vlan')
+
+ for interface in config.list_nodes(base + ['interface']):
+ base_path = base + ['interface', interface]
+ for vlan in ['vlan-id', 'vlan-range']:
+ if config.exists(base_path + [vlan]):
+ for tmp in config.return_values(base_path + [vlan]):
+ config.set(base_path + ['vlan'], value=tmp, replace=False)
+ config.delete(base_path + [vlan])
+
+ if config.exists(base_path + ['network-mode']):
+ tmp = config.return_value(base_path + ['network-mode'])
+ config.delete(base_path + ['network-mode'])
+ # Change L2|L3 to lower case l2|l3
+ config.set(base_path + ['mode'], value=tmp.lower())
+
+ pool_base = base + ['client-ip-pool']
+ if config.exists(pool_base):
+ default_pool = ''
+ gateway = ''
+
+ #named pool migration
+ namedpools_base = pool_base + ['name']
+
+ for pool_name in config.list_nodes(namedpools_base):
+ pool_path = namedpools_base + [pool_name]
+ if config.exists(pool_path + ['subnet']):
+ subnet = config.return_value(pool_path + ['subnet'])
+ config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
+ # Get netmask from subnet
+ mask = subnet.split("/")[1]
+ if config.exists(pool_path + ['next-pool']):
+ next_pool = config.return_value(pool_path + ['next-pool'])
+ config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
+ if not default_pool:
+ default_pool = pool_name
+ if config.exists(pool_path + ['gateway-address']) and mask:
+ gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}'
+ config.set(base + ['gateway-address'], value=gateway, replace=False)
+
+ if not default_pool and config.list_nodes(namedpools_base):
+ default_pool = config.list_nodes(namedpools_base)[0]
+
+ config.delete(namedpools_base)
+
+ if default_pool:
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/ipoe-server/2-to-3 b/src/migration-scripts/ipoe-server/2-to-3
index 0909315a8..dcd15e595 100755..100644
--- a/src/migration-scripts/ipoe-server/2-to-3
+++ b/src/migration-scripts/ipoe-server/2-to-3
@@ -1,58 +1,40 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrating to named ipv6 pools
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['service', 'ipoe-server']
+pool_base = base + ['client-ipv6-pool']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ if not config.exists(pool_base):
+ return
-config = ConfigTree(config_file)
-base = ['service', 'ipoe-server']
-pool_base = base + ['client-ipv6-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-ipv6_pool_name = 'ipv6-pool'
-config.copy(pool_base, pool_base + [ipv6_pool_name])
-
-if config.exists(pool_base + ['prefix']):
- config.delete(pool_base + ['prefix'])
- config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
-if config.exists(pool_base + ['delegate']):
- config.delete(pool_base + ['delegate'])
-
-# format as tag node
-config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ ipv6_pool_name = 'ipv6-pool'
+ config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+ if config.exists(pool_base + ['prefix']):
+ config.delete(pool_base + ['prefix'])
+ config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+ if config.exists(pool_base + ['delegate']):
+ config.delete(pool_base + ['delegate'])
+
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/ipsec/10-to-11 b/src/migration-scripts/ipsec/10-to-11
index 509216267..6c4ccb553 100755..100644
--- a/src/migration-scripts/ipsec/10-to-11
+++ b/src/migration-scripts/ipsec/10-to-11
@@ -1,83 +1,63 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
+# T4916: Rewrite IPsec peer authentication and psk migration
from vyos.configtree import ConfigTree
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# PEER changes
-if config.exists(base + ['site-to-site', 'peer']):
- for peer in config.list_nodes(base + ['site-to-site', 'peer']):
- peer_base = base + ['site-to-site', 'peer', peer]
-
- # replace: 'ipsec site-to-site peer <tag> authentication pre-shared-secret xxx'
- # => 'ipsec authentication psk <tag> secret xxx'
- if config.exists(peer_base + ['authentication', 'pre-shared-secret']):
- tmp = config.return_value(peer_base + ['authentication', 'pre-shared-secret'])
- config.delete(peer_base + ['authentication', 'pre-shared-secret'])
- config.set(base + ['authentication', 'psk', peer, 'secret'], value=tmp)
- # format as tag node to avoid loading problems
- config.set_tag(base + ['authentication', 'psk'])
-
- # Get id's from peers for "ipsec auth psk <tag> id xxx"
- if config.exists(peer_base + ['authentication', 'local-id']):
- local_id = config.return_value(peer_base + ['authentication', 'local-id'])
- config.set(base + ['authentication', 'psk', peer, 'id'], value=local_id, replace=False)
- if config.exists(peer_base + ['authentication', 'remote-id']):
- remote_id = config.return_value(peer_base + ['authentication', 'remote-id'])
- config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_id, replace=False)
-
- if config.exists(peer_base + ['local-address']):
- tmp = config.return_value(peer_base + ['local-address'])
- config.set(base + ['authentication', 'psk', peer, 'id'], value=tmp, replace=False)
- if config.exists(peer_base + ['remote-address']):
- tmp = config.return_values(peer_base + ['remote-address'])
- if tmp:
- for remote_addr in tmp:
- if remote_addr == 'any':
- remote_addr = '%any'
- config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_addr, replace=False)
-
- # get DHCP peer interface as psk dhcp-interface
- if config.exists(peer_base + ['dhcp-interface']):
- tmp = config.return_value(peer_base + ['dhcp-interface'])
- config.set(base + ['authentication', 'psk', peer, 'dhcp-interface'], value=tmp)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # PEER changes
+ if config.exists(base + ['site-to-site', 'peer']):
+ for peer in config.list_nodes(base + ['site-to-site', 'peer']):
+ peer_base = base + ['site-to-site', 'peer', peer]
+
+ # replace: 'ipsec site-to-site peer <tag> authentication pre-shared-secret xxx'
+ # => 'ipsec authentication psk <tag> secret xxx'
+ if config.exists(peer_base + ['authentication', 'pre-shared-secret']):
+ tmp = config.return_value(peer_base + ['authentication', 'pre-shared-secret'])
+ config.delete(peer_base + ['authentication', 'pre-shared-secret'])
+ config.set(base + ['authentication', 'psk', peer, 'secret'], value=tmp)
+ # format as tag node to avoid loading problems
+ config.set_tag(base + ['authentication', 'psk'])
+
+ # Get id's from peers for "ipsec auth psk <tag> id xxx"
+ if config.exists(peer_base + ['authentication', 'local-id']):
+ local_id = config.return_value(peer_base + ['authentication', 'local-id'])
+ config.set(base + ['authentication', 'psk', peer, 'id'], value=local_id, replace=False)
+ if config.exists(peer_base + ['authentication', 'remote-id']):
+ remote_id = config.return_value(peer_base + ['authentication', 'remote-id'])
+ config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_id, replace=False)
+
+ if config.exists(peer_base + ['local-address']):
+ tmp = config.return_value(peer_base + ['local-address'])
+ config.set(base + ['authentication', 'psk', peer, 'id'], value=tmp, replace=False)
+ if config.exists(peer_base + ['remote-address']):
+ tmp = config.return_values(peer_base + ['remote-address'])
+ if tmp:
+ for remote_addr in tmp:
+ if remote_addr == 'any':
+ remote_addr = '%any'
+ config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_addr, replace=False)
+
+ # get DHCP peer interface as psk dhcp-interface
+ if config.exists(peer_base + ['dhcp-interface']):
+ tmp = config.return_value(peer_base + ['dhcp-interface'])
+ config.set(base + ['authentication', 'psk', peer, 'dhcp-interface'], value=tmp)
diff --git a/src/migration-scripts/ipsec/11-to-12 b/src/migration-scripts/ipsec/11-to-12
index 4833d0876..fc65f1825 100755..100644
--- a/src/migration-scripts/ipsec/11-to-12
+++ b/src/migration-scripts/ipsec/11-to-12
@@ -1,51 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Remove legacy ipsec.conf and ipsec.secrets - Not supported with swanctl
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-if config.exists(base + ['include-ipsec-conf']):
- config.delete(base + ['include-ipsec-conf'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-if config.exists(base + ['include-ipsec-secrets']):
- config.delete(base + ['include-ipsec-secrets'])
+ if config.exists(base + ['include-ipsec-conf']):
+ config.delete(base + ['include-ipsec-conf'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(base + ['include-ipsec-secrets']):
+ config.delete(base + ['include-ipsec-secrets'])
diff --git a/src/migration-scripts/ipsec/12-to-13 b/src/migration-scripts/ipsec/12-to-13
index d90c70314..ffe766eb2 100755..100644
--- a/src/migration-scripts/ipsec/12-to-13
+++ b/src/migration-scripts/ipsec/12-to-13
@@ -1,43 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Changed value of dead-peer-detection.action from hold to trap
# Changed value of close-action from hold to trap and from restart to start
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec', 'ike-group']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
for ike_group in config.list_nodes(base):
base_dpd_action = base + [ike_group, 'dead-peer-detection', 'action']
base_close_action = base + [ike_group, 'close-action']
@@ -48,10 +35,3 @@ else:
config.set(base_close_action, 'trap', replace=True)
if config.return_value(base_close_action) == 'restart':
config.set(base_close_action, 'start', replace=True)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
diff --git a/src/migration-scripts/ipsec/4-to-5 b/src/migration-scripts/ipsec/4-to-5
index 772d05787..a88a543d3 100755..100644
--- a/src/migration-scripts/ipsec/4-to-5
+++ b/src/migration-scripts/ipsec/4-to-5
@@ -1,47 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# log-modes have changed, keyword all to any
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-ctree = ConfigTree(config_file)
-
-if not ctree.exists(['vpn', 'ipsec', 'logging','log-modes']):
- # Nothing to do
- sys.exit(0)
-else:
- lmodes = ctree.return_values(['vpn', 'ipsec', 'logging','log-modes'])
- for mode in lmodes:
- if mode == 'all':
- ctree.set(['vpn', 'ipsec', 'logging','log-modes'], value='any', replace=True)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['vpn', 'ipsec', 'logging','log-modes']):
+ # Nothing to do
+ return
- try:
- open(file_name,'w').write(ctree.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ lmodes = config.return_values(['vpn', 'ipsec', 'logging','log-modes'])
+ for mode in lmodes:
+ if mode == 'all':
+ config.set(['vpn', 'ipsec', 'logging','log-modes'], value='any', replace=True)
diff --git a/src/migration-scripts/ipsec/5-to-6 b/src/migration-scripts/ipsec/5-to-6
index 7d7c777c6..373428d61 100755..100644
--- a/src/migration-scripts/ipsec/5-to-6
+++ b/src/migration-scripts/ipsec/5-to-6
@@ -1,93 +1,73 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Remove deprecated strongSwan options from VyOS CLI
# - vpn ipsec nat-traversal enable
# - vpn ipsec nat-networks allowed-network
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# Delete CLI nodes whose config options got removed by strongSwan
-for cli_node in ['nat-traversal', 'nat-networks']:
- if config.exists(base + [cli_node]):
- config.delete(base + [cli_node])
-
-# Remove options only valid in Openswan
-if config.exists(base + ['site-to-site', 'peer']):
- for peer in config.list_nodes(base + ['site-to-site', 'peer']):
- if not config.exists(base + ['site-to-site', 'peer', peer, 'tunnel']):
- continue
- for tunnel in config.list_nodes(base + ['site-to-site', 'peer', peer, 'tunnel']):
- # allow-public-networks - Sets a value in ipsec.conf that was only ever valid in Openswan on kernel 2.6
- nat_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-nat-networks']
- if config.exists(nat_networks):
- config.delete(nat_networks)
-
- # allow-nat-networks - Also sets a value only valid in Openswan
- public_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-public-networks']
- if config.exists(public_networks):
- config.delete(public_networks)
-
-# Rename "logging log-level" and "logging log-modes" to something more human friendly
-log = base + ['logging']
-if config.exists(log):
- config.rename(log, 'log')
- log = base + ['log']
-
-log_level = log + ['log-level']
-if config.exists(log_level):
- config.rename(log_level, 'level')
-
-log_mode = log + ['log-modes']
-if config.exists(log_mode):
- config.rename(log_mode, 'subsystem')
-
-# Rename "ipsec-interfaces interface" to "interface"
-base_interfaces = base + ['ipsec-interfaces', 'interface']
-if config.exists(base_interfaces):
- config.copy(base_interfaces, base + ['interface'])
- config.delete(base + ['ipsec-interfaces'])
-
-# Remove deprecated "auto-update" option
-tmp = base + ['auto-update']
-if config.exists(tmp):
- config.delete(tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Delete CLI nodes whose config options got removed by strongSwan
+ for cli_node in ['nat-traversal', 'nat-networks']:
+ if config.exists(base + [cli_node]):
+ config.delete(base + [cli_node])
+
+ # Remove options only valid in Openswan
+ if config.exists(base + ['site-to-site', 'peer']):
+ for peer in config.list_nodes(base + ['site-to-site', 'peer']):
+ if not config.exists(base + ['site-to-site', 'peer', peer, 'tunnel']):
+ continue
+ for tunnel in config.list_nodes(base + ['site-to-site', 'peer', peer, 'tunnel']):
+ # allow-public-networks - Sets a value in ipsec.conf that was only ever valid in Openswan on kernel 2.6
+ nat_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-nat-networks']
+ if config.exists(nat_networks):
+ config.delete(nat_networks)
+
+ # allow-nat-networks - Also sets a value only valid in Openswan
+ public_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-public-networks']
+ if config.exists(public_networks):
+ config.delete(public_networks)
+
+ # Rename "logging log-level" and "logging log-modes" to something more human friendly
+ log = base + ['logging']
+ if config.exists(log):
+ config.rename(log, 'log')
+ log = base + ['log']
+
+ log_level = log + ['log-level']
+ if config.exists(log_level):
+ config.rename(log_level, 'level')
+
+ log_mode = log + ['log-modes']
+ if config.exists(log_mode):
+ config.rename(log_mode, 'subsystem')
+
+ # Rename "ipsec-interfaces interface" to "interface"
+ base_interfaces = base + ['ipsec-interfaces', 'interface']
+ if config.exists(base_interfaces):
+ config.copy(base_interfaces, base + ['interface'])
+ config.delete(base + ['ipsec-interfaces'])
+
+ # Remove deprecated "auto-update" option
+ tmp = base + ['auto-update']
+ if config.exists(tmp):
+ config.delete(tmp)
diff --git a/src/migration-scripts/ipsec/6-to-7 b/src/migration-scripts/ipsec/6-to-7
index f8b6de560..5679477c0 100755..100644
--- a/src/migration-scripts/ipsec/6-to-7
+++ b/src/migration-scripts/ipsec/6-to-7
@@ -1,26 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrate /config/auth certificates and keys into PKI configuration
import os
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_crl
@@ -29,27 +25,27 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
pki_base = ['pki']
ipsec_site_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
-config = ConfigTree(config_file)
-changes_made = False
-
AUTH_DIR = '/config/auth'
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
-if config.exists(ipsec_site_base):
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(ipsec_site_base):
+ return
+
+ migration_needed = False
+ for peer in config.list_nodes(ipsec_site_base):
+ if config.exists(ipsec_site_base + [peer, 'authentication', 'x509']):
+ migration_needed = True
+ break
+
+ if not migration_needed:
+ return
+
config.set(pki_base + ['ca'])
config.set_tag(pki_base + ['ca'])
@@ -60,8 +56,6 @@ if config.exists(ipsec_site_base):
if not config.exists(ipsec_site_base + [peer, 'authentication', 'x509']):
continue
- changes_made = True
-
peer_x509_base = ipsec_site_base + [peer, 'authentication', 'x509']
pki_name = 'peer_' + peer.replace(".", "-").replace("@", "")
@@ -159,11 +153,3 @@ if config.exists(ipsec_site_base):
print(f'Failed to migrate private key on peer "{peer}"')
config.delete(peer_x509_base + ['key'])
-
-if changes_made:
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/ipsec/7-to-8 b/src/migration-scripts/ipsec/7-to-8
index 9acc737d5..481f00d29 100755..100644
--- a/src/migration-scripts/ipsec/7-to-8
+++ b/src/migration-scripts/ipsec/7-to-8
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrate rsa keys into PKI configuration
@@ -22,29 +21,15 @@ import struct
from cryptography.hazmat.primitives.asymmetric import rsa
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
from vyos.pki import load_private_key
from vyos.pki import encode_public_key
from vyos.pki import encode_private_key
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
pki_base = ['pki']
ipsec_site_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
rsa_keys_base = ['vpn', 'rsa-keys']
-config = ConfigTree(config_file)
-
LOCAL_KEY_PATHS = ['/config/auth/', '/config/ipsec.d/rsa-keys/']
def migrate_from_vyatta_key(data):
@@ -60,65 +45,59 @@ def wrapped_pem_to_config_value(pem):
local_key_name = 'localhost'
-if config.exists(rsa_keys_base):
- if not config.exists(pki_base + ['key-pair']):
- config.set(pki_base + ['key-pair'])
- config.set_tag(pki_base + ['key-pair'])
-
- if config.exists(rsa_keys_base + ['local-key', 'file']):
- local_file = config.return_value(rsa_keys_base + ['local-key', 'file'])
- local_path = None
- local_key = None
-
- for path in LOCAL_KEY_PATHS:
- full_path = os.path.join(path, local_file)
- if os.path.exists(full_path):
- local_path = full_path
- break
-
- if local_path:
- with open(local_path, 'r') as f:
- local_key_data = f.read()
- local_key = load_private_key(local_key_data, wrap_tags=False)
-
- if local_key:
- local_key_pem = encode_private_key(local_key)
- config.set(pki_base + ['key-pair', local_key_name, 'private', 'key'], value=wrapped_pem_to_config_value(local_key_pem))
- else:
- print('Failed to migrate local RSA key')
-
- if config.exists(rsa_keys_base + ['rsa-key-name']):
- for rsa_name in config.list_nodes(rsa_keys_base + ['rsa-key-name']):
- if not config.exists(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']):
- continue
+def migrate(config: ConfigTree) -> None:
+ if config.exists(rsa_keys_base):
+ if not config.exists(pki_base + ['key-pair']):
+ config.set(pki_base + ['key-pair'])
+ config.set_tag(pki_base + ['key-pair'])
+
+ if config.exists(rsa_keys_base + ['local-key', 'file']):
+ local_file = config.return_value(rsa_keys_base + ['local-key', 'file'])
+ local_path = None
+ local_key = None
+
+ for path in LOCAL_KEY_PATHS:
+ full_path = os.path.join(path, local_file)
+ if os.path.exists(full_path):
+ local_path = full_path
+ break
+
+ if local_path:
+ with open(local_path, 'r') as f:
+ local_key_data = f.read()
+ local_key = load_private_key(local_key_data, wrap_tags=False)
+
+ if local_key:
+ local_key_pem = encode_private_key(local_key)
+ config.set(pki_base + ['key-pair', local_key_name, 'private', 'key'], value=wrapped_pem_to_config_value(local_key_pem))
+ else:
+ print('Failed to migrate local RSA key')
- vyatta_key = config.return_value(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key'])
- public_key = migrate_from_vyatta_key(vyatta_key)
+ if config.exists(rsa_keys_base + ['rsa-key-name']):
+ for rsa_name in config.list_nodes(rsa_keys_base + ['rsa-key-name']):
+ if not config.exists(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']):
+ continue
- if public_key:
- public_key_pem = encode_public_key(public_key)
- config.set(pki_base + ['key-pair', rsa_name, 'public', 'key'], value=wrapped_pem_to_config_value(public_key_pem))
- else:
- print(f'Failed to migrate rsa-key "{rsa_name}"')
+ vyatta_key = config.return_value(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key'])
+ public_key = migrate_from_vyatta_key(vyatta_key)
- config.delete(rsa_keys_base)
+ if public_key:
+ public_key_pem = encode_public_key(public_key)
+ config.set(pki_base + ['key-pair', rsa_name, 'public', 'key'], value=wrapped_pem_to_config_value(public_key_pem))
+ else:
+ print(f'Failed to migrate rsa-key "{rsa_name}"')
-if config.exists(ipsec_site_base):
- for peer in config.list_nodes(ipsec_site_base):
- mode = config.return_value(ipsec_site_base + [peer, 'authentication', 'mode'])
+ config.delete(rsa_keys_base)
- if mode != 'rsa':
- continue
+ if config.exists(ipsec_site_base):
+ for peer in config.list_nodes(ipsec_site_base):
+ mode = config.return_value(ipsec_site_base + [peer, 'authentication', 'mode'])
- config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'local-key'], value=local_key_name)
+ if mode != 'rsa':
+ continue
- remote_key_name = config.return_value(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
- config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'remote-key'], value=remote_key_name)
- config.delete(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
+ config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'local-key'], value=local_key_name)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ remote_key_name = config.return_value(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
+ config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'remote-key'], value=remote_key_name)
+ config.delete(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
diff --git a/src/migration-scripts/ipsec/8-to-9 b/src/migration-scripts/ipsec/8-to-9
index c08411f83..7f325139f 100755..100644
--- a/src/migration-scripts/ipsec/8-to-9
+++ b/src/migration-scripts/ipsec/8-to-9
@@ -1,48 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
+# T4288 : close-action is missing in swanctl.conf
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec', 'ike-group']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
for ike_group in config.list_nodes(base):
base_closeaction = base + [ike_group, 'close-action']
if config.exists(base_closeaction) and config.return_value(base_closeaction) == 'clear':
config.set(base_closeaction, 'none', replace=True)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
diff --git a/src/migration-scripts/ipsec/9-to-10 b/src/migration-scripts/ipsec/9-to-10
index bc10e1997..321a75973 100755..100644
--- a/src/migration-scripts/ipsec/9-to-10
+++ b/src/migration-scripts/ipsec/9-to-10
@@ -1,131 +1,114 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
-import re
+# T4118: Change vpn ipsec syntax for IKE ESP and peer
+# T4879: IPsec migration script remote-id for peer name eq address
-from sys import argv
-from sys import exit
+import re
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# IKE changes, T4118:
-if config.exists(base + ['ike-group']):
- for ike_group in config.list_nodes(base + ['ike-group']):
- # replace 'ipsec ike-group <tag> mobike disable'
- # => 'ipsec ike-group <tag> disable-mobike'
- mobike = base + ['ike-group', ike_group, 'mobike']
- if config.exists(mobike):
- if config.return_value(mobike) == 'disable':
- config.set(base + ['ike-group', ike_group, 'disable-mobike'])
- config.delete(mobike)
-
- # replace 'ipsec ike-group <tag> ikev2-reauth yes'
- # => 'ipsec ike-group <tag> ikev2-reauth'
- reauth = base + ['ike-group', ike_group, 'ikev2-reauth']
- if config.exists(reauth):
- if config.return_value(reauth) == 'yes':
- config.delete(reauth)
- config.set(reauth)
- else:
- config.delete(reauth)
-
-# ESP changes
-# replace 'ipsec esp-group <tag> compression enable'
-# => 'ipsec esp-group <tag> compression'
-if config.exists(base + ['esp-group']):
- for esp_group in config.list_nodes(base + ['esp-group']):
- compression = base + ['esp-group', esp_group, 'compression']
- if config.exists(compression):
- if config.return_value(compression) == 'enable':
- config.delete(compression)
- config.set(compression)
- else:
- config.delete(compression)
-
-# PEER changes
-if config.exists(base + ['site-to-site', 'peer']):
- for peer in config.list_nodes(base + ['site-to-site', 'peer']):
- peer_base = base + ['site-to-site', 'peer', peer]
-
- # replace: 'peer <tag> id x'
- # => 'peer <tag> local-id x'
- if config.exists(peer_base + ['authentication', 'id']):
- config.rename(peer_base + ['authentication', 'id'], 'local-id')
-
- # For the peer '@foo' set remote-id 'foo' if remote-id is not defined
- # For the peer '192.0.2.1' set remote-id '192.0.2.1' if remote-id is not defined
- if not config.exists(peer_base + ['authentication', 'remote-id']):
- tmp = peer.replace('@', '') if peer.startswith('@') else peer
- config.set(peer_base + ['authentication', 'remote-id'], value=tmp)
-
- # replace: 'peer <tag> force-encapsulation enable'
- # => 'peer <tag> force-udp-encapsulation'
- force_enc = peer_base + ['force-encapsulation']
- if config.exists(force_enc):
- if config.return_value(force_enc) == 'enable':
- config.delete(force_enc)
- config.set(peer_base + ['force-udp-encapsulation'])
- else:
- config.delete(force_enc)
-
- # add option: 'peer <tag> remote-address x.x.x.x'
- remote_address = peer
- if peer.startswith('@'):
- remote_address = 'any'
- config.set(peer_base + ['remote-address'], value=remote_address)
- # Peer name it is swanctl connection name and shouldn't contain dots or colons
- # rename peer:
- # peer 192.0.2.1 => peer peer_192-0-2-1
- # peer 2001:db8::2 => peer peer_2001-db8--2
- # peer @foo => peer peer_foo
- re_peer_name = re.sub(':|\.', '-', peer)
- if re_peer_name.startswith('@'):
- re_peer_name = re.sub('@', '', re_peer_name)
- new_peer_name = f'peer_{re_peer_name}'
-
- config.rename(peer_base, new_peer_name)
-
-# remote-access/road-warrior changes
-if config.exists(base + ['remote-access', 'connection']):
- for connection in config.list_nodes(base + ['remote-access', 'connection']):
- ra_base = base + ['remote-access', 'connection', connection]
- # replace: 'remote-access connection <tag> authentication id x'
- # => 'remote-access connection <tag> authentication local-id x'
- if config.exists(ra_base + ['authentication', 'id']):
- config.rename(ra_base + ['authentication', 'id'], 'local-id')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # IKE changes, T4118:
+ if config.exists(base + ['ike-group']):
+ for ike_group in config.list_nodes(base + ['ike-group']):
+ # replace 'ipsec ike-group <tag> mobike disable'
+ # => 'ipsec ike-group <tag> disable-mobike'
+ mobike = base + ['ike-group', ike_group, 'mobike']
+ if config.exists(mobike):
+ if config.return_value(mobike) == 'disable':
+ config.set(base + ['ike-group', ike_group, 'disable-mobike'])
+ config.delete(mobike)
+
+ # replace 'ipsec ike-group <tag> ikev2-reauth yes'
+ # => 'ipsec ike-group <tag> ikev2-reauth'
+ reauth = base + ['ike-group', ike_group, 'ikev2-reauth']
+ if config.exists(reauth):
+ if config.return_value(reauth) == 'yes':
+ config.delete(reauth)
+ config.set(reauth)
+ else:
+ config.delete(reauth)
+
+ # ESP changes
+ # replace 'ipsec esp-group <tag> compression enable'
+ # => 'ipsec esp-group <tag> compression'
+ if config.exists(base + ['esp-group']):
+ for esp_group in config.list_nodes(base + ['esp-group']):
+ compression = base + ['esp-group', esp_group, 'compression']
+ if config.exists(compression):
+ if config.return_value(compression) == 'enable':
+ config.delete(compression)
+ config.set(compression)
+ else:
+ config.delete(compression)
+
+ # PEER changes
+ if config.exists(base + ['site-to-site', 'peer']):
+ for peer in config.list_nodes(base + ['site-to-site', 'peer']):
+ peer_base = base + ['site-to-site', 'peer', peer]
+
+ # replace: 'peer <tag> id x'
+ # => 'peer <tag> local-id x'
+ if config.exists(peer_base + ['authentication', 'id']):
+ config.rename(peer_base + ['authentication', 'id'], 'local-id')
+
+ # For the peer '@foo' set remote-id 'foo' if remote-id is not defined
+ # For the peer '192.0.2.1' set remote-id '192.0.2.1' if remote-id is not defined
+ if not config.exists(peer_base + ['authentication', 'remote-id']):
+ tmp = peer.replace('@', '') if peer.startswith('@') else peer
+ config.set(peer_base + ['authentication', 'remote-id'], value=tmp)
+
+ # replace: 'peer <tag> force-encapsulation enable'
+ # => 'peer <tag> force-udp-encapsulation'
+ force_enc = peer_base + ['force-encapsulation']
+ if config.exists(force_enc):
+ if config.return_value(force_enc) == 'enable':
+ config.delete(force_enc)
+ config.set(peer_base + ['force-udp-encapsulation'])
+ else:
+ config.delete(force_enc)
+
+ # add option: 'peer <tag> remote-address x.x.x.x'
+ remote_address = peer
+ if peer.startswith('@'):
+ remote_address = 'any'
+ config.set(peer_base + ['remote-address'], value=remote_address)
+ # Peer name it is swanctl connection name and shouldn't contain dots or colons
+ # rename peer:
+ # peer 192.0.2.1 => peer peer_192-0-2-1
+ # peer 2001:db8::2 => peer peer_2001-db8--2
+ # peer @foo => peer peer_foo
+ re_peer_name = re.sub(':|\.', '-', peer)
+ if re_peer_name.startswith('@'):
+ re_peer_name = re.sub('@', '', re_peer_name)
+ new_peer_name = f'peer_{re_peer_name}'
+
+ config.rename(peer_base, new_peer_name)
+
+ # remote-access/road-warrior changes
+ if config.exists(base + ['remote-access', 'connection']):
+ for connection in config.list_nodes(base + ['remote-access', 'connection']):
+ ra_base = base + ['remote-access', 'connection', connection]
+ # replace: 'remote-access connection <tag> authentication id x'
+ # => 'remote-access connection <tag> authentication local-id x'
+ if config.exists(ra_base + ['authentication', 'id']):
+ config.rename(ra_base + ['authentication', 'id'], 'local-id')
diff --git a/src/migration-scripts/isis/0-to-1 b/src/migration-scripts/isis/0-to-1
index 0149c0c1f..e24288558 100755..100644
--- a/src/migration-scripts/isis/0-to-1
+++ b/src/migration-scripts/isis/0-to-1
@@ -1,56 +1,36 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'isis']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-# We need a temporary copy of the config
-tmp_base = ['protocols', 'isis2']
-config.copy(base, tmp_base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-# Now it's save to delete the old configuration
-config.delete(base)
+ # We need a temporary copy of the config
+ tmp_base = ['protocols', 'isis2']
+ config.copy(base, tmp_base)
-# Rename temporary copy to new final config (IS-IS domain key is static and no
-# longer required to be set via CLI)
-config.rename(tmp_base, 'isis')
+ # Now it's save to delete the old configuration
+ config.delete(base)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # Rename temporary copy to new final config (IS-IS domain key is static and no
+ # longer required to be set via CLI)
+ config.rename(tmp_base, 'isis')
diff --git a/src/migration-scripts/isis/1-to-2 b/src/migration-scripts/isis/1-to-2
index 9c110bf2a..0fc92a6de 100755..100644
--- a/src/migration-scripts/isis/1-to-2
+++ b/src/migration-scripts/isis/1-to-2
@@ -1,46 +1,27 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4739 refactor, and remove "on" from segment routing from the configuration
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-# Check if ISIS segment routing is configured. Then check if segment routing "on" exists, then delete the "on" as it is no longer needed. This is for global configuration.
-if config.exists(['protocols', 'isis']):
- if config.exists(['protocols', 'isis', 'segment-routing']):
- if config.exists(['protocols', 'isis', 'segment-routing', 'enable']):
- config.delete(['protocols', 'isis', 'segment-routing', 'enable'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Check if ISIS segment routing is configured. Then check if segment
+ # routing "on" exists, then delete the "on" as it is no longer needed.
+ # This is for global configuration.
+ if config.exists(['protocols', 'isis']):
+ if config.exists(['protocols', 'isis', 'segment-routing']):
+ if config.exists(['protocols', 'isis', 'segment-routing', 'enable']):
+ config.delete(['protocols', 'isis', 'segment-routing', 'enable'])
diff --git a/src/migration-scripts/isis/2-to-3 b/src/migration-scripts/isis/2-to-3
index 78e3c1715..afb9f2340 100755..100644
--- a/src/migration-scripts/isis/2-to-3
+++ b/src/migration-scripts/isis/2-to-3
@@ -1,63 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
isis_base = ['protocols', 'isis']
-# Check if IS-IS is configured - if so, migrate the CLI node
-if config.exists(isis_base):
- if config.exists(isis_base + ['route-map']):
- tmp = config.return_value(isis_base + ['route-map'])
-
- config.set(['system', 'ip', 'protocol', 'isis', 'route-map'], value=tmp)
- config.set_tag(['system', 'ip', 'protocol'])
- config.delete(isis_base + ['route-map'])
-
-# Check if vrf names are configured. Check if IS-IS is configured - if so,
-# migrate the CLI node(s)
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- vrf_base = ['vrf', 'name', vrf]
- if config.exists(vrf_base + ['protocols', 'isis', 'route-map']):
- tmp = config.return_value(vrf_base + ['protocols', 'isis', 'route-map'])
-
- config.set(vrf_base + ['ip', 'protocol', 'isis', 'route-map'], value=tmp)
- config.set_tag(vrf_base + ['ip', 'protocol', 'isis'])
- config.delete(vrf_base + ['protocols', 'isis', 'route-map'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Check if IS-IS is configured - if so, migrate the CLI node
+ if config.exists(isis_base):
+ if config.exists(isis_base + ['route-map']):
+ tmp = config.return_value(isis_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'isis', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(isis_base + ['route-map'])
+
+ # Check if vrf names are configured. Check if IS-IS is configured - if so,
+ # migrate the CLI node(s)
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'isis', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'isis', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'isis', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'isis'])
+ config.delete(vrf_base + ['protocols', 'isis', 'route-map'])
diff --git a/src/migration-scripts/l2tp/0-to-1 b/src/migration-scripts/l2tp/0-to-1
index 15d229822..f0cb6af96 100755..100644
--- a/src/migration-scripts/l2tp/0-to-1
+++ b/src/migration-scripts/l2tp/0-to-1
@@ -1,29 +1,32 @@
-#!/usr/bin/env python3
-
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
+
+# T987: Unclutter L2TP/IPSec RADIUS configuration nodes
# Unclutter L2TP VPN configuiration - move radius-server top level tag
# nodes to a regular node which now also configures the radius source address
# used when querying a radius server
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+cfg_base = ['vpn', 'l2tp', 'remote-access', 'authentication']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_base):
+ # Nothing to do
+ return
-cfg_base = ['vpn', 'l2tp', 'remote-access', 'authentication']
-if not config.exists(cfg_base):
- # Nothing to do
- sys.exit(0)
-else:
# Migrate "vpn l2tp authentication radius-source-address" to new
# "vpn l2tp authentication radius source-address"
if config.exists(cfg_base + ['radius-source-address']):
@@ -51,10 +54,3 @@ else:
# delete top level tag node
if config.exists(cfg_base + ['radius-server']):
config.delete(cfg_base + ['radius-server'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/l2tp/1-to-2 b/src/migration-scripts/l2tp/1-to-2
index 2ffb91c53..468d564ac 100755..100644
--- a/src/migration-scripts/l2tp/1-to-2
+++ b/src/migration-scripts/l2tp/1-to-2
@@ -1,33 +1,28 @@
-#!/usr/bin/env python3
-
-# Delete depricated outside-nexthop address
-
-import sys
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
+
+# T1858: Delete deprecated outside-nexthop
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+cfg_base = ['vpn', 'l2tp', 'remote-access']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_base):
+ # Nothing to do
+ return
-cfg_base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(cfg_base):
- # Nothing to do
- sys.exit(0)
-else:
if config.exists(cfg_base + ['outside-nexthop']):
config.delete(cfg_base + ['outside-nexthop'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/l2tp/2-to-3 b/src/migration-scripts/l2tp/2-to-3
index 8527c2d4a..00fabb6b6 100755..100644
--- a/src/migration-scripts/l2tp/2-to-3
+++ b/src/migration-scripts/l2tp/2-to-3
@@ -1,40 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
-# - remove primary/secondary identifier from nameserver
-# - TODO: remove radius server req-limit
+# T2264: combine IPv4/IPv6 name-server CLI syntax
+# T2264: combine WINS CLI syntax
+# T2264: remove RADIUS req-limit node
+# T2264: migrate IPv6 prefix node to common CLI style
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['vpn', 'l2tp', 'remote-access']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
# Migrate IPv4 DNS servers
dns_base = base + ['dns-servers']
if config.exists(dns_base):
@@ -98,10 +90,3 @@ else:
prefix = p.split(',')[0]
mask = p.split(',')[1]
config.set(ipv6_base + ['delegate', prefix, 'delegate-prefix'], value=mask)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/l2tp/3-to-4 b/src/migration-scripts/l2tp/3-to-4
index 14b86ff04..01c3fa844 100755..100644
--- a/src/migration-scripts/l2tp/3-to-4
+++ b/src/migration-scripts/l2tp/3-to-4
@@ -1,26 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
-# - remove primary/secondary identifier from nameserver
-# - TODO: remove radius server req-limit
+# T2816: T3642: Move IPSec/L2TP code into vpn_ipsec.py and update to use PKI.
import os
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_private_key
@@ -28,141 +24,125 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access', 'ipsec-settings']
pki_base = ['pki']
-if not config.exists(base):
- exit(0)
-
AUTH_DIR = '/config/auth'
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
-if not config.exists(base + ['authentication', 'x509']):
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(base + ['authentication', 'x509']):
+ return
+
+ x509_base = base + ['authentication', 'x509']
+ pki_name = 'l2tp_remote_access'
+
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on l2tp remote-access config')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['crl-file']):
+ crl_file = config.return_value(x509_base + ['crl-file'])
+ crl_path = os.path.join(AUTH_DIR, crl_file)
+ crl = None
+
+ if os.path.isfile(crl_path):
+ if not os.access(crl_path, os.R_OK):
+ run(f'sudo chmod 644 {crl_path}')
+
+ with open(crl_path, 'r') as f:
+ crl_data = f.read()
+ crl = load_certificate(crl_data, wrap_tags=False)
+
+ if crl:
+ crl_pem = encode_certificate(crl)
+ config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+ else:
+ print(f'Failed to migrate CRL on l2tp remote-access config')
+
+ config.delete(x509_base + ['crl-file'])
+
+ if config.exists(x509_base + ['server-cert-file']):
+ cert_file = config.return_value(x509_base + ['server-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on l2tp remote-access config')
+
+ config.delete(x509_base + ['server-cert-file'])
+
+ if config.exists(x509_base + ['server-key-file']):
+ key_file = config.return_value(x509_base + ['server-key-file'])
+ key_passphrase = None
-x509_base = base + ['authentication', 'x509']
-pki_name = 'l2tp_remote_access'
+ if config.exists(x509_base + ['server-key-password']):
+ key_passphrase = config.return_value(x509_base + ['server-key-password'])
-if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
-if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
-if config.exists(x509_base + ['ca-cert-file']):
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on l2tp remote-access config')
-
- config.delete(x509_base + ['ca-cert-file'])
-
-if config.exists(x509_base + ['crl-file']):
- crl_file = config.return_value(x509_base + ['crl-file'])
- crl_path = os.path.join(AUTH_DIR, crl_file)
- crl = None
-
- if os.path.isfile(crl_path):
- if not os.access(crl_path, os.R_OK):
- run(f'sudo chmod 644 {crl_path}')
-
- with open(crl_path, 'r') as f:
- crl_data = f.read()
- crl = load_certificate(crl_data, wrap_tags=False)
-
- if crl:
- crl_pem = encode_certificate(crl)
- config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
- else:
- print(f'Failed to migrate CRL on l2tp remote-access config')
-
- config.delete(x509_base + ['crl-file'])
-
-if config.exists(x509_base + ['server-cert-file']):
- cert_file = config.return_value(x509_base + ['server-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on l2tp remote-access config')
-
- config.delete(x509_base + ['server-cert-file'])
-
-if config.exists(x509_base + ['server-key-file']):
- key_file = config.return_value(x509_base + ['server-key-file'])
- key_passphrase = None
-
- if config.exists(x509_base + ['server-key-password']):
- key_passphrase = config.return_value(x509_base + ['server-key-password'])
-
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=key_passphrase)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
-
- if key_passphrase:
- config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected'])
- config.set(x509_base + ['private-key-passphrase'], value=key_passphrase)
- else:
- print(f'Failed to migrate private key on l2tp remote-access config')
-
- config.delete(x509_base + ['server-key-file'])
- if config.exists(x509_base + ['server-key-password']):
- config.delete(x509_base + ['server-key-password'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=key_passphrase)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+
+ if key_passphrase:
+ config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected'])
+ config.set(x509_base + ['private-key-passphrase'], value=key_passphrase)
+ else:
+ print(f'Failed to migrate private key on l2tp remote-access config')
+
+ config.delete(x509_base + ['server-key-file'])
+ if config.exists(x509_base + ['server-key-password']):
+ config.delete(x509_base + ['server-key-password'])
diff --git a/src/migration-scripts/l2tp/4-to-5 b/src/migration-scripts/l2tp/4-to-5
index b7f4d2677..56d451b8d 100755..100644
--- a/src/migration-scripts/l2tp/4-to-5
+++ b/src/migration-scripts/l2tp/4-to-5
@@ -1,85 +1,68 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - move all pool to named pools
# 'start-stop' migrate to namedpool 'default-range-pool'
# 'subnet' migrate to namedpool 'default-subnet-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.base import Warning
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
pool_base = base + ['client-ip-pool']
-if not config.exists(base):
- exit(0)
-if not config.exists(pool_base):
- exit(0)
-default_pool = ''
-range_pool_name = 'default-range-pool'
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
- def is_legalrange(ip1: str, ip2: str, mask: str):
- from ipaddress import IPv4Interface
- interface1 = IPv4Interface(f'{ip1}/{mask}')
+ if not config.exists(pool_base):
+ return
- interface2 = IPv4Interface(f'{ip2}/{mask}')
- return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+ default_pool = ''
+ range_pool_name = 'default-range-pool'
- start_ip = config.return_value(pool_base + ['start'])
- stop_ip = config.return_value(pool_base + ['stop'])
- if is_legalrange(start_ip, stop_ip,'24'):
- ip_range = f'{start_ip}-{stop_ip}'
- config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
- default_pool = range_pool_name
- else:
- Warning(
- f'L2TP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
+ if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+ def is_legalrange(ip1: str, ip2: str, mask: str):
+ from ipaddress import IPv4Interface
+ interface1 = IPv4Interface(f'{ip1}/{mask}')
+
+ interface2 = IPv4Interface(f'{ip2}/{mask}')
+ return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
- config.delete(pool_base + ['start'])
- config.delete(pool_base + ['stop'])
+ start_ip = config.return_value(pool_base + ['start'])
+ stop_ip = config.return_value(pool_base + ['stop'])
+ if is_legalrange(start_ip, stop_ip,'24'):
+ ip_range = f'{start_ip}-{stop_ip}'
+ config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+ default_pool = range_pool_name
+ else:
+ Warning(
+ f'L2TP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
-if config.exists(pool_base + ['subnet']):
- for subnet in config.return_values(pool_base + ['subnet']):
- config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
+ config.delete(pool_base + ['start'])
+ config.delete(pool_base + ['stop'])
- config.delete(pool_base + ['subnet'])
- default_pool = range_pool_name
+ if config.exists(pool_base + ['subnet']):
+ for subnet in config.return_values(pool_base + ['subnet']):
+ config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
-if default_pool:
- config.set(base + ['default-pool'], value=default_pool)
-# format as tag node
-config.set_tag(pool_base)
+ config.delete(pool_base + ['subnet'])
+ default_pool = range_pool_name
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if default_pool:
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/l2tp/5-to-6 b/src/migration-scripts/l2tp/5-to-6
index ac40b89c8..cc9f948a6 100755..100644
--- a/src/migration-scripts/l2tp/5-to-6
+++ b/src/migration-scripts/l2tp/5-to-6
@@ -1,106 +1,88 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(base):
- exit(0)
-
-#migrate idle to ppp option lcp-echo-timeout
-idle_path = base + ['idle']
-if config.exists(idle_path):
- config.set(base + ['ppp-options', 'lcp-echo-timeout'],
- value=config.return_value(idle_path))
- config.delete(idle_path)
-
-#migrate mppe from authentication to ppp-otion
-mppe_path = base + ['authentication', 'mppe']
-if config.exists(mppe_path):
- config.set(base + ['ppp-options', 'mppe'],
- value=config.return_value(mppe_path))
- config.delete(mppe_path)
-
-#migrate require to protocol
-require_path = base + ['authentication', 'require']
-if config.exists(require_path):
- protocols = list(config.return_values(require_path))
- for protocol in protocols:
- config.set(base + ['authentication', 'protocols'], value=protocol,
- replace=False)
- config.delete(require_path)
-else:
- config.set(base + ['authentication', 'protocols'], value='mschap-v2')
-
-#migrate default gateway if not exist
-if not config.exists(base + ['gateway-address']):
- config.set(base + ['gateway-address'], value='10.255.255.0')
-
-#migrate authentication radius timeout
-rad_timeout_path = base + ['authentication', 'radius', 'timeout']
-if config.exists(rad_timeout_path):
- if int(config.return_value(rad_timeout_path)) > 60:
- config.set(rad_timeout_path, value=60)
-
-#migrate authentication radius acct timeout
-rad_acct_timeout_path = base + ['authentication', 'radius', 'acct-timeout']
-if config.exists(rad_acct_timeout_path):
- if int(config.return_value(rad_acct_timeout_path)) > 60:
- config.set(rad_acct_timeout_path,value=60)
-
-#migrate authentication radius max-try
-rad_max_try_path = base + ['authentication', 'radius', 'max-try']
-if config.exists(rad_max_try_path):
- if int(config.return_value(rad_max_try_path)) > 20:
- config.set(rad_max_try_path, value=20)
-
-#migrate dae-server to dynamic-author
-dae_path_old = base + ['authentication', 'radius', 'dae-server']
-dae_path_new = base + ['authentication', 'radius', 'dynamic-author']
-
-if config.exists(dae_path_old + ['ip-address']):
- config.set(dae_path_new + ['server'],
- value=config.return_value(dae_path_old + ['ip-address']))
-
-if config.exists(dae_path_old + ['port']):
- config.set(dae_path_new + ['port'],
- value=config.return_value(dae_path_old + ['port']))
-
-if config.exists(dae_path_old + ['secret']):
- config.set(dae_path_new + ['key'],
- value=config.return_value(dae_path_old + ['secret']))
-
-if config.exists(dae_path_old):
- config.delete(dae_path_old)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ #migrate idle to ppp option lcp-echo-timeout
+ idle_path = base + ['idle']
+ if config.exists(idle_path):
+ config.set(base + ['ppp-options', 'lcp-echo-timeout'],
+ value=config.return_value(idle_path))
+ config.delete(idle_path)
+
+ #migrate mppe from authentication to ppp-otion
+ mppe_path = base + ['authentication', 'mppe']
+ if config.exists(mppe_path):
+ config.set(base + ['ppp-options', 'mppe'],
+ value=config.return_value(mppe_path))
+ config.delete(mppe_path)
+
+ #migrate require to protocol
+ require_path = base + ['authentication', 'require']
+ if config.exists(require_path):
+ protocols = list(config.return_values(require_path))
+ for protocol in protocols:
+ config.set(base + ['authentication', 'protocols'], value=protocol,
+ replace=False)
+ config.delete(require_path)
+ else:
+ config.set(base + ['authentication', 'protocols'], value='mschap-v2')
+
+ #migrate default gateway if not exist
+ if not config.exists(base + ['gateway-address']):
+ config.set(base + ['gateway-address'], value='10.255.255.0')
+
+ #migrate authentication radius timeout
+ rad_timeout_path = base + ['authentication', 'radius', 'timeout']
+ if config.exists(rad_timeout_path):
+ if int(config.return_value(rad_timeout_path)) > 60:
+ config.set(rad_timeout_path, value=60)
+
+ #migrate authentication radius acct timeout
+ rad_acct_timeout_path = base + ['authentication', 'radius', 'acct-timeout']
+ if config.exists(rad_acct_timeout_path):
+ if int(config.return_value(rad_acct_timeout_path)) > 60:
+ config.set(rad_acct_timeout_path,value=60)
+
+ #migrate authentication radius max-try
+ rad_max_try_path = base + ['authentication', 'radius', 'max-try']
+ if config.exists(rad_max_try_path):
+ if int(config.return_value(rad_max_try_path)) > 20:
+ config.set(rad_max_try_path, value=20)
+
+ #migrate dae-server to dynamic-author
+ dae_path_old = base + ['authentication', 'radius', 'dae-server']
+ dae_path_new = base + ['authentication', 'radius', 'dynamic-author']
+
+ if config.exists(dae_path_old + ['ip-address']):
+ config.set(dae_path_new + ['server'],
+ value=config.return_value(dae_path_old + ['ip-address']))
+
+ if config.exists(dae_path_old + ['port']):
+ config.set(dae_path_new + ['port'],
+ value=config.return_value(dae_path_old + ['port']))
+
+ if config.exists(dae_path_old + ['secret']):
+ config.set(dae_path_new + ['key'],
+ value=config.return_value(dae_path_old + ['secret']))
+
+ if config.exists(dae_path_old):
+ config.delete(dae_path_old)
diff --git a/src/migration-scripts/l2tp/6-to-7 b/src/migration-scripts/l2tp/6-to-7
index 1c536585c..4dba5974e 100755..100644
--- a/src/migration-scripts/l2tp/6-to-7
+++ b/src/migration-scripts/l2tp/6-to-7
@@ -1,57 +1,39 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrating to named ipv6 pools
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
pool_base = base + ['client-ipv6-pool']
-if not config.exists(base):
- exit(0)
-if not config.exists(pool_base):
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-ipv6_pool_name = 'ipv6-pool'
-config.copy(pool_base, pool_base + [ipv6_pool_name])
+ if not config.exists(pool_base):
+ return
-if config.exists(pool_base + ['prefix']):
- config.delete(pool_base + ['prefix'])
- config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
-if config.exists(pool_base + ['delegate']):
- config.delete(pool_base + ['delegate'])
-# format as tag node
-config.set_tag(pool_base)
+ ipv6_pool_name = 'ipv6-pool'
+ config.copy(pool_base, pool_base + [ipv6_pool_name])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(pool_base + ['prefix']):
+ config.delete(pool_base + ['prefix'])
+ config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+ if config.exists(pool_base + ['delegate']):
+ config.delete(pool_base + ['delegate'])
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/l2tp/7-to-8 b/src/migration-scripts/l2tp/7-to-8
index e429ed057..527906fc8 100755..100644
--- a/src/migration-scripts/l2tp/7-to-8
+++ b/src/migration-scripts/l2tp/7-to-8
@@ -1,65 +1,47 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrate from 'ccp-disable' to 'ppp-options.disable-ccp'
# Migration ipv6 options
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(base):
- exit(0)
-
-#CCP migration
-if config.exists(base + ['ccp-disable']):
- config.delete(base + ['ccp-disable'])
- config.set(base + ['ppp-options', 'disable-ccp'])
-
-#IPV6 options migrations
-if config.exists(base + ['ppp-options','ipv6-peer-intf-id']):
- intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id'])
- if intf_peer_id == 'ipv4':
- intf_peer_id = 'ipv4-addr'
- config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True)
- config.delete(base + ['ppp-options','ipv6-peer-intf-id'])
-
-if config.exists(base + ['ppp-options','ipv6-intf-id']):
- intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id'])
- config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True)
- config.delete(base + ['ppp-options','ipv6-intf-id'])
-
-if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']):
- config.set(base + ['ppp-options','ipv6-accept-peer-interface-id'])
- config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ #CCP migration
+ if config.exists(base + ['ccp-disable']):
+ config.delete(base + ['ccp-disable'])
+ config.set(base + ['ppp-options', 'disable-ccp'])
+
+ #IPV6 options migrations
+ if config.exists(base + ['ppp-options','ipv6-peer-intf-id']):
+ intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id'])
+ if intf_peer_id == 'ipv4':
+ intf_peer_id = 'ipv4-addr'
+ config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True)
+ config.delete(base + ['ppp-options','ipv6-peer-intf-id'])
+
+ if config.exists(base + ['ppp-options','ipv6-intf-id']):
+ intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id'])
+ config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True)
+ config.delete(base + ['ppp-options','ipv6-intf-id'])
+
+ if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']):
+ config.set(base + ['ppp-options','ipv6-accept-peer-interface-id'])
+ config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id'])
diff --git a/src/migration-scripts/l2tp/8-to-9 b/src/migration-scripts/l2tp/8-to-9
index 672180e25..e6b689e80 100755..100644
--- a/src/migration-scripts/l2tp/8-to-9
+++ b/src/migration-scripts/l2tp/8-to-9
@@ -1,46 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Deleted 'dhcp-interface' from l2tp
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(base):
- exit(0)
-# deleting unused dhcp-interface
-if config.exists(base + ['dhcp-interface']):
- config.delete(base + ['dhcp-interface'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # deleting unused dhcp-interface
+ if config.exists(base + ['dhcp-interface']):
+ config.delete(base + ['dhcp-interface'])
diff --git a/src/migration-scripts/lldp/0-to-1 b/src/migration-scripts/lldp/0-to-1
index a99356062..c16e7e84b 100755..100644
--- a/src/migration-scripts/lldp/0-to-1
+++ b/src/migration-scripts/lldp/0-to-1
@@ -1,49 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Delete "set service lldp interface <interface> location civic-based" option
# as it was broken most of the time anyways
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base = ['service', 'lldp', 'interface']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['service', 'lldp', 'interface']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
# Delete nodes with abandoned CLI syntax
for interface in config.list_nodes(base):
if config.exists(base + [interface, 'location', 'civic-based']):
config.delete(base + [interface, 'location', 'civic-based'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/lldp/1-to-2 b/src/migration-scripts/lldp/1-to-2
index 35efb25db..7f233a725 100755..100644
--- a/src/migration-scripts/lldp/1-to-2
+++ b/src/migration-scripts/lldp/1-to-2
@@ -1,48 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5855: migrate "set service lldp snmp enable" -> `set service lldp snmp"
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'lldp']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-if config.exists(base + ['snmp']):
- enabled = config.exists(base + ['snmp', 'enable'])
- config.delete(base + ['snmp'])
- if enabled: config.set(base + ['snmp'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ if config.exists(base + ['snmp']):
+ enabled = config.exists(base + ['snmp', 'enable'])
+ config.delete(base + ['snmp'])
+ if enabled: config.set(base + ['snmp'])
diff --git a/src/migration-scripts/monitoring/0-to-1 b/src/migration-scripts/monitoring/0-to-1
index 384d22f8c..92f824325 100755..100644
--- a/src/migration-scripts/monitoring/0-to-1
+++ b/src/migration-scripts/monitoring/0-to-1
@@ -14,58 +14,53 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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 sys import argv
-from sys import exit
+# T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'monitoring', 'telegraf']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['authentication', 'organization']):
- tmp = config.return_value(base + ['authentication', 'organization'])
- config.delete(base + ['authentication', 'organization'])
- config.set(base + ['influxdb', 'authentication', 'organization'], value=tmp)
-if config.exists(base + ['authentication', 'token']):
- tmp = config.return_value(base + ['authentication', 'token'])
- config.delete(base + ['authentication', 'token'])
- config.set(base + ['influxdb', 'authentication', 'token'], value=tmp)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-if config.exists(base + ['bucket']):
- tmp = config.return_value(base + ['bucket'])
- config.delete(base + ['bucket'])
- config.set(base + ['influxdb', 'bucket'], value=tmp)
+ if config.exists(base + ['authentication', 'organization']):
+ tmp = config.return_value(base + ['authentication', 'organization'])
+ config.delete(base + ['authentication', 'organization'])
+ config.set(base + ['influxdb', 'authentication', 'organization'], value=tmp)
-if config.exists(base + ['port']):
- tmp = config.return_value(base + ['port'])
- config.delete(base + ['port'])
- config.set(base + ['influxdb', 'port'], value=tmp)
+ if config.exists(base + ['authentication', 'token']):
+ tmp = config.return_value(base + ['authentication', 'token'])
+ config.delete(base + ['authentication', 'token'])
+ config.set(base + ['influxdb', 'authentication', 'token'], value=tmp)
-if config.exists(base + ['url']):
- tmp = config.return_value(base + ['url'])
- config.delete(base + ['url'])
- config.set(base + ['influxdb', 'url'], value=tmp)
+ if config.exists(base + ['bucket']):
+ tmp = config.return_value(base + ['bucket'])
+ config.delete(base + ['bucket'])
+ config.set(base + ['influxdb', 'bucket'], value=tmp)
+ if config.exists(base + ['port']):
+ tmp = config.return_value(base + ['port'])
+ config.delete(base + ['port'])
+ config.set(base + ['influxdb', 'port'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(base + ['url']):
+ tmp = config.return_value(base + ['url'])
+ config.delete(base + ['url'])
+ config.set(base + ['influxdb', 'url'], value=tmp)
diff --git a/src/migration-scripts/nat/4-to-5 b/src/migration-scripts/nat/4-to-5
index ce215d455..e1919da50 100755..100644
--- a/src/migration-scripts/nat/4-to-5
+++ b/src/migration-scripts/nat/4-to-5
@@ -1,40 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Drop the enable/disable from the nat "log" node. If log node is specified
# it is "enabled"
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['nat']):
- # Nothing to do
- exit(0)
-else:
for direction in ['source', 'destination']:
# If a node doesn't exist, we obviously have nothing to do.
if not config.exists(['nat', direction]):
@@ -55,10 +43,3 @@ else:
config.delete(base + ['log'])
if tmp == 'enable':
config.set(base + ['log'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/nat/5-to-6 b/src/migration-scripts/nat/5-to-6
index cfe98ddcf..a583d4eb6 100755..100644
--- a/src/migration-scripts/nat/5-to-6
+++ b/src/migration-scripts/nat/5-to-6
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5643: move from 'set nat [source|destination] rule X [inbound-interface|outbound interface] <iface>'
# to
@@ -23,7 +22,7 @@
# 'set nat [source|destination] rule X [source| destination| translation] address <IP/Netmask| !IP/Netmask>'
import ipaddress
-from sys import argv,exit
+
from vyos.configtree import ConfigTree
@@ -62,21 +61,10 @@ def _func_T6100(conf, base_path):
return
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
if not config.exists(['nat']):
# Nothing to do
- exit(0)
+ return
for direction in ['source', 'destination']:
# If a node doesn't exist, we obviously have nothing to do.
@@ -92,10 +80,3 @@ if __name__ == '__main__':
base = ['nat', direction, 'rule', rule]
_func_T5643(config,base)
_func_T6100(config,base)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/nat/6-to-7 b/src/migration-scripts/nat/6-to-7
index a2e735394..81b413e36 100755..100644
--- a/src/migration-scripts/nat/6-to-7
+++ b/src/migration-scripts/nat/6-to-7
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5681: Firewall re-writing. Simplify cli when mathcing interface
# From
@@ -23,49 +22,31 @@
# 'set nat [source|destination] rule X [inbound-interface|outbound interface] group <iface_group>'
# Also remove command if interface == any
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['nat']):
- # Nothing to do
- exit(0)
-
-for direction in ['source', 'destination']:
- # If a node doesn't exist, we obviously have nothing to do.
- if not config.exists(['nat', direction]):
- continue
-
- # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
- # but there are no rules under it.
- if not config.list_nodes(['nat', direction]):
- continue
-
- for rule in config.list_nodes(['nat', direction, 'rule']):
- base = ['nat', direction, 'rule', rule]
- for iface in ['inbound-interface','outbound-interface']:
- if config.exists(base + [iface]):
- if config.exists(base + [iface, 'interface-name']):
- tmp = config.return_value(base + [iface, 'interface-name'])
- if tmp != 'any':
- config.delete(base + [iface, 'interface-name'])
- config.set(base + [iface, 'name'], value=tmp)
- else:
- config.delete(base + [iface])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat']):
+ # Nothing to do
+ return
+
+ for direction in ['source', 'destination']:
+ # If a node doesn't exist, we obviously have nothing to do.
+ if not config.exists(['nat', direction]):
+ continue
+
+ # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
+ # but there are no rules under it.
+ if not config.list_nodes(['nat', direction]):
+ continue
+
+ for rule in config.list_nodes(['nat', direction, 'rule']):
+ base = ['nat', direction, 'rule', rule]
+ for iface in ['inbound-interface','outbound-interface']:
+ if config.exists(base + [iface]):
+ if config.exists(base + [iface, 'interface-name']):
+ tmp = config.return_value(base + [iface, 'interface-name'])
+ if tmp != 'any':
+ config.delete(base + [iface, 'interface-name'])
+ config.set(base + [iface, 'name'], value=tmp)
+ else:
+ config.delete(base + [iface])
diff --git a/src/migration-scripts/nat/7-to-8 b/src/migration-scripts/nat/7-to-8
index ab2ffa6d3..9ae389ef1 100755..100644
--- a/src/migration-scripts/nat/7-to-8
+++ b/src/migration-scripts/nat/7-to-8
@@ -1,62 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6345: random - In kernel 5.0 and newer this is the same as fully-random.
# In earlier kernels the port mapping will be randomized using a seeded
# MD5 hash mix using source and destination address and destination port.
# drop fully-random from CLI
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['nat']):
- # Nothing to do
- exit(0)
-
-for direction in ['source', 'destination']:
- # If a node doesn't exist, we obviously have nothing to do.
- if not config.exists(['nat', direction]):
- continue
-
- # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
- # but there are no rules under it.
- if not config.list_nodes(['nat', direction]):
- continue
-
- for rule in config.list_nodes(['nat', direction, 'rule']):
- port_mapping = ['nat', direction, 'rule', rule, 'translation', 'options', 'port-mapping']
- if config.exists(port_mapping):
- tmp = config.return_value(port_mapping)
- if tmp == 'fully-random':
- config.set(port_mapping, value='random')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat']):
+ # Nothing to do
+ return
+
+ for direction in ['source', 'destination']:
+ # If a node doesn't exist, we obviously have nothing to do.
+ if not config.exists(['nat', direction]):
+ continue
+
+ # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
+ # but there are no rules under it.
+ if not config.list_nodes(['nat', direction]):
+ continue
+
+ for rule in config.list_nodes(['nat', direction, 'rule']):
+ port_mapping = ['nat', direction, 'rule', rule, 'translation', 'options', 'port-mapping']
+ if config.exists(port_mapping):
+ tmp = config.return_value(port_mapping)
+ if tmp == 'fully-random':
+ config.set(port_mapping, value='random')
diff --git a/src/migration-scripts/nat66/0-to-1 b/src/migration-scripts/nat66/0-to-1
index 444b2315f..b3c6bf4cc 100755..100644
--- a/src/migration-scripts/nat66/0-to-1
+++ b/src/migration-scripts/nat66/0-to-1
@@ -1,33 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
def merge_npt(config,base,rule):
merge_base = ['nat66','source','rule',rule]
# Configure migration functions
@@ -51,21 +38,15 @@ def merge_npt(config,base,rule):
tmp = config.return_value(base + ['translation','prefix'])
config.set(merge_base + ['translation','address'],value=tmp)
-if not config.exists(['nat', 'nptv6']):
- # Nothing to do
- exit(0)
-
-for rule in config.list_nodes(['nat', 'nptv6', 'rule']):
- base = ['nat', 'nptv6', 'rule', rule]
- # Merge 'nat nptv6' to 'nat66 source'
- merge_npt(config,base,rule)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat', 'nptv6']):
+ # Nothing to do
+ return
-# Delete the original NPT configuration
-config.delete(['nat','nptv6']);
+ for rule in config.list_nodes(['nat', 'nptv6', 'rule']):
+ base = ['nat', 'nptv6', 'rule', rule]
+ # Merge 'nat nptv6' to 'nat66 source'
+ merge_npt(config,base,rule)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Delete the original NPT configuration
+ config.delete(['nat','nptv6']);
diff --git a/src/migration-scripts/nat66/1-to-2 b/src/migration-scripts/nat66/1-to-2
index b7d4e3f6b..f49940ae0 100755..100644
--- a/src/migration-scripts/nat66/1-to-2
+++ b/src/migration-scripts/nat66/1-to-2
@@ -14,50 +14,48 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
+
# T5681: Firewall re-writing. Simplify cli when mathcing interface
# From
# 'set nat66 [source|destination] rule X [inbound-interface|outbound interface] <iface>'
# to
# 'set nat66 [source|destination] rule X [inbound-interface|outbound interface] name <iface>'
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-if not config.exists(['nat66']):
- # Nothing to do
- exit(0)
-
-for direction in ['source', 'destination']:
- # If a node doesn't exist, we obviously have nothing to do.
- if not config.exists(['nat66', direction]):
- continue
-
- # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
- # but there are no rules under it.
- if not config.list_nodes(['nat66', direction]):
- continue
-
- for rule in config.list_nodes(['nat66', direction, 'rule']):
- base = ['nat66', direction, 'rule', rule]
- for iface in ['inbound-interface','outbound-interface']:
- if config.exists(base + [iface]):
- tmp = config.return_value(base + [iface])
- config.delete(base + [iface])
- config.set(base + [iface, 'name'], value=tmp)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat66']):
+ # Nothing to do
+ return
+
+ for direction in ['source', 'destination']:
+ # If a node doesn't exist, we obviously have nothing to do.
+ if not config.exists(['nat66', direction]):
+ continue
+
+ # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
+ # but there are no rules under it.
+ if not config.list_nodes(['nat66', direction]):
+ continue
+
+ for rule in config.list_nodes(['nat66', direction, 'rule']):
+ base = ['nat66', direction, 'rule', rule]
+ for iface in ['inbound-interface','outbound-interface']:
+ if config.exists(base + [iface]):
+ tmp = config.return_value(base + [iface])
+ config.delete(base + [iface])
+ config.set(base + [iface, 'name'], value=tmp)
diff --git a/src/migration-scripts/nat66/2-to-3 b/src/migration-scripts/nat66/2-to-3
index f34f170b3..55d5f4b2b 100755..100644
--- a/src/migration-scripts/nat66/2-to-3
+++ b/src/migration-scripts/nat66/2-to-3
@@ -1,61 +1,45 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from sys import argv,exit
-from vyos.configtree import ConfigTree
+# 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/>.
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+# T2898: add ndp-proxy service
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+from vyos.configtree import ConfigTree
base = ['nat66', 'source']
new_base = ['service', 'ndp-proxy', 'interface']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for rule in config.list_nodes(base + ['rule']):
- base_rule = base + ['rule', rule]
-
- interface = None
- if config.exists(base_rule + ['outbound-interface', 'name']):
- interface = config.return_value(base_rule + ['outbound-interface', 'name'])
- else:
- continue
-
- prefix_base = base_rule + ['source', 'prefix']
- if config.exists(prefix_base):
- prefix = config.return_value(prefix_base)
- config.set(new_base + [interface, 'prefix', prefix, 'mode'], value='static')
- config.set_tag(new_base)
- config.set_tag(new_base + [interface, 'prefix'])
-
- if config.exists(base_rule + ['disable']):
- config.set(new_base + [interface, 'prefix', prefix, 'disable'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for rule in config.list_nodes(base + ['rule']):
+ base_rule = base + ['rule', rule]
+
+ interface = None
+ if config.exists(base_rule + ['outbound-interface', 'name']):
+ interface = config.return_value(base_rule + ['outbound-interface', 'name'])
+ else:
+ continue
+
+ prefix_base = base_rule + ['source', 'prefix']
+ if config.exists(prefix_base):
+ prefix = config.return_value(prefix_base)
+ config.set(new_base + [interface, 'prefix', prefix, 'mode'], value='static')
+ config.set_tag(new_base)
+ config.set_tag(new_base + [interface, 'prefix'])
+
+ if config.exists(base_rule + ['disable']):
+ config.set(new_base + [interface, 'prefix', prefix, 'disable'])
diff --git a/src/migration-scripts/ntp/0-to-1 b/src/migration-scripts/ntp/0-to-1
index cbce45b9b..01f5a460a 100755..100644
--- a/src/migration-scripts/ntp/0-to-1
+++ b/src/migration-scripts/ntp/0-to-1
@@ -1,36 +1,32 @@
#!/usr/bin/env python3
-# Delete "set system ntp server <n> dynamic" option
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
-import sys
+# Delete "set system ntp server <n> dynamic" option
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['system', 'ntp', 'server']):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['system', 'ntp', 'server']):
- # Nothing to do
- sys.exit(0)
-else:
# Delete abandoned leaf node if found inside tag node for
# "set system ntp server <n> dynamic"
base = ['system', 'ntp', 'server']
for server in config.list_nodes(base):
if config.exists(base + [server, 'dynamic']):
config.delete(base + [server, 'dynamic'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/ntp/1-to-2 b/src/migration-scripts/ntp/1-to-2
index fd1f15d91..fd7b08221 100755..100644
--- a/src/migration-scripts/ntp/1-to-2
+++ b/src/migration-scripts/ntp/1-to-2
@@ -1,72 +1,53 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3008: move from ntpd to chrony and migrate "system ntp" to "service ntp"
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['system', 'ntp']
new_base_path = ['service', 'ntp']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-
-# config.copy does not recursively create a path, so create ['service'] if
-# it doesn't yet exist, such as for config.boot.default
-if not config.exists(['service']):
- config.set(['service'])
-
-# copy "system ntp" to "service ntp"
-config.copy(base_path, new_base_path)
-config.delete(base_path)
-
-# chrony does not support the preempt option, drop it
-for server in config.list_nodes(new_base_path + ['server']):
- server_base = new_base_path + ['server', server]
- if config.exists(server_base + ['preempt']):
- config.delete(server_base + ['preempt'])
-
-# Rename "allow-clients" -> "allow-client"
-if config.exists(new_base_path + ['allow-clients']):
- config.rename(new_base_path + ['allow-clients'], 'allow-client')
-
-# By default VyOS 1.3 allowed NTP queries for all networks - in chrony we
-# explicitly disable this behavior and clients need to be specified using the
-# allow-client CLI option. In order to be fully backwards compatible, we specify
-# 0.0.0.0/0 and ::/0 as allow networks if not specified otherwise explicitly.
-if not config.exists(new_base_path + ['allow-client']):
- config.set(new_base_path + ['allow-client', 'address'], value='0.0.0.0/0', replace=False)
- config.set(new_base_path + ['allow-client', 'address'], value='::/0', replace=False)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
+
+ # config.copy does not recursively create a path, so create ['service'] if
+ # it doesn't yet exist, such as for config.boot.default
+ if not config.exists(['service']):
+ config.set(['service'])
+
+ # copy "system ntp" to "service ntp"
+ config.copy(base_path, new_base_path)
+ config.delete(base_path)
+
+ # chrony does not support the preempt option, drop it
+ for server in config.list_nodes(new_base_path + ['server']):
+ server_base = new_base_path + ['server', server]
+ if config.exists(server_base + ['preempt']):
+ config.delete(server_base + ['preempt'])
+
+ # Rename "allow-clients" -> "allow-client"
+ if config.exists(new_base_path + ['allow-clients']):
+ config.rename(new_base_path + ['allow-clients'], 'allow-client')
+
+ # By default VyOS 1.3 allowed NTP queries for all networks - in chrony we
+ # explicitly disable this behavior and clients need to be specified using the
+ # allow-client CLI option. In order to be fully backwards compatible, we specify
+ # 0.0.0.0/0 and ::/0 as allow networks if not specified otherwise explicitly.
+ if not config.exists(new_base_path + ['allow-client']):
+ config.set(new_base_path + ['allow-client', 'address'], value='0.0.0.0/0', replace=False)
+ config.set(new_base_path + ['allow-client', 'address'], value='::/0', replace=False)
diff --git a/src/migration-scripts/ntp/2-to-3 b/src/migration-scripts/ntp/2-to-3
index a4351845e..bbda90351 100755..100644
--- a/src/migration-scripts/ntp/2-to-3
+++ b/src/migration-scripts/ntp/2-to-3
@@ -1,62 +1,43 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5154: allow only one ip address per family for parameter 'listen-address'
# Allow only one interface for parameter 'interface'
# If more than one are specified, remove such entries
-import sys
-
from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
from vyos.template import is_ipv6
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['service', 'ntp']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv4(addr)]) > 1):
- for addr in config.return_values(base_path + ['listen-address']):
- if is_ipv4(addr):
- config.delete_value(base_path + ['listen-address'], addr)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
-if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv6(addr)]) > 1):
- for addr in config.return_values(base_path + ['listen-address']):
- if is_ipv6(addr):
- config.delete_value(base_path + ['listen-address'], addr)
+ if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv4(addr)]) > 1):
+ for addr in config.return_values(base_path + ['listen-address']):
+ if is_ipv4(addr):
+ config.delete_value(base_path + ['listen-address'], addr)
-if config.exists(base_path + ['interface']):
- if len(config.return_values(base_path + ['interface'])) > 1:
- config.delete(base_path + ['interface'])
+ if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv6(addr)]) > 1):
+ for addr in config.return_values(base_path + ['listen-address']):
+ if is_ipv6(addr):
+ config.delete_value(base_path + ['listen-address'], addr)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ if config.exists(base_path + ['interface']):
+ if len(config.return_values(base_path + ['interface'])) > 1:
+ config.delete(base_path + ['interface'])
diff --git a/src/migration-scripts/openconnect/0-to-1 b/src/migration-scripts/openconnect/0-to-1
index c64b16cb2..aa5a97eee 100755..100644
--- a/src/migration-scripts/openconnect/0-to-1
+++ b/src/migration-scripts/openconnect/0-to-1
@@ -1,25 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Update SSL to use PKI configuration
import os
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_private_key
@@ -27,109 +24,93 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'openconnect']
pki_base = ['pki']
-if not config.exists(base):
- exit(0)
-
AUTH_DIR = '/config/auth'
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
-if not config.exists(base + ['ssl']):
- exit(0)
-
-x509_base = base + ['ssl']
-pki_name = 'openconnect'
-
-if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
-if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
-if config.exists(x509_base + ['ca-cert-file']):
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on openconnect config')
-
- config.delete(x509_base + ['ca-cert-file'])
-
-if config.exists(x509_base + ['cert-file']):
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on openconnect config')
-
- config.delete(x509_base + ['cert-file'])
-
-if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on openconnect config')
-
- config.delete(x509_base + ['key-file'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(base + ['ssl']):
+ return
+
+ x509_base = base + ['ssl']
+ pki_name = 'openconnect'
+
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on openconnect config')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['cert-file']):
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on openconnect config')
+
+ config.delete(x509_base + ['cert-file'])
+
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on openconnect config')
+
+ config.delete(x509_base + ['key-file'])
diff --git a/src/migration-scripts/openconnect/1-to-2 b/src/migration-scripts/openconnect/1-to-2
index 7978aa56e..4f74b44df 100755..100644
--- a/src/migration-scripts/openconnect/1-to-2
+++ b/src/migration-scripts/openconnect/1-to-2
@@ -1,42 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Delete depricated outside-nexthop address
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
cfg_base = ['vpn', 'openconnect']
-if not config.exists(cfg_base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_base):
+ # Nothing to do
+ return
+
if config.exists(cfg_base + ['authentication', 'mode']):
if config.return_value(cfg_base + ['authentication', 'mode']) == 'radius':
# if "mode value radius", change to "mode + valueless node radius"
@@ -46,9 +33,3 @@ else:
# if "mode local", change to "mode + node local value password"
config.delete_value(cfg_base + ['authentication', 'mode'], 'local')
config.set(cfg_base + ['authentication', 'mode', 'local'], value='password')
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/openconnect/2-to-3 b/src/migration-scripts/openconnect/2-to-3
index e78fc8a91..00e13ecb0 100755..100644
--- a/src/migration-scripts/openconnect/2-to-3
+++ b/src/migration-scripts/openconnect/2-to-3
@@ -1,50 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4982: Retain prior default TLS version (v1.0) when upgrading installations with existing openconnect configurations
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-
-config = ConfigTree(config_file)
cfg_base = ['vpn', 'openconnect']
-# bail out early if service is unconfigured
-if not config.exists(cfg_base):
- sys.exit(0)
-
-# new default is TLS 1.2 - set explicit old default value of TLS 1.0 for upgraded configurations to keep compatibility
-tls_min_path = cfg_base + ['tls-version-min']
-if not config.exists(tls_min_path):
- config.set(tls_min_path, value='1.0')
+def migrate(config: ConfigTree) -> None:
+ # bail out early if service is unconfigured
+ if not config.exists(cfg_base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ # new default is TLS 1.2 - set explicit old default value of TLS 1.0 for upgraded configurations to keep compatibility
+ tls_min_path = cfg_base + ['tls-version-min']
+ if not config.exists(tls_min_path):
+ config.set(tls_min_path, value='1.0')
diff --git a/src/migration-scripts/openvpn/0-to-1 b/src/migration-scripts/openvpn/0-to-1
index 24bb38d3c..e5db731ed 100755..100644
--- a/src/migration-scripts/openvpn/0-to-1
+++ b/src/migration-scripts/openvpn/0-to-1
@@ -1,26 +1,27 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Removes outdated ciphers (DES and Blowfish) from OpenVPN configs
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['interfaces', 'openvpn']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['interfaces', 'openvpn']):
- # Nothing to do
- sys.exit(0)
-else:
ovpn_intfs = config.list_nodes(['interfaces', 'openvpn'])
for i in ovpn_intfs:
# Remove DES and Blowfish from 'encryption cipher'
@@ -40,10 +41,3 @@ else:
if config.exists(['interfaces', 'openvpn', i, 'encryption']) and \
(config.list_nodes(['interfaces', 'openvpn', i, 'encryption']) == []):
config.delete(['interfaces', 'openvpn', i, 'encryption'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/openvpn/1-to-2 b/src/migration-scripts/openvpn/1-to-2
index 1f82a2128..b7b7d4c77 100755..100644
--- a/src/migration-scripts/openvpn/1-to-2
+++ b/src/migration-scripts/openvpn/1-to-2
@@ -17,25 +17,13 @@
# Removes --cipher option (deprecated) from OpenVPN configs
# and moves it to --data-ciphers for server and client modes
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['interfaces', 'openvpn']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['interfaces', 'openvpn']):
- # Nothing to do
- sys.exit(0)
-else:
ovpn_intfs = config.list_nodes(['interfaces', 'openvpn'])
for i in ovpn_intfs:
# Remove 'encryption cipher' and add this value to 'encryption ncp-ciphers'
@@ -65,10 +53,3 @@ else:
for c in ncp_ciphers:
config.set(ncp_cipher_path, value=c, replace=False)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/ospf/0-to-1 b/src/migration-scripts/ospf/0-to-1
index 4085423a2..a1f810960 100755..100644
--- a/src/migration-scripts/ospf/0-to-1
+++ b/src/migration-scripts/ospf/0-to-1
@@ -1,22 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3753: upgrade to FRR8 and move CLI options to better fit with the new FRR CLI
-from sys import argv
from vyos.configtree import ConfigTree
def ospf_passive_migration(config, ospf_base):
@@ -40,45 +38,29 @@ def ospf_passive_migration(config, ospf_base):
config.set_tag(ospf_base + ['interface'])
config.delete(ospf_base + ['passive-interface-exclude'])
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
ospfv3_base = ['protocols', 'ospfv3']
-if config.exists(ospfv3_base):
- area_base = ospfv3_base + ['area']
- if config.exists(area_base):
- for area in config.list_nodes(area_base):
- if not config.exists(area_base + [area, 'interface']):
- continue
- for interface in config.return_values(area_base + [area, 'interface']):
- config.set(ospfv3_base + ['interface', interface, 'area'], value=area)
- config.set_tag(ospfv3_base + ['interface'])
+def migrate(config: ConfigTree) -> None:
+ if config.exists(ospfv3_base):
+ area_base = ospfv3_base + ['area']
+ if config.exists(area_base):
+ for area in config.list_nodes(area_base):
+ if not config.exists(area_base + [area, 'interface']):
+ continue
- config.delete(area_base + [area, 'interface'])
+ for interface in config.return_values(area_base + [area, 'interface']):
+ config.set(ospfv3_base + ['interface', interface, 'area'], value=area)
+ config.set_tag(ospfv3_base + ['interface'])
-# Migrate OSPF syntax in default VRF
-ospf_base = ['protocols', 'ospf']
-ospf_passive_migration(config, ospf_base)
+ config.delete(area_base + [area, 'interface'])
-vrf_base = ['vrf', 'name']
-if config.exists(vrf_base):
- for vrf in config.list_nodes(vrf_base):
- vrf_ospf_base = vrf_base + [vrf, 'protocols', 'ospf']
- if config.exists(vrf_ospf_base):
- ospf_passive_migration(config, vrf_ospf_base)
+ # Migrate OSPF syntax in default VRF
+ ospf_base = ['protocols', 'ospf']
+ ospf_passive_migration(config, ospf_base)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ vrf_base = ['vrf', 'name']
+ if config.exists(vrf_base):
+ for vrf in config.list_nodes(vrf_base):
+ vrf_ospf_base = vrf_base + [vrf, 'protocols', 'ospf']
+ if config.exists(vrf_ospf_base):
+ ospf_passive_migration(config, vrf_ospf_base)
diff --git a/src/migration-scripts/ospf/1-to-2 b/src/migration-scripts/ospf/1-to-2
index ba9499c60..5368d8dd7 100755..100644
--- a/src/migration-scripts/ospf/1-to-2
+++ b/src/migration-scripts/ospf/1-to-2
@@ -1,80 +1,60 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
ospf_base = ['protocols', 'ospf']
-# Check if OSPF is configured - if so, migrate the CLI node
-if config.exists(ospf_base):
- if config.exists(ospf_base + ['route-map']):
- tmp = config.return_value(ospf_base + ['route-map'])
-
- config.set(['system', 'ip', 'protocol', 'ospf', 'route-map'], value=tmp)
- config.set_tag(['system', 'ip', 'protocol'])
- config.delete(ospf_base + ['route-map'])
-
-ospfv3_base = ['protocols', 'ospfv3']
-# Check if OSPFv3 is configured - if so, migrate the CLI node
-if config.exists(ospfv3_base):
- if config.exists(ospfv3_base + ['route-map']):
- tmp = config.return_value(ospfv3_base + ['route-map'])
-
- config.set(['system', 'ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
- config.set_tag(['system', 'ipv6', 'protocol'])
- config.delete(ospfv3_base + ['route-map'])
-
-# Check if vrf names are configured. Check if OSPF/OSPFv3 is configured - if so,
-# migrate the CLI node(s)
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- vrf_base = ['vrf', 'name', vrf]
- if config.exists(vrf_base + ['protocols', 'ospf', 'route-map']):
- tmp = config.return_value(vrf_base + ['protocols', 'ospf', 'route-map'])
-
- config.set(vrf_base + ['ip', 'protocol', 'ospf', 'route-map'], value=tmp)
- config.set_tag(vrf_base + ['ip', 'protocol', 'ospf'])
- config.delete(vrf_base + ['protocols', 'ospf', 'route-map'])
-
- if config.exists(vrf_base + ['protocols', 'ospfv3', 'route-map']):
- tmp = config.return_value(vrf_base + ['protocols', 'ospfv3', 'route-map'])
-
- config.set(vrf_base + ['ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
- config.set_tag(vrf_base + ['ipv6', 'protocol', 'ospfv6'])
- config.delete(vrf_base + ['protocols', 'ospfv3', 'route-map'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Check if OSPF is configured - if so, migrate the CLI node
+ if config.exists(ospf_base):
+ if config.exists(ospf_base + ['route-map']):
+ tmp = config.return_value(ospf_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'ospf', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(ospf_base + ['route-map'])
+
+ ospfv3_base = ['protocols', 'ospfv3']
+ # Check if OSPFv3 is configured - if so, migrate the CLI node
+ if config.exists(ospfv3_base):
+ if config.exists(ospfv3_base + ['route-map']):
+ tmp = config.return_value(ospfv3_base + ['route-map'])
+
+ config.set(['system', 'ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ipv6', 'protocol'])
+ config.delete(ospfv3_base + ['route-map'])
+
+ # Check if vrf names are configured. Check if OSPF/OSPFv3 is configured - if so,
+ # migrate the CLI node(s)
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'ospf', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'ospf', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'ospf', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'ospf'])
+ config.delete(vrf_base + ['protocols', 'ospf', 'route-map'])
+
+ if config.exists(vrf_base + ['protocols', 'ospfv3', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'ospfv3', 'route-map'])
+
+ config.set(vrf_base + ['ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ipv6', 'protocol', 'ospfv6'])
+ config.delete(vrf_base + ['protocols', 'ospfv3', 'route-map'])
diff --git a/src/migration-scripts/pim/0-to-1 b/src/migration-scripts/pim/0-to-1
index bf8af733c..ce24b23ba 100755..100644
--- a/src/migration-scripts/pim/0-to-1
+++ b/src/migration-scripts/pim/0-to-1
@@ -1,72 +1,54 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5736: igmp: migrate "protocols igmp" to "protocols pim"
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['protocols', 'igmp']
pim_base = ['protocols', 'pim']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-for interface in config.list_nodes(base + ['interface']):
- base_igmp_iface = base + ['interface', interface]
- pim_base_iface = pim_base + ['interface', interface]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- # Create IGMP note under PIM interface
- if not config.exists(pim_base_iface + ['igmp']):
- config.set(pim_base_iface + ['igmp'])
+ for interface in config.list_nodes(base + ['interface']):
+ base_igmp_iface = base + ['interface', interface]
+ pim_base_iface = pim_base + ['interface', interface]
- if config.exists(base_igmp_iface + ['join']):
- config.copy(base_igmp_iface + ['join'], pim_base_iface + ['igmp', 'join'])
- config.set_tag(pim_base_iface + ['igmp', 'join'])
+ # Create IGMP note under PIM interface
+ if not config.exists(pim_base_iface + ['igmp']):
+ config.set(pim_base_iface + ['igmp'])
- new_join_base = pim_base_iface + ['igmp', 'join']
- for address in config.list_nodes(new_join_base):
- if config.exists(new_join_base + [address, 'source']):
- config.rename(new_join_base + [address, 'source'], 'source-address')
+ if config.exists(base_igmp_iface + ['join']):
+ config.copy(base_igmp_iface + ['join'], pim_base_iface + ['igmp', 'join'])
+ config.set_tag(pim_base_iface + ['igmp', 'join'])
- if config.exists(base_igmp_iface + ['query-interval']):
- config.copy(base_igmp_iface + ['query-interval'], pim_base_iface + ['igmp', 'query-interval'])
+ new_join_base = pim_base_iface + ['igmp', 'join']
+ for address in config.list_nodes(new_join_base):
+ if config.exists(new_join_base + [address, 'source']):
+ config.rename(new_join_base + [address, 'source'], 'source-address')
- if config.exists(base_igmp_iface + ['query-max-response-time']):
- config.copy(base_igmp_iface + ['query-max-response-time'], pim_base_iface + ['igmp', 'query-max-response-time'])
+ if config.exists(base_igmp_iface + ['query-interval']):
+ config.copy(base_igmp_iface + ['query-interval'], pim_base_iface + ['igmp', 'query-interval'])
- if config.exists(base_igmp_iface + ['version']):
- config.copy(base_igmp_iface + ['version'], pim_base_iface + ['igmp', 'version'])
+ if config.exists(base_igmp_iface + ['query-max-response-time']):
+ config.copy(base_igmp_iface + ['query-max-response-time'], pim_base_iface + ['igmp', 'query-max-response-time'])
-config.delete(base)
+ if config.exists(base_igmp_iface + ['version']):
+ config.copy(base_igmp_iface + ['version'], pim_base_iface + ['igmp', 'version'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.delete(base)
diff --git a/src/migration-scripts/policy/0-to-1 b/src/migration-scripts/policy/0-to-1
index 8508b734a..837946c37 100755..100644
--- a/src/migration-scripts/policy/0-to-1
+++ b/src/migration-scripts/policy/0-to-1
@@ -1,65 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3631: route-map: migrate "set extcommunity-rt" and "set extcommunity-soo"
# to "set extcommunity rt|soo" to match FRR syntax
-
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy', 'route-map']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for route_map in config.list_nodes(base):
- if not config.exists(base + [route_map, 'rule']):
- continue
- for rule in config.list_nodes(base + [route_map, 'rule']):
- base_rule = base + [route_map, 'rule', rule]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- if config.exists(base_rule + ['set', 'extcommunity-rt']):
- tmp = config.return_value(base_rule + ['set', 'extcommunity-rt'])
- config.delete(base_rule + ['set', 'extcommunity-rt'])
- config.set(base_rule + ['set', 'extcommunity', 'rt'], value=tmp)
+ for route_map in config.list_nodes(base):
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ base_rule = base + [route_map, 'rule', rule]
+ if config.exists(base_rule + ['set', 'extcommunity-rt']):
+ tmp = config.return_value(base_rule + ['set', 'extcommunity-rt'])
+ config.delete(base_rule + ['set', 'extcommunity-rt'])
+ config.set(base_rule + ['set', 'extcommunity', 'rt'], value=tmp)
- if config.exists(base_rule + ['set', 'extcommunity-soo']):
- tmp = config.return_value(base_rule + ['set', 'extcommunity-soo'])
- config.delete(base_rule + ['set', 'extcommunity-soo'])
- config.set(base_rule + ['set', 'extcommunity', 'soo'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(base_rule + ['set', 'extcommunity-soo']):
+ tmp = config.return_value(base_rule + ['set', 'extcommunity-soo'])
+ config.delete(base_rule + ['set', 'extcommunity-soo'])
+ config.set(base_rule + ['set', 'extcommunity', 'soo'], value=tmp)
diff --git a/src/migration-scripts/policy/1-to-2 b/src/migration-scripts/policy/1-to-2
index c7a983bba..ba3e48db0 100755..100644
--- a/src/migration-scripts/policy/1-to-2
+++ b/src/migration-scripts/policy/1-to-2
@@ -1,86 +1,67 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4170: rename "policy ipv6-route" to "policy route6" to match common
# IPv4/IPv6 schema
# T4178: Update tcp flags to use multi value node
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-if config.exists(base + ['ipv6-route']):
- config.rename(base + ['ipv6-route'],'route6')
- config.set_tag(['policy', 'route6'])
+ if config.exists(base + ['ipv6-route']):
+ config.rename(base + ['ipv6-route'],'route6')
+ config.set_tag(['policy', 'route6'])
-for route in ['route', 'route6']:
- if config.exists(base + [route]):
- for name in config.list_nodes(base + [route]):
- if config.exists(base + [route, name, 'rule']):
- for rule in config.list_nodes(base + [route, name, 'rule']):
- rule_tcp_flags = base + [route, name, 'rule', rule, 'tcp', 'flags']
+ for route in ['route', 'route6']:
+ if config.exists(base + [route]):
+ for name in config.list_nodes(base + [route]):
+ if config.exists(base + [route, name, 'rule']):
+ for rule in config.list_nodes(base + [route, name, 'rule']):
+ rule_tcp_flags = base + [route, name, 'rule', rule, 'tcp', 'flags']
- if config.exists(rule_tcp_flags):
- tmp = config.return_value(rule_tcp_flags)
- config.delete(rule_tcp_flags)
- for flag in tmp.split(","):
+ if config.exists(rule_tcp_flags):
+ tmp = config.return_value(rule_tcp_flags)
+ config.delete(rule_tcp_flags)
for flag in tmp.split(","):
- if flag[0] == '!':
- config.set(rule_tcp_flags + ['not', flag[1:].lower()])
- else:
- config.set(rule_tcp_flags + [flag.lower()])
+ for flag in tmp.split(","):
+ if flag[0] == '!':
+ config.set(rule_tcp_flags + ['not', flag[1:].lower()])
+ else:
+ config.set(rule_tcp_flags + [flag.lower()])
-if config.exists(['interfaces']):
- def if_policy_rename(config, path):
- if config.exists(path + ['policy', 'ipv6-route']):
- config.rename(path + ['policy', 'ipv6-route'], 'route6')
+ if config.exists(['interfaces']):
+ def if_policy_rename(config, path):
+ if config.exists(path + ['policy', 'ipv6-route']):
+ config.rename(path + ['policy', 'ipv6-route'], 'route6')
- for if_type in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', if_type]):
- if_path = ['interfaces', if_type, ifname]
- if_policy_rename(config, if_path)
+ for if_type in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', if_type]):
+ if_path = ['interfaces', if_type, ifname]
+ if_policy_rename(config, if_path)
- for vif_type in ['vif', 'vif-s']:
- if config.exists(if_path + [vif_type]):
- for vifname in config.list_nodes(if_path + [vif_type]):
- if_policy_rename(config, if_path + [vif_type, vifname])
+ for vif_type in ['vif', 'vif-s']:
+ if config.exists(if_path + [vif_type]):
+ for vifname in config.list_nodes(if_path + [vif_type]):
+ if_policy_rename(config, if_path + [vif_type, vifname])
- if config.exists(if_path + [vif_type, vifname, 'vif-c']):
- for vifcname in config.list_nodes(if_path + [vif_type, vifname, 'vif-c']):
- if_policy_rename(config, if_path + [vif_type, vifname, 'vif-c', vifcname])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(if_path + [vif_type, vifname, 'vif-c']):
+ for vifcname in config.list_nodes(if_path + [vif_type, vifname, 'vif-c']):
+ if_policy_rename(config, if_path + [vif_type, vifname, 'vif-c', vifcname])
diff --git a/src/migration-scripts/policy/2-to-3 b/src/migration-scripts/policy/2-to-3
index 8a62c8e6f..399a55387 100755..100644
--- a/src/migration-scripts/policy/2-to-3
+++ b/src/migration-scripts/policy/2-to-3
@@ -1,58 +1,38 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3976: change cli
# from: set policy route-map FOO rule 10 match ipv6 nexthop 'h:h:h:h:h:h:h:h'
# to: set policy route-map FOO rule 10 match ipv6 nexthop address 'h:h:h:h:h:h:h:h'
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy', 'route-map']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for route_map in config.list_nodes(base):
- if not config.exists(base + [route_map, 'rule']):
- continue
- for rule in config.list_nodes(base + [route_map, 'rule']):
- base_rule = base + [route_map, 'rule', rule]
-
- if config.exists(base_rule + ['match', 'ipv6', 'nexthop']):
- tmp = config.return_value(base_rule + ['match', 'ipv6', 'nexthop'])
- config.delete(base_rule + ['match', 'ipv6', 'nexthop'])
- config.set(base_rule + ['match', 'ipv6', 'nexthop', 'address'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1) \ No newline at end of file
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for route_map in config.list_nodes(base):
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ base_rule = base + [route_map, 'rule', rule]
+
+ if config.exists(base_rule + ['match', 'ipv6', 'nexthop']):
+ tmp = config.return_value(base_rule + ['match', 'ipv6', 'nexthop'])
+ config.delete(base_rule + ['match', 'ipv6', 'nexthop'])
+ config.set(base_rule + ['match', 'ipv6', 'nexthop', 'address'], value=tmp)
diff --git a/src/migration-scripts/policy/3-to-4 b/src/migration-scripts/policy/3-to-4
index 476fa3af2..5d4959def 100755..100644
--- a/src/migration-scripts/policy/3-to-4
+++ b/src/migration-scripts/policy/3-to-4
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4660: change cli
# from: set policy route-map FOO rule 10 set community 'TEXT'
@@ -33,9 +32,6 @@
# Multiple value
# to: set policy route-map FOO rule 10 set extcommunity [rt|soo] <community>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
@@ -96,67 +92,52 @@ def extcommunity_migrate(config: ConfigTree, rule: list[str]) -> None:
config.set(rule + ['soo'], value=community, replace=False)
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name: str = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base: list[str] = ['policy', 'route-map']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for route_map in config.list_nodes(base):
- if not config.exists(base + [route_map, 'rule']):
- continue
- for rule in config.list_nodes(base + [route_map, 'rule']):
- base_rule: list[str] = base + [route_map, 'rule', rule, 'set']
-
- # IF additive presents in coummunity then comm-list is redundant
- isAdditive: bool = True
- #### Change Set community ########
- if config.exists(base_rule + ['community']):
- isAdditive = community_migrate(config,
- base_rule + ['community'])
-
- #### Change Set community-list delete migrate ########
- if config.exists(base_rule + ['comm-list', 'comm-list']):
- if isAdditive:
- tmp = config.return_value(
- base_rule + ['comm-list', 'comm-list'])
- config.delete(base_rule + ['comm-list'])
- config.set(base_rule + ['community', 'delete'], value=tmp)
- else:
- config.delete(base_rule + ['comm-list'])
-
- isAdditive = False
- #### Change Set large-community ########
- if config.exists(base_rule + ['large-community']):
- isAdditive = community_migrate(config,
- base_rule + ['large-community'])
-
- #### Change Set large-community delete by List ########
- if config.exists(base_rule + ['large-comm-list-delete']):
- if isAdditive:
- tmp = config.return_value(
- base_rule + ['large-comm-list-delete'])
- config.delete(base_rule + ['large-comm-list-delete'])
- config.set(base_rule + ['large-community', 'delete'],
- value=tmp)
- else:
- config.delete(base_rule + ['large-comm-list-delete'])
-
- #### Change Set extcommunity ########
- extcommunity_migrate(config, base_rule + ['extcommunity'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for route_map in config.list_nodes(base):
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ base_rule: list[str] = base + [route_map, 'rule', rule, 'set']
+
+ # IF additive presents in coummunity then comm-list is redundant
+ isAdditive: bool = True
+ #### Change Set community ########
+ if config.exists(base_rule + ['community']):
+ isAdditive = community_migrate(config,
+ base_rule + ['community'])
+
+ #### Change Set community-list delete migrate ########
+ if config.exists(base_rule + ['comm-list', 'comm-list']):
+ if isAdditive:
+ tmp = config.return_value(
+ base_rule + ['comm-list', 'comm-list'])
+ config.delete(base_rule + ['comm-list'])
+ config.set(base_rule + ['community', 'delete'], value=tmp)
+ else:
+ config.delete(base_rule + ['comm-list'])
+
+ isAdditive = False
+ #### Change Set large-community ########
+ if config.exists(base_rule + ['large-community']):
+ isAdditive = community_migrate(config,
+ base_rule + ['large-community'])
+
+ #### Change Set large-community delete by List ########
+ if config.exists(base_rule + ['large-comm-list-delete']):
+ if isAdditive:
+ tmp = config.return_value(
+ base_rule + ['large-comm-list-delete'])
+ config.delete(base_rule + ['large-comm-list-delete'])
+ config.set(base_rule + ['large-community', 'delete'],
+ value=tmp)
+ else:
+ config.delete(base_rule + ['large-comm-list-delete'])
+
+ #### Change Set extcommunity ########
+ extcommunity_migrate(config, base_rule + ['extcommunity'])
diff --git a/src/migration-scripts/policy/4-to-5 b/src/migration-scripts/policy/4-to-5
index 738850f67..0ecfdfd5e 100755..100644
--- a/src/migration-scripts/policy/4-to-5
+++ b/src/migration-scripts/policy/4-to-5
@@ -1,39 +1,24 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T2199: Migrate interface policy nodes to policy route <name> interface <ifname>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base4 = ['policy', 'route']
base6 = ['policy', 'route6']
-config = ConfigTree(config_file)
-
def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None, vifc=None):
"""Delete unexpected policy on interfaces in cases when
@@ -55,35 +40,6 @@ def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None
config.delete(if_path + ['policy'])
-
-if not config.exists(base4) and not config.exists(base6):
- # Delete orphaned nodes on interfaces T5941
- for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- delete_orphaned_interface_policy(config, iftype, ifname)
-
- if config.exists(['interfaces', iftype, ifname, 'vif']):
- for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
- delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s']):
- for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
- delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
- # Nothing to do
- exit(0)
-
def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
if_path = ['interfaces', iftype, ifname]
ifname_full = ifname
@@ -111,25 +67,40 @@ def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
config.delete(if_path + ['policy'])
-for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- migrate_interface(config, iftype, ifname)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base4) and not config.exists(base6):
+ # Delete orphaned nodes on interfaces T5941
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ delete_orphaned_interface_policy(config, iftype, ifname)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
- if config.exists(['interfaces', iftype, ifname, 'vif']):
- for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
- migrate_interface(config, iftype, ifname, vif=vif)
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
- if config.exists(['interfaces', iftype, ifname, 'vif-s']):
- for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
- migrate_interface(config, iftype, ifname, vifs=vifs)
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
- if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
+ # Nothing to do
+ return
+
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ migrate_interface(config, iftype, ifname)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ migrate_interface(config, iftype, ifname, vif=vif)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ migrate_interface(config, iftype, ifname, vifs=vifs)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
diff --git a/src/migration-scripts/policy/5-to-6 b/src/migration-scripts/policy/5-to-6
index 86287d578..acba0b4be 100755..100644
--- a/src/migration-scripts/policy/5-to-6
+++ b/src/migration-scripts/policy/5-to-6
@@ -1,62 +1,42 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5165: Migrate policy local-route rule <tag> destination|source
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base4 = ['policy', 'local-route']
base6 = ['policy', 'local-route6']
-config = ConfigTree(config_file)
-
-if not config.exists(base4) and not config.exists(base6):
- # Nothing to do
- exit(0)
-
-# replace 'policy local-route{v6} rule <tag> destination|source <x.x.x.x>'
-# => 'policy local-route{v6} rule <tag> destination|source address <x.x.x.x>'
-for base in [base4, base6]:
- if config.exists(base + ['rule']):
- for rule in config.list_nodes(base + ['rule']):
- dst_path = base + ['rule', rule, 'destination']
- src_path = base + ['rule', rule, 'source']
- # Destination
- if config.exists(dst_path):
- for dst_addr in config.return_values(dst_path):
- config.set(dst_path + ['address'], value=dst_addr, replace=False)
- # Source
- if config.exists(src_path):
- for src_addr in config.return_values(src_path):
- config.set(src_path + ['address'], value=src_addr, replace=False)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base4) and not config.exists(base6):
+ # Nothing to do
+ return
+
+ # replace 'policy local-route{v6} rule <tag> destination|source <x.x.x.x>'
+ # => 'policy local-route{v6} rule <tag> destination|source address <x.x.x.x>'
+ for base in [base4, base6]:
+ if config.exists(base + ['rule']):
+ for rule in config.list_nodes(base + ['rule']):
+ dst_path = base + ['rule', rule, 'destination']
+ src_path = base + ['rule', rule, 'source']
+ # Destination
+ if config.exists(dst_path):
+ for dst_addr in config.return_values(dst_path):
+ config.set(dst_path + ['address'], value=dst_addr, replace=False)
+ # Source
+ if config.exists(src_path):
+ for src_addr in config.return_values(src_path):
+ config.set(src_path + ['address'], value=src_addr, replace=False)
diff --git a/src/migration-scripts/policy/6-to-7 b/src/migration-scripts/policy/6-to-7
index cdefc6837..69aa703c5 100755..100644
--- a/src/migration-scripts/policy/6-to-7
+++ b/src/migration-scripts/policy/6-to-7
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5729: Switch to valueless whenever is possible.
# From
@@ -22,55 +21,36 @@
# set policy [route | route6] ... rule <rule> log
# Remove command if log=disable
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for family in ['route', 'route6']:
- if config.exists(base + [family]):
-
- for policy_name in config.list_nodes(base + [family]):
- if config.exists(base + [family, policy_name, 'rule']):
- for rule in config.list_nodes(base + [family, policy_name, 'rule']):
- # Log
- if config.exists(base + [family, policy_name, 'rule', rule, 'log']):
- log_value = config.return_value(base + [family, policy_name, 'rule', rule, 'log'])
- config.delete(base + [family, policy_name, 'rule', rule, 'log'])
- if log_value == 'enable':
- config.set(base + [family, policy_name, 'rule', rule, 'log'])
- # State
- if config.exists(base + [family, policy_name, 'rule', rule, 'state']):
- flag_enable = 'False'
- for state in ['established', 'invalid', 'new', 'related']:
- if config.exists(base + [family, policy_name, 'rule', rule, 'state', state]):
- state_value = config.return_value(base + [family, policy_name, 'rule', rule, 'state', state])
- config.delete(base + [family, policy_name, 'rule', rule, 'state', state])
- if state_value == 'enable':
- config.set(base + [family, policy_name, 'rule', rule, 'state'], value=state, replace=False)
- flag_enable = 'True'
- if flag_enable == 'False':
- config.delete(base + [family, policy_name, 'rule', rule, 'state'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for family in ['route', 'route6']:
+ if config.exists(base + [family]):
+
+ for policy_name in config.list_nodes(base + [family]):
+ if config.exists(base + [family, policy_name, 'rule']):
+ for rule in config.list_nodes(base + [family, policy_name, 'rule']):
+ # Log
+ if config.exists(base + [family, policy_name, 'rule', rule, 'log']):
+ log_value = config.return_value(base + [family, policy_name, 'rule', rule, 'log'])
+ config.delete(base + [family, policy_name, 'rule', rule, 'log'])
+ if log_value == 'enable':
+ config.set(base + [family, policy_name, 'rule', rule, 'log'])
+ # State
+ if config.exists(base + [family, policy_name, 'rule', rule, 'state']):
+ flag_enable = 'False'
+ for state in ['established', 'invalid', 'new', 'related']:
+ if config.exists(base + [family, policy_name, 'rule', rule, 'state', state]):
+ state_value = config.return_value(base + [family, policy_name, 'rule', rule, 'state', state])
+ config.delete(base + [family, policy_name, 'rule', rule, 'state', state])
+ if state_value == 'enable':
+ config.set(base + [family, policy_name, 'rule', rule, 'state'], value=state, replace=False)
+ flag_enable = 'True'
+ if flag_enable == 'False':
+ config.delete(base + [family, policy_name, 'rule', rule, 'state'])
diff --git a/src/migration-scripts/policy/7-to-8 b/src/migration-scripts/policy/7-to-8
index 73eece1a6..a887f37fe 100755..100644
--- a/src/migration-scripts/policy/7-to-8
+++ b/src/migration-scripts/policy/7-to-8
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5834: Rename 'enable-default-log' to 'default-log'
# From
@@ -20,37 +19,18 @@
# To
# set policy [route | route 6] <route> default-log
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-for family in ['route', 'route6']:
- if config.exists(base + [family]):
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- for policy_name in config.list_nodes(base + [family]):
- if config.exists(base + [family, policy_name, 'enable-default-log']):
- config.rename(base + [family, policy_name, 'enable-default-log'], 'default-log')
+ for family in ['route', 'route6']:
+ if config.exists(base + [family]):
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for policy_name in config.list_nodes(base + [family]):
+ if config.exists(base + [family, policy_name, 'enable-default-log']):
+ config.rename(base + [family, policy_name, 'enable-default-log'], 'default-log')
diff --git a/src/migration-scripts/pppoe-server/0-to-1 b/src/migration-scripts/pppoe-server/0-to-1
index 4d36f8545..8c9a24fbe 100755..100644
--- a/src/migration-scripts/pppoe-server/0-to-1
+++ b/src/migration-scripts/pppoe-server/0-to-1
@@ -1,50 +1,33 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Convert "service pppoe-server authentication radius-server node key"
# to: "service pppoe-server authentication radius-server node secret"
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-ctree = ConfigTree(config_file)
base = ['service', 'pppoe-server', 'authentication', 'radius-server']
-if not ctree.exists(base):
- # Nothing to do
- exit(0)
-else:
+def migrate(ctree: ConfigTree) -> None:
+ if not ctree.exists(base):
+ # Nothing to do
+ return
+
nodes = ctree.list_nodes(base)
for node in nodes:
if ctree.exists(base + [node, 'key']):
val = ctree.return_value(base + [node, 'key'])
ctree.set(base + [node, 'secret'], value=val, replace=False)
ctree.delete(base + [node, 'key'])
-
- try:
- open(file_name,'w').write(ctree.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pppoe-server/1-to-2 b/src/migration-scripts/pppoe-server/1-to-2
index b266893c0..c9c968bff 100755..100644
--- a/src/migration-scripts/pppoe-server/1-to-2
+++ b/src/migration-scripts/pppoe-server/1-to-2
@@ -1,39 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# change mppe node to a leaf node with value prefer
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['service', 'pppoe-server']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['service', 'pppoe-server']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
mppe_base = base + ['ppp-options', 'mppe']
if config.exists(mppe_base):
# get current values
@@ -49,10 +39,3 @@ else:
config.set(mppe_base, value='prefer')
elif 'deny' in tmp:
config.set(mppe_base, value='deny')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pppoe-server/2-to-3 b/src/migration-scripts/pppoe-server/2-to-3
index a7be060df..160cffdf8 100755..100644
--- a/src/migration-scripts/pppoe-server/2-to-3
+++ b/src/migration-scripts/pppoe-server/2-to-3
@@ -1,48 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Convert "service pppoe-server interface ethX" to: "service pppoe-server interface ethX {}"
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-ctree = ConfigTree(config_file)
cbase = ['service', 'pppoe-server','interface']
-if not ctree.exists(cbase):
- exit(0)
-else:
+def migrate(ctree: ConfigTree) -> None:
+ if not ctree.exists(cbase):
+ return
+
nics = ctree.return_values(cbase)
# convert leafNode to a tagNode
ctree.set(cbase)
ctree.set_tag(cbase)
for nic in nics:
ctree.set(cbase + [nic])
-
- try:
- open(file_name,'w').write(ctree.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pppoe-server/3-to-4 b/src/migration-scripts/pppoe-server/3-to-4
index 477ed6f22..29dd62201 100755..100644
--- a/src/migration-scripts/pppoe-server/3-to-4
+++ b/src/migration-scripts/pppoe-server/3-to-4
@@ -1,39 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - remove primary/secondary identifier from nameserver
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'pppoe-server']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
# Migrate IPv4 DNS servers
dns_base = base + ['dns-servers']
@@ -130,10 +119,3 @@ else:
prefix = p.split(',')[0]
mask = p.split(',')[1]
config.set(ipv6_base + ['delegate', prefix, 'delegation-prefix'], value=mask)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pppoe-server/4-to-5 b/src/migration-scripts/pppoe-server/4-to-5
index 5850db673..03fbfb247 100755..100644
--- a/src/migration-scripts/pppoe-server/4-to-5
+++ b/src/migration-scripts/pppoe-server/4-to-5
@@ -1,49 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - rename local-ip to gateway-address
from vyos.configtree import ConfigTree
-from sys import argv
-from sys import exit
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-file_name = argv[1]
+base_path = ['service', 'pppoe-server']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base_path = ['service', 'pppoe-server']
-if not config.exists(base_path):
- # Nothing to do
- exit(0)
-else:
config_gw = base_path + ['local-ip']
if config.exists(config_gw):
config.rename(config_gw, 'gateway-address')
config.delete(config_gw)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
diff --git a/src/migration-scripts/pppoe-server/5-to-6 b/src/migration-scripts/pppoe-server/5-to-6
index e079ae684..13de8f8d2 100755..100644
--- a/src/migration-scripts/pppoe-server/5-to-6
+++ b/src/migration-scripts/pppoe-server/5-to-6
@@ -1,52 +1,33 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T4703: merge vlan-id and vlan-range to vlan CLI node
from vyos.configtree import ConfigTree
-from sys import argv
-from sys import exit
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base_path = ['service', 'pppoe-server', 'interface']
-if not config.exists(base_path):
- # Nothing to do
- exit(0)
-
-for interface in config.list_nodes(base_path):
- for vlan in ['vlan-id', 'vlan-range']:
- if config.exists(base_path + [interface, vlan]):
- print(interface, vlan)
- for tmp in config.return_values(base_path + [interface, vlan]):
- config.set(base_path + [interface, 'vlan'], value=tmp, replace=False)
- config.delete(base_path + [interface, vlan])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
+
+ for interface in config.list_nodes(base_path):
+ for vlan in ['vlan-id', 'vlan-range']:
+ if config.exists(base_path + [interface, vlan]):
+ print(interface, vlan)
+ for tmp in config.return_values(base_path + [interface, vlan]):
+ config.set(base_path + [interface, 'vlan'], value=tmp, replace=False)
+ config.delete(base_path + [interface, vlan])
diff --git a/src/migration-scripts/pppoe-server/6-to-7 b/src/migration-scripts/pppoe-server/6-to-7
index d51c1c9d8..79745a0c6 100755..100644
--- a/src/migration-scripts/pppoe-server/6-to-7
+++ b/src/migration-scripts/pppoe-server/6-to-7
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - move all pool to named pools
# 'start-stop' migrate to namedpool 'default-range-pool'
@@ -24,94 +23,77 @@
# If there are not named pools, namedless pool will be default.
# 2. If authentication mode = 'radius' then namedless pool will be default
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.base import Warning
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'pppoe-server']
pool_base = base + ['client-ip-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-default_pool = ''
-range_pool_name = 'default-range-pool'
-
-#Default nameless pools migrations
-if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
- def is_legalrange(ip1: str, ip2: str, mask: str):
- from ipaddress import IPv4Interface
- interface1 = IPv4Interface(f'{ip1}/{mask}')
- interface2 = IPv4Interface(f'{ip2}/{mask}')
- return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
- start_ip = config.return_value(pool_base + ['start'])
- stop_ip = config.return_value(pool_base + ['stop'])
- if is_legalrange(start_ip, stop_ip, '24'):
- ip_range = f'{start_ip}-{stop_ip}'
- config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(pool_base):
+ return
+
+ default_pool = ''
+ range_pool_name = 'default-range-pool'
+
+ #Default nameless pools migrations
+ if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+ def is_legalrange(ip1: str, ip2: str, mask: str):
+ from ipaddress import IPv4Interface
+ interface1 = IPv4Interface(f'{ip1}/{mask}')
+ interface2 = IPv4Interface(f'{ip2}/{mask}')
+ return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+
+ start_ip = config.return_value(pool_base + ['start'])
+ stop_ip = config.return_value(pool_base + ['stop'])
+ if is_legalrange(start_ip, stop_ip, '24'):
+ ip_range = f'{start_ip}-{stop_ip}'
+ config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+ default_pool = range_pool_name
+ else:
+ Warning(
+ f'PPPoE client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
+ config.delete(pool_base + ['start'])
+ config.delete(pool_base + ['stop'])
+
+ if config.exists(pool_base + ['subnet']):
default_pool = range_pool_name
- else:
- Warning(
- f'PPPoE client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
- config.delete(pool_base + ['start'])
- config.delete(pool_base + ['stop'])
-
-if config.exists(pool_base + ['subnet']):
- default_pool = range_pool_name
- for subnet in config.return_values(pool_base + ['subnet']):
- config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
- config.delete(pool_base + ['subnet'])
-
-gateway = ''
-if config.exists(base + ['gateway-address']):
- gateway = config.return_value(base + ['gateway-address'])
-
-#named pool migration
-namedpools_base = pool_base + ['name']
-if config.exists(namedpools_base):
- if config.exists(base + ['authentication', 'mode']):
- if config.return_value(base + ['authentication', 'mode']) == 'local':
- if config.list_nodes(namedpools_base):
- default_pool = config.list_nodes(namedpools_base)[0]
-
- for pool_name in config.list_nodes(namedpools_base):
- pool_path = namedpools_base + [pool_name]
- if config.exists(pool_path + ['subnet']):
- subnet = config.return_value(pool_path + ['subnet'])
- config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
- if config.exists(pool_path + ['next-pool']):
- next_pool = config.return_value(pool_path + ['next-pool'])
- config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
- if not gateway:
- if config.exists(pool_path + ['gateway-address']):
- gateway = config.return_value(pool_path + ['gateway-address'])
-
- config.delete(namedpools_base)
-
-if gateway:
- config.set(base + ['gateway-address'], value=gateway)
-if default_pool:
- config.set(base + ['default-pool'], value=default_pool)
-# format as tag node
-config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for subnet in config.return_values(pool_base + ['subnet']):
+ config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
+ config.delete(pool_base + ['subnet'])
+
+ gateway = ''
+ if config.exists(base + ['gateway-address']):
+ gateway = config.return_value(base + ['gateway-address'])
+
+ #named pool migration
+ namedpools_base = pool_base + ['name']
+ if config.exists(namedpools_base):
+ if config.exists(base + ['authentication', 'mode']):
+ if config.return_value(base + ['authentication', 'mode']) == 'local':
+ if config.list_nodes(namedpools_base):
+ default_pool = config.list_nodes(namedpools_base)[0]
+
+ for pool_name in config.list_nodes(namedpools_base):
+ pool_path = namedpools_base + [pool_name]
+ if config.exists(pool_path + ['subnet']):
+ subnet = config.return_value(pool_path + ['subnet'])
+ config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
+ if config.exists(pool_path + ['next-pool']):
+ next_pool = config.return_value(pool_path + ['next-pool'])
+ config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
+ if not gateway:
+ if config.exists(pool_path + ['gateway-address']):
+ gateway = config.return_value(pool_path + ['gateway-address'])
+
+ config.delete(namedpools_base)
+
+ if gateway:
+ config.set(base + ['gateway-address'], value=gateway)
+ if default_pool:
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/pppoe-server/7-to-8 b/src/migration-scripts/pppoe-server/7-to-8
index 0381f0bf9..90e4fa053 100755..100644
--- a/src/migration-scripts/pppoe-server/7-to-8
+++ b/src/migration-scripts/pppoe-server/7-to-8
@@ -1,58 +1,40 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrating to named ipv6 pools
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['service', 'pppoe-server']
+pool_base = base + ['client-ipv6-pool']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ if not config.exists(pool_base):
+ return
-config = ConfigTree(config_file)
-base = ['service', 'pppoe-server']
-pool_base = base + ['client-ipv6-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-ipv6_pool_name = 'ipv6-pool'
-config.copy(pool_base, pool_base + [ipv6_pool_name])
-
-if config.exists(pool_base + ['prefix']):
- config.delete(pool_base + ['prefix'])
- config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
-if config.exists(pool_base + ['delegate']):
- config.delete(pool_base + ['delegate'])
-
-# format as tag node
-config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ ipv6_pool_name = 'ipv6-pool'
+ config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+ if config.exists(pool_base + ['prefix']):
+ config.delete(pool_base + ['prefix'])
+ config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+ if config.exists(pool_base + ['delegate']):
+ config.delete(pool_base + ['delegate'])
+
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/pppoe-server/8-to-9 b/src/migration-scripts/pppoe-server/8-to-9
index 4932a766f..e7e0aaa2c 100755..100644
--- a/src/migration-scripts/pppoe-server/8-to-9
+++ b/src/migration-scripts/pppoe-server/8-to-9
@@ -1,66 +1,48 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Change from 'ccp' to 'disable-ccp' in ppp-option section
# Migration ipv6 options
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'pppoe-server']
-if not config.exists(base):
- exit(0)
-
-#CCP migration
-if config.exists(base + ['ppp-options', 'ccp']):
- config.delete(base + ['ppp-options', 'ccp'])
-else:
- config.set(base + ['ppp-options', 'disable-ccp'])
-
-#IPV6 options migrations
-if config.exists(base + ['ppp-options','ipv6-peer-intf-id']):
- intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id'])
- if intf_peer_id == 'ipv4':
- intf_peer_id = 'ipv4-addr'
- config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True)
- config.delete(base + ['ppp-options','ipv6-peer-intf-id'])
-
-if config.exists(base + ['ppp-options','ipv6-intf-id']):
- intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id'])
- config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True)
- config.delete(base + ['ppp-options','ipv6-intf-id'])
-
-if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']):
- config.set(base + ['ppp-options','ipv6-accept-peer-interface-id'])
- config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ #CCP migration
+ if config.exists(base + ['ppp-options', 'ccp']):
+ config.delete(base + ['ppp-options', 'ccp'])
+ else:
+ config.set(base + ['ppp-options', 'disable-ccp'])
+
+ #IPV6 options migrations
+ if config.exists(base + ['ppp-options','ipv6-peer-intf-id']):
+ intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id'])
+ if intf_peer_id == 'ipv4':
+ intf_peer_id = 'ipv4-addr'
+ config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True)
+ config.delete(base + ['ppp-options','ipv6-peer-intf-id'])
+
+ if config.exists(base + ['ppp-options','ipv6-intf-id']):
+ intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id'])
+ config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True)
+ config.delete(base + ['ppp-options','ipv6-intf-id'])
+
+ if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']):
+ config.set(base + ['ppp-options','ipv6-accept-peer-interface-id'])
+ config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id'])
diff --git a/src/migration-scripts/pppoe-server/9-to-10 b/src/migration-scripts/pppoe-server/9-to-10
index e0c782f04..d3475e8ff 100755..100644
--- a/src/migration-scripts/pppoe-server/9-to-10
+++ b/src/migration-scripts/pppoe-server/9-to-10
@@ -1,56 +1,38 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migration of pado-delay options
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'pppoe-server', 'pado-delay']
-if not config.exists(base):
- exit(0)
-pado_delay = {}
-for delay in config.list_nodes(base):
- sessions = config.return_value(base + [delay, 'sessions'])
- pado_delay[delay] = sessions
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-# need to define delay for latest sessions
-sorted_delays = dict(sorted(pado_delay.items(), key=lambda k_v: int(k_v[1])))
-last_delay = list(sorted_delays)[-1]
+ pado_delay = {}
+ for delay in config.list_nodes(base):
+ sessions = config.return_value(base + [delay, 'sessions'])
+ pado_delay[delay] = sessions
-# Rename last delay -> disable
-tmp = base + [last_delay]
-if config.exists(tmp):
- config.rename(tmp, 'disable')
+ # need to define delay for latest sessions
+ sorted_delays = dict(sorted(pado_delay.items(), key=lambda k_v: int(k_v[1])))
+ last_delay = list(sorted_delays)[-1]
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Rename last delay -> disable
+ tmp = base + [last_delay]
+ if config.exists(tmp):
+ config.rename(tmp, 'disable')
diff --git a/src/migration-scripts/pptp/0-to-1 b/src/migration-scripts/pptp/0-to-1
index 1b7697c11..dd0b6f57e 100755..100644
--- a/src/migration-scripts/pptp/0-to-1
+++ b/src/migration-scripts/pptp/0-to-1
@@ -1,29 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Unclutter PPTP VPN configuiration - move radius-server top level tag
# nodes to a regular node which now also configures the radius source address
# used when querying a radius server
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+cfg_base = ['vpn', 'pptp', 'remote-access', 'authentication']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_base):
+ # Nothing to do
+ return
-cfg_base = ['vpn', 'pptp', 'remote-access', 'authentication']
-if not config.exists(cfg_base):
- # Nothing to do
- sys.exit(0)
-else:
# Migrate "vpn pptp authentication radius-source-address" to new
# "vpn pptp authentication radius source-address"
if config.exists(cfg_base + ['radius-source-address']):
@@ -50,10 +52,3 @@ else:
# delete top level tag node
if config.exists(cfg_base + ['radius-server']):
config.delete(cfg_base + ['radius-server'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/pptp/1-to-2 b/src/migration-scripts/pptp/1-to-2
index 99624dceb..1e7601193 100755..100644
--- a/src/migration-scripts/pptp/1-to-2
+++ b/src/migration-scripts/pptp/1-to-2
@@ -1,41 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - migrate dns-servers node to common name-servers
# - remove radios req-limit node
-from sys import argv, exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['vpn', 'pptp', 'remote-access']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['vpn', 'pptp', 'remote-access']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
# Migrate IPv4 DNS servers
dns_base = base + ['dns-servers']
if config.exists(dns_base):
@@ -62,10 +51,3 @@ else:
for server in config.list_nodes(radius_base + ['server']):
if config.exists(radius_base + ['server', server, 'req-limit']):
config.delete(radius_base + ['server', server, 'req-limit'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pptp/2-to-3 b/src/migration-scripts/pptp/2-to-3
index 42c4dedf4..8b0d6d865 100755..100644
--- a/src/migration-scripts/pptp/2-to-3
+++ b/src/migration-scripts/pptp/2-to-3
@@ -1,73 +1,55 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - move all pool to named pools
# 'start-stop' migrate to namedpool 'default-range-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.base import Warning
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'pptp', 'remote-access']
pool_base = base + ['client-ip-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-range_pool_name = 'default-range-pool'
-
-if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
- def is_legalrange(ip1: str, ip2: str, mask: str):
- from ipaddress import IPv4Interface
- interface1 = IPv4Interface(f'{ip1}/{mask}')
- interface2 = IPv4Interface(f'{ip2}/{mask}')
- return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
-
- start_ip = config.return_value(pool_base + ['start'])
- stop_ip = config.return_value(pool_base + ['stop'])
- if is_legalrange(start_ip, stop_ip, '24'):
- ip_range = f'{start_ip}-{stop_ip}'
- config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
- config.set(base + ['default-pool'], value=range_pool_name)
- else:
- Warning(
- f'PPTP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
-
- config.delete(pool_base + ['start'])
- config.delete(pool_base + ['stop'])
-# format as tag node
-config.set_tag(pool_base)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(pool_base):
+ return
+
+ range_pool_name = 'default-range-pool'
+
+ if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+ def is_legalrange(ip1: str, ip2: str, mask: str):
+ from ipaddress import IPv4Interface
+ interface1 = IPv4Interface(f'{ip1}/{mask}')
+ interface2 = IPv4Interface(f'{ip2}/{mask}')
+ return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+
+ start_ip = config.return_value(pool_base + ['start'])
+ stop_ip = config.return_value(pool_base + ['stop'])
+ if is_legalrange(start_ip, stop_ip, '24'):
+ ip_range = f'{start_ip}-{stop_ip}'
+ config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+ config.set(base + ['default-pool'], value=range_pool_name)
+ else:
+ Warning(
+ f'PPTP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
+
+ config.delete(pool_base + ['start'])
+ config.delete(pool_base + ['stop'])
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/pptp/3-to-4 b/src/migration-scripts/pptp/3-to-4
index ebd343028..2dabd8475 100755..100644
--- a/src/migration-scripts/pptp/3-to-4
+++ b/src/migration-scripts/pptp/3-to-4
@@ -1,48 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Move 'mppe' from 'authentication' node to 'ppp-options'
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'pptp', 'remote-access']
-if not config.exists(base):
- exit(0)
-
-if config.exists(base + ['authentication','mppe']):
- mppe = config.return_value(base + ['authentication','mppe'])
- config.set(base + ['ppp-options', 'mppe'], value=mppe, replace=True)
- config.delete(base + ['authentication','mppe'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(base + ['authentication','mppe']):
+ mppe = config.return_value(base + ['authentication','mppe'])
+ config.set(base + ['ppp-options', 'mppe'], value=mppe, replace=True)
+ config.delete(base + ['authentication','mppe'])
diff --git a/src/migration-scripts/pptp/4-to-5 b/src/migration-scripts/pptp/4-to-5
index 83632b6d8..c906f58c4 100755..100644
--- a/src/migration-scripts/pptp/4-to-5
+++ b/src/migration-scripts/pptp/4-to-5
@@ -1,63 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Move 'require' from 'protocols' in 'authentication' node
# - Migrate to new default values in radius timeout and acct-timeout
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'pptp', 'remote-access']
-if not config.exists(base):
- exit(0)
-
-#migrate require to protocols
-require_path = base + ['authentication', 'require']
-if config.exists(require_path):
- protocols = list(config.return_values(require_path))
- for protocol in protocols:
- config.set(base + ['authentication', 'protocols'], value=protocol,
- replace=False)
- config.delete(require_path)
-else:
- config.set(base + ['authentication', 'protocols'], value='mschap-v2')
-
-radius_path = base + ['authentication', 'radius']
-if config.exists(radius_path):
- if not config.exists(radius_path + ['timeout']):
- config.set(radius_path + ['timeout'], value=3)
- if not config.exists(radius_path + ['acct-timeout']):
- config.set(radius_path + ['acct-timeout'], value=3)
-
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ #migrate require to protocols
+ require_path = base + ['authentication', 'require']
+ if config.exists(require_path):
+ protocols = list(config.return_values(require_path))
+ for protocol in protocols:
+ config.set(base + ['authentication', 'protocols'], value=protocol,
+ replace=False)
+ config.delete(require_path)
+ else:
+ config.set(base + ['authentication', 'protocols'], value='mschap-v2')
+
+ radius_path = base + ['authentication', 'radius']
+ if config.exists(radius_path):
+ if not config.exists(radius_path + ['timeout']):
+ config.set(radius_path + ['timeout'], value=3)
+ if not config.exists(radius_path + ['acct-timeout']):
+ config.set(radius_path + ['acct-timeout'], value=3)
diff --git a/src/migration-scripts/qos/1-to-2 b/src/migration-scripts/qos/1-to-2
index 666811e5a..c43d8fa47 100755..100644
--- a/src/migration-scripts/qos/1-to-2
+++ b/src/migration-scripts/qos/1-to-2
@@ -1,20 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from sys import argv,exit
+# 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 vyos.base import Warning
from vyos.configtree import ConfigTree
@@ -28,18 +25,6 @@ def bandwidth_percent_to_val(interface, percent) -> int:
speed = int(speed) *1000000 # convert to MBit/s
return speed * int(percent) // 100 # integer division
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-base = ['traffic-policy']
-config = ConfigTree(config_file)
-
def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None, vifc=None):
"""Delete unexpected traffic-policy on interfaces in cases when
@@ -62,133 +47,122 @@ def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None
config.delete(if_path + ['traffic-policy'])
-if not config.exists(base):
- # Delete orphaned nodes on interfaces T5941
- for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- delete_orphaned_interface_policy(config, iftype, ifname)
-
- if config.exists(['interfaces', iftype, ifname, 'vif']):
- for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
- delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s']):
- for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
- delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
- # Nothing to do
- exit(0)
-
-iface_config = {}
-
-if config.exists(['interfaces']):
- def get_qos(config, interface, interface_base):
- if config.exists(interface_base):
- tmp = { interface : {} }
- if config.exists(interface_base + ['in']):
- tmp[interface]['ingress'] = config.return_value(interface_base + ['in'])
- if config.exists(interface_base + ['out']):
- tmp[interface]['egress'] = config.return_value(interface_base + ['out'])
- config.delete(interface_base)
- return tmp
- return None
-
- # Migrate "interface ethernet eth0 traffic-policy in|out" to "qos interface eth0 ingress|egress"
- for type in config.list_nodes(['interfaces']):
- for interface in config.list_nodes(['interfaces', type]):
- interface_base = ['interfaces', type, interface, 'traffic-policy']
- tmp = get_qos(config, interface, interface_base)
- if tmp: iface_config.update(tmp)
-
- vif_path = ['interfaces', type, interface, 'vif']
- if config.exists(vif_path):
- for vif in config.list_nodes(vif_path):
- vif_interface_base = vif_path + [vif, 'traffic-policy']
- ifname = f'{interface}.{vif}'
- tmp = get_qos(config, ifname, vif_interface_base)
- if tmp: iface_config.update(tmp)
-
- vif_s_path = ['interfaces', type, interface, 'vif-s']
- if config.exists(vif_s_path):
- for vif_s in config.list_nodes(vif_s_path):
- vif_s_interface_base = vif_s_path + [vif_s, 'traffic-policy']
- ifname = f'{interface}.{vif_s}'
- tmp = get_qos(config, ifname, vif_s_interface_base)
- if tmp: iface_config.update(tmp)
-
- # vif-c interfaces MUST be migrated before their parent vif-s
- # interface as the migrate_*() functions delete the path!
- vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
- if config.exists(vif_c_path):
- for vif_c in config.list_nodes(vif_c_path):
- vif_c_interface_base = vif_c_path + [vif_c, 'traffic-policy']
- ifname = f'{interface}.{vif_s}.{vif_c}'
- tmp = get_qos(config, ifname, vif_s_interface_base)
- if tmp: iface_config.update(tmp)
-
-
-# Now we have the information which interface uses which QoS policy.
-# Interface binding will be moved to the qos CLi tree
-config.set(['qos'])
-config.copy(base, ['qos', 'policy'])
-config.delete(base)
-
-# Now map the interface policy binding to the new CLI syntax
-if len(iface_config):
- config.set(['qos', 'interface'])
- config.set_tag(['qos', 'interface'])
-
-for interface, interface_config in iface_config.items():
- config.set(['qos', 'interface', interface])
- config.set_tag(['qos', 'interface', interface])
- if 'ingress' in interface_config:
- config.set(['qos', 'interface', interface, 'ingress'], value=interface_config['ingress'])
- if 'egress' in interface_config:
- config.set(['qos', 'interface', interface, 'egress'], value=interface_config['egress'])
-
-# Remove "burst" CLI node from network emulator
-netem_base = ['qos', 'policy', 'network-emulator']
-if config.exists(netem_base):
- for policy_name in config.list_nodes(netem_base):
- if config.exists(netem_base + [policy_name, 'burst']):
- config.delete(netem_base + [policy_name, 'burst'])
-
-# Change bandwidth unit MBit -> mbit as tc only supports mbit
-base = ['qos', 'policy']
-if config.exists(base):
- for policy_type in config.list_nodes(base):
- for policy in config.list_nodes(base + [policy_type]):
- policy_base = base + [policy_type, policy]
- if config.exists(policy_base + ['bandwidth']):
- tmp = config.return_value(policy_base + ['bandwidth'])
- config.set(policy_base + ['bandwidth'], value=tmp.lower())
-
- if config.exists(policy_base + ['class']):
- for cls in config.list_nodes(policy_base + ['class']):
- cls_base = policy_base + ['class', cls]
- if config.exists(cls_base + ['bandwidth']):
- tmp = config.return_value(cls_base + ['bandwidth'])
- config.set(cls_base + ['bandwidth'], value=tmp.lower())
-
- if config.exists(policy_base + ['default', 'bandwidth']):
+def migrate(config: ConfigTree) -> None:
+ base = ['traffic-policy']
+
+ if not config.exists(base):
+ # Delete orphaned nodes on interfaces T5941
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ delete_orphaned_interface_policy(config, iftype, ifname)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
+
+ # Nothing to do
+ return
+
+ iface_config = {}
+
+ if config.exists(['interfaces']):
+ def get_qos(config, interface, interface_base):
+ if config.exists(interface_base):
+ tmp = { interface : {} }
+ if config.exists(interface_base + ['in']):
+ tmp[interface]['ingress'] = config.return_value(interface_base + ['in'])
+ if config.exists(interface_base + ['out']):
+ tmp[interface]['egress'] = config.return_value(interface_base + ['out'])
+ config.delete(interface_base)
+ return tmp
+ return None
+
+ # Migrate "interface ethernet eth0 traffic-policy in|out" to "qos interface eth0 ingress|egress"
+ for type in config.list_nodes(['interfaces']):
+ for interface in config.list_nodes(['interfaces', type]):
+ interface_base = ['interfaces', type, interface, 'traffic-policy']
+ tmp = get_qos(config, interface, interface_base)
+ if tmp: iface_config.update(tmp)
+
+ vif_path = ['interfaces', type, interface, 'vif']
+ if config.exists(vif_path):
+ for vif in config.list_nodes(vif_path):
+ vif_interface_base = vif_path + [vif, 'traffic-policy']
+ ifname = f'{interface}.{vif}'
+ tmp = get_qos(config, ifname, vif_interface_base)
+ if tmp: iface_config.update(tmp)
+
+ vif_s_path = ['interfaces', type, interface, 'vif-s']
+ if config.exists(vif_s_path):
+ for vif_s in config.list_nodes(vif_s_path):
+ vif_s_interface_base = vif_s_path + [vif_s, 'traffic-policy']
+ ifname = f'{interface}.{vif_s}'
+ tmp = get_qos(config, ifname, vif_s_interface_base)
+ if tmp: iface_config.update(tmp)
+
+ # vif-c interfaces MUST be migrated before their parent vif-s
+ # interface as the migrate_*() functions delete the path!
+ vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
+ if config.exists(vif_c_path):
+ for vif_c in config.list_nodes(vif_c_path):
+ vif_c_interface_base = vif_c_path + [vif_c, 'traffic-policy']
+ ifname = f'{interface}.{vif_s}.{vif_c}'
+ tmp = get_qos(config, ifname, vif_s_interface_base)
+ if tmp: iface_config.update(tmp)
+
+
+ # Now we have the information which interface uses which QoS policy.
+ # Interface binding will be moved to the qos CLi tree
+ config.set(['qos'])
+ config.copy(base, ['qos', 'policy'])
+ config.delete(base)
+
+ # Now map the interface policy binding to the new CLI syntax
+ if len(iface_config):
+ config.set(['qos', 'interface'])
+ config.set_tag(['qos', 'interface'])
+
+ for interface, interface_config in iface_config.items():
+ config.set(['qos', 'interface', interface])
+ config.set_tag(['qos', 'interface', interface])
+ if 'ingress' in interface_config:
+ config.set(['qos', 'interface', interface, 'ingress'], value=interface_config['ingress'])
+ if 'egress' in interface_config:
+ config.set(['qos', 'interface', interface, 'egress'], value=interface_config['egress'])
+
+ # Remove "burst" CLI node from network emulator
+ netem_base = ['qos', 'policy', 'network-emulator']
+ if config.exists(netem_base):
+ for policy_name in config.list_nodes(netem_base):
+ if config.exists(netem_base + [policy_name, 'burst']):
+ config.delete(netem_base + [policy_name, 'burst'])
+
+ # Change bandwidth unit MBit -> mbit as tc only supports mbit
+ base = ['qos', 'policy']
+ if config.exists(base):
+ for policy_type in config.list_nodes(base):
+ for policy in config.list_nodes(base + [policy_type]):
+ policy_base = base + [policy_type, policy]
+ if config.exists(policy_base + ['bandwidth']):
+ tmp = config.return_value(policy_base + ['bandwidth'])
+ config.set(policy_base + ['bandwidth'], value=tmp.lower())
+
+ if config.exists(policy_base + ['class']):
+ for cls in config.list_nodes(policy_base + ['class']):
+ cls_base = policy_base + ['class', cls]
+ if config.exists(cls_base + ['bandwidth']):
+ tmp = config.return_value(cls_base + ['bandwidth'])
+ config.set(cls_base + ['bandwidth'], value=tmp.lower())
+
if config.exists(policy_base + ['default', 'bandwidth']):
- tmp = config.return_value(policy_base + ['default', 'bandwidth'])
- config.set(policy_base + ['default', 'bandwidth'], value=tmp.lower())
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(policy_base + ['default', 'bandwidth']):
+ tmp = config.return_value(policy_base + ['default', 'bandwidth'])
+ config.set(policy_base + ['default', 'bandwidth'], value=tmp.lower())
diff --git a/src/migration-scripts/quagga/10-to-11 b/src/migration-scripts/quagga/10-to-11
index 0ed4f5df6..15dbbb193 100755..100644
--- a/src/migration-scripts/quagga/10-to-11
+++ b/src/migration-scripts/quagga/10-to-11
@@ -1,51 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
static_base = ['protocols', 'static']
-# Check if static routes are configured - if so, migrate the CLI node
-if config.exists(static_base):
- if config.exists(static_base + ['route-map']):
- tmp = config.return_value(static_base + ['route-map'])
- config.set(['system', 'ip', 'protocol', 'static', 'route-map'], value=tmp)
- config.set_tag(['system', 'ip', 'protocol'])
- config.delete(static_base + ['route-map'])
+def migrate(config: ConfigTree) -> None:
+ # Check if static routes are configured - if so, migrate the CLI node
+ if config.exists(static_base):
+ if config.exists(static_base + ['route-map']):
+ tmp = config.return_value(static_base + ['route-map'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ config.set(['system', 'ip', 'protocol', 'static', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(static_base + ['route-map'])
diff --git a/src/migration-scripts/quagga/2-to-3 b/src/migration-scripts/quagga/2-to-3
index 96b56da70..d62c387ba 100755..100644
--- a/src/migration-scripts/quagga/2-to-3
+++ b/src/migration-scripts/quagga/2-to-3
@@ -1,37 +1,21 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2018 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-
-import sys
+# 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 vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
def migrate_neighbor(config, neighbor_path, neighbor):
if config.exists(neighbor_path):
neighbors = config.list_nodes(neighbor_path)
@@ -117,10 +101,11 @@ def migrate_neighbor(config, neighbor_path, neighbor):
config.delete(neighbor_path + [neighbor, 'disable-send-community'])
-if not config.exists(['protocols', 'bgp']):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ return
+
# Just to avoid writing it so many times
af_path = ['address-family', 'ipv4-unicast']
@@ -132,7 +117,7 @@ else:
bgp_path = ['protocols', 'bgp', asn]
else:
# There's actually no BGP, just its empty shell
- sys.exit(0)
+ return
## Move global IPv4-specific BGP options to "address-family ipv4-unicast"
@@ -194,10 +179,3 @@ else:
config.set(bgp_path + af_path + ['redistribute', redistribute, 'route-map'], value=redist_route_map)
config.delete(redistribute_path)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/quagga/3-to-4 b/src/migration-scripts/quagga/3-to-4
index 1e8c8e2f2..81cf139f6 100755..100644
--- a/src/migration-scripts/quagga/3-to-4
+++ b/src/migration-scripts/quagga/3-to-4
@@ -1,20 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
+# 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/>.
# Between 1.2.3 and 1.2.4, FRR added per-neighbor enforce-first-as option.
# Unfortunately they also removed the global enforce-first-as option,
@@ -23,26 +20,14 @@
# To emulate the effect of the original option, we insert it in every neighbor
# if the config used to have the original global option
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['protocols', 'bgp']):
- # Nothing to do
- sys.exit(0)
-else:
# Check if BGP is actually configured and obtain the ASN
asn_list = config.list_nodes(['protocols', 'bgp'])
if asn_list:
@@ -50,7 +35,7 @@ else:
asn = asn_list[0]
else:
# There's actually no BGP, just its empty shell
- sys.exit(0)
+ return
# Check if BGP enforce-first-as option is set
enforce_first_as_path = ['protocols', 'bgp', asn, 'parameters', 'enforce-first-as']
@@ -64,13 +49,4 @@ else:
config.set(['protocols', 'bgp', asn, 'neighbor', p, 'enforce-first-as'])
else:
# Do nothing
- sys.exit(0)
-
- # Save a new configuration file
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
-
+ return
diff --git a/src/migration-scripts/quagga/4-to-5 b/src/migration-scripts/quagga/4-to-5
index fcb496a9c..27b995431 100755..100644
--- a/src/migration-scripts/quagga/4-to-5
+++ b/src/migration-scripts/quagga/4-to-5
@@ -1,41 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-#
-
-import sys
+# 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 vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ return
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['protocols', 'bgp']):
- # Nothing to do
- sys.exit(0)
-else:
# Check if BGP is actually configured and obtain the ASN
asn_list = config.list_nodes(['protocols', 'bgp'])
if asn_list:
@@ -43,7 +28,7 @@ else:
asn = asn_list[0]
else:
# There's actually no BGP, just its empty shell
- sys.exit(0)
+ return
# Check if BGP scan-time parameter exist
scan_time_param = ['protocols', 'bgp', asn, 'parameters', 'scan-time']
@@ -52,12 +37,4 @@ else:
config.delete(scan_time_param)
else:
# Do nothing
- sys.exit(0)
-
- # Save a new configuration file
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ return
diff --git a/src/migration-scripts/quagga/5-to-6 b/src/migration-scripts/quagga/5-to-6
index f075fc2e7..08fd070de 100755..100644
--- a/src/migration-scripts/quagga/5-to-6
+++ b/src/migration-scripts/quagga/5-to-6
@@ -1,42 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# * Remove parameter 'disable-network-import-check' which, as implemented,
-# had no effect on boot.
-
-import sys
+# 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 vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['protocols', 'bgp']):
- # Nothing to do
- sys.exit(0)
-else:
# Check if BGP is actually configured and obtain the ASN
asn_list = config.list_nodes(['protocols', 'bgp'])
if asn_list:
@@ -44,7 +28,7 @@ else:
asn = asn_list[0]
else:
# There's actually no BGP, just its empty shell
- sys.exit(0)
+ return
# Check if BGP parameter disable-network-import-check exists
param = ['protocols', 'bgp', asn, 'parameters', 'disable-network-import-check']
@@ -53,11 +37,4 @@ else:
config.delete(param)
else:
# Do nothing
- sys.exit(0)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ return
diff --git a/src/migration-scripts/quagga/6-to-7 b/src/migration-scripts/quagga/6-to-7
index ed295a95c..095baac03 100755..100644
--- a/src/migration-scripts/quagga/6-to-7
+++ b/src/migration-scripts/quagga/6-to-7
@@ -1,116 +1,97 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T3037, BGP address-family ipv6-unicast capability dynamic does not exist in
# FRR, there is only a base, per neighbor dynamic capability, migrate config
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
from vyos.template import is_ipv6
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'bgp']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# Check if BGP is actually configured and obtain the ASN
-asn_list = config.list_nodes(base)
-if asn_list:
- # There's always just one BGP node, if any
- bgp_base = base + [asn_list[0]]
-
- for neighbor_type in ['neighbor', 'peer-group']:
- if not config.exists(bgp_base + [neighbor_type]):
- continue
- for neighbor in config.list_nodes(bgp_base + [neighbor_type]):
- # T2844 - add IPv4 AFI disable-send-community support
- send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community']
- if config.exists(send_comm_path):
- new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast']
- config.set(new_base)
- config.copy(send_comm_path, new_base + ['disable-send-community'])
- config.delete(send_comm_path)
-
- cap_dynamic = False
- peer_group = None
- for afi in ['ipv4-unicast', 'ipv6-unicast']:
- afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi]
- # Exit loop early if AFI does not exist
- if not config.exists(afi_path):
- continue
-
- cap_path = afi_path + ['capability', 'dynamic']
- if config.exists(cap_path):
- cap_dynamic = True
- config.delete(cap_path)
-
- # We have now successfully migrated the address-family
- # specific dynamic capability to the neighbor/peer-group
- # level. If this has been the only option under the
- # address-family nodes, we can clean them up by checking if
- # no other nodes are left under that tree and if so, delete
- # the parent.
- #
- # We walk from the most inner node to the most outer one.
- cleanup = -1
- while len(config.list_nodes(cap_path[:cleanup])) == 0:
- config.delete(cap_path[:cleanup])
- cleanup -= 1
-
- peer_group_path = afi_path + ['peer-group']
- if config.exists(peer_group_path):
- if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or
- (is_ipv6(neighbor) and afi == 'ipv6-unicast')):
- peer_group = config.return_value(peer_group_path)
-
- config.delete(peer_group_path)
-
- # We have now successfully migrated the address-family
- # specific peer-group to the neighbor level. If this has
- # been the only option under the address-family nodes, we
- # can clean them up by checking if no other nodes are left
- # under that tree and if so, delete the parent.
- #
- # We walk from the most inner node to the most outer one.
- cleanup = -1
- while len(config.list_nodes(peer_group_path[:cleanup])) == 0:
- config.delete(peer_group_path[:cleanup])
- cleanup -= 1
-
- if cap_dynamic:
- config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic'])
- if peer_group:
- config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Check if BGP is actually configured and obtain the ASN
+ asn_list = config.list_nodes(base)
+ if asn_list:
+ # There's always just one BGP node, if any
+ bgp_base = base + [asn_list[0]]
+
+ for neighbor_type in ['neighbor', 'peer-group']:
+ if not config.exists(bgp_base + [neighbor_type]):
+ continue
+ for neighbor in config.list_nodes(bgp_base + [neighbor_type]):
+ # T2844 - add IPv4 AFI disable-send-community support
+ send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community']
+ if config.exists(send_comm_path):
+ new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast']
+ config.set(new_base)
+ config.copy(send_comm_path, new_base + ['disable-send-community'])
+ config.delete(send_comm_path)
+
+ cap_dynamic = False
+ peer_group = None
+ for afi in ['ipv4-unicast', 'ipv6-unicast']:
+ afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi]
+ # Exit loop early if AFI does not exist
+ if not config.exists(afi_path):
+ continue
+
+ cap_path = afi_path + ['capability', 'dynamic']
+ if config.exists(cap_path):
+ cap_dynamic = True
+ config.delete(cap_path)
+
+ # We have now successfully migrated the address-family
+ # specific dynamic capability to the neighbor/peer-group
+ # level. If this has been the only option under the
+ # address-family nodes, we can clean them up by checking if
+ # no other nodes are left under that tree and if so, delete
+ # the parent.
+ #
+ # We walk from the most inner node to the most outer one.
+ cleanup = -1
+ while len(config.list_nodes(cap_path[:cleanup])) == 0:
+ config.delete(cap_path[:cleanup])
+ cleanup -= 1
+
+ peer_group_path = afi_path + ['peer-group']
+ if config.exists(peer_group_path):
+ if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or
+ (is_ipv6(neighbor) and afi == 'ipv6-unicast')):
+ peer_group = config.return_value(peer_group_path)
+
+ config.delete(peer_group_path)
+
+ # We have now successfully migrated the address-family
+ # specific peer-group to the neighbor level. If this has
+ # been the only option under the address-family nodes, we
+ # can clean them up by checking if no other nodes are left
+ # under that tree and if so, delete the parent.
+ #
+ # We walk from the most inner node to the most outer one.
+ cleanup = -1
+ while len(config.list_nodes(peer_group_path[:cleanup])) == 0:
+ config.delete(peer_group_path[:cleanup])
+ cleanup -= 1
+
+ if cap_dynamic:
+ config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic'])
+ if peer_group:
+ config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group)
diff --git a/src/migration-scripts/quagga/7-to-8 b/src/migration-scripts/quagga/7-to-8
index 8f11bf390..d9de26d15 100755..100644
--- a/src/migration-scripts/quagga/7-to-8
+++ b/src/migration-scripts/quagga/7-to-8
@@ -1,61 +1,42 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T3391: Migrate "maximum-paths" setting from "protocols bgp asn maximum-paths"
# under the IPv4 address-family tree. Reason is we currently have no way in
# configuring this for IPv6 address-family. This mimics the FRR configuration.
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'bgp']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# Check if BGP is actually configured and obtain the ASN
-asn_list = config.list_nodes(base)
-if asn_list:
- # There's always just one BGP node, if any
- bgp_base = base + [asn_list[0]]
-
- maximum_paths = bgp_base + ['maximum-paths']
- if config.exists(maximum_paths):
- for bgp_type in ['ebgp', 'ibgp']:
- if config.exists(maximum_paths + [bgp_type]):
- new_base = bgp_base + ['address-family', 'ipv4-unicast', 'maximum-paths']
- config.set(new_base)
- config.copy(maximum_paths + [bgp_type], new_base + [bgp_type])
- config.delete(maximum_paths)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Check if BGP is actually configured and obtain the ASN
+ asn_list = config.list_nodes(base)
+ if asn_list:
+ # There's always just one BGP node, if any
+ bgp_base = base + [asn_list[0]]
+
+ maximum_paths = bgp_base + ['maximum-paths']
+ if config.exists(maximum_paths):
+ for bgp_type in ['ebgp', 'ibgp']:
+ if config.exists(maximum_paths + [bgp_type]):
+ new_base = bgp_base + ['address-family', 'ipv4-unicast', 'maximum-paths']
+ config.set(new_base)
+ config.copy(maximum_paths + [bgp_type], new_base + [bgp_type])
+ config.delete(maximum_paths)
diff --git a/src/migration-scripts/quagga/8-to-9 b/src/migration-scripts/quagga/8-to-9
index 0f683d5a1..eece6c15d 100755..100644
--- a/src/migration-scripts/quagga/8-to-9
+++ b/src/migration-scripts/quagga/8-to-9
@@ -1,24 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T2450: drop interface-route and interface-route6 from "protocols static"
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
def migrate_interface_route(config, base, path, route_route6):
@@ -84,54 +80,38 @@ def migrate_route(config, base, path, route_route6):
config.rename(vrf_path, 'vrf')
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['protocols', 'static']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ # Migrate interface-route into route
+ migrate_interface_route(config, base, ['interface-route'], 'route')
-base = ['protocols', 'static']
+ # Migrate interface-route6 into route6
+ migrate_interface_route(config, base, ['interface-route6'], 'route6')
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
+ # Cleanup nodes inside route
+ migrate_route(config, base, ['route'], 'route')
-# Migrate interface-route into route
-migrate_interface_route(config, base, ['interface-route'], 'route')
+ # Cleanup nodes inside route6
+ migrate_route(config, base, ['route6'], 'route6')
-# Migrate interface-route6 into route6
-migrate_interface_route(config, base, ['interface-route6'], 'route6')
+ #
+ # PBR table cleanup
+ table_path = base + ['table']
+ if config.exists(table_path):
+ for table in config.list_nodes(table_path):
+ # Migrate interface-route into route
+ migrate_interface_route(config, table_path + [table], ['interface-route'], 'route')
-# Cleanup nodes inside route
-migrate_route(config, base, ['route'], 'route')
+ # Migrate interface-route6 into route6
+ migrate_interface_route(config, table_path + [table], ['interface-route6'], 'route6')
-# Cleanup nodes inside route6
-migrate_route(config, base, ['route6'], 'route6')
+ # Cleanup nodes inside route
+ migrate_route(config, table_path + [table], ['route'], 'route')
-#
-# PBR table cleanup
-table_path = base + ['table']
-if config.exists(table_path):
- for table in config.list_nodes(table_path):
- # Migrate interface-route into route
- migrate_interface_route(config, table_path + [table], ['interface-route'], 'route')
-
- # Migrate interface-route6 into route6
- migrate_interface_route(config, table_path + [table], ['interface-route6'], 'route6')
-
- # Cleanup nodes inside route
- migrate_route(config, table_path + [table], ['route'], 'route')
-
- # Cleanup nodes inside route6
- migrate_route(config, table_path + [table], ['route6'], 'route6')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Cleanup nodes inside route6
+ migrate_route(config, table_path + [table], ['route6'], 'route6')
diff --git a/src/migration-scripts/quagga/9-to-10 b/src/migration-scripts/quagga/9-to-10
index 3731762f7..4ac1f0b7d 100755..100644
--- a/src/migration-scripts/quagga/9-to-10
+++ b/src/migration-scripts/quagga/9-to-10
@@ -1,62 +1,42 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# re-organize route-map as-path
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy', 'route-map']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for route_map in config.list_nodes(base):
- # Bail out Early
- if not config.exists(base + [route_map, 'rule']):
- continue
-
- for rule in config.list_nodes(base + [route_map, 'rule']):
- rule_base = base + [route_map, 'rule', rule]
- if config.exists(rule_base + ['set', 'as-path-exclude']):
- tmp = config.return_value(rule_base + ['set', 'as-path-exclude'])
- config.delete(rule_base + ['set', 'as-path-exclude'])
- config.set(rule_base + ['set', 'as-path', 'exclude'], value=tmp)
-
- if config.exists(rule_base + ['set', 'as-path-prepend']):
- tmp = config.return_value(rule_base + ['set', 'as-path-prepend'])
- config.delete(rule_base + ['set', 'as-path-prepend'])
- config.set(rule_base + ['set', 'as-path', 'prepend'], value=tmp)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for route_map in config.list_nodes(base):
+ # Bail out Early
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ rule_base = base + [route_map, 'rule', rule]
+ if config.exists(rule_base + ['set', 'as-path-exclude']):
+ tmp = config.return_value(rule_base + ['set', 'as-path-exclude'])
+ config.delete(rule_base + ['set', 'as-path-exclude'])
+ config.set(rule_base + ['set', 'as-path', 'exclude'], value=tmp)
+
+ if config.exists(rule_base + ['set', 'as-path-prepend']):
+ tmp = config.return_value(rule_base + ['set', 'as-path-prepend'])
+ config.delete(rule_base + ['set', 'as-path-prepend'])
+ config.set(rule_base + ['set', 'as-path', 'prepend'], value=tmp)
diff --git a/src/migration-scripts/reverse-proxy/0-to-1 b/src/migration-scripts/reverse-proxy/0-to-1
index d61493815..b495474a6 100755..100644
--- a/src/migration-scripts/reverse-proxy/0-to-1
+++ b/src/migration-scripts/reverse-proxy/0-to-1
@@ -1,48 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6409: Remove unused 'backend bk-example parameters' node
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['load-balancing', 'reverse-proxy', 'backend']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-# we need to run this for every configured network
-for backend in config.list_nodes(base):
- param_node = base + [backend, 'parameters']
- if config.exists(param_node):
- config.delete(param_node)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # we need to run this for every configured network
+ for backend in config.list_nodes(base):
+ param_node = base + [backend, 'parameters']
+ if config.exists(param_node):
+ config.delete(param_node)
diff --git a/src/migration-scripts/rip/0-to-1 b/src/migration-scripts/rip/0-to-1
index 08a866374..6d41bcf58 100755..100644
--- a/src/migration-scripts/rip/0-to-1
+++ b/src/migration-scripts/rip/0-to-1
@@ -1,51 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
ripng_base = ['protocols', 'ripng']
-# Check if RIPng is configured - if so, migrate the CLI node
-if config.exists(ripng_base):
- if config.exists(ripng_base + ['route-map']):
- tmp = config.return_value(ripng_base + ['route-map'])
- config.set(['system', 'ipv6', 'protocol', 'ripng', 'route-map'], value=tmp)
- config.set_tag(['system', 'ipv6', 'protocol'])
- config.delete(ripng_base + ['route-map'])
+def migrate(config: ConfigTree) -> None:
+ # Check if RIPng is configured - if so, migrate the CLI node
+ if config.exists(ripng_base):
+ if config.exists(ripng_base + ['route-map']):
+ tmp = config.return_value(ripng_base + ['route-map'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ config.set(['system', 'ipv6', 'protocol', 'ripng', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ipv6', 'protocol'])
+ config.delete(ripng_base + ['route-map'])
diff --git a/src/migration-scripts/rpki/0-to-1 b/src/migration-scripts/rpki/0-to-1
index a7b5d07d5..b6e781fa9 100755..100644
--- a/src/migration-scripts/rpki/0-to-1
+++ b/src/migration-scripts/rpki/0-to-1
@@ -1,63 +1,44 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import exit
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'rpki']
-config = ConfigTree(config_file)
-
-# Nothing to do
-if not config.exists(base):
- exit(0)
-
-if config.exists(base + ['cache']):
- preference = 1
- for cache in config.list_nodes(base + ['cache']):
- address_node = base + ['cache', cache, 'address']
- if config.exists(address_node):
- address = config.return_value(address_node)
- # We do not longer support the address leafNode, RPKI cache server
- # IP address is now used from the tagNode
- config.delete(address_node)
- # VyOS 1.2 had no per instance preference, setting new defaults
- config.set(base + ['cache', cache, 'preference'], value=preference)
- # Increase preference for the next caching peer - actually VyOS 1.2
- # supported only one but better save then sorry (T3253)
- preference += 1
-
- # T3293: If the RPKI cache name equals the configured address,
- # renaming is not possible, as rename expects the new path to not
- # exist.
- if not config.exists(base + ['cache', address]):
- config.rename(base + ['cache', cache], address)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Nothing to do
+ if not config.exists(base):
+ return
+
+ if config.exists(base + ['cache']):
+ preference = 1
+ for cache in config.list_nodes(base + ['cache']):
+ address_node = base + ['cache', cache, 'address']
+ if config.exists(address_node):
+ address = config.return_value(address_node)
+ # We do not longer support the address leafNode, RPKI cache server
+ # IP address is now used from the tagNode
+ config.delete(address_node)
+ # VyOS 1.2 had no per instance preference, setting new defaults
+ config.set(base + ['cache', cache, 'preference'], value=preference)
+ # Increase preference for the next caching peer - actually VyOS 1.2
+ # supported only one but better save then sorry (T3253)
+ preference += 1
+
+ # T3293: If the RPKI cache name equals the configured address,
+ # renaming is not possible, as rename expects the new path to not
+ # exist.
+ if not config.exists(base + ['cache', address]):
+ config.rename(base + ['cache', cache], address)
diff --git a/src/migration-scripts/rpki/1-to-2 b/src/migration-scripts/rpki/1-to-2
index 50d4a3dfc..855236d6c 100755..100644
--- a/src/migration-scripts/rpki/1-to-2
+++ b/src/migration-scripts/rpki/1-to-2
@@ -1,73 +1,53 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6011: rpki: known-hosts-file is no longer supported bxy FRR CLI,
# remove VyOS CLI node
-from sys import exit
-from sys import argv
-
from vyos.configtree import ConfigTree
from vyos.pki import OPENSSH_KEY_BEGIN
from vyos.pki import OPENSSH_KEY_END
from vyos.utils.file import read_file
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'rpki']
-config = ConfigTree(config_file)
-
-# Nothing to do
-if not config.exists(base):
- exit(0)
-
-if config.exists(base + ['cache']):
- for cache in config.list_nodes(base + ['cache']):
- ssh_node = base + ['cache', cache, 'ssh']
- if config.exists(ssh_node + ['known-hosts-file']):
- config.delete(ssh_node + ['known-hosts-file'])
-
- if config.exists(base + ['cache', cache, 'ssh']):
- private_key_node = base + ['cache', cache, 'ssh', 'private-key-file']
- private_key_file = config.return_value(private_key_node)
- private_key = read_file(private_key_file).replace(OPENSSH_KEY_BEGIN, '').replace(OPENSSH_KEY_END, '').replace('\n','')
-
- public_key_node = base + ['cache', cache, 'ssh', 'public-key-file']
- public_key_file = config.return_value(public_key_node)
- public_key = read_file(public_key_file).split()
-
- config.set(['pki', 'openssh', f'rpki-{cache}', 'private', 'key'], value=private_key)
- config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'key'], value=public_key[1])
- config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'type'], value=public_key[0])
- config.set_tag(['pki', 'openssh'])
- config.set(ssh_node + ['key'], value=f'rpki-{cache}')
-
- config.delete(private_key_node)
- config.delete(public_key_node)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Nothing to do
+ if not config.exists(base):
+ return
+
+ if config.exists(base + ['cache']):
+ for cache in config.list_nodes(base + ['cache']):
+ ssh_node = base + ['cache', cache, 'ssh']
+ if config.exists(ssh_node + ['known-hosts-file']):
+ config.delete(ssh_node + ['known-hosts-file'])
+
+ if config.exists(base + ['cache', cache, 'ssh']):
+ private_key_node = base + ['cache', cache, 'ssh', 'private-key-file']
+ private_key_file = config.return_value(private_key_node)
+ private_key = read_file(private_key_file).replace(OPENSSH_KEY_BEGIN, '').replace(OPENSSH_KEY_END, '').replace('\n','')
+
+ public_key_node = base + ['cache', cache, 'ssh', 'public-key-file']
+ public_key_file = config.return_value(public_key_node)
+ public_key = read_file(public_key_file).split()
+
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'private', 'key'], value=private_key)
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'key'], value=public_key[1])
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'type'], value=public_key[0])
+ config.set_tag(['pki', 'openssh'])
+ config.set(ssh_node + ['key'], value=f'rpki-{cache}')
+
+ config.delete(private_key_node)
+ config.delete(public_key_node)
diff --git a/src/migration-scripts/salt/0-to-1 b/src/migration-scripts/salt/0-to-1
index 481d9de8f..3990a88dc 100755..100644
--- a/src/migration-scripts/salt/0-to-1
+++ b/src/migration-scripts/salt/0-to-1
@@ -1,43 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Delete log_file, log_level and user nodes
# rename hash_type to hash
# rename mine_interval to interval
-from sys import argv,exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'salt-minion']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
# delete nodes which are now populated with sane defaults
for node in ['log_file', 'log_level', 'user']:
@@ -49,10 +36,3 @@ else:
if config.exists(base + ['mine_interval']):
config.rename(base + ['mine_interval'], 'interval')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/snmp/0-to-1 b/src/migration-scripts/snmp/0-to-1
index b1e61b958..03b190cb7 100755..100644
--- a/src/migration-scripts/snmp/0-to-1
+++ b/src/migration-scripts/snmp/0-to-1
@@ -1,38 +1,27 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
config_base = ['service', 'snmp', 'v3']
-if not config.exists(config_base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(config_base):
+ # Nothing to do
+ return
+
# we no longer support a per trap target engine ID (https://vyos.dev/T818)
if config.exists(config_base + ['v3', 'trap-target']):
for target in config.list_nodes(config_base + ['v3', 'trap-target']):
@@ -47,10 +36,3 @@ else:
# https://vyos.dev/T1769
if config.exists(config_base + ['v3', 'tsm']):
config.delete(config_base + ['v3', 'tsm'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/snmp/1-to-2 b/src/migration-scripts/snmp/1-to-2
index e02cd1aa1..0120f8acb 100755..100644
--- a/src/migration-scripts/snmp/1-to-2
+++ b/src/migration-scripts/snmp/1-to-2
@@ -1,22 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv, exit
from vyos.configtree import ConfigTree
+# We no longer support hashed values prefixed with '0x' to unclutter
+# CLI and also calculate the hases in advance instead of retrieving
+# them after service startup - which was always a bad idea
+prefix = '0x'
+
def migrate_keys(config, path):
# authentication: rename node 'encrypted-key' -> 'encrypted-password'
config_path_auth = path + ['auth', 'encrypted-key']
@@ -42,48 +45,26 @@ def migrate_keys(config, path):
tmp = tmp.replace(prefix, '')
config.set(config_path_priv, value=tmp)
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
config_base = ['service', 'snmp', 'v3']
if not config.exists(config_base):
# Nothing to do
- exit(0)
- else:
- # We no longer support hashed values prefixed with '0x' to unclutter
- # CLI and also calculate the hases in advance instead of retrieving
- # them after service startup - which was always a bad idea
- prefix = '0x'
-
- config_engineid = config_base + ['engineid']
- if config.exists(config_engineid):
- tmp = config.return_value(config_engineid)
- if tmp.startswith(prefix):
- tmp = tmp.replace(prefix, '')
- config.set(config_engineid, value=tmp)
+ return
- config_user = config_base + ['user']
- if config.exists(config_user):
- for user in config.list_nodes(config_user):
- migrate_keys(config, config_user + [user])
+ config_engineid = config_base + ['engineid']
+ if config.exists(config_engineid):
+ tmp = config.return_value(config_engineid)
+ if tmp.startswith(prefix):
+ tmp = tmp.replace(prefix, '')
+ config.set(config_engineid, value=tmp)
- config_trap = config_base + ['trap-target']
- if config.exists(config_trap):
- for trap in config.list_nodes(config_trap):
- migrate_keys(config, config_trap + [trap])
+ config_user = config_base + ['user']
+ if config.exists(config_user):
+ for user in config.list_nodes(config_user):
+ migrate_keys(config, config_user + [user])
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config_trap = config_base + ['trap-target']
+ if config.exists(config_trap):
+ for trap in config.list_nodes(config_trap):
+ migrate_keys(config, config_trap + [trap])
diff --git a/src/migration-scripts/snmp/2-to-3 b/src/migration-scripts/snmp/2-to-3
index ab9b5dcba..6d828b619 100755..100644
--- a/src/migration-scripts/snmp/2-to-3
+++ b/src/migration-scripts/snmp/2-to-3
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4857: Implement FRR SNMP recomendations
# cli changes from:
@@ -20,35 +19,15 @@
# To
# set service snmp oid-enable ip-forward
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service snmp']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['oid-enable']):
- config.delete(base + ['oid-enable'])
- config.set(base + ['oid-enable'], 'ip-forward')
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(base + ['oid-enable']):
+ config.delete(base + ['oid-enable'])
+ config.set(base + ['oid-enable'], 'ip-forward')
diff --git a/src/migration-scripts/ssh/0-to-1 b/src/migration-scripts/ssh/0-to-1
index 2595599ac..65b68f509 100755..100644
--- a/src/migration-scripts/ssh/0-to-1
+++ b/src/migration-scripts/ssh/0-to-1
@@ -1,32 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Delete "service ssh allow-root" option
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['service', 'ssh', 'allow-root']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['service', 'ssh', 'allow-root']):
- # Nothing to do
- sys.exit(0)
-else:
# Delete node with abandoned command
config.delete(['service', 'ssh', 'allow-root'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/ssh/1-to-2 b/src/migration-scripts/ssh/1-to-2
index 79d65d7d4..b601db3b4 100755..100644
--- a/src/migration-scripts/ssh/1-to-2
+++ b/src/migration-scripts/ssh/1-to-2
@@ -1,81 +1,63 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# VyOS 1.2 crux allowed configuring a lower or upper case loglevel. This
# is no longer supported as the input data is validated and will lead to
# an error. If user specifies an upper case logleve, make it lowercase
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'ssh']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-path_loglevel = base + ['loglevel']
-if config.exists(path_loglevel):
- # red in configured loglevel and convert it to lower case
- tmp = config.return_value(path_loglevel).lower()
- # VyOS 1.2 had no proper value validation on the CLI thus the
- # user could use any arbitrary values - sanitize them
- if tmp not in ['quiet', 'fatal', 'error', 'info', 'verbose']:
- tmp = 'info'
- config.set(path_loglevel, value=tmp)
-
-# T4273: migrate ssh cipher list to multi node
-path_ciphers = base + ['ciphers']
-if config.exists(path_ciphers):
- tmp = []
- # get curtrent cipher list - comma delimited
- for cipher in config.return_values(path_ciphers):
- tmp.extend(cipher.split(','))
- # delete old cipher suite representation
- config.delete(path_ciphers)
-
- for cipher in tmp:
- config.set(path_ciphers, value=cipher, replace=False)
-
-# T4273: migrate ssh key-exchange list to multi node
-path_kex = base + ['key-exchange']
-if config.exists(path_kex):
- tmp = []
- # get curtrent cipher list - comma delimited
- for kex in config.return_values(path_kex):
- tmp.extend(kex.split(','))
- # delete old cipher suite representation
- config.delete(path_kex)
-
- for kex in tmp:
- config.set(path_kex, value=kex, replace=False)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ path_loglevel = base + ['loglevel']
+ if config.exists(path_loglevel):
+ # red in configured loglevel and convert it to lower case
+ tmp = config.return_value(path_loglevel).lower()
+ # VyOS 1.2 had no proper value validation on the CLI thus the
+ # user could use any arbitrary values - sanitize them
+ if tmp not in ['quiet', 'fatal', 'error', 'info', 'verbose']:
+ tmp = 'info'
+ config.set(path_loglevel, value=tmp)
+
+ # T4273: migrate ssh cipher list to multi node
+ path_ciphers = base + ['ciphers']
+ if config.exists(path_ciphers):
+ tmp = []
+ # get curtrent cipher list - comma delimited
+ for cipher in config.return_values(path_ciphers):
+ tmp.extend(cipher.split(','))
+ # delete old cipher suite representation
+ config.delete(path_ciphers)
+
+ for cipher in tmp:
+ config.set(path_ciphers, value=cipher, replace=False)
+
+ # T4273: migrate ssh key-exchange list to multi node
+ path_kex = base + ['key-exchange']
+ if config.exists(path_kex):
+ tmp = []
+ # get curtrent cipher list - comma delimited
+ for kex in config.return_values(path_kex):
+ tmp.extend(kex.split(','))
+ # delete old cipher suite representation
+ config.delete(path_kex)
+
+ for kex in tmp:
+ config.set(path_kex, value=kex, replace=False)
diff --git a/src/migration-scripts/sstp/0-to-1 b/src/migration-scripts/sstp/0-to-1
index 150127aaf..1bd7d6c6b 100755..100644
--- a/src/migration-scripts/sstp/0-to-1
+++ b/src/migration-scripts/sstp/0-to-1
@@ -1,19 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
+# 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/>.
# - migrate from "service sstp-server" to "vpn sstp"
# - remove primary/secondary identifier from nameserver
@@ -23,25 +21,15 @@
# - do not migrate radius server req-limit, use default of unlimited
# - migrate SSL certificate path
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+old_base = ['service', 'sstp-server']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-old_base = ['service', 'sstp-server']
-if not config.exists(old_base):
- # Nothing to do
- sys.exit(0)
-else:
# ensure new base path exists
if not config.exists(['vpn']):
config.set(['vpn'])
@@ -119,10 +107,3 @@ else:
if config.exists(new_ssl + ['server-key']):
config.rename(new_ssl + ['server-key'], 'key-file')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/sstp/1-to-2 b/src/migration-scripts/sstp/1-to-2
index f7ecbb6d4..2349e3c9f 100755..100644
--- a/src/migration-scripts/sstp/1-to-2
+++ b/src/migration-scripts/sstp/1-to-2
@@ -1,45 +1,35 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - migrate relative path SSL certificate to absolute path, as certs are only
# allowed to stored in /config/user-data/sstp/ this is pretty straight
# forward move. Delete certificates from source directory
import os
-import sys
from shutil import copy2
from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base_path = ['vpn', 'sstp', 'ssl']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base_path = ['vpn', 'sstp', 'ssl']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-else:
cert_path_old ='/config/user-data/sstp/'
cert_path_new ='/config/auth/sstp/'
@@ -101,10 +91,3 @@ else:
# check if old certificate directory exists but is empty
if os.path.isdir(cert_path_old) and not os.listdir(cert_path_old):
os.rmdir(cert_path_old)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/sstp/2-to-3 b/src/migration-scripts/sstp/2-to-3
index 245db7ad6..4255a896e 100755..100644
--- a/src/migration-scripts/sstp/2-to-3
+++ b/src/migration-scripts/sstp/2-to-3
@@ -1,41 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Rename SSTP ppp-settings node to ppp-options to make use of a common
# Jinja Template to render Accel-PPP services
from vyos.configtree import ConfigTree
-from sys import argv
-from sys import exit
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-file_name = argv[1]
+base_path = ['vpn', 'sstp']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base_path = ['vpn', 'sstp']
-if not config.exists(base_path):
- # Nothing to do
- exit(0)
-else:
if config.exists(base_path + ['ppp-settings']):
config.rename(base_path + ['ppp-settings'], 'ppp-options')
@@ -68,11 +57,3 @@ else:
config_nw_settings = base_path + ['network-settings']
if config.exists(config_nw_settings):
config.delete(config_nw_settings)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
diff --git a/src/migration-scripts/sstp/3-to-4 b/src/migration-scripts/sstp/3-to-4
index 5b7757e60..fd10985de 100755..100644
--- a/src/migration-scripts/sstp/3-to-4
+++ b/src/migration-scripts/sstp/3-to-4
@@ -1,25 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Update SSL to use PKI configuration
import os
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_private_key
@@ -27,109 +24,93 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'sstp']
pki_base = ['pki']
-if not config.exists(base):
- exit(0)
-
AUTH_DIR = '/config/auth'
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
-if not config.exists(base + ['ssl']):
- exit(0)
-
-x509_base = base + ['ssl']
-pki_name = 'sstp'
-
-if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
-if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
-if config.exists(x509_base + ['ca-cert-file']):
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on sstp config')
-
- config.delete(x509_base + ['ca-cert-file'])
-
-if config.exists(x509_base + ['cert-file']):
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on sstp config')
-
- config.delete(x509_base + ['cert-file'])
-
-if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on sstp config')
-
- config.delete(x509_base + ['key-file'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(base + ['ssl']):
+ return
+
+ x509_base = base + ['ssl']
+ pki_name = 'sstp'
+
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on sstp config')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['cert-file']):
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on sstp config')
+
+ config.delete(x509_base + ['cert-file'])
+
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on sstp config')
+
+ config.delete(x509_base + ['key-file'])
diff --git a/src/migration-scripts/sstp/4-to-5 b/src/migration-scripts/sstp/4-to-5
index 6907240a0..254e828af 100755..100644
--- a/src/migration-scripts/sstp/4-to-5
+++ b/src/migration-scripts/sstp/4-to-5
@@ -1,59 +1,41 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - move all pool to named pools
# 'subnet' migrate to namedpool 'default-subnet-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'sstp']
pool_base = base + ['client-ip-pool']
-if not config.exists(base):
- exit(0)
-if not config.exists(pool_base):
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-range_pool_name = 'default-range-pool'
+ if not config.exists(pool_base):
+ return
-if config.exists(pool_base + ['subnet']):
- default_pool = range_pool_name
- for subnet in config.return_values(pool_base + ['subnet']):
- config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
- config.delete(pool_base + ['subnet'])
- config.set(base + ['default-pool'], value=default_pool)
-# format as tag node
-config.set_tag(pool_base)
+ range_pool_name = 'default-range-pool'
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(pool_base + ['subnet']):
+ default_pool = range_pool_name
+ for subnet in config.return_values(pool_base + ['subnet']):
+ config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
+ config.delete(pool_base + ['subnet'])
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/sstp/5-to-6 b/src/migration-scripts/sstp/5-to-6
index 43b99044d..fc3cc29b2 100755..100644
--- a/src/migration-scripts/sstp/5-to-6
+++ b/src/migration-scripts/sstp/5-to-6
@@ -1,58 +1,40 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrating to named ipv6 pools
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['vpn', 'sstp']
+pool_base = base + ['client-ipv6-pool']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ if not config.exists(pool_base):
+ return
-config = ConfigTree(config_file)
-base = ['vpn', 'sstp']
-pool_base = base + ['client-ipv6-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-ipv6_pool_name = 'ipv6-pool'
-config.copy(pool_base, pool_base + [ipv6_pool_name])
-
-if config.exists(pool_base + ['prefix']):
- config.delete(pool_base + ['prefix'])
- config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
-if config.exists(pool_base + ['delegate']):
- config.delete(pool_base + ['delegate'])
-
-# format as tag node
-config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ ipv6_pool_name = 'ipv6-pool'
+ config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+ if config.exists(pool_base + ['prefix']):
+ config.delete(pool_base + ['prefix'])
+ config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+ if config.exists(pool_base + ['delegate']):
+ config.delete(pool_base + ['delegate'])
+
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/system/10-to-11 b/src/migration-scripts/system/10-to-11
index 5d662af40..76d7f23cb 100755..100644
--- a/src/migration-scripts/system/10-to-11
+++ b/src/migration-scripts/system/10-to-11
@@ -1,36 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Operator accounts have been deprecated due to a security issue. Those accounts
# will be converted to regular admin accounts.
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base_level = ['system', 'login', 'user']
-if not config.exists(base_level):
- # Nothing to do, which shouldn't happen anyway
- # only if you wipe the config and reboot.
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_level):
+ # Nothing to do, which shouldn't happen anyway
+ # only if you wipe the config and reboot.
+ return
+
for user in config.list_nodes(base_level):
if config.exists(base_level + [user, 'level']):
if config.return_value(base_level + [user, 'level']) == 'operator':
config.set(base_level + [user, 'level'], value="admin", replace=True)
-
- try:
- open(file_name,'w').write(config.to_string())
-
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/11-to-12 b/src/migration-scripts/system/11-to-12
index 880ab56dc..71c359b7e 100755..100644
--- a/src/migration-scripts/system/11-to-12
+++ b/src/migration-scripts/system/11-to-12
@@ -1,28 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Unclutter RADIUS configuration
#
# Move radius-server top level tag nodes to a regular node which allows us
# to specify additional general features for the RADIUS client.
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+cfg_base = ['system', 'login']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not (config.exists(cfg_base + ['radius-server']) or config.exists(cfg_base + ['radius-source-address'])):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-cfg_base = ['system', 'login']
-if not (config.exists(cfg_base + ['radius-server']) or config.exists(cfg_base + ['radius-source-address'])):
- # Nothing to do
- sys.exit(0)
-else:
#
# Migrate "system login radius-source-address" to "system login radius"
#
@@ -63,10 +67,3 @@ else:
# delete top level tag node
if config.exists(cfg_base + ['radius-server']):
config.delete(cfg_base + ['radius-server'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/12-to-13 b/src/migration-scripts/system/12-to-13
index e6c4e3802..014edba91 100755..100644
--- a/src/migration-scripts/system/12-to-13
+++ b/src/migration-scripts/system/12-to-13
@@ -1,47 +1,44 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# converts 'set system syslog host <address>:<port>'
# to 'set system syslog host <address> port <port>'
-import sys
import re
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
cbase = ['system', 'syslog', 'host']
-if not config.exists(cbase):
- sys.exit(0)
-
-for host in config.list_nodes(cbase):
- if re.search(':[0-9]{1,5}$',host):
- h = re.search('^[a-zA-Z\-0-9\.]+', host).group(0)
- p = re.sub(':', '', re.search(':[0-9]+$', host).group(0))
- config.set(cbase + [h])
- config.set(cbase + [h, 'port'], value=p)
- for fac in config.list_nodes(cbase + [host, 'facility']):
- config.set(cbase + [h, 'facility', fac])
- config.set_tag(cbase + [h, 'facility'])
- if config.exists(cbase + [host, 'facility', fac, 'protocol']):
- proto = config.return_value(cbase + [host, 'facility', fac, 'protocol'])
- config.set(cbase + [h, 'facility', fac, 'protocol'], value=proto)
- if config.exists(cbase + [host, 'facility', fac, 'level']):
- lvl = config.return_value(cbase + [host, 'facility', fac, 'level'])
- config.set(cbase + [h, 'facility', fac, 'level'], value=lvl)
- config.delete(cbase + [host])
-
-try:
- open(file_name,'w').write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cbase):
+ return
+
+ for host in config.list_nodes(cbase):
+ if re.search(':[0-9]{1,5}$',host):
+ h = re.search('^[a-zA-Z\-0-9\.]+', host).group(0)
+ p = re.sub(':', '', re.search(':[0-9]+$', host).group(0))
+ config.set(cbase + [h])
+ config.set(cbase + [h, 'port'], value=p)
+ for fac in config.list_nodes(cbase + [host, 'facility']):
+ config.set(cbase + [h, 'facility', fac])
+ config.set_tag(cbase + [h, 'facility'])
+ if config.exists(cbase + [host, 'facility', fac, 'protocol']):
+ proto = config.return_value(cbase + [host, 'facility', fac, 'protocol'])
+ config.set(cbase + [h, 'facility', fac, 'protocol'], value=proto)
+ if config.exists(cbase + [host, 'facility', fac, 'level']):
+ lvl = config.return_value(cbase + [host, 'facility', fac, 'level'])
+ config.set(cbase + [h, 'facility', fac, 'level'], value=lvl)
+ config.delete(cbase + [host])
diff --git a/src/migration-scripts/system/13-to-14 b/src/migration-scripts/system/13-to-14
index 5b781158b..fbbecbcd3 100755..100644
--- a/src/migration-scripts/system/13-to-14
+++ b/src/migration-scripts/system/13-to-14
@@ -1,4 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Fixup non existent time-zones. Some systems have time-zone set to: Los*
# (Los_Angeles), Den* (Denver), New* (New_York) ... but those are no real IANA
@@ -9,27 +22,18 @@
# Migrate all configured timezones to real IANA assigned timezones!
import re
-import sys
from vyos.configtree import ConfigTree
from vyos.utils.process import cmd
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+tz_base = ['system', 'time-zone']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(tz_base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-tz_base = ['system', 'time-zone']
-if not config.exists(tz_base):
- # Nothing to do
- sys.exit(0)
-else:
tz = config.return_value(tz_base)
# retrieve all valid timezones
@@ -61,10 +65,3 @@ else:
# replace timezone data is required
config.set(tz_base, value=tz)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/14-to-15 b/src/migration-scripts/system/14-to-15
index feaac37de..281809460 100755..100644
--- a/src/migration-scripts/system/14-to-15
+++ b/src/migration-scripts/system/14-to-15
@@ -1,40 +1,37 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
+# 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/>.
+
# Delete 'system ipv6 blacklist' option as the IPv6 module can no longer be
# blacklisted as it is required by e.g. WireGuard and thus will always be
# loaded.
import os
-import sys
ipv6_blacklist_file = '/etc/modprobe.d/vyatta_blacklist_ipv6.conf'
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+ip_base = ['system', 'ipv6']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(ip_base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-ip_base = ['system', 'ipv6']
-if not config.exists(ip_base):
- # Nothing to do
- sys.exit(0)
-else:
# delete 'system ipv6 blacklist' node
if config.exists(ip_base + ['blacklist']):
config.delete(ip_base + ['blacklist'])
if os.path.isfile(ipv6_blacklist_file):
os.unlink(ipv6_blacklist_file)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/15-to-16 b/src/migration-scripts/system/15-to-16
index 2944cdb1e..7db042930 100755..100644
--- a/src/migration-scripts/system/15-to-16
+++ b/src/migration-scripts/system/15-to-16
@@ -1,36 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Make 'system options reboot-on-panic' valueless
+# 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/>.
-import sys
+# Make 'system options reboot-on-panic' valueless
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base = ['system', 'options']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['system', 'options']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
if config.exists(base + ['reboot-on-panic']):
reboot = config.return_value(base + ['reboot-on-panic'])
config.delete(base + ['reboot-on-panic'])
# create new valueless node if action was true
if reboot == "true":
config.set(base + ['reboot-on-panic'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/16-to-17 b/src/migration-scripts/system/16-to-17
index afa171a9b..9fb86af88 100755..100644
--- a/src/migration-scripts/system/16-to-17
+++ b/src/migration-scripts/system/16-to-17
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# * remove "system login user <user> group" node, Why should be add a user to a
# 3rd party group when the system is fully managed by CLI?
@@ -20,35 +19,18 @@
# This is the only privilege level left and also the default, what is the
# sense in keeping this orphaned node?
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base = ['system', 'login', 'user']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['system', 'login', 'user']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
for user in config.list_nodes(base):
if config.exists(base + [user, 'group']):
config.delete(base + [user, 'group'])
if config.exists(base + [user, 'level']):
config.delete(base + [user, 'level'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/17-to-18 b/src/migration-scripts/system/17-to-18
index f6adebb06..323ef4e65 100755..100644
--- a/src/migration-scripts/system/17-to-18
+++ b/src/migration-scripts/system/17-to-18
@@ -1,42 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# remove "system console netconsole"
# remove "system console device <device> modem"
import os
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base = ['system', 'console']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['system', 'console']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
# remove "system console netconsole" (T2561)
if config.exists(base + ['netconsole']):
config.delete(base + ['netconsole'])
@@ -67,10 +57,3 @@ else:
config.copy(dev_path, base + ['device', usb_device])
# Delete old USB node from config
config.delete(dev_path)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/18-to-19 b/src/migration-scripts/system/18-to-19
index fad1d17a4..5d9788d70 100755..100644
--- a/src/migration-scripts/system/18-to-19
+++ b/src/migration-scripts/system/18-to-19
@@ -1,102 +1,81 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# migrate disable-dhcp-nameservers (boolean) to name-servers-dhcp <interface>
# if disable-dhcp-nameservers is set, just remove it
# else retrieve all interface names that have configured dhcp(v6) address and
# add them to the new name-servers-dhcp node
-from sys import argv, exit
from vyos.ifconfig import Interface
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['system']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['disable-dhcp-nameservers']):
- config.delete(base + ['disable-dhcp-nameservers'])
-else:
- dhcp_interfaces = []
-
- # go through all interfaces searching for 'address dhcp(v6)?'
- for sect in Interface.sections():
- sect_base = ['interfaces', sect]
-
- if not config.exists(sect_base):
- continue
- for intf in config.list_nodes(sect_base):
- intf_base = sect_base + [intf]
-
- # try without vlans
- if config.exists(intf_base + ['address']):
- for addr in config.return_values(intf_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(intf)
-
- # try vif
- if config.exists(intf_base + ['vif']):
- for vif in config.list_nodes(intf_base + ['vif']):
- vif_base = intf_base + ['vif', vif]
- if config.exists(vif_base + ['address']):
- for addr in config.return_values(vif_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif}')
-
- # try vif-s
- if config.exists(intf_base + ['vif-s']):
- for vif_s in config.list_nodes(intf_base + ['vif-s']):
- vif_s_base = intf_base + ['vif-s', vif_s]
- if config.exists(vif_s_base + ['address']):
- for addr in config.return_values(vif_s_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif_s}')
-
- # try vif-c
- if config.exists(intf_base + ['vif-c']):
- for vif_c in config.list_nodes(vif_s_base + ['vif-c']):
- vif_c_base = vif_s_base + ['vif-c', vif_c]
- if config.exists(vif_c_base + ['address']):
- for addr in config.return_values(vif_c_base + ['address']):
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['disable-dhcp-nameservers']):
+ config.delete(base + ['disable-dhcp-nameservers'])
+ else:
+ dhcp_interfaces = []
+
+ # go through all interfaces searching for 'address dhcp(v6)?'
+ for sect in Interface.sections():
+ sect_base = ['interfaces', sect]
+
+ if not config.exists(sect_base):
+ continue
+
+ for intf in config.list_nodes(sect_base):
+ intf_base = sect_base + [intf]
+
+ # try without vlans
+ if config.exists(intf_base + ['address']):
+ for addr in config.return_values(intf_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(intf)
+
+ # try vif
+ if config.exists(intf_base + ['vif']):
+ for vif in config.list_nodes(intf_base + ['vif']):
+ vif_base = intf_base + ['vif', vif]
+ if config.exists(vif_base + ['address']):
+ for addr in config.return_values(vif_base + ['address']):
if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif_s}.{vif_c}')
-
- # set new config nodes
- for intf in dhcp_interfaces:
- config.set(base + ['name-servers-dhcp'], value=intf, replace=False)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
-exit(0)
+ dhcp_interfaces.append(f'{intf}.{vif}')
+
+ # try vif-s
+ if config.exists(intf_base + ['vif-s']):
+ for vif_s in config.list_nodes(intf_base + ['vif-s']):
+ vif_s_base = intf_base + ['vif-s', vif_s]
+ if config.exists(vif_s_base + ['address']):
+ for addr in config.return_values(vif_s_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(f'{intf}.{vif_s}')
+
+ # try vif-c
+ if config.exists(intf_base + ['vif-c']):
+ for vif_c in config.list_nodes(vif_s_base + ['vif-c']):
+ vif_c_base = vif_s_base + ['vif-c', vif_c]
+ if config.exists(vif_c_base + ['address']):
+ for addr in config.return_values(vif_c_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(f'{intf}.{vif_s}.{vif_c}')
+
+ # set new config nodes
+ for intf in dhcp_interfaces:
+ config.set(base + ['name-servers-dhcp'], value=intf, replace=False)
diff --git a/src/migration-scripts/system/19-to-20 b/src/migration-scripts/system/19-to-20
index 177173c50..cb84e11fc 100755..100644
--- a/src/migration-scripts/system/19-to-20
+++ b/src/migration-scripts/system/19-to-20
@@ -1,62 +1,44 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3048: remove smp-affinity node from ethernet and use tuned instead
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'options']
base_new = ['system', 'option']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base_new):
- for node in config.list_nodes(base):
- config.copy(base + [node], base_new + [node])
-else:
- config.copy(base, base_new)
-config.delete(base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-# Rename "system option beep-if-fully-booted" -> "system option startup-beep"
-base_beep = base_new + ['beep-if-fully-booted']
-if config.exists(base_beep):
- config.rename(base_beep, 'startup-beep')
+ if config.exists(base_new):
+ for node in config.list_nodes(base):
+ config.copy(base + [node], base_new + [node])
+ else:
+ config.copy(base, base_new)
-# Rename "system option ctrl-alt-del-action" -> "system option ctrl-alt-delete"
-base_ctrl_alt_del = base_new + ['ctrl-alt-del-action']
-if config.exists(base_ctrl_alt_del):
- config.rename(base_ctrl_alt_del, 'ctrl-alt-delete')
+ config.delete(base)
+ # Rename "system option beep-if-fully-booted" -> "system option startup-beep"
+ base_beep = base_new + ['beep-if-fully-booted']
+ if config.exists(base_beep):
+ config.rename(base_beep, 'startup-beep')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Rename "system option ctrl-alt-del-action" -> "system option ctrl-alt-delete"
+ base_ctrl_alt_del = base_new + ['ctrl-alt-del-action']
+ if config.exists(base_ctrl_alt_del):
+ config.rename(base_ctrl_alt_del, 'ctrl-alt-delete')
diff --git a/src/migration-scripts/system/20-to-21 b/src/migration-scripts/system/20-to-21
index 24e042ce2..71c283da6 100755..100644
--- a/src/migration-scripts/system/20-to-21
+++ b/src/migration-scripts/system/20-to-21
@@ -1,46 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3795: merge "system name-servers-dhcp" into "system name-server"
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'name-servers-dhcp']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-for interface in config.return_values(base):
- config.set(['system', 'name-server'], value=interface, replace=False)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config.delete(base)
+ for interface in config.return_values(base):
+ config.set(['system', 'name-server'], value=interface, replace=False)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.delete(base)
diff --git a/src/migration-scripts/system/21-to-22 b/src/migration-scripts/system/21-to-22
index 2a1b603c6..0e68a6856 100755..100644
--- a/src/migration-scripts/system/21-to-22
+++ b/src/migration-scripts/system/21-to-22
@@ -1,55 +1,38 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'sysctl']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for all_custom in ['all', 'custom']:
- if config.exists(base + [all_custom]):
- for key in config.list_nodes(base + [all_custom]):
- tmp = config.return_value(base + [all_custom, key, 'value'])
- config.set(base + ['parameter', key, 'value'], value=tmp)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for all_custom in ['all', 'custom']:
+ if config.exists(base + [all_custom]):
+ for key in config.list_nodes(base + [all_custom]):
+ tmp = config.return_value(base + [all_custom, key, 'value'])
+ config.set(base + ['parameter', key, 'value'], value=tmp)
+ config.set_tag(base + ['parameter'])
+ config.delete(base + [all_custom])
+
+ for ipv4_param in ['net.ipv4.igmp_max_memberships', 'net.ipv4.ipfrag_time']:
+ if config.exists(base + [ipv4_param]):
+ tmp = config.return_value(base + [ipv4_param])
+ config.set(base + ['parameter', ipv4_param, 'value'], value=tmp)
config.set_tag(base + ['parameter'])
- config.delete(base + [all_custom])
-
-for ipv4_param in ['net.ipv4.igmp_max_memberships', 'net.ipv4.ipfrag_time']:
- if config.exists(base + [ipv4_param]):
- tmp = config.return_value(base + [ipv4_param])
- config.set(base + ['parameter', ipv4_param, 'value'], value=tmp)
- config.set_tag(base + ['parameter'])
- config.delete(base + [ipv4_param])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.delete(base + [ipv4_param])
diff --git a/src/migration-scripts/system/22-to-23 b/src/migration-scripts/system/22-to-23
index f83279b88..e49094e4a 100755..100644
--- a/src/migration-scripts/system/22-to-23
+++ b/src/migration-scripts/system/22-to-23
@@ -1,48 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'ipv6']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-# T4346: drop support to disbale IPv6 address family within the OS Kernel
-if config.exists(base + ['disable']):
- config.delete(base + ['disable'])
- # IPv6 address family disable was the only CLI option set - we can cleanup
- # the entire tree
- if len(config.list_nodes(base)) == 0:
- config.delete(base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # T4346: drop support to disbale IPv6 address family within the OS Kernel
+ if config.exists(base + ['disable']):
+ config.delete(base + ['disable'])
+ # IPv6 address family disable was the only CLI option set - we can cleanup
+ # the entire tree
+ if len(config.list_nodes(base)) == 0:
+ config.delete(base)
diff --git a/src/migration-scripts/system/23-to-24 b/src/migration-scripts/system/23-to-24
index 1fd61d83b..feb62bc32 100755..100644
--- a/src/migration-scripts/system/23-to-24
+++ b/src/migration-scripts/system/23-to-24
@@ -1,38 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 ipaddress import ip_interface
from ipaddress import ip_address
-from sys import exit, argv
+
from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'static', 'arp']
tmp_base = ['protocols', 'static', 'arp-tmp']
-config = ConfigTree(config_file)
-def fixup_cli(config, path, interface):
+def fixup_cli(config, path, interface, host):
if config.exists(path + ['address']):
for address in config.return_values(path + ['address']):
tmp = ip_interface(address)
@@ -47,41 +37,35 @@ def fixup_cli(config, path, interface):
config.set_tag(iface_path + [interface, 'address'])
continue
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# We need a temporary copy of the config tree as the original one needs to be
-# deleted first due to a change iun thge tagNode structure.
-config.copy(base, tmp_base)
-config.delete(base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-for host in config.list_nodes(tmp_base):
- for type in config.list_nodes(['interfaces']):
- for interface in config.list_nodes(['interfaces', type]):
- if_base = ['interfaces', type, interface]
- fixup_cli(config, if_base, interface)
+ # We need a temporary copy of the config tree as the original one needs to be
+ # deleted first due to a change iun thge tagNode structure.
+ config.copy(base, tmp_base)
+ config.delete(base)
- if config.exists(if_base + ['vif']):
- for vif in config.list_nodes(if_base + ['vif']):
- vif_base = ['interfaces', type, interface, 'vif', vif]
- fixup_cli(config, vif_base, f'{interface}.{vif}')
+ for host in config.list_nodes(tmp_base):
+ for type in config.list_nodes(['interfaces']):
+ for interface in config.list_nodes(['interfaces', type]):
+ if_base = ['interfaces', type, interface]
+ fixup_cli(config, if_base, interface, host)
- if config.exists(if_base + ['vif-s']):
- for vif_s in config.list_nodes(if_base + ['vif-s']):
- vif_s_base = ['interfaces', type, interface, 'vif-s', vif_s]
- fixup_cli(config, vif_s_base, f'{interface}.{vif_s}')
+ if config.exists(if_base + ['vif']):
+ for vif in config.list_nodes(if_base + ['vif']):
+ vif_base = ['interfaces', type, interface, 'vif', vif]
+ fixup_cli(config, vif_base, f'{interface}.{vif}', host)
- if config.exists(if_base + ['vif-s', vif_s, 'vif-c']):
- for vif_c in config.list_nodes(if_base + ['vif-s', vif_s, 'vif-c']):
- vif_c_base = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c', vif_c]
- fixup_cli(config, vif_c_base, f'{interface}.{vif_s}.{vif_c}')
+ if config.exists(if_base + ['vif-s']):
+ for vif_s in config.list_nodes(if_base + ['vif-s']):
+ vif_s_base = ['interfaces', type, interface, 'vif-s', vif_s]
+ fixup_cli(config, vif_s_base, f'{interface}.{vif_s}', host)
-config.delete(tmp_base)
+ if config.exists(if_base + ['vif-s', vif_s, 'vif-c']):
+ for vif_c in config.list_nodes(if_base + ['vif-s', vif_s, 'vif-c']):
+ vif_c_base = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c', vif_c]
+ fixup_cli(config, vif_c_base, f'{interface}.{vif_s}.{vif_c}', host)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ config.delete(tmp_base)
diff --git a/src/migration-scripts/system/24-to-25 b/src/migration-scripts/system/24-to-25
index 1c81a76e7..bdb89902e 100755..100644
--- a/src/migration-scripts/system/24-to-25
+++ b/src/migration-scripts/system/24-to-25
@@ -1,52 +1,35 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# Migrate system syslog global archive to system logs logrotate messages
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'syslog', 'global', 'archive']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-if config.exists(base + ['file']):
- tmp = config.return_value(base + ['file'])
- config.set(['system', 'logs', 'logrotate', 'messages', 'rotate'], value=tmp)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-if config.exists(base + ['size']):
- tmp = config.return_value(base + ['size'])
- tmp = max(round(int(tmp) / 1024), 1) # kb -> mb
- config.set(['system', 'logs', 'logrotate', 'messages', 'max-size'], value=tmp)
+ if config.exists(base + ['file']):
+ tmp = config.return_value(base + ['file'])
+ config.set(['system', 'logs', 'logrotate', 'messages', 'rotate'], value=tmp)
-config.delete(base)
+ if config.exists(base + ['size']):
+ tmp = config.return_value(base + ['size'])
+ tmp = max(round(int(tmp) / 1024), 1) # kb -> mb
+ config.set(['system', 'logs', 'logrotate', 'messages', 'max-size'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ config.delete(base)
diff --git a/src/migration-scripts/system/25-to-26 b/src/migration-scripts/system/25-to-26
index 7bdf3be98..8832f48e5 100755..100644
--- a/src/migration-scripts/system/25-to-26
+++ b/src/migration-scripts/system/25-to-26
@@ -1,39 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# syslog: migrate deprecated CLI options
# - protocols -> local7
# - security -> auth
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'syslog']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
def rename_facilities(config, base_tree, facility, facility_new) -> None:
if config.exists(base + [base_tree, 'facility', facility]):
@@ -44,39 +30,36 @@ def rename_facilities(config, base_tree, facility, facility_new) -> None:
# delete old duplicate facility config
config.delete(base + [base_tree, 'facility', facility])
-#
-# Rename protocols and securityy facility to common ones
-#
-replace = {
- 'protocols' : 'local7',
- 'security' : 'auth'
-}
-for facility, facility_new in replace.items():
- rename_facilities(config, 'console', facility, facility_new)
- rename_facilities(config, 'global', facility, facility_new)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
- if config.exists(base + ['host']):
- for host in config.list_nodes(base + ['host']):
- rename_facilities(config, f'host {host}', facility, facility_new)
+ #
+ # Rename protocols and securityy facility to common ones
+ #
+ replace = {
+ 'protocols' : 'local7',
+ 'security' : 'auth'
+ }
+ for facility, facility_new in replace.items():
+ rename_facilities(config, 'console', facility, facility_new)
+ rename_facilities(config, 'global', facility, facility_new)
-#
-# It makes no sense to configure udp/tcp transport per individual facility
-#
-if config.exists(base + ['host']):
- for host in config.list_nodes(base + ['host']):
- protocol = None
- for facility in config.list_nodes(base + ['host', host, 'facility']):
- tmp_path = base + ['host', host, 'facility', facility, 'protocol']
- if config.exists(tmp_path):
- # We can only change the first one
- if protocol == None:
- protocol = config.return_value(tmp_path)
- config.set(base + ['host', host, 'protocol'], value=protocol)
- config.delete(tmp_path)
+ if config.exists(base + ['host']):
+ for host in config.list_nodes(base + ['host']):
+ rename_facilities(config, f'host {host}', facility, facility_new)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ #
+ # It makes no sense to configure udp/tcp transport per individual facility
+ #
+ if config.exists(base + ['host']):
+ for host in config.list_nodes(base + ['host']):
+ protocol = None
+ for facility in config.list_nodes(base + ['host', host, 'facility']):
+ tmp_path = base + ['host', host, 'facility', facility, 'protocol']
+ if config.exists(tmp_path):
+ # We can only change the first one
+ if protocol == None:
+ protocol = config.return_value(tmp_path)
+ config.set(base + ['host', host, 'protocol'], value=protocol)
+ config.delete(tmp_path)
diff --git a/src/migration-scripts/system/26-to-27 b/src/migration-scripts/system/26-to-27
index 80bb82cbd..499e16e08 100755..100644
--- a/src/migration-scripts/system/26-to-27
+++ b/src/migration-scripts/system/26-to-27
@@ -1,47 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# T5877: migrate 'system domain-search domain' to 'system domain-search'
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'domain-search']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-if config.exists(base + ['domain']):
- entries = config.return_values(base + ['domain'])
- config.delete(base + ['domain'])
- for entry in entries:
- config.set(base, value=entry, replace=False)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(base + ['domain']):
+ entries = config.return_values(base + ['domain'])
+ config.delete(base + ['domain'])
+ for entry in entries:
+ config.set(base, value=entry, replace=False)
diff --git a/src/migration-scripts/system/6-to-7 b/src/migration-scripts/system/6-to-7
index d24521134..e91ccc4e9 100755..100644
--- a/src/migration-scripts/system/6-to-7
+++ b/src/migration-scripts/system/6-to-7
@@ -1,48 +1,36 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Change smp_affinity to smp-affinity
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-update_required = False
-
-intf_types = config.list_nodes(["interfaces"])
-
-for intf_type in intf_types:
- intf_type_path = ["interfaces", intf_type]
- intfs = config.list_nodes(intf_type_path)
-
- for intf in intfs:
- intf_path = intf_type_path + [intf]
- if not config.exists(intf_path + ["smp_affinity"]):
- # Nothing to do.
- continue
- else:
- # Rename the node.
- old_smp_affinity_path = intf_path + ["smp_affinity"]
- config.rename(old_smp_affinity_path, "smp-affinity")
- update_required = True
-
-if update_required:
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("failed to save the modified config: {}".format(e))
- sys.exit(1)
-
-
-
+def migrate(config: ConfigTree) -> None:
+ intf_types = config.list_nodes(["interfaces"])
+
+ for intf_type in intf_types:
+ intf_type_path = ["interfaces", intf_type]
+ intfs = config.list_nodes(intf_type_path)
+
+ for intf in intfs:
+ intf_path = intf_type_path + [intf]
+ if not config.exists(intf_path + ["smp_affinity"]):
+ # Nothing to do.
+ continue
+ else:
+ # Rename the node.
+ old_smp_affinity_path = intf_path + ["smp_affinity"]
+ config.rename(old_smp_affinity_path, "smp-affinity")
+ update_required = True
diff --git a/src/migration-scripts/system/7-to-8 b/src/migration-scripts/system/7-to-8
index 5d084d2bf..64dd4dc93 100755..100644
--- a/src/migration-scripts/system/7-to-8
+++ b/src/migration-scripts/system/7-to-8
@@ -1,26 +1,27 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Converts "system gateway-address" option to "protocols static route 0.0.0.0/0 next-hop $gw"
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['system', 'gateway-address']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['system', 'gateway-address']):
- # Nothing to do
- sys.exit(0)
-else:
# Save the address
gw = config.return_value(['system', 'gateway-address'])
@@ -36,10 +37,3 @@ else:
# They must be formatted as such to load correctly.
config.set_tag(['protocols', 'static', 'route'])
config.set_tag(['protocols', 'static', 'route', '0.0.0.0/0', 'next-hop'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/8-to-9 b/src/migration-scripts/system/8-to-9
index e3bb2bca8..ea5f7af81 100755..100644
--- a/src/migration-scripts/system/8-to-9
+++ b/src/migration-scripts/system/8-to-9
@@ -1,32 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# Deletes "system package" option as it is deprecated
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['system', 'package']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['system', 'package']):
- # Nothing to do
- sys.exit(0)
-else:
# Delete the node with the old syntax
config.delete(['system', 'package'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/vrf/0-to-1 b/src/migration-scripts/vrf/0-to-1
index 8187138d9..70abae2a8 100755..100644
--- a/src/migration-scripts/vrf/0-to-1
+++ b/src/migration-scripts/vrf/0-to-1
@@ -1,132 +1,113 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T2450: drop interface-route and interface-route6 from "protocols vrf"
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'vrf']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for vrf in config.list_nodes(base):
- static_base = base + [vrf, 'static']
- if not config.exists(static_base):
- continue
-
- #
- # Migrate interface-route into route
- #
- interface_route_path = static_base + ['interface-route']
- if config.exists(interface_route_path):
- for route in config.list_nodes(interface_route_path):
- interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface'])
-
- tmp = interface_route_path + [route, 'next-hop-interface']
- for interface in config.list_nodes(tmp):
- new_base = static_base + ['route', route, 'interface']
- config.set(new_base)
- config.set_tag(new_base)
- config.copy(tmp + [interface], new_base + [interface])
-
- config.delete(interface_route_path)
-
- #
- # Migrate interface-route6 into route6
- #
- interface_route_path = static_base + ['interface-route6']
- if config.exists(interface_route_path):
- for route in config.list_nodes(interface_route_path):
- interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface'])
-
- tmp = interface_route_path + [route, 'next-hop-interface']
- for interface in config.list_nodes(tmp):
- new_base = static_base + ['route6', route, 'interface']
- config.set(new_base)
- config.set_tag(new_base)
- config.copy(tmp + [interface], new_base + [interface])
-
- config.delete(interface_route_path)
-
- #
- # Cleanup nodes inside route
- #
- route_path = static_base + ['route']
- if config.exists(route_path):
- for route in config.list_nodes(route_path):
- next_hop = route_path + [route, 'next-hop']
- if config.exists(next_hop):
- for gateway in config.list_nodes(next_hop):
- interface_path = next_hop + [gateway, 'next-hop-interface']
- if config.exists(interface_path):
- config.rename(interface_path, 'interface')
- vrf_path = next_hop + [gateway, 'next-hop-vrf']
- if config.exists(vrf_path):
- config.rename(vrf_path, 'vrf')
-
- next_hop = route_path + [route, 'interface']
- if config.exists(next_hop):
- for interface in config.list_nodes(next_hop):
- interface_path = next_hop + [interface, 'next-hop-interface']
- if config.exists(interface_path):
- config.rename(interface_path, 'interface')
- vrf_path = next_hop + [interface, 'next-hop-vrf']
- if config.exists(vrf_path):
- config.rename(vrf_path, 'vrf')
-
- #
- # Cleanup nodes inside route6
- #
- route_path = static_base + ['route6']
- if config.exists(route_path):
- for route in config.list_nodes(route_path):
- next_hop = route_path + [route, 'next-hop']
- if config.exists(next_hop):
- for gateway in config.list_nodes(next_hop):
- vrf_path = next_hop + [gateway, 'next-hop-vrf']
- if config.exists(vrf_path):
- config.rename(vrf_path, 'vrf')
-
- next_hop = route_path + [route, 'interface']
- if config.exists(next_hop):
- for interface in config.list_nodes(next_hop):
- interface_path = next_hop + [interface, 'next-hop-interface']
- if config.exists(interface_path):
- config.rename(interface_path, 'interface')
- vrf_path = next_hop + [interface, 'next-hop-vrf']
- if config.exists(vrf_path):
- config.rename(vrf_path, 'vrf')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for vrf in config.list_nodes(base):
+ static_base = base + [vrf, 'static']
+ if not config.exists(static_base):
+ continue
+
+ #
+ # Migrate interface-route into route
+ #
+ interface_route_path = static_base + ['interface-route']
+ if config.exists(interface_route_path):
+ for route in config.list_nodes(interface_route_path):
+ interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface'])
+
+ tmp = interface_route_path + [route, 'next-hop-interface']
+ for interface in config.list_nodes(tmp):
+ new_base = static_base + ['route', route, 'interface']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.copy(tmp + [interface], new_base + [interface])
+
+ config.delete(interface_route_path)
+
+ #
+ # Migrate interface-route6 into route6
+ #
+ interface_route_path = static_base + ['interface-route6']
+ if config.exists(interface_route_path):
+ for route in config.list_nodes(interface_route_path):
+ interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface'])
+
+ tmp = interface_route_path + [route, 'next-hop-interface']
+ for interface in config.list_nodes(tmp):
+ new_base = static_base + ['route6', route, 'interface']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.copy(tmp + [interface], new_base + [interface])
+
+ config.delete(interface_route_path)
+
+ #
+ # Cleanup nodes inside route
+ #
+ route_path = static_base + ['route']
+ if config.exists(route_path):
+ for route in config.list_nodes(route_path):
+ next_hop = route_path + [route, 'next-hop']
+ if config.exists(next_hop):
+ for gateway in config.list_nodes(next_hop):
+ interface_path = next_hop + [gateway, 'next-hop-interface']
+ if config.exists(interface_path):
+ config.rename(interface_path, 'interface')
+ vrf_path = next_hop + [gateway, 'next-hop-vrf']
+ if config.exists(vrf_path):
+ config.rename(vrf_path, 'vrf')
+
+ next_hop = route_path + [route, 'interface']
+ if config.exists(next_hop):
+ for interface in config.list_nodes(next_hop):
+ interface_path = next_hop + [interface, 'next-hop-interface']
+ if config.exists(interface_path):
+ config.rename(interface_path, 'interface')
+ vrf_path = next_hop + [interface, 'next-hop-vrf']
+ if config.exists(vrf_path):
+ config.rename(vrf_path, 'vrf')
+
+ #
+ # Cleanup nodes inside route6
+ #
+ route_path = static_base + ['route6']
+ if config.exists(route_path):
+ for route in config.list_nodes(route_path):
+ next_hop = route_path + [route, 'next-hop']
+ if config.exists(next_hop):
+ for gateway in config.list_nodes(next_hop):
+ vrf_path = next_hop + [gateway, 'next-hop-vrf']
+ if config.exists(vrf_path):
+ config.rename(vrf_path, 'vrf')
+
+ next_hop = route_path + [route, 'interface']
+ if config.exists(next_hop):
+ for interface in config.list_nodes(next_hop):
+ interface_path = next_hop + [interface, 'next-hop-interface']
+ if config.exists(interface_path):
+ config.rename(interface_path, 'interface')
+ vrf_path = next_hop + [interface, 'next-hop-vrf']
+ if config.exists(vrf_path):
+ config.rename(vrf_path, 'vrf')
diff --git a/src/migration-scripts/vrf/1-to-2 b/src/migration-scripts/vrf/1-to-2
index 52d4c2c7b..557a9ec58 100755..100644
--- a/src/migration-scripts/vrf/1-to-2
+++ b/src/migration-scripts/vrf/1-to-2
@@ -1,62 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T3344: migrate routing options from "protocols vrf" to "vrf <name> protocols"
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['protocols', 'vrf']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ vrf_base = ['vrf', 'name']
+ config.set(vrf_base)
+ config.set_tag(vrf_base)
-base = ['protocols', 'vrf']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-vrf_base = ['vrf', 'name']
-config.set(vrf_base)
-config.set_tag(vrf_base)
-
-# Copy all existing static routes to the new base node under "vrf name <name> protocols static"
-for vrf in config.list_nodes(base):
- static_base = base + [vrf, 'static']
- if not config.exists(static_base):
- continue
-
- new_static_base = vrf_base + [vrf, 'protocols']
- config.set(new_static_base)
- config.copy(static_base, new_static_base + ['static'])
- config.set_tag(new_static_base + ['static', 'route'])
-
-# Now delete the old configuration
-config.delete(base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Copy all existing static routes to the new base node under "vrf name <name> protocols static"
+ for vrf in config.list_nodes(base):
+ static_base = base + [vrf, 'static']
+ if not config.exists(static_base):
+ continue
+
+ new_static_base = vrf_base + [vrf, 'protocols']
+ config.set(new_static_base)
+ config.copy(static_base, new_static_base + ['static'])
+ config.set_tag(new_static_base + ['static', 'route'])
+
+ # Now delete the old configuration
+ config.delete(base)
diff --git a/src/migration-scripts/vrf/2-to-3 b/src/migration-scripts/vrf/2-to-3
index d45b185ee..acacffb41 100755..100644
--- a/src/migration-scripts/vrf/2-to-3
+++ b/src/migration-scripts/vrf/2-to-3
@@ -1,26 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Since connection tracking zones are int16, VRFs tables maximum value must
# be limited to 65535
# Also, interface names in nftables cannot start from numbers,
# so VRF name should not start from a number
-from sys import argv
-from sys import exit
from random import randrange
from random import choice
from string import ascii_lowercase
@@ -69,76 +66,60 @@ def _search_tables(config_commands, table_num):
return table_items
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vrf', 'name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# Get a list of all currently used VRFs and tables
-vrfs_current = {}
-for vrf in config.list_nodes(base):
- vrfs_current[vrf] = int(config.return_value(base + [vrf, 'table']))
-
-# Check VRF names and table numbers
-name_regex = re.compile(r'^\d.*$')
-for vrf_name, vrf_table in vrfs_current.items():
- # Check table number
- if vrf_table > 65535:
- # Find new unused table number
- vrfs_current[vrf_name] = None
- while not vrfs_current[vrf_name]:
- table_random = randrange(100, 65535)
- if table_random not in vrfs_current.values():
- vrfs_current[vrf_name] = table_random
- # Update number to a new one
- config.set(['vrf', 'name', vrf_name, 'table'],
- vrfs_current[vrf_name],
- replace=True)
- # Check config items with old table number and replace to new one
- config_commands = config.to_commands().split('\n')
- table_config_lines = _search_tables(config_commands, vrf_table)
- # Rename table nodes
- if table_config_lines.get('table_tags'):
- for table_config_path in table_config_lines.get('table_tags'):
- config.rename(table_config_path, f'{vrfs_current[vrf_name]}')
- # Replace table values
- if table_config_lines.get('table_values'):
- for table_config_path in table_config_lines.get('table_values'):
- config.set(table_config_path,
- f'{vrfs_current[vrf_name]}',
- replace=True)
-
- # Check VRF name
- if name_regex.match(vrf_name):
- vrf_name_new = None
- while not vrf_name_new:
- vrf_name_rand = f'{choice(ascii_lowercase)}{vrf_name}'[:15]
- if vrf_name_rand not in vrfs_current:
- vrf_name_new = vrf_name_rand
- # Update VRF name to a new one
- config.rename(['vrf', 'name', vrf_name], vrf_name_new)
- # Check config items with old VRF name and replace to new one
- config_commands = config.to_commands().split('\n')
- vrf_config_lines = _search_vrfs(config_commands, vrf_name)
- # Rename VRF to a new name
- if vrf_config_lines:
- for vrf_value_path in vrf_config_lines:
- config.set(vrf_value_path, vrf_name_new, replace=True)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Get a list of all currently used VRFs and tables
+ vrfs_current = {}
+ for vrf in config.list_nodes(base):
+ vrfs_current[vrf] = int(config.return_value(base + [vrf, 'table']))
+
+ # Check VRF names and table numbers
+ name_regex = re.compile(r'^\d.*$')
+ for vrf_name, vrf_table in vrfs_current.items():
+ # Check table number
+ if vrf_table > 65535:
+ # Find new unused table number
+ vrfs_current[vrf_name] = None
+ while not vrfs_current[vrf_name]:
+ table_random = randrange(100, 65535)
+ if table_random not in vrfs_current.values():
+ vrfs_current[vrf_name] = table_random
+ # Update number to a new one
+ config.set(['vrf', 'name', vrf_name, 'table'],
+ vrfs_current[vrf_name],
+ replace=True)
+ # Check config items with old table number and replace to new one
+ config_commands = config.to_commands().split('\n')
+ table_config_lines = _search_tables(config_commands, vrf_table)
+ # Rename table nodes
+ if table_config_lines.get('table_tags'):
+ for table_config_path in table_config_lines.get('table_tags'):
+ config.rename(table_config_path, f'{vrfs_current[vrf_name]}')
+ # Replace table values
+ if table_config_lines.get('table_values'):
+ for table_config_path in table_config_lines.get('table_values'):
+ config.set(table_config_path,
+ f'{vrfs_current[vrf_name]}',
+ replace=True)
+
+ # Check VRF name
+ if name_regex.match(vrf_name):
+ vrf_name_new = None
+ while not vrf_name_new:
+ vrf_name_rand = f'{choice(ascii_lowercase)}{vrf_name}'[:15]
+ if vrf_name_rand not in vrfs_current:
+ vrf_name_new = vrf_name_rand
+ # Update VRF name to a new one
+ config.rename(['vrf', 'name', vrf_name], vrf_name_new)
+ # Check config items with old VRF name and replace to new one
+ config_commands = config.to_commands().split('\n')
+ vrf_config_lines = _search_vrfs(config_commands, vrf_name)
+ # Rename VRF to a new name
+ if vrf_config_lines:
+ for vrf_value_path in vrf_config_lines:
+ config.set(vrf_value_path, vrf_name_new, replace=True)
diff --git a/src/migration-scripts/vrrp/1-to-2 b/src/migration-scripts/vrrp/1-to-2
index dba5af81c..8639a7553 100755..100644
--- a/src/migration-scripts/vrrp/1-to-2
+++ b/src/migration-scripts/vrrp/1-to-2
@@ -1,37 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2018 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
import re
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
# Convert the old VRRP syntax to the new syntax
# The old approach was to put VRRP groups inside interfaces,
@@ -109,162 +95,156 @@ def get_vrrp_group(path):
# Only if no data is collected from any interface we can conclude that VRRP is not configured
# and exit.
-groups = []
-base_paths = []
-
-if config.exists(["interfaces", "ethernet"]):
- base_paths.append("ethernet")
-if config.exists(["interfaces", "bonding"]):
- base_paths.append("bonding")
-
-for bp in base_paths:
- parent_path = ["interfaces", bp]
-
- parent_intfs = config.list_nodes(parent_path)
-
- for pi in parent_intfs:
- # Extract VRRP groups from the parent interface
- vg_path =[pi, "vrrp", "vrrp-group"]
- if config.exists(parent_path + vg_path):
- pgroups = config.list_nodes(parent_path + vg_path)
- for pg in pgroups:
- g = get_vrrp_group(parent_path + vg_path + [pg])
- g["interface"] = pi
- g["vrid"] = pg
- groups.append(g)
-
- # Delete the VRRP subtree
- # If left in place, configs will not load correctly
- config.delete(parent_path + [pi, "vrrp"])
-
- # Extract VRRP groups from 802.1q VLAN interfaces
- if config.exists(parent_path + [pi, "vif"]):
- vifs = config.list_nodes(parent_path + [pi, "vif"])
- for vif in vifs:
- vif_vg_path = [pi, "vif", vif, "vrrp", "vrrp-group"]
- if config.exists(parent_path + vif_vg_path):
- vifgroups = config.list_nodes(parent_path + vif_vg_path)
- for vif_group in vifgroups:
- g = get_vrrp_group(parent_path + vif_vg_path + [vif_group])
- g["interface"] = "{0}.{1}".format(pi, vif)
- g["vrid"] = vif_group
- groups.append(g)
-
- config.delete(parent_path + [pi, "vif", vif, "vrrp"])
-
- # Extract VRRP groups from 802.3ad QinQ service VLAN interfaces
- if config.exists(parent_path + [pi, "vif-s"]):
- vif_ss = config.list_nodes(parent_path + [pi, "vif-s"])
- for vif_s in vif_ss:
- vifs_vg_path = [pi, "vif-s", vif_s, "vrrp", "vrrp-group"]
- if config.exists(parent_path + vifs_vg_path):
- vifsgroups = config.list_nodes(parent_path + vifs_vg_path)
- for vifs_group in vifsgroups:
- g = get_vrrp_group(parent_path + vifs_vg_path + [vifs_group])
- g["interface"] = "{0}.{1}".format(pi, vif_s)
- g["vrid"] = vifs_group
- groups.append(g)
-
- config.delete(parent_path + [pi, "vif-s", vif_s, "vrrp"])
-
- # Extract VRRP groups from QinQ client VLAN interfaces nested in the vif-s
- if config.exists(parent_path + [pi, "vif-s", vif_s, "vif-c"]):
- vif_cs = config.list_nodes(parent_path + [pi, "vif-s", vif_s, "vif-c"])
- for vif_c in vif_cs:
- vifc_vg_path = [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp", "vrrp-group"]
- vifcgroups = config.list_nodes(parent_path + vifc_vg_path)
- for vifc_group in vifcgroups:
- g = get_vrrp_group(parent_path + vifc_vg_path + [vifc_group])
- g["interface"] = "{0}.{1}.{2}".format(pi, vif_s, vif_c)
- g["vrid"] = vifc_group
- groups.append(g)
-
- config.delete(parent_path + [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp"])
-
-# If nothing was collected before this point, it means the config has no VRRP setup
-if not groups:
- sys.exit(0)
-
-# Otherwise, there is VRRP to convert
-
-# Now convert the collected groups to the new syntax
-base_group_path = ["high-availability", "vrrp", "group"]
-sync_path = ["high-availability", "vrrp", "sync-group"]
-
-for g in groups:
- group_name = "{0}-{1}".format(g["interface"], g["vrid"])
- group_path = base_group_path + [group_name]
-
- config.set(group_path + ["interface"], value=g["interface"])
- config.set(group_path + ["vrid"], value=g["vrid"])
-
- if "advertise_interval" in g:
- config.set(group_path + ["advertise-interval"], value=g["advertise_interval"])
-
- if "priority" in g:
- config.set(group_path + ["priority"], value=g["priority"])
-
- if not g["preempt"]:
- config.set(group_path + ["no-preempt"], value=None)
-
- if "preempt_delay" in g:
- config.set(group_path + ["preempt-delay"], value=g["preempt_delay"])
-
- if g["rfc_compatibility"]:
- config.set(group_path + ["rfc3768-compatibility"], value=None)
-
- if g["disable"]:
- config.set(group_path + ["disable"], value=None)
-
- if "hello_source" in g:
- config.set(group_path + ["hello-source-address"], value=g["hello_source"])
-
- if "peer_address" in g:
- config.set(group_path + ["peer-address"], value=g["peer_address"])
-
- if "auth_password" in g:
- config.set(group_path + ["authentication", "password"], value=g["auth_password"])
- if "auth_type" in g:
- config.set(group_path + ["authentication", "type"], value=g["auth_type"])
-
- if "master_script" in g:
- config.set(group_path + ["transition-script", "master"], value=g["master_script"])
- if "backup_script" in g:
- config.set(group_path + ["transition-script", "backup"], value=g["backup_script"])
- if "fault_script" in g:
- config.set(group_path + ["transition-script", "fault"], value=g["fault_script"])
-
- if "health_check_interval" in g:
- config.set(group_path + ["health-check", "interval"], value=g["health_check_interval"])
- if "health_check_count" in g:
- config.set(group_path + ["health-check", "failure-count"], value=g["health_check_count"])
- if "health_check_script" in g:
- config.set(group_path + ["health-check", "script"], value=g["health_check_script"])
-
- # Not that it should ever be absent...
- if "virtual_addresses" in g:
- # The new CLI disallows addresses without prefix length
- # Pre-rewrite configs didn't support IPv6 VRRP, but handle it anyway
- for va in g["virtual_addresses"]:
- if not re.search(r'/', va):
- if re.search(r':', va):
- va = "{0}/128".format(va)
- else:
- va = "{0}/32".format(va)
- config.set(group_path + ["virtual-address"], value=va, replace=False)
-
- # Sync group
- if "sync_group" in g:
- config.set(sync_path + [g["sync_group"], "member"], value=group_name, replace=False)
-
-# Set the tag flag
-config.set_tag(base_group_path)
-if config.exists(sync_path):
- config.set_tag(sync_path)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ groups = []
+ base_paths = []
+
+ if config.exists(["interfaces", "ethernet"]):
+ base_paths.append("ethernet")
+ if config.exists(["interfaces", "bonding"]):
+ base_paths.append("bonding")
+
+ for bp in base_paths:
+ parent_path = ["interfaces", bp]
+
+ parent_intfs = config.list_nodes(parent_path)
+
+ for pi in parent_intfs:
+ # Extract VRRP groups from the parent interface
+ vg_path =[pi, "vrrp", "vrrp-group"]
+ if config.exists(parent_path + vg_path):
+ pgroups = config.list_nodes(parent_path + vg_path)
+ for pg in pgroups:
+ g = get_vrrp_group(parent_path + vg_path + [pg])
+ g["interface"] = pi
+ g["vrid"] = pg
+ groups.append(g)
+
+ # Delete the VRRP subtree
+ # If left in place, configs will not load correctly
+ config.delete(parent_path + [pi, "vrrp"])
+
+ # Extract VRRP groups from 802.1q VLAN interfaces
+ if config.exists(parent_path + [pi, "vif"]):
+ vifs = config.list_nodes(parent_path + [pi, "vif"])
+ for vif in vifs:
+ vif_vg_path = [pi, "vif", vif, "vrrp", "vrrp-group"]
+ if config.exists(parent_path + vif_vg_path):
+ vifgroups = config.list_nodes(parent_path + vif_vg_path)
+ for vif_group in vifgroups:
+ g = get_vrrp_group(parent_path + vif_vg_path + [vif_group])
+ g["interface"] = "{0}.{1}".format(pi, vif)
+ g["vrid"] = vif_group
+ groups.append(g)
+
+ config.delete(parent_path + [pi, "vif", vif, "vrrp"])
+
+ # Extract VRRP groups from 802.3ad QinQ service VLAN interfaces
+ if config.exists(parent_path + [pi, "vif-s"]):
+ vif_ss = config.list_nodes(parent_path + [pi, "vif-s"])
+ for vif_s in vif_ss:
+ vifs_vg_path = [pi, "vif-s", vif_s, "vrrp", "vrrp-group"]
+ if config.exists(parent_path + vifs_vg_path):
+ vifsgroups = config.list_nodes(parent_path + vifs_vg_path)
+ for vifs_group in vifsgroups:
+ g = get_vrrp_group(parent_path + vifs_vg_path + [vifs_group])
+ g["interface"] = "{0}.{1}".format(pi, vif_s)
+ g["vrid"] = vifs_group
+ groups.append(g)
+
+ config.delete(parent_path + [pi, "vif-s", vif_s, "vrrp"])
+
+ # Extract VRRP groups from QinQ client VLAN interfaces nested in the vif-s
+ if config.exists(parent_path + [pi, "vif-s", vif_s, "vif-c"]):
+ vif_cs = config.list_nodes(parent_path + [pi, "vif-s", vif_s, "vif-c"])
+ for vif_c in vif_cs:
+ vifc_vg_path = [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp", "vrrp-group"]
+ vifcgroups = config.list_nodes(parent_path + vifc_vg_path)
+ for vifc_group in vifcgroups:
+ g = get_vrrp_group(parent_path + vifc_vg_path + [vifc_group])
+ g["interface"] = "{0}.{1}.{2}".format(pi, vif_s, vif_c)
+ g["vrid"] = vifc_group
+ groups.append(g)
+
+ config.delete(parent_path + [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp"])
+
+ # If nothing was collected before this point, it means the config has no VRRP setup
+ if not groups:
+ return
+
+ # Otherwise, there is VRRP to convert
+
+ # Now convert the collected groups to the new syntax
+ base_group_path = ["high-availability", "vrrp", "group"]
+ sync_path = ["high-availability", "vrrp", "sync-group"]
+
+ for g in groups:
+ group_name = "{0}-{1}".format(g["interface"], g["vrid"])
+ group_path = base_group_path + [group_name]
+
+ config.set(group_path + ["interface"], value=g["interface"])
+ config.set(group_path + ["vrid"], value=g["vrid"])
+
+ if "advertise_interval" in g:
+ config.set(group_path + ["advertise-interval"], value=g["advertise_interval"])
+
+ if "priority" in g:
+ config.set(group_path + ["priority"], value=g["priority"])
+
+ if not g["preempt"]:
+ config.set(group_path + ["no-preempt"], value=None)
+
+ if "preempt_delay" in g:
+ config.set(group_path + ["preempt-delay"], value=g["preempt_delay"])
+
+ if g["rfc_compatibility"]:
+ config.set(group_path + ["rfc3768-compatibility"], value=None)
+
+ if g["disable"]:
+ config.set(group_path + ["disable"], value=None)
+
+ if "hello_source" in g:
+ config.set(group_path + ["hello-source-address"], value=g["hello_source"])
+
+ if "peer_address" in g:
+ config.set(group_path + ["peer-address"], value=g["peer_address"])
+
+ if "auth_password" in g:
+ config.set(group_path + ["authentication", "password"], value=g["auth_password"])
+ if "auth_type" in g:
+ config.set(group_path + ["authentication", "type"], value=g["auth_type"])
+
+ if "master_script" in g:
+ config.set(group_path + ["transition-script", "master"], value=g["master_script"])
+ if "backup_script" in g:
+ config.set(group_path + ["transition-script", "backup"], value=g["backup_script"])
+ if "fault_script" in g:
+ config.set(group_path + ["transition-script", "fault"], value=g["fault_script"])
+
+ if "health_check_interval" in g:
+ config.set(group_path + ["health-check", "interval"], value=g["health_check_interval"])
+ if "health_check_count" in g:
+ config.set(group_path + ["health-check", "failure-count"], value=g["health_check_count"])
+ if "health_check_script" in g:
+ config.set(group_path + ["health-check", "script"], value=g["health_check_script"])
+
+ # Not that it should ever be absent...
+ if "virtual_addresses" in g:
+ # The new CLI disallows addresses without prefix length
+ # Pre-rewrite configs didn't support IPv6 VRRP, but handle it anyway
+ for va in g["virtual_addresses"]:
+ if not re.search(r'/', va):
+ if re.search(r':', va):
+ va = "{0}/128".format(va)
+ else:
+ va = "{0}/32".format(va)
+ config.set(group_path + ["virtual-address"], value=va, replace=False)
+
+ # Sync group
+ if "sync_group" in g:
+ config.set(sync_path + [g["sync_group"], "member"], value=group_name, replace=False)
+
+ # Set the tag flag
+ config.set_tag(base_group_path)
+ if config.exists(sync_path):
+ config.set_tag(sync_path)
diff --git a/src/migration-scripts/vrrp/2-to-3 b/src/migration-scripts/vrrp/2-to-3
index ed583b489..468918f91 100755..100644
--- a/src/migration-scripts/vrrp/2-to-3
+++ b/src/migration-scripts/vrrp/2-to-3
@@ -1,62 +1,44 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3847: vrrp config cleanup
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print('Must specify file name!')
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['high-availability', 'vrrp']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['group']):
- for group in config.list_nodes(base + ['group']):
- group_base = base + ['group', group]
-
- # Deprecated option
- tmp = group_base + ['transition-script', 'mode-force']
- if config.exists(tmp):
- config.delete(tmp)
-
- # Rename virtual-address -> address
- tmp = group_base + ['virtual-address']
- if config.exists(tmp):
- config.rename(tmp, 'address')
-
- # Rename virtual-address-excluded -> excluded-address
- tmp = group_base + ['virtual-address-excluded']
- if config.exists(tmp):
- config.rename(tmp, 'excluded-address')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['group']):
+ for group in config.list_nodes(base + ['group']):
+ group_base = base + ['group', group]
+
+ # Deprecated option
+ tmp = group_base + ['transition-script', 'mode-force']
+ if config.exists(tmp):
+ config.delete(tmp)
+
+ # Rename virtual-address -> address
+ tmp = group_base + ['virtual-address']
+ if config.exists(tmp):
+ config.rename(tmp, 'address')
+
+ # Rename virtual-address-excluded -> excluded-address
+ tmp = group_base + ['virtual-address-excluded']
+ if config.exists(tmp):
+ config.rename(tmp, 'excluded-address')
diff --git a/src/migration-scripts/vrrp/3-to-4 b/src/migration-scripts/vrrp/3-to-4
index e5d93578c..9f05cf7a1 100755..100644
--- a/src/migration-scripts/vrrp/3-to-4
+++ b/src/migration-scripts/vrrp/3-to-4
@@ -1,51 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print('Must specify file name!')
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['high-availability', 'virtual-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base):
- for vs in config.list_nodes(base):
- vs_base = base + [vs]
- # If the fwmark is used, the address is not required
- if not config.exists(vs_base + ['fwmark']):
- # add option: 'virtual-server <tag> address x.x.x.x'
- config.set(vs_base + ['address'], value=vs)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+ if config.exists(base):
+ for vs in config.list_nodes(base):
+ vs_base = base + [vs]
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # If the fwmark is used, the address is not required
+ if not config.exists(vs_base + ['fwmark']):
+ # add option: 'virtual-server <tag> address x.x.x.x'
+ config.set(vs_base + ['address'], value=vs)
diff --git a/src/migration-scripts/webproxy/1-to-2 b/src/migration-scripts/webproxy/1-to-2
index 03f357878..5a4847474 100755..100644
--- a/src/migration-scripts/webproxy/1-to-2
+++ b/src/migration-scripts/webproxy/1-to-2
@@ -1,39 +1,33 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# 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/>.
# migrate old style `webproxy proxy-bypass 1.2.3.4/24`
# to new style `webproxy whitelist destination-address 1.2.3.4/24`
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+cfg_webproxy_base = ['service', 'webproxy']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_webproxy_base + ['proxy-bypass']):
+ # Nothing to do
+ return
-cfg_webproxy_base = ['service', 'webproxy']
-if not config.exists(cfg_webproxy_base + ['proxy-bypass']):
- # Nothing to do
- sys.exit(0)
-else:
bypass_addresses = config.return_values(cfg_webproxy_base + ['proxy-bypass'])
# delete old configuration node
config.delete(cfg_webproxy_base + ['proxy-bypass'])
for bypass_address in bypass_addresses:
# add data to new configuration node
config.set(cfg_webproxy_base + ['whitelist', 'destination-address'], value=bypass_address, replace=False)
-
- # save updated configuration
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py
index 15fbb65a2..c197ca434 100755
--- a/src/op_mode/firewall.py
+++ b/src/op_mode/firewall.py
@@ -63,10 +63,10 @@ def get_nftables_details(family, hook, priority):
aux=''
if hook == 'name' or hook == 'ipv6-name':
- command = f'sudo nft list chain {suffix} vyos_filter {name_prefix}{priority}'
+ command = f'nft list chain {suffix} vyos_filter {name_prefix}{priority}'
else:
up_hook = hook.upper()
- command = f'sudo nft list chain {suffix} vyos_filter VYOS_{aux}{up_hook}_{priority}'
+ command = f'nft list chain {suffix} vyos_filter VYOS_{aux}{up_hook}_{priority}'
try:
results = cmd(command)
@@ -90,12 +90,42 @@ def get_nftables_details(family, hook, priority):
out[rule_id] = rule
return out
+def get_nftables_state_details(family):
+ if family == 'ipv6':
+ suffix = 'ip6'
+ name_suffix = 'POLICY6'
+ elif family == 'ipv4':
+ suffix = 'ip'
+ name_suffix = 'POLICY'
+ else:
+ # no state policy for bridge
+ return {}
+
+ command = f'nft list chain {suffix} vyos_filter VYOS_STATE_{name_suffix}'
+ try:
+ results = cmd(command)
+ except:
+ return {}
+
+ out = {}
+ for line in results.split('\n'):
+ rule = {}
+ for state in ['established', 'related', 'invalid']:
+ if state in line:
+ counter_search = re.search(r'counter packets (\d+) bytes (\d+)', line)
+ if counter_search:
+ rule['packets'] = counter_search[1]
+ rule['bytes'] = counter_search[2]
+ rule['conditions'] = re.sub(r'(\b(counter packets \d+ bytes \d+|drop|reject|return|log)\b|comment "[\w\-]+")', '', line).strip()
+ out[state] = rule
+ return out
+
def get_nftables_group_members(family, table, name):
prefix = 'ip6' if family == 'ipv6' else 'ip'
out = []
try:
- results_str = cmd(f'sudo nft -j list set {prefix} {table} {name}')
+ results_str = cmd(f'nft -j list set {prefix} {table} {name}')
results = json.loads(results_str)
except:
return out
@@ -172,6 +202,34 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N
rows[rows.index(i)].pop(1)
print(tabulate.tabulate(rows, header) + '\n')
+def output_firewall_state_policy(family):
+ if family == 'bridge':
+ return {}
+ print(f'\n---------------------------------\n{family} State Policy\n')
+
+ details = get_nftables_state_details(family)
+ rows = []
+
+ for state, state_conf in details.items():
+ row = [state, state_conf['conditions']]
+ row.append(state_conf.get('packets', 0))
+ row.append(state_conf.get('bytes', 0))
+ row.append(state_conf.get('conditions'))
+ rows.append(row)
+
+ if rows:
+ if args.rule:
+ rows.pop()
+
+ if args.detail:
+ header = ['State', 'Conditions', 'Packets', 'Bytes']
+ output_firewall_vertical(rows, header)
+ else:
+ header = ['State', 'Packets', 'Bytes', 'Conditions']
+ for i in rows:
+ rows[rows.index(i)].pop(1)
+ print(tabulate.tabulate(rows, header) + '\n')
+
def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule_id=None):
print(f'\n---------------------------------\n{family} Firewall "{hook} {prior}"\n')
@@ -305,6 +363,10 @@ def show_firewall():
return
for family in ['ipv4', 'ipv6', 'bridge']:
+ if 'global_options' in firewall:
+ if 'state_policy' in firewall['global_options']:
+ output_firewall_state_policy(family)
+
if family in firewall:
for hook, hook_conf in firewall[family].items():
for prior, prior_conf in firewall[family][hook].items():
@@ -316,12 +378,17 @@ def show_firewall_family(family):
conf = Config()
firewall = get_config_node(conf)
- if not firewall or family not in firewall:
+ if not firewall:
return
- for hook, hook_conf in firewall[family].items():
- for prior, prior_conf in firewall[family][hook].items():
- output_firewall_name(family, hook, prior, prior_conf)
+ if 'global_options' in firewall:
+ if 'state_policy' in firewall['global_options']:
+ output_firewall_state_policy(family)
+
+ if family in firewall:
+ for hook, hook_conf in firewall[family].items():
+ for prior, prior_conf in firewall[family][hook].items():
+ output_firewall_name(family, hook, prior, prior_conf)
def show_firewall_name(family, hook, priority):
print('Ruleset Information')
@@ -622,6 +689,10 @@ def show_statistics():
return
for family in ['ipv4', 'ipv6', 'bridge']:
+ if 'global_options' in firewall:
+ if 'state_policy' in firewall['global_options']:
+ output_firewall_state_policy(family)
+
if family in firewall:
for hook, hook_conf in firewall[family].items():
for prior, prior_conf in firewall[family][hook].items():
diff --git a/src/op_mode/generate_firewall_rule-resequence.py b/src/op_mode/generate_service_rule-resequence.py
index 21441f689..9333d6353 100755
--- a/src/op_mode/generate_firewall_rule-resequence.py
+++ b/src/op_mode/generate_service_rule-resequence.py
@@ -77,7 +77,7 @@ def change_rule_numbers(config_dict, start, step):
change_rule_numbers(config_dict[key], start, step)
-def convert_rule_keys_to_int(config_dict):
+def convert_rule_keys_to_int(config_dict, prev_key=None):
"""
Converts rule keys in the configuration dictionary to integers.
@@ -91,11 +91,11 @@ def convert_rule_keys_to_int(config_dict):
new_dict = {}
for key, value in config_dict.items():
# Convert key to integer if possible
- new_key = int(key) if key.isdigit() else key
+ new_key = int(key) if key.isdigit() and prev_key == 'rule' else key
# Recur for nested dictionaries
if isinstance(value, dict):
- new_value = convert_rule_keys_to_int(value)
+ new_value = convert_rule_keys_to_int(value, key)
else:
new_value = value
@@ -111,27 +111,24 @@ def convert_rule_keys_to_int(config_dict):
if __name__ == "__main__":
# Parse command-line arguments
parser = argparse.ArgumentParser(description='Convert dictionary to set commands with rule number modifications.')
- parser.add_argument('--start', type=int, default=100, help='Start rule number')
+ parser.add_argument('--service', type=str, help='Name of service')
+ parser.add_argument('--start', type=int, default=100, help='Start rule number (default: 100)')
parser.add_argument('--step', type=int, default=10, help='Step for rule numbers (default: 10)')
args = parser.parse_args()
config = ConfigTreeQuery()
- if not config.exists('firewall'):
- print('Firewall is not configured')
+ if not config.exists(args.service):
+ print(f'{args.service} is not configured')
exit(1)
- config_dict = config.get_config_dict('firewall')
+ config_dict = config.get_config_dict(args.service)
- # Remove global-options, group and flowtable as they don't need sequencing
- if 'global-options' in config_dict['firewall']:
- del config_dict['firewall']['global-options']
+ if 'firewall' in config_dict:
+ # Remove global-options, group and flowtable as they don't need sequencing
+ for item in ['global-options', 'group', 'flowtable']:
+ if item in config_dict['firewall']:
+ del config_dict['firewall'][item]
- if 'group' in config_dict['firewall']:
- del config_dict['firewall']['group']
-
- if 'flowtable' in config_dict['firewall']:
- del config_dict['firewall']['flowtable']
-
# Convert rule keys to integers, rule "10" -> rule 10
# This is necessary for sorting the rules
config_dict = convert_rule_keys_to_int(config_dict)
diff --git a/src/op_mode/show_techsupport_report.py b/src/op_mode/show_techsupport_report.py
index 230fb252d..32cf67778 100644
--- a/src/op_mode/show_techsupport_report.py
+++ b/src/op_mode/show_techsupport_report.py
@@ -14,10 +14,12 @@
# 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 sys
from typing import List
-from vyos.utils.process import rc_cmd
from vyos.ifconfig import Section
from vyos.ifconfig import Interface
+from vyos.utils.process import rc_cmd
def print_header(command: str) -> None:
@@ -50,7 +52,15 @@ def execute_command(command: str, header_text: str) -> None:
print_header(header_text)
try:
rc, output = rc_cmd(command)
- print(output)
+ # Enable unbuffered print param to improve responsiveness of printed
+ # output to end user
+ print(output, flush=True)
+ # Exit gracefully when user interrupts program output
+ # Flush standard streams; redirect remaining output to devnull
+ # Resolves T5633: Bug #1 and 3
+ except (BrokenPipeError, KeyboardInterrupt):
+ os.dup2(os.open(os.devnull, os.O_WRONLY), sys.stdout.fileno())
+ sys.exit(1)
except Exception as e:
print(f"Error executing command: {command}")
print(f"Error message: {e}")
@@ -155,13 +165,13 @@ def show_route() -> None:
"show ip route supernets-only",
"show ip route table all",
"show ip route vrf all",
- "show ipv6 route bgp | head 108",
+ "show ipv6 route bgp | head -108",
"show ipv6 route cache",
"show ipv6 route connected",
"show ipv6 route forward",
"show ipv6 route isis",
"show ipv6 route kernel",
- "show ipv6 route ospf",
+ "show ipv6 route ospfv3",
"show ipv6 route rip",
"show ipv6 route static",
"show ipv6 route summary",
@@ -179,8 +189,9 @@ def show_firewall() -> None:
def show_system() -> None:
"""Prints system parameters."""
- execute_command(op('show system image version'), 'Show System Image Version')
- execute_command(op('show system image storage'), 'Show System Image Storage')
+ execute_command(op('show version'), 'Show System Version')
+ execute_command(op('show system storage'), 'Show System Storage')
+ execute_command(op('show system image details'), 'Show System Image Details')
def show_date() -> None:
diff --git a/src/tests/helper.py b/src/tests/helper.py
index f7033148a..cc0710494 100644
--- a/src/tests/helper.py
+++ b/src/tests/helper.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2018 VyOS maintainers and contributors
+# Copyright (C) 2018-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
diff --git a/src/tests/test_config_diff.py b/src/tests/test_config_diff.py
index 61a2f3487..39e17613a 100644
--- a/src/tests/test_config_diff.py
+++ b/src/tests/test_config_diff.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-#
# Copyright (C) 2023-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
diff --git a/src/tests/test_config_parser.py b/src/tests/test_config_parser.py
index c69732daa..9a4f02859 100644
--- a/src/tests/test_config_parser.py
+++ b/src/tests/test_config_parser.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-#
# Copyright (C) 2018-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
diff --git a/smoketest/scripts/cli/test_configd_inspect.py b/src/tests/test_configd_inspect.py
index af46c6148..98552c8f3 100755..100644
--- a/smoketest/scripts/cli/test_configd_inspect.py
+++ b/src/tests/test_configd_inspect.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-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,16 +15,16 @@
import os
import re
import json
-import unittest
+
import warnings
import importlib.util
-from inspect import signature, getsource
+from inspect import signature
+from inspect import getsource
from functools import wraps
+from unittest import TestCase
-from vyos.defaults import directories
-
-INC_FILE = '/usr/share/vyos/configd-include.json'
-CONF_DIR = directories['conf_mode']
+INC_FILE = 'data/configd-include.json'
+CONF_DIR = 'src/conf_mode'
f_list = ['get_config', 'verify', 'generate', 'apply']
@@ -47,7 +45,7 @@ def ignore_deprecation_warning(f):
f(*args, **kwargs)
return decorated_function
-class TestConfigdInclude(unittest.TestCase):
+class TestConfigdInspect(TestCase):
def setUp(self):
with open(INC_FILE) as f:
self.inc_list = json.load(f)
@@ -105,6 +103,3 @@ class TestConfigdInclude(unittest.TestCase):
str_m = getsource(m)
n = str_m.count('my_set')
self.assertEqual(n, 0, f"'{s}' modifies config")
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/tests/test_configverify.py b/src/tests/test_configverify.py
index 15ccdf13d..f1ec65cd2 100644
--- a/src/tests/test_configverify.py
+++ b/src/tests/test_configverify.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-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
diff --git a/src/tests/test_dependency_graph.py b/src/tests/test_dependency_graph.py
index f682e87bb..f3f1db376 100644
--- a/src/tests/test_dependency_graph.py
+++ b/src/tests/test_dependency_graph.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-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
diff --git a/src/tests/test_dict_search.py b/src/tests/test_dict_search.py
index 2435d89c7..6b4bc933a 100644
--- a/src/tests/test_dict_search.py
+++ b/src/tests/test_dict_search.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-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
diff --git a/src/tests/test_find_device_file.py b/src/tests/test_find_device_file.py
index f18043d65..5b90f2034 100755..100644
--- a/src/tests/test_find_device_file.py
+++ b/src/tests/test_find_device_file.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-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
@@ -28,8 +26,5 @@ class TestDeviceFile(TestCase):
def test_zero(self):
self.assertEqual(find_device_file('zero'), '/dev/zero')
- def test_input_event(self):
- self.assertEqual(find_device_file('event0'), '/dev/input/event0')
-
def test_non_existing(self):
self.assertFalse(find_device_file('vyos'))
diff --git a/src/tests/test_initial_setup.py b/src/tests/test_initial_setup.py
index f85bf1265..4cd5fb169 100644
--- a/src/tests/test_initial_setup.py
+++ b/src/tests/test_initial_setup.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-#
# Copyright (C) 2018-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
diff --git a/src/tests/test_op_mode.py b/src/tests/test_op_mode.py
index 90963b3c5..23f709653 100644
--- a/src/tests/test_op_mode.py
+++ b/src/tests/test_op_mode.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-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
@@ -62,4 +60,3 @@ class TestVyOSOpMode(TestCase):
data = [1, False, "foo"]
self.assertEqual(_normalize_field_names(data), [1, False, "foo"])
-
diff --git a/src/tests/test_task_scheduler.py b/src/tests/test_task_scheduler.py
index 130f825e6..795ffeb9d 100644
--- a/src/tests/test_task_scheduler.py
+++ b/src/tests/test_task_scheduler.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright (C) 2018-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
diff --git a/src/tests/test_template.py b/src/tests/test_template.py
index dbb86b40b..6377f6da5 100644
--- a/src/tests/test_template.py
+++ b/src/tests/test_template.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-#
# Copyright (C) 2020-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
diff --git a/src/tests/test_utils.py b/src/tests/test_utils.py
index 9ae329ced..7bfd2618e 100644
--- a/src/tests/test_utils.py
+++ b/src/tests/test_utils.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-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
diff --git a/src/tests/test_utils_network.py b/src/tests/test_utils_network.py
index 5a6dc2586..d68dec16f 100644
--- a/src/tests/test_utils_network.py
+++ b/src/tests/test_utils_network.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-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
@@ -45,6 +43,3 @@ class TestVyOSUtilsNetwork(TestCase):
self.assertFalse(vyos.utils.network.is_loopback_addr('::2'))
self.assertFalse(vyos.utils.network.is_loopback_addr('192.0.2.1'))
-
-
-