summaryrefslogtreecommitdiff
path: root/smoketest
diff options
context:
space:
mode:
Diffstat (limited to 'smoketest')
-rw-r--r--smoketest/configs/azure-bgp-gateway435
-rw-r--r--smoketest/configs/bgp-bfd-communities533
-rw-r--r--smoketest/configs/bgp-big-as-cloud1956
-rw-r--r--smoketest/configs/bgp-evpn-leaf148
-rw-r--r--smoketest/configs/bgp-evpn-spine128
-rw-r--r--smoketest/configs/bgp-rpki (renamed from smoketest/configs/pppoe-client)70
-rw-r--r--smoketest/configs/bgp-small-as687
-rw-r--r--smoketest/configs/bgp-small-internet-exchange488
-rw-r--r--smoketest/configs/dialup-router-complex1662
-rw-r--r--smoketest/configs/dialup-router-medium-vpn707
-rw-r--r--smoketest/configs/isis-small105
-rw-r--r--smoketest/configs/ospf-small142
-rw-r--r--smoketest/configs/rip-router267
-rw-r--r--smoketest/configs/tunnel-broker142
-rw-r--r--smoketest/configs/vrf-basic231
-rw-r--r--smoketest/configs/vrf-bgp166
-rw-r--r--smoketest/configs/vrf-ospf145
-rw-r--r--smoketest/scripts/cli/base_accel_ppp_test.py30
-rw-r--r--smoketest/scripts/cli/base_interfaces_test.py390
-rw-r--r--smoketest/scripts/cli/base_vyostest_shim.py90
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bonding.py52
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bridge.py148
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_dummy.py14
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_ethernet.py106
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_geneve.py62
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_l2tpv3.py24
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_loopback.py35
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_macsec.py108
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_openvpn.py364
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_pppoe.py71
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_pseudo_ethernet.py28
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_tunnel.py447
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_vxlan.py78
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_wireguard.py54
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_wireless.py71
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_wirelessmodem.py31
-rwxr-xr-xsmoketest/scripts/cli/test_nat.py76
-rwxr-xr-xsmoketest/scripts/cli/test_nat66.py186
-rwxr-xr-xsmoketest/scripts/cli/test_policy.py702
-rwxr-xr-xsmoketest/scripts/cli/test_policy_local-route.py61
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bfd.py170
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py495
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_igmp-proxy.py41
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_isis.py102
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospf.py321
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospfv3.py154
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rip.py131
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ripng.py126
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rpki.py154
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static.py396
-rwxr-xr-xsmoketest/scripts/cli/test_service_bcast-relay.py37
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcp-relay.py35
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcp-server.py156
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcpv6-relay.py31
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcpv6-server.py82
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_dynamic.py88
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_forwarding.py62
-rwxr-xr-xsmoketest/scripts/cli/test_service_https.py23
-rwxr-xr-xsmoketest/scripts/cli/test_service_mdns-repeater.py27
-rwxr-xr-xsmoketest/scripts/cli/test_service_pppoe-server.py17
-rwxr-xr-xsmoketest/scripts/cli/test_service_router-advert.py27
-rwxr-xr-xsmoketest/scripts/cli/test_service_snmp.py76
-rwxr-xr-xsmoketest/scripts/cli/test_service_ssh.py68
-rwxr-xr-xsmoketest/scripts/cli/test_service_tftp-server.py33
-rwxr-xr-xsmoketest/scripts/cli/test_service_webproxy.py97
-rwxr-xr-xsmoketest/scripts/cli/test_system_acceleration_qat.py27
-rwxr-xr-xsmoketest/scripts/cli/test_system_ip.py28
-rwxr-xr-xsmoketest/scripts/cli/test_system_ipv6.py98
-rwxr-xr-xsmoketest/scripts/cli/test_system_lcd.py19
-rwxr-xr-xsmoketest/scripts/cli/test_system_login.py99
-rwxr-xr-xsmoketest/scripts/cli/test_system_nameserver.py30
-rwxr-xr-xsmoketest/scripts/cli/test_system_ntp.py39
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_openconnect.py32
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_sstp.py6
-rwxr-xr-xsmoketest/scripts/cli/test_vrf.py146
-rwxr-xr-xsmoketest/scripts/system/test_iproute2.py31
76 files changed, 13021 insertions, 1723 deletions
diff --git a/smoketest/configs/azure-bgp-gateway b/smoketest/configs/azure-bgp-gateway
new file mode 100644
index 000000000..b3f5e9edc
--- /dev/null
+++ b/smoketest/configs/azure-bgp-gateway
@@ -0,0 +1,435 @@
+firewall {
+ all-ping enable
+ broadcast-ping disable
+ config-trap disable
+ ipv6-receive-redirects disable
+ ipv6-src-route disable
+ ip-src-route disable
+ log-martians disable
+ options {
+ interface vti31 {
+ adjust-mss 1350
+ }
+ interface vti32 {
+ adjust-mss 1350
+ }
+ interface vti41 {
+ adjust-mss 1350
+ }
+ interface vti42 {
+ adjust-mss 1350
+ }
+ interface vti51 {
+ adjust-mss 1350
+ }
+ interface vti52 {
+ adjust-mss 1350
+ }
+ }
+ receive-redirects disable
+ send-redirects enable
+ source-validation disable
+ syn-cookies enable
+ twa-hazards-protection disable
+}
+high-availability {
+ vrrp {
+ group DMZ-VLAN-3962 {
+ interface eth1
+ preempt-delay 180
+ priority 200
+ virtual-address 192.168.34.36/27
+ vrid 62
+ }
+ }
+}
+interfaces {
+ ethernet eth0 {
+ address 192.0.2.189/27
+ duplex auto
+ smp-affinity auto
+ speed auto
+ }
+ ethernet eth1 {
+ address 192.168.34.37/27
+ duplex auto
+ smp-affinity auto
+ speed auto
+ }
+ loopback lo {
+ }
+ vti vti31 {
+ }
+ vti vti32 {
+ }
+ vti vti41 {
+ }
+ vti vti42 {
+ }
+ vti vti51 {
+ }
+ vti vti52 {
+ }
+}
+policy {
+ prefix-list AZURE-BGP-IPv4-in {
+ description "Prefixes received from Azure"
+ rule 100 {
+ action permit
+ le 32
+ prefix 100.64.0.0/10
+ }
+ }
+ prefix-list ONPREM-BGP-IPv4-out {
+ description "Prefixes allowed to be announced into Azure"
+ rule 100 {
+ action permit
+ prefix 10.0.0.0/8
+ }
+ rule 200 {
+ action permit
+ prefix 172.16.0.0/12
+ }
+ rule 300 {
+ action permit
+ prefix 192.168.0.0/16
+ }
+ }
+}
+protocols {
+ bgp 65522 {
+ address-family {
+ ipv4-unicast {
+ network 10.0.0.0/8 {
+ }
+ network 172.16.0.0/12 {
+ }
+ network 192.168.0.0/16 {
+ }
+ }
+ }
+ neighbor 100.66.8.36 {
+ peer-group AZURE
+ remote-as 64517
+ }
+ neighbor 100.66.8.37 {
+ peer-group AZURE
+ remote-as 64517
+ }
+ neighbor 100.66.24.36 {
+ peer-group AZURE
+ remote-as 64513
+ }
+ neighbor 100.66.24.37 {
+ peer-group AZURE
+ remote-as 64513
+ }
+ neighbor 100.66.40.36 {
+ peer-group AZURE
+ remote-as 64515
+ }
+ neighbor 100.66.40.37 {
+ peer-group AZURE
+ remote-as 64515
+ }
+ neighbor 192.168.34.38 {
+ address-family {
+ ipv4-unicast {
+ nexthop-self
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ password VyOSR0xx123
+ remote-as 65522
+ update-source eth1
+ }
+ peer-group AZURE {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 50
+ prefix-list {
+ export ONPREM-BGP-IPv4-out
+ import AZURE-BGP-IPv4-in
+ }
+ }
+ }
+ ebgp-multihop 2
+ update-source eth1
+ }
+ timers {
+ holdtime 30
+ keepalive 5
+ }
+ }
+ static {
+ interface-route 100.66.8.36/32 {
+ next-hop-interface vti31 {
+ }
+ next-hop-interface vti32 {
+ }
+ }
+ interface-route 100.66.8.37/32 {
+ next-hop-interface vti31 {
+ }
+ next-hop-interface vti32 {
+ }
+ }
+ interface-route 100.66.24.36/32 {
+ next-hop-interface vti41 {
+ }
+ next-hop-interface vti42 {
+ }
+ }
+ interface-route 100.66.24.37/32 {
+ next-hop-interface vti41 {
+ }
+ next-hop-interface vti42 {
+ }
+ }
+ interface-route 100.66.40.36/32 {
+ next-hop-interface vti51 {
+ }
+ next-hop-interface vti52 {
+ }
+ }
+ interface-route 100.66.40.37/32 {
+ next-hop-interface vti51 {
+ }
+ next-hop-interface vti52 {
+ }
+ }
+ route 0.0.0.0/0 {
+ next-hop 192.168.34.33 {
+ }
+ }
+ route 51.105.0.0/16 {
+ next-hop 192.0.2.161 {
+ }
+ }
+ route 52.143.0.0/16 {
+ next-hop 192.0.2.161 {
+ }
+ }
+ route 195.137.175.0/24 {
+ next-hop 192.0.2.161 {
+ }
+ }
+ route 212.23.159.0/26 {
+ next-hop 192.0.2.161 {
+ }
+ }
+ }
+}
+service {
+ ssh {
+ disable-host-validation
+ port 22
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ domain-name vyos.net
+ flow-accounting {
+ interface eth1
+ interface vti31
+ interface vti32
+ interface vti41
+ interface vti42
+ interface vti51
+ interface vti52
+ netflow {
+ server 10.0.1.1 {
+ port 2055
+ }
+ source-ip 192.168.34.37
+ version 10
+ }
+ syslog-facility daemon
+ }
+ host-name azure-gw-01
+ login {
+ radius-server 192.0.2.253 {
+ port 1812
+ secret secret1234
+ timeout 2
+ }
+ radius-server 192.0.2.254 {
+ port 1812
+ secret secret1234
+ timeout 2
+ }
+ radius-source-address 192.168.34.37
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ name-server 192.0.2.254
+ ntp {
+ server 192.0.2.254 {
+ }
+ }
+ syslog {
+ global {
+ archive {
+ file 10
+ size 20480
+ }
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ host 10.0.9.188 {
+ facility all {
+ level info
+ protocol udp
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+vpn {
+ ipsec {
+ esp-group ESP-AZURE {
+ compression disable
+ lifetime 27000
+ mode tunnel
+ pfs disable
+ proposal 1 {
+ encryption aes256
+ hash sha1
+ }
+ }
+ ike-group IKE-AZURE {
+ close-action none
+ dead-peer-detection {
+ action restart
+ interval 2
+ timeout 15
+ }
+ ikev2-reauth no
+ key-exchange ikev2
+ lifetime 27000
+ proposal 1 {
+ dh-group 2
+ encryption aes256
+ hash sha1
+ }
+ }
+ ipsec-interfaces {
+ interface eth0
+ }
+ logging {
+ log-level 2
+ log-modes ike
+ }
+ site-to-site {
+ peer 51.105.0.2 {
+ authentication {
+ mode pre-shared-secret
+ pre-shared-secret averysecretpsktowardsazure
+ }
+ connection-type respond
+ ike-group IKE-AZURE
+ ikev2-reauth inherit
+ local-address 192.0.2.189
+ vti {
+ bind vti51
+ esp-group ESP-AZURE
+ }
+ }
+ peer 51.105.0.3 {
+ authentication {
+ mode pre-shared-secret
+ pre-shared-secret averysecretpsktowardsazure
+ }
+ connection-type respond
+ ike-group IKE-AZURE
+ ikev2-reauth inherit
+ local-address 192.0.2.189
+ vti {
+ bind vti52
+ esp-group ESP-AZURE
+ }
+ }
+ peer 51.105.0.246 {
+ authentication {
+ mode pre-shared-secret
+ pre-shared-secret averysecretpsktowardsazure
+ }
+ connection-type respond
+ ike-group IKE-AZURE
+ ikev2-reauth inherit
+ local-address 192.0.2.189
+ vti {
+ bind vti32
+ esp-group ESP-AZURE
+ }
+ }
+ peer 51.105.0.247 {
+ authentication {
+ mode pre-shared-secret
+ pre-shared-secret averysecretpsktowardsazure
+ }
+ connection-type respond
+ ike-group IKE-AZURE
+ ikev2-reauth inherit
+ local-address 192.0.2.189
+ vti {
+ bind vti31
+ esp-group ESP-AZURE
+ }
+ }
+ peer 51.105.0.18 {
+ authentication {
+ mode pre-shared-secret
+ pre-shared-secret averysecretpsktowardsazure
+ }
+ connection-type respond
+ ike-group IKE-AZURE
+ ikev2-reauth inherit
+ local-address 192.0.2.189
+ vti {
+ bind vti42
+ esp-group ESP-AZURE
+ }
+ }
+ peer 51.105.0.19 {
+ authentication {
+ mode pre-shared-secret
+ pre-shared-secret averysecretpsktowardsazure
+ }
+ connection-type respond
+ ike-group IKE-AZURE
+ ikev2-reauth inherit
+ local-address 192.0.2.189
+ vti {
+ bind vti41
+ esp-group ESP-AZURE
+ }
+ }
+ }
+ }
+}
+
+
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
+/* Release version: 1.2.5 */
diff --git a/smoketest/configs/bgp-bfd-communities b/smoketest/configs/bgp-bfd-communities
new file mode 100644
index 000000000..3b3056a51
--- /dev/null
+++ b/smoketest/configs/bgp-bfd-communities
@@ -0,0 +1,533 @@
+interfaces {
+ ethernet eth0 {
+ address 192.0.2.100/25
+ address 2001:db8::ffff/64
+ }
+ loopback lo {
+ }
+}
+policy {
+ large-community-list ANYCAST_ALL {
+ rule 10 {
+ action permit
+ description "Allow all anycast from anywhere"
+ regex "4242420696:100:.*"
+ }
+ }
+ large-community-list ANYCAST_INT {
+ rule 10 {
+ action permit
+ description "Allow all anycast from int"
+ regex 4242420696:100:1
+ }
+ }
+ prefix-list BGP-BACKBONE-IN {
+ description "Inbound backbone routes from other sites"
+ rule 10 {
+ action deny
+ description "Block default route"
+ prefix 0.0.0.0/0
+ }
+ rule 20 {
+ action deny
+ description "Block int primary"
+ ge 21
+ prefix 192.168.0.0/20
+ }
+ rule 30 {
+ action deny
+ description "Block loopbacks"
+ ge 25
+ prefix 192.168.253.0/24
+ }
+ rule 40 {
+ action deny
+ description "Block backbone peering"
+ ge 25
+ prefix 192.168.254.0/24
+ }
+ rule 999 {
+ action permit
+ description "Allow everything else"
+ ge 1
+ prefix 0.0.0.0/0
+ }
+ }
+ prefix-list BGP-BACKBONE-OUT {
+ description "Outbound backbone routes to other sites"
+ rule 10 {
+ action permit
+ description "Int primary"
+ ge 23
+ prefix 192.168.0.0/20
+ }
+ }
+ prefix-list GLOBAL {
+ description "Globally redistributed routes"
+ rule 10 {
+ action permit
+ prefix 192.168.100.1/32
+ }
+ rule 20 {
+ action permit
+ prefix 192.168.7.128/25
+ }
+ }
+ prefix-list6 BGP-BACKBONE-IN-V6 {
+ description "Inbound backbone routes from other sites"
+ rule 10 {
+ action deny
+ description "Block default route"
+ prefix ::/0
+ }
+ rule 20 {
+ action deny
+ description "Block int primary"
+ ge 53
+ prefix fd52:d62e:8011::/52
+ }
+ rule 30 {
+ action deny
+ description "Block peering and stuff"
+ ge 53
+ prefix fd52:d62e:8011:f000::/52
+ }
+ rule 999 {
+ action permit
+ description "Allow everything else"
+ ge 1
+ prefix ::/0
+ }
+ }
+ prefix-list6 BGP-BACKBONE-OUT-V6 {
+ description "Outbound backbone routes to other sites"
+ rule 10 {
+ action permit
+ ge 64
+ prefix fd52:d62e:8011::/52
+ }
+ }
+ prefix-list6 GLOBAL-V6 {
+ description "Globally redistributed routes"
+ rule 10 {
+ action permit
+ ge 64
+ prefix fd52:d62e:8011:2::/63
+ }
+ }
+ route-map BGP-REDISTRIBUTE {
+ rule 10 {
+ action permit
+ description "Prepend AS and allow VPN and modem"
+ match {
+ ip {
+ address {
+ prefix-list GLOBAL
+ }
+ }
+ }
+ set {
+ as-path-prepend 4242420666
+ }
+ }
+ rule 20 {
+ action permit
+ description "Allow VPN"
+ match {
+ ipv6 {
+ address {
+ prefix-list GLOBAL-V6
+ }
+ }
+ }
+ }
+ }
+ route-map BGP-BACKBONE-IN {
+ rule 10 {
+ action permit
+ match {
+ ip {
+ address {
+ prefix-list BGP-BACKBONE-IN
+ }
+ }
+ }
+ }
+ rule 20 {
+ action permit
+ match {
+ ipv6 {
+ address {
+ prefix-list BGP-BACKBONE-IN-V6
+ }
+ }
+ }
+ }
+ rule 30 {
+ action permit
+ match {
+ large-community {
+ large-community-list ANYCAST_ALL
+ }
+ }
+ }
+ }
+ route-map BGP-BACKBONE-OUT {
+ rule 10 {
+ action permit
+ match {
+ ip {
+ address {
+ prefix-list BGP-BACKBONE-OUT
+ }
+ }
+ }
+ }
+ rule 20 {
+ action permit
+ match {
+ ipv6 {
+ address {
+ prefix-list BGP-BACKBONE-OUT-V6
+ }
+ }
+ }
+ }
+ rule 30 {
+ action permit
+ match {
+ large-community {
+ large-community-list ANYCAST_INT
+ }
+ }
+ set {
+ as-path-prepend 4242420666
+ }
+ }
+ }
+}
+protocols {
+ bfd {
+ peer 192.168.253.1 {
+ interval {
+ receive 50
+ transmit 50
+ }
+ multihop
+ source {
+ address 192.168.253.3
+ }
+ }
+ peer 192.168.253.2 {
+ interval {
+ receive 50
+ transmit 50
+ }
+ multihop
+ source {
+ address 192.168.253.3
+ }
+ }
+ peer 192.168.253.6 {
+ interval {
+ receive 50
+ transmit 50
+ }
+ multihop
+ source {
+ address 192.168.253.3
+ }
+ }
+ peer 192.168.253.7 {
+ interval {
+ receive 50
+ transmit 50
+ }
+ multihop
+ source {
+ address 192.168.253.3
+ }
+ }
+ peer 192.168.253.12 {
+ interval {
+ receive 100
+ transmit 100
+ }
+ multihop
+ source {
+ address 192.168.253.3
+ }
+ }
+ peer fd52:d62e:8011:fffe:192:168:253:1 {
+ interval {
+ receive 50
+ transmit 50
+ }
+ multihop
+ source {
+ address fd52:d62e:8011:fffe:192:168:253:3
+ }
+ }
+ peer fd52:d62e:8011:fffe:192:168:253:2 {
+ interval {
+ receive 50
+ transmit 50
+ }
+ multihop
+ source {
+ address fd52:d62e:8011:fffe:192:168:253:3
+ }
+ }
+ peer fd52:d62e:8011:fffe:192:168:253:6 {
+ interval {
+ receive 50
+ transmit 50
+ }
+ multihop
+ source {
+ address fd52:d62e:8011:fffe:192:168:253:3
+ }
+ }
+ peer fd52:d62e:8011:fffe:192:168:253:7 {
+ interval {
+ receive 50
+ transmit 50
+ }
+ multihop
+ source {
+ address fd52:d62e:8011:fffe:192:168:253:3
+ }
+ }
+ peer fd52:d62e:8011:fffe:192:168:253:12 {
+ interval {
+ receive 100
+ transmit 100
+ }
+ multihop
+ source {
+ address fd52:d62e:8011:fffe:192:168:253:3
+ }
+ }
+ }
+ bgp 4242420666 {
+ address-family {
+ ipv4-unicast {
+ redistribute {
+ connected {
+ route-map BGP-REDISTRIBUTE
+ }
+ static {
+ route-map BGP-REDISTRIBUTE
+ }
+ }
+ }
+ ipv6-unicast {
+ redistribute {
+ connected {
+ route-map BGP-REDISTRIBUTE
+ }
+ }
+ }
+ }
+ neighbor 192.168.253.1 {
+ peer-group INT
+ }
+ neighbor 192.168.253.2 {
+ peer-group INT
+ }
+ neighbor 192.168.253.6 {
+ peer-group DAL13
+ }
+ neighbor 192.168.253.7 {
+ peer-group DAL13
+ }
+ neighbor 192.168.253.12 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ export BGP-BACKBONE-OUT
+ import BGP-BACKBONE-IN
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ bfd {
+ }
+ ebgp-multihop 2
+ remote-as 4242420669
+ update-source dum0
+ }
+ neighbor fd52:d62e:8011:fffe:192:168:253:1 {
+ address-family {
+ ipv6-unicast {
+ peer-group INTv6
+ }
+ }
+ }
+ neighbor fd52:d62e:8011:fffe:192:168:253:2 {
+ address-family {
+ ipv6-unicast {
+ peer-group INTv6
+ }
+ }
+ }
+ neighbor fd52:d62e:8011:fffe:192:168:253:6 {
+ address-family {
+ ipv6-unicast {
+ peer-group DAL13v6
+ }
+ }
+ }
+ neighbor fd52:d62e:8011:fffe:192:168:253:7 {
+ address-family {
+ ipv6-unicast {
+ peer-group DAL13v6
+ }
+ }
+ }
+ neighbor fd52:d62e:8011:fffe:192:168:253:12 {
+ address-family {
+ ipv6-unicast {
+ route-map {
+ export BGP-BACKBONE-OUT
+ import BGP-BACKBONE-IN
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ bfd {
+ }
+ ebgp-multihop 2
+ remote-as 4242420669
+ update-source dum0
+ }
+ parameters {
+ confederation {
+ identifier 4242420696
+ peers 4242420668
+ peers 4242420669
+ }
+ default {
+ no-ipv4-unicast
+ }
+ distance {
+ global {
+ external 220
+ internal 220
+ local 220
+ }
+ }
+ graceful-restart {
+ }
+ }
+ peer-group DAL13 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ export BGP-BACKBONE-OUT
+ import BGP-BACKBONE-IN
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ bfd
+ ebgp-multihop 2
+ remote-as 4242420668
+ update-source dum0
+ }
+ peer-group DAL13v6 {
+ address-family {
+ ipv6-unicast {
+ route-map {
+ export BGP-BACKBONE-OUT
+ import BGP-BACKBONE-IN
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ bfd
+ ebgp-multihop 2
+ remote-as 4242420668
+ update-source dum0
+ }
+ peer-group INT {
+ address-family {
+ ipv4-unicast {
+ default-originate {
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ bfd
+ remote-as 4242420666
+ update-source dum0
+ }
+ peer-group INTv6 {
+ address-family {
+ ipv6-unicast {
+ default-originate {
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ bfd
+ remote-as 4242420666
+ update-source dum0
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 200
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/
+ plaintext-password ""
+ }
+ level admin
+ }
+ }
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
+/* Release version: 1.2.6-S1 */
diff --git a/smoketest/configs/bgp-big-as-cloud b/smoketest/configs/bgp-big-as-cloud
new file mode 100644
index 000000000..694243d1e
--- /dev/null
+++ b/smoketest/configs/bgp-big-as-cloud
@@ -0,0 +1,1956 @@
+firewall {
+ all-ping enable
+ broadcast-ping disable
+ config-trap disable
+ group {
+ address-group bgp-peers-4 {
+ address 192.0.68.3
+ address 192.0.68.2
+ address 192.0.176.193
+ address 192.0.52.0-192.0.52.255
+ address 192.0.53.0-192.0.53.255
+ address 192.0.16.209
+ address 192.0.192.0-192.0.192.255
+ address 192.0.193.0-192.0.193.255
+ address 192.0.194.0-192.0.194.255
+ address 192.0.195.0-192.0.195.255
+ address 192.0.196.0-192.0.196.255
+ address 192.0.197.0-192.0.197.255
+ address 192.0.198.0-192.0.198.255
+ address 192.0.199.0-192.0.199.255
+ }
+ address-group vrrp-peers-4 {
+ address 192.0.68.3
+ address 192.0.160.3
+ address 192.0.98.3
+ address 192.0.71.131
+ address 192.0.84.67
+ address 192.0.71.195
+ address 192.0.71.115
+ address 192.0.70.195
+ address 192.0.70.179
+ address 192.0.70.163
+ address 192.0.70.147
+ address 192.0.70.131
+ address 192.0.70.19
+ address 192.0.70.3
+ address 192.0.71.99
+ address 192.0.68.67
+ address 192.0.71.67
+ address 192.0.71.3
+ address 192.0.68.35
+ address 192.0.68.131
+ address 192.0.69.2
+ address 192.0.70.35
+ address 192.0.70.67
+ }
+ ipv6-address-group bgp-peers-6 {
+ address 2001:db8:c::3
+ address 2001:db8:1000::2e9
+ address 2001:db8:24::fb
+ address 2001:db8:24::fc
+ address 2001:db8:24::fd
+ address 2001:db8:24::2e
+ address 2001:db8:24::3d
+ address 2001:db8:24::4a
+ address 2001:db8:24::5e
+ address 2001:db8:24::7
+ address 2001:db8:24::11
+ address 2001:db8:24::18
+ address 2001:db8:24::20
+ address 2001:db8:24::22
+ address 2001:db8:24::31
+ address 2001:db8:24::58
+ address 2001:db8:24::64
+ address 2001:db8:24::a5
+ address 2001:db8:24::aa
+ address 2001:db8:24::ab
+ address 2001:db8:24::b0
+ address 2001:db8:24::b3
+ address 2001:db8:24::bd
+ address 2001:db8:24::c
+ address 2001:db8:24::d2
+ address 2001:db8:24::d3
+ address 2001:db8:838::1
+ address 2001:db8::1a27:5051:c09d
+ address 2001:db8::1a27:5051:c19d
+ address 2001:db8::20ad:0:1
+ address 2001:db8::2306:0:1
+ address 2001:db8::2ca:0:1
+ address 2001:db8::2ca:0:2
+ address 2001:db8::2ca:0:3
+ address 2001:db8::2ca:0:4
+ }
+ ipv6-address-group vrrp-peers-6 {
+ address fe80::fe89:15cf
+ }
+ ipv6-network-group AS64512-6 {
+ network 2001::/29
+ }
+ network-group AS64512-4 {
+ network 192.0.68.0/22
+ network 192.0.98.0/24
+ network 192.0.160.0/24
+ network 192.0.84.0/22
+ }
+ }
+ ipv6-name management-to-local-6 {
+ default-action reject
+ enable-default-log
+ }
+ ipv6-name management-to-peers-6 {
+ default-action reject
+ enable-default-log
+ }
+ ipv6-name management-to-servers-6 {
+ default-action reject
+ enable-default-log
+ }
+ ipv6-name peers-to-local-6 {
+ default-action reject
+ enable-default-log
+ rule 500 {
+ action accept
+ protocol icmpv6
+ }
+ rule 501 {
+ action accept
+ protocol vrrp
+ source {
+ group {
+ address-group vrrp-peers-6
+ }
+ }
+ }
+ rule 502 {
+ action accept
+ destination {
+ port bgp
+ }
+ protocol tcp
+ source {
+ group {
+ address-group bgp-peers-6
+ }
+ }
+ }
+ rule 503 {
+ action accept
+ protocol tcp
+ source {
+ group {
+ address-group bgp-peers-6
+ }
+ port bgp
+ }
+ }
+ }
+ ipv6-name peers-to-management-6 {
+ default-action reject
+ enable-default-log
+ }
+ ipv6-name peers-to-servers-6 {
+ default-action reject
+ enable-default-log
+ rule 9990 {
+ action reject
+ source {
+ group {
+ network-group AS64512-6
+ }
+ }
+ }
+ rule 9999 {
+ action accept
+ destination {
+ group {
+ network-group AS64512-6
+ }
+ }
+ }
+ }
+ ipv6-name servers-to-local-6 {
+ default-action reject
+ enable-default-log
+ rule 500 {
+ action accept
+ protocol icmpv6
+ }
+ rule 501 {
+ action accept
+ protocol vrrp
+ source {
+ group {
+ address-group vrrp-peers-6
+ }
+ }
+ }
+ rule 511 {
+ action accept
+ protocol tcp_udp
+ source {
+ port 53
+ }
+ }
+ }
+ ipv6-name servers-to-management-6 {
+ default-action reject
+ enable-default-log
+ }
+ ipv6-name servers-to-peers-6 {
+ default-action reject
+ enable-default-log
+ rule 51 {
+ action accept
+ source {
+ group {
+ network-group AS64512-6
+ }
+ }
+ }
+ }
+ ipv6-receive-redirects disable
+ ipv6-src-route disable
+ ip-src-route disable
+ log-martians enable
+ name management-to-local-4 {
+ default-action reject
+ enable-default-log
+ rule 500 {
+ action accept
+ protocol icmp
+ }
+ rule 501 {
+ action accept
+ destination {
+ port 22
+ }
+ protocol tcp
+ }
+ rule 502 {
+ action accept
+ destination {
+ port snmp
+ }
+ protocol udp
+ }
+ }
+ name management-to-peers-4 {
+ default-action reject
+ enable-default-log
+ }
+ name management-to-servers-4 {
+ default-action reject
+ enable-default-log
+ }
+ name peers-to-local-4 {
+ default-action reject
+ enable-default-log
+ rule 500 {
+ action accept
+ protocol icmp
+ }
+ rule 501 {
+ action accept
+ protocol vrrp
+ source {
+ group {
+ address-group vrrp-peers-4
+ }
+ }
+ }
+ rule 502 {
+ action accept
+ destination {
+ port bgp
+ }
+ protocol tcp
+ source {
+ group {
+ address-group bgp-peers-4
+ }
+ }
+ }
+ rule 503 {
+ action accept
+ protocol tcp
+ source {
+ group {
+ address-group bgp-peers-4
+ }
+ port bgp
+ }
+ }
+ }
+ name peers-to-management-4 {
+ default-action reject
+ enable-default-log
+ }
+ name peers-to-servers-4 {
+ default-action reject
+ enable-default-log
+ rule 9990 {
+ action reject
+ source {
+ group {
+ network-group AS64512-4
+ }
+ }
+ }
+ rule 9999 {
+ action accept
+ destination {
+ group {
+ network-group AS64512-4
+ }
+ }
+ }
+ }
+ name servers-to-local-4 {
+ default-action reject
+ enable-default-log
+ rule 500 {
+ action accept
+ protocol icmp
+ }
+ rule 501 {
+ action accept
+ protocol vrrp
+ source {
+ group {
+ address-group vrrp-peers-4
+ }
+ }
+ }
+ rule 511 {
+ action accept
+ protocol tcp_udp
+ source {
+ port 53
+ }
+ }
+ }
+ name servers-to-management-4 {
+ default-action reject
+ enable-default-log
+ }
+ name servers-to-peers-4 {
+ default-action reject
+ enable-default-log
+ rule 51 {
+ action accept
+ source {
+ group {
+ network-group AS64512-4
+ }
+ }
+ }
+ }
+ receive-redirects disable
+ send-redirects enable
+ source-validation disable
+ syn-cookies enable
+ twa-hazards-protection disable
+}
+high-availability {
+ vrrp {
+ group 11-4 {
+ interface eth0.11
+ priority 200
+ virtual-address 192.0.68.1/27
+ vrid 4
+ }
+ group 11-6 {
+ interface eth0.11
+ priority 200
+ virtual-address 2001:db8:c::1/64
+ vrid 6
+ }
+ group 102-4 {
+ interface eth0.102
+ priority 200
+ virtual-address 192.0.98.1/24
+ vrid 4
+ }
+ group 102-6 {
+ interface eth0.102
+ priority 200
+ virtual-address 2001:db8:0:102::1/64
+ vrid 6
+ }
+ group 105-4 {
+ interface eth0.105
+ priority 200
+ virtual-address 192.0.160.1/24
+ vrid 4
+ }
+ group 105-6 {
+ interface eth0.105
+ priority 200
+ virtual-address 2001:db8:0:105::1/64
+ vrid 6
+ }
+ group 1001-4 {
+ interface eth0.1001
+ priority 200
+ virtual-address 192.0.68.33/27
+ vrid 4
+ }
+ group 1001-6 {
+ interface eth0.1001
+ priority 200
+ virtual-address 2001:db8:0:1001::1/64
+ vrid 6
+ }
+ group 1002-4 {
+ interface eth0.1002
+ priority 200
+ virtual-address 192.0.68.65/26
+ vrid 4
+ }
+ group 1002-6 {
+ interface eth0.1002
+ priority 200
+ virtual-address 2001:db8:0:1002::1/64
+ vrid 6
+ }
+ group 1003-4 {
+ interface eth0.1003
+ priority 200
+ virtual-address 192.0.68.129/25
+ vrid 4
+ }
+ group 1003-6 {
+ interface eth0.1003
+ priority 200
+ virtual-address 2001:db8:0:1003::1/64
+ vrid 6
+ }
+ group 1004-4 {
+ interface eth0.1004
+ priority 200
+ virtual-address 192.0.69.1/24
+ vrid 4
+ }
+ group 1004-6 {
+ interface eth0.1004
+ priority 200
+ virtual-address 2001:db8:0:1004::1/64
+ vrid 6
+ }
+ group 1005-4 {
+ interface eth0.1005
+ priority 200
+ virtual-address 192.0.70.1/28
+ vrid 4
+ }
+ group 1005-6 {
+ interface eth0.1005
+ priority 200
+ virtual-address 2001:db8:0:1005::1/64
+ vrid 6
+ }
+ group 1006-4 {
+ interface eth0.1006
+ priority 200
+ virtual-address 192.0.70.17/28
+ vrid 4
+ }
+ group 1006-6 {
+ interface eth0.1006
+ priority 200
+ virtual-address 2001:db8:0:1006::1/64
+ vrid 6
+ }
+ group 1007-4 {
+ interface eth0.1007
+ priority 200
+ virtual-address 192.0.70.33/27
+ vrid 4
+ }
+ group 1007-6 {
+ interface eth0.1007
+ priority 200
+ virtual-address 2001:db8:0:1007::1/64
+ vrid 6
+ }
+ group 1008-4 {
+ interface eth0.1008
+ priority 200
+ virtual-address 192.0.70.65/26
+ vrid 4
+ }
+ group 1008-6 {
+ interface eth0.1008
+ priority 200
+ virtual-address 2001:db8:0:1008::1/64
+ vrid 6
+ }
+ group 1009-4 {
+ interface eth0.1009
+ priority 200
+ virtual-address 192.0.70.129/28
+ vrid 4
+ }
+ group 1009-6 {
+ interface eth0.1009
+ priority 200
+ virtual-address 2001:db8:0:1009::1/64
+ vrid 6
+ }
+ group 1010-4 {
+ interface eth0.1010
+ priority 200
+ virtual-address 192.0.70.145/28
+ vrid 4
+ }
+ group 1010-6 {
+ interface eth0.1010
+ priority 200
+ virtual-address 2001:db8:0:1010::1/64
+ vrid 6
+ }
+ group 1011-4 {
+ interface eth0.1011
+ priority 200
+ virtual-address 192.0.70.161/28
+ vrid 4
+ }
+ group 1011-6 {
+ interface eth0.1011
+ priority 200
+ virtual-address 2001:db8:0:1011::1/64
+ vrid 6
+ }
+ group 1012-4 {
+ interface eth0.1012
+ priority 200
+ virtual-address 192.0.70.177/28
+ vrid 4
+ }
+ group 1012-6 {
+ interface eth0.1012
+ priority 200
+ virtual-address 2001:db8:0:1012::1/64
+ vrid 6
+ }
+ group 1013-4 {
+ interface eth0.1013
+ priority 200
+ virtual-address 192.0.70.193/27
+ vrid 4
+ }
+ group 1013-6 {
+ interface eth0.1013
+ priority 200
+ virtual-address 2001:db8:0:1013::1/64
+ vrid 6
+ }
+ group 1014-4 {
+ interface eth0.1014
+ priority 200
+ virtual-address 192.0.84.65/26
+ vrid 4
+ }
+ group 1014-6 {
+ interface eth0.1014
+ priority 200
+ virtual-address 2001:db8:0:1014::1/64
+ vrid 6
+ }
+ group 1015-4 {
+ interface eth0.1015
+ priority 200
+ virtual-address 192.0.71.1/26
+ vrid 4
+ }
+ group 1015-6 {
+ interface eth0.1015
+ priority 200
+ virtual-address 2001:db8:0:1015::1/64
+ vrid 6
+ }
+ group 1016-4 {
+ interface eth0.1016
+ priority 200
+ virtual-address 192.0.71.65/27
+ vrid 4
+ }
+ group 1016-6 {
+ interface eth0.1016
+ priority 200
+ virtual-address 2001:db8:0:1016::1/64
+ vrid 6
+ }
+ group 1017-4 {
+ interface eth0.1017
+ priority 200
+ virtual-address 192.0.71.97/28
+ vrid 4
+ }
+ group 1017-6 {
+ interface eth0.1017
+ priority 200
+ virtual-address 2001:db8:0:1017::1/64
+ vrid 6
+ }
+ group 1018-4 {
+ interface eth0.1018
+ priority 200
+ virtual-address 192.0.71.113/28
+ vrid 4
+ }
+ group 1018-6 {
+ interface eth0.1018
+ priority 200
+ virtual-address 2001:db8:0:1018::1/64
+ vrid 6
+ }
+ group 1019-4 {
+ interface eth0.1019
+ priority 200
+ virtual-address 192.0.71.129/26
+ vrid 4
+ }
+ group 1019-6 {
+ interface eth0.1019
+ priority 200
+ virtual-address 2001:db8:0:1019::1/64
+ vrid 6
+ }
+ group 1020-4 {
+ interface eth0.1020
+ priority 200
+ virtual-address 192.0.71.193/26
+ vrid 4
+ }
+ group 1020-6 {
+ interface eth0.1020
+ priority 200
+ virtual-address 2001:db8:0:1020::1/64
+ vrid 6
+ }
+ }
+}
+interfaces {
+ ethernet eth0 {
+ address 192.0.0.11/16
+ duplex auto
+ smp-affinity auto
+ speed auto
+ vif 11 {
+ address 192.0.68.2/27
+ address 2001:db8:c::2/64
+ }
+ vif 102 {
+ address 192.0.98.2/24
+ address 2001:db8:0:102::2/64
+ }
+ vif 105 {
+ address 192.0.160.2/24
+ address 2001:db8:0:105::2/64
+ }
+ vif 838 {
+ address 192.0.16.210/30
+ address 2001:db8:838::2/64
+ }
+ vif 886 {
+ address 192.0.193.224/21
+ address 2001:db8::3:669:0:1/64
+ }
+ vif 1001 {
+ address 192.0.68.34/27
+ address 2001:db8:0:1001::2/64
+ }
+ vif 1002 {
+ address 192.0.68.66/26
+ address 2001:db8:0:1002::2/64
+ }
+ vif 1003 {
+ address 192.0.68.130/25
+ address 2001:db8:0:1003::2/64
+ }
+ vif 1004 {
+ address 192.0.69.2/24
+ address 2001:db8:0:1004::2/64
+ }
+ vif 1005 {
+ address 192.0.70.2/28
+ address 2001:db8:0:1005::2/64
+ }
+ vif 1006 {
+ address 192.0.70.18/28
+ address 2001:db8:0:1006::2/64
+ }
+ vif 1007 {
+ address 192.0.70.34/27
+ address 2001:db8:0:1007::2/64
+ }
+ vif 1008 {
+ address 192.0.70.66/26
+ address 2001:db8:0:1008::2/64
+ }
+ vif 1009 {
+ address 192.0.70.130/28
+ address 2001:db8:0:1009::2/64
+ }
+ vif 1010 {
+ address 192.0.70.146/28
+ address 2001:db8:0:1010::2/64
+ }
+ vif 1011 {
+ address 192.0.70.162/28
+ address 2001:db8:0:1011::2/64
+ }
+ vif 1012 {
+ address 192.0.70.178/28
+ address 2001:db8:0:1012::2/64
+ }
+ vif 1013 {
+ address 192.0.70.194/27
+ address 2001:db8:0:1013::3/64
+ }
+ vif 1014 {
+ address 192.0.84.66/26
+ address 2001:db8:0:1014::2/64
+ }
+ vif 1015 {
+ address 192.0.71.2/26
+ address 2001:db8:0:1015::2/64
+ }
+ vif 1016 {
+ address 192.0.71.66/27
+ address 2001:db8:0:1016::2/64
+ }
+ vif 1017 {
+ address 192.0.71.98/28
+ address 2001:db8:0:1017::2/64
+ }
+ vif 1018 {
+ address 192.0.71.114/28
+ address 2001:db8:0:1018::2/64
+ }
+ vif 1019 {
+ address 192.0.71.130/26
+ address 2001:db8:0:1019::2/64
+ }
+ vif 1020 {
+ address 192.0.71.194/26
+ address 2001:db8:0:1020::2/64
+ }
+ vif 4088 {
+ address 2001:db8:24::c7/64
+ address 192.0.52.199/23
+ }
+ vif 4089 {
+ address 192.0.176.194/30
+ address 2001:db8:1000::2ea/126
+ }
+ }
+ loopback lo {
+ }
+}
+policy {
+ as-path-list AS64513-AS64514 {
+ rule 10 {
+ action permit
+ regex "^64513 64514$"
+ }
+ }
+ as-path-list AS64512 {
+ rule 10 {
+ action permit
+ regex ^$
+ }
+ }
+ prefix-list defaultV4 {
+ rule 10 {
+ action permit
+ prefix 0.0.0.0/0
+ }
+ }
+ prefix-list hostrouteV4 {
+ rule 10 {
+ action permit
+ ge 32
+ prefix 192.0.160.0/24
+ }
+ rule 20 {
+ action permit
+ ge 32
+ prefix 192.0.98.0/24
+ }
+ rule 30 {
+ action permit
+ ge 32
+ prefix 192.0.68.0/22
+ }
+ rule 40 {
+ action permit
+ ge 32
+ prefix 192.0.84.0/22
+ }
+ }
+ prefix-list vyosV4 {
+ rule 10 {
+ action permit
+ prefix 192.0.160.0/24
+ }
+ rule 20 {
+ action permit
+ prefix 192.0.98.0/24
+ }
+ rule 30 {
+ action permit
+ prefix 192.0.68.0/22
+ }
+ rule 40 {
+ action permit
+ prefix 192.0.84.0/22
+ }
+ }
+ prefix-list privateV4 {
+ rule 10 {
+ action permit
+ le 32
+ prefix 192.0.0.0/8
+ }
+ rule 20 {
+ action permit
+ le 32
+ prefix 192.0.0.0/12
+ }
+ rule 30 {
+ action permit
+ le 32
+ prefix 192.0.0.0/16
+ }
+ }
+ prefix-list6 all6 {
+ rule 10 {
+ action permit
+ ge 4
+ prefix 2000::/3
+ }
+ }
+ prefix-list6 hostrouteV6 {
+ rule 20 {
+ action permit
+ ge 128
+ prefix 2001:db8::/29
+ }
+ }
+ prefix-list6 vyosV6 {
+ rule 20 {
+ action permit
+ prefix 2001:db8::/29
+ }
+ }
+ prefix-list6 privateV6 {
+ rule 10 {
+ action permit
+ prefix fc00::/7
+ }
+ }
+ route-map ExportRouteMap {
+ rule 5 {
+ action permit
+ match {
+ as-path AS64512
+ ip {
+ address {
+ prefix-list hostrouteV4
+ }
+ }
+ }
+ set {
+ community 65000:666
+ }
+ }
+ rule 10 {
+ action permit
+ match {
+ as-path AS64512
+ ip {
+ address {
+ prefix-list vyosV4
+ }
+ }
+ }
+ }
+ rule 15 {
+ action permit
+ match {
+ as-path AS64512
+ ipv6 {
+ address {
+ prefix-list hostrouteV6
+ }
+ }
+ }
+ set {
+ community 65000:666
+ }
+ }
+ rule 20 {
+ action permit
+ match {
+ as-path AS64512
+ ipv6 {
+ address {
+ prefix-list vyosV6
+ }
+ }
+ }
+ }
+ rule 100 {
+ action deny
+ }
+ }
+ route-map ExportRouteMapAS64515 {
+ rule 10 {
+ action permit
+ match {
+ ipv6 {
+ address {
+ prefix-list all6
+ }
+ }
+ }
+ }
+ rule 20 {
+ action deny
+ match {
+ ip {
+ address {
+ prefix-list defaultV4
+ }
+ }
+ }
+ }
+ rule 100 {
+ action deny
+ }
+ }
+ route-map ExportRouteMapAS64516 {
+ rule 5 {
+ action permit
+ match {
+ as-path AS64512
+ ip {
+ address {
+ prefix-list hostrouteV4
+ }
+ }
+ }
+ set {
+ community 65000:666
+ }
+ }
+ rule 10 {
+ action permit
+ match {
+ as-path AS64512
+ ip {
+ address {
+ prefix-list vyosV4
+ }
+ }
+ }
+ }
+ rule 15 {
+ action permit
+ match {
+ as-path AS64512
+ ipv6 {
+ address {
+ prefix-list hostrouteV6
+ }
+ }
+ }
+ set {
+ community 65000:666
+ }
+ }
+ rule 20 {
+ action permit
+ match {
+ as-path AS64512
+ ipv6 {
+ address {
+ prefix-list vyosV6
+ }
+ }
+ }
+ }
+ rule 100 {
+ action deny
+ }
+ }
+ route-map ExportRouteMapAS64517 {
+ rule 5 {
+ action permit
+ match {
+ as-path AS64512
+ ip {
+ address {
+ prefix-list hostrouteV4
+ }
+ }
+ }
+ set {
+ community 64517:666
+ }
+ }
+ rule 10 {
+ action permit
+ match {
+ as-path AS64512
+ ip {
+ address {
+ prefix-list vyosV4
+ }
+ }
+ }
+ }
+ rule 15 {
+ action permit
+ match {
+ as-path AS64512
+ ipv6 {
+ address {
+ prefix-list hostrouteV6
+ }
+ }
+ }
+ set {
+ community 64517:666
+ }
+ }
+ rule 20 {
+ action permit
+ match {
+ as-path AS64512
+ ipv6 {
+ address {
+ prefix-list vyosV6
+ }
+ }
+ }
+ }
+ rule 100 {
+ action deny
+ }
+ }
+ route-map ExportRouteMapAS64513 {
+ rule 5 {
+ action permit
+ match {
+ as-path AS64512
+ ip {
+ address {
+ prefix-list hostrouteV4
+ }
+ }
+ }
+ set {
+ community 64513:666
+ }
+ }
+ rule 10 {
+ action permit
+ match {
+ as-path AS64512
+ ip {
+ address {
+ prefix-list vyosV4
+ }
+ }
+ }
+ }
+ rule 15 {
+ action permit
+ match {
+ as-path AS64512
+ ipv6 {
+ address {
+ prefix-list hostrouteV6
+ }
+ }
+ }
+ set {
+ community 64513:666
+ }
+ }
+ rule 20 {
+ action permit
+ match {
+ as-path AS64512
+ ipv6 {
+ address {
+ prefix-list vyosV6
+ }
+ }
+ }
+ }
+ rule 100 {
+ action deny
+ }
+ }
+ route-map ImportRouteMap {
+ rule 10 {
+ action deny
+ match {
+ ip {
+ address {
+ prefix-list privateV4
+ }
+ }
+ }
+ }
+ rule 15 {
+ action deny
+ match {
+ ipv6 {
+ address {
+ prefix-list privateV6
+ }
+ }
+ }
+ }
+ rule 20 {
+ action deny
+ match {
+ ip {
+ address {
+ prefix-list vyosV4
+ }
+ }
+ }
+ }
+ rule 30 {
+ action deny
+ match {
+ ipv6 {
+ address {
+ prefix-list vyosV6
+ }
+ }
+ }
+ }
+ rule 40 {
+ action deny
+ match {
+ as-path AS64512
+ }
+ }
+ rule 50 {
+ action permit
+ match {
+ as-path AS64513-AS64514
+ }
+ set {
+ weight 10001
+ }
+ }
+ rule 65535 {
+ action permit
+ }
+ }
+}
+protocols {
+ bgp 64500 {
+ address-family {
+ ipv4-unicast {
+ network 192.0.98.0/24 {
+ }
+ network 192.0.160.0/24 {
+ }
+ network 192.0.68.0/22 {
+ }
+ network 192.0.84.0/22 {
+ }
+ redistribute {
+ static {
+ route-map ExportRouteMap
+ }
+ }
+ }
+ ipv6-unicast {
+ network 2001:db8::/29 {
+ }
+ redistribute {
+ static {
+ route-map ExportRouteMap
+ }
+ }
+ }
+ }
+ maximum-paths {
+ ebgp 8
+ ibgp 16
+ }
+ neighbor 192.0.16.209 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ export ExportRouteMapAS64516
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64501
+ }
+ neighbor 192.0.192.6 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 100
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64502
+ }
+ neighbor 192.0.192.157 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 350000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64503
+ }
+ neighbor 192.0.192.228 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 10000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64504
+ }
+ neighbor 192.0.193.157 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 350000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64505
+ }
+ neighbor 192.0.193.202 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 10000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64506
+ }
+ neighbor 192.0.193.223 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 10000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64507
+ }
+ neighbor 192.0.194.161 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 10000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64508
+ }
+ neighbor 192.0.194.171 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 10000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64509
+ }
+ neighbor 192.0.176.193 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ export ExportRouteMapAS64516
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64510
+ }
+ neighbor 192.0.52.12 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 300
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64511
+ }
+ neighbor 192.0.52.17 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 75
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ password vyosvyos
+ remote-as 64512
+ }
+ neighbor 192.0.52.24 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 300
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64513
+ }
+ neighbor 192.0.52.32 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 50
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ password vyosfoooo
+ remote-as 64514
+ }
+ neighbor 192.0.52.34 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 10
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64515
+ }
+ neighbor 192.0.52.46 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 10
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64516
+ }
+ neighbor 192.0.52.49 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 75
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ password secret
+ remote-as 64517
+ }
+ neighbor 192.0.52.74 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 15000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ password secretvyos
+ remote-as 64518
+ }
+ neighbor 192.0.52.94 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 250
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64519
+ }
+ neighbor 192.0.52.100 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 50
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64520
+ }
+ neighbor 192.0.52.119 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 30
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64521
+ }
+ neighbor 192.0.52.165 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 50
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64522
+ }
+ neighbor 192.0.52.170 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 150000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64523
+ }
+ neighbor 192.0.52.171 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 10000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64524
+ }
+ neighbor 192.0.52.179 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 20
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64525
+ }
+ neighbor 192.0.52.189 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 1000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64526
+ }
+ neighbor 192.0.52.210 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 15
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64527
+ }
+ neighbor 192.0.52.211 {
+ address-family {
+ ipv4-unicast {
+ maximum-prefix 15
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64528
+ }
+ neighbor 192.0.52.251 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ weight 1010
+ }
+ }
+ remote-as 64529
+ }
+ neighbor 192.0.52.252 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ export ExportRouteMap
+ }
+ weight 1010
+ }
+ }
+ remote-as 64530
+ }
+ neighbor 192.0.52.253 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ export ExportRouteMapAS64515
+ import ImportRouteMap
+ }
+ }
+ }
+ passive
+ remote-as 64531
+ }
+ neighbor 192.0.68.3 {
+ address-family {
+ ipv4-unicast {
+ nexthop-self
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ remote-as 64532
+ update-source 192.0.68.2
+ }
+ neighbor 2001:db8:838::1 {
+ address-family {
+ ipv6-unicast {
+ route-map {
+ export ExportRouteMapAS64516
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64533
+ }
+ neighbor 2001:db8:c::3 {
+ address-family {
+ ipv6-unicast {
+ nexthop-self
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ remote-as 64534
+ update-source 2001:db8:c::2
+ }
+ neighbor 2001:db8:24::2e {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 5
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ password vyossecret
+ remote-as 64535
+ }
+ neighbor 2001:db8:24::4a {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 1000
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64536
+ }
+ neighbor 2001:db8:24::5e {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 200
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64537
+ }
+ neighbor 2001:db8:24::11 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 20
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64538
+ }
+ neighbor 2001:db8:24::18 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 300
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64539
+ }
+ neighbor 2001:db8:24::20 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 10
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64540
+ }
+ neighbor 2001:db8:24::22 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 5
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64541
+ }
+ neighbor 2001:db8:24::31 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 20
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64542
+ }
+ neighbor 2001:db8:24::58 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 15
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64543
+ }
+ neighbor 2001:db8:24::64 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 10
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ password geheim
+ remote-as 64544
+ }
+ neighbor 2001:db8:24::a5 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 10
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64545
+ }
+ neighbor 2001:db8:24::aa {
+ address-family {
+ ipv6-unicast {
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64546
+ }
+ neighbor 2001:db8:24::ab {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 1800
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ remote-as 64547
+ }
+ neighbor 2001:db8:24::b0 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 5
+ route-map {
+ export ExportRouteMap
+ import ImportRouteMap
+ }
+ }
+ }
+ password secret123
+ remote-as 64548
+ }
+ parameters {
+ default {
+ no-ipv4-unicast
+ }
+ log-neighbor-changes
+ router-id 192.0.68.2
+ }
+ }
+ static {
+ route 192.0.98.0/24 {
+ blackhole {
+ }
+ }
+ route 192.0.160.0/24 {
+ blackhole {
+ }
+ }
+ route 192.0.68.0/22 {
+ blackhole {
+ }
+ }
+ route 192.0.84.0/22 {
+ blackhole {
+ }
+ }
+ route6 2001:db8::/29 {
+ blackhole {
+ }
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ flow-accounting {
+ disable-imt
+ interface eth0.4088
+ interface eth0.4089
+ netflow {
+ engine-id 1
+ server 192.0.2.55 {
+ port 2055
+ }
+ version 9
+ }
+ syslog-facility daemon
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/
+ plaintext-password ""
+ }
+ }
+ }
+ name-server 2001:db8::1
+ name-server 2001:db8::2
+ name-server 192.0.2.1
+ name-server 192.0.2.2
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level all
+ }
+ preserve-fqdn
+ }
+ }
+ time-zone Europe/Zurich
+}
+zone-policy {
+ zone local {
+ default-action drop
+ from management {
+ firewall {
+ ipv6-name management-to-local-6
+ name management-to-local-4
+ }
+ }
+ from peers {
+ firewall {
+ ipv6-name peers-to-local-6
+ name peers-to-local-4
+ }
+ }
+ from servers {
+ firewall {
+ ipv6-name servers-to-local-6
+ name servers-to-local-4
+ }
+ }
+ local-zone
+ }
+ zone management {
+ default-action reject
+ from peers {
+ firewall {
+ ipv6-name peers-to-management-6
+ name peers-to-management-4
+ }
+ }
+ from servers {
+ firewall {
+ ipv6-name servers-to-management-6
+ name servers-to-management-4
+ }
+ }
+ interface eth0
+ }
+ zone peers {
+ default-action reject
+ from management {
+ firewall {
+ ipv6-name management-to-peers-6
+ name management-to-peers-4
+ }
+ }
+ from servers {
+ firewall {
+ ipv6-name servers-to-peers-6
+ name servers-to-peers-4
+ }
+ }
+ interface eth0.4088
+ interface eth0.4089
+ interface eth0.11
+ interface eth0.838
+ interface eth0.886
+ }
+ zone servers {
+ default-action reject
+ from management {
+ firewall {
+ ipv6-name management-to-servers-6
+ name management-to-servers-4
+ }
+ }
+ from peers {
+ firewall {
+ ipv6-name peers-to-servers-6
+ name peers-to-servers-4
+ }
+ }
+ interface eth0.1001
+ interface eth0.105
+ interface eth0.102
+ interface eth0.1019
+ interface eth0.1014
+ interface eth0.1020
+ interface eth0.1018
+ interface eth0.1013
+ interface eth0.1012
+ interface eth0.1011
+ interface eth0.1010
+ interface eth0.1009
+ interface eth0.1006
+ interface eth0.1005
+ interface eth0.1017
+ interface eth0.1016
+ interface eth0.1002
+ interface eth0.1015
+ interface eth0.1003
+ interface eth0.1004
+ interface eth0.1007
+ interface eth0.1008
+ }
+}
+
+
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
+/* Release version: 1.2.5 */
diff --git a/smoketest/configs/bgp-evpn-leaf b/smoketest/configs/bgp-evpn-leaf
new file mode 100644
index 000000000..73d658de8
--- /dev/null
+++ b/smoketest/configs/bgp-evpn-leaf
@@ -0,0 +1,148 @@
+interfaces {
+ bridge br100 {
+ member {
+ interface eth3 {
+ }
+ interface vxlan100 {
+ }
+ }
+ }
+ dummy dum0 {
+ address 172.29.0.1/32
+ }
+ ethernet eth0 {
+ description "Out-of-Band Managament Port"
+ address 2001:db8::41/64
+ address 192.0.2.41/27
+ vrf MGMT
+ }
+ ethernet eth1 {
+ address 172.29.1.1/31
+ mtu 1600
+ }
+ ethernet eth2 {
+ address 172.29.2.1/31
+ mtu 1600
+ }
+ ethernet eth3 {
+ }
+ loopback lo {
+ }
+ vxlan vxlan100 {
+ parameters {
+ nolearning
+ }
+ port 4789
+ source-address 172.29.0.1
+ vni 100
+ }
+}
+protocols {
+ bgp 65010 {
+ address-family {
+ ipv4-unicast {
+ maximum-paths {
+ ibgp 4
+ }
+ redistribute {
+ connected {
+ }
+ }
+ }
+ l2vpn-evpn {
+ advertise-all-vni
+ }
+ }
+ neighbor 172.29.1.0 {
+ peer-group evpn
+ }
+ neighbor 172.29.2.0 {
+ peer-group evpn
+ }
+ parameters {
+ log-neighbor-changes
+ }
+ peer-group evpn {
+ address-family {
+ ipv4-unicast {
+ nexthop-self {
+ }
+ }
+ l2vpn-evpn {
+ nexthop-self {
+ }
+ }
+ }
+ remote-as 65010
+ }
+ }
+ vrf MGMT {
+ static {
+ route 0.0.0.0/0 {
+ next-hop 192.0.2.62 {
+ }
+ }
+ route6 ::/0 {
+ next-hop 2001:db8::1 {
+ }
+ }
+ }
+ }
+}
+service {
+ lldp {
+ interface all {
+ }
+ }
+ ssh {
+ disable-host-validation
+ vrf MGMT
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ ntp {
+ listen-address 192.0.2.41
+ listen-address 2001:db8::41
+ server 0.de.pool.ntp.org {
+ prefer
+ }
+ vrf MGMT
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+}
+vrf {
+ name MGMT {
+ table 1000
+ }
+}
+
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@2:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@20:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:nat66@1:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8: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.4-rolling-202103091038
diff --git a/smoketest/configs/bgp-evpn-spine b/smoketest/configs/bgp-evpn-spine
new file mode 100644
index 000000000..5dafc2f77
--- /dev/null
+++ b/smoketest/configs/bgp-evpn-spine
@@ -0,0 +1,128 @@
+interfaces {
+ ethernet eth0 {
+ description "Out-of-Band Managament Port"
+ address 192.0.2.51/27
+ address 2001:db8::51/64
+ vrf MGMT
+ }
+ ethernet eth1 {
+ address 172.29.1.0/31
+ mtu 1600
+ }
+ ethernet eth2 {
+ address 172.29.1.2/31
+ mtu 1600
+ }
+ ethernet eth3 {
+ address 172.29.1.4/31
+ mtu 1600
+ }
+ loopback lo {
+ }
+}
+protocols {
+ bgp 65010 {
+ address-family {
+ ipv4-unicast {
+ maximum-paths {
+ ibgp 4
+ }
+ redistribute {
+ connected {
+ }
+ }
+ }
+ }
+ listen {
+ range 172.29.1.0/24 {
+ peer-group evpn
+ }
+ }
+ parameters {
+ log-neighbor-changes
+ }
+ peer-group evpn {
+ address-family {
+ ipv4-unicast {
+ route-reflector-client
+ }
+ l2vpn-evpn {
+ route-reflector-client
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 65010
+ }
+ }
+ vrf MGMT {
+ static {
+ route 0.0.0.0/0 {
+ next-hop 192.0.2.62 {
+ }
+ }
+ route6 ::/0 {
+ next-hop 2001:db8::1 {
+ }
+ }
+ }
+ }
+}
+service {
+ lldp {
+ interface all {
+ }
+ }
+ ssh {
+ disable-host-validation
+ vrf MGMT
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ ntp {
+ listen-address 192.0.2.51
+ listen-address 2001:db8::51
+ server 0.de.pool.ntp.org {
+ prefer
+ }
+ vrf MGMT
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+}
+vrf {
+ name MGMT {
+ table 1000
+ }
+}
+
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@2:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@20:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:nat66@1:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8: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.4-rolling-202103091038
diff --git a/smoketest/configs/pppoe-client b/smoketest/configs/bgp-rpki
index ef6a26423..e11ec9e72 100644
--- a/smoketest/configs/pppoe-client
+++ b/smoketest/configs/bgp-rpki
@@ -1,17 +1,71 @@
interfaces {
ethernet eth0 {
+ address 192.0.2.100/25
+ address 2001:db8::ffff/64
+ }
+ ethernet eth1 {
}
loopback lo {
}
- pppoe pppoe0 {
- authentication {
- password bar
- user foo
+}
+policy {
+ route-map ebgp-transit-rpki {
+ rule 10 {
+ action deny
+ match {
+ rpki invalid
+ }
+ }
+ rule 20 {
+ action permit
+ match {
+ rpki notfound
+ }
+ set {
+ local-preference 20
+ }
+ }
+ rule 30 {
+ action permit
+ match {
+ rpki valid
+ }
+ set {
+ local-preference 100
+ }
+ }
+ }
+}
+protocols {
+ bgp 64500 {
+ neighbor 1.2.3.4 {
+ address-family {
+ ipv4-unicast {
+ nexthop-self {
+ }
+ route-map {
+ import ebgp-transit-rpki
+ }
+ }
+ }
+ remote-as 10
+ }
+ }
+ rpki {
+ cache routinator {
+ address 192.0.2.10
+ port 3323
+ }
+ }
+ static {
+ route 0.0.0.0/0 {
+ next-hop 192.0.2.1 {
+ }
+ }
+ route6 ::/0 {
+ next-hop 2001:db8::1 {
+ }
}
- connect-on-demand
- default-route auto
- mtu 1492
- source-interface eth0
}
}
service {
diff --git a/smoketest/configs/bgp-small-as b/smoketest/configs/bgp-small-as
new file mode 100644
index 000000000..6b953a3f6
--- /dev/null
+++ b/smoketest/configs/bgp-small-as
@@ -0,0 +1,687 @@
+firewall {
+ all-ping enable
+ broadcast-ping disable
+ config-trap disable
+ group {
+ address-group NET-VYOS-HTTPS-4 {
+ address 10.0.150.73
+ }
+ ipv6-network-group NET-VYOS-6 {
+ network 2001:db8:200::/40
+ }
+ network-group NET-VYOS-4 {
+ network 10.0.150.0/23
+ network 192.168.189.0/24
+ }
+ port-group MY-NAS-PORTS {
+ port 80
+ port 5000
+ port 5001
+ port 6022
+ port 9443
+ }
+ }
+ ipv6-name WAN-TO-VLAN15-6 {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 100 {
+ action accept
+ source {
+ group {
+ network-group NET-VYOS-6
+ }
+ }
+ }
+ rule 1010 {
+ action accept
+ destination {
+ address 2001:db8:200:15::a
+ group {
+ port-group MY-NAS-PORTS
+ }
+ }
+ protocol tcp
+ }
+ }
+ ipv6-receive-redirects disable
+ ipv6-src-route disable
+ ip-src-route disable
+ log-martians enable
+ name WAN-TO-VLAN15-4 {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 100 {
+ action accept
+ source {
+ group {
+ network-group NET-VYOS-4
+ }
+ }
+ }
+ rule 1000 {
+ action accept
+ destination {
+ group {
+ address-group NET-VYOS-HTTPS-4
+ }
+ port 80,443
+ }
+ protocol tcp
+ }
+ rule 1010 {
+ action accept
+ destination {
+ address 10.0.150.74
+ group {
+ port-group MY-NAS-PORTS
+ }
+ }
+ protocol tcp
+ }
+ }
+ receive-redirects disable
+ send-redirects enable
+ source-validation disable
+ syn-cookies enable
+ twa-hazards-protection disable
+}
+high-availability {
+ vrrp {
+ group VLAN5-IPv4 {
+ interface eth0.5
+ preempt-delay 180
+ priority 250
+ virtual-address 10.0.150.120/28
+ vrid 5
+ }
+ group VLAN5-IPv6 {
+ interface eth0.5
+ preempt-delay 180
+ priority 250
+ virtual-address 2001:db8:200:f0::ffff/64
+ vrid 6
+ }
+ group VLAN10-IPv4 {
+ interface eth0.10
+ preempt-delay 180
+ priority 250
+ virtual-address 10.0.150.62/26
+ vrid 10
+ }
+ group VLAN10-IPv6 {
+ interface eth0.10
+ preempt-delay 180
+ priority 250
+ virtual-address 2001:db8:200:10::ffff/64
+ virtual-address 2001:db8:200::ffff/64
+ vrid 11
+ }
+ group VLAN15-IPv4 {
+ interface eth0.15
+ preempt-delay 180
+ priority 250
+ virtual-address 10.0.150.78/28
+ vrid 15
+ }
+ group VLAN15-IPv6 {
+ interface eth0.15
+ preempt-delay 180
+ priority 250
+ virtual-address 2001:db8:200:15::ffff/64
+ vrid 16
+ }
+ group VLAN500-IPv4 {
+ interface eth0.500
+ preempt-delay 180
+ priority 250
+ virtual-address 10.0.151.238/28
+ vrid 238
+ }
+ group VLAN500-IPv6 {
+ interface eth0.500
+ preempt-delay 180
+ priority 250
+ virtual-address 2001:db8:200:50::ffff/64
+ vrid 239
+ }
+ group VLAN520-IPv4 {
+ interface eth0.520
+ preempt-delay 180
+ priority 250
+ virtual-address 10.0.150.190/28
+ vrid 52
+ }
+ group VLAN520-IPv6 {
+ interface eth0.520
+ preempt-delay 180
+ priority 250
+ virtual-address 2001:db8:200:520::ffff/64
+ vrid 53
+ }
+ group VLAN810-IPv4 {
+ interface eth0.810
+ preempt-delay 180
+ priority 250
+ virtual-address 10.0.151.30/27
+ vrid 80
+ }
+ group VLAN810-IPv6 {
+ interface eth0.810
+ preempt-delay 180
+ priority 250
+ virtual-address 2001:db8:200:102::ffff/64
+ vrid 81
+ }
+ sync-group VYOS {
+ member VLAN5-IPv4
+ member VLAN5-IPv6
+ member VLAN10-IPv4
+ member VLAN10-IPv6
+ member VLAN500-IPv4
+ member VLAN500-IPv6
+ member VLAN15-IPv4
+ member VLAN15-IPv6
+ member VLAN810-IPv6
+ member VLAN810-IPv4
+ member VLAN520-IPv4
+ member VLAN520-IPv6
+ }
+ }
+}
+interfaces {
+ dummy dum0 {
+ address 2001:db8:200:ffff::2/128
+ address 10.0.151.251/32
+ }
+ ethernet eth0 {
+ vif 5 {
+ address 10.0.150.121/28
+ address 2001:db8:200:f0::4/64
+ ip {
+ ospf {
+ authentication {
+ md5 {
+ key-id 10 {
+ md5-key vyosospfkey
+ }
+ }
+ }
+ cost 10
+ dead-interval 40
+ hello-interval 10
+ network broadcast
+ priority 200
+ retransmit-interval 5
+ transmit-delay 5
+ }
+ }
+ }
+ vif 10 {
+ address 2001:db8:200:10::1:ffff/64
+ address 2001:db8:200::1:ffff/64
+ address 10.0.150.60/26
+ }
+ vif 15 {
+ address 10.0.150.76/28
+ address 2001:db8:200:15::1:ffff/64
+ firewall {
+ out {
+ ipv6-name WAN-TO-VLAN15-6
+ name WAN-TO-VLAN15-4
+ }
+ }
+ }
+ vif 50 {
+ address 192.168.189.2/24
+ }
+ vif 110 {
+ address 2001:db8:200:101::ffff/64
+ address 10.0.151.190/27
+ address 10.0.151.158/28
+ }
+ vif 410 {
+ address 10.0.151.206/28
+ address 2001:db8:200:104::ffff/64
+ }
+ vif 450 {
+ address 2001:db8:200:103::ffff/64
+ address 10.0.151.142/29
+ disable
+ }
+ vif 500 {
+ address 10.0.151.236/28
+ address 2001:db8:200:50::1:ffff/64
+ }
+ vif 520 {
+ address 10.0.150.188/26
+ address 2001:db8:200:520::1:ffff/64
+ }
+ vif 800 {
+ address 2001:db8:200:ff::104:1/112
+ address 10.0.151.212/31
+ }
+ vif 810 {
+ address 10.0.151.28/27
+ address 2001:db8:200:102::1:ffff/64
+ }
+ }
+ ethernet eth1 {
+ }
+ loopback lo {
+ }
+}
+policy {
+ prefix-list as65000-origin-v4 {
+ rule 10 {
+ action permit
+ prefix 10.0.150.0/23
+ }
+ rule 100 {
+ action permit
+ prefix 0.0.0.0/0
+ }
+ }
+ prefix-list6 as65000-origin-v6 {
+ rule 10 {
+ action permit
+ prefix 2001:db8:200::/40
+ }
+ }
+ route-map as65010-in {
+ rule 10 {
+ action permit
+ set {
+ local-preference 30
+ }
+ }
+ }
+ route-map as65010-out {
+ rule 10 {
+ action permit
+ set {
+ as-path-prepend "65000 65000"
+ }
+ }
+ }
+}
+protocols {
+ bgp 65000 {
+ address-family {
+ ipv4-unicast {
+ network 10.0.150.0/23 {
+ }
+ }
+ ipv6-unicast {
+ network 2001:db8:200::/40 {
+ }
+ }
+ }
+ neighbor 10.0.151.222 {
+ disable-send-community {
+ extended
+ standard
+ }
+ address-family {
+ ipv4-unicast {
+ default-originate {
+ }
+ prefix-list {
+ export as65000-origin-v4
+ }
+ route-map {
+ export as65010-out
+ import as65010-in
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 65010
+ }
+ neighbor 10.0.151.252 {
+ peer-group VYOSv4
+ }
+ neighbor 10.0.151.254 {
+ peer-group VYOSv4
+ }
+ neighbor 2001:db8:200:ffff::3 {
+ peer-group VYOSv6
+ }
+ neighbor 2001:db8:200:ffff::a {
+ peer-group VYOSv6
+ }
+ neighbor 2001:db8:200:ff::101:2 {
+ address-family {
+ ipv6-unicast {
+ capability {
+ dynamic
+ }
+ prefix-list {
+ export as65000-origin-v6
+ }
+ route-map {
+ import as65010-in
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ remote-as 65010
+ }
+ parameters {
+ default {
+ no-ipv4-unicast
+ }
+ log-neighbor-changes
+ router-id 10.0.151.251
+ }
+ peer-group VYOSv4 {
+ address-family {
+ ipv4-unicast {
+ nexthop-self {
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 65000
+ update-source dum0
+ }
+ peer-group VYOSv6 {
+ address-family {
+ ipv6-unicast {
+ nexthop-self {
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 65000
+ update-source dum0
+ }
+ timers {
+ holdtime 30
+ keepalive 10
+ }
+ }
+ ospf {
+ area 0 {
+ area-type {
+ normal
+ }
+ authentication md5
+ network 10.0.151.251/32
+ network 10.0.151.208/31
+ network 10.0.150.112/28
+ }
+ parameters {
+ abr-type cisco
+ router-id 10.0.151.251
+ }
+ passive-interface default
+ passive-interface-exclude dum0
+ passive-interface-exclude eth0.5
+ redistribute {
+ connected {
+ metric-type 2
+ }
+ static {
+ metric-type 2
+ }
+ }
+ }
+ ospfv3 {
+ area 0.0.0.0 {
+ interface dum0
+ interface eth0.5
+ }
+ parameters {
+ router-id 10.0.151.251
+ }
+ redistribute {
+ connected {
+ }
+ static {
+ }
+ }
+ }
+ static {
+ route 10.0.0.0/8 {
+ MY-NAS {
+ distance 254
+ }
+ }
+ route 172.16.0.0/12 {
+ MY-NAS {
+ distance 254
+ }
+ }
+ route 192.168.0.0/16 {
+ MY-NAS {
+ distance 254
+ }
+ }
+ route 193.148.249.144/32 {
+ next-hop 192.168.189.1 {
+ }
+ }
+ route 10.0.150.0/23 {
+ MY-NAS {
+ distance 254
+ }
+ }
+ route 10.0.151.32/27 {
+ next-hop 10.0.151.5 {
+ }
+ }
+ route6 2001:db8:2fe:ffff::/64 {
+ next-hop 2001:db8:200:102::4 {
+ }
+ }
+ route6 2001:db8:2ff::/48 {
+ next-hop 2001:db8:200:101::1 {
+ }
+ }
+ route6 2001:db8:200::/40 {
+ MY-NAS {
+ distance 254
+ }
+ }
+ }
+}
+service {
+ dhcp-server {
+ shared-network-name NET-VYOS-DHCP-1 {
+ subnet 10.0.151.224/28 {
+ default-router 10.0.151.238
+ dns-server 10.0.150.2
+ dns-server 10.0.150.1
+ domain-name vyos.net
+ failover {
+ local-address 10.0.151.236
+ name NET-VYOS-DHCP-1
+ peer-address 10.0.151.237
+ status primary
+ }
+ lease 1800
+ range 0 {
+ start 10.0.151.225
+ stop 10.0.151.237
+ }
+ }
+ }
+ shared-network-name NET-VYOS-HOSTING-1 {
+ subnet 10.0.150.128/26 {
+ default-router 10.0.150.190
+ dns-server 10.0.150.2
+ dns-server 10.0.150.1
+ domain-name vyos.net
+ failover {
+ local-address 10.0.150.188
+ name NET-VYOS-HOSTING-1
+ peer-address 10.0.150.189
+ status primary
+ }
+ lease 604800
+ range 0 {
+ start 10.0.150.129
+ stop 10.0.150.187
+ }
+ }
+ }
+ }
+ lldp {
+ interface all {
+ }
+ management-address 10.0.151.251
+ snmp {
+ enable
+ }
+ }
+ router-advert {
+ interface eth4.500 {
+ default-preference high
+ name-server 2001:db8:200::1
+ name-server 2001:db8:200::2
+ prefix 2001:db8:200:50::/64 {
+ valid-lifetime infinity
+ }
+ }
+ interface eth4.520 {
+ default-preference high
+ name-server 2001:db8:200::1
+ name-server 2001:db8:200::2
+ prefix 2001:db8:200:520::/64 {
+ valid-lifetime infinity
+ }
+ }
+ }
+ snmp {
+ community public {
+ network 10.0.150.0/26
+ network 2001:db8:200:10::/64
+ }
+ contact noc@vyos.net
+ listen-address 10.0.151.251 {
+ }
+ listen-address 2001:db8:200:ffff::2 {
+ }
+ location "Jenkins"
+ }
+ ssh {
+ disable-host-validation
+ listen-address 10.0.151.251
+ listen-address 2001:db8:200:ffff::2
+ listen-address 192.168.189.2
+ loglevel fatal
+ port 22
+ }
+}
+system {
+ config-management {
+ commit-revisions 200
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ domain-name vyos.net
+ host-name vyos
+ login {
+ banner {
+ pre-login "VyOS - Network\n"
+ }
+ radius {
+ server 192.0.2.1 {
+ key SuperS3cretRADIUSkey
+ timeout 1
+ }
+ server 192.0.2.2 {
+ key SuperS3cretRADIUSkey
+ timeout 1
+ }
+ source-address 192.0.2.254
+ }
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ name-server 192.0.2.1
+ name-server 192.0.2.2
+ name-server 2001:db8:200::1
+ name-server 2001:db8:200::2
+ ntp {
+ allow-clients {
+ address 10.0.150.0/23
+ address 2001:db8:200::/40
+ }
+ listen-address 10.0.151.251
+ listen-address 2001:db8:200:ffff::2
+ server 0.de.pool.ntp.org {
+ }
+ server 1.de.pool.ntp.org {
+ }
+ server 2.de.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level notice
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ host 10.0.150.26 {
+ facility all {
+ level all
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+
+
+// 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@6: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-beta-202101151942
diff --git a/smoketest/configs/bgp-small-internet-exchange b/smoketest/configs/bgp-small-internet-exchange
new file mode 100644
index 000000000..d51f87c4a
--- /dev/null
+++ b/smoketest/configs/bgp-small-internet-exchange
@@ -0,0 +1,488 @@
+interfaces {
+ ethernet eth0 {
+ address 192.0.2.100/25
+ address 2001:db8:aaaa::ffff/64
+ }
+ ethernet eth1 {
+ address 192.0.2.200/25
+ address 2001:db8:bbbb::ffff/64
+ }
+ loopback lo {
+ }
+}
+policy {
+ as-path-list bogon-asns {
+ rule 10 {
+ action permit
+ description "RFC 7607"
+ regex _0_
+ }
+ rule 20 {
+ action permit
+ description "RFC 4893"
+ regex _23456_
+ }
+ rule 30 {
+ action permit
+ description "RFC 5398/6996/7300"
+ regex _6449[6-9]_|_65[0-4][0-9][0-9]_|_655[0-4][0-9]_|_6555[0-1]_
+ }
+ rule 40 {
+ action permit
+ description "IANA reserved"
+ 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]_
+ }
+ }
+ prefix-list bogon-v4 {
+ rule 10 {
+ action permit
+ le 32
+ prefix 0.0.0.0/8
+ }
+ rule 20 {
+ action permit
+ le 32
+ prefix 10.0.0.0/8
+ }
+ rule 30 {
+ action permit
+ le 32
+ prefix 100.64.0.0/10
+ }
+ rule 40 {
+ action permit
+ le 32
+ prefix 127.0.0.0/8
+ }
+ rule 50 {
+ action permit
+ le 32
+ prefix 169.254.0.0/16
+ }
+ rule 60 {
+ action permit
+ le 32
+ prefix 172.16.0.0/12
+ }
+ rule 70 {
+ action permit
+ le 32
+ prefix 192.0.2.0/24
+ }
+ rule 80 {
+ action permit
+ le 32
+ prefix 192.88.99.0/24
+ }
+ rule 90 {
+ action permit
+ le 32
+ prefix 192.168.0.0/16
+ }
+ rule 100 {
+ action permit
+ le 32
+ prefix 198.18.0.0/15
+ }
+ rule 110 {
+ action permit
+ le 32
+ prefix 198.51.100.0/24
+ }
+ rule 120 {
+ action permit
+ le 32
+ prefix 203.0.113.0/24
+ }
+ rule 130 {
+ action permit
+ le 32
+ prefix 224.0.0.0/4
+ }
+ rule 140 {
+ action permit
+ le 32
+ prefix 240.0.0.0/4
+ }
+ }
+ prefix-list IX-out-v4 {
+ rule 10 {
+ action permit
+ prefix 10.0.0.0/23
+ }
+ rule 20 {
+ action permit
+ prefix 10.0.128.0/23
+ }
+ }
+ prefix-list prefix-filter-v4 {
+ rule 10 {
+ action permit
+ ge 25
+ prefix 0.0.0.0/0
+ }
+ }
+ prefix-list6 bogon-v6 {
+ rule 10 {
+ action permit
+ description "RFC 4291 IPv4-compatible, loopback, et al"
+ le 128
+ prefix ::/8
+ }
+ rule 20 {
+ action permit
+ description "RFC 6666 Discard-Only"
+ le 128
+ prefix 0100::/64
+ }
+ rule 30 {
+ action permit
+ description "RFC 5180 BMWG"
+ le 128
+ prefix 2001:2::/48
+ }
+ rule 40 {
+ action permit
+ description "RFC 4843 ORCHID"
+ le 128
+ prefix 2001:10::/28
+ }
+ rule 50 {
+ action permit
+ description "RFC 3849 documentation"
+ le 128
+ prefix 2001:db8::/32
+ }
+ rule 60 {
+ action permit
+ description "RFC 7526 6to4 anycast relay"
+ le 128
+ prefix 2002::/16
+ }
+ rule 70 {
+ action permit
+ description "RFC 3701 old 6bone"
+ le 128
+ prefix 3ffe::/16
+ }
+ rule 80 {
+ action permit
+ description "RFC 4193 unique local unicast"
+ le 128
+ prefix fc00::/7
+ }
+ rule 90 {
+ action permit
+ description "RFC 4291 link local unicast"
+ le 128
+ prefix fe80::/10
+ }
+ rule 100 {
+ action permit
+ description "RFC 3879 old site local unicast"
+ le 128
+ prefix fec0::/10
+ }
+ rule 110 {
+ action permit
+ description "RFC 4291 multicast"
+ le 128
+ prefix ff00::/8
+ }
+ }
+ prefix-list6 prefix-filter-v6 {
+ rule 10 {
+ action permit
+ ge 49
+ prefix ::/0
+ }
+ }
+ prefix-list6 IX-out-v6 {
+ rule 10 {
+ action permit
+ prefix 2001:db8:100::/40
+ }
+ rule 20 {
+ action permit
+ prefix 2001:db8:200::/40
+ }
+ }
+ route-map eBGP-IN-v4 {
+ rule 10 {
+ action deny
+ match {
+ as-path bogon-asns
+ }
+ }
+ rule 20 {
+ action deny
+ match {
+ ip {
+ address {
+ prefix-list bogon-v4
+ }
+ }
+ }
+ }
+ rule 30 {
+ action deny
+ match {
+ ip {
+ address {
+ prefix-list prefix-filter-v4
+ }
+ }
+ }
+ }
+ rule 40 {
+ action permit
+ set {
+ local-preference 100
+ metric 0
+ }
+ }
+ }
+ route-map eBGP-IN-v6 {
+ rule 10 {
+ action deny
+ match {
+ as-path bogon-asns
+ }
+ }
+ rule 20 {
+ action deny
+ match {
+ ipv6 {
+ address {
+ prefix-list bogon-v6
+ }
+ }
+ }
+ }
+ rule 30 {
+ action deny
+ match {
+ ipv6 {
+ address {
+ prefix-list prefix-filter-v6
+ }
+ }
+ }
+ }
+ rule 40 {
+ action permit
+ set {
+ local-preference 100
+ metric 0
+ }
+ }
+ }
+ route-map IX-in-v4 {
+ rule 5 {
+ action permit
+ call eBGP-IN-v4
+ on-match {
+ next
+ }
+ }
+ rule 10 {
+ action permit
+ }
+ }
+ route-map IX-out-v4 {
+ rule 10 {
+ action permit
+ match {
+ ip {
+ address {
+ prefix-list IX-out-v4
+ }
+ }
+ }
+ }
+ }
+ route-map IX-in-v6 {
+ rule 5 {
+ action permit
+ call eBGP-IN-v6
+ on-match {
+ next
+ }
+ }
+ rule 10 {
+ action permit
+ }
+ }
+ route-map IX-out-v6 {
+ rule 10 {
+ action permit
+ match {
+ ipv6 {
+ address {
+ prefix-list IX-out-v6
+ }
+ }
+ }
+ }
+ }
+}
+protocols {
+ bgp 65000 {
+ address-family {
+ ipv4-unicast {
+ network 10.0.0.0/23 {
+ }
+ network 10.0.128.0/23 {
+ }
+ }
+ ipv6-unicast {
+ network 2001:db8:100::/40 {
+ }
+ network 2001:db8:200::/40 {
+ }
+ }
+ }
+ neighbor 192.0.2.1 {
+ description "Peering: IX-1 (Route Server)"
+ peer-group IXPeeringIPv4
+ remote-as 65020
+ }
+ neighbor 192.0.2.2 {
+ description "Peering: IX-1 (Route Server)"
+ peer-group IXPeeringIPv4
+ remote-as 65020
+ }
+ neighbor 192.0.2.3 {
+ description "Peering: IX-1 (Route Server)"
+ peer-group IXPeeringIPv4
+ remote-as 65020
+ }
+ neighbor 192.0.2.129 {
+ description "Peering: IX-2 (Route Server)"
+ peer-group IXPeeringIPv4
+ remote-as 65030
+ }
+ neighbor 192.0.2.130 {
+ description "Peering: IX-2 (Route Server)"
+ peer-group IXPeeringIPv4
+ remote-as 65030
+ }
+ neighbor 2001:db8:aaaa::1 {
+ description "Peering: IX-1 (Route Server)"
+ peer-group IXPeeringIPv6
+ remote-as 65020
+ }
+ neighbor 2001:db8:aaaa::2 {
+ description "Peering: IX-1 (Route Server)"
+ peer-group IXPeeringIPv6
+ remote-as 65020
+ }
+ neighbor 2001:db8:bbbb::1 {
+ description "Peering: IX-2 (Route Server)"
+ peer-group IXPeeringIPv6
+ remote-as 65030
+ }
+ neighbor 2001:db8:bbbb::2 {
+ description "Peering: IX-2 (Route Server)"
+ peer-group IXPeeringIPv6
+ remote-as 65030
+ }
+ parameters {
+ default {
+ no-ipv4-unicast
+ }
+ }
+ peer-group IXPeeringIPv4 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ export IX-out-v4
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ }
+ peer-group IXPeeringIPv6 {
+ address-family {
+ ipv6-unicast {
+ route-map {
+ export IX-out-v6
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ }
+ }
+ static {
+ route 10.0.0.0/23 {
+ blackhole {
+ distance 250
+ }
+ }
+ route 10.0.128.0/23 {
+ blackhole {
+ distance 250
+ }
+ }
+ route6 2001:db8:100::/40 {
+ blackhole {
+ distance 250
+ }
+ }
+ route6 2001:db8:200::/40 {
+ blackhole {
+ distance 250
+ }
+ }
+ }
+}
+service {
+ ssh {
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/
+ plaintext-password ""
+ }
+ }
+ }
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+}
+
+
+// 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@13:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@6:salt@1:snmp@2:ssh@2:sstp@3:system@19:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webgui@1:webproxy@2:zone-policy@1"
+// Release version: 1.3-rolling-202010241631
diff --git a/smoketest/configs/dialup-router-complex b/smoketest/configs/dialup-router-complex
new file mode 100644
index 000000000..fef79ea56
--- /dev/null
+++ b/smoketest/configs/dialup-router-complex
@@ -0,0 +1,1662 @@
+firewall {
+ all-ping enable
+ broadcast-ping disable
+ config-trap disable
+ group {
+ address-group MEDIA-STREAMING-CLIENTS {
+ address 172.16.35.241
+ address 172.16.35.242
+ address 172.16.35.243
+ }
+ address-group DMZ-WEBSERVER {
+ address 172.16.36.10
+ address 172.16.36.40
+ address 172.16.36.20
+ }
+ address-group DMZ-RDP-SERVER {
+ address 172.16.33.40
+ }
+ address-group DOMAIN-CONTROLLER {
+ address 172.16.100.10
+ address 172.16.100.20
+ }
+ address-group AUDIO-STREAM {
+ address 172.16.35.20
+ address 172.16.35.21
+ address 172.16.35.22
+ address 172.16.35.23
+ }
+ ipv6-network-group LOCAL-ADDRESSES {
+ network ff02::/64
+ network fe80::/10
+ }
+ network-group SSH-IN-ALLOW {
+ network 192.0.2.0/24
+ network 10.0.0.0/8
+ network 172.16.0.0/12
+ network 192.168.0.0/16
+ }
+ port-group SMART-TV-PORTS {
+ port 5005-5006
+ port 80
+ port 443
+ port 3722
+ }
+ }
+ ipv6-name ALLOW-ALL-6 {
+ default-action accept
+ }
+ ipv6-name ALLOW-BASIC-6 {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ state {
+ invalid enable
+ }
+ }
+ rule 10 {
+ action accept
+ protocol icmpv6
+ }
+ }
+ ipv6-name ALLOW-ESTABLISHED-6 {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ state {
+ invalid enable
+ }
+ }
+ rule 10 {
+ action accept
+ destination {
+ group {
+ network-group LOCAL-ADDRESSES
+ }
+ }
+ protocol icmpv6
+ source {
+ address fe80::/10
+ }
+ }
+ rule 20 {
+ action accept
+ icmpv6 {
+ type echo-request
+ }
+ protocol icmpv6
+ }
+ rule 21 {
+ action accept
+ icmpv6 {
+ type destination-unreachable
+ }
+ protocol icmpv6
+ }
+ rule 22 {
+ action accept
+ icmpv6 {
+ type packet-too-big
+ }
+ protocol icmpv6
+ }
+ rule 23 {
+ action accept
+ icmpv6 {
+ type time-exceeded
+ }
+ protocol icmpv6
+ }
+ rule 24 {
+ action accept
+ icmpv6 {
+ type parameter-problem
+ }
+ protocol icmpv6
+ }
+ }
+ ipv6-name WAN-LOCAL-6 {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ state {
+ invalid enable
+ }
+ }
+ rule 10 {
+ action accept
+ destination {
+ address ff02::/64
+ }
+ protocol icmpv6
+ source {
+ address fe80::/10
+ }
+ }
+ rule 50 {
+ action accept
+ description DHCPv6
+ destination {
+ address fe80::/10
+ port 546
+ }
+ protocol udp
+ source {
+ address fe80::/10
+ port 547
+ }
+ }
+ }
+ ipv6-receive-redirects disable
+ ipv6-src-route disable
+ ip-src-route disable
+ log-martians enable
+ name DMZ-GUEST {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ }
+ name DMZ-LAN {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 100 {
+ action accept
+ description "NTP and LDAP to AD DC"
+ destination {
+ group {
+ address-group DOMAIN-CONTROLLER
+ }
+ port 123,389,636
+ }
+ protocol tcp_udp
+ }
+ rule 300 {
+ action accept
+ destination {
+ group {
+ address-group DMZ-RDP-SERVER
+ }
+ port 3389
+ }
+ protocol tcp_udp
+ source {
+ address 172.16.36.20
+ }
+ }
+ }
+ name DMZ-LOCAL {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 50 {
+ action accept
+ destination {
+ address 172.16.254.30
+ port 53
+ }
+ protocol tcp_udp
+ }
+ rule 123 {
+ action accept
+ destination {
+ port 123
+ }
+ protocol udp
+ }
+ }
+ name DMZ-WAN {
+ default-action accept
+ }
+ name GUEST-DMZ {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 100 {
+ action accept
+ destination {
+ port 80,443
+ }
+ protocol tcp
+ }
+ }
+ name GUEST-IOT {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 100 {
+ action accept
+ description "MEDIA-STREAMING-CLIENTS Devices to GUEST"
+ destination {
+ group {
+ address-group MEDIA-STREAMING-CLIENTS
+ }
+ }
+ protocol tcp_udp
+ }
+ rule 110 {
+ action accept
+ description "AUDIO-STREAM Devices to GUEST"
+ destination {
+ group {
+ address-group AUDIO-STREAM
+ }
+ }
+ protocol tcp_udp
+ }
+ rule 200 {
+ action accept
+ description "MCAST relay"
+ destination {
+ address 224.0.0.251
+ port 5353
+ }
+ protocol udp
+ }
+ rule 300 {
+ action accept
+ description "BCAST relay"
+ destination {
+ port 1900
+ }
+ protocol udp
+ }
+ }
+ name GUEST-LAN {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ }
+ name GUEST-LOCAL {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 10 {
+ action accept
+ description DNS
+ destination {
+ address 172.31.0.254
+ port 53
+ }
+ protocol tcp_udp
+ }
+ rule 11 {
+ action accept
+ description DHCP
+ destination {
+ port 67
+ }
+ protocol udp
+ }
+ rule 15 {
+ action accept
+ destination {
+ address 172.31.0.254
+ }
+ protocol icmp
+ }
+ rule 200 {
+ action accept
+ description "MCAST relay"
+ destination {
+ address 224.0.0.251
+ port 5353
+ }
+ protocol udp
+ }
+ rule 210 {
+ action accept
+ description "AUDIO-STREAM Broadcast"
+ destination {
+ port 1900
+ }
+ protocol udp
+ }
+ }
+ name GUEST-WAN {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 25 {
+ action accept
+ description SMTP
+ destination {
+ port 25,587
+ }
+ protocol tcp
+ }
+ rule 53 {
+ action accept
+ destination {
+ port 53
+ }
+ protocol tcp_udp
+ }
+ rule 60 {
+ action accept
+ source {
+ address 172.31.0.200
+ }
+ }
+ rule 80 {
+ action accept
+ source {
+ address 172.31.0.200
+ }
+ }
+ rule 100 {
+ action accept
+ protocol icmp
+ }
+ rule 110 {
+ action accept
+ description POP3
+ destination {
+ port 110,995
+ }
+ protocol tcp
+ }
+ rule 123 {
+ action accept
+ description "NTP Client"
+ destination {
+ port 123
+ }
+ protocol udp
+ }
+ rule 143 {
+ action accept
+ description IMAP
+ destination {
+ port 143,993
+ }
+ protocol tcp
+ }
+ rule 200 {
+ action accept
+ destination {
+ port 80,443
+ }
+ protocol tcp
+ }
+ rule 500 {
+ action accept
+ description "L2TP IPSec"
+ destination {
+ port 500,4500
+ }
+ protocol udp
+ }
+ rule 600 {
+ action accept
+ destination {
+ port 5222-5224
+ }
+ protocol tcp
+ }
+ rule 601 {
+ action accept
+ destination {
+ port 3478-3497,4500,16384-16387,16393-16402
+ }
+ protocol udp
+ }
+ rule 1000 {
+ action accept
+ source {
+ address 172.31.0.184
+ }
+ }
+ }
+ name IOT-GUEST {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 100 {
+ action accept
+ description "MEDIA-STREAMING-CLIENTS Devices to IOT"
+ protocol tcp_udp
+ source {
+ group {
+ address-group MEDIA-STREAMING-CLIENTS
+ }
+ }
+ }
+ rule 110 {
+ action accept
+ description "AUDIO-STREAM Devices to IOT"
+ protocol tcp_udp
+ source {
+ group {
+ address-group AUDIO-STREAM
+ }
+ }
+ }
+ rule 200 {
+ action accept
+ description "MCAST relay"
+ destination {
+ address 224.0.0.251
+ port 5353
+ }
+ protocol udp
+ }
+ rule 300 {
+ action accept
+ description "BCAST relay"
+ destination {
+ port 1900
+ }
+ protocol udp
+ }
+ }
+ name IOT-LAN {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 100 {
+ action accept
+ description "AppleTV to LAN"
+ destination {
+ group {
+ port-group SMART-TV-PORTS
+ }
+ }
+ protocol tcp_udp
+ source {
+ group {
+ address-group MEDIA-STREAMING-CLIENTS
+ }
+ }
+ }
+ rule 110 {
+ action accept
+ description "AUDIO-STREAM Devices to LAN"
+ protocol tcp_udp
+ source {
+ group {
+ address-group AUDIO-STREAM
+ }
+ }
+ }
+ }
+ name IOT-LOCAL {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 10 {
+ action accept
+ description DNS
+ destination {
+ address 172.16.254.30
+ port 53
+ }
+ protocol tcp_udp
+ }
+ rule 11 {
+ action accept
+ description DHCP
+ destination {
+ port 67
+ }
+ protocol udp
+ }
+ rule 15 {
+ action accept
+ destination {
+ address 172.16.35.254
+ }
+ protocol icmp
+ }
+ rule 200 {
+ action accept
+ description "MCAST relay"
+ destination {
+ address 224.0.0.251
+ port 5353
+ }
+ protocol udp
+ }
+ rule 201 {
+ action accept
+ description "MCAST relay"
+ destination {
+ address 172.16.35.254
+ port 5353
+ }
+ protocol udp
+ }
+ rule 210 {
+ action accept
+ description "AUDIO-STREAM Broadcast"
+ destination {
+ port 1900,1902,6969
+ }
+ protocol udp
+ }
+ }
+ name IOT-WAN {
+ default-action accept
+ }
+ name LAN-DMZ {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 22 {
+ action accept
+ description "SSH into DMZ"
+ destination {
+ port 22
+ }
+ protocol tcp
+ }
+ rule 100 {
+ action accept
+ destination {
+ group {
+ address-group DMZ-WEBSERVER
+ }
+ port 22,80,443
+ }
+ protocol tcp
+ }
+ }
+ name LAN-GUEST {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ }
+ name LAN-IOT {
+ default-action accept
+ }
+ name LAN-LOCAL {
+ default-action accept
+ }
+ name LAN-WAN {
+ default-action accept
+ }
+ name LOCAL-DMZ {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ }
+ name LOCAL-GUEST {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 5 {
+ action accept
+ protocol icmp
+ }
+ rule 200 {
+ action accept
+ description "MCAST relay"
+ destination {
+ address 224.0.0.251
+ port 5353
+ }
+ protocol udp
+ }
+ rule 300 {
+ action accept
+ description "BCAST relay"
+ destination {
+ port 1900
+ }
+ protocol udp
+ }
+ }
+ name LOCAL-IOT {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 5 {
+ action accept
+ protocol icmp
+ }
+ rule 200 {
+ action accept
+ description "MCAST relay"
+ destination {
+ address 224.0.0.251
+ port 5353
+ }
+ protocol udp
+ }
+ rule 300 {
+ action accept
+ description "BCAST relay"
+ destination {
+ port 1900,6969
+ }
+ protocol udp
+ }
+ }
+ name LOCAL-LAN {
+ default-action accept
+ }
+ name LOCAL-WAN {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 10 {
+ action accept
+ protocol icmp
+ }
+ rule 50 {
+ action accept
+ description DNS
+ destination {
+ port 53
+ }
+ protocol tcp_udp
+ }
+ rule 80 {
+ action accept
+ destination {
+ port 80,443
+ }
+ protocol tcp
+ }
+ rule 123 {
+ action accept
+ description NTP
+ destination {
+ port 123
+ }
+ protocol udp
+ }
+ }
+ name WAN-DMZ {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 100 {
+ action accept
+ destination {
+ address 172.16.36.10
+ port 80,443
+ }
+ protocol tcp
+ }
+ }
+ name WAN-GUEST {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 1000 {
+ action accept
+ destination {
+ address 172.31.0.184
+ }
+ }
+ rule 8000 {
+ action accept
+ destination {
+ address 172.31.0.200
+ port 10000
+ }
+ protocol udp
+ }
+ }
+ name WAN-IOT {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ }
+ name WAN-LAN {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 1000 {
+ action accept
+ destination {
+ address 172.16.33.40
+ port 3389
+ }
+ protocol tcp
+ source {
+ group {
+ network-group SSH-IN-ALLOW
+ }
+ }
+ }
+ }
+ name WAN-LOCAL {
+ default-action drop
+ enable-default-log
+ rule 1 {
+ action accept
+ state {
+ established enable
+ related enable
+ }
+ }
+ rule 2 {
+ action drop
+ log enable
+ state {
+ invalid enable
+ }
+ }
+ rule 22 {
+ action accept
+ destination {
+ port 22
+ }
+ protocol tcp
+ source {
+ group {
+ network-group SSH-IN-ALLOW
+ }
+ }
+ }
+ }
+ options {
+ interface pppoe0 {
+ adjust-mss 1452
+ adjust-mss6 1432
+ }
+ }
+ receive-redirects disable
+ send-redirects enable
+ source-validation disable
+ syn-cookies enable
+ twa-hazards-protection disable
+}
+interfaces {
+ dummy dum0 {
+ address 172.16.254.30/32
+ }
+ ethernet eth0 {
+ duplex auto
+ speed auto
+ vif 5 {
+ address 172.16.37.254/24
+ }
+ vif 10 {
+ address 172.16.33.254/24
+ }
+ vif 20 {
+ address 172.31.0.254/24
+ }
+ vif 35 {
+ address 172.16.35.254/24
+ }
+ vif 50 {
+ address 172.16.36.254/24
+ }
+ vif 100 {
+ address 172.16.100.254/24
+ }
+ vif 201 {
+ address 172.18.201.254/24
+ }
+ vif 202 {
+ address 172.18.202.254/24
+ }
+ vif 203 {
+ address 172.18.203.254/24
+ }
+ vif 204 {
+ address 172.18.204.254/24
+ }
+ }
+ ethernet eth1 {
+ vif 7 {
+ description FTTH-PPPoE
+ }
+ }
+ loopback lo {
+ address 172.16.254.30/32
+ }
+ pppoe pppoe0 {
+ authentication {
+ password vyos
+ user vyos
+ }
+ default-route auto
+ description "FTTH 100/50MBit"
+ dhcpv6-options {
+ pd 0 {
+ interface eth0.10 {
+ address 1
+ sla-id 10
+ }
+ interface eth0.20 {
+ address 1
+ sla-id 20
+ }
+ length 56
+ }
+ }
+ ipv6 {
+ address {
+ autoconf
+ }
+ }
+ mtu 1492
+ no-peer-dns
+ source-interface eth1.7
+ }
+}
+nat {
+ destination {
+ rule 100 {
+ description HTTP(S)
+ destination {
+ port 80,443
+ }
+ inbound-interface pppoe0
+ log
+ protocol tcp
+ translation {
+ address 172.16.36.10
+ }
+ }
+ rule 1000 {
+ destination {
+ port 3389
+ }
+ disable
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 172.16.33.40
+ }
+ }
+ rule 8000 {
+ destination {
+ port 10000
+ }
+ inbound-interface pppoe0
+ log
+ protocol udp
+ translation {
+ address 172.31.0.200
+ }
+ }
+ }
+ source {
+ rule 100 {
+ log
+ outbound-interface pppoe0
+ source {
+ address 172.16.32.0/19
+ }
+ translation {
+ address masquerade
+ }
+ }
+ rule 200 {
+ outbound-interface pppoe0
+ source {
+ address 172.16.100.0/24
+ }
+ translation {
+ address masquerade
+ }
+ }
+ rule 300 {
+ outbound-interface pppoe0
+ source {
+ address 172.31.0.0/24
+ }
+ translation {
+ address masquerade
+ }
+ }
+ rule 400 {
+ outbound-interface pppoe0
+ source {
+ address 172.18.200.0/21
+ }
+ translation {
+ address masquerade
+ }
+ }
+ }
+}
+protocols {
+ static {
+ interface-route6 2000::/3 {
+ next-hop-interface pppoe0 {
+ }
+ }
+ route 10.0.0.0/8 {
+ blackhole {
+ distance 254
+ }
+ }
+ route 169.254.0.0/16 {
+ blackhole {
+ distance 254
+ }
+ }
+ route 172.16.0.0/12 {
+ blackhole {
+ distance 254
+ }
+ }
+ route 192.168.0.0/16 {
+ blackhole {
+ distance 254
+ }
+ }
+ }
+}
+service {
+ dhcp-server {
+ shared-network-name BACKBONE {
+ authoritative
+ subnet 172.16.37.0/24 {
+ default-router 172.16.37.254
+ dns-server 172.16.254.30
+ domain-name vyos.net
+ domain-search vyos.net
+ lease 86400
+ ntp-server 172.16.254.30
+ range 0 {
+ start 172.16.37.120
+ stop 172.16.37.149
+ }
+ static-mapping AP1.wue3 {
+ ip-address 172.16.37.231
+ mac-address 18:e8:29:6c:c3:a5
+ }
+ }
+ }
+ shared-network-name GUEST {
+ authoritative
+ subnet 172.31.0.0/24 {
+ default-router 172.31.0.254
+ dns-server 172.31.0.254
+ domain-name vyos.net
+ domain-search vyos.net
+ lease 86400
+ range 0 {
+ start 172.31.0.100
+ stop 172.31.0.199
+ }
+ static-mapping host01 {
+ ip-address 172.31.0.200
+ mac-address 00:50:00:00:00:01
+ }
+ static-mapping host02 {
+ ip-address 172.31.0.184
+ mac-address 00:50:00:00:00:02
+ }
+ }
+ }
+ shared-network-name IOT {
+ authoritative
+ subnet 172.16.35.0/24 {
+ default-router 172.16.35.254
+ dns-server 172.16.254.30
+ domain-name vyos.net
+ domain-search vyos.net
+ lease 86400
+ ntp-server 172.16.254.30
+ range 0 {
+ start 172.16.35.101
+ stop 172.16.35.149
+ }
+ }
+ }
+ shared-network-name LAN {
+ authoritative
+ subnet 172.16.33.0/24 {
+ default-router 172.16.33.254
+ dns-server 172.16.254.30
+ domain-name vyos.net
+ domain-search vyos.net
+ lease 86400
+ ntp-server 172.16.254.30
+ range 0 {
+ start 172.16.33.100
+ stop 172.16.33.189
+ }
+ }
+ }
+ }
+ dns {
+ forwarding {
+ allow-from 172.16.0.0/12
+ cache-size 0
+ domain 16.172.in-addr.arpa {
+ addnta
+ recursion-desired
+ server 172.16.100.10
+ server 172.16.100.20
+ server 172.16.110.30
+ }
+ domain 18.172.in-addr.arpa {
+ addnta
+ recursion-desired
+ server 172.16.100.10
+ server 172.16.100.20
+ server 172.16.110.30
+ }
+ domain vyos.net {
+ addnta
+ recursion-desired
+ server 172.16.100.20
+ server 172.16.100.10
+ server 172.16.110.30
+ }
+ ignore-hosts-file
+ listen-address 172.16.254.30
+ listen-address 172.31.0.254
+ negative-ttl 60
+ }
+ }
+ lldp {
+ legacy-protocols {
+ cdp
+ }
+ snmp {
+ enable
+ }
+ }
+ mdns {
+ repeater {
+ interface eth0.35
+ interface eth0.10
+ }
+ }
+ router-advert {
+ interface eth0.10 {
+ prefix ::/64 {
+ preferred-lifetime 2700
+ valid-lifetime 5400
+ }
+ }
+ interface eth0.20 {
+ prefix ::/64 {
+ preferred-lifetime 2700
+ valid-lifetime 5400
+ }
+ }
+ }
+ snmp {
+ community fooBar {
+ authorization ro
+ network 172.16.100.0/24
+ }
+ contact "VyOS maintainers and contributors <maintainers@vyos.io>"
+ listen-address 172.16.254.30 {
+ port 161
+ }
+ location "The Internet"
+ }
+ ssh {
+ disable-host-validation
+ port 22
+ }
+}
+system {
+ config-management {
+ commit-revisions 200
+ }
+ conntrack {
+ expect-table-size 2048
+ hash-size 32768
+ modules {
+ sip {
+ disable
+ }
+ }
+ table-size 262144
+ timeout {
+ icmp 30
+ other 600
+ udp {
+ other 300
+ stream 300
+ }
+ }
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ domain-name vyos.net
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/
+ plaintext-password ""
+ }
+ }
+ }
+ name-server 172.16.254.30
+ ntp {
+ allow-clients {
+ address 172.16.0.0/12
+ }
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ option {
+ ctrl-alt-delete ignore
+ reboot-on-panic
+ startup-beep
+ }
+ syslog {
+ global {
+ facility all {
+ level debug
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ host 172.16.100.1 {
+ facility all {
+ level warning
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+traffic-policy {
+ shaper QoS {
+ bandwidth 50mbit
+ default {
+ bandwidth 100%
+ burst 15k
+ queue-limit 1000
+ queue-type fq-codel
+ }
+ }
+}
+zone-policy {
+ zone DMZ {
+ default-action drop
+ from GUEST {
+ firewall {
+ name GUEST-DMZ
+ }
+ }
+ from LAN {
+ firewall {
+ name LAN-DMZ
+ }
+ }
+ from LOCAL {
+ firewall {
+ name LOCAL-DMZ
+ }
+ }
+ from WAN {
+ firewall {
+ name WAN-DMZ
+ }
+ }
+ interface eth0.50
+ }
+ zone GUEST {
+ default-action drop
+ from DMZ {
+ firewall {
+ name DMZ-GUEST
+ }
+ }
+ from IOT {
+ firewall {
+ name IOT-GUEST
+ }
+ }
+ from LAN {
+ firewall {
+ name LAN-GUEST
+ }
+ }
+ from LOCAL {
+ firewall {
+ ipv6-name ALLOW-ALL-6
+ name LOCAL-GUEST
+ }
+ }
+ from WAN {
+ firewall {
+ ipv6-name ALLOW-ESTABLISHED-6
+ name WAN-GUEST
+ }
+ }
+ interface eth0.20
+ }
+ zone IOT {
+ default-action drop
+ from GUEST {
+ firewall {
+ name GUEST-IOT
+ }
+ }
+ from LAN {
+ firewall {
+ name LAN-IOT
+ }
+ }
+ from LOCAL {
+ firewall {
+ name LOCAL-IOT
+ }
+ }
+ from WAN {
+ firewall {
+ name WAN-IOT
+ }
+ }
+ interface eth0.35
+ }
+ zone LAN {
+ default-action drop
+ from DMZ {
+ firewall {
+ name DMZ-LAN
+ }
+ }
+ from GUEST {
+ firewall {
+ name GUEST-LAN
+ }
+ }
+ from IOT {
+ firewall {
+ name IOT-LAN
+ }
+ }
+ from LOCAL {
+ firewall {
+ ipv6-name ALLOW-ALL-6
+ name LOCAL-LAN
+ }
+ }
+ from WAN {
+ firewall {
+ ipv6-name ALLOW-ESTABLISHED-6
+ name WAN-LAN
+ }
+ }
+ interface eth0.5
+ interface eth0.10
+ interface eth0.100
+ interface eth0.201
+ interface eth0.202
+ interface eth0.203
+ interface eth0.204
+ }
+ zone LOCAL {
+ default-action drop
+ from DMZ {
+ firewall {
+ name DMZ-LOCAL
+ }
+ }
+ from GUEST {
+ firewall {
+ ipv6-name ALLOW-ESTABLISHED-6
+ name GUEST-LOCAL
+ }
+ }
+ from IOT {
+ firewall {
+ name IOT-LOCAL
+ }
+ }
+ from LAN {
+ firewall {
+ ipv6-name ALLOW-ALL-6
+ name LAN-LOCAL
+ }
+ }
+ from WAN {
+ firewall {
+ ipv6-name WAN-LOCAL-6
+ name WAN-LOCAL
+ }
+ }
+ local-zone
+ }
+ zone WAN {
+ default-action drop
+ from DMZ {
+ firewall {
+ name DMZ-WAN
+ }
+ }
+ from GUEST {
+ firewall {
+ ipv6-name ALLOW-ALL-6
+ name GUEST-WAN
+ }
+ }
+ from IOT {
+ firewall {
+ name IOT-WAN
+ }
+ }
+ from LAN {
+ firewall {
+ ipv6-name ALLOW-ALL-6
+ name LAN-WAN
+ }
+ }
+ from LOCAL {
+ firewall {
+ ipv6-name ALLOW-ALL-6
+ name LOCAL-WAN
+ }
+ }
+ interface pppoe0
+ }
+}
+
+
+// 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@6: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-beta-202101091250
diff --git a/smoketest/configs/dialup-router-medium-vpn b/smoketest/configs/dialup-router-medium-vpn
new file mode 100644
index 000000000..dfb3d9621
--- /dev/null
+++ b/smoketest/configs/dialup-router-medium-vpn
@@ -0,0 +1,707 @@
+firewall {
+ all-ping enable
+ broadcast-ping disable
+ config-trap disable
+ ipv6-receive-redirects disable
+ ipv6-src-route disable
+ ip-src-route disable
+ log-martians enable
+ options {
+ interface vtun0 {
+ adjust-mss 1380
+ }
+ interface vtun1 {
+ adjust-mss 1380
+ }
+ interface vtun2 {
+ adjust-mss 1380
+ }
+ interface wg0 {
+ adjust-mss 1380
+ }
+ interface wg1 {
+ adjust-mss 1380
+ }
+ }
+ receive-redirects disable
+ send-redirects enable
+ source-validation disable
+ syn-cookies disable
+ twa-hazards-protection enable
+}
+high-availability {
+ vrrp {
+ group LAN {
+ hello-source-address 192.168.0.250
+ interface eth1
+ peer-address 192.168.0.251
+ priority 200
+ virtual-address 192.168.0.1/24
+ vrid 1
+ }
+ sync-group failover-group {
+ member LAN
+ }
+ }
+}
+interfaces {
+ ethernet eth0 {
+ duplex auto
+ mtu 9000
+ offload-options {
+ generic-receive on
+ generic-segmentation on
+ scatter-gather on
+ tcp-segmentation on
+ }
+ pppoe 0 {
+ default-route auto
+ mtu 1500
+ name-server auto
+ password password
+ traffic-policy {
+ out shape-17mbit
+ }
+ user-id vyos
+ password vyos
+ }
+ smp-affinity auto
+ speed auto
+ }
+ ethernet eth1 {
+ address 192.168.0.250/24
+ duplex auto
+ ip {
+ source-validation strict
+ }
+ mtu 9000
+ offload-options {
+ generic-receive on
+ generic-segmentation on
+ scatter-gather on
+ tcp-segmentation on
+ }
+ policy {
+ route LAN-POLICY-BASED-ROUTING
+ }
+ smp-affinity auto
+ speed auto
+ traffic-policy {
+ out shape-94mbit
+ }
+ }
+ loopback lo {
+ }
+ openvpn vtun0 {
+ encryption aes256
+ hash sha512
+ ip {
+ source-validation strict
+ }
+ keep-alive {
+ failure-count 3
+ interval 30
+ }
+ mode client
+ openvpn-option "comp-lzo adaptive"
+ openvpn-option fast-io
+ openvpn-option persist-key
+ openvpn-option "reneg-sec 86400"
+ persistent-tunnel
+ remote-host 192.0.2.10
+ tls {
+ ca-cert-file /config/auth/ovpn_test_ca.pem
+ cert-file /config/auth/ovpn_test_server.pem
+ key-file /config/auth/ovpn_test_server.key
+ auth-file /config/auth/ovpn_test_tls_auth.key
+ }
+ }
+ openvpn vtun1 {
+ authentication {
+ password vyos1
+ username vyos1
+ }
+ encryption aes256
+ hash sha1
+ keep-alive {
+ failure-count 3
+ interval 30
+ }
+ mode client
+ openvpn-option "comp-lzo adaptive"
+ openvpn-option "tun-mtu 1500"
+ openvpn-option "tun-mtu-extra 32"
+ openvpn-option "mssfix 1300"
+ openvpn-option persist-key
+ openvpn-option "mute 10"
+ openvpn-option route-nopull
+ openvpn-option fast-io
+ openvpn-option "reneg-sec 86400"
+ persistent-tunnel
+ protocol udp
+ remote-host 01.foo.com
+ remote-port 1194
+ tls {
+ ca-cert-file /config/auth/ovpn_test_ca.pem
+ auth-file /config/auth/ovpn_test_tls_auth.key
+ }
+ }
+ openvpn vtun2 {
+ authentication {
+ password vyos2
+ username vyos2
+ }
+ disable
+ encryption aes256
+ hash sha512
+ keep-alive {
+ failure-count 3
+ interval 30
+ }
+ mode client
+ openvpn-option "tun-mtu 1500"
+ openvpn-option "tun-mtu-extra 32"
+ openvpn-option "mssfix 1300"
+ openvpn-option persist-key
+ openvpn-option "mute 10"
+ openvpn-option route-nopull
+ openvpn-option fast-io
+ openvpn-option remote-random
+ openvpn-option "reneg-sec 86400"
+ persistent-tunnel
+ protocol udp
+ remote-host 01.myvpn.com
+ remote-host 02.myvpn.com
+ remote-host 03.myvpn.com
+ remote-port 1194
+ tls {
+ ca-cert-file /config/auth/ovpn_test_ca.pem
+ auth-file /config/auth/ovpn_test_tls_auth.key
+ }
+ }
+ wireguard wg0 {
+ address 192.168.10.1/24
+ peer red {
+ allowed-ips 192.168.10.4/32
+ persistent-keepalive 20
+ preshared-key CumyXX7osvUT9AwnS+m2TEfCaL0Ptc2LfuZ78Sujuk8=
+ pubkey ALGWvMJCKpHF2tVH3hEIHqUe9iFfAmZATUUok/WQzks=
+ }
+ peer green {
+ allowed-ips 192.168.10.21/32
+ persistent-keepalive 25
+ preshared-key LQ9qmlTh9G4nZu4UgElxRUwg7JB/qoV799aADJOijnY=
+ pubkey 5iQUD3VoCDBTPXAPHOwUJ0p7xzKGHEY/wQmgvBVmaFI=
+ }
+ peer blue {
+ allowed-ips 192.168.10.3/32
+ persistent-keepalive 20
+ preshared-key ztFDOY9UyaDvn8N3X97SFMDwIfv7EEfuUIPP2yab6UI=
+ pubkey G4pZishpMRrLmd96Kr6V7LIuNGdcUb81gWaYZ+FWkG0=
+ }
+ peer pink {
+ allowed-ips 192.168.10.14/32
+ allowed-ips 192.168.10.16/32
+ persistent-keepalive 25
+ preshared-key Qi9Odyx0/5itLPN5C5bEy3uMX+tmdl15QbakxpKlWqQ=
+ pubkey i4qNPmxyy9EETL4tIoZOLKJF4p7IlVmpAE15gglnAk4=
+ }
+ port 7777
+ }
+ wireguard wg1 {
+ address 10.89.90.2/30
+ peer sam {
+ allowed-ips 10.1.1.0/24
+ allowed-ips 10.89.90.1/32
+ endpoint 192.0.2.45:1200
+ persistent-keepalive 20
+ preshared-key XpFtzx2Z+nR8pBv9/sSf7I94OkZkVYTz0AeU5Q/QQUE=
+ pubkey v5zfKGvH6W/lfDXJ0en96lvKo1gfFxMUWxe02+Fj5BU=
+ }
+ port 7778
+ }
+}
+nat {
+ destination {
+ rule 50 {
+ destination {
+ port 49371
+ }
+ inbound-interface pppoe0
+ protocol tcp_udp
+ translation {
+ address 192.168.0.5
+ }
+ }
+ rule 51 {
+ destination {
+ port 58050-58051
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.5
+ }
+ }
+ rule 52 {
+ destination {
+ port 22067-22070
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.5
+ }
+ }
+ rule 53 {
+ destination {
+ port 34342
+ }
+ inbound-interface pppoe0
+ protocol tcp_udp
+ translation {
+ address 192.168.0.121
+ }
+ }
+ rule 54 {
+ destination {
+ port 45459
+ }
+ inbound-interface pppoe0
+ protocol tcp_udp
+ translation {
+ address 192.168.0.120
+ }
+ }
+ rule 55 {
+ destination {
+ port 22
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.5
+ }
+ }
+ rule 56 {
+ destination {
+ port 8920
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.5
+ }
+ }
+ rule 60 {
+ destination {
+ port 80,443
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.5
+ }
+ }
+ rule 70 {
+ destination {
+ port 5001
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.5
+ }
+ }
+ rule 80 {
+ destination {
+ port 25
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.5
+ }
+ }
+ rule 90 {
+ destination {
+ port 8123
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.7
+ }
+ }
+ rule 91 {
+ destination {
+ port 1880
+ }
+ inbound-interface pppoe0
+ protocol tcp
+ translation {
+ address 192.168.0.7
+ }
+ }
+ rule 500 {
+ destination {
+ address !192.168.0.0/24
+ port 53
+ }
+ inbound-interface eth1
+ protocol tcp_udp
+ source {
+ address !192.168.0.1-192.168.0.5
+ }
+ translation {
+ address 192.168.0.1
+ }
+ }
+ }
+ source {
+ rule 1000 {
+ outbound-interface pppoe0
+ translation {
+ address masquerade
+ }
+ }
+ rule 2000 {
+ outbound-interface vtun0
+ source {
+ address 192.168.0.0/16
+ }
+ translation {
+ address masquerade
+ }
+ }
+ rule 3000 {
+ outbound-interface vtun1
+ translation {
+ address masquerade
+ }
+ }
+ }
+}
+policy {
+ prefix-list user2-routes {
+ rule 1 {
+ action permit
+ prefix 10.1.1.0/24
+ }
+ }
+ prefix-list user1-routes {
+ rule 1 {
+ action permit
+ prefix 192.168.0.0/24
+ }
+ }
+ route LAN-POLICY-BASED-ROUTING {
+ rule 10 {
+ destination {
+ }
+ disable
+ set {
+ table 10
+ }
+ source {
+ address 192.168.0.119/32
+ }
+ }
+ rule 20 {
+ destination {
+ }
+ set {
+ table 100
+ }
+ source {
+ address 192.168.0.240
+ }
+ }
+ }
+ route-map rm-static-to-bgp {
+ rule 10 {
+ action permit
+ match {
+ ip {
+ address {
+ prefix-list user1-routes
+ }
+ }
+ }
+ }
+ rule 100 {
+ action deny
+ }
+ }
+}
+protocols {
+ bgp 64590 {
+ address-family {
+ ipv4-unicast {
+ redistribute {
+ connected {
+ route-map rm-static-to-bgp
+ }
+ }
+ }
+ }
+ neighbor 10.89.90.1 {
+ address-family {
+ ipv4-unicast {
+ nexthop-self
+ prefix-list {
+ export user1-routes
+ import user2-routes
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ password ericandre2020
+ remote-as 64589
+ }
+ parameters {
+ log-neighbor-changes
+ router-id 10.89.90.2
+ }
+ }
+ static {
+ interface-route 100.64.160.23/32 {
+ next-hop-interface pppoe0 {
+ }
+ }
+ interface-route 100.64.165.25/32 {
+ next-hop-interface pppoe0 {
+ }
+ }
+ interface-route 100.64.165.26/32 {
+ next-hop-interface pppoe0 {
+ }
+ }
+ interface-route 100.64.198.0/24 {
+ next-hop-interface vtun0 {
+ }
+ }
+ table 10 {
+ interface-route 0.0.0.0/0 {
+ next-hop-interface vtun1 {
+ }
+ }
+ }
+ table 100 {
+ route 0.0.0.0/0 {
+ next-hop 192.168.10.5 {
+ }
+ }
+ }
+ }
+}
+service {
+ conntrack-sync {
+ accept-protocol tcp,udp,icmp
+ disable-external-cache
+ event-listen-queue-size 8
+ expect-sync all
+ failover-mechanism {
+ vrrp {
+ sync-group failover-group
+ }
+ }
+ interface eth1 {
+ peer 192.168.0.251
+ }
+ sync-queue-size 8
+ }
+ dhcp-server {
+ shared-network-name LAN {
+ authoritative
+ subnet 192.168.0.0/24 {
+ default-router 192.168.0.1
+ dns-server 192.168.0.1
+ domain-name vyos.net
+ domain-search vyos.net
+ failover {
+ local-address 192.168.0.250
+ name DHCP02
+ peer-address 192.168.0.251
+ status primary
+ }
+ lease 86400
+ range LANDynamic {
+ start 192.168.0.200
+ stop 192.168.0.240
+ }
+ static-mapping IPTV {
+ ip-address 192.168.0.104
+ mac-address 00:50:01:31:b5:f6
+ }
+ static-mapping McPrintus {
+ ip-address 192.168.0.60
+ mac-address 00:50:01:58:ac:95
+ static-mapping-parameters "option domain-name-servers 192.168.0.6,192.168.0.17;"
+ }
+ static-mapping Audio {
+ ip-address 192.168.0.107
+ mac-address 00:50:01:dc:91:14
+ }
+ static-mapping Mobile01 {
+ ip-address 192.168.0.109
+ mac-address 00:50:01:bc:ac:51
+ static-mapping-parameters "option domain-name-servers 192.168.0.6,192.168.0.17;"
+ }
+ static-mapping sand {
+ ip-address 192.168.0.110
+ mac-address 00:50:01:af:c5:d2
+ }
+ static-mapping pearTV {
+ ip-address 192.168.0.101
+ mac-address 00:50:01:ba:62:79
+ }
+ static-mapping camera1 {
+ ip-address 192.168.0.11
+ mac-address 00:50:01:70:b9:4d
+ static-mapping-parameters "option domain-name-servers 192.168.0.6,192.168.0.17;"
+ }
+ static-mapping camera2 {
+ ip-address 192.168.0.12
+ mac-address 00:50:01:70:b7:4f
+ static-mapping-parameters "option domain-name-servers 192.168.0.6,192.168.0.17;"
+ }
+ }
+ }
+ }
+ dns {
+ forwarding {
+ allow-from 192.168.0.0/16
+ cache-size 8192
+ dnssec off
+ listen-address 192.168.0.1
+ name-server 100.64.0.1
+ name-server 100.64.0.2
+ }
+ }
+ snmp {
+ community AwesomeCommunity {
+ authorization ro
+ client 127.0.0.1
+ network 192.168.0.0/24
+ }
+ }
+ ssh {
+ access-control {
+ allow {
+ user vyos
+ }
+ }
+ client-keepalive-interval 60
+ listen-address 192.168.0.1
+ listen-address 192.168.10.1
+ listen-address 192.168.0.250
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ ip {
+ arp {
+ table-size 1024
+ }
+ }
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ name-server 192.168.0.1
+ ntp {
+ allow-clients {
+ address 192.168.0.0/16
+ }
+ listen-address 192.168.0.1
+ listen-address 192.168.0.250
+ server nz.pool.ntp.org {
+ prefer
+ }
+ }
+ options {
+ beep-if-fully-booted
+ ctrl-alt-del-action ignore
+ reboot-on-panic true
+ }
+ static-host-mapping {
+ host-name host104.vyos.net {
+ inet 192.168.0.104
+ }
+ host-name host60.vyos.net {
+ inet 192.168.0.60
+ }
+ host-name host107.vyos.net {
+ inet 192.168.0.107
+ }
+ host-name host109.vyos.net {
+ inet 192.168.0.109
+ }
+ }
+ sysctl {
+ custom net.core.default_qdisc {
+ value fq
+ }
+ custom net.ipv4.tcp_congestion_control {
+ value bbr
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ }
+ host 192.168.0.252 {
+ facility all {
+ level debug
+ protocol udp
+ }
+ }
+ }
+ task-scheduler {
+ task Update-Blacklists {
+ executable {
+ path /config/scripts/vyos-foo-update.script
+ }
+ interval 3h
+ }
+ }
+ time-zone Pacific/Auckland
+}
+traffic-policy {
+ shaper shape-17mbit {
+ bandwidth 17mbit
+ default {
+ bandwidth 100%
+ burst 15k
+ queue-type fq-codel
+ }
+ }
+ shaper shape-94mbit {
+ bandwidth 94mbit
+ default {
+ bandwidth 100%
+ burst 15k
+ queue-type fq-codel
+ }
+ }
+}
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
+/* Release version: 1.2.6 */
diff --git a/smoketest/configs/isis-small b/smoketest/configs/isis-small
new file mode 100644
index 000000000..2c42ac9c4
--- /dev/null
+++ b/smoketest/configs/isis-small
@@ -0,0 +1,105 @@
+interfaces {
+ dummy dum0 {
+ address 203.0.113.1/24
+ }
+ ethernet eth0 {
+ duplex auto
+ speed auto
+ }
+ ethernet eth1 {
+ address 192.0.2.1/24
+ duplex auto
+ speed auto
+ }
+ ethernet eth2 {
+ duplex auto
+ speed auto
+ }
+ ethernet eth3 {
+ duplex auto
+ speed auto
+ }
+}
+policy {
+ prefix-list EXPORT-ISIS {
+ rule 10 {
+ action permit
+ prefix 203.0.113.0/24
+ }
+ }
+ route-map EXPORT-ISIS {
+ rule 10 {
+ action permit
+ match {
+ ip {
+ address {
+ prefix-list EXPORT-ISIS
+ }
+ }
+ }
+ }
+ }
+}
+protocols {
+ isis FOO {
+ interface eth1 {
+ bfd
+ }
+ net 49.0001.1921.6800.1002.00
+ redistribute {
+ ipv4 {
+ connected {
+ level-2 {
+ route-map EXPORT-ISIS
+ }
+ }
+ }
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 200
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ domain-name vyos.io
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/
+ plaintext-password ""
+ }
+ level admin
+ }
+ }
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+
+
+// 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
+
diff --git a/smoketest/configs/ospf-small b/smoketest/configs/ospf-small
new file mode 100644
index 000000000..d95ba4ea4
--- /dev/null
+++ b/smoketest/configs/ospf-small
@@ -0,0 +1,142 @@
+interfaces {
+ dummy dum0 {
+ address 172.18.254.201/32
+ }
+ ethernet eth0 {
+ duplex auto
+ smp-affinity auto
+ speed auto
+ vif 201 {
+ address 172.18.201.10/24
+ ip {
+ ospf {
+ authentication {
+ md5 {
+ key-id 10 {
+ md5-key OSPFVyOSNET
+ }
+ }
+ }
+ dead-interval 40
+ hello-interval 10
+ priority 1
+ retransmit-interval 5
+ transmit-delay 1
+ }
+ }
+ ipv6 {
+ ospfv3 {
+ bfd
+ cost 40
+ }
+ }
+ }
+ }
+ ethernet eth1 {
+ duplex auto
+ smp-affinity auto
+ speed auto
+ ipv6 {
+ ospfv3 {
+ bfd
+ cost 60
+ mtu-ignore
+ network broadcast
+ priority 20
+ }
+ }
+ }
+}
+protocols {
+ ospf {
+ area 0 {
+ network 172.18.201.0/24
+ network 172.18.254.201/32
+ }
+ log-adjacency-changes {
+ }
+ parameters {
+ abr-type cisco
+ router-id 172.18.254.201
+ }
+ passive-interface default
+ passive-interface-exclude eth0.201
+ }
+ ospfv3 {
+ area 0.0.0.0 {
+ interface eth0
+ interface eth1
+ interface eth2
+ }
+ }
+ static {
+ route 0.0.0.0/0 {
+ next-hop 172.18.201.254 {
+ distance 10
+ }
+ }
+ }
+}
+service {
+ lldp {
+ interface all {
+ }
+ }
+ snmp {
+ community public {
+ authorization ro
+ network 172.16.100.0/24
+ }
+ contact "VyOS maintainers and contributors <maintainers@vyos.io>"
+ location "Jenkins"
+ }
+ ssh {
+ disable-host-validation
+ port 22
+ }
+}
+system {
+ config-management {
+ commit-revisions 200
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ domain-name vyos.net
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/
+ plaintext-password ""
+ }
+ level admin
+ }
+ }
+ name-server 172.16.254.30
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
+/* Release version: 1.2.6 */
diff --git a/smoketest/configs/rip-router b/smoketest/configs/rip-router
new file mode 100644
index 000000000..09cb11a45
--- /dev/null
+++ b/smoketest/configs/rip-router
@@ -0,0 +1,267 @@
+interfaces {
+ dummy dum0 {
+ address 192.0.2.0/32
+ }
+ ethernet eth0 {
+ duplex auto
+ ip {
+ rip {
+ authentication {
+ md5 1 {
+ password VyOSsecure
+ }
+ }
+ split-horizon {
+ poison-reverse
+ }
+ }
+ }
+ ipv6 {
+ ripng {
+ split-horizon {
+ poison-reverse
+ }
+ }
+ }
+ smp-affinity auto
+ speed auto
+ address 172.18.202.10/24
+ }
+ ethernet eth1 {
+ duplex auto
+ smp-affinity auto
+ speed auto
+ vif 20 {
+ ip {
+ rip {
+ authentication {
+ plaintext-password VyOSsecure
+ }
+ split-horizon {
+ poison-reverse
+ }
+ }
+ }
+ ipv6 {
+ ripng {
+ split-horizon {
+ disable
+ }
+ }
+ }
+ }
+ vif-s 200 {
+ ip {
+ rip {
+ authentication {
+ md5 1 {
+ password VyOSsecure
+ }
+ }
+ split-horizon {
+ disable
+ }
+ }
+ }
+ ipv6 {
+ ripng {
+ split-horizon {
+ poison-reverse
+ }
+ }
+ }
+ vif-c 2000 {
+ ip {
+ rip {
+ authentication {
+ md5 1 {
+ password VyOSsecure
+ }
+ }
+ }
+ }
+ }
+ vif-c 3000 {
+ ip {
+ rip {
+ split-horizon {
+ disable
+ }
+ }
+ }
+ ipv6 {
+ ripng {
+ split-horizon {
+ poison-reverse
+ }
+ }
+ }
+ }
+ }
+ }
+}
+policy {
+ access-list6 198 {
+ rule 10 {
+ action permit
+ source {
+ any
+ }
+ }
+ }
+ access-list6 199 {
+ rule 20 {
+ action deny
+ source {
+ any
+ }
+ }
+ }
+ prefix-list6 bar-prefix {
+ rule 200 {
+ action deny
+ prefix 2001:db8::/32
+ }
+ }
+ prefix-list6 foo-prefix {
+ rule 100 {
+ action permit
+ prefix 2001:db8::/32
+ }
+ }
+ route-map FooBar123 {
+ rule 10 {
+ action permit
+ }
+ }
+}
+protocols {
+ rip {
+ default-distance 20
+ default-information {
+ originate
+ }
+ interface eth0
+ interface eth1.20
+ interface eth1.200
+ interface eth1.200.2000
+ interface eth1.200.3000
+ network 192.168.0.0/24
+ redistribute {
+ connected {
+ }
+ }
+ }
+ ripng {
+ aggregate-address 2001:db8:1000::/48
+ default-information {
+ originate
+ }
+ default-metric 8
+ distribute-list {
+ access-list {
+ in 198
+ out 199
+ }
+ interface eth0 {
+ access-list {
+ in 198
+ out 199
+ }
+ prefix-list {
+ in foo-prefix
+ out bar-prefix
+ }
+ }
+ interface eth1 {
+ access-list {
+ in 198
+ out 199
+ }
+ prefix-list {
+ in foo-prefix
+ out bar-prefix
+ }
+ }
+ interface eth2 {
+ access-list {
+ in 198
+ out 199
+ }
+ prefix-list {
+ in foo-prefix
+ out bar-prefix
+ }
+ }
+ prefix-list {
+ in foo-prefix
+ out bar-prefix
+ }
+ }
+ interface eth0
+ interface eth1
+ interface eth2
+ network 2001:db8:1000::/64
+ network 2001:db8:1001::/64
+ network 2001:db8:2000::/64
+ network 2001:db8:2001::/64
+ passive-interface default
+ redistribute {
+ connected {
+ metric 8
+ route-map FooBar123
+ }
+ static {
+ metric 8
+ route-map FooBar123
+ }
+ }
+ route 2001:db8:1000::/64
+ }
+}
+service {
+ ssh {
+ port 22
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+}
+
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
+/* Release version: 1.2.6-S1 */
diff --git a/smoketest/configs/tunnel-broker b/smoketest/configs/tunnel-broker
new file mode 100644
index 000000000..b52ba2541
--- /dev/null
+++ b/smoketest/configs/tunnel-broker
@@ -0,0 +1,142 @@
+interfaces {
+ dummy dum0 {
+ address 192.0.2.0/32
+ }
+ dummy dum1 {
+ address 192.0.2.1/32
+ }
+ dummy dum2 {
+ address 192.0.2.2/32
+ }
+ dummy dum3 {
+ address 192.0.2.3/32
+ }
+ dummy dum4 {
+ address 192.0.2.4/32
+ }
+ ethernet eth0 {
+ duplex auto
+ smp-affinity auto
+ speed auto
+ address 172.18.202.10/24
+ }
+ l2tpv3 l2tpeth10 {
+ description "L2 VPN Tunnel"
+ destination-port 5010
+ encapsulation ip
+ local-ip 172.18.202.10
+ mtu 1500
+ peer-session-id 110
+ peer-tunnel-id 10
+ remote-ip 172.18.254.201
+ session-id 110
+ source-port 5010
+ tunnel-id 10
+ }
+ l2tpv3 l2tpeth20 {
+ description "L2 VPN Tunnel"
+ destination-port 5020
+ encapsulation ip
+ local-ip 172.18.202.10
+ mtu 1500
+ peer-session-id 120
+ peer-tunnel-id 20
+ remote-ip 172.18.254.202
+ session-id 120
+ source-port 5020
+ tunnel-id 20
+ }
+ l2tpv3 l2tpeth30 {
+ description "L2 VPN Tunnel"
+ destination-port 5030
+ encapsulation ip
+ local-ip 172.18.202.10
+ mtu 1500
+ peer-session-id 130
+ peer-tunnel-id 30
+ remote-ip 172.18.254.203
+ session-id 130
+ source-port 5030
+ tunnel-id 30
+ }
+ tunnel tun100 {
+ address 172.16.0.1/30
+ encapsulation gre-bridge
+ local-ip 192.0.2.0
+ remote-ip 192.0.2.100
+ }
+ tunnel tun200 {
+ address 172.16.0.5/30
+ encapsulation gre
+ local-ip 192.0.2.1
+ remote-ip 192.0.2.101
+ }
+ tunnel tun300 {
+ address 172.16.0.9/30
+ encapsulation ipip
+ local-ip 192.0.2.2
+ remote-ip 192.0.2.102
+ }
+ tunnel tun400 {
+ address 172.16.0.13/30
+ encapsulation gre-bridge
+ local-ip 192.0.2.3
+ remote-ip 192.0.2.103
+ }
+ tunnel tun500 {
+ address 172.16.0.17/30
+ encapsulation gre
+ local-ip 192.0.2.4
+ remote-ip 192.0.2.104
+ }
+}
+protocols {
+ static {
+ route 0.0.0.0/0 {
+ next-hop 172.18.202.1 {
+ distance 10
+ }
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+}
+
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
+/* Release version: 1.2.6-S1 */
diff --git a/smoketest/configs/vrf-basic b/smoketest/configs/vrf-basic
new file mode 100644
index 000000000..ded33f683
--- /dev/null
+++ b/smoketest/configs/vrf-basic
@@ -0,0 +1,231 @@
+interfaces {
+ ethernet eth0 {
+ address 192.0.2.1/24
+ }
+ ethernet eth1 {
+ duplex auto
+ speed auto
+ vrf green
+ }
+ ethernet eth2 {
+ vrf red
+ }
+}
+protocols {
+ static {
+ route 0.0.0.0/0 {
+ next-hop 192.0.2.254 {
+ distance 10
+ }
+ }
+ table 10 {
+ interface-route 1.0.0.0/8 {
+ next-hop-interface eth0 {
+ distance 20
+ }
+ }
+ interface-route 2.0.0.0/8 {
+ next-hop-interface eth0 {
+ distance 20
+ }
+ }
+ interface-route 3.0.0.0/8 {
+ next-hop-interface eth0 {
+ distance 20
+ }
+ }
+ }
+ table 20 {
+ interface-route 4.0.0.0/8 {
+ next-hop-interface eth0 {
+ distance 20
+ }
+ }
+ interface-route 5.0.0.0/8 {
+ next-hop-interface eth0 {
+ distance 50
+ }
+ }
+ interface-route 6.0.0.0/8 {
+ next-hop-interface eth0 {
+ distance 60
+ }
+ }
+ interface-route6 2001:db8:100::/40 {
+ next-hop-interface eth1 {
+ distance 20
+ }
+ }
+ interface-route6 2001:db8::/40 {
+ next-hop-interface eth1 {
+ distance 10
+ }
+ }
+ route 11.0.0.0/8 {
+ next-hop 1.1.1.1 {
+ next-hop-interface eth0
+ }
+ }
+ route 12.0.0.0/8 {
+ next-hop 1.1.1.1 {
+ next-hop-interface eth0
+ }
+ }
+ route 13.0.0.0/8 {
+ next-hop 1.1.1.1 {
+ next-hop-interface eth0
+ }
+ }
+ }
+ table 30 {
+ interface-route6 2001:db8:200::/40 {
+ next-hop-interface eth1 {
+ distance 20
+ }
+ }
+ route 14.0.0.0/8 {
+ next-hop 2.2.1.1 {
+ next-hop-interface eth1
+ }
+ }
+ route 15.0.0.0/8 {
+ next-hop 2.2.1.1 {
+ next-hop-interface eth1
+ }
+ }
+ }
+ }
+ vrf green {
+ static {
+ interface-route 100.0.0.0/8 {
+ next-hop-interface eth0 {
+ distance 200
+ next-hop-vrf default
+ }
+ }
+ interface-route 101.0.0.0/8 {
+ next-hop-interface eth0 {
+ next-hop-vrf default
+ }
+ next-hop-interface eth1 {
+ }
+ }
+ interface-route6 2001:db8:300::/40 {
+ next-hop-interface eth1 {
+ distance 20
+ next-hop-vrf default
+ }
+ }
+ route 20.0.0.0/8 {
+ next-hop 1.1.1.1 {
+ next-hop-interface eth1
+ next-hop-vrf default
+ }
+ }
+ route 21.0.0.0/8 {
+ next-hop 2.2.1.1 {
+ next-hop-interface eth1
+ next-hop-vrf default
+ }
+ }
+ route6 2001:db8:100::/40 {
+ next-hop fe80::1 {
+ interface eth0
+ next-hop-vrf default
+ }
+ }
+ }
+ }
+ vrf red {
+ static {
+ interface-route 103.0.0.0/8 {
+ next-hop-interface eth0 {
+ distance 201
+ next-hop-vrf default
+ }
+ }
+ interface-route 104.0.0.0/8 {
+ next-hop-interface eth0 {
+ next-hop-vrf default
+ }
+ next-hop-interface eth1 {
+ next-hop-vrf default
+ }
+ }
+ interface-route6 2001:db8:400::/40 {
+ next-hop-interface eth1 {
+ distance 24
+ next-hop-vrf default
+ }
+ }
+ route 30.0.0.0/8 {
+ next-hop 1.1.1.1 {
+ next-hop-interface eth1
+ }
+ }
+ route 40.0.0.0/8 {
+ next-hop 2.2.1.1 {
+ next-hop-interface eth1
+ next-hop-vrf default
+ }
+ }
+ route6 2001:db8:100::/40 {
+ next-hop fe80::1 {
+ interface eth0
+ next-hop-vrf default
+ }
+ }
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ nt
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+vrf {
+ name green {
+ table 1000
+ }
+ name red {
+ table 2000
+ }
+}
+
+// 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@6: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-beta-202101231023
diff --git a/smoketest/configs/vrf-bgp b/smoketest/configs/vrf-bgp
new file mode 100644
index 000000000..4ad372a36
--- /dev/null
+++ b/smoketest/configs/vrf-bgp
@@ -0,0 +1,166 @@
+interfaces {
+ ethernet eth0 {
+ address 192.0.2.1/24
+ }
+ ethernet eth1 {
+ vrf black
+ }
+ ethernet eth2 {
+ vrf black
+ }
+}
+protocols {
+ ospf {
+ area 0 {
+ network 192.0.2.0/24
+ }
+ interface eth0 {
+ authentication {
+ md5 {
+ key-id 10 {
+ md5-key ospfkey
+ }
+ }
+ }
+ }
+ log-adjacency-changes {
+ }
+ parameters {
+ abr-type cisco
+ router-id 1.2.3.4
+ }
+ passive-interface default
+ passive-interface-exclude eth0
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ nt
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+vrf {
+ name black {
+ protocols {
+ bgp 65000 {
+ address-family {
+ ipv4-unicast {
+ network 10.0.150.0/23 {
+ }
+ }
+ ipv6-unicast {
+ network 2001:db8:200::/40 {
+ }
+ }
+ }
+ neighbor 10.0.151.222 {
+ disable-send-community {
+ extended
+ standard
+ }
+ address-family {
+ ipv4-unicast {
+ default-originate {
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 65010
+ }
+ neighbor 10.0.151.252 {
+ peer-group VYOSv4
+ }
+ neighbor 10.0.151.254 {
+ peer-group VYOSv4
+ }
+ neighbor 2001:db8:200:ffff::3 {
+ peer-group VYOSv6
+ }
+ neighbor 2001:db8:200:ffff::a {
+ peer-group VYOSv6
+ }
+ neighbor 2001:db8:200:ff::101:2 {
+ remote-as 65010
+ }
+ parameters {
+ default {
+ no-ipv4-unicast
+ }
+ log-neighbor-changes
+ router-id 10.0.151.251
+ }
+ peer-group VYOSv4 {
+ address-family {
+ ipv4-unicast {
+ nexthop-self {
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 65000
+ update-source dum0
+ }
+ peer-group VYOSv6 {
+ address-family {
+ ipv6-unicast {
+ nexthop-self {
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 65000
+ update-source dum0
+ }
+ }
+
+ }
+ table 2000
+ }
+}
+
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@2:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@20:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:nat66@1:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@9:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrf@2:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
+// Release version: 1.4-rolling-202103130218
diff --git a/smoketest/configs/vrf-ospf b/smoketest/configs/vrf-ospf
new file mode 100644
index 000000000..7855e86bf
--- /dev/null
+++ b/smoketest/configs/vrf-ospf
@@ -0,0 +1,145 @@
+interfaces {
+ ethernet eth0 {
+ address 192.0.2.1/24
+ }
+ ethernet eth1 {
+ vrf red
+ }
+ ethernet eth2 {
+ vrf blue
+ }
+}
+protocols {
+ ospf {
+ area 0 {
+ network 192.0.2.0/24
+ }
+ interface eth0 {
+ authentication {
+ md5 {
+ key-id 10 {
+ md5-key ospfkey
+ }
+ }
+ }
+ }
+ log-adjacency-changes {
+ }
+ parameters {
+ abr-type cisco
+ router-id 1.2.3.4
+ }
+ passive-interface default
+ passive-interface-exclude eth0
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ nt
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+vrf {
+ name blue {
+ protocols {
+ ospf {
+ area 0 {
+ network 172.18.201.0/24
+ }
+ interface eth2 {
+ authentication {
+ md5 {
+ key-id 30 {
+ md5-key vyoskey456
+ }
+ }
+ }
+ dead-interval 40
+ hello-interval 10
+ priority 1
+ retransmit-interval 5
+ transmit-delay 1
+ }
+ log-adjacency-changes {
+ }
+ parameters {
+ abr-type cisco
+ router-id 5.6.7.8
+ }
+ passive-interface default
+ passive-interface-exclude eth2
+ }
+ }
+ table 2000
+ }
+ name red {
+ protocols {
+ ospf {
+ area 0 {
+ network 172.18.202.0/24
+ }
+ interface eth1 {
+ authentication {
+ md5 {
+ key-id 20 {
+ md5-key vyoskey123
+ }
+ }
+ }
+ dead-interval 40
+ hello-interval 10
+ priority 1
+ retransmit-interval 5
+ transmit-delay 1
+ }
+ log-adjacency-changes {
+ }
+ parameters {
+ abr-type cisco
+ router-id 9.10.11.12
+ }
+ passive-interface default
+ passive-interface-exclude eth1
+ }
+ }
+ table 1000
+ }
+}
+
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@2:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@20:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:nat66@1:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@9:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrf@2:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
+// Release version: 1.4-rolling-202103130218
diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py
index 705c932b4..b2acb03cc 100644
--- a/smoketest/scripts/cli/base_accel_ppp_test.py
+++ b/smoketest/scripts/cli/base_accel_ppp_test.py
@@ -12,10 +12,10 @@
# 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 re
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
from configparser import ConfigParser
from vyos.configsession import ConfigSession
@@ -26,26 +26,22 @@ from vyos.util import get_half_cpus
from vyos.util import process_named_running
class BasicAccelPPPTest:
- class BaseTest(unittest.TestCase):
-
+ class TestCase(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
self._gateway = '192.0.2.1'
-
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
- self.session.delete(self._base_path)
+ self.cli_delete(self._base_path)
def tearDown(self):
- self.session.delete(self._base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(self._base_path)
+ self.cli_commit()
def set(self, path):
- self.session.set(self._base_path + path)
+ self.cli_set(self._base_path + path)
def delete(self, path):
- self.session.delete(self._base_path + path)
+ self.cli_delete(self._base_path + path)
def basic_config(self):
# PPPoE local auth mode requires local users to be configured!
@@ -65,7 +61,7 @@ class BasicAccelPPPTest:
self.set(['name-server', ns])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
@@ -95,11 +91,11 @@ class BasicAccelPPPTest:
# upload rate-limit requires also download rate-limit
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
self.set(['authentication', 'local-users', 'username', user, 'rate-limit', 'download', download])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
@@ -123,7 +119,7 @@ class BasicAccelPPPTest:
# Check local-users default value(s)
self.delete(['authentication', 'local-users', 'username', user, 'static-ip'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# check local users
tmp = cmd(f'sudo cat {self._chap_secrets}')
@@ -162,7 +158,7 @@ class BasicAccelPPPTest:
self.set(['authentication', 'radius', 'source-address', source_address])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
@@ -200,7 +196,7 @@ class BasicAccelPPPTest:
self.set(['authentication', 'radius', 'server', radius_server, 'disable-accounting'])
# commit changes
- self.session.commit()
+ self.cli_commit()
conf.read(self._config_file)
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py
index 8ee5395d0..f897088ef 100644
--- a/smoketest/scripts/cli/base_interfaces_test.py
+++ b/smoketest/scripts/cli/base_interfaces_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2019-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -12,16 +12,17 @@
# 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 re
import os
import unittest
-import json
from binascii import hexlify
-from netifaces import ifaddresses
from netifaces import AF_INET
from netifaces import AF_INET6
+from netifaces import ifaddresses
+from netifaces import interfaces
+
+from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.ifconfig import Interface
@@ -30,6 +31,7 @@ from vyos.util import read_file
from vyos.util import cmd
from vyos.util import dict_search
from vyos.util import process_named_running
+from vyos.util import get_interface_config
from vyos.validate import is_intf_addr_assigned
from vyos.validate import is_ipv6_link_local
@@ -51,24 +53,15 @@ def is_mirrored_to(interface, mirror_if, qdisc):
ret_val = True
return ret_val
-
-dhcp6c_config_file = '/run/dhcp6c/dhcp6c.{}.conf'
-def get_dhcp6c_config_value(interface, key):
- tmp = read_file(dhcp6c_config_file.format(interface))
- tmp = re.findall(r'\n?{}\s+(.*)'.format(key), tmp)
-
- out = []
- for item in tmp:
- out.append(item.replace(';',''))
- return out
-
class BasicInterfaceTest:
- class BaseTest(unittest.TestCase):
+ class TestCase(VyOSUnitTestSHIM.TestCase):
_test_ip = False
_test_mtu = False
_test_vlan = False
_test_qinq = False
_test_ipv6 = False
+ _test_ipv6_pd = False
+ _test_ipv6_dhcpc6 = False
_test_mirror = False
_base_path = []
@@ -84,37 +77,35 @@ class BasicInterfaceTest:
_mtu = '1280'
def setUp(self):
- self.session = ConfigSession(os.getpid())
-
# Setup mirror interfaces for SPAN (Switch Port Analyzer)
for span in self._mirror_interfaces:
section = Section.section(span)
- self.session.set(['interfaces', section, span])
+ self.cli_set(['interfaces', section, span])
def tearDown(self):
- # Ethernet is handled in its derived class
- if 'ethernet' not in self._base_path:
- self.session.delete(self._base_path)
-
# Tear down mirror interfaces for SPAN (Switch Port Analyzer)
for span in self._mirror_interfaces:
section = Section.section(span)
- self.session.delete(['interfaces', section, span])
+ self.cli_delete(['interfaces', section, span])
- self.session.commit()
- del self.session
+ self.cli_delete(self._base_path)
+ self.cli_commit()
+
+ # Verify that no previously interface remained on the system
+ for intf in self._interfaces:
+ self.assertNotIn(intf, interfaces())
def test_span_mirror(self):
if not self._mirror_interfaces:
- return None
+ self.skipTest('not supported')
# Check the two-way mirror rules of ingress and egress
for mirror in self._mirror_interfaces:
for interface in self._interfaces:
- self.session.set(self._base_path + [interface, 'mirror', 'ingress', mirror])
- self.session.set(self._base_path + [interface, 'mirror', 'egress', mirror])
+ self.cli_set(self._base_path + [interface, 'mirror', 'ingress', mirror])
+ self.cli_set(self._base_path + [interface, 'mirror', 'egress', mirror])
- self.session.commit()
+ self.cli_commit()
# Verify config
for mirror in self._mirror_interfaces:
@@ -122,45 +113,69 @@ class BasicInterfaceTest:
self.assertTrue(is_mirrored_to(interface, mirror, 'ffff'))
self.assertTrue(is_mirrored_to(interface, mirror, '1'))
+ def test_interface_disable(self):
+ # Check if description can be added to interface and
+ # can be read back
+ for intf in self._interfaces:
+ self.cli_set(self._base_path + [intf, 'disable'])
+ for option in self._options.get(intf, []):
+ self.cli_set(self._base_path + [intf] + option.split())
+
+ self.cli_commit()
+
+ # Validate interface description
+ for intf in self._interfaces:
+ self.assertEqual(Interface(intf).get_admin_state(), 'down')
def test_interface_description(self):
# Check if description can be added to interface and
# can be read back
for intf in self._interfaces:
test_string=f'Description-Test-{intf}'
- self.session.set(self._base_path + [intf, 'description', test_string])
+ self.cli_set(self._base_path + [intf, 'description', test_string])
for option in self._options.get(intf, []):
- self.session.set(self._base_path + [intf] + option.split())
+ self.cli_set(self._base_path + [intf] + option.split())
- self.session.commit()
+ self.cli_commit()
# Validate interface description
for intf in self._interfaces:
test_string=f'Description-Test-{intf}'
tmp = read_file(f'/sys/class/net/{intf}/ifalias')
- self.assertTrue(tmp, test_string)
+ self.assertEqual(tmp, test_string)
+ self.assertEqual(Interface(intf).get_alias(), test_string)
+ self.cli_delete(self._base_path + [intf, 'description'])
+
+ self.cli_commit()
+
+ # Validate remove interface description "empty"
+ for intf in self._interfaces:
+ tmp = read_file(f'/sys/class/net/{intf}/ifalias')
+ self.assertEqual(tmp, str())
+ self.assertEqual(Interface(intf).get_alias(), str())
def test_add_single_ip_address(self):
addr = '192.0.2.0/31'
for intf in self._interfaces:
- self.session.set(self._base_path + [intf, 'address', addr])
+ self.cli_set(self._base_path + [intf, 'address', addr])
for option in self._options.get(intf, []):
- self.session.set(self._base_path + [intf] + option.split())
+ self.cli_set(self._base_path + [intf] + option.split())
- self.session.commit()
+ self.cli_commit()
for intf in self._interfaces:
self.assertTrue(is_intf_addr_assigned(intf, addr))
+ self.assertEqual(Interface(intf).get_admin_state(), 'up')
def test_add_multiple_ip_addresses(self):
# Add address
for intf in self._interfaces:
for addr in self._test_addr:
- self.session.set(self._base_path + [intf, 'address', addr])
+ self.cli_set(self._base_path + [intf, 'address', addr])
for option in self._options.get(intf, []):
- self.session.set(self._base_path + [intf] + option.split())
+ self.cli_set(self._base_path + [intf] + option.split())
- self.session.commit()
+ self.cli_commit()
# Validate address
for intf in self._interfaces:
@@ -175,15 +190,15 @@ class BasicInterfaceTest:
def test_ipv6_link_local_address(self):
# Common function for IPv6 link-local address assignemnts
if not self._test_ipv6:
- return None
+ self.skipTest('not supported')
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
- self.session.set(base + option.split())
+ self.cli_set(base + option.split())
# after commit we must have an IPv6 link-local address
- self.session.commit()
+ self.cli_commit()
for interface in self._interfaces:
for addr in ifaddresses(interface)[AF_INET6]:
@@ -192,26 +207,26 @@ class BasicInterfaceTest:
# disable IPv6 link-local address assignment
for interface in self._interfaces:
base = self._base_path + [interface]
- self.session.set(base + ['ipv6', 'address', 'no-default-link-local'])
+ self.cli_set(base + ['ipv6', 'address', 'no-default-link-local'])
# after commit we must have no IPv6 link-local address
- self.session.commit()
+ self.cli_commit()
for interface in self._interfaces:
self.assertTrue(AF_INET6 not in ifaddresses(interface))
def test_interface_mtu(self):
if not self._test_mtu:
- return None
+ self.skipTest('not supported')
for intf in self._interfaces:
base = self._base_path + [intf]
- self.session.set(base + ['mtu', self._mtu])
+ self.cli_set(base + ['mtu', self._mtu])
for option in self._options.get(intf, []):
- self.session.set(base + option.split())
+ self.cli_set(base + option.split())
# commit interface changes
- self.session.commit()
+ self.cli_commit()
# verify changed MTU
for intf in self._interfaces:
@@ -222,21 +237,21 @@ class BasicInterfaceTest:
# Testcase if MTU can be changed to 1200 on non IPv6
# enabled interfaces
if not self._test_mtu:
- return None
+ self.skipTest('not supported')
old_mtu = self._mtu
self._mtu = '1200'
for intf in self._interfaces:
base = self._base_path + [intf]
- self.session.set(base + ['mtu', self._mtu])
- self.session.set(base + ['ipv6', 'address', 'no-default-link-local'])
+ self.cli_set(base + ['mtu', self._mtu])
+ self.cli_set(base + ['ipv6', 'address', 'no-default-link-local'])
for option in self._options.get(intf, []):
- self.session.set(base + option.split())
+ self.cli_set(base + option.split())
# commit interface changes
- self.session.commit()
+ self.cli_commit()
# verify changed MTU
for intf in self._interfaces:
@@ -245,22 +260,26 @@ class BasicInterfaceTest:
self._mtu = old_mtu
- def test_8021q_vlan_interfaces(self):
+ def test_vif_8021q_interfaces(self):
+ # XXX: This testcase is not allowed to run as first testcase, reason
+ # is the Wireless test will first load the wifi kernel hwsim module
+ # which creates a wlan0 and wlan1 interface which will fail the
+ # tearDown() test in the end that no interface is allowed to survive!
if not self._test_vlan:
- return None
+ self.skipTest('not supported')
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
- self.session.set(base + option.split())
+ self.cli_set(base + option.split())
for vlan in self._vlan_range:
base = self._base_path + [interface, 'vif', vlan]
- self.session.set(base + ['mtu', self._mtu])
+ self.cli_set(base + ['mtu', self._mtu])
for address in self._test_addr:
- self.session.set(base + ['address', address])
+ self.cli_set(base + ['address', address])
- self.session.commit()
+ self.cli_commit()
for intf in self._interfaces:
for vlan in self._vlan_range:
@@ -270,29 +289,70 @@ class BasicInterfaceTest:
tmp = read_file(f'/sys/class/net/{vif}/mtu')
self.assertEqual(tmp, self._mtu)
+ self.assertEqual(Interface(vif).get_admin_state(), 'up')
+
+ def test_vif_8021q_lower_up_down(self):
+ # Testcase for https://phabricator.vyos.net/T3349
+ if not self._test_vlan:
+ self.skipTest('not supported')
+
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ for option in self._options.get(interface, []):
+ self.cli_set(base + option.split())
+
+ # disable the lower interface
+ self.cli_set(base + ['disable'])
+
+ for vlan in self._vlan_range:
+ vlan_base = self._base_path + [interface, 'vif', vlan]
+ # disable the vlan interface
+ self.cli_set(vlan_base + ['disable'])
+ self.cli_commit()
- def test_8021ad_qinq_vlan_interfaces(self):
+ # re-enable all lower interfaces
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ self.cli_delete(base + ['disable'])
+
+ self.cli_commit()
+
+ # verify that the lower interfaces are admin up and the vlan
+ # interfaces are all admin down
+ for interface in self._interfaces:
+ self.assertEqual(Interface(interface).get_admin_state(), 'up')
+
+ for vlan in self._vlan_range:
+ ifname = f'{interface}.{vlan}'
+ self.assertEqual(Interface(ifname).get_admin_state(), 'down')
+
+
+ def test_vif_s_8021ad_vlan_interfaces(self):
+ # XXX: This testcase is not allowed to run as first testcase, reason
+ # is the Wireless test will first load the wifi kernel hwsim module
+ # which creates a wlan0 and wlan1 interface which will fail the
+ # tearDown() test in the end that no interface is allowed to survive!
if not self._test_qinq:
- return None
+ self.skipTest('not supported')
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
- self.session.set(base + option.split())
+ self.cli_set(base + option.split())
for vif_s in self._qinq_range:
for vif_c in self._vlan_range:
base = self._base_path + [interface, 'vif-s', vif_s, 'vif-c', vif_c]
- self.session.set(base + ['mtu', self._mtu])
+ self.cli_set(base + ['mtu', self._mtu])
for address in self._test_addr:
- self.session.set(base + ['address', address])
+ self.cli_set(base + ['address', address])
- self.session.commit()
+ self.cli_commit()
for interface in self._interfaces:
for vif_s in self._qinq_range:
- tmp = json.loads(cmd(f'ip -d -j link show dev {interface}.{vif_s}'))[0]
+ tmp = get_interface_config(f'{interface}.{vif_s}')
self.assertEqual(dict_search('linkinfo.info_data.protocol', tmp), '802.1ad')
for vif_c in self._vlan_range:
@@ -305,26 +365,26 @@ class BasicInterfaceTest:
def test_interface_ip_options(self):
if not self._test_ip:
- return None
+ self.skipTest('not supported')
for interface in self._interfaces:
arp_tmo = '300'
path = self._base_path + [interface]
for option in self._options.get(interface, []):
- self.session.set(path + option.split())
+ self.cli_set(path + option.split())
# Options
- self.session.set(path + ['ip', 'arp-cache-timeout', arp_tmo])
- self.session.set(path + ['ip', 'disable-arp-filter'])
- self.session.set(path + ['ip', 'disable-forwarding'])
- self.session.set(path + ['ip', 'enable-arp-accept'])
- self.session.set(path + ['ip', 'enable-arp-announce'])
- self.session.set(path + ['ip', 'enable-arp-ignore'])
- self.session.set(path + ['ip', 'enable-proxy-arp'])
- self.session.set(path + ['ip', 'proxy-arp-pvlan'])
- self.session.set(path + ['ip', 'source-validation', 'loose'])
-
- self.session.commit()
+ self.cli_set(path + ['ip', 'arp-cache-timeout', arp_tmo])
+ self.cli_set(path + ['ip', 'disable-arp-filter'])
+ self.cli_set(path + ['ip', 'disable-forwarding'])
+ self.cli_set(path + ['ip', 'enable-arp-accept'])
+ self.cli_set(path + ['ip', 'enable-arp-announce'])
+ self.cli_set(path + ['ip', 'enable-arp-ignore'])
+ self.cli_set(path + ['ip', 'enable-proxy-arp'])
+ self.cli_set(path + ['ip', 'proxy-arp-pvlan'])
+ self.cli_set(path + ['ip', 'source-validation', 'loose'])
+
+ self.cli_commit()
for interface in self._interfaces:
tmp = read_file(f'/proc/sys/net/ipv4/neigh/{interface}/base_reachable_time_ms')
@@ -356,19 +416,19 @@ class BasicInterfaceTest:
def test_interface_ipv6_options(self):
if not self._test_ipv6:
- return None
+ self.skipTest('not supported')
for interface in self._interfaces:
dad_transmits = '10'
path = self._base_path + [interface]
for option in self._options.get(interface, []):
- self.session.set(path + option.split())
+ self.cli_set(path + option.split())
# Options
- self.session.set(path + ['ipv6', 'disable-forwarding'])
- self.session.set(path + ['ipv6', 'dup-addr-detect-transmits', dad_transmits])
+ self.cli_set(path + ['ipv6', 'disable-forwarding'])
+ self.cli_set(path + ['ipv6', 'dup-addr-detect-transmits', dad_transmits])
- self.session.commit()
+ self.cli_commit()
for interface in self._interfaces:
tmp = read_file(f'/proc/sys/net/ipv6/conf/{interface}/forwarding')
@@ -377,40 +437,156 @@ class BasicInterfaceTest:
tmp = read_file(f'/proc/sys/net/ipv6/conf/{interface}/dad_transmits')
self.assertEqual(dad_transmits, tmp)
+ def test_dhcpv6_clinet_options(self):
+ if not self._test_ipv6_dhcpc6:
+ self.skipTest('not supported')
- def test_ipv6_dhcpv6_prefix_delegation(self):
- if not self._test_ipv6:
- return None
+ duid_base = 10
+ for interface in self._interfaces:
+ duid = '00:01:00:01:27:71:db:f0:00:50:00:00:00:{}'.format(duid_base)
+ path = self._base_path + [interface]
+ for option in self._options.get(interface, []):
+ self.cli_set(path + option.split())
+
+ # Enable DHCPv6 client
+ self.cli_set(path + ['address', 'dhcpv6'])
+ self.cli_set(path + ['dhcpv6-options', 'rapid-commit'])
+ self.cli_set(path + ['dhcpv6-options', 'parameters-only'])
+ self.cli_set(path + ['dhcpv6-options', 'duid', duid])
+ duid_base += 1
+
+ self.cli_commit()
+
+ duid_base = 10
+ for interface in self._interfaces:
+ duid = '00:01:00:01:27:71:db:f0:00:50:00:00:00:{}'.format(duid_base)
+ dhcpc6_config = read_file(f'/run/dhcp6c/dhcp6c.{interface}.conf')
+ self.assertIn(f'interface {interface} ' + '{', dhcpc6_config)
+ self.assertIn(f' request domain-name-servers;', dhcpc6_config)
+ self.assertIn(f' request domain-name;', dhcpc6_config)
+ self.assertIn(f' information-only;', dhcpc6_config)
+ self.assertIn(f' send ia-na 0;', dhcpc6_config)
+ self.assertIn(f' send rapid-commit;', dhcpc6_config)
+ self.assertIn(f' send client-id {duid};', dhcpc6_config)
+ self.assertIn('};', dhcpc6_config)
+ duid_base += 1
+
+ # Check for running process
+ self.assertTrue(process_named_running('dhcp6c'))
+
+ def test_dhcpv6pd_auto_sla_id(self):
+ if not self._test_ipv6_pd:
+ self.skipTest('not supported')
+
+ prefix_len = '56'
+ sla_len = str(64 - int(prefix_len))
+
+ delegatees = ['dum2340', 'dum2341', 'dum2342', 'dum2343', 'dum2344']
- address = '1'
- sla_id = '0'
- sla_len = '8'
for interface in self._interfaces:
path = self._base_path + [interface]
for option in self._options.get(interface, []):
- self.session.set(path + option.split())
+ self.cli_set(path + option.split())
+ address = '1'
# prefix delegation stuff
pd_base = path + ['dhcpv6-options', 'pd', '0']
- self.session.set(pd_base + ['length', '56'])
- self.session.set(pd_base + ['interface', interface, 'address', address])
- self.session.set(pd_base + ['interface', interface, 'sla-id', sla_id])
+ self.cli_set(pd_base + ['length', prefix_len])
+
+ for delegatee in delegatees:
+ section = Section.section(delegatee)
+ self.cli_set(['interfaces', section, delegatee])
+ self.cli_set(pd_base + ['interface', delegatee, 'address', address])
+ # increment interface address
+ address = str(int(address) + 1)
- self.session.commit()
+ self.cli_commit()
for interface in self._interfaces:
+ dhcpc6_config = read_file(f'/run/dhcp6c/dhcp6c.{interface}.conf')
+
# verify DHCPv6 prefix delegation
- # will return: ['delegation', '::/56 infinity;']
- tmp = get_dhcp6c_config_value(interface, 'prefix')[1].split()[0] # mind the whitespace
- self.assertEqual(tmp, '::/56')
- tmp = get_dhcp6c_config_value(interface, 'prefix-interface')[0].split()[0]
- self.assertEqual(tmp, interface)
- tmp = get_dhcp6c_config_value(interface, 'ifid')[0]
- self.assertEqual(tmp, address)
- tmp = get_dhcp6c_config_value(interface, 'sla-id')[0]
- self.assertEqual(tmp, sla_id)
- tmp = get_dhcp6c_config_value(interface, 'sla-len')[0]
- self.assertEqual(tmp, sla_len)
+ self.assertIn(f'prefix ::/{prefix_len} infinity;', dhcpc6_config)
+
+ address = '1'
+ sla_id = '0'
+ for delegatee in delegatees:
+ self.assertIn(f'prefix-interface {delegatee}' + r' {', dhcpc6_config)
+ self.assertIn(f'ifid {address};', dhcpc6_config)
+ self.assertIn(f'sla-id {sla_id};', dhcpc6_config)
+ self.assertIn(f'sla-len {sla_len};', dhcpc6_config)
+
+ # increment sla-id
+ sla_id = str(int(sla_id) + 1)
+ # increment interface address
+ address = str(int(address) + 1)
# Check for running process
self.assertTrue(process_named_running('dhcp6c'))
+
+ for delegatee in delegatees:
+ # we can already cleanup the test delegatee interface here
+ # as until commit() is called, nothing happens
+ section = Section.section(delegatee)
+ self.cli_delete(['interfaces', section, delegatee])
+
+ def test_dhcpv6pd_manual_sla_id(self):
+ if not self._test_ipv6_pd:
+ self.skipTest('not supported')
+
+ prefix_len = '56'
+ sla_len = str(64 - int(prefix_len))
+
+ delegatees = ['dum3340', 'dum3341', 'dum3342', 'dum3343', 'dum3344']
+
+ for interface in self._interfaces:
+ path = self._base_path + [interface]
+ for option in self._options.get(interface, []):
+ self.cli_set(path + option.split())
+
+ # prefix delegation stuff
+ address = '1'
+ sla_id = '1'
+ pd_base = path + ['dhcpv6-options', 'pd', '0']
+ self.cli_set(pd_base + ['length', prefix_len])
+
+ for delegatee in delegatees:
+ section = Section.section(delegatee)
+ self.cli_set(['interfaces', section, delegatee])
+ self.cli_set(pd_base + ['interface', delegatee, 'address', address])
+ self.cli_set(pd_base + ['interface', delegatee, 'sla-id', sla_id])
+
+ # increment interface address
+ address = str(int(address) + 1)
+ sla_id = str(int(sla_id) + 1)
+
+ self.cli_commit()
+
+ # Verify dhcpc6 client configuration
+ for interface in self._interfaces:
+ address = '1'
+ sla_id = '1'
+ dhcpc6_config = read_file(f'/run/dhcp6c/dhcp6c.{interface}.conf')
+
+ # verify DHCPv6 prefix delegation
+ self.assertIn(f'prefix ::/{prefix_len} infinity;', dhcpc6_config)
+
+ for delegatee in delegatees:
+ self.assertIn(f'prefix-interface {delegatee}' + r' {', dhcpc6_config)
+ self.assertIn(f'ifid {address};', dhcpc6_config)
+ self.assertIn(f'sla-id {sla_id};', dhcpc6_config)
+ self.assertIn(f'sla-len {sla_len};', dhcpc6_config)
+
+ # increment sla-id
+ sla_id = str(int(sla_id) + 1)
+ # increment interface address
+ address = str(int(address) + 1)
+
+ # Check for running process
+ self.assertTrue(process_named_running('dhcp6c'))
+
+ for delegatee in delegatees:
+ # we can already cleanup the test delegatee interface here
+ # as until commit() is called, nothing happens
+ section = Section.section(delegatee)
+ self.cli_delete(['interfaces', section, delegatee])
diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py
new file mode 100644
index 000000000..18e49f47f
--- /dev/null
+++ b/smoketest/scripts/cli/base_vyostest_shim.py
@@ -0,0 +1,90 @@
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import unittest
+
+from time import sleep
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+from vyos import ConfigError
+from vyos.util import cmd
+
+save_config = '/tmp/vyos-smoketest-save'
+
+# This class acts as shim between individual Smoketests developed for VyOS and
+# the Python UnitTest framework. Before every test is loaded, we dump the current
+# system configuration and reload it after the test - despite the test results.
+#
+# Using this approach we can not render a live system useless while running any
+# kind of smoketest. In addition it adds debug capabilities like printing the
+# command used to execute the test.
+class VyOSUnitTestSHIM:
+ class TestCase(unittest.TestCase):
+ # if enabled in derived class, print out each and every set/del command
+ # on the CLI. This is usefull to grap all the commands required to
+ # trigger the certain failure condition.
+ # Use "self.debug = True" in derived classes setUp() method
+ debug = False
+
+ @classmethod
+ def setUpClass(cls):
+ cls._session = ConfigSession(os.getpid())
+ cls._session.save_config(save_config)
+ pass
+
+ @classmethod
+ def tearDownClass(cls):
+ # discard any pending changes which might caused a messed up config
+ cls._session.discard()
+ # ... and restore the initial state
+ cls._session.migrate_and_load_config(save_config)
+
+ try:
+ cls._session.commit()
+ except (ConfigError, ConfigSessionError):
+ cls._session.discard()
+ cls.fail(cls)
+
+ def cli_set(self, config):
+ if self.debug:
+ print('set ' + ' '.join(config))
+ self._session.set(config)
+
+ def cli_delete(self, config):
+ if self.debug:
+ print('del ' + ' '.join(config))
+ self._session.delete(config)
+
+ def cli_commit(self):
+ self._session.commit()
+
+ def getFRRconfig(self, string, end='$', endsection='^!'):
+ """ Retrieve current "running configuration" from FRR """
+ command = f'vtysh -c "show run" | sed -n "/^{string}{end}/,/{endsection}/p"'
+
+ count = 0
+ tmp = ''
+ while count < 10 and tmp == '':
+ # Let FRR settle after a config change first before harassing it again
+ sleep(1)
+ tmp = cmd(command)
+ count += 1
+
+ if self.debug or tmp == '':
+ import pprint
+ print(f'\n\ncommand "{command}" returned:\n')
+ pprint.pprint(tmp)
+ return tmp
diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py
index a35682b7c..03cdafb8d 100755
--- a/smoketest/scripts/cli/test_interfaces_bonding.py
+++ b/smoketest/scripts/cli/test_interfaces_bonding.py
@@ -24,32 +24,36 @@ from vyos.ifconfig.interface import Interface
from vyos.configsession import ConfigSessionError
from vyos.util import read_file
-class BondingInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._test_mtu = True
- self._test_vlan = True
- self._test_qinq = True
- self._test_ipv6 = True
- self._base_path = ['interfaces', 'bonding']
- self._interfaces = ['bond0']
- self._mirror_interfaces = ['dum21354']
- self._members = []
+class BondingInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._test_ipv6_pd = True
+ cls._test_ipv6_dhcpc6 = True
+ cls._test_mtu = True
+ cls._test_vlan = True
+ cls._test_qinq = True
+ cls._base_path = ['interfaces', 'bonding']
+ cls._interfaces = ['bond0']
+ cls._mirror_interfaces = ['dum21354']
+ cls._members = []
# we need to filter out VLAN interfaces identified by a dot (.)
# in their name - just in case!
if 'TEST_ETH' in os.environ:
- self._members = os.environ['TEST_ETH'].split()
+ cls._members = os.environ['TEST_ETH'].split()
else:
- for tmp in Section.interfaces("ethernet"):
+ for tmp in Section.interfaces('ethernet'):
if not '.' in tmp:
- self._members.append(tmp)
+ cls._members.append(tmp)
- self._options['bond0'] = []
- for member in self._members:
- self._options['bond0'].append(f'member interface {member}')
-
- super().setUp()
+ cls._options['bond0'] = []
+ for member in cls._members:
+ cls._options['bond0'].append(f'member interface {member}')
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
def test_add_single_ip_address(self):
super().test_add_single_ip_address()
@@ -58,8 +62,8 @@ class BondingInterfaceTest(BasicInterfaceTest.BaseTest):
slaves = read_file(f'/sys/class/net/{interface}/bonding/slaves').split()
self.assertListEqual(slaves, self._members)
- def test_8021q_vlan_interfaces(self):
- super().test_8021q_vlan_interfaces()
+ def test_vif_8021q_interfaces(self):
+ super().test_vif_8021q_interfaces()
for interface in self._interfaces:
slaves = read_file(f'/sys/class/net/{interface}/bonding/slaves').split()
@@ -73,16 +77,16 @@ class BondingInterfaceTest(BasicInterfaceTest.BaseTest):
# configure member interfaces
for interface in self._interfaces:
for option in self._options.get(interface, []):
- self.session.set(self._base_path + [interface] + option.split())
+ self.cli_set(self._base_path + [interface] + option.split())
- self.session.commit()
+ self.cli_commit()
# remove single bond member port
for interface in self._interfaces:
remove_member = self._members[0]
- self.session.delete(self._base_path + [interface, 'member', 'interface', remove_member])
+ self.cli_delete(self._base_path + [interface, 'member', 'interface', remove_member])
- self.session.commit()
+ self.cli_commit()
# removed member port must be admin-up
for interface in self._interfaces:
diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py
index 7444701c1..21f20c781 100755
--- a/smoketest/scripts/cli/test_interfaces_bridge.py
+++ b/smoketest/scripts/cli/test_interfaces_bridge.py
@@ -25,72 +25,126 @@ from netifaces import interfaces
from vyos.ifconfig import Section
from vyos.util import cmd
from vyos.util import read_file
-
-class BridgeInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._test_ipv6 = True
- self._test_vlan = True
- self._test_qinq = True
- self._base_path = ['interfaces', 'bridge']
- self._mirror_interfaces = ['dum21354']
- self._members = []
+from vyos.util import get_interface_config
+from vyos.validate import is_intf_addr_assigned
+
+class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._test_ipv6_pd = True
+ cls._test_ipv6_dhcpc6 = True
+ cls._test_vlan = True
+ cls._base_path = ['interfaces', 'bridge']
+ cls._mirror_interfaces = ['dum21354']
+ cls._members = []
# we need to filter out VLAN interfaces identified by a dot (.)
# in their name - just in case!
if 'TEST_ETH' in os.environ:
- self._members = os.environ['TEST_ETH'].split()
+ cls._members = os.environ['TEST_ETH'].split()
else:
- for tmp in Section.interfaces("ethernet"):
+ for tmp in Section.interfaces('ethernet'):
if not '.' in tmp:
- self._members.append(tmp)
+ cls._members.append(tmp)
+
+ cls._options['br0'] = []
+ for member in cls._members:
+ cls._options['br0'].append(f'member interface {member}')
+ cls._interfaces = list(cls._options)
+
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
+
+ def tearDown(self):
+ for intf in self._interfaces:
+ self.cli_delete(self._base_path + [intf])
+
+ super().tearDown()
+
+ def test_isolated_interfaces(self):
+ # Add member interfaces to bridge and set STP cost/priority
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ self.cli_set(base + ['stp'])
- self._options['br0'] = []
- for member in self._members:
- self._options['br0'].append(f'member interface {member}')
- self._interfaces = list(self._options)
+ # assign members to bridge interface
+ for member in self._members:
+ base_member = base + ['member', 'interface', member]
+ self.cli_set(base_member + ['isolated'])
+
+ # commit config
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ tmp = get_interface_config(interface)
+ # STP must be enabled as configured above
+ self.assertEqual(1, tmp['linkinfo']['info_data']['stp_state'])
+
+ # validate member interface configuration
+ for member in self._members:
+ tmp = get_interface_config(member)
+ # Isolated must be enabled as configured above
+ self.assertTrue(tmp['linkinfo']['info_slave_data']['isolated'])
- super().setUp()
def test_add_remove_bridge_member(self):
# Add member interfaces to bridge and set STP cost/priority
for interface in self._interfaces:
base = self._base_path + [interface]
- self.session.set(base + ['stp'])
- self.session.set(base + ['address', '192.0.2.1/24'])
+ self.cli_set(base + ['stp'])
+ self.cli_set(base + ['address', '192.0.2.1/24'])
cost = 1000
priority = 10
# assign members to bridge interface
for member in self._members:
base_member = base + ['member', 'interface', member]
- self.session.set(base_member + ['cost', str(cost)])
- self.session.set(base_member + ['priority', str(priority)])
+ self.cli_set(base_member + ['cost', str(cost)])
+ self.cli_set(base_member + ['priority', str(priority)])
cost += 1
priority += 1
# commit config
- self.session.commit()
+ self.cli_commit()
- # check member interfaces are added on the bridge
- bridge_members = []
- for tmp in glob(f'/sys/class/net/{interface}/lower_*'):
- bridge_members.append(os.path.basename(tmp).replace('lower_', ''))
+ # Add member interfaces to bridge and set STP cost/priority
+ for interface in self._interfaces:
+ cost = 1000
+ priority = 10
+ for member in self._members:
+ tmp = get_interface_config(member)
+ self.assertEqual(interface, tmp['master'])
+ self.assertFalse( tmp['linkinfo']['info_slave_data']['isolated'])
+ self.assertEqual(cost, tmp['linkinfo']['info_slave_data']['cost'])
+ self.assertEqual(priority, tmp['linkinfo']['info_slave_data']['priority'])
- for member in self._members:
- self.assertIn(member, bridge_members)
+ cost += 1
+ priority += 1
- # delete all members
+
+ def test_vif_8021q_interfaces(self):
for interface in self._interfaces:
- self.session.delete(self._base_path + [interface, 'member'])
+ base = self._base_path + [interface]
+ self.cli_set(base + ['enable-vlan'])
+ super().test_vif_8021q_interfaces()
- self.session.commit()
+ def test_vif_8021q_lower_up_down(self):
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ self.cli_set(base + ['enable-vlan'])
+ super().test_vif_8021q_interfaces()
def test_bridge_vlan_filter(self):
+ vif_vlan = 2
# Add member interface to bridge and set VLAN filter
for interface in self._interfaces:
base = self._base_path + [interface]
- self.session.set(base + ['vif', '1', 'address', '192.0.2.1/24'])
- self.session.set(base + ['vif', '2', 'address', '192.0.3.1/24'])
+ self.cli_set(base + ['enable-vlan'])
+ self.cli_set(base + ['address', '192.0.2.1/24'])
+ self.cli_set(base + ['vif', str(vif_vlan), 'address', '192.0.3.1/24'])
+ self.cli_set(base + ['vif', str(vif_vlan), 'mtu', self._mtu])
vlan_id = 101
allowed_vlan = 2
@@ -98,13 +152,13 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest):
# assign members to bridge interface
for member in self._members:
base_member = base + ['member', 'interface', member]
- self.session.set(base_member + ['allowed-vlan', str(allowed_vlan)])
- self.session.set(base_member + ['allowed-vlan', allowed_vlan_range])
- self.session.set(base_member + ['native-vlan', str(vlan_id)])
+ self.cli_set(base_member + ['allowed-vlan', str(allowed_vlan)])
+ self.cli_set(base_member + ['allowed-vlan', allowed_vlan_range])
+ self.cli_set(base_member + ['native-vlan', str(vlan_id)])
vlan_id += 1
# commit config
- self.session.commit()
+ self.cli_commit()
# Detect the vlan filter function
for interface in self._interfaces:
@@ -160,7 +214,7 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest):
# delete all members
for interface in self._interfaces:
- self.session.delete(self._base_path + [interface, 'member'])
+ self.cli_delete(self._base_path + [interface, 'member'])
def test_bridge_vlan_members(self):
@@ -169,10 +223,10 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest):
for interface in self._interfaces:
for member in self._members:
for vif in vifs:
- self.session.set(['interfaces', 'ethernet', member, 'vif', vif])
- self.session.set(['interfaces', 'bridge', interface, 'member', 'interface', f'{member}.{vif}'])
+ self.cli_set(['interfaces', 'ethernet', member, 'vif', vif])
+ self.cli_set(['interfaces', 'bridge', interface, 'member', 'interface', f'{member}.{vif}'])
- self.session.commit()
+ self.cli_commit()
# Verify config
for interface in self._interfaces:
@@ -181,10 +235,12 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest):
# member interface must be assigned to the bridge
self.assertTrue(os.path.exists(f'/sys/class/net/{interface}/lower_{member}.{vif}'))
- # remove VLAN interfaces
- for vif in vifs:
- self.session.delete(['interfaces', 'ethernet', member, 'vif', vif])
+ # delete all members
+ for interface in self._interfaces:
+ for member in self._members:
+ for vif in vifs:
+ self.cli_delete(['interfaces', 'ethernet', member, 'vif', vif])
+ self.cli_delete(['interfaces', 'bridge', interface, 'member', 'interface', f'{member}.{vif}'])
if __name__ == '__main__':
- unittest.main(verbosity=2, failfast=True)
-
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_dummy.py b/smoketest/scripts/cli/test_interfaces_dummy.py
index c482a6f0b..dedc6fe05 100755
--- a/smoketest/scripts/cli/test_interfaces_dummy.py
+++ b/smoketest/scripts/cli/test_interfaces_dummy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -18,11 +18,13 @@ import unittest
from base_interfaces_test import BasicInterfaceTest
-class DummyInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._base_path = ['interfaces', 'dummy']
- self._interfaces = ['dum0', 'dum1', 'dum2']
- super().setUp()
+class DummyInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._base_path = ['interfaces', 'dummy']
+ cls._interfaces = ['dum435', 'dum8677', 'dum0931', 'dum089']
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py
index 3c4796283..cb0c8a426 100755
--- a/smoketest/scripts/cli/test_interfaces_ethernet.py
+++ b/smoketest/scripts/cli/test_interfaces_ethernet.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -19,6 +19,7 @@ import re
import unittest
from base_interfaces_test import BasicInterfaceTest
+from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.util import cmd
from vyos.util import process_named_running
@@ -33,37 +34,35 @@ def get_wpa_supplicant_value(interface, key):
tmp = re.findall(r'\n?{}=(.*)'.format(key), tmp)
return tmp[0]
-class EthernetInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._test_ip = True
- self._test_mtu = True
- self._test_vlan = True
- self._test_qinq = True
- self._test_ipv6 = True
- self._base_path = ['interfaces', 'ethernet']
- self._mirror_interfaces = ['dum21354']
+class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._test_ipv6_pd = True
+ cls._test_ipv6_dhcpc6 = True
+ cls._test_mtu = True
+ cls._test_vlan = True
+ cls._test_qinq = True
+ cls._base_path = ['interfaces', 'ethernet']
+ cls._mirror_interfaces = ['dum21354']
# we need to filter out VLAN interfaces identified by a dot (.)
# in their name - just in case!
if 'TEST_ETH' in os.environ:
tmp = os.environ['TEST_ETH'].split()
- self._interfaces = tmp
+ cls._interfaces = tmp
else:
- for tmp in Section.interfaces("ethernet"):
+ for tmp in Section.interfaces('ethernet'):
if not '.' in tmp:
- self._interfaces.append(tmp)
+ cls._interfaces.append(tmp)
- self._macs = {}
- for interface in self._interfaces:
- try:
- mac = self.session.show_config(self._base_path +
- [interface, 'hw-id']).split()[1]
- except:
- # during initial system startup there is no hw-id node
- mac = read_file(f'/sys/class/net/{interface}/address')
- self._macs[interface] = mac
+ cls._macs = {}
+ for interface in cls._interfaces:
+ cls._macs[interface] = read_file(f'/sys/class/net/{interface}/address')
- super().setUp()
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
def tearDown(self):
@@ -71,31 +70,34 @@ class EthernetInterfaceTest(BasicInterfaceTest.BaseTest):
# when using a dedicated interface to test via TEST_ETH environment
# variable only this one will be cleared in the end - usable to test
# ethernet interfaces via SSH
- self.session.delete(self._base_path + [interface])
- self.session.set(self._base_path + [interface, 'duplex', 'auto'])
- self.session.set(self._base_path + [interface, 'speed', 'auto'])
- self.session.set(self._base_path + [interface, 'hw-id', self._macs[interface]])
+ self.cli_delete(self._base_path + [interface])
+ self.cli_set(self._base_path + [interface, 'duplex', 'auto'])
+ self.cli_set(self._base_path + [interface, 'speed', 'auto'])
+ self.cli_set(self._base_path + [interface, 'hw-id', self._macs[interface]])
- super().tearDown()
+ # Tear down mirror interfaces for SPAN (Switch Port Analyzer)
+ for span in self._mirror_interfaces:
+ section = Section.section(span)
+ self.cli_delete(['interfaces', section, span])
+ self.cli_commit()
def test_dhcp_disable_interface(self):
# When interface is configured as admin down, it must be admin down
# even when dhcpc starts on the given interface
for interface in self._interfaces:
- self.session.set(self._base_path + [interface, 'disable'])
+ self.cli_set(self._base_path + [interface, 'disable'])
# Also enable DHCP (ISC DHCP always places interface in admin up
# state so we check that we do not start DHCP client.
# https://phabricator.vyos.net/T2767
- self.session.set(self._base_path + [interface, 'address', 'dhcp'])
+ self.cli_set(self._base_path + [interface, 'address', 'dhcp'])
- self.session.commit()
+ self.cli_commit()
# Validate interface state
for interface in self._interfaces:
- with open(f'/sys/class/net/{interface}/flags', 'r') as f:
- flags = f.read()
+ flags = read_file(f'/sys/class/net/{interface}/flags')
self.assertEqual(int(flags, 16) & 1, 0)
def test_offloading_rps(self):
@@ -111,9 +113,9 @@ class EthernetInterfaceTest(BasicInterfaceTest.BaseTest):
rps_cpus &= ~1
for interface in self._interfaces:
- self.session.set(self._base_path + [interface, 'offload', 'rps'])
+ self.cli_set(self._base_path + [interface, 'offload', 'rps'])
- self.session.commit()
+ self.cli_commit()
for interface in self._interfaces:
cpus = read_file('/sys/class/net/eth1/queues/rx-0/rps_cpus')
@@ -123,15 +125,37 @@ class EthernetInterfaceTest(BasicInterfaceTest.BaseTest):
self.assertEqual(f'{cpus:x}', f'{rps_cpus:x}')
+ def test_non_existing_interface(self):
+ unknonw_interface = self._base_path + ['eth667']
+ self.cli_set(unknonw_interface)
+
+ # check validate() - interface does not exist
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ # we need to remove this wrong interface from the configuration
+ # manually, else tearDown() will have problem in commit()
+ self.cli_delete(unknonw_interface)
+
+ def test_speed_duplex_verify(self):
+ for interface in self._interfaces:
+ self.cli_set(self._base_path + [interface, 'speed', '1000'])
+
+ # check validate() - if either speed or duplex is not auto, the
+ # other one must be manually configured, too
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'speed', 'auto'])
+ self.cli_commit()
def test_eapol_support(self):
for interface in self._interfaces:
# Enable EAPoL
- self.session.set(self._base_path + [interface, 'eapol', 'ca-cert-file', ca_cert])
- self.session.set(self._base_path + [interface, 'eapol', 'cert-file', ssl_cert])
- self.session.set(self._base_path + [interface, 'eapol', 'key-file', ssl_key])
+ self.cli_set(self._base_path + [interface, 'eapol', 'ca-cert-file', ca_cert])
+ self.cli_set(self._base_path + [interface, 'eapol', 'cert-file', ssl_cert])
+ self.cli_set(self._base_path + [interface, 'eapol', 'key-file', ssl_key])
- self.session.commit()
+ self.cli_commit()
# Check for running process
self.assertTrue(process_named_running('wpa_supplicant'))
@@ -169,12 +193,12 @@ if __name__ == '__main__':
# Generate mandatory SSL certificate
tmp = f'openssl req -newkey rsa:4096 -new -nodes -x509 -days 3650 '\
f'-keyout {ssl_key} -out {ssl_cert} -subj {subject}'
- print(cmd(tmp))
+ cmd(tmp)
if not os.path.isfile(ca_cert):
# Generate "CA"
tmp = f'openssl req -new -x509 -key {ssl_key} -out {ca_cert} -subj {subject}'
- print(cmd(tmp))
+ cmd(tmp)
for file in [ca_cert, ssl_cert, ssl_key]:
cmd(f'sudo chown radius_priv_user:vyattacfg {file}')
diff --git a/smoketest/scripts/cli/test_interfaces_geneve.py b/smoketest/scripts/cli/test_interfaces_geneve.py
index 98f55210f..129ee71e5 100755
--- a/smoketest/scripts/cli/test_interfaces_geneve.py
+++ b/smoketest/scripts/cli/test_interfaces_geneve.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -17,17 +17,65 @@
import unittest
from vyos.configsession import ConfigSession
+from vyos.ifconfig import Interface
+from vyos.util import get_interface_config
+
from base_interfaces_test import BasicInterfaceTest
-class GeneveInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._base_path = ['interfaces', 'geneve']
- self._options = {
+class GeneveInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._base_path = ['interfaces', 'geneve']
+ cls._options = {
'gnv0': ['vni 10', 'remote 127.0.1.1'],
'gnv1': ['vni 20', 'remote 127.0.1.2'],
+ 'gnv1': ['vni 30', 'remote 2001:db8::1', 'parameters ipv6 flowlabel 0x1000'],
}
- self._interfaces = list(self._options)
- super().setUp()
+ cls._interfaces = list(cls._options)
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
+
+ def test_geneve_parameters(self):
+ tos = '40'
+ ttl = 20
+ for intf in self._interfaces:
+ for option in self._options.get(intf, []):
+ self.cli_set(self._base_path + [intf] + option.split())
+
+ self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'dont-fragment'])
+ self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'tos', tos])
+ self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'ttl', str(ttl)])
+ ttl += 10
+
+ self.cli_commit()
+
+ ttl = 20
+ for interface in self._interfaces:
+ options = get_interface_config(interface)
+
+ vni = options['linkinfo']['info_data']['id']
+ self.assertIn(f'vni {vni}', self._options[interface])
+
+ if any('remote' in s for s in self._options[interface]):
+ key = 'remote'
+ if 'remote6' in options['linkinfo']['info_data']:
+ key = 'remote6'
+
+ remote = options['linkinfo']['info_data'][key]
+ self.assertIn(f'remote {remote}', self._options[interface])
+
+ if any('flowlabel' in s for s in self._options[interface]):
+ label = options['linkinfo']['info_data']['label']
+ self.assertIn(f'parameters ipv6 flowlabel {label}', self._options[interface])
+
+ self.assertEqual('geneve', options['linkinfo']['info_kind'])
+ self.assertEqual('set', options['linkinfo']['info_data']['df'])
+ self.assertEqual(f'0x{tos}', options['linkinfo']['info_data']['tos'])
+ self.assertEqual(ttl, options['linkinfo']['info_data']['ttl'])
+ self.assertEqual(Interface(interface).get_admin_state(), 'up')
+ ttl += 10
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_l2tpv3.py b/smoketest/scripts/cli/test_interfaces_l2tpv3.py
index c756bfdd5..24cb9464e 100755
--- a/smoketest/scripts/cli/test_interfaces_l2tpv3.py
+++ b/smoketest/scripts/cli/test_interfaces_l2tpv3.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -20,21 +20,25 @@ import unittest
from base_interfaces_test import BasicInterfaceTest
from vyos.util import cmd
-class GeneveInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._base_path = ['interfaces', 'l2tpv3']
- self._options = {
- 'l2tpeth10': ['local-ip 127.0.0.1', 'remote-ip 127.10.10.10',
+class GeneveInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._base_path = ['interfaces', 'l2tpv3']
+ cls._options = {
+ 'l2tpeth10': ['source-address 127.0.0.1', 'remote 127.10.10.10',
'tunnel-id 100', 'peer-tunnel-id 10',
'session-id 100', 'peer-session-id 10',
'source-port 1010', 'destination-port 10101'],
- 'l2tpeth20': ['local-ip 127.0.0.1', 'peer-session-id 20',
- 'peer-tunnel-id 200', 'remote-ip 127.20.20.20',
+ 'l2tpeth20': ['source-address 127.0.0.1', 'peer-session-id 20',
+ 'peer-tunnel-id 200', 'remote 127.20.20.20',
'session-id 20', 'tunnel-id 200',
'source-port 2020', 'destination-port 20202'],
}
- self._interfaces = list(self._options)
- super().setUp()
+ cls._interfaces = list(cls._options)
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
def test_add_single_ip_address(self):
super().test_add_single_ip_address()
diff --git a/smoketest/scripts/cli/test_interfaces_loopback.py b/smoketest/scripts/cli/test_interfaces_loopback.py
index 79225a1bd..85b5ca6d6 100755
--- a/smoketest/scripts/cli/test_interfaces_loopback.py
+++ b/smoketest/scripts/cli/test_interfaces_loopback.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -17,25 +17,40 @@
import unittest
from base_interfaces_test import BasicInterfaceTest
+from netifaces import interfaces
+
from vyos.validate import is_intf_addr_assigned
-class LoopbackInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- super().setUp()
- # these addresses are never allowed to be removed from the system
- self._loopback_addresses = ['127.0.0.1', '::1']
- self._base_path = ['interfaces', 'loopback']
- self._interfaces = ['lo']
+loopbacks = ['127.0.0.1', '::1']
+
+class LoopbackInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._base_path = ['interfaces', 'loopback']
+ cls._interfaces = ['lo']
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
+
+ def tearDown(self):
+ self.cli_delete(self._base_path)
+ self.cli_commit()
+
+ # loopback interface must persist!
+ for intf in self._interfaces:
+ self.assertIn(intf, interfaces())
def test_add_single_ip_address(self):
super().test_add_single_ip_address()
- for addr in self._loopback_addresses:
+ for addr in loopbacks:
self.assertTrue(is_intf_addr_assigned('lo', addr))
def test_add_multiple_ip_addresses(self):
super().test_add_multiple_ip_addresses()
- for addr in self._loopback_addresses:
+ for addr in loopbacks:
self.assertTrue(is_intf_addr_assigned('lo', addr))
+ def test_interface_disable(self):
+ self.skipTest('not supported')
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py
index d9635951f..e4280a5b7 100755
--- a/smoketest/scripts/cli/test_interfaces_macsec.py
+++ b/smoketest/scripts/cli/test_interfaces_macsec.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
import re
import unittest
@@ -22,7 +23,9 @@ from netifaces import interfaces
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
+from vyos.util import cmd
from vyos.util import read_file
+from vyos.util import get_interface_config
from vyos.util import process_named_running
def get_config_value(interface, key):
@@ -30,18 +33,26 @@ def get_config_value(interface, key):
tmp = re.findall(r'\n?{}=(.*)'.format(key), tmp)
return tmp[0]
-class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- super().setUp()
- self._base_path = ['interfaces', 'macsec']
- self._options = { 'macsec0': ['source-interface eth0', 'security cipher gcm-aes-128'] }
+def get_cipher(interface):
+ tmp = get_interface_config(interface)
+ return tmp['linkinfo']['info_data']['cipher_suite'].lower()
- # if we have a physical eth1 interface, add a second macsec instance
- if 'eth1' in Section.interfaces("ethernet"):
- macsec = { 'macsec1': [f'source-interface eth1', 'security cipher gcm-aes-128'] }
- self._options.update(macsec)
+class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._base_path = ['interfaces', 'macsec']
+ cls._options = { 'macsec0': ['source-interface eth0', 'security cipher gcm-aes-128'] }
- self._interfaces = list(self._options)
+ # if we have a physical eth1 interface, add a second macsec instance
+ if 'eth1' in Section.interfaces('ethernet'):
+ macsec = { 'macsec1': [f'source-interface eth1', 'security cipher gcm-aes-128'] }
+ cls._options.update(macsec)
+
+ cls._interfaces = list(cls._options)
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
def test_macsec_encryption(self):
# MACsec can be operating in authentication and encryption mode - both
@@ -57,31 +68,31 @@ class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
if option.split()[0] == 'source-interface':
src_interface = option.split()[1]
- self.session.set(self._base_path + [interface] + option.split())
+ self.cli_set(self._base_path + [interface] + option.split())
# Encrypt link
- self.session.set(self._base_path + [interface, 'security', 'encrypt'])
+ self.cli_set(self._base_path + [interface, 'security', 'encrypt'])
# check validate() - Physical source interface MTU must be higher then our MTU
- self.session.set(self._base_path + [interface, 'mtu', '1500'])
+ self.cli_set(self._base_path + [interface, 'mtu', '1500'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(self._base_path + [interface, 'mtu'])
+ self.cli_commit()
+ self.cli_delete(self._base_path + [interface, 'mtu'])
# check validate() - MACsec security keys mandartory when encryption is enabled
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'security', 'mka', 'cak', mak_cak])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'mka', 'cak', mak_cak])
# check validate() - MACsec security keys mandartory when encryption is enabled
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'security', 'mka', 'ckn', mak_ckn])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'mka', 'ckn', mak_ckn])
- self.session.set(self._base_path + [interface, 'security', 'replay-window', replay_window])
+ self.cli_set(self._base_path + [interface, 'security', 'replay-window', replay_window])
# final commit of settings
- self.session.commit()
+ self.cli_commit()
tmp = get_config_value(src_interface, 'macsec_integ_only')
self.assertTrue("0" in tmp)
@@ -105,23 +116,46 @@ class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
# Check for running process
self.assertTrue(process_named_running('wpa_supplicant'))
- def test_macsec_mandatory_options(self):
+ def test_macsec_gcm_aes_128(self):
interface = 'macsec1'
- self.session.set(self._base_path + [interface])
+ cipher = 'gcm-aes-128'
+ self.cli_set(self._base_path + [interface])
+
+ # check validate() - source interface is mandatory
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'source-interface', 'eth0'])
+
+ # check validate() - cipher is mandatory
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'cipher', cipher])
+
+ # final commit and verify
+ self.cli_commit()
+ self.assertIn(interface, interfaces())
+ self.assertIn(interface, interfaces())
+ self.assertEqual(cipher, get_cipher(interface))
+
+ def test_macsec_gcm_aes_256(self):
+ interface = 'macsec4'
+ cipher = 'gcm-aes-256'
+ self.cli_set(self._base_path + [interface])
# check validate() - source interface is mandatory
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'source-interface', 'eth0'])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'source-interface', 'eth0'])
# check validate() - cipher is mandatory
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'security', 'cipher', 'gcm-aes-128'])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'cipher', cipher])
# final commit and verify
- self.session.commit()
+ self.cli_commit()
self.assertIn(interface, interfaces())
+ self.assertEqual(cipher, get_cipher(interface))
def test_macsec_source_interface(self):
# Ensure source-interface can bot be part of any other bond or bridge
@@ -131,24 +165,24 @@ class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
for interface, option_value in self._options.items():
for option in option_value:
- self.session.set(self._base_path + [interface] + option.split())
+ self.cli_set(self._base_path + [interface] + option.split())
if option.split()[0] == 'source-interface':
src_interface = option.split()[1]
- self.session.set(base_bridge + ['member', 'interface', src_interface])
+ self.cli_set(base_bridge + ['member', 'interface', src_interface])
# check validate() - Source interface must not already be a member of a bridge
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(base_bridge)
+ self.cli_commit()
+ self.cli_delete(base_bridge)
- self.session.set(base_bond + ['member', 'interface', src_interface])
+ self.cli_set(base_bond + ['member', 'interface', src_interface])
# check validate() - Source interface must not already be a member of a bridge
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(base_bond)
+ self.cli_commit()
+ self.cli_delete(base_bond)
# final commit and verify
- self.session.commit()
+ self.cli_commit()
self.assertIn(interface, interfaces())
if __name__ == '__main__':
diff --git a/smoketest/scripts/cli/test_interfaces_openvpn.py b/smoketest/scripts/cli/test_interfaces_openvpn.py
index 00db3f667..655ee770d 100755
--- a/smoketest/scripts/cli/test_interfaces_openvpn.py
+++ b/smoketest/scripts/cli/test_interfaces_openvpn.py
@@ -21,6 +21,8 @@ from glob import glob
from ipaddress import IPv4Network
from netifaces import interfaces
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.util import cmd
@@ -58,85 +60,83 @@ def get_vrf(interface):
tmp = tmp.replace('upper_', '')
return tmp
-class TestInterfacesOpenVPN(unittest.TestCase):
+class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
- self.session.set(['interfaces', 'dummy', dummy_if, 'address', '192.0.2.1/32'])
- self.session.set(['vrf', 'name', vrf_name, 'table', '12345'])
+ self.cli_set(['interfaces', 'dummy', dummy_if, 'address', '192.0.2.1/32'])
+ self.cli_set(['vrf', 'name', vrf_name, 'table', '12345'])
def tearDown(self):
- self.session.delete(base_path)
- self.session.delete(['interfaces', 'dummy', dummy_if])
- self.session.delete(['vrf'])
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_delete(['interfaces', 'dummy', dummy_if])
+ self.cli_delete(['vrf'])
+ self.cli_commit()
def test_openvpn_client_verify(self):
# Create OpenVPN client interface and test verify() steps.
interface = 'vtun2000'
path = base_path + [interface]
- self.session.set(path + ['mode', 'client'])
+ self.cli_set(path + ['mode', 'client'])
# check validate() - cannot specify both "encryption disable-ncp" and
# "encryption ncp-ciphers" at the same time
- self.session.set(path + ['encryption', 'disable-ncp'])
- self.session.set(path + ['encryption', 'ncp-ciphers', 'aes192gcm'])
+ self.cli_set(path + ['encryption', 'disable-ncp'])
+ self.cli_set(path + ['encryption', 'ncp-ciphers', 'aes192gcm'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['encryption', 'ncp-ciphers'])
+ self.cli_commit()
+ self.cli_delete(path + ['encryption', 'ncp-ciphers'])
# check validate() - cannot specify local-port in client mode
- self.session.set(path + ['local-port', '5000'])
+ self.cli_set(path + ['local-port', '5000'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['local-port'])
+ self.cli_commit()
+ self.cli_delete(path + ['local-port'])
# check validate() - cannot specify local-host in client mode
- self.session.set(path + ['local-host', '127.0.0.1'])
+ self.cli_set(path + ['local-host', '127.0.0.1'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['local-host'])
+ self.cli_commit()
+ self.cli_delete(path + ['local-host'])
# check validate() - cannot specify protocol tcp-passive in client mode
- self.session.set(path + ['protocol', 'tcp-passive'])
+ self.cli_set(path + ['protocol', 'tcp-passive'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['protocol'])
+ self.cli_commit()
+ self.cli_delete(path + ['protocol'])
# check validate() - remote-host must be set in client mode
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['remote-host', '192.0.9.9'])
+ self.cli_commit()
+ self.cli_set(path + ['remote-host', '192.0.9.9'])
# check validate() - cannot specify "tls dh-file" in client mode
- self.session.set(path + ['tls', 'dh-file', dh_pem])
+ self.cli_set(path + ['tls', 'dh-file', dh_pem])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['tls'])
+ self.cli_commit()
+ self.cli_delete(path + ['tls'])
# check validate() - must specify one of "shared-secret-key-file" and "tls"
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['shared-secret-key-file', s2s_key])
+ self.cli_commit()
+ self.cli_set(path + ['shared-secret-key-file', s2s_key])
# check validate() - must specify one of "shared-secret-key-file" and "tls"
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['shared-secret-key-file', s2s_key])
+ self.cli_commit()
+ self.cli_delete(path + ['shared-secret-key-file', s2s_key])
- self.session.set(path + ['tls', 'ca-cert-file', ca_cert])
- self.session.set(path + ['tls', 'cert-file', ssl_cert])
- self.session.set(path + ['tls', 'key-file', ssl_key])
+ self.cli_set(path + ['tls', 'ca-cert-file', ca_cert])
+ self.cli_set(path + ['tls', 'cert-file', ssl_cert])
+ self.cli_set(path + ['tls', 'key-file', ssl_key])
# check validate() - can not have auth username without a password
- self.session.set(path + ['authentication', 'username', 'vyos'])
+ self.cli_set(path + ['authentication', 'username', 'vyos'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['authentication', 'password', 'vyos'])
+ self.cli_commit()
+ self.cli_set(path + ['authentication', 'password', 'vyos'])
# client commit must pass
- self.session.commit()
+ self.cli_commit()
self.assertTrue(process_named_running(PROCESS_NAME))
self.assertIn(interface, interfaces())
@@ -152,22 +152,22 @@ class TestInterfacesOpenVPN(unittest.TestCase):
path = base_path + [interface]
auth_hash = 'sha1'
- self.session.set(path + ['device-type', 'tun'])
- self.session.set(path + ['encryption', 'cipher', 'aes256'])
- self.session.set(path + ['hash', auth_hash])
- self.session.set(path + ['mode', 'client'])
- self.session.set(path + ['persistent-tunnel'])
- self.session.set(path + ['protocol', protocol])
- self.session.set(path + ['remote-host', remote_host])
- self.session.set(path + ['remote-port', remote_port])
- self.session.set(path + ['tls', 'ca-cert-file', ca_cert])
- self.session.set(path + ['tls', 'cert-file', ssl_cert])
- self.session.set(path + ['tls', 'key-file', ssl_key])
- self.session.set(path + ['vrf', vrf_name])
- self.session.set(path + ['authentication', 'username', interface+'user'])
- self.session.set(path + ['authentication', 'password', interface+'secretpw'])
-
- self.session.commit()
+ self.cli_set(path + ['device-type', 'tun'])
+ self.cli_set(path + ['encryption', 'cipher', 'aes256'])
+ self.cli_set(path + ['hash', auth_hash])
+ self.cli_set(path + ['mode', 'client'])
+ self.cli_set(path + ['persistent-tunnel'])
+ self.cli_set(path + ['protocol', protocol])
+ self.cli_set(path + ['remote-host', remote_host])
+ self.cli_set(path + ['remote-port', remote_port])
+ self.cli_set(path + ['tls', 'ca-cert-file', ca_cert])
+ self.cli_set(path + ['tls', 'cert-file', ssl_cert])
+ self.cli_set(path + ['tls', 'key-file', ssl_key])
+ self.cli_set(path + ['vrf', vrf_name])
+ self.cli_set(path + ['authentication', 'username', interface+'user'])
+ self.cli_set(path + ['authentication', 'password', interface+'secretpw'])
+
+ self.cli_commit()
for ii in num_range:
interface = f'vtun{ii}'
@@ -200,8 +200,8 @@ class TestInterfacesOpenVPN(unittest.TestCase):
self.assertIn(f'{interface}secretpw', pw)
# check that no interface remained after deleting them
- self.session.delete(base_path)
- self.session.commit()
+ self.cli_delete(base_path)
+ self.cli_commit()
for ii in num_range:
interface = f'vtun{ii}'
@@ -213,104 +213,104 @@ class TestInterfacesOpenVPN(unittest.TestCase):
path = base_path + [interface]
# check validate() - must speciy operating mode
- self.session.set(path)
+ self.cli_set(path)
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['mode', 'server'])
+ self.cli_commit()
+ self.cli_set(path + ['mode', 'server'])
# check validate() - cannot specify protocol tcp-active in server mode
- self.session.set(path + ['protocol', 'tcp-active'])
+ self.cli_set(path + ['protocol', 'tcp-active'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['protocol'])
+ self.cli_commit()
+ self.cli_delete(path + ['protocol'])
# check validate() - cannot specify local-port in client mode
- self.session.set(path + ['remote-port', '5000'])
+ self.cli_set(path + ['remote-port', '5000'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['remote-port'])
+ self.cli_commit()
+ self.cli_delete(path + ['remote-port'])
# check validate() - cannot specify local-host in client mode
- self.session.set(path + ['remote-host', '127.0.0.1'])
+ self.cli_set(path + ['remote-host', '127.0.0.1'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['remote-host'])
+ self.cli_commit()
+ self.cli_delete(path + ['remote-host'])
# check validate() - must specify "tls dh-file" when not using EC keys
# in server mode
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['tls', 'dh-file', dh_pem])
+ self.cli_commit()
+ self.cli_set(path + ['tls', 'dh-file', dh_pem])
# check validate() - must specify "server subnet" or add interface to
# bridge in server mode
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
# check validate() - server client-ip-pool is too large
# [100.64.0.4 -> 100.127.255.251 = 4194295], maximum is 65536 addresses.
- self.session.set(path + ['server', 'subnet', '100.64.0.0/10'])
+ self.cli_set(path + ['server', 'subnet', '100.64.0.0/10'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
# check validate() - cannot specify more than 1 IPv4 and 1 IPv6 server subnet
- self.session.set(path + ['server', 'subnet', '100.64.0.0/20'])
+ self.cli_set(path + ['server', 'subnet', '100.64.0.0/20'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['server', 'subnet', '100.64.0.0/10'])
+ self.cli_commit()
+ self.cli_delete(path + ['server', 'subnet', '100.64.0.0/10'])
# check validate() - must specify "tls ca-cert-file"
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['tls', 'ca-cert-file', ca_cert])
+ self.cli_commit()
+ self.cli_set(path + ['tls', 'ca-cert-file', ca_cert])
# check validate() - must specify "tls cert-file"
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['tls', 'cert-file', ssl_cert])
+ self.cli_commit()
+ self.cli_set(path + ['tls', 'cert-file', ssl_cert])
# check validate() - must specify "tls key-file"
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['tls', 'key-file', ssl_key])
+ self.cli_commit()
+ self.cli_set(path + ['tls', 'key-file', ssl_key])
# check validate() - cannot specify "tls role" in client-server mode'
- self.session.set(path + ['tls', 'role', 'active'])
+ self.cli_set(path + ['tls', 'role', 'active'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
# check validate() - cannot specify "tls role" in client-server mode'
- self.session.set(path + ['tls', 'auth-file', auth_key])
+ self.cli_set(path + ['tls', 'auth-file', auth_key])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
# check validate() - cannot specify "tcp-passive" when "tls role" is "active"
- self.session.set(path + ['protocol', 'tcp-passive'])
+ self.cli_set(path + ['protocol', 'tcp-passive'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['protocol'])
+ self.cli_commit()
+ self.cli_delete(path + ['protocol'])
# check validate() - cannot specify "tls dh-file" when "tls role" is "active"
- self.session.set(path + ['tls', 'dh-file', dh_pem])
+ self.cli_set(path + ['tls', 'dh-file', dh_pem])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['tls', 'dh-file'])
+ self.cli_commit()
+ self.cli_delete(path + ['tls', 'dh-file'])
# Now test the other path with tls role passive
- self.session.set(path + ['tls', 'role', 'passive'])
+ self.cli_set(path + ['tls', 'role', 'passive'])
# check validate() - cannot specify "tcp-active" when "tls role" is "passive"
- self.session.set(path + ['protocol', 'tcp-active'])
+ self.cli_set(path + ['protocol', 'tcp-active'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['protocol'])
+ self.cli_commit()
+ self.cli_delete(path + ['protocol'])
# check validate() - must specify "tls dh-file" when "tls role" is "passive"
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['tls', 'dh-file', dh_pem])
+ self.cli_commit()
+ self.cli_set(path + ['tls', 'dh-file', dh_pem])
- self.session.commit()
+ self.cli_commit()
self.assertTrue(process_named_running(PROCESS_NAME))
self.assertIn(interface, interfaces())
@@ -330,29 +330,29 @@ class TestInterfacesOpenVPN(unittest.TestCase):
path = base_path + [interface]
port = str(2000 + ii)
- self.session.set(path + ['device-type', 'tun'])
- self.session.set(path + ['encryption', 'cipher', 'aes192'])
- self.session.set(path + ['hash', auth_hash])
- self.session.set(path + ['mode', 'server'])
- self.session.set(path + ['local-port', port])
- self.session.set(path + ['server', 'subnet', subnet])
- self.session.set(path + ['server', 'topology', 'subnet'])
- self.session.set(path + ['keep-alive', 'failure-count', '5'])
- self.session.set(path + ['keep-alive', 'interval', '5'])
+ self.cli_set(path + ['device-type', 'tun'])
+ self.cli_set(path + ['encryption', 'cipher', 'aes192'])
+ self.cli_set(path + ['hash', auth_hash])
+ self.cli_set(path + ['mode', 'server'])
+ self.cli_set(path + ['local-port', port])
+ self.cli_set(path + ['server', 'subnet', subnet])
+ self.cli_set(path + ['server', 'topology', 'subnet'])
+ self.cli_set(path + ['keep-alive', 'failure-count', '5'])
+ self.cli_set(path + ['keep-alive', 'interval', '5'])
# clients
- self.session.set(path + ['server', 'client', 'client1', 'ip', client_ip])
+ self.cli_set(path + ['server', 'client', 'client1', 'ip', client_ip])
for route in client1_routes:
- self.session.set(path + ['server', 'client', 'client1', 'subnet', route])
+ self.cli_set(path + ['server', 'client', 'client1', 'subnet', route])
- self.session.set(path + ['replace-default-route'])
- self.session.set(path + ['tls', 'ca-cert-file', ca_cert])
- self.session.set(path + ['tls', 'cert-file', ssl_cert])
- self.session.set(path + ['tls', 'key-file', ssl_key])
- self.session.set(path + ['tls', 'dh-file', dh_pem])
- self.session.set(path + ['vrf', vrf_name])
+ self.cli_set(path + ['replace-default-route'])
+ self.cli_set(path + ['tls', 'ca-cert-file', ca_cert])
+ self.cli_set(path + ['tls', 'cert-file', ssl_cert])
+ self.cli_set(path + ['tls', 'key-file', ssl_key])
+ self.cli_set(path + ['tls', 'dh-file', dh_pem])
+ self.cli_set(path + ['vrf', vrf_name])
- self.session.commit()
+ self.cli_commit()
for ii in num_range:
interface = f'vtun{ii}'
@@ -404,8 +404,8 @@ class TestInterfacesOpenVPN(unittest.TestCase):
self.assertIn(interface, interfaces())
# check that no interface remained after deleting them
- self.session.delete(base_path)
- self.session.commit()
+ self.cli_delete(base_path)
+ self.cli_commit()
for ii in num_range:
interface = f'vtun{ii}'
@@ -423,23 +423,23 @@ class TestInterfacesOpenVPN(unittest.TestCase):
path = base_path + [interface]
port = str(2000 + ii)
- self.session.set(path + ['device-type', 'tun'])
- self.session.set(path + ['encryption', 'cipher', 'aes192'])
- self.session.set(path + ['hash', auth_hash])
- self.session.set(path + ['mode', 'server'])
- self.session.set(path + ['local-port', port])
- self.session.set(path + ['server', 'subnet', subnet])
- self.session.set(path + ['server', 'topology', 'net30'])
- self.session.set(path + ['replace-default-route'])
- self.session.set(path + ['keep-alive', 'failure-count', '10'])
- self.session.set(path + ['keep-alive', 'interval', '5'])
- self.session.set(path + ['tls', 'ca-cert-file', ca_cert])
- self.session.set(path + ['tls', 'cert-file', ssl_cert])
- self.session.set(path + ['tls', 'key-file', ssl_key])
- self.session.set(path + ['tls', 'dh-file', dh_pem])
- self.session.set(path + ['vrf', vrf_name])
-
- self.session.commit()
+ self.cli_set(path + ['device-type', 'tun'])
+ self.cli_set(path + ['encryption', 'cipher', 'aes192'])
+ self.cli_set(path + ['hash', auth_hash])
+ self.cli_set(path + ['mode', 'server'])
+ self.cli_set(path + ['local-port', port])
+ self.cli_set(path + ['server', 'subnet', subnet])
+ self.cli_set(path + ['server', 'topology', 'net30'])
+ self.cli_set(path + ['replace-default-route'])
+ self.cli_set(path + ['keep-alive', 'failure-count', '10'])
+ self.cli_set(path + ['keep-alive', 'interval', '5'])
+ self.cli_set(path + ['tls', 'ca-cert-file', ca_cert])
+ self.cli_set(path + ['tls', 'cert-file', ssl_cert])
+ self.cli_set(path + ['tls', 'key-file', ssl_key])
+ self.cli_set(path + ['tls', 'dh-file', dh_pem])
+ self.cli_set(path + ['vrf', vrf_name])
+
+ self.cli_commit()
for ii in num_range:
interface = f'vtun{ii}'
@@ -479,8 +479,8 @@ class TestInterfacesOpenVPN(unittest.TestCase):
self.assertIn(interface, interfaces())
# check that no interface remained after deleting them
- self.session.delete(base_path)
- self.session.commit()
+ self.cli_delete(base_path)
+ self.cli_commit()
for ii in num_range:
interface = f'vtun{ii}'
@@ -493,57 +493,57 @@ class TestInterfacesOpenVPN(unittest.TestCase):
interface = 'vtun5000'
path = base_path + [interface]
- self.session.set(path + ['mode', 'site-to-site'])
+ self.cli_set(path + ['mode', 'site-to-site'])
# check validate() - encryption ncp-ciphers cannot be specified in site-to-site mode
- self.session.set(path + ['encryption', 'ncp-ciphers', 'aes192gcm'])
+ self.cli_set(path + ['encryption', 'ncp-ciphers', 'aes192gcm'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['encryption'])
+ self.cli_commit()
+ self.cli_delete(path + ['encryption'])
# check validate() - must specify "local-address" or add interface to bridge
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['local-address', '10.0.0.1'])
- self.session.set(path + ['local-address', '2001:db8:1::1'])
+ self.cli_commit()
+ self.cli_set(path + ['local-address', '10.0.0.1'])
+ self.cli_set(path + ['local-address', '2001:db8:1::1'])
# check validate() - cannot specify more than 1 IPv4 local-address
- self.session.set(path + ['local-address', '10.0.0.2'])
+ self.cli_set(path + ['local-address', '10.0.0.2'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['local-address', '10.0.0.2'])
+ self.cli_commit()
+ self.cli_delete(path + ['local-address', '10.0.0.2'])
# check validate() - cannot specify more than 1 IPv6 local-address
- self.session.set(path + ['local-address', '2001:db8:1::2'])
+ self.cli_set(path + ['local-address', '2001:db8:1::2'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['local-address', '2001:db8:1::2'])
+ self.cli_commit()
+ self.cli_delete(path + ['local-address', '2001:db8:1::2'])
# check validate() - IPv4 "local-address" requires IPv4 "remote-address"
# or IPv4 "local-address subnet"
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['remote-address', '192.168.0.1'])
- self.session.set(path + ['remote-address', '2001:db8:ffff::1'])
+ self.cli_commit()
+ self.cli_set(path + ['remote-address', '192.168.0.1'])
+ self.cli_set(path + ['remote-address', '2001:db8:ffff::1'])
# check validate() - Cannot specify more than 1 IPv4 "remote-address"
- self.session.set(path + ['remote-address', '192.168.0.2'])
+ self.cli_set(path + ['remote-address', '192.168.0.2'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['remote-address', '192.168.0.2'])
+ self.cli_commit()
+ self.cli_delete(path + ['remote-address', '192.168.0.2'])
# check validate() - Cannot specify more than 1 IPv6 "remote-address"
- self.session.set(path + ['remote-address', '2001:db8:ffff::2'])
+ self.cli_set(path + ['remote-address', '2001:db8:ffff::2'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(path + ['remote-address', '2001:db8:ffff::2'])
+ self.cli_commit()
+ self.cli_delete(path + ['remote-address', '2001:db8:ffff::2'])
# check validate() - Must specify one of "shared-secret-key-file" and "tls"
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(path + ['shared-secret-key-file', s2s_key])
+ self.cli_commit()
+ self.cli_set(path + ['shared-secret-key-file', s2s_key])
- self.session.commit()
+ self.cli_commit()
def test_openvpn_site2site_interfaces_tun(self):
# Create two OpenVPN site-to-site interfaces
@@ -561,23 +561,23 @@ class TestInterfacesOpenVPN(unittest.TestCase):
path = base_path + [interface]
port = str(3000 + ii)
- self.session.set(path + ['local-address', local_address])
+ self.cli_set(path + ['local-address', local_address])
# even numbers use tun type, odd numbers use tap type
if ii % 2 == 0:
- self.session.set(path + ['device-type', 'tun'])
+ self.cli_set(path + ['device-type', 'tun'])
else:
- self.session.set(path + ['device-type', 'tap'])
- self.session.set(path + ['local-address', local_address, 'subnet-mask', local_address_subnet])
+ self.cli_set(path + ['device-type', 'tap'])
+ self.cli_set(path + ['local-address', local_address, 'subnet-mask', local_address_subnet])
- self.session.set(path + ['mode', 'site-to-site'])
- self.session.set(path + ['local-port', port])
- self.session.set(path + ['remote-port', port])
- self.session.set(path + ['shared-secret-key-file', s2s_key])
- self.session.set(path + ['remote-address', remote_address])
- self.session.set(path + ['vrf', vrf_name])
+ self.cli_set(path + ['mode', 'site-to-site'])
+ self.cli_set(path + ['local-port', port])
+ self.cli_set(path + ['remote-port', port])
+ self.cli_set(path + ['shared-secret-key-file', s2s_key])
+ self.cli_set(path + ['remote-address', remote_address])
+ self.cli_set(path + ['vrf', vrf_name])
- self.session.commit()
+ self.cli_commit()
for ii in num_range:
interface = f'vtun{ii}'
@@ -608,8 +608,8 @@ class TestInterfacesOpenVPN(unittest.TestCase):
# check that no interface remained after deleting them
- self.session.delete(base_path)
- self.session.commit()
+ self.cli_delete(base_path)
+ self.cli_commit()
for ii in num_range:
interface = f'vtun{ii}'
@@ -625,27 +625,27 @@ if __name__ == '__main__':
# Generate mandatory SSL certificate
tmp = f'openssl req -newkey rsa:4096 -new -nodes -x509 -days 3650 '\
f'-keyout {ssl_key} -out {ssl_cert} -subj {subject}'
- print(cmd(tmp))
+ cmd(tmp)
if not os.path.isfile(ca_cert):
# Generate "CA"
tmp = f'openssl req -new -x509 -key {ssl_key} -out {ca_cert} -subj {subject}'
- print(cmd(tmp))
+ cmd(tmp)
if not os.path.isfile(dh_pem):
# Generate "DH" key
tmp = f'openssl dhparam -out {dh_pem} 2048'
- print(cmd(tmp))
+ cmd(tmp)
if not os.path.isfile(s2s_key):
# Generate site-2-site key
tmp = f'openvpn --genkey --secret {s2s_key}'
- print(cmd(tmp))
+ cmd(tmp)
if not os.path.isfile(auth_key):
# Generate TLS auth key
tmp = f'openvpn --genkey --secret {auth_key}'
- print(cmd(tmp))
+ cmd(tmp)
for file in [ca_cert, ssl_cert, ssl_key, dh_pem, s2s_key, auth_key]:
cmd(f'sudo chown openvpn:openvpn {file}')
diff --git a/smoketest/scripts/cli/test_interfaces_pppoe.py b/smoketest/scripts/cli/test_interfaces_pppoe.py
index 6bfe35d86..b8682fe71 100755
--- a/smoketest/scripts/cli/test_interfaces_pppoe.py
+++ b/smoketest/scripts/cli/test_interfaces_pppoe.py
@@ -15,11 +15,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
-import os
import unittest
from psutil import process_iter
-from vyos.configsession import ConfigSession, ConfigSessionError
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
from vyos.util import read_file
config_file = '/etc/ppp/peers/{}'
@@ -42,16 +44,14 @@ def get_dhcp6c_config_value(interface, key):
out.append(item.replace(';',''))
return out
-class PPPoEInterfaceTest(unittest.TestCase):
+class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
self._interfaces = ['pppoe10', 'pppoe20', 'pppoe30']
self._source_interface = 'eth0'
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_pppoe_client(self):
# Check if PPPoE dialer can be configured and runs
@@ -60,19 +60,19 @@ class PPPoEInterfaceTest(unittest.TestCase):
passwd = 'VyOS-passwd-' + interface
mtu = '1400'
- self.session.set(base_path + [interface, 'authentication', 'user', user])
- self.session.set(base_path + [interface, 'authentication', 'password', passwd])
- self.session.set(base_path + [interface, 'default-route', 'auto'])
- self.session.set(base_path + [interface, 'mtu', mtu])
- self.session.set(base_path + [interface, 'no-peer-dns'])
+ self.cli_set(base_path + [interface, 'authentication', 'user', user])
+ self.cli_set(base_path + [interface, 'authentication', 'password', passwd])
+ self.cli_set(base_path + [interface, 'default-route', 'auto'])
+ self.cli_set(base_path + [interface, 'mtu', mtu])
+ self.cli_set(base_path + [interface, 'no-peer-dns'])
# check validate() - a source-interface is required
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + [interface, 'source-interface', self._source_interface])
+ self.cli_commit()
+ self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
# commit changes
- self.session.commit()
+ self.cli_commit()
# verify configuration file(s)
for interface in self._interfaces:
@@ -97,27 +97,48 @@ class PPPoEInterfaceTest(unittest.TestCase):
self.assertTrue(running)
+
+ def test_pppoe_clent_disabled_interface(self):
+ # Check if PPPoE Client can be disabled
+ for interface in self._interfaces:
+ self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos'])
+ self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos'])
+ self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
+ self.cli_set(base_path + [interface, 'disable'])
+
+ self.cli_commit()
+
+ # Validate PPPoE client process
+ running = False
+ for interface in self._interfaces:
+ for proc in process_iter():
+ if interface in proc.cmdline():
+ running = True
+
+ self.assertFalse(running)
+
+
def test_pppoe_dhcpv6pd(self):
# Check if PPPoE dialer can be configured with DHCPv6-PD
address = '1'
sla_id = '0'
sla_len = '8'
for interface in self._interfaces:
- self.session.set(base_path + [interface, 'authentication', 'user', 'vyos'])
- self.session.set(base_path + [interface, 'authentication', 'password', 'vyos'])
- self.session.set(base_path + [interface, 'default-route', 'none'])
- self.session.set(base_path + [interface, 'no-peer-dns'])
- self.session.set(base_path + [interface, 'source-interface', self._source_interface])
- self.session.set(base_path + [interface, 'ipv6', 'address', 'autoconf'])
+ self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos'])
+ self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos'])
+ self.cli_set(base_path + [interface, 'default-route', 'none'])
+ self.cli_set(base_path + [interface, 'no-peer-dns'])
+ self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
+ self.cli_set(base_path + [interface, 'ipv6', 'address', 'autoconf'])
# prefix delegation stuff
dhcpv6_pd_base = base_path + [interface, 'dhcpv6-options', 'pd', '0']
- self.session.set(dhcpv6_pd_base + ['length', '56'])
- self.session.set(dhcpv6_pd_base + ['interface', self._source_interface, 'address', address])
- self.session.set(dhcpv6_pd_base + ['interface', self._source_interface, 'sla-id', sla_id])
+ self.cli_set(dhcpv6_pd_base + ['length', '56'])
+ self.cli_set(dhcpv6_pd_base + ['interface', self._source_interface, 'address', address])
+ self.cli_set(dhcpv6_pd_base + ['interface', self._source_interface, 'sla-id', sla_id])
# commit changes
- self.session.commit()
+ self.cli_commit()
# verify "normal" PPPoE value - 1492 is default MTU
tmp = get_config_value(interface, 'mtu')[1]
diff --git a/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py b/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py
index 85e5e70bd..ff343bb87 100755
--- a/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py
+++ b/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -18,20 +18,24 @@ import unittest
from base_interfaces_test import BasicInterfaceTest
-class PEthInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._test_ip = True
- self._test_ipv6 = True
- self._test_mtu = True
- self._test_vlan = True
- self._test_qinq = True
- self._base_path = ['interfaces', 'pseudo-ethernet']
- self._options = {
+class PEthInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._test_ipv6_pd = True
+ cls._test_ipv6_dhcpc6 = True
+ cls._test_mtu = True
+ cls._test_vlan = True
+ cls._test_qinq = True
+ cls._base_path = ['interfaces', 'pseudo-ethernet']
+ cls._options = {
'peth0': ['source-interface eth1'],
'peth1': ['source-interface eth1'],
}
- self._interfaces = list(self._options)
- super().setUp()
+ cls._interfaces = list(cls._options)
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py
index ca68cb8ba..6af31ddff 100755
--- a/smoketest/scripts/cli/test_interfaces_tunnel.py
+++ b/smoketest/scripts/cli/test_interfaces_tunnel.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -15,365 +15,222 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
-import json
-
-from vyos.configsession import ConfigSession
-from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
from base_interfaces_test import BasicInterfaceTest
+from vyos.configsession import ConfigSessionError
+from vyos.util import get_interface_config
+from vyos.template import inc_ip
+
remote_ip4 = '192.0.2.100'
remote_ip6 = '2001:db8::ffff'
source_if = 'dum2222'
mtu = 1476
-def tunnel_conf(interface):
- tmp = cmd(f'ip -d -j link show {interface}')
- # {'address': '2.2.2.2',
- # 'broadcast': '192.0.2.10',
- # 'flags': ['POINTOPOINT', 'NOARP', 'UP', 'LOWER_UP'],
- # 'group': 'default',
- # 'gso_max_segs': 65535,
- # 'gso_max_size': 65536,
- # 'ifindex': 10,
- # 'ifname': 'tun10',
- # 'inet6_addr_gen_mode': 'none',
- # 'link': None,
- # 'link_pointtopoint': True,
- # 'link_type': 'gre',
- # 'linkinfo': {'info_data': {'local': '2.2.2.2',
- # 'pmtudisc': True,
- # 'remote': '192.0.2.10',
- # 'tos': '0x1',
- # 'ttl': 255},
- # 'info_kind': 'gre'},
- # 'linkmode': 'DEFAULT',
- # 'max_mtu': 65511,
- # 'min_mtu': 68,
- # 'mtu': 1476,
- # 'num_rx_queues': 1,
- # 'num_tx_queues': 1,
- # 'operstate': 'UNKNOWN',
- # 'promiscuity': 0,
- # 'qdisc': 'noqueue',
- # 'txqlen': 1000}
- return json.loads(tmp)[0]
-
-class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._test_mtu = True
- self._base_path = ['interfaces', 'tunnel']
- self.local_v4 = '192.0.2.1'
- self.local_v6 = '2001:db8::1'
-
- self._options = {
- 'tun10': ['encapsulation ipip', 'remote-ip 192.0.2.10', 'local-ip ' + self.local_v4],
- 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'local-ip ' + self.local_v4],
+class TunnelInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._test_mtu = True
+ cls._base_path = ['interfaces', 'tunnel']
+ cls.local_v4 = '192.0.2.1'
+ cls.local_v6 = '2001:db8::1'
+ cls._options = {
+ 'tun10': ['encapsulation ipip', 'remote 192.0.2.10', 'source-address ' + cls.local_v4],
+ 'tun20': ['encapsulation gre', 'remote 192.0.2.20', 'source-address ' + cls.local_v4],
}
+ cls._interfaces = list(cls._options)
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
- self._interfaces = list(self._options)
+ def setUp(self):
super().setUp()
-
- self.session.set(['interfaces', 'dummy', source_if, 'address', self.local_v4 + '/32'])
- self.session.set(['interfaces', 'dummy', source_if, 'address', self.local_v6 + '/128'])
+ self.cli_set(['interfaces', 'dummy', source_if, 'address', self.local_v4 + '/32'])
+ self.cli_set(['interfaces', 'dummy', source_if, 'address', self.local_v6 + '/128'])
def tearDown(self):
- self.session.delete(['interfaces', 'dummy', source_if])
+ self.cli_delete(['interfaces', 'dummy', source_if])
super().tearDown()
- def test_ipip(self):
- interface = 'tun100'
- encapsulation = 'ipip'
- local_if_addr = '10.10.10.1/24'
-
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
-
- # Must provide an "encapsulation" for tunnel tun10
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
-
- # Must configure either local-ip or dhcp-interface for tunnel ipip tun100
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
-
- # missing required option remote for ipip
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
-
- # Configure Tunnel Source interface
- self.session.set(self._base_path + [interface, 'source-interface', source_if])
-
- self.session.commit()
-
- conf = tunnel_conf(interface)
- self.assertEqual(interface, conf['ifname'])
- self.assertEqual(encapsulation, conf['link_type'])
- self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(source_if, conf['link'])
-
- self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
- self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
-
- def test_ipip6(self):
- interface = 'tun110'
- encapsulation = 'ipip6'
- local_if_addr = '10.10.10.1/24'
-
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
-
- # Must provide an "encapsulation" for tunnel tun10
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
-
- # Must configure either local-ip or dhcp-interface for tunnel ipip tun100
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
-
- # missing required option remote for ipip
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
-
- # Configure Tunnel Source interface
- self.session.set(self._base_path + [interface, 'source-interface', source_if])
-
- self.session.commit()
-
- conf = tunnel_conf(interface)
- self.assertEqual(interface, conf['ifname'])
- self.assertEqual('tunnel6', conf['link_type'])
- self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(source_if, conf['link'])
-
- self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
- self.assertEqual(remote_ip6, conf['linkinfo']['info_data']['remote'])
-
- def test_tunnel_verify_ipv4_local_remote_addr(self):
+ def test_ipv4_encapsulations(self):
# When running tests ensure that for certain encapsulation types the
# local and remote IP address is actually an IPv4 address
interface = f'tun1000'
local_if_addr = f'10.10.200.1/24'
- for encapsulation in ['ipip', 'sit', 'gre']:
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
- self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
+ for encapsulation in ['ipip', 'sit', 'gre', 'gretap']:
+ self.cli_set(self._base_path + [interface, 'address', local_if_addr])
+ self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
+ self.cli_set(self._base_path + [interface, 'source-address', self.local_v6])
+ self.cli_set(self._base_path + [interface, 'remote', remote_ip6])
- # Encapsulation mode requires IPv4 local-ip
+ # Encapsulation mode requires IPv4 source-address
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
- # Encapsulation mode requires IPv4 local-ip
+ # Encapsulation mode requires IPv4 remote
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
+ self.cli_set(self._base_path + [interface, 'source-interface', source_if])
+
+ # Source interface can not be used with sit and gretap
+ if encapsulation in ['sit', 'gretap']:
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(self._base_path + [interface, 'source-interface'])
# Check if commit is ok
- self.session.commit()
+ self.cli_commit()
+
+ conf = get_interface_config(interface)
+ if encapsulation not in ['sit', 'gretap']:
+ self.assertEqual(source_if, conf['link'])
+
+ self.assertEqual(interface, conf['ifname'])
+ self.assertEqual(mtu, conf['mtu'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
+ self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
+ self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
+ self.assertTrue(conf['linkinfo']['info_data']['pmtudisc'])
# cleanup this instance
- self.session.delete(self._base_path + [interface])
- self.session.commit()
+ self.cli_delete(self._base_path + [interface])
+ self.cli_commit()
- def test_tunnel_verify_ipv6_local_remote_addr(self):
+ def test_ipv6_encapsulations(self):
# When running tests ensure that for certain encapsulation types the
# local and remote IP address is actually an IPv6 address
interface = f'tun1010'
local_if_addr = f'10.10.200.1/24'
- for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre']:
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
- self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre', 'ip6gretap']:
+ self.cli_set(self._base_path + [interface, 'address', local_if_addr])
+ self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
+ self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
- # Encapsulation mode requires IPv6 local-ip
+ # Encapsulation mode requires IPv6 source-address
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'source-address', self.local_v6])
- # Encapsulation mode requires IPv6 local-ip
+ # Encapsulation mode requires IPv6 remote
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'remote', remote_ip6])
- # Check if commit is ok
- self.session.commit()
+ # Configure Tunnel Source interface
+ self.cli_set(self._base_path + [interface, 'source-interface', source_if])
+ # Source interface can not be used with ip6gretap
+ if encapsulation in ['ip6gretap']:
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(self._base_path + [interface, 'source-interface'])
- # cleanup this instance
- self.session.delete(self._base_path + [interface])
- self.session.commit()
+ # Check if commit is ok
+ self.cli_commit()
- def test_tunnel_verify_local_dhcp(self):
- # We can not use local-ip and dhcp-interface at the same time
+ conf = get_interface_config(interface)
+ if encapsulation not in ['ip6gretap']:
+ self.assertEqual(source_if, conf['link'])
- interface = f'tun1020'
- local_if_addr = f'10.0.0.1/24'
+ self.assertEqual(interface, conf['ifname'])
+ self.assertEqual(mtu, conf['mtu'])
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
- self.session.set(self._base_path + [interface, 'encapsulation', 'gre'])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
- self.session.set(self._base_path + [interface, 'dhcp-interface', 'eth0'])
+ # Not applicable for ip6gre
+ if 'proto' in conf['linkinfo']['info_data']:
+ self.assertEqual(encapsulation, conf['linkinfo']['info_data']['proto'])
- # local-ip and dhcp-interface can not be used at the same time
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(self._base_path + [interface, 'dhcp-interface'])
+ # remap encapsulation protocol(s) only for ipip6, ip6ip6
+ if encapsulation in ['ipip6', 'ip6ip6']:
+ encapsulation = 'ip6tnl'
- # Check if commit is ok
- self.session.commit()
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
+ self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
+ self.assertEqual(remote_ip6, conf['linkinfo']['info_data']['remote'])
- def test_tunnel_ip6ip6(self):
- interface = 'tun120'
- encapsulation = 'ip6ip6'
- local_if_addr = '2001:db8:f00::1/24'
+ # cleanup this instance
+ self.cli_delete(self._base_path + [interface])
+ self.cli_commit()
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
+ def test_tunnel_verify_local_dhcp(self):
+ # We can not use source-address and dhcp-interface at the same time
- # Must provide an "encapsulation" for tunnel tun10
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
+ interface = f'tun1020'
+ local_if_addr = f'10.0.0.1/24'
- # Must configure either local-ip or dhcp-interface for tunnel ipip tun100
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
+ self.cli_set(self._base_path + [interface, 'address', local_if_addr])
+ self.cli_set(self._base_path + [interface, 'encapsulation', 'gre'])
+ self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
+ self.cli_set(self._base_path + [interface, 'dhcp-interface', 'eth0'])
- # missing required option remote for ipip
+ # source-address and dhcp-interface can not be used at the same time
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
-
- # Configure Tunnel Source interface
- self.session.set(self._base_path + [interface, 'source-interface', source_if])
+ self.cli_commit()
+ self.cli_delete(self._base_path + [interface, 'dhcp-interface'])
- self.session.commit()
-
- conf = tunnel_conf(interface)
- self.assertEqual(interface, conf['ifname'])
- self.assertEqual('tunnel6', conf['link_type'])
- self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(source_if, conf['link'])
-
- self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
- self.assertEqual(remote_ip6, conf['linkinfo']['info_data']['remote'])
+ # Check if commit is ok
+ self.cli_commit()
- def test_tunnel_gre_ipv4(self):
- interface = 'tun200'
+ def test_tunnel_parameters_gre(self):
+ interface = f'tun1030'
+ gre_key = '10'
encapsulation = 'gre'
- local_if_addr = '172.16.1.1/24'
+ tos = '20'
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
+ self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
+ self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
- # Must provide an "encapsulation" for tunnel tun10
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
-
- # Must configure either local-ip or dhcp-interface
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
-
- # No assertion is raised for GRE remote-ip when missing
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
-
- # Configure Tunnel Source interface
- self.session.set(self._base_path + [interface, 'source-interface', source_if])
-
- self.session.commit()
+ self.cli_set(self._base_path + [interface, 'parameters', 'ip', 'no-pmtu-discovery'])
+ self.cli_set(self._base_path + [interface, 'parameters', 'ip', 'key', gre_key])
+ self.cli_set(self._base_path + [interface, 'parameters', 'ip', 'tos', tos])
- conf = tunnel_conf(interface)
- self.assertEqual(interface, conf['ifname'])
- self.assertEqual(encapsulation, conf['link_type'])
- self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(source_if, conf['link'])
+ # Check if commit is ok
+ self.cli_commit()
+ conf = get_interface_config(interface)
+ self.assertEqual(mtu, conf['mtu'])
+ self.assertEqual(interface, conf['ifname'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
- self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
-
-
- def test_gre_ipv6(self):
- interface = 'tun210'
- encapsulation = 'ip6gre'
- local_if_addr = '2001:db8:f01::1/24'
+ self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(0, conf['linkinfo']['info_data']['ttl'])
+ self.assertFalse( conf['linkinfo']['info_data']['pmtudisc'])
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
+ def test_gretap_parameters_change(self):
+ interface = f'tun1040'
+ gre_key = '10'
+ encapsulation = 'gretap'
+ tos = '20'
- # Must provide an "encapsulation" for tunnel tun10
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
-
- # Must configure either local-ip or dhcp-interface
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
+ self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
+ self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
- # No assertion is raised for GRE remote-ip when missing
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
-
- # Configure Tunnel Source interface
- self.session.set(self._base_path + [interface, 'source-interface', source_if])
-
- self.session.commit()
-
- conf = tunnel_conf(interface)
- self.assertEqual(interface, conf['ifname'])
- self.assertEqual(encapsulation, conf['link_type'])
- self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(source_if, conf['link'])
-
- self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
- self.assertEqual(remote_ip6, conf['linkinfo']['info_data']['remote'])
-
-
- def test_tunnel_sit(self):
- interface = 'tun300'
- encapsulation = 'sit'
- local_if_addr = '172.16.2.1/24'
-
- self.session.set(self._base_path + [interface, 'address', local_if_addr])
-
- # Must provide an "encapsulation" for tunnel tun10
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
-
- # Must configure either local-ip or dhcp-interface
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
-
- # No assertion is raised for GRE remote-ip when missing
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
-
- # Source interface can not be used with sit
- self.session.set(self._base_path + [interface, 'source-interface', source_if])
- with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(self._base_path + [interface, 'source-interface'])
-
- self.session.commit()
-
- conf = tunnel_conf(interface)
- self.assertEqual(interface, conf['ifname'])
- self.assertEqual(encapsulation, conf['link_type'])
- self.assertEqual(mtu, conf['mtu'])
+ # Check if commit is ok
+ self.cli_commit()
+ conf = get_interface_config(interface)
+ self.assertEqual(mtu, conf['mtu'])
+ self.assertEqual(interface, conf['ifname'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
- self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(0, conf['linkinfo']['info_data']['ttl'])
+
+ # Change remote ip address (inc host by 2
+ new_remote = inc_ip(remote_ip4, 2)
+ self.cli_set(self._base_path + [interface, 'remote', new_remote])
+ # Check if commit is ok
+ self.cli_commit()
+ conf = get_interface_config(interface)
+ self.assertEqual(new_remote, conf['linkinfo']['info_data']['remote'])
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py
index a9b0fc5a1..7b420cd51 100755
--- a/smoketest/scripts/cli/test_interfaces_vxlan.py
+++ b/smoketest/scripts/cli/test_interfaces_vxlan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -16,19 +16,75 @@
import unittest
-from vyos.configsession import ConfigSession, ConfigSessionError
+from vyos.configsession import ConfigSession
+from vyos.ifconfig import Interface
+from vyos.util import get_interface_config
+
from base_interfaces_test import BasicInterfaceTest
-class VXLANInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._test_mtu = True
- self._base_path = ['interfaces', 'vxlan']
- self._options = {
- 'vxlan0': ['vni 10', 'remote 127.0.0.2'],
- 'vxlan1': ['vni 20', 'group 239.1.1.1', 'source-interface eth0'],
+class VXLANInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._test_ipv6 = True
+ cls._test_mtu = True
+ cls._base_path = ['interfaces', 'vxlan']
+ cls._options = {
+ 'vxlan10': ['vni 10', 'remote 127.0.0.2'],
+ 'vxlan20': ['vni 20', 'group 239.1.1.1', 'source-interface eth0'],
+ 'vxlan30': ['vni 30', 'remote 2001:db8:2000::1', 'source-address 2001:db8:1000::1', 'parameters ipv6 flowlabel 0x1000'],
}
- self._interfaces = list(self._options)
- super().setUp()
+ cls._interfaces = list(cls._options)
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
+
+ def test_vxlan_parameters(self):
+ tos = '40'
+ ttl = 20
+ for intf in self._interfaces:
+ for option in self._options.get(intf, []):
+ self.cli_set(self._base_path + [intf] + option.split())
+
+ self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'dont-fragment'])
+ self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'tos', tos])
+ self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'ttl', str(ttl)])
+ ttl += 10
+
+ self.cli_commit()
+
+ ttl = 20
+ for interface in self._interfaces:
+ options = get_interface_config(interface)
+
+ vni = options['linkinfo']['info_data']['id']
+ self.assertIn(f'vni {vni}', self._options[interface])
+
+ if any('link' in s for s in self._options[interface]):
+ link = options['linkinfo']['info_data']['link']
+ self.assertIn(f'source-interface {link}', self._options[interface])
+
+ if any('local6' in s for s in self._options[interface]):
+ remote = options['linkinfo']['info_data']['local6']
+ self.assertIn(f'source-address {local6}', self._options[interface])
+
+ if any('remote6' in s for s in self._options[interface]):
+ remote = options['linkinfo']['info_data']['remote6']
+ self.assertIn(f'remote {remote}', self._options[interface])
+
+ if any('group' in s for s in self._options[interface]):
+ group = options['linkinfo']['info_data']['group']
+ self.assertIn(f'group {group}', self._options[interface])
+
+ if any('flowlabel' in s for s in self._options[interface]):
+ label = options['linkinfo']['info_data']['label']
+ self.assertIn(f'parameters ipv6 flowlabel {label}', self._options[interface])
+
+ self.assertEqual('vxlan', options['linkinfo']['info_kind'])
+ self.assertEqual('set', options['linkinfo']['info_data']['df'])
+ self.assertEqual(f'0x{tos}', options['linkinfo']['info_data']['tos'])
+ self.assertEqual(ttl, options['linkinfo']['info_data']['ttl'])
+ self.assertEqual(Interface(interface).get_admin_state(), 'up')
+ ttl += 10
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_wireguard.py b/smoketest/scripts/cli/test_interfaces_wireguard.py
index d9a51b146..d31ec0332 100755
--- a/smoketest/scripts/cli/test_interfaces_wireguard.py
+++ b/smoketest/scripts/cli/test_interfaces_wireguard.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -17,8 +17,10 @@
import os
import unittest
-from vyos.configsession import ConfigSession, ConfigSessionError
-from base_interfaces_test import BasicInterfaceTest
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+
# Generate WireGuard default keypair
if not os.path.isdir('/config/auth/wireguard/default'):
@@ -26,17 +28,15 @@ if not os.path.isdir('/config/auth/wireguard/default'):
base_path = ['interfaces', 'wireguard']
-class WireGuardInterfaceTest(unittest.TestCase):
+class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
self._test_addr = ['192.0.2.1/26', '192.0.2.255/31', '192.0.2.64/32',
'2001:db8:1::ffff/64', '2001:db8:101::1/112']
self._interfaces = ['wg0', 'wg1']
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_wireguard_peer(self):
# Create WireGuard interfaces with associated peers
@@ -46,19 +46,19 @@ class WireGuardInterfaceTest(unittest.TestCase):
pubkey = 'n6ZZL7ph/QJUJSUUTyu19c77my1dRCDHkMzFQUO9Z3A='
for addr in self._test_addr:
- self.session.set(base_path + [intf, 'address', addr])
+ self.cli_set(base_path + [intf, 'address', addr])
- self.session.set(base_path + [intf, 'peer', peer, 'address', '127.0.0.1'])
- self.session.set(base_path + [intf, 'peer', peer, 'port', '1337'])
+ self.cli_set(base_path + [intf, 'peer', peer, 'address', '127.0.0.1'])
+ self.cli_set(base_path + [intf, 'peer', peer, 'port', '1337'])
# Allow different prefixes to traverse the tunnel
allowed_ips = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
for ip in allowed_ips:
- self.session.set(base_path + [intf, 'peer', peer, 'allowed-ips', ip])
+ self.cli_set(base_path + [intf, 'peer', peer, 'allowed-ips', ip])
- self.session.set(base_path + [intf, 'peer', peer, 'preshared-key', psk])
- self.session.set(base_path + [intf, 'peer', peer, 'pubkey', pubkey])
- self.session.commit()
+ self.cli_set(base_path + [intf, 'peer', peer, 'preshared-key', psk])
+ self.cli_set(base_path + [intf, 'peer', peer, 'pubkey', pubkey])
+ self.cli_commit()
self.assertTrue(os.path.isdir(f'/sys/class/net/{intf}'))
@@ -71,26 +71,26 @@ class WireGuardInterfaceTest(unittest.TestCase):
pubkey_1 = 'n1CUsmR0M2LUUsyicBd6blZICwUqqWWHbu4ifZ2/9gk='
pubkey_2 = 'ebFx/1G0ti8tvuZd94sEIosAZZIznX+dBAKG/8DFm0I='
- self.session.set(base_path + [interface, 'address', '172.16.0.1/24'])
+ self.cli_set(base_path + [interface, 'address', '172.16.0.1/24'])
- self.session.set(base_path + [interface, 'peer', 'PEER01', 'pubkey', pubkey_1])
- self.session.set(base_path + [interface, 'peer', 'PEER01', 'port', port])
- self.session.set(base_path + [interface, 'peer', 'PEER01', 'allowed-ips', '10.205.212.10/32'])
- self.session.set(base_path + [interface, 'peer', 'PEER01', 'address', '192.0.2.1'])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'pubkey', pubkey_1])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'port', port])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'allowed-ips', '10.205.212.10/32'])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'address', '192.0.2.1'])
- self.session.set(base_path + [interface, 'peer', 'PEER02', 'pubkey', pubkey_2])
- self.session.set(base_path + [interface, 'peer', 'PEER02', 'port', port])
- self.session.set(base_path + [interface, 'peer', 'PEER02', 'allowed-ips', '10.205.212.11/32'])
- self.session.set(base_path + [interface, 'peer', 'PEER02', 'address', '192.0.2.2'])
+ self.cli_set(base_path + [interface, 'peer', 'PEER02', 'pubkey', pubkey_2])
+ self.cli_set(base_path + [interface, 'peer', 'PEER02', 'port', port])
+ self.cli_set(base_path + [interface, 'peer', 'PEER02', 'allowed-ips', '10.205.212.11/32'])
+ self.cli_set(base_path + [interface, 'peer', 'PEER02', 'address', '192.0.2.2'])
# Commit peers
- self.session.commit()
+ self.cli_commit()
self.assertTrue(os.path.isdir(f'/sys/class/net/{interface}'))
# Delete second peer
- self.session.delete(base_path + [interface, 'peer', 'PEER01'])
- self.session.commit()
+ self.cli_delete(base_path + [interface, 'peer', 'PEER01'])
+ self.cli_commit()
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_wireless.py b/smoketest/scripts/cli/test_interfaces_wireless.py
index ffaa7d523..4f539a23c 100755
--- a/smoketest/scripts/cli/test_interfaces_wireless.py
+++ b/smoketest/scripts/cli/test_interfaces_wireless.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -31,10 +31,12 @@ def get_config_value(interface, key):
tmp = re.findall(f'{key}=+(.*)', tmp)
return tmp[0]
-class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
- def setUp(self):
- self._base_path = ['interfaces', 'wireless']
- self._options = {
+class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._test_ip = True
+ cls._base_path = ['interfaces', 'wireless']
+ cls._options = {
'wlan0': ['physical-device phy0', 'ssid VyOS-WIFI-0',
'type station', 'address 192.0.2.1/30'],
'wlan1': ['physical-device phy0', 'ssid VyOS-WIFI-1', 'country-code se',
@@ -44,8 +46,9 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
'wlan11': ['physical-device phy1', 'ssid VyOS-WIFI-3', 'country-code se',
'type access-point', 'address 192.0.2.13/30', 'channel 0'],
}
- self._interfaces = list(self._options)
- super().setUp()
+ cls._interfaces = list(cls._options)
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
def test_wireless_add_single_ip_address(self):
# derived method to check if member interfaces are enslaved properly
@@ -66,12 +69,12 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
interface = 'wlan0'
ssid = 'ssid'
- self.session.set(self._base_path + [interface, 'ssid', ssid])
- self.session.set(self._base_path + [interface, 'country-code', 'se'])
- self.session.set(self._base_path + [interface, 'type', 'access-point'])
+ self.cli_set(self._base_path + [interface, 'ssid', ssid])
+ self.cli_set(self._base_path + [interface, 'country-code', 'se'])
+ self.cli_set(self._base_path + [interface, 'type', 'access-point'])
# auto-powersave is special
- self.session.set(self._base_path + [interface, 'capabilities', 'ht', 'auto-powersave'])
+ self.cli_set(self._base_path + [interface, 'capabilities', 'ht', 'auto-powersave'])
ht_opt = {
# VyOS CLI option hostapd - ht_capab setting
@@ -87,7 +90,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
'smps static' : '[SMPS-STATIC]',
}
for key in ht_opt:
- self.session.set(self._base_path + [interface, 'capabilities', 'ht'] + key.split())
+ self.cli_set(self._base_path + [interface, 'capabilities', 'ht'] + key.split())
vht_opt = {
# VyOS CLI option hostapd - ht_capab setting
@@ -104,9 +107,9 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
'short-gi 160' : '[SHORT-GI-160]',
}
for key in vht_opt:
- self.session.set(self._base_path + [interface, 'capabilities', 'vht'] + key.split())
+ self.cli_set(self._base_path + [interface, 'capabilities', 'vht'] + key.split())
- self.session.commit()
+ self.cli_commit()
#
# Validate Config
@@ -147,29 +150,29 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
mode = 'n'
country = 'de'
- self.session.set(self._base_path + [interface, 'physical-device', phy])
- self.session.set(self._base_path + [interface, 'type', 'access-point'])
- self.session.set(self._base_path + [interface, 'mode', mode])
+ self.cli_set(self._base_path + [interface, 'physical-device', phy])
+ self.cli_set(self._base_path + [interface, 'type', 'access-point'])
+ self.cli_set(self._base_path + [interface, 'mode', mode])
# SSID must be set
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'ssid', ssid])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'ssid', ssid])
# Channel must be set
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'channel', channel])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'channel', channel])
# Country-Code must be set
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(self._base_path + [interface, 'country-code', country])
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'country-code', country])
- self.session.set(self._base_path + [interface, 'security', 'wpa', 'mode', 'wpa2'])
- self.session.set(self._base_path + [interface, 'security', 'wpa', 'passphrase', wpa_key])
+ self.cli_set(self._base_path + [interface, 'security', 'wpa', 'mode', 'wpa2'])
+ self.cli_set(self._base_path + [interface, 'security', 'wpa', 'passphrase', wpa_key])
- self.session.commit()
+ self.cli_commit()
#
# Validate Config
@@ -210,13 +213,13 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
# We need a bridge where we can hook our access-point interface to
bridge_path = ['interfaces', 'bridge', bridge]
- self.session.set(bridge_path + ['member', 'interface', interface])
+ self.cli_set(bridge_path + ['member', 'interface', interface])
- self.session.set(self._base_path + [interface, 'ssid', ssid])
- self.session.set(self._base_path + [interface, 'country-code', 'se'])
- self.session.set(self._base_path + [interface, 'type', 'access-point'])
+ self.cli_set(self._base_path + [interface, 'ssid', ssid])
+ self.cli_set(self._base_path + [interface, 'country-code', 'se'])
+ self.cli_set(self._base_path + [interface, 'type', 'access-point'])
- self.session.commit()
+ self.cli_commit()
# Check for running process
self.assertTrue(process_named_running('hostapd'))
@@ -227,9 +230,9 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest):
self.assertIn(interface, bridge_members)
- self.session.delete(bridge_path)
- self.session.delete(self._base_path)
- self.session.commit()
+ self.cli_delete(bridge_path)
+ self.cli_delete(self._base_path)
+ self.cli_commit()
if __name__ == '__main__':
check_kmod('mac80211_hwsim')
diff --git a/smoketest/scripts/cli/test_interfaces_wirelessmodem.py b/smoketest/scripts/cli/test_interfaces_wirelessmodem.py
index 45cd069f4..c36835ea7 100755
--- a/smoketest/scripts/cli/test_interfaces_wirelessmodem.py
+++ b/smoketest/scripts/cli/test_interfaces_wirelessmodem.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -18,7 +18,10 @@ import os
import unittest
from psutil import process_iter
-from vyos.configsession import ConfigSession, ConfigSessionError
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
config_file = '/etc/ppp/peers/{}'
base_path = ['interfaces', 'wirelessmodem']
@@ -30,33 +33,31 @@ def get_config_value(interface, key):
return list(line.split())
return []
-class WWANInterfaceTest(unittest.TestCase):
+class WWANInterfaceTest(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
self._interfaces = ['wlm0', 'wlm1']
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
- def test_wlm_1(self):
+ def test_wwan(self):
for interface in self._interfaces:
- self.session.set(base_path + [interface, 'no-peer-dns'])
- self.session.set(base_path + [interface, 'connect-on-demand'])
+ self.cli_set(base_path + [interface, 'no-peer-dns'])
+ self.cli_set(base_path + [interface, 'connect-on-demand'])
# check validate() - APN must be configure
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + [interface, 'apn', 'vyos.net'])
+ self.cli_commit()
+ self.cli_set(base_path + [interface, 'apn', 'vyos.net'])
# check validate() - device must be configure
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + [interface, 'device', 'ttyS0'])
+ self.cli_commit()
+ self.cli_set(base_path + [interface, 'device', 'ttyS0'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# verify configuration file(s)
for interface in self._interfaces:
diff --git a/smoketest/scripts/cli/test_nat.py b/smoketest/scripts/cli/test_nat.py
index 7ca82f86f..0706f234e 100755
--- a/smoketest/scripts/cli/test_nat.py
+++ b/smoketest/scripts/cli/test_nat.py
@@ -19,6 +19,7 @@ import jmespath
import json
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.util import cmd
@@ -28,16 +29,15 @@ base_path = ['nat']
src_path = base_path + ['source']
dst_path = base_path + ['destination']
-class TestNAT(unittest.TestCase):
+class TestNAT(VyOSUnitTestSHIM.TestCase):
def setUp(self):
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
- self.session = ConfigSession(os.getpid())
- self.session.delete(base_path)
+ self.cli_delete(base_path)
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_snat(self):
rules = ['100', '110', '120', '130', '200', '210', '220', '230']
@@ -48,15 +48,15 @@ class TestNAT(unittest.TestCase):
# depending of rule order we check either for source address for NAT
# or configured destination address for NAT
if int(rule) < 200:
- self.session.set(src_path + ['rule', rule, 'source', 'address', network])
- self.session.set(src_path + ['rule', rule, 'outbound-interface', outbound_iface_100])
- self.session.set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
+ self.cli_set(src_path + ['rule', rule, 'source', 'address', network])
+ self.cli_set(src_path + ['rule', rule, 'outbound-interface', outbound_iface_100])
+ self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
else:
- self.session.set(src_path + ['rule', rule, 'destination', 'address', network])
- self.session.set(src_path + ['rule', rule, 'outbound-interface', outbound_iface_200])
- self.session.set(src_path + ['rule', rule, 'exclude'])
+ self.cli_set(src_path + ['rule', rule, 'destination', 'address', network])
+ self.cli_set(src_path + ['rule', rule, 'outbound-interface', outbound_iface_200])
+ self.cli_set(src_path + ['rule', rule, 'exclude'])
- self.session.commit()
+ self.cli_commit()
tmp = cmd('sudo nft -j list table nat')
data_json = jmespath.search('nftables[?rule].rule[?chain]', json.loads(tmp))
@@ -98,17 +98,17 @@ class TestNAT(unittest.TestCase):
for rule in rules:
port = f'10{rule}'
- self.session.set(dst_path + ['rule', rule, 'source', 'port', port])
- self.session.set(dst_path + ['rule', rule, 'translation', 'address', '192.0.2.1'])
- self.session.set(dst_path + ['rule', rule, 'translation', 'port', port])
+ self.cli_set(dst_path + ['rule', rule, 'source', 'port', port])
+ self.cli_set(dst_path + ['rule', rule, 'translation', 'address', '192.0.2.1'])
+ self.cli_set(dst_path + ['rule', rule, 'translation', 'port', port])
if int(rule) < 200:
- self.session.set(dst_path + ['rule', rule, 'protocol', inbound_proto_100])
- self.session.set(dst_path + ['rule', rule, 'inbound-interface', inbound_iface_100])
+ self.cli_set(dst_path + ['rule', rule, 'protocol', inbound_proto_100])
+ self.cli_set(dst_path + ['rule', rule, 'inbound-interface', inbound_iface_100])
else:
- self.session.set(dst_path + ['rule', rule, 'protocol', inbound_proto_200])
- self.session.set(dst_path + ['rule', rule, 'inbound-interface', inbound_iface_200])
+ self.cli_set(dst_path + ['rule', rule, 'protocol', inbound_proto_200])
+ self.cli_set(dst_path + ['rule', rule, 'inbound-interface', inbound_iface_200])
- self.session.commit()
+ self.cli_commit()
tmp = cmd('sudo nft -j list table nat')
data_json = jmespath.search('nftables[?rule].rule[?chain]', json.loads(tmp))
@@ -138,23 +138,45 @@ class TestNAT(unittest.TestCase):
else:
self.assertEqual(iface, inbound_iface_200)
-
def test_snat_required_translation_address(self):
# T2813: Ensure translation address is specified
rule = '5'
- self.session.set(src_path + ['rule', rule, 'source', 'address', '192.0.2.0/24'])
+ self.cli_set(src_path + ['rule', rule, 'source', 'address', '192.0.2.0/24'])
# check validate() - outbound-interface must be defined
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(src_path + ['rule', rule, 'outbound-interface', 'eth0'])
+ self.cli_commit()
+ self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'eth0'])
# check validate() - translation address not specified
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
+
+ self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
+ self.cli_commit()
+
+ def test_dnat_negated_addresses(self):
+ # T3186: negated addresses are not accepted by nftables
+ rule = '1000'
+ self.cli_set(dst_path + ['rule', rule, 'destination', 'address', '!192.0.2.1'])
+ self.cli_set(dst_path + ['rule', rule, 'destination', 'port', '53'])
+ self.cli_set(dst_path + ['rule', rule, 'inbound-interface', 'eth0'])
+ self.cli_set(dst_path + ['rule', rule, 'protocol', 'tcp_udp'])
+ self.cli_set(dst_path + ['rule', rule, 'source', 'address', '!192.0.2.1'])
+ self.cli_set(dst_path + ['rule', rule, 'translation', 'address', '192.0.2.1'])
+ self.cli_set(dst_path + ['rule', rule, 'translation', 'port', '53'])
+ self.cli_commit()
+
+ def test_nat_no_rules(self):
+ # T3206: deleting all rules but keep the direction 'destination' or
+ # 'source' resulteds in KeyError: 'rule'.
+ #
+ # Test that both 'nat destination' and 'nat source' nodes can exist
+ # without any rule
+ self.cli_set(src_path)
+ self.cli_set(dst_path)
+ self.cli_commit()
- self.session.set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
- self.session.commit()
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_nat66.py b/smoketest/scripts/cli/test_nat66.py
new file mode 100755
index 000000000..dca92c97d
--- /dev/null
+++ b/smoketest/scripts/cli/test_nat66.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2020 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
+import jmespath
+import json
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+from vyos.util import cmd
+from vyos.util import dict_search
+
+base_path = ['nat66']
+src_path = base_path + ['source']
+dst_path = base_path + ['destination']
+
+class TestNAT66(VyOSUnitTestSHIM.TestCase):
+ def setUp(self):
+ # ensure we can also run this test on a live system - so lets clean
+ # out the current configuration :)
+ self.cli_delete(base_path)
+
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_source_nat66(self):
+ source_prefix = 'fc00::/64'
+ translation_prefix = 'fc01::/64'
+ self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'eth1'])
+ self.cli_set(src_path + ['rule', '1', 'source', 'prefix', source_prefix])
+ self.cli_set(src_path + ['rule', '1', 'translation', 'address', translation_prefix])
+
+ # check validate() - outbound-interface must be defined
+ self.cli_commit()
+
+ tmp = cmd('sudo nft -j list table ip6 nat')
+ data_json = jmespath.search('nftables[?rule].rule[?chain]', json.loads(tmp))
+
+ for idx in range(0, len(data_json)):
+ data = data_json[idx]
+
+ self.assertEqual(data['chain'], 'POSTROUTING')
+ self.assertEqual(data['family'], 'ip6')
+ self.assertEqual(data['table'], 'nat')
+
+ iface = dict_search('match.right', data['expr'][0])
+ address = dict_search('match.right.prefix.addr', data['expr'][2])
+ mask = dict_search('match.right.prefix.len', data['expr'][2])
+ translation_address = dict_search('snat.addr.prefix.addr', data['expr'][3])
+ translation_mask = dict_search('snat.addr.prefix.len', data['expr'][3])
+
+ self.assertEqual(iface, 'eth1')
+ # check for translation address
+ self.assertEqual(f'{translation_address}/{translation_mask}', translation_prefix)
+ self.assertEqual(f'{address}/{mask}', source_prefix)
+
+ def test_source_nat66_address(self):
+ source_prefix = 'fc00::/64'
+ translation_address = 'fc00::1'
+ self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'eth1'])
+ self.cli_set(src_path + ['rule', '1', 'source', 'prefix', source_prefix])
+ self.cli_set(src_path + ['rule', '1', 'translation', 'address', translation_address])
+
+ # check validate() - outbound-interface must be defined
+ self.cli_commit()
+
+ tmp = cmd('sudo nft -j list table ip6 nat')
+ data_json = jmespath.search('nftables[?rule].rule[?chain]', json.loads(tmp))
+
+ for idx in range(0, len(data_json)):
+ data = data_json[idx]
+
+ self.assertEqual(data['chain'], 'POSTROUTING')
+ self.assertEqual(data['family'], 'ip6')
+ self.assertEqual(data['table'], 'nat')
+
+ iface = dict_search('match.right', data['expr'][0])
+ address = dict_search('match.right.prefix.addr', data['expr'][2])
+ mask = dict_search('match.right.prefix.len', data['expr'][2])
+ snat_address = dict_search('snat.addr', data['expr'][3])
+
+ self.assertEqual(iface, 'eth1')
+ # check for translation address
+ self.assertEqual(snat_address, translation_address)
+ self.assertEqual(f'{address}/{mask}', source_prefix)
+
+ def test_destination_nat66(self):
+ destination_address = 'fc00::1'
+ translation_address = 'fc01::1'
+ self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'eth1'])
+ self.cli_set(dst_path + ['rule', '1', 'destination', 'address', destination_address])
+ self.cli_set(dst_path + ['rule', '1', 'translation', 'address', translation_address])
+
+ # check validate() - outbound-interface must be defined
+ self.cli_commit()
+
+ tmp = cmd('sudo nft -j list table ip6 nat')
+ data_json = jmespath.search('nftables[?rule].rule[?chain]', json.loads(tmp))
+
+ for idx in range(0, len(data_json)):
+ data = data_json[idx]
+
+ self.assertEqual(data['chain'], 'PREROUTING')
+ self.assertEqual(data['family'], 'ip6')
+ self.assertEqual(data['table'], 'nat')
+
+ iface = dict_search('match.right', data['expr'][0])
+ dnat_addr = dict_search('dnat.addr', data['expr'][3])
+
+ self.assertEqual(dnat_addr, translation_address)
+ self.assertEqual(iface, 'eth1')
+
+ def test_destination_nat66_prefix(self):
+ destination_prefix = 'fc00::/64'
+ translation_prefix = 'fc01::/64'
+ self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'eth1'])
+ self.cli_set(dst_path + ['rule', '1', 'destination', 'address', destination_prefix])
+ self.cli_set(dst_path + ['rule', '1', 'translation', 'address', translation_prefix])
+
+ # check validate() - outbound-interface must be defined
+ self.cli_commit()
+
+ tmp = cmd('sudo nft -j list table ip6 nat')
+ data_json = jmespath.search('nftables[?rule].rule[?chain]', json.loads(tmp))
+
+ for idx in range(0, len(data_json)):
+ data = data_json[idx]
+
+ self.assertEqual(data['chain'], 'PREROUTING')
+ self.assertEqual(data['family'], 'ip6')
+ self.assertEqual(data['table'], 'nat')
+
+ iface = dict_search('match.right', data['expr'][0])
+ translation_address = dict_search('dnat.addr.prefix.addr', data['expr'][3])
+ translation_mask = dict_search('dnat.addr.prefix.len', data['expr'][3])
+
+ self.assertEqual(f'{translation_address}/{translation_mask}', translation_prefix)
+ self.assertEqual(iface, 'eth1')
+
+ def test_source_nat66_required_translation_prefix(self):
+ # T2813: Ensure translation address is specified
+ rule = '5'
+ source_prefix = 'fc00::/64'
+ self.cli_set(src_path + ['rule', rule, 'source', 'prefix', source_prefix])
+
+ # check validate() - outbound-interface must be defined
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'eth0'])
+
+ # check validate() - translation address not specified
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
+ self.cli_commit()
+
+ def test_nat66_no_rules(self):
+ # T3206: deleting all rules but keep the direction 'destination' or
+ # 'source' resulteds in KeyError: 'rule'.
+ #
+ # Test that both 'nat destination' and 'nat source' nodes can exist
+ # without any rule
+ self.cli_set(src_path)
+ self.cli_set(dst_path)
+ self.cli_commit()
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py
new file mode 100755
index 000000000..57557af68
--- /dev/null
+++ b/smoketest/scripts/cli/test_policy.py
@@ -0,0 +1,702 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+from vyos.util import cmd
+
+base_path = ['policy']
+
+class TestPolicy(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_access_list(self):
+ acls = {
+ '50' : {
+ 'rule' : {
+ '5' : {
+ 'action' : 'permit',
+ 'source' : { 'any' : '' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'host' : '1.2.3.4' },
+ },
+ },
+ },
+ '150' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'source' : { 'any' : '' },
+ 'destination' : { 'host' : '2.2.2.2' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'any' : '' },
+ 'destination' : { 'any' : '' },
+ },
+ },
+ },
+ '2000' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'destination' : { 'any' : '' },
+ 'source' : { 'network' : '10.0.0.0', 'inverse-mask' : '0.255.255.255' },
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'destination' : { 'any' : '' },
+ 'source' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'destination' : { 'any' : '' },
+ 'source' : { 'network' : '192.168.0.0', 'inverse-mask' : '0.0.255.255' },
+ },
+ '50' : {
+ 'action' : 'permit',
+ 'destination' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
+ 'source' : { 'network' : '10.0.0.0', 'inverse-mask' : '0.255.255.255' },
+ },
+ '60' : {
+ 'action' : 'deny',
+ 'destination' : { 'network' : '192.168.0.0', 'inverse-mask' : '0.0.255.255' },
+ 'source' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
+ },
+ '70' : {
+ 'action' : 'deny',
+ 'destination' : { 'any' : '' },
+ 'source' : { 'any' : '' },
+ },
+ },
+ },
+ }
+
+ for acl, acl_config in acls.items():
+ path = base_path + ['access-list', acl]
+ self.cli_set(path + ['description', f'VyOS-ACL-{acl}'])
+ if 'rule' not in acl_config:
+ continue
+
+ for rule, rule_config in acl_config['rule'].items():
+ self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
+ for direction in ['source', 'destination']:
+ if direction in rule_config:
+ if 'any' in rule_config[direction]:
+ self.cli_set(path + ['rule', rule, direction, 'any'])
+ if 'host' in rule_config[direction]:
+ self.cli_set(path + ['rule', rule, direction, 'host', rule_config[direction]['host']])
+ if 'network' in rule_config[direction]:
+ self.cli_set(path + ['rule', rule, direction, 'network', rule_config[direction]['network']])
+ self.cli_set(path + ['rule', rule, direction, 'inverse-mask', rule_config[direction]['inverse-mask']])
+
+ self.cli_commit()
+
+ config = self.getFRRconfig('access-list', end='')
+ for acl, acl_config in acls.items():
+ seq = '5'
+ for rule, rule_config in acl_config['rule'].items():
+ tmp = f'access-list {acl} seq {seq}'
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ if {'source', 'destination'} <= set(rule_config):
+ tmp += ' ip'
+
+ for direction in ['source', 'destination']:
+ if direction in rule_config:
+ if 'any' in rule_config[direction]:
+ tmp += ' any'
+ if 'host' in rule_config[direction]:
+ tmp += ' ' + rule_config[direction]['host']
+ if 'network' in rule_config[direction]:
+ tmp += ' ' + rule_config[direction]['network'] + ' ' + rule_config[direction]['inverse-mask']
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+ def test_access_list6(self):
+ acls = {
+ '50' : {
+ 'rule' : {
+ '5' : {
+ 'action' : 'permit',
+ 'source' : { 'any' : '' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:10::/48', 'exact-match' : '' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:20::/48' },
+ },
+ },
+ },
+ '100' : {
+ 'rule' : {
+ '5' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:10::/64', 'exact-match' : '' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:20::/64', },
+ },
+ '15' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:30::/64', 'exact-match' : '' },
+ },
+ '20' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:40::/64', 'exact-match' : '' },
+ },
+ '100' : {
+ 'action' : 'deny',
+ 'source' : { 'any' : '' },
+ },
+ },
+ },
+ }
+
+ for acl, acl_config in acls.items():
+ path = base_path + ['access-list6', acl]
+ self.cli_set(path + ['description', f'VyOS-ACL-{acl}'])
+ if 'rule' not in acl_config:
+ continue
+
+ for rule, rule_config in acl_config['rule'].items():
+ self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
+ for direction in ['source', 'destination']:
+ if direction in rule_config:
+ if 'any' in rule_config[direction]:
+ self.cli_set(path + ['rule', rule, direction, 'any'])
+ if 'network' in rule_config[direction]:
+ self.cli_set(path + ['rule', rule, direction, 'network', rule_config[direction]['network']])
+ if 'exact-match' in rule_config[direction]:
+ self.cli_set(path + ['rule', rule, direction, 'exact-match'])
+
+ self.cli_commit()
+
+ config = self.getFRRconfig('ipv6 access-list', end='')
+ for acl, acl_config in acls.items():
+ seq = '5'
+ for rule, rule_config in acl_config['rule'].items():
+ tmp = f'ipv6 access-list {acl} seq {seq}'
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ if {'source', 'destination'} <= set(rule_config):
+ tmp += ' ip'
+
+ for direction in ['source', 'destination']:
+ if direction in rule_config:
+ if 'any' in rule_config[direction]:
+ tmp += ' any'
+ if 'network' in rule_config[direction]:
+ tmp += ' ' + rule_config[direction]['network']
+ if 'exact-match' in rule_config[direction]:
+ tmp += ' exact-match'
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+
+ def test_as_path_list(self):
+ test_data = {
+ 'VyOS' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '^44501 64502$',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'regex' : '44501|44502|44503',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '^44501_([0-9]+_)+',
+ },
+ },
+ },
+ 'Customers' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '_10_',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'regex' : '_20_',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '_30_',
+ },
+ '30' : {
+ 'action' : 'deny',
+ 'regex' : '_40_',
+ },
+ },
+ },
+ 'bogons' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '_0_',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'regex' : '_23456_',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '_6449[6-9]_|_65[0-4][0-9][0-9]_|_655[0-4][0-9]_|_6555[0-1]_',
+ },
+ '30' : {
+ 'action' : 'permit',
+ '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]_',
+ },
+ },
+ },
+ }
+
+ for as_path, as_path_config in test_data.items():
+ path = base_path + ['as-path-list', as_path]
+ self.cli_set(path + ['description', f'VyOS-ASPATH-{as_path}'])
+ if 'rule' not in as_path_config:
+ continue
+
+ for rule, rule_config in as_path_config['rule'].items():
+ if 'action' in rule_config:
+ self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'regex' in rule_config:
+ self.cli_set(path + ['rule', rule, 'regex', rule_config['regex']])
+
+ self.cli_commit()
+
+ config = self.getFRRconfig('bgp as-path access-list', end='')
+ for as_path, as_path_config in test_data.items():
+ if 'rule' not in as_path_config:
+ continue
+
+ for rule, rule_config in as_path_config['rule'].items():
+ tmp = f'bgp as-path access-list {as_path}'
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['regex']
+
+ self.assertIn(tmp, config)
+
+ def test_community_list(self):
+ test_data = {
+ '100' : {
+ 'rule' : {
+ '4' : {
+ 'action' : 'permit',
+ 'regex' : '.*',
+ },
+ },
+ },
+ '200' : {
+ 'rule' : {
+ '1' : {
+ 'action' : 'deny',
+ 'regex' : '^1:201$',
+ },
+ '2' : {
+ 'action' : 'deny',
+ 'regex' : '1:101$',
+ },
+ '3' : {
+ 'action' : 'deny',
+ 'regex' : '^1:100$',
+ },
+ },
+ },
+ }
+
+ for comm_list, comm_list_config in test_data.items():
+ path = base_path + ['community-list', comm_list]
+ self.cli_set(path + ['description', f'VyOS-COMM-{comm_list}'])
+ if 'rule' not in comm_list_config:
+ continue
+
+ for rule, rule_config in comm_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'regex' in rule_config:
+ self.cli_set(path + ['rule', rule, 'regex', rule_config['regex']])
+
+ self.cli_commit()
+
+ config = self.getFRRconfig('bgp community-list', end='')
+ for comm_list, comm_list_config in test_data.items():
+ if 'rule' not in comm_list_config:
+ continue
+
+ seq = '5'
+ for rule, rule_config in comm_list_config['rule'].items():
+ tmp = f'bgp community-list {comm_list} seq {seq}'
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['regex']
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+ def test_extended_community_list(self):
+ test_data = {
+ 'foo' : {
+ 'rule' : {
+ '4' : {
+ 'action' : 'permit',
+ 'regex' : '.*',
+ },
+ },
+ },
+ '200' : {
+ 'rule' : {
+ '1' : {
+ 'action' : 'deny',
+ 'regex' : '^1:201$',
+ },
+ '2' : {
+ 'action' : 'deny',
+ 'regex' : '1:101$',
+ },
+ '3' : {
+ 'action' : 'deny',
+ 'regex' : '^1:100$',
+ },
+ },
+ },
+ }
+
+ for comm_list, comm_list_config in test_data.items():
+ path = base_path + ['extcommunity-list', comm_list]
+ self.cli_set(path + ['description', f'VyOS-EXTCOMM-{comm_list}'])
+ if 'rule' not in comm_list_config:
+ continue
+
+ for rule, rule_config in comm_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'regex' in rule_config:
+ self.cli_set(path + ['rule', rule, 'regex', rule_config['regex']])
+
+ self.cli_commit()
+
+ config = self.getFRRconfig('bgp extcommunity-list', end='')
+ for comm_list, comm_list_config in test_data.items():
+ if 'rule' not in comm_list_config:
+ continue
+
+ seq = '5'
+ for rule, rule_config in comm_list_config['rule'].items():
+ # if the community is not a number but a name, the expanded
+ # keyword is used
+ expanded = ''
+ if not comm_list.isnumeric():
+ expanded = ' expanded'
+ tmp = f'bgp extcommunity-list{expanded} {comm_list} seq {seq}'
+
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['regex']
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+
+ def test_large_community_list(self):
+ test_data = {
+ 'foo' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '667:123:100',
+ },
+ },
+ },
+ 'bar' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '65000:120:10',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'regex' : '65000:120:20',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '65000:120:30',
+ },
+ },
+ },
+ }
+
+ for comm_list, comm_list_config in test_data.items():
+ path = base_path + ['large-community-list', comm_list]
+ self.cli_set(path + ['description', f'VyOS-LARGECOMM-{comm_list}'])
+ if 'rule' not in comm_list_config:
+ continue
+
+ for rule, rule_config in comm_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'regex' in rule_config:
+ self.cli_set(path + ['rule', rule, 'regex', rule_config['regex']])
+
+ self.cli_commit()
+
+ config = self.getFRRconfig('bgp large-community-list', end='')
+ for comm_list, comm_list_config in test_data.items():
+ if 'rule' not in comm_list_config:
+ continue
+
+ seq = '5'
+ for rule, rule_config in comm_list_config['rule'].items():
+ tmp = f'bgp large-community-list expanded {comm_list} seq {seq}'
+
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['regex']
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+
+ def test_prefix_list(self):
+ test_data = {
+ 'foo' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'prefix' : '10.0.0.0/8',
+ 'ge' : '16',
+ 'le' : '24',
+ },
+ '20' : {
+ 'action' : 'deny',
+ 'prefix' : '172.16.0.0/12',
+ 'ge' : '16',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'prefix' : '192.168.0.0/16',
+ },
+ },
+ },
+ 'bar' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'prefix' : '10.0.10.0/24',
+ 'ge' : '25',
+ 'le' : '26',
+ },
+ '20' : {
+ 'action' : 'deny',
+ 'prefix' : '10.0.20.0/24',
+ 'le' : '25',
+ },
+ '25' : {
+ 'action' : 'permit',
+ 'prefix' : '10.0.25.0/24',
+ },
+ },
+ },
+ }
+
+ for prefix_list, prefix_list_config in test_data.items():
+ path = base_path + ['prefix-list', prefix_list]
+ self.cli_set(path + ['description', f'VyOS-PFX-LIST-{prefix_list}'])
+ if 'rule' not in prefix_list_config:
+ continue
+
+ for rule, rule_config in prefix_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'prefix' in rule_config:
+ self.cli_set(path + ['rule', rule, 'prefix', rule_config['prefix']])
+ if 'ge' in rule_config:
+ self.cli_set(path + ['rule', rule, 'ge', rule_config['ge']])
+ if 'le' in rule_config:
+ self.cli_set(path + ['rule', rule, 'le', rule_config['le']])
+
+ self.cli_commit()
+
+ config = self.getFRRconfig('ip prefix-list', end='')
+ for prefix_list, prefix_list_config in test_data.items():
+ if 'rule' not in prefix_list_config:
+ continue
+
+ for rule, rule_config in prefix_list_config['rule'].items():
+ tmp = f'ip prefix-list {prefix_list} seq {rule}'
+
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['prefix']
+
+ if 'ge' in rule_config:
+ tmp += ' ge ' + rule_config['ge']
+ if 'le' in rule_config:
+ tmp += ' le ' + rule_config['le']
+
+ self.assertIn(tmp, config)
+
+
+ def test_prefix_list6(self):
+ test_data = {
+ 'foo' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'prefix' : '2001:db8::/32',
+ 'ge' : '40',
+ 'le' : '48',
+ },
+ '20' : {
+ 'action' : 'deny',
+ 'prefix' : '2001:db8::/32',
+ 'ge' : '48',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'prefix' : '2001:db8:1000::/64',
+ },
+ },
+ },
+ 'bar' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'prefix' : '2001:db8:100::/40',
+ 'ge' : '48',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'prefix' : '2001:db8:200::/40',
+ 'ge' : '48',
+ },
+ '25' : {
+ 'action' : 'deny',
+ 'prefix' : '2001:db8:300::/40',
+ 'le' : '64',
+ },
+ },
+ },
+ }
+
+ for prefix_list, prefix_list_config in test_data.items():
+ path = base_path + ['prefix-list6', prefix_list]
+ self.cli_set(path + ['description', f'VyOS-PFX-LIST-{prefix_list}'])
+ if 'rule' not in prefix_list_config:
+ continue
+
+ for rule, rule_config in prefix_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'prefix' in rule_config:
+ self.cli_set(path + ['rule', rule, 'prefix', rule_config['prefix']])
+ if 'ge' in rule_config:
+ self.cli_set(path + ['rule', rule, 'ge', rule_config['ge']])
+ if 'le' in rule_config:
+ self.cli_set(path + ['rule', rule, 'le', rule_config['le']])
+
+ self.cli_commit()
+
+ config = self.getFRRconfig('ipv6 prefix-list', end='')
+ for prefix_list, prefix_list_config in test_data.items():
+ if 'rule' not in prefix_list_config:
+ continue
+
+ for rule, rule_config in prefix_list_config['rule'].items():
+ tmp = f'ipv6 prefix-list {prefix_list} seq {rule}'
+
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['prefix']
+
+ if 'ge' in rule_config:
+ tmp += ' ge ' + rule_config['ge']
+ if 'le' in rule_config:
+ tmp += ' le ' + rule_config['le']
+
+ self.assertIn(tmp, config)
+
+
+ # Test set table for some sources
+ def test_table_id(self):
+ path = base_path + ['local-route']
+
+ sources = ['203.0.113.1', '203.0.113.2']
+ rule = '50'
+ table = '23'
+ for src in sources:
+ self.cli_set(path + ['rule', rule, 'set', 'table', table])
+ self.cli_set(path + ['rule', rule, 'source', src])
+
+ self.cli_commit()
+
+ # Check generated configuration
+
+ # Expected values
+ original = """
+ 50: from 203.0.113.1 lookup 23
+ 50: from 203.0.113.2 lookup 23
+ """
+ tmp = cmd('ip rule show prio 50')
+ original = original.split()
+ tmp = tmp.split()
+
+ self.assertEqual(tmp, original)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_policy_local-route.py b/smoketest/scripts/cli/test_policy_local-route.py
deleted file mode 100755
index de1882a65..000000000
--- a/smoketest/scripts/cli/test_policy_local-route.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020 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
-import unittest
-
-from vyos.configsession import ConfigSession
-from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import process_named_running
-
-class PolicyLocalRouteTest(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
- self._sources = ['203.0.113.1', '203.0.113.2']
-
- def tearDown(self):
- # Delete all policies
- self.session.delete(['policy', 'local-route'])
- self.session.commit()
- del self.session
-
- # Test set table for some sources
- def test_table_id(self):
- base = ['policy', 'local-route']
- rule = '50'
- table = '23'
- for src in self._sources:
- self.session.set(base + ['rule', rule, 'set', 'table', table])
- self.session.set(base + ['rule', rule, 'source', src])
-
- self.session.commit()
-
- # Check generated configuration
-
- # Expected values
- original = """
- 50: from 203.0.113.1 lookup 23
- 50: from 203.0.113.2 lookup 23
- """
- tmp = cmd('ip rule show prio 50')
- original = original.split()
- tmp = tmp.split()
-
- self.assertEqual(tmp, original)
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py
new file mode 100755
index 000000000..a57f8d5f2
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_bfd.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+from vyos.util import process_named_running
+
+PROCESS_NAME = 'bfdd'
+base_path = ['protocols', 'bfd']
+
+dum_if = 'dum1001'
+peers = {
+ '192.0.2.10' : {
+ 'intv_rx' : '500',
+ 'intv_tx' : '600',
+ 'multihop' : '',
+ 'source_addr': '192.0.2.254',
+ },
+ '192.0.2.20' : {
+ 'echo_mode' : '',
+ 'intv_echo' : '100',
+ 'intv_mult' : '100',
+ 'intv_rx' : '222',
+ 'intv_tx' : '333',
+ 'shutdown' : '',
+ 'source_intf': dum_if,
+ },
+ '2001:db8::a' : {
+ 'source_addr': '2001:db8::1',
+ 'source_intf': dum_if,
+ },
+ '2001:db8::b' : {
+ 'source_addr': '2001:db8::1',
+ 'multihop' : '',
+ },
+}
+
+profiles = {
+ 'foo' : {
+ 'echo_mode' : '',
+ 'intv_echo' : '100',
+ 'intv_mult' : '101',
+ 'intv_rx' : '222',
+ 'intv_tx' : '333',
+ 'shutdown' : '',
+ },
+ 'bar' : {
+ 'intv_mult' : '102',
+ 'intv_rx' : '444',
+ },
+}
+
+class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
+ def test_bfd_peer(self):
+ for peer, peer_config in peers.items():
+ if 'echo_mode' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'echo-mode'])
+ if 'intv_echo' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'interval', 'echo-interval', peer_config["intv_echo"]])
+ if 'intv_mult' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'interval', 'multiplier', peer_config["intv_mult"]])
+ if 'intv_rx' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'interval', 'receive', peer_config["intv_rx"]])
+ if 'intv_tx' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'interval', 'transmit', peer_config["intv_tx"]])
+ if 'multihop' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'multihop'])
+ if 'shutdown' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'shutdown'])
+ if 'source_addr' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'source', 'address', peer_config["source_addr"]])
+ if 'source_intf' in peer_config:
+ self.cli_set(base_path + ['peer', peer, 'source', 'interface', peer_config["source_intf"]])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR bgpd configuration
+ frrconfig = self.getFRRconfig('bfd')
+ for peer, peer_config in peers.items():
+ tmp = f'peer {peer}'
+ if 'multihop' in peer_config:
+ tmp += f' multihop'
+ if 'source_addr' in peer_config:
+ tmp += f' local-address {peer_config["source_addr"]}'
+ if 'source_intf' in peer_config:
+ tmp += f' interface {peer_config["source_intf"]}'
+
+ self.assertIn(tmp, frrconfig)
+ peerconfig = self.getFRRconfig(f' peer {peer}', end='')
+
+ if 'echo_mode' in peer_config:
+ self.assertIn(f'echo-mode', peerconfig)
+ if 'intv_echo' in peer_config:
+ self.assertIn(f'echo-interval {peer_config["intv_echo"]}', peerconfig)
+ if 'intv_mult' in peer_config:
+ self.assertIn(f'detect-multiplier {peer_config["intv_mult"]}', peerconfig)
+ if 'intv_rx' in peer_config:
+ self.assertIn(f'receive-interval {peer_config["intv_rx"]}', peerconfig)
+ if 'intv_tx' in peer_config:
+ self.assertIn(f'transmit-interval {peer_config["intv_tx"]}', peerconfig)
+ if 'shutdown' in peer_config:
+ self.assertIn(f'shutdown', peerconfig)
+ else:
+ self.assertNotIn(f'shutdown', peerconfig)
+
+ def test_bfd_profile(self):
+ peer = '192.0.2.10'
+
+ for profile, profile_config in profiles.items():
+ if 'echo_mode' in profile_config:
+ self.cli_set(base_path + ['profile', profile, 'echo-mode'])
+ if 'intv_echo' in profile_config:
+ self.cli_set(base_path + ['profile', profile, 'interval', 'echo-interval', profile_config["intv_echo"]])
+ if 'intv_mult' in profile_config:
+ self.cli_set(base_path + ['profile', profile, 'interval', 'multiplier', profile_config["intv_mult"]])
+ if 'intv_rx' in profile_config:
+ self.cli_set(base_path + ['profile', profile, 'interval', 'receive', profile_config["intv_rx"]])
+ if 'intv_tx' in profile_config:
+ self.cli_set(base_path + ['profile', profile, 'interval', 'transmit', profile_config["intv_tx"]])
+ if 'shutdown' in profile_config:
+ self.cli_set(base_path + ['profile', profile, 'shutdown'])
+
+ self.cli_set(base_path + ['peer', peer, 'profile', list(profiles)[0]])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR bgpd configuration
+ for profile, profile_config in profiles.items():
+ config = self.getFRRconfig(f' profile {profile}', endsection='^ !')
+ if 'echo_mode' in profile_config:
+ self.assertIn(f'echo-mode', config)
+ if 'intv_echo' in profile_config:
+ self.assertIn(f'echo-interval {profile_config["intv_echo"]}', config)
+ if 'intv_mult' in profile_config:
+ self.assertIn(f'detect-multiplier {profile_config["intv_mult"]}', config)
+ if 'intv_rx' in profile_config:
+ self.assertIn(f'receive-interval {profile_config["intv_rx"]}', config)
+ if 'intv_tx' in profile_config:
+ self.assertIn(f'transmit-interval {profile_config["intv_tx"]}', config)
+ if 'shutdown' in profile_config:
+ self.assertIn(f'shutdown', config)
+ else:
+ self.assertNotIn(f'shutdown', config)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index 1d93aeda4..4f39948c0 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -14,87 +14,147 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
-from vyos.configsession import ConfigSession
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
+from vyos.template import is_ipv6
from vyos.util import process_named_running
PROCESS_NAME = 'bgpd'
ASN = '64512'
-base_path = ['protocols', 'bgp', ASN]
+base_path = ['protocols', 'bgp']
+
+route_map_in = 'foo-map-in'
+route_map_out = 'foo-map-out'
+prefix_list_in = 'pfx-foo-in'
+prefix_list_out = 'pfx-foo-out'
+prefix_list_in6 = 'pfx-foo-in6'
+prefix_list_out6 = 'pfx-foo-out6'
neighbor_config = {
'192.0.2.1' : {
- 'cap_dynamic' : '',
- 'cap_ext_next': '',
- 'remote_as' : '100',
- 'adv_interv' : '400',
- 'passive' : '',
- 'password' : 'VyOS-Secure123',
- 'shutdown' : '',
- 'cap_over' : '',
- 'ttl_security': '5',
- 'local_as' : '300',
+ 'cap_dynamic' : '',
+ 'cap_ext_next' : '',
+ 'remote_as' : '100',
+ 'adv_interv' : '400',
+ 'passive' : '',
+ 'password' : 'VyOS-Secure123',
+ 'shutdown' : '',
+ 'cap_over' : '',
+ 'ttl_security' : '5',
+ 'local_as' : '300',
+ 'route_map_in' : route_map_in,
+ 'route_map_out': route_map_out,
+ 'no_send_comm_ext' : '',
+ 'addpath_all' : '',
},
'192.0.2.2' : {
- 'remote_as' : '200',
- 'shutdown' : '',
- 'no_cap_nego' : '',
- 'port' : '667',
- 'cap_strict' : '',
+ 'remote_as' : '200',
+ 'shutdown' : '',
+ 'no_cap_nego' : '',
+ 'port' : '667',
+ 'cap_strict' : '',
+ 'pfx_list_in' : prefix_list_in,
+ 'pfx_list_out' : prefix_list_out,
+ 'no_send_comm_std' : '',
},
'192.0.2.3' : {
-# XXX: not available in current Perl backend
-# 'description' : 'foo bar baz',
- 'remote_as' : '200',
- 'passive' : '',
- 'multi_hop' : '5',
- 'update_src' : 'lo',
+ 'description' : 'foo bar baz',
+ 'remote_as' : '200',
+ 'passive' : '',
+ 'multi_hop' : '5',
+ 'update_src' : 'lo',
+ },
+ '2001:db8::1' : {
+ 'cap_dynamic' : '',
+ 'cap_ext_next' : '',
+ 'remote_as' : '123',
+ 'adv_interv' : '400',
+ 'passive' : '',
+ 'password' : 'VyOS-Secure123',
+ 'shutdown' : '',
+ 'cap_over' : '',
+ 'ttl_security' : '5',
+ 'local_as' : '300',
+ 'route_map_in' : route_map_in,
+ 'route_map_out': route_map_out,
+ 'no_send_comm_std' : '',
+ 'addpath_per_as' : '',
+ },
+ '2001:db8::2' : {
+ 'remote_as' : '456',
+ 'shutdown' : '',
+ 'no_cap_nego' : '',
+ 'port' : '667',
+ 'cap_strict' : '',
+ 'pfx_list_in' : prefix_list_in6,
+ 'pfx_list_out' : prefix_list_out6,
+ 'no_send_comm_ext' : '',
},
}
peer_group_config = {
'foo' : {
- 'remote_as' : '100',
- 'passive' : '',
- 'password' : 'VyOS-Secure123',
- 'shutdown' : '',
- 'cap_over' : '',
+ 'remote_as' : '100',
+ 'passive' : '',
+ 'password' : 'VyOS-Secure123',
+ 'shutdown' : '',
+ 'cap_over' : '',
# XXX: not available in current Perl backend
# 'ttl_security': '5',
},
'bar' : {
-# XXX: not available in current Perl backend
-# 'description' : 'foo peer bar group',
- 'remote_as' : '200',
- 'shutdown' : '',
- 'no_cap_nego' : '',
- 'local_as' : '300',
+ 'description' : 'foo peer bar group',
+ 'remote_as' : '200',
+ 'shutdown' : '',
+ 'no_cap_nego' : '',
+ 'local_as' : '300',
+ 'pfx_list_in' : prefix_list_in,
+ 'pfx_list_out' : prefix_list_out,
+ 'no_send_comm_ext' : '',
},
'baz' : {
- 'cap_dynamic' : '',
- 'cap_ext_next': '',
- 'remote_as' : '200',
- 'passive' : '',
- 'multi_hop' : '5',
- 'update_src' : 'lo',
+ 'cap_dynamic' : '',
+ 'cap_ext_next' : '',
+ 'remote_as' : '200',
+ 'passive' : '',
+ 'multi_hop' : '5',
+ 'update_src' : 'lo',
+ 'route_map_in' : route_map_in,
+ 'route_map_out': route_map_out,
},
}
-def getFRRBGPconfig():
- return cmd(f'vtysh -c "show run" | sed -n "/router bgp {ASN}/,/^!/p"')
-class TestProtocolsBGP(unittest.TestCase):
+class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
+ self.cli_set(['policy', 'route-map', route_map_in, 'rule', '10', 'action', 'permit'])
+ self.cli_set(['policy', 'route-map', route_map_out, 'rule', '10', 'action', 'permit'])
+ self.cli_set(['policy', 'prefix-list', prefix_list_in, 'rule', '10', 'action', 'permit'])
+ self.cli_set(['policy', 'prefix-list', prefix_list_in, 'rule', '10', 'prefix', '192.0.2.0/25'])
+ self.cli_set(['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'action', 'permit'])
+ self.cli_set(['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'prefix', '192.0.2.128/25'])
+
+ self.cli_set(['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'action', 'permit'])
+ self.cli_set(['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'prefix', '2001:db8:1000::/64'])
+ self.cli_set(['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'action', 'deny'])
+ self.cli_set(['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'prefix', '2001:db8:2000::/64'])
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(['policy', 'route-map', route_map_in])
+ self.cli_delete(['policy', 'route-map', route_map_out])
+ self.cli_delete(['policy', 'prefix-list', prefix_list_in])
+ self.cli_delete(['policy', 'prefix-list', prefix_list_out])
+ self.cli_delete(['policy', 'prefix-list6', prefix_list_in6])
+ self.cli_delete(['policy', 'prefix-list6', prefix_list_out6])
+
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
def verify_frr_config(self, peer, peer_config, frrconfig):
# recurring patterns to verify for both a simple neighbor and a peer-group
@@ -124,121 +184,205 @@ class TestProtocolsBGP(unittest.TestCase):
self.assertIn(f' neighbor {peer} ttl-security hops {peer_config["ttl_security"]}', frrconfig)
if 'update_src' in peer_config:
self.assertIn(f' neighbor {peer} update-source {peer_config["update_src"]}', frrconfig)
+ if 'route_map_in' in peer_config:
+ self.assertIn(f' neighbor {peer} route-map {peer_config["route_map_in"]} in', frrconfig)
+ if 'route_map_out' in peer_config:
+ self.assertIn(f' neighbor {peer} route-map {peer_config["route_map_out"]} out', frrconfig)
+ if 'pfx_list_in' in peer_config:
+ self.assertIn(f' neighbor {peer} prefix-list {peer_config["pfx_list_in"]} in', frrconfig)
+ if 'pfx_list_out' in peer_config:
+ self.assertIn(f' neighbor {peer} prefix-list {peer_config["pfx_list_out"]} out', frrconfig)
+ if 'no_send_comm_std' in peer_config:
+ self.assertIn(f' no neighbor {peer} send-community', frrconfig)
+ if 'no_send_comm_ext' in peer_config:
+ self.assertIn(f' no neighbor {peer} send-community extended', frrconfig)
+ if 'addpath_all' in peer_config:
+ self.assertIn(f' neighbor {peer} addpath-tx-all-paths', frrconfig)
+ if 'addpath_per_as' in peer_config:
+ self.assertIn(f' neighbor {peer} addpath-tx-bestpath-per-AS', frrconfig)
+
def test_bgp_01_simple(self):
router_id = '127.0.0.1'
local_pref = '500'
-
- self.session.set(base_path + ['parameters', 'router-id', router_id])
- self.session.set(base_path + ['parameters', 'log-neighbor-changes'])
- # Default local preference (higher=more preferred)
- self.session.set(base_path + ['parameters', 'default', 'local-pref', local_pref])
+ stalepath_time = '60'
+ max_path_v4 = '2'
+ max_path_v4ibgp = '4'
+ max_path_v6 = '8'
+ max_path_v6ibgp = '16'
+
+ self.cli_set(base_path + ['parameters', 'router-id', router_id])
+ self.cli_set(base_path + ['parameters', 'log-neighbor-changes'])
+
+ # Local AS number MUST be defined
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(base_path + ['local-as', ASN])
+
+ # Default local preference (higher = more preferred, default value is 100)
+ self.cli_set(base_path + ['parameters', 'default', 'local-pref', local_pref])
# Deactivate IPv4 unicast for a peer by default
- self.session.set(base_path + ['parameters', 'default', 'no-ipv4-unicast'])
+ self.cli_set(base_path + ['parameters', 'default', 'no-ipv4-unicast'])
+ self.cli_set(base_path + ['parameters', 'graceful-restart', 'stalepath-time', stalepath_time])
+ self.cli_set(base_path + ['parameters', 'graceful-shutdown'])
+ self.cli_set(base_path + ['parameters', 'ebgp-requires-policy'])
+
+ # AFI maximum path support
+ self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ebgp', max_path_v4])
+ self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ibgp', max_path_v4ibgp])
+ self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'maximum-paths', 'ebgp', max_path_v6])
+ self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'maximum-paths', 'ibgp', max_path_v6ibgp])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = getFRRBGPconfig()
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' bgp router-id {router_id}', frrconfig)
self.assertIn(f' bgp log-neighbor-changes', frrconfig)
self.assertIn(f' bgp default local-preference {local_pref}', frrconfig)
self.assertIn(f' no bgp default ipv4-unicast', frrconfig)
+ self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig)
+ self.assertIn(f' bgp graceful-shutdown', frrconfig)
+ self.assertNotIn(f'bgp ebgp-requires-policy', frrconfig)
+
+ afiv4_config = self.getFRRconfig(' address-family ipv4 unicast')
+ self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config)
+ self.assertIn(f' maximum-paths ibgp {max_path_v4ibgp}', afiv4_config)
+
+ afiv6_config = self.getFRRconfig(' address-family ipv6 unicast')
+ self.assertIn(f' maximum-paths {max_path_v6}', afiv6_config)
+ self.assertIn(f' maximum-paths ibgp {max_path_v6ibgp}', afiv6_config)
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
def test_bgp_02_neighbors(self):
+ self.cli_set(base_path + ['local-as', ASN])
# Test out individual neighbor configuration items, not all of them are
# also available to a peer-group!
- for neighbor, config in neighbor_config.items():
- if 'adv_interv' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'advertisement-interval', config["adv_interv"]])
- if 'cap_dynamic' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'capability', 'dynamic'])
- if 'cap_ext_next' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'capability', 'extended-nexthop'])
- if 'description' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'description', config["description"]])
- if 'no_cap_nego' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'disable-capability-negotiation'])
- if 'multi_hop' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'ebgp-multihop', config["multi_hop"]])
- if 'local_as' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'local-as', config["local_as"]])
- if 'cap_over' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'override-capability'])
- if 'passive' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'passive'])
- if 'password' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'password', config["password"]])
- if 'port' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'port', config["port"]])
- if 'remote_as' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'remote-as', config["remote_as"]])
- if 'cap_strict' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'strict-capability-match'])
- if 'shutdown' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'shutdown'])
- if 'ttl_security' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'ttl-security', 'hops', config["ttl_security"]])
- if 'update_src' in config:
- self.session.set(base_path + ['neighbor', neighbor, 'update-source', config["update_src"]])
+ for peer, peer_config in neighbor_config.items():
+ afi = 'ipv4-unicast'
+ if is_ipv6(peer):
+ afi = 'ipv6-unicast'
+
+ if 'adv_interv' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'advertisement-interval', peer_config["adv_interv"]])
+ if 'cap_dynamic' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'capability', 'dynamic'])
+ if 'cap_ext_next' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'capability', 'extended-nexthop'])
+ if 'description' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'description', peer_config["description"]])
+ if 'no_cap_nego' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'disable-capability-negotiation'])
+ if 'multi_hop' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'ebgp-multihop', peer_config["multi_hop"]])
+ if 'local_as' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"]])
+ if 'cap_over' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'override-capability'])
+ if 'passive' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'passive'])
+ if 'password' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'password', peer_config["password"]])
+ if 'port' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'port', peer_config["port"]])
+ if 'remote_as' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'remote-as', peer_config["remote_as"]])
+ if 'cap_strict' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'strict-capability-match'])
+ if 'shutdown' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'shutdown'])
+ if 'ttl_security' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'ttl-security', 'hops', peer_config["ttl_security"]])
+ if 'update_src' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'update-source', peer_config["update_src"]])
+ if 'route_map_in' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'route-map', 'import', peer_config["route_map_in"]])
+ if 'route_map_out' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'route-map', 'export', peer_config["route_map_out"]])
+ if 'pfx_list_in' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'import', peer_config["pfx_list_in"]])
+ if 'pfx_list_out' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'export', peer_config["pfx_list_out"]])
+ if 'no_send_comm_std' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'standard'])
+ if 'no_send_comm_ext' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'extended'])
+ if 'addpath_all' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-all'])
+ if 'addpath_per_as' in peer_config:
+ self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-per-as'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = getFRRBGPconfig()
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}')
self.assertIn(f'router bgp {ASN}', frrconfig)
for peer, peer_config in neighbor_config.items():
- if 'adv_interv' in config:
+ if 'adv_interv' in peer_config:
self.assertIn(f' neighbor {peer} advertisement-interval {peer_config["adv_interv"]}', frrconfig)
- if 'port' in config:
+ if 'port' in peer_config:
self.assertIn(f' neighbor {peer} port {peer_config["port"]}', frrconfig)
- if 'cap_strict' in config:
+ if 'cap_strict' in peer_config:
self.assertIn(f' neighbor {peer} strict-capability-match', frrconfig)
self.verify_frr_config(peer, peer_config, frrconfig)
def test_bgp_03_peer_groups(self):
+ self.cli_set(base_path + ['local-as', ASN])
# Test out individual peer-group configuration items
for peer_group, config in peer_group_config.items():
if 'cap_dynamic' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'capability', 'dynamic'])
+ self.cli_set(base_path + ['peer-group', peer_group, 'capability', 'dynamic'])
if 'cap_ext_next' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'capability', 'extended-nexthop'])
+ self.cli_set(base_path + ['peer-group', peer_group, 'capability', 'extended-nexthop'])
if 'description' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'description', config["description"]])
+ self.cli_set(base_path + ['peer-group', peer_group, 'description', config["description"]])
if 'no_cap_nego' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'disable-capability-negotiation'])
+ self.cli_set(base_path + ['peer-group', peer_group, 'disable-capability-negotiation'])
if 'multi_hop' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'ebgp-multihop', config["multi_hop"]])
+ self.cli_set(base_path + ['peer-group', peer_group, 'ebgp-multihop', config["multi_hop"]])
if 'local_as' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"]])
+ self.cli_set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"]])
if 'cap_over' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'override-capability'])
+ self.cli_set(base_path + ['peer-group', peer_group, 'override-capability'])
if 'passive' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'passive'])
+ self.cli_set(base_path + ['peer-group', peer_group, 'passive'])
if 'password' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'password', config["password"]])
+ self.cli_set(base_path + ['peer-group', peer_group, 'password', config["password"]])
if 'remote_as' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'remote-as', config["remote_as"]])
+ self.cli_set(base_path + ['peer-group', peer_group, 'remote-as', config["remote_as"]])
if 'shutdown' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'shutdown'])
+ self.cli_set(base_path + ['peer-group', peer_group, 'shutdown'])
if 'ttl_security' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'ttl-security', 'hops', config["ttl_security"]])
+ self.cli_set(base_path + ['peer-group', peer_group, 'ttl-security', 'hops', config["ttl_security"]])
if 'update_src' in config:
- self.session.set(base_path + ['peer-group', peer_group, 'update-source', config["update_src"]])
+ self.cli_set(base_path + ['peer-group', peer_group, 'update-source', config["update_src"]])
+ if 'route_map_in' in config:
+ self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'route-map', 'import', config["route_map_in"]])
+ if 'route_map_out' in config:
+ self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'route-map', 'export', config["route_map_out"]])
+ if 'pfx_list_in' in config:
+ self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'prefix-list', 'import', config["pfx_list_in"]])
+ if 'pfx_list_out' in config:
+ self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'prefix-list', 'export', config["pfx_list_out"]])
+ if 'no_send_comm_std' in config:
+ self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'standard'])
+ if 'no_send_comm_ext' in config:
+ self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'extended'])
+ if 'addpath_all' in config:
+ self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-all'])
+ if 'addpath_per_as' in config:
+ self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-per-as'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = getFRRBGPconfig()
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}')
self.assertIn(f'router bgp {ASN}', frrconfig)
for peer, peer_config in peer_group_config.items():
@@ -259,27 +403,29 @@ class TestProtocolsBGP(unittest.TestCase):
},
}
+ self.cli_set(base_path + ['local-as', ASN])
+
# We want to redistribute ...
- redistributes = ['connected', 'kernel', 'ospf', 'rip', 'static']
+ redistributes = ['connected', 'isis', 'kernel', 'ospf', 'rip', 'static']
for redistribute in redistributes:
- self.session.set(base_path + ['address-family', 'ipv4-unicast',
+ self.cli_set(base_path + ['address-family', 'ipv4-unicast',
'redistribute', redistribute])
for network, network_config in networks.items():
- self.session.set(base_path + ['address-family', 'ipv4-unicast',
+ self.cli_set(base_path + ['address-family', 'ipv4-unicast',
'network', network])
if 'as_set' in network_config:
- self.session.set(base_path + ['address-family', 'ipv4-unicast',
+ self.cli_set(base_path + ['address-family', 'ipv4-unicast',
'aggregate-address', network, 'as-set'])
if 'summary_only' in network_config:
- self.session.set(base_path + ['address-family', 'ipv4-unicast',
+ self.cli_set(base_path + ['address-family', 'ipv4-unicast',
'aggregate-address', network, 'summary-only'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = getFRRBGPconfig()
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv4 unicast', frrconfig)
@@ -297,34 +443,39 @@ class TestProtocolsBGP(unittest.TestCase):
def test_bgp_05_afi_ipv6(self):
networks = {
'2001:db8:100::/48' : {
- },
+ },
'2001:db8:200::/48' : {
- },
+ },
'2001:db8:300::/48' : {
'summary_only' : '',
- },
+ },
}
+ self.cli_set(base_path + ['local-as', ASN])
+
# We want to redistribute ...
redistributes = ['connected', 'kernel', 'ospfv3', 'ripng', 'static']
for redistribute in redistributes:
- self.session.set(base_path + ['address-family', 'ipv6-unicast',
+ self.cli_set(base_path + ['address-family', 'ipv6-unicast',
'redistribute', redistribute])
for network, network_config in networks.items():
- self.session.set(base_path + ['address-family', 'ipv6-unicast',
+ self.cli_set(base_path + ['address-family', 'ipv6-unicast',
'network', network])
if 'summary_only' in network_config:
- self.session.set(base_path + ['address-family', 'ipv6-unicast',
+ self.cli_set(base_path + ['address-family', 'ipv6-unicast',
'aggregate-address', network, 'summary-only'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = getFRRBGPconfig()
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv6 unicast', frrconfig)
+ # T2100: By default ebgp-requires-policy is disabled to keep VyOS
+ # 1.3 and 1.2 backwards compatibility
+ self.assertIn(f' no bgp ebgp-requires-policy', frrconfig)
for redistribute in redistributes:
# FRR calls this OSPF6
@@ -338,5 +489,95 @@ class TestProtocolsBGP(unittest.TestCase):
self.assertIn(f' aggregate-address {network} summary-only', frrconfig)
+ def test_bgp_06_listen_range(self):
+ # Implemented via T1875
+ limit = '64'
+ listen_ranges = ['192.0.2.0/25', '192.0.2.128/25']
+ peer_group = 'listenfoobar'
+
+ self.cli_set(base_path + ['local-as', ASN])
+ self.cli_set(base_path + ['listen', 'limit', limit])
+
+ for prefix in listen_ranges:
+ self.cli_set(base_path + ['listen', 'range', prefix])
+ # check validate() - peer-group must be defined for range/prefix
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(base_path + ['listen', 'range', prefix, 'peer-group', peer_group])
+
+ # check validate() - peer-group does yet not exist!
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(base_path + ['peer-group', peer_group, 'remote-as', ASN])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR bgpd configuration
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ self.assertIn(f'router bgp {ASN}', frrconfig)
+ self.assertIn(f' neighbor {peer_group} peer-group', frrconfig)
+ self.assertIn(f' neighbor {peer_group} remote-as {ASN}', frrconfig)
+ self.assertIn(f' bgp listen limit {limit}', frrconfig)
+ for prefix in listen_ranges:
+ self.assertIn(f' bgp listen range {prefix} peer-group {peer_group}', frrconfig)
+
+
+ def test_bgp_07_l2vpn_evpn(self):
+ vnis = ['10010', '10020', '10030']
+ neighbors = ['192.0.2.10', '192.0.2.20', '192.0.2.30']
+
+ self.cli_set(base_path + ['local-as', ASN])
+
+ self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-all-vni'])
+ self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-default-gw'])
+ self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-svi-ip'])
+ self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'flooding', 'disable'])
+ for vni in vnis:
+ self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-default-gw'])
+ self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-svi-ip'])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR bgpd configuration
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+ self.assertIn(f'router bgp {ASN}', frrconfig)
+ self.assertIn(f' address-family l2vpn evpn', frrconfig)
+ self.assertIn(f' advertise-all-vni', frrconfig)
+ self.assertIn(f' advertise-default-gw', frrconfig)
+ self.assertIn(f' advertise-svi-ip', frrconfig)
+ self.assertIn(f' flooding disable', frrconfig)
+ for vni in vnis:
+ vniconfig = self.getFRRconfig(f' vni {vni}')
+ self.assertIn(f'vni {vni}', vniconfig)
+ self.assertIn(f' advertise-default-gw', vniconfig)
+ self.assertIn(f' advertise-svi-ip', vniconfig)
+
+ def test_bgp_08_vrf_simple(self):
+ router_id = '127.0.0.3'
+ vrfs = ['red', 'green', 'blue']
+
+ # It is safe to assume that when the basic VRF test works, all
+ # other BGP related features work, as we entirely inherit the CLI
+ # templates and Jinja2 FRR template.
+ table = '1000'
+
+ for vrf in vrfs:
+ vrf_base = ['vrf', 'name', vrf]
+ self.cli_set(vrf_base + ['table', table])
+ self.cli_set(vrf_base + ['protocols', 'bgp', 'local-as', ASN])
+ self.cli_set(vrf_base + ['protocols', 'bgp', 'parameters', 'router-id', router_id])
+ table = str(int(table) + 1000)
+
+ self.cli_commit()
+
+ for vrf in vrfs:
+ # Verify FRR bgpd configuration
+ frrconfig = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}')
+
+ self.assertIn(f'router bgp {ASN} vrf {vrf}', frrconfig)
+ self.assertIn(f' bgp router-id {router_id}', frrconfig)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_igmp-proxy.py b/smoketest/scripts/cli/test_protocols_igmp-proxy.py
index 6aaad739d..1eaf21722 100755
--- a/smoketest/scripts/cli/test_protocols_igmp-proxy.py
+++ b/smoketest/scripts/cli/test_protocols_igmp-proxy.py
@@ -14,9 +14,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.util import read_file
@@ -28,46 +29,44 @@ base_path = ['protocols', 'igmp-proxy']
upstream_if = 'eth1'
downstream_if = 'eth2'
-class TestProtocolsIGMPProxy(unittest.TestCase):
+class TestProtocolsIGMPProxy(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
- self.session.set(['interfaces', 'ethernet', upstream_if, 'address', '172.16.1.1/24'])
+ self.cli_set(['interfaces', 'ethernet', upstream_if, 'address', '172.16.1.1/24'])
def tearDown(self):
- self.session.delete(['interfaces', 'ethernet', upstream_if, 'address'])
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(['interfaces', 'ethernet', upstream_if, 'address'])
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_igmpproxy(self):
threshold = '20'
altnet = '192.0.2.0/24'
whitelist = '10.0.0.0/8'
- self.session.set(base_path + ['disable-quickleave'])
- self.session.set(base_path + ['interface', upstream_if, 'threshold', threshold])
- self.session.set(base_path + ['interface', upstream_if, 'alt-subnet', altnet])
- self.session.set(base_path + ['interface', upstream_if, 'whitelist', whitelist])
+ self.cli_set(base_path + ['disable-quickleave'])
+ self.cli_set(base_path + ['interface', upstream_if, 'threshold', threshold])
+ self.cli_set(base_path + ['interface', upstream_if, 'alt-subnet', altnet])
+ self.cli_set(base_path + ['interface', upstream_if, 'whitelist', whitelist])
# Must define an upstream and at least 1 downstream interface!
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + ['interface', upstream_if, 'role', 'upstream'])
+ self.cli_commit()
+ self.cli_set(base_path + ['interface', upstream_if, 'role', 'upstream'])
# Interface does not exist
- self.session.set(base_path + ['interface', 'eth20', 'role', 'upstream'])
+ self.cli_set(base_path + ['interface', 'eth20', 'role', 'upstream'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(base_path + ['interface', 'eth20'])
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', 'eth20'])
# Only 1 upstream interface allowed
- self.session.set(base_path + ['interface', downstream_if, 'role', 'upstream'])
+ self.cli_set(base_path + ['interface', downstream_if, 'role', 'upstream'])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + ['interface', downstream_if, 'role', 'downstream'])
+ self.cli_commit()
+ self.cli_set(base_path + ['interface', downstream_if, 'role', 'downstream'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check generated configuration
config = read_file(IGMP_PROXY_CONF)
diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py
new file mode 100755
index 000000000..623cb044d
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_isis.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+from vyos.ifconfig import Section
+from vyos.util import process_named_running
+
+PROCESS_NAME = 'isisd'
+base_path = ['protocols', 'isis']
+
+domain = 'VyOS'
+net = '49.0001.1921.6800.1002.00'
+
+class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
+ def test_isis_01_redistribute(self):
+ prefix_list = 'EXPORT-ISIS'
+ route_map = 'EXPORT-ISIS'
+ rule = '10'
+ self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', rule, 'action', 'permit'])
+ self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', rule, 'prefix', '203.0.113.0/24'])
+ self.cli_set(['policy', 'route-map', route_map, 'rule', rule, 'action', 'permit'])
+ self.cli_set(['policy', 'route-map', route_map, 'rule', rule, 'match', 'ip', 'address', 'prefix-list', prefix_list])
+
+ self.cli_set(base_path + ['net', net])
+ self.cli_set(base_path + ['redistribute', 'ipv4', 'connected', 'level-2', 'route-map', route_map])
+
+ interfaces = Section.interfaces('ethernet')
+ for interface in interfaces:
+ self.cli_set(base_path + ['interface', interface])
+
+ # Commit all changes
+ self.cli_commit()
+
+ # Verify all changes
+ tmp = self.getFRRconfig(f'router isis {domain}')
+ self.assertIn(f' net {net}', tmp)
+ self.assertIn(f' redistribute ipv4 connected level-2 route-map {route_map}', tmp)
+
+ for interface in interfaces:
+ tmp = self.getFRRconfig(f'interface {interface}')
+ self.assertIn(f' ip router isis {domain}', tmp)
+
+ self.cli_delete(['policy'])
+
+
+ def test_isis_02_vrfs(self):
+ vrfs = ['red', 'green', 'blue']
+ # It is safe to assume that when the basic VRF test works, all other
+ # IS-IS related features work, as we entirely inherit the CLI templates
+ # and Jinja2 FRR template.
+ table = '1000'
+ vrf = 'red'
+ vrf_base = ['vrf', 'name', vrf]
+ vrf_iface = 'eth1'
+ self.cli_set(vrf_base + ['table', table])
+ self.cli_set(vrf_base + ['protocols', 'isis', 'net', net])
+ self.cli_set(vrf_base + ['protocols', 'isis', 'interface', vrf_iface])
+ self.cli_set(['interfaces', 'ethernet', vrf_iface, 'vrf', vrf])
+
+ # Also set a default VRF IS-IS config
+ self.cli_set(base_path + ['net', net])
+ self.cli_set(base_path + ['interface', 'eth0'])
+ self.cli_commit()
+
+ # Verify FRR isisd configuration
+ tmp = self.getFRRconfig(f'router isis {domain}')
+ self.assertIn(f'router isis {domain}', tmp)
+ self.assertIn(f' net {net}', tmp)
+
+ tmp = self.getFRRconfig(f'router isis {domain} vrf {vrf}')
+ self.assertIn(f'router isis {domain} vrf {vrf}', tmp)
+ self.assertIn(f' net {net}', tmp)
+
+ self.cli_delete(['vrf', 'name', vrf])
+ self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf'])
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py
new file mode 100755
index 000000000..8d94c86cb
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_ospf.py
@@ -0,0 +1,321 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.ifconfig import Section
+from vyos.util import process_named_running
+
+PROCESS_NAME = 'ospfd'
+base_path = ['protocols', 'ospf']
+
+route_map = 'foo-bar-baz10'
+
+class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
+ def setUp(self):
+ self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
+ self.cli_set(['policy', 'route-map', route_map, 'rule', '20', 'action', 'permit'])
+
+ def tearDown(self):
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+ self.cli_delete(['policy', 'route-map', route_map])
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_ospf_01_defaults(self):
+ # commit changes
+ self.cli_set(base_path)
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
+ self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
+
+ def test_ospf_02_simple(self):
+ router_id = '127.0.0.1'
+ abr_type = 'ibm'
+ bandwidth = '1000'
+ metric = '123'
+
+ self.cli_set(base_path + ['auto-cost', 'reference-bandwidth', bandwidth])
+ self.cli_set(base_path + ['parameters', 'router-id', router_id])
+ self.cli_set(base_path + ['parameters', 'abr-type', abr_type])
+ self.cli_set(base_path + ['log-adjacency-changes', 'detail'])
+ self.cli_set(base_path + ['default-metric', metric])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' auto-cost reference-bandwidth {bandwidth}', frrconfig)
+ self.assertIn(f' ospf router-id {router_id}', frrconfig)
+ self.assertIn(f' ospf abr-type {abr_type}', frrconfig)
+ self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
+ self.assertIn(f' default-metric {metric}', frrconfig)
+
+
+ def test_ospf_03_access_list(self):
+ acl = '100'
+ seq = '10'
+ protocols = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static']
+
+ self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'action', 'permit'])
+ self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'source', 'any'])
+ self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'destination', 'any'])
+ for ptotocol in protocols:
+ self.cli_set(base_path + ['access-list', acl, 'export', ptotocol])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
+ for ptotocol in protocols:
+ self.assertIn(f' distribute-list {acl} out {ptotocol}', frrconfig) # defaults
+ self.cli_delete(['policy', 'access-list', acl])
+
+
+ def test_ospf_04_default_originate(self):
+ seq = '100'
+ metric = '50'
+ metric_type = '1'
+
+ self.cli_set(base_path + ['default-information', 'originate', 'metric', metric])
+ self.cli_set(base_path + ['default-information', 'originate', 'metric-type', metric_type])
+ self.cli_set(base_path + ['default-information', 'originate', 'route-map', route_map])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
+ self.assertIn(f' default-information originate metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
+
+ # Now set 'always'
+ self.cli_set(base_path + ['default-information', 'originate', 'always'])
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
+
+
+ def test_ospf_05_options(self):
+ global_distance = '128'
+ intra_area = '100'
+ inter_area = '110'
+ external = '120'
+ on_startup = '30'
+ on_shutdown = '60'
+ refresh = '50'
+
+ self.cli_set(base_path + ['distance', 'global', global_distance])
+ self.cli_set(base_path + ['distance', 'ospf', 'external', external])
+ self.cli_set(base_path + ['distance', 'ospf', 'intra-area', intra_area])
+
+ self.cli_set(base_path + ['max-metric', 'router-lsa', 'on-startup', on_startup])
+ self.cli_set(base_path + ['max-metric', 'router-lsa', 'on-shutdown', on_shutdown])
+
+ self.cli_set(base_path + ['mpls-te', 'enable'])
+ self.cli_set(base_path + ['refresh', 'timers', refresh])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' mpls-te on', frrconfig)
+ self.assertIn(f' mpls-te router-address 0.0.0.0', frrconfig) # default
+ self.assertIn(f' distance {global_distance}', frrconfig)
+ self.assertIn(f' distance ospf intra-area {intra_area} external {external}', frrconfig)
+ self.assertIn(f' max-metric router-lsa on-startup {on_startup}', frrconfig)
+ self.assertIn(f' max-metric router-lsa on-shutdown {on_shutdown}', frrconfig)
+ self.assertIn(f' refresh timer {refresh}', frrconfig)
+
+
+ # enable inter-area
+ self.cli_set(base_path + ['distance', 'ospf', 'inter-area', inter_area])
+ self.cli_commit()
+
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f' distance ospf intra-area {intra_area} inter-area {inter_area} external {external}', frrconfig)
+
+
+ def test_ospf_06_neighbor(self):
+ priority = '10'
+ poll_interval = '20'
+ neighbors = ['1.1.1.1', '2.2.2.2', '3.3.3.3']
+ for neighbor in neighbors:
+ self.cli_set(base_path + ['neighbor', neighbor, 'priority', priority])
+ self.cli_set(base_path + ['neighbor', neighbor, 'poll-interval', poll_interval])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ for neighbor in neighbors:
+ self.assertIn(f' neighbor {neighbor} priority {priority} poll-interval {poll_interval}', frrconfig) # default
+
+
+ def test_ospf_07_passive_interface(self):
+ self.cli_set(base_path + ['passive-interface', 'default'])
+ interfaces = Section.interfaces('ethernet')
+ for interface in interfaces:
+ self.cli_set(base_path + ['passive-interface-exclude', interface])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' passive-interface default', frrconfig) # default
+ for interface in interfaces:
+ self.assertIn(f' no passive-interface {interface}', frrconfig) # default
+
+
+ def test_ospf_08_redistribute(self):
+ metric = '15'
+ metric_type = '1'
+ redistribute = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static']
+
+ for protocol in redistribute:
+ self.cli_set(base_path + ['redistribute', protocol, 'metric', metric])
+ self.cli_set(base_path + ['redistribute', protocol, 'route-map', route_map])
+ if protocol not in ['kernel', 'static']:
+ self.cli_set(base_path + ['redistribute', protocol, 'metric-type', metric_type])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ for protocol in redistribute:
+ if protocol in ['kernel', 'static']:
+ self.assertIn(f' redistribute {protocol} metric {metric} route-map {route_map}', frrconfig)
+ else:
+ self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
+
+
+ def test_ospf_09_virtual_link(self):
+ networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
+ area = '10'
+ shortcut = 'enable'
+ virtual_link = '192.0.2.1'
+ hello = '6'
+ retransmit = '5'
+ transmit = '5'
+ dead = '40'
+
+ self.cli_set(base_path + ['area', area, 'shortcut', shortcut])
+ self.cli_set(base_path + ['area', area, 'virtual-link', virtual_link, 'hello-interval', hello])
+ self.cli_set(base_path + ['area', area, 'virtual-link', virtual_link, 'retransmit-interval', retransmit])
+ self.cli_set(base_path + ['area', area, 'virtual-link', virtual_link, 'transmit-delay', transmit])
+ self.cli_set(base_path + ['area', area, 'virtual-link', virtual_link, 'dead-interval', dead])
+ for network in networks:
+ self.cli_set(base_path + ['area', area, 'network', network])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' area {area} shortcut {shortcut}', frrconfig)
+ self.assertIn(f' area {area} virtual-link {virtual_link} hello-interval {hello} retransmit-interval {retransmit} transmit-delay {transmit} dead-interval {dead}', frrconfig)
+ for network in networks:
+ self.assertIn(f' network {network} area {area}', frrconfig)
+
+
+ def test_ospf_10_interface_configureation(self):
+ interfaces = Section.interfaces('ethernet')
+ password = 'vyos1234'
+ bandwidth = '10000'
+ cost = '150'
+ network = 'point-to-point'
+ priority = '200'
+
+ for interface in interfaces:
+ self.cli_set(base_path + ['interface', interface, 'authentication', 'plaintext-password', password])
+ self.cli_set(base_path + ['interface', interface, 'bandwidth', bandwidth])
+ self.cli_set(base_path + ['interface', interface, 'bfd'])
+ self.cli_set(base_path + ['interface', interface, 'cost', cost])
+ self.cli_set(base_path + ['interface', interface, 'mtu-ignore'])
+ self.cli_set(base_path + ['interface', interface, 'network', network])
+ self.cli_set(base_path + ['interface', interface, 'priority', priority])
+
+ # commit changes
+ self.cli_commit()
+
+ for interface in interfaces:
+ config = self.getFRRconfig(f'interface {interface}')
+ self.assertIn(f'interface {interface}', config)
+ self.assertIn(f' ip ospf authentication-key {password}', config)
+ self.assertIn(f' ip ospf bfd', config)
+ self.assertIn(f' ip ospf cost {cost}', config)
+ self.assertIn(f' ip ospf mtu-ignore', config)
+ self.assertIn(f' ip ospf network {network}', config)
+ self.assertIn(f' ip ospf priority {priority}', config)
+ self.assertIn(f' bandwidth {bandwidth}', config)
+
+
+ def test_ospf_11_vrfs(self):
+ # It is safe to assume that when the basic VRF test works, all
+ # other OSPF related features work, as we entirely inherit the CLI
+ # templates and Jinja2 FRR template.
+ table = '1000'
+ vrf = 'blue'
+ vrf_base = ['vrf', 'name', vrf]
+ vrf_iface = 'eth1'
+ self.cli_set(vrf_base + ['table', table])
+ self.cli_set(vrf_base + ['protocols', 'ospf', 'interface', vrf_iface])
+ self.cli_set(['interfaces', 'ethernet', vrf_iface, 'vrf', vrf])
+
+ # Also set a default VRF OSPF config
+ self.cli_set(base_path)
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
+ self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
+
+ frrconfig = self.getFRRconfig(f'router ospf vrf {vrf}')
+ self.assertIn(f'router ospf vrf {vrf}', frrconfig)
+ self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
+ self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
+
+ self.cli_delete(['vrf', 'name', vrf])
+ self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf'])
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py
new file mode 100755
index 000000000..6bb551642
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_ospfv3.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.ifconfig import Section
+from vyos.util import process_named_running
+
+PROCESS_NAME = 'ospf6d'
+base_path = ['protocols', 'ospfv3']
+
+router_id = '192.0.2.1'
+default_area = '0'
+
+class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_ospfv3_01_basic(self):
+ seq = '10'
+ prefix = '2001:db8::/32'
+ acl_name = 'foo-acl-100'
+
+ self.cli_set(['policy', 'access-list6', acl_name, 'rule', seq, 'action', 'permit'])
+ self.cli_set(['policy', 'access-list6', acl_name, 'rule', seq, 'source', 'any'])
+
+ self.cli_set(base_path + ['parameters', 'router-id', router_id])
+ self.cli_set(base_path + ['area', default_area, 'range', prefix, 'advertise'])
+ self.cli_set(base_path + ['area', default_area, 'export-list', acl_name])
+ self.cli_set(base_path + ['area', default_area, 'import-list', acl_name])
+
+ interfaces = Section.interfaces('ethernet')
+ for interface in interfaces:
+ self.cli_set(base_path + ['area', default_area, 'interface', interface])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf6')
+ self.assertIn(f'router ospf6', frrconfig)
+ self.assertIn(f' area {default_area} range {prefix}', frrconfig)
+ self.assertIn(f' ospf6 router-id {router_id}', frrconfig)
+ self.assertIn(f' area {default_area} import-list {acl_name}', frrconfig)
+ self.assertIn(f' area {default_area} export-list {acl_name}', frrconfig)
+
+ for interface in interfaces:
+ self.assertIn(f' interface {interface} area {default_area}', frrconfig)
+
+ self.cli_delete(['policy', 'access-list6', acl_name])
+
+
+ def test_ospfv3_02_distance(self):
+ dist_global = '200'
+ dist_external = '110'
+ dist_inter_area = '120'
+ dist_intra_area = '130'
+
+ self.cli_set(base_path + ['distance', 'global', dist_global])
+ self.cli_set(base_path + ['distance', 'ospfv3', 'external', dist_external])
+ self.cli_set(base_path + ['distance', 'ospfv3', 'inter-area', dist_inter_area])
+ self.cli_set(base_path + ['distance', 'ospfv3', 'intra-area', dist_intra_area])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf6')
+ self.assertIn(f'router ospf6', frrconfig)
+ self.assertIn(f' distance {dist_global}', frrconfig)
+ self.assertIn(f' distance ospf6 intra-area {dist_intra_area} inter-area {dist_inter_area} external {dist_external}', frrconfig)
+
+
+ def test_ospfv3_03_redistribute(self):
+ route_map = 'foo-bar'
+ route_map_seq = '10'
+ redistribute = ['bgp', 'connected', 'kernel', 'ripng', 'static']
+
+ self.cli_set(['policy', 'route-map', route_map, 'rule', route_map_seq, 'action', 'permit'])
+
+ for protocol in redistribute:
+ self.cli_set(base_path + ['redistribute', protocol, 'route-map', route_map])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf6')
+ self.assertIn(f'router ospf6', frrconfig)
+ for protocol in redistribute:
+ self.assertIn(f' redistribute {protocol} route-map {route_map}', frrconfig)
+
+ def test_ospfv3_04_interfaces(self):
+
+ self.cli_set(base_path + ['parameters', 'router-id', router_id])
+ self.cli_set(base_path + ['area', default_area])
+
+ cost = '100'
+ priority = '10'
+ interfaces = Section.interfaces('ethernet')
+ for interface in interfaces:
+ if_base = base_path + ['interface', interface]
+ self.cli_set(if_base + ['bfd'])
+ self.cli_set(if_base + ['cost', cost])
+ self.cli_set(if_base + ['instance-id', '0'])
+ self.cli_set(if_base + ['mtu-ignore'])
+ self.cli_set(if_base + ['network', 'point-to-point'])
+ self.cli_set(if_base + ['passive'])
+ self.cli_set(if_base + ['priority', priority])
+ cost = str(int(cost) + 10)
+ priority = str(int(priority) + 5)
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf6')
+ self.assertIn(f'router ospf6', frrconfig)
+
+ cost = '100'
+ priority = '10'
+ for interface in interfaces:
+ if_config = self.getFRRconfig(f'interface {interface}')
+ self.assertIn(f'interface {interface}', if_config)
+ self.assertIn(f' ipv6 ospf6 bfd', if_config)
+ self.assertIn(f' ipv6 ospf6 cost {cost}', if_config)
+ self.assertIn(f' ipv6 ospf6 mtu-ignore', if_config)
+ self.assertIn(f' ipv6 ospf6 network point-to-point', if_config)
+ self.assertIn(f' ipv6 ospf6 passive', if_config)
+ self.assertIn(f' ipv6 ospf6 priority {priority}', if_config)
+ cost = str(int(cost) + 10)
+ priority = str(int(priority) + 5)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_rip.py b/smoketest/scripts/cli/test_protocols_rip.py
new file mode 100755
index 000000000..3406688c5
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_rip.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.ifconfig import Section
+from vyos.util import process_named_running
+
+PROCESS_NAME = 'ripd'
+acl_in = '198'
+acl_out = '199'
+prefix_list_in = 'foo-prefix'
+prefix_list_out = 'bar-prefix'
+route_map = 'FooBar123'
+
+base_path = ['protocols', 'rip']
+
+class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase):
+ def setUp(self):
+ self.cli_set(['policy', 'access-list', acl_in, 'rule', '10', 'action', 'permit'])
+ self.cli_set(['policy', 'access-list', acl_in, 'rule', '10', 'source', 'any'])
+ self.cli_set(['policy', 'access-list', acl_in, 'rule', '10', 'destination', 'any'])
+ self.cli_set(['policy', 'access-list', acl_out, 'rule', '20', 'action', 'deny'])
+ self.cli_set(['policy', 'access-list', acl_out, 'rule', '20', 'source', 'any'])
+ self.cli_set(['policy', 'access-list', acl_out, 'rule', '20', 'destination', 'any'])
+ self.cli_set(['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'action', 'permit'])
+ self.cli_set(['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'prefix', '192.0.2.0/24'])
+ self.cli_set(['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'action', 'deny'])
+ self.cli_set(['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'prefix', '192.0.2.0/24'])
+ self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
+
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_delete(['policy', 'access-list', acl_in])
+ self.cli_delete(['policy', 'access-list', acl_out])
+ self.cli_delete(['policy', 'prefix-list', prefix_list_in])
+ self.cli_delete(['policy', 'prefix-list', prefix_list_out])
+ self.cli_delete(['policy', 'route-map', route_map])
+ self.cli_commit()
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
+ def test_rip(self):
+ distance = '40'
+ network_distance = '66'
+ metric = '8'
+ interfaces = Section.interfaces('ethernet')
+ neighbors = ['1.2.3.4', '1.2.3.5', '1.2.3.6']
+ networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
+ redistribute = ['bgp', 'connected', 'isis', 'kernel', 'ospf', 'static']
+ timer_garbage = '888'
+ timer_timeout = '1000'
+ timer_update = '90'
+
+ self.cli_set(base_path + ['default-distance', distance])
+ self.cli_set(base_path + ['default-information', 'originate'])
+ self.cli_set(base_path + ['default-metric', metric])
+ self.cli_set(base_path + ['distribute-list', 'access-list', 'in', acl_in])
+ self.cli_set(base_path + ['distribute-list', 'access-list', 'out', acl_out])
+ self.cli_set(base_path + ['distribute-list', 'prefix-list', 'in', prefix_list_in])
+ self.cli_set(base_path + ['distribute-list', 'prefix-list', 'out', prefix_list_out])
+ self.cli_set(base_path + ['passive-interface', 'default'])
+ self.cli_set(base_path + ['timers', 'garbage-collection', timer_garbage])
+ self.cli_set(base_path + ['timers', 'timeout', timer_timeout])
+ self.cli_set(base_path + ['timers', 'update', timer_update])
+ for interface in interfaces:
+ self.cli_set(base_path + ['interface', interface])
+ self.cli_set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'in', acl_in])
+ self.cli_set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'out', acl_out])
+ self.cli_set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'in', prefix_list_in])
+ self.cli_set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'out', prefix_list_out])
+ for neighbor in neighbors:
+ self.cli_set(base_path + ['neighbor', neighbor])
+ for network in networks:
+ self.cli_set(base_path + ['network', network])
+ self.cli_set(base_path + ['network-distance', network, 'distance', network_distance])
+ self.cli_set(base_path + ['route', network])
+ for proto in redistribute:
+ self.cli_set(base_path + ['redistribute', proto, 'metric', metric])
+ self.cli_set(base_path + ['redistribute', proto, 'route-map', route_map])
+
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router rip')
+ self.assertIn(f'router rip', frrconfig)
+ self.assertIn(f' distance {distance}', frrconfig)
+ self.assertIn(f' default-information originate', frrconfig)
+ self.assertIn(f' default-metric {metric}', frrconfig)
+ self.assertIn(f' distribute-list {acl_in} in', frrconfig)
+ self.assertIn(f' distribute-list {acl_out} out', frrconfig)
+ self.assertIn(f' distribute-list prefix {prefix_list_in} in', frrconfig)
+ self.assertIn(f' distribute-list prefix {prefix_list_out} out', frrconfig)
+ self.assertIn(f' passive-interface default', frrconfig)
+ self.assertIn(f' timers basic {timer_update} {timer_timeout} {timer_garbage}', frrconfig)
+ for interface in interfaces:
+ self.assertIn(f' network {interface}', frrconfig)
+ self.assertIn(f' distribute-list {acl_in} in {interface}', frrconfig)
+ self.assertIn(f' distribute-list {acl_out} out {interface}', frrconfig)
+ self.assertIn(f' distribute-list prefix {prefix_list_in} in {interface}', frrconfig)
+ self.assertIn(f' distribute-list prefix {prefix_list_out} out {interface}', frrconfig)
+ for neighbor in neighbors:
+ self.assertIn(f' neighbor {neighbor}', frrconfig)
+ for network in networks:
+ self.assertIn(f' network {network}', frrconfig)
+ self.assertIn(f' distance {network_distance} {network}', frrconfig)
+ self.assertIn(f' route {network}', frrconfig)
+ for proto in redistribute:
+ self.assertIn(f' redistribute {proto} metric {metric} route-map {route_map}', frrconfig)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py
new file mode 100755
index 000000000..add92b73d
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_ripng.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.ifconfig import Section
+from vyos.util import process_named_running
+
+PROCESS_NAME = 'ripngd'
+acl_in = '198'
+acl_out = '199'
+prefix_list_in = 'foo-prefix'
+prefix_list_out = 'bar-prefix'
+route_map = 'FooBar123'
+
+base_path = ['protocols', 'ripng']
+
+class TestProtocolsRIPng(VyOSUnitTestSHIM.TestCase):
+ def setUp(self):
+ self.cli_set(['policy', 'access-list6', acl_in, 'rule', '10', 'action', 'permit'])
+ self.cli_set(['policy', 'access-list6', acl_in, 'rule', '10', 'source', 'any'])
+ self.cli_set(['policy', 'access-list6', acl_out, 'rule', '20', 'action', 'deny'])
+ self.cli_set(['policy', 'access-list6', acl_out, 'rule', '20', 'source', 'any'])
+ self.cli_set(['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'action', 'permit'])
+ self.cli_set(['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'prefix', '2001:db8::/32'])
+ self.cli_set(['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'action', 'deny'])
+ self.cli_set(['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'prefix', '2001:db8::/32'])
+ self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
+
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_delete(['policy', 'access-list6', acl_in])
+ self.cli_delete(['policy', 'access-list6', acl_out])
+ self.cli_delete(['policy', 'prefix-list6', prefix_list_in])
+ self.cli_delete(['policy', 'prefix-list6', prefix_list_out])
+ self.cli_delete(['policy', 'route-map', route_map])
+ self.cli_commit()
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
+ def test_ripng(self):
+ metric = '8'
+ interfaces = Section.interfaces('ethernet')
+ aggregates = ['2001:db8:1000::/48', '2001:db8:2000::/48', '2001:db8:3000::/48']
+ networks = ['2001:db8:1000::/64', '2001:db8:1001::/64', '2001:db8:2000::/64', '2001:db8:2001::/64']
+ redistribute = ['bgp', 'connected', 'kernel', 'ospfv3', 'static']
+ timer_garbage = '888'
+ timer_timeout = '1000'
+ timer_update = '90'
+
+ self.cli_set(base_path + ['default-information', 'originate'])
+ self.cli_set(base_path + ['default-metric', metric])
+ self.cli_set(base_path + ['distribute-list', 'access-list', 'in', acl_in])
+ self.cli_set(base_path + ['distribute-list', 'access-list', 'out', acl_out])
+ self.cli_set(base_path + ['distribute-list', 'prefix-list', 'in', prefix_list_in])
+ self.cli_set(base_path + ['distribute-list', 'prefix-list', 'out', prefix_list_out])
+ self.cli_set(base_path + ['passive-interface', 'default'])
+ self.cli_set(base_path + ['timers', 'garbage-collection', timer_garbage])
+ self.cli_set(base_path + ['timers', 'timeout', timer_timeout])
+ self.cli_set(base_path + ['timers', 'update', timer_update])
+ for aggregate in aggregates:
+ self.cli_set(base_path + ['aggregate-address', aggregate])
+
+ for interface in interfaces:
+ self.cli_set(base_path + ['interface', interface])
+ self.cli_set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'in', acl_in])
+ self.cli_set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'out', acl_out])
+ self.cli_set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'in', prefix_list_in])
+ self.cli_set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'out', prefix_list_out])
+ for network in networks:
+ self.cli_set(base_path + ['network', network])
+ self.cli_set(base_path + ['route', network])
+ for proto in redistribute:
+ self.cli_set(base_path + ['redistribute', proto, 'metric', metric])
+ self.cli_set(base_path + ['redistribute', proto, 'route-map', route_map])
+
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ripng')
+ self.assertIn(f'router ripng', frrconfig)
+ self.assertIn(f' default-information originate', frrconfig)
+ self.assertIn(f' default-metric {metric}', frrconfig)
+ self.assertIn(f' ipv6 distribute-list {acl_in} in', frrconfig)
+ self.assertIn(f' ipv6 distribute-list {acl_out} out', frrconfig)
+ self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in} in', frrconfig)
+ self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out} out', frrconfig)
+ self.assertIn(f' passive-interface default', frrconfig)
+ self.assertIn(f' timers basic {timer_update} {timer_timeout} {timer_garbage}', frrconfig)
+ for aggregate in aggregates:
+ self.assertIn(f' aggregate-address {aggregate}', frrconfig)
+ for interface in interfaces:
+ self.assertIn(f' network {interface}', frrconfig)
+ self.assertIn(f' ipv6 distribute-list {acl_in} in {interface}', frrconfig)
+ self.assertIn(f' ipv6 distribute-list {acl_out} out {interface}', frrconfig)
+ self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in} in {interface}', frrconfig)
+ self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out} out {interface}', frrconfig)
+ for network in networks:
+ self.assertIn(f' network {network}', frrconfig)
+ self.assertIn(f' route {network}', frrconfig)
+ for proto in redistribute:
+ if proto == 'ospfv3':
+ proto = 'ospf6'
+ self.assertIn(f' redistribute {proto} metric {metric} route-map {route_map}', frrconfig)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py
new file mode 100755
index 000000000..8212e9469
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_rpki.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+from vyos.util import cmd
+from vyos.util import process_named_running
+
+base_path = ['protocols', 'rpki']
+PROCESS_NAME = 'bgpd'
+
+rpki_known_hosts = '/config/auth/known_hosts'
+rpki_ssh_key = '/config/auth/id_rsa_rpki'
+rpki_ssh_pub = f'{rpki_ssh_key}.pub'
+
+class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ # Nothing RPKI specific should be left over in the config
+ #
+ # Disabled until T3266 is resolved
+ # frrconfig = self.getFRRconfig('rpki')
+ # self.assertNotIn('rpki', frrconfig)
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
+ def test_rpki(self):
+ polling = '7200'
+ cache = {
+ '192.0.2.1' : {
+ 'port' : '8080',
+ 'preference' : '1'
+ },
+ '192.0.2.2' : {
+ 'port' : '9090',
+ 'preference' : '2'
+ },
+ '2001:db8::1' : {
+ 'port' : '1234',
+ 'preference' : '3'
+ },
+ '2001:db8::2' : {
+ 'port' : '5678',
+ 'preference' : '4'
+ },
+ }
+
+ self.cli_set(base_path + ['polling-period', polling])
+ for peer, peer_config in cache.items():
+ self.cli_set(base_path + ['cache', peer, 'port', peer_config['port']])
+ self.cli_set(base_path + ['cache', peer, 'preference', peer_config['preference']])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR configuration
+ frrconfig = self.getFRRconfig('rpki')
+ self.assertIn(f'rpki polling_period {polling}', frrconfig)
+
+ for peer, peer_config in cache.items():
+ port = peer_config['port']
+ preference = peer_config['preference']
+ self.assertIn(f'rpki cache {peer} {port} preference {preference}', frrconfig)
+
+ def test_rpki_ssh(self):
+ polling = '7200'
+ cache = {
+ '192.0.2.3' : {
+ 'port' : '1234',
+ 'username' : 'foo',
+ 'preference' : '10'
+ },
+ '192.0.2.4' : {
+ 'port' : '5678',
+ 'username' : 'bar',
+ 'preference' : '20'
+ },
+ }
+
+ self.cli_set(base_path + ['polling-period', polling])
+
+ for peer, peer_config in cache.items():
+ self.cli_set(base_path + ['cache', peer, 'port', peer_config['port']])
+ self.cli_set(base_path + ['cache', peer, 'preference', peer_config['preference']])
+ self.cli_set(base_path + ['cache', peer, 'ssh', 'username', peer_config['username']])
+ self.cli_set(base_path + ['cache', peer, 'ssh', 'public-key-file', rpki_ssh_pub])
+ self.cli_set(base_path + ['cache', peer, 'ssh', 'private-key-file', rpki_ssh_key])
+ self.cli_set(base_path + ['cache', peer, 'ssh', 'known-hosts-file', rpki_known_hosts])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR configuration
+ frrconfig = self.getFRRconfig('rpki')
+ self.assertIn(f'rpki polling_period {polling}', frrconfig)
+
+ for peer, peer_config in cache.items():
+ port = peer_config['port']
+ preference = peer_config['preference']
+ username = peer_config['username']
+ self.assertIn(f'rpki cache {peer} {port} {username} {rpki_ssh_key} {rpki_known_hosts} preference {preference}', frrconfig)
+
+
+ def test_rpki_verify_preference(self):
+ cache = {
+ '192.0.2.1' : {
+ 'port' : '8080',
+ 'preference' : '1'
+ },
+ '192.0.2.2' : {
+ 'port' : '9090',
+ 'preference' : '1'
+ },
+ }
+
+ for peer, peer_config in cache.items():
+ self.cli_set(base_path + ['cache', peer, 'port', peer_config['port']])
+ self.cli_set(base_path + ['cache', peer, 'preference', peer_config['preference']])
+
+ # check validate() - preferences must be unique
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+
+if __name__ == '__main__':
+ # Create OpenSSH keypair used in RPKI tests
+ if not os.path.isfile(rpki_ssh_key):
+ cmd(f'ssh-keygen -t rsa -f {rpki_ssh_key} -N ""')
+
+ if not os.path.isfile(rpki_known_hosts):
+ cmd(f'touch {rpki_known_hosts}')
+
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
new file mode 100755
index 000000000..75d3e6a42
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_static.py
@@ -0,0 +1,396 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+from vyos.template import is_ipv6
+from vyos.util import get_interface_config
+
+base_path = ['protocols', 'static']
+vrf_path = ['protocols', 'vrf']
+
+routes = {
+ '10.0.0.0/8' : {
+ 'next_hop' : {
+ '192.0.2.100' : { 'distance' : '100' },
+ '192.0.2.110' : { 'distance' : '110', 'interface' : 'eth0' },
+ '192.0.2.120' : { 'distance' : '120', 'disable' : '' },
+ },
+ 'interface' : {
+ 'eth0' : { 'distance' : '130' },
+ 'eth1' : { 'distance' : '140' },
+ },
+ 'blackhole' : { 'distance' : '250', 'tag' : '500' },
+ },
+ '172.16.0.0/12' : {
+ 'interface' : {
+ 'eth0' : { 'distance' : '50', 'vrf' : 'black' },
+ 'eth1' : { 'distance' : '60', 'vrf' : 'black' },
+ },
+ 'blackhole' : { 'distance' : '90' },
+ },
+ '192.0.2.0/24' : {
+ 'interface' : {
+ 'eth0' : { 'distance' : '50', 'vrf' : 'black' },
+ 'eth1' : { 'disable' : '' },
+ },
+ 'blackhole' : { 'distance' : '90' },
+ },
+ '100.64.0.0/10' : {
+ 'blackhole' : { },
+ },
+ '2001:db8:100::/40' : {
+ 'next_hop' : {
+ '2001:db8::1' : { 'distance' : '10' },
+ '2001:db8::2' : { 'distance' : '20', 'interface' : 'eth0' },
+ '2001:db8::3' : { 'distance' : '30', 'disable' : '' },
+ },
+ 'interface' : {
+ 'eth0' : { 'distance' : '40', 'vrf' : 'black' },
+ 'eth1' : { 'distance' : '50', 'disable' : '' },
+ },
+ 'blackhole' : { 'distance' : '250', 'tag' : '500' },
+ },
+ '2001:db8:200::/40' : {
+ 'interface' : {
+ 'eth0' : { 'distance' : '40' },
+ 'eth1' : { 'distance' : '50', 'disable' : '' },
+ },
+ 'blackhole' : { 'distance' : '250', 'tag' : '500' },
+ },
+ '2001:db8::/32' : {
+ 'blackhole' : { 'distance' : '200', 'tag' : '600' },
+ },
+}
+
+tables = ['80', '81', '82']
+
+class StaticRouteTest(VyOSUnitTestSHIM.TestCase):
+ def setUp(self):
+ # This is our "target" VRF when leaking routes:
+ self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
+
+ def tearDown(self):
+ for route, route_config in routes.items():
+ route_type = 'route'
+ if is_ipv6(route):
+ route_type = 'route6'
+ self.cli_delete(base_path + [route_type, route])
+
+ for table in tables:
+ self.cli_delete(base_path + ['table', table])
+
+ tmp = self.getFRRconfig('', end='')
+ self.cli_commit()
+
+ def test_protocols_static(self):
+ for route, route_config in routes.items():
+ route_type = 'route'
+ if is_ipv6(route):
+ route_type = 'route6'
+ base = base_path + [route_type, route]
+ if 'next_hop' in route_config:
+ for next_hop, next_hop_config in route_config['next_hop'].items():
+ self.cli_set(base + ['next-hop', next_hop])
+ if 'disable' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'disable'])
+ if 'distance' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
+ if 'interface' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
+ if 'vrf' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
+
+
+ if 'interface' in route_config:
+ for interface, interface_config in route_config['interface'].items():
+ self.cli_set(base + ['interface', interface])
+ if 'disable' in interface_config:
+ self.cli_set(base + ['interface', interface, 'disable'])
+ if 'distance' in interface_config:
+ self.cli_set(base + ['interface', interface, 'distance', interface_config['distance']])
+ if 'vrf' in interface_config:
+ self.cli_set(base + ['interface', interface, 'vrf', interface_config['vrf']])
+
+ if 'blackhole' in route_config:
+ self.cli_set(base + ['blackhole'])
+ if 'distance' in route_config['blackhole']:
+ self.cli_set(base + ['blackhole', 'distance', route_config['blackhole']['distance']])
+ if 'tag' in route_config['blackhole']:
+ self.cli_set(base + ['blackhole', 'tag', route_config['blackhole']['tag']])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR bgpd configuration
+ frrconfig = self.getFRRconfig('ip route', end='')
+
+ # Verify routes
+ for route, route_config in routes.items():
+ ip_ipv6 = 'ip'
+ if is_ipv6(route):
+ ip_ipv6 = 'ipv6'
+
+ if 'next_hop' in route_config:
+ for next_hop, next_hop_config in route_config['next_hop'].items():
+ tmp = f'{ip_ipv6} route {route} {next_hop}'
+ if 'interface' in next_hop_config:
+ tmp += ' ' + next_hop_config['interface']
+ if 'distance' in next_hop_config:
+ tmp += ' ' + next_hop_config['distance']
+ if 'vrf' in next_hop_config:
+ tmp += ' nexthop-vrf ' + next_hop_config['vrf']
+
+ if 'disable' in next_hop_config:
+ self.assertNotIn(tmp, frrconfig)
+ else:
+ self.assertIn(tmp, frrconfig)
+
+ if 'interface' in route_config:
+ for interface, interface_config in route_config['interface'].items():
+ tmp = f'{ip_ipv6} route {route} {interface}'
+ if 'interface' in interface_config:
+ tmp += ' ' + interface_config['interface']
+ if 'distance' in interface_config:
+ tmp += ' ' + interface_config['distance']
+ if 'vrf' in interface_config:
+ tmp += ' nexthop-vrf ' + interface_config['vrf']
+
+ if 'disable' in interface_config:
+ self.assertNotIn(tmp, frrconfig)
+ else:
+ self.assertIn(tmp, frrconfig)
+
+ if 'blackhole' in route_config:
+ tmp = f'{ip_ipv6} route {route} blackhole'
+ if 'tag' in route_config['blackhole']:
+ tmp += ' tag ' + route_config['blackhole']['tag']
+ if 'distance' in route_config['blackhole']:
+ tmp += ' ' + route_config['blackhole']['distance']
+
+ self.assertIn(tmp, frrconfig)
+
+ def test_protocols_static_table(self):
+ for table in tables:
+ for route, route_config in routes.items():
+ route_type = 'route'
+ if is_ipv6(route):
+ route_type = 'route6'
+ base = base_path + ['table', table, route_type, route]
+
+ if 'next_hop' in route_config:
+ for next_hop, next_hop_config in route_config['next_hop'].items():
+ self.cli_set(base + ['next-hop', next_hop])
+ if 'disable' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'disable'])
+ if 'distance' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
+ if 'interface' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
+ if 'vrf' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
+
+
+ if 'interface' in route_config:
+ for interface, interface_config in route_config['interface'].items():
+ self.cli_set(base + ['interface', interface])
+ if 'disable' in interface_config:
+ self.cli_set(base + ['interface', interface, 'disable'])
+ if 'distance' in interface_config:
+ self.cli_set(base + ['interface', interface, 'distance', interface_config['distance']])
+ if 'vrf' in interface_config:
+ self.cli_set(base + ['interface', interface, 'vrf', interface_config['vrf']])
+
+ if 'blackhole' in route_config:
+ self.cli_set(base + ['blackhole'])
+ if 'distance' in route_config['blackhole']:
+ self.cli_set(base + ['blackhole', 'distance', route_config['blackhole']['distance']])
+ if 'tag' in route_config['blackhole']:
+ self.cli_set(base + ['blackhole', 'tag', route_config['blackhole']['tag']])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify FRR bgpd configuration
+ frrconfig = self.getFRRconfig('ip route', end='')
+
+ for table in tables:
+ # Verify routes
+ for route, route_config in routes.items():
+ ip_ipv6 = 'ip'
+ if is_ipv6(route):
+ ip_ipv6 = 'ipv6'
+
+ if 'next_hop' in route_config:
+ for next_hop, next_hop_config in route_config['next_hop'].items():
+ tmp = f'{ip_ipv6} route {route} {next_hop}'
+ if 'interface' in next_hop_config:
+ tmp += ' ' + next_hop_config['interface']
+ if 'distance' in next_hop_config:
+ tmp += ' ' + next_hop_config['distance']
+ if 'vrf' in next_hop_config:
+ tmp += ' nexthop-vrf ' + next_hop_config['vrf']
+
+ tmp += ' table ' + table
+ if 'disable' in next_hop_config:
+ self.assertNotIn(tmp, frrconfig)
+ else:
+ self.assertIn(tmp, frrconfig)
+
+ if 'interface' in route_config:
+ for interface, interface_config in route_config['interface'].items():
+ tmp = f'{ip_ipv6} route {route} {interface}'
+ if 'interface' in interface_config:
+ tmp += ' ' + interface_config['interface']
+ if 'distance' in interface_config:
+ tmp += ' ' + interface_config['distance']
+ if 'vrf' in interface_config:
+ tmp += ' nexthop-vrf ' + interface_config['vrf']
+
+ tmp += ' table ' + table
+ if 'disable' in interface_config:
+ self.assertNotIn(tmp, frrconfig)
+ else:
+ self.assertIn(tmp, frrconfig)
+
+ if 'blackhole' in route_config:
+ tmp = f'{ip_ipv6} route {route} blackhole'
+ if 'tag' in route_config['blackhole']:
+ tmp += ' tag ' + route_config['blackhole']['tag']
+ if 'distance' in route_config['blackhole']:
+ tmp += ' ' + route_config['blackhole']['distance']
+
+ tmp += ' table ' + table
+ self.assertIn(tmp, frrconfig)
+
+
+ def test_protocols_vrf_static(self):
+ # Create VRF instances and apply the static routes from above to FRR.
+ # Re-read the configured routes and match them if they are programmed
+ # properly. This also includes VRF leaking
+ vrfs = {
+ 'red' : { 'table' : '1000' },
+ 'green' : { 'table' : '2000' },
+ 'blue' : { 'table' : '3000' },
+ }
+
+ for vrf, vrf_config in vrfs.items():
+ vrf_base_path = ['vrf', 'name', vrf]
+ self.cli_set(vrf_base_path + ['table', vrf_config['table']])
+
+ for route, route_config in routes.items():
+ route_type = 'route'
+ if is_ipv6(route):
+ route_type = 'route6'
+ route_base_path = vrf_base_path + ['protocols', 'static', route_type, route]
+
+ if 'next_hop' in route_config:
+ for next_hop, next_hop_config in route_config['next_hop'].items():
+ self.cli_set(route_base_path + ['next-hop', next_hop])
+ if 'disable' in next_hop_config:
+ self.cli_set(route_base_path + ['next-hop', next_hop, 'disable'])
+ if 'distance' in next_hop_config:
+ self.cli_set(route_base_path + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
+ if 'interface' in next_hop_config:
+ self.cli_set(route_base_path + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
+ if 'vrf' in next_hop_config:
+ self.cli_set(route_base_path + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
+
+
+ if 'interface' in route_config:
+ for interface, interface_config in route_config['interface'].items():
+ self.cli_set(route_base_path + ['interface', interface])
+ if 'disable' in interface_config:
+ self.cli_set(route_base_path + ['interface', interface, 'disable'])
+ if 'distance' in interface_config:
+ self.cli_set(route_base_path + ['interface', interface, 'distance', interface_config['distance']])
+ if 'vrf' in interface_config:
+ self.cli_set(route_base_path + ['interface', interface, 'vrf', interface_config['vrf']])
+
+ if 'blackhole' in route_config:
+ self.cli_set(route_base_path + ['blackhole'])
+ if 'distance' in route_config['blackhole']:
+ self.cli_set(route_base_path + ['blackhole', 'distance', route_config['blackhole']['distance']])
+ if 'tag' in route_config['blackhole']:
+ self.cli_set(route_base_path + ['blackhole', 'tag', route_config['blackhole']['tag']])
+
+ # commit changes
+ self.cli_commit()
+
+ for vrf, vrf_config in vrfs.items():
+ tmp = get_interface_config(vrf)
+
+ # Compare VRF table ID
+ self.assertEqual(tmp['linkinfo']['info_data']['table'], int(vrf_config['table']))
+ self.assertEqual(tmp['linkinfo']['info_kind'], 'vrf')
+
+ # Verify FRR bgpd configuration
+ frrconfig = self.getFRRconfig(f'vrf {vrf}')
+ self.assertIn(f'vrf {vrf}', frrconfig)
+
+ # Verify routes
+ for route, route_config in routes.items():
+ ip_ipv6 = 'ip'
+ if is_ipv6(route):
+ ip_ipv6 = 'ipv6'
+
+ if 'next_hop' in route_config:
+ for next_hop, next_hop_config in route_config['next_hop'].items():
+ tmp = f'{ip_ipv6} route {route} {next_hop}'
+ if 'interface' in next_hop_config:
+ tmp += ' ' + next_hop_config['interface']
+ if 'distance' in next_hop_config:
+ tmp += ' ' + next_hop_config['distance']
+ if 'vrf' in next_hop_config:
+ tmp += ' nexthop-vrf ' + next_hop_config['vrf']
+
+ if 'disable' in next_hop_config:
+ self.assertNotIn(tmp, frrconfig)
+ else:
+ self.assertIn(tmp, frrconfig)
+
+ if 'interface' in route_config:
+ for interface, interface_config in route_config['interface'].items():
+ tmp = f'{ip_ipv6} route {route} {interface}'
+ if 'interface' in interface_config:
+ tmp += ' ' + interface_config['interface']
+ if 'distance' in interface_config:
+ tmp += ' ' + interface_config['distance']
+ if 'vrf' in interface_config:
+ tmp += ' nexthop-vrf ' + interface_config['vrf']
+
+ if 'disable' in interface_config:
+ self.assertNotIn(tmp, frrconfig)
+ else:
+ self.assertIn(tmp, frrconfig)
+
+ if 'blackhole' in route_config:
+ tmp = f'{ip_ipv6} route {route} blackhole'
+ if 'tag' in route_config['blackhole']:
+ tmp += ' tag ' + route_config['blackhole']['tag']
+ if 'distance' in route_config['blackhole']:
+ tmp += ' ' + route_config['blackhole']['distance']
+
+ self.assertIn(tmp, frrconfig)
+
+ self.cli_delete(['vrf'])
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_bcast-relay.py b/smoketest/scripts/cli/test_service_bcast-relay.py
index c28509714..58b730ab4 100755
--- a/smoketest/scripts/cli/test_service_bcast-relay.py
+++ b/smoketest/scripts/cli/test_service_bcast-relay.py
@@ -14,47 +14,46 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from psutil import process_iter
-from vyos.configsession import ConfigSession, ConfigSessionError
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
base_path = ['service', 'broadcast-relay']
-class TestServiceBroadcastRelay(unittest.TestCase):
+class TestServiceBroadcastRelay(VyOSUnitTestSHIM.TestCase):
_address1 = '192.0.2.1/24'
_address2 = '192.0.2.1/24'
def setUp(self):
- self.session = ConfigSession(os.getpid())
- self.session.set(['interfaces', 'dummy', 'dum1001', 'address', self._address1])
- self.session.set(['interfaces', 'dummy', 'dum1002', 'address', self._address2])
- self.session.commit()
+ self.cli_set(['interfaces', 'dummy', 'dum1001', 'address', self._address1])
+ self.cli_set(['interfaces', 'dummy', 'dum1002', 'address', self._address2])
def tearDown(self):
- self.session.delete(['interfaces', 'dummy', 'dum1001'])
- self.session.delete(['interfaces', 'dummy', 'dum1002'])
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(['interfaces', 'dummy', 'dum1001'])
+ self.cli_delete(['interfaces', 'dummy', 'dum1002'])
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_broadcast_relay_service(self):
ids = range(1, 5)
for id in ids:
base = base_path + ['id', str(id)]
- self.session.set(base + ['description', 'vyos'])
- self.session.set(base + ['port', str(10000 + id)])
+ self.cli_set(base + ['description', 'vyos'])
+ self.cli_set(base + ['port', str(10000 + id)])
# check validate() - two interfaces must be present
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
- self.session.set(base + ['interface', 'dum1001'])
- self.session.set(base + ['interface', 'dum1002'])
- self.session.set(base + ['address', self._address1.split('/')[0]])
+ self.cli_set(base + ['interface', 'dum1001'])
+ self.cli_set(base + ['interface', 'dum1002'])
+ self.cli_set(base + ['address', self._address1.split('/')[0]])
- self.session.commit()
+ self.cli_commit()
for id in ids:
# check if process is running
diff --git a/smoketest/scripts/cli/test_service_dhcp-relay.py b/smoketest/scripts/cli/test_service_dhcp-relay.py
index 676c4a481..db2edba54 100755
--- a/smoketest/scripts/cli/test_service_dhcp-relay.py
+++ b/smoketest/scripts/cli/test_service_dhcp-relay.py
@@ -14,14 +14,13 @@
# 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 re
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import cmd
from vyos.util import process_named_running
from vyos.util import read_file
@@ -29,14 +28,10 @@ PROCESS_NAME = 'dhcrelay'
RELAY_CONF = '/run/dhcp-relay/dhcrelay.conf'
base_path = ['service', 'dhcp-relay']
-class TestServiceDHCPRelay(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestServiceDHCPRelay(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_relay_default(self):
max_size = '800'
@@ -44,28 +39,28 @@ class TestServiceDHCPRelay(unittest.TestCase):
agents_packets = 'append'
servers = ['192.0.2.1', '192.0.2.2']
- self.session.set(base_path + ['interface', 'lo'])
+ self.cli_set(base_path + ['interface', 'lo'])
# check validate() - DHCP relay does not support the loopback interface
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(base_path + ['interface', 'lo'])
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', 'lo'])
# activate DHCP relay on all ethernet interfaces
for tmp in Section.interfaces("ethernet"):
- self.session.set(base_path + ['interface', tmp])
+ self.cli_set(base_path + ['interface', tmp])
# check validate() - No DHCP relay server(s) configured
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
for server in servers:
- self.session.set(base_path + ['server', server])
+ self.cli_set(base_path + ['server', server])
- self.session.set(base_path + ['relay-options', 'max-size', max_size])
- self.session.set(base_path + ['relay-options', 'hop-count', hop_count])
- self.session.set(base_path + ['relay-options', 'relay-agents-packets', agents_packets])
+ self.cli_set(base_path + ['relay-options', 'max-size', max_size])
+ self.cli_set(base_path + ['relay-options', 'hop-count', hop_count])
+ self.cli_set(base_path + ['relay-options', 'relay-agents-packets', agents_packets])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check configured port
config = read_file(RELAY_CONF)
diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py
index db7b2dda4..d3f6f21f1 100755
--- a/smoketest/scripts/cli/test_service_dhcp-server.py
+++ b/smoketest/scripts/cli/test_service_dhcp-server.py
@@ -14,13 +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 re
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
from vyos.util import process_named_running
from vyos.util import read_file
from vyos.template import address_from_cidr
@@ -37,17 +36,15 @@ dns_1 = inc_ip(subnet, 2)
dns_2 = inc_ip(subnet, 3)
domain_name = 'vyos.net'
-class TestServiceDHCPServer(unittest.TestCase):
+class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
cidr_mask = subnet.split('/')[-1]
- self.session.set(['interfaces', 'dummy', 'dum8765', 'address', f'{router}/{cidr_mask}'])
+ self.cli_set(['interfaces', 'dummy', 'dum8765', 'address', f'{router}/{cidr_mask}'])
def tearDown(self):
- self.session.delete(['interfaces', 'dummy', 'dum8765'])
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(['interfaces', 'dummy', 'dum8765'])
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_dhcp_single_pool_range(self):
shared_net_name = 'SMOKE-1'
@@ -57,25 +54,25 @@ class TestServiceDHCPServer(unittest.TestCase):
range_1_start = inc_ip(subnet, 40)
range_1_stop = inc_ip(subnet, 50)
- self.session.set(base_path + ['dynamic-dns-update'])
+ self.cli_set(base_path + ['dynamic-dns-update'])
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
# we use the first subnet IP address as default gateway
- self.session.set(pool + ['default-router', router])
- self.session.set(pool + ['dns-server', dns_1])
- self.session.set(pool + ['dns-server', dns_2])
- self.session.set(pool + ['domain-name', domain_name])
+ self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['dns-server', dns_1])
+ self.cli_set(pool + ['dns-server', dns_2])
+ self.cli_set(pool + ['domain-name', domain_name])
# check validate() - No DHCP address range or active static-mapping set
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(pool + ['range', '0', 'start', range_0_start])
- self.session.set(pool + ['range', '0', 'stop', range_0_stop])
- self.session.set(pool + ['range', '1', 'start', range_1_start])
- self.session.set(pool + ['range', '1', 'stop', range_1_stop])
+ self.cli_commit()
+ self.cli_set(pool + ['range', '0', 'start', range_0_start])
+ self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
+ self.cli_set(pool + ['range', '1', 'start', range_1_start])
+ self.cli_set(pool + ['range', '1', 'stop', range_1_stop])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(DHCPD_CONF)
network = address_from_cidr(subnet)
@@ -110,42 +107,42 @@ class TestServiceDHCPServer(unittest.TestCase):
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
# we use the first subnet IP address as default gateway
- self.session.set(pool + ['default-router', router])
- self.session.set(pool + ['dns-server', dns_1])
- self.session.set(pool + ['dns-server', dns_2])
- self.session.set(pool + ['domain-name', domain_name])
- self.session.set(pool + ['ip-forwarding'])
- self.session.set(pool + ['smtp-server', smtp_server])
- self.session.set(pool + ['pop-server', smtp_server])
- self.session.set(pool + ['time-server', time_server])
- self.session.set(pool + ['tftp-server-name', tftp_server])
+ self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['dns-server', dns_1])
+ self.cli_set(pool + ['dns-server', dns_2])
+ self.cli_set(pool + ['domain-name', domain_name])
+ self.cli_set(pool + ['ip-forwarding'])
+ self.cli_set(pool + ['smtp-server', smtp_server])
+ self.cli_set(pool + ['pop-server', smtp_server])
+ self.cli_set(pool + ['time-server', time_server])
+ self.cli_set(pool + ['tftp-server-name', tftp_server])
for search in search_domains:
- self.session.set(pool + ['domain-search', search])
- self.session.set(pool + ['bootfile-name', bootfile_name])
- self.session.set(pool + ['bootfile-server', bootfile_server])
- self.session.set(pool + ['wpad-url', wpad])
- self.session.set(pool + ['server-identifier', server_identifier])
+ self.cli_set(pool + ['domain-search', search])
+ self.cli_set(pool + ['bootfile-name', bootfile_name])
+ self.cli_set(pool + ['bootfile-server', bootfile_server])
+ self.cli_set(pool + ['wpad-url', wpad])
+ self.cli_set(pool + ['server-identifier', server_identifier])
- self.session.set(pool + ['static-route', 'destination-subnet', '10.0.0.0/24'])
- self.session.set(pool + ['static-route', 'router', '192.0.2.1'])
+ self.cli_set(pool + ['static-route', 'destination-subnet', '10.0.0.0/24'])
+ self.cli_set(pool + ['static-route', 'router', '192.0.2.1'])
# check validate() - No DHCP address range or active static-mapping set
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(pool + ['range', '0', 'start', range_0_start])
- self.session.set(pool + ['range', '0', 'stop', range_0_stop])
+ self.cli_commit()
+ self.cli_set(pool + ['range', '0', 'start', range_0_start])
+ self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
# failover
failover_local = router
failover_remote = inc_ip(router, 1)
- self.session.set(pool + ['failover', 'local-address', failover_local])
- self.session.set(pool + ['failover', 'name', shared_net_name])
- self.session.set(pool + ['failover', 'peer-address', failover_remote])
- self.session.set(pool + ['failover', 'status', 'primary'])
+ self.cli_set(pool + ['failover', 'local-address', failover_local])
+ self.cli_set(pool + ['failover', 'name', shared_net_name])
+ self.cli_set(pool + ['failover', 'peer-address', failover_remote])
+ self.cli_set(pool + ['failover', 'status', 'primary'])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(DHCPD_CONF)
@@ -200,27 +197,28 @@ class TestServiceDHCPServer(unittest.TestCase):
def test_dhcp_single_pool_static_mapping(self):
shared_net_name = 'SMOKE-2'
+ domain_name = 'private'
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
# we use the first subnet IP address as default gateway
- self.session.set(pool + ['default-router', router])
- self.session.set(pool + ['dns-server', dns_1])
- self.session.set(pool + ['dns-server', dns_2])
- self.session.set(pool + ['domain-name', domain_name])
+ self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['dns-server', dns_1])
+ self.cli_set(pool + ['dns-server', dns_2])
+ self.cli_set(pool + ['domain-name', domain_name])
# check validate() - No DHCP address range or active static-mapping set
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
client_base = 10
for client in ['client1', 'client2', 'client3']:
mac = '00:50:00:00:00:{}'.format(client_base)
- self.session.set(pool + ['static-mapping', client, 'mac-address', mac])
- self.session.set(pool + ['static-mapping', client, 'ip-address', inc_ip(subnet, client_base)])
+ self.cli_set(pool + ['static-mapping', client, 'mac-address', mac])
+ self.cli_set(pool + ['static-mapping', client, 'ip-address', inc_ip(subnet, client_base)])
client_base += 1
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(DHCPD_CONF)
network = address_from_cidr(subnet)
@@ -263,25 +261,25 @@ class TestServiceDHCPServer(unittest.TestCase):
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
# we use the first subnet IP address as default gateway
- self.session.set(pool + ['default-router', router])
- self.session.set(pool + ['dns-server', dns_1])
- self.session.set(pool + ['domain-name', domain_name])
- self.session.set(pool + ['lease', lease_time])
+ self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['dns-server', dns_1])
+ self.cli_set(pool + ['domain-name', domain_name])
+ self.cli_set(pool + ['lease', lease_time])
- self.session.set(pool + ['range', '0', 'start', range_0_start])
- self.session.set(pool + ['range', '0', 'stop', range_0_stop])
- self.session.set(pool + ['range', '1', 'start', range_1_start])
- self.session.set(pool + ['range', '1', 'stop', range_1_stop])
+ self.cli_set(pool + ['range', '0', 'start', range_0_start])
+ self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
+ self.cli_set(pool + ['range', '1', 'start', range_1_start])
+ self.cli_set(pool + ['range', '1', 'stop', range_1_stop])
client_base = 60
for client in ['client1', 'client2', 'client3', 'client4']:
mac = '02:50:00:00:00:{}'.format(client_base)
- self.session.set(pool + ['static-mapping', client, 'mac-address', mac])
- self.session.set(pool + ['static-mapping', client, 'ip-address', inc_ip(subnet, client_base)])
+ self.cli_set(pool + ['static-mapping', client, 'mac-address', mac])
+ self.cli_set(pool + ['static-mapping', client, 'ip-address', inc_ip(subnet, client_base)])
client_base += 1
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(DHCPD_CONF)
for network in ['0', '1', '2', '3']:
@@ -328,13 +326,13 @@ class TestServiceDHCPServer(unittest.TestCase):
range_0_stop = inc_ip(subnet, 20)
pool = base_path + ['shared-network-name', 'EXCLUDE-TEST', 'subnet', subnet]
- self.session.set(pool + ['default-router', router])
- self.session.set(pool + ['exclude', router])
- self.session.set(pool + ['range', '0', 'start', range_0_start])
- self.session.set(pool + ['range', '0', 'stop', range_0_stop])
+ self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['exclude', router])
+ self.cli_set(pool + ['range', '0', 'start', range_0_start])
+ self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
# commit changes
- self.session.commit()
+ self.cli_commit()
# VErify
config = read_file(DHCPD_CONF)
@@ -361,13 +359,13 @@ class TestServiceDHCPServer(unittest.TestCase):
range_0_start_excl = inc_ip(exclude_addr, 1)
pool = base_path + ['shared-network-name', 'EXCLUDE-TEST-2', 'subnet', subnet]
- self.session.set(pool + ['default-router', router])
- self.session.set(pool + ['exclude', exclude_addr])
- self.session.set(pool + ['range', '0', 'start', range_0_start])
- self.session.set(pool + ['range', '0', 'stop', range_0_stop])
+ self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['exclude', exclude_addr])
+ self.cli_set(pool + ['range', '0', 'start', range_0_start])
+ self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Verify
config = read_file(DHCPD_CONF)
@@ -385,7 +383,7 @@ class TestServiceDHCPServer(unittest.TestCase):
def test_dhcp_relay_server(self):
# Listen on specific address and return DHCP leases from a non
# directly connected pool
- self.session.set(base_path + ['listen-address', router])
+ self.cli_set(base_path + ['listen-address', router])
relay_subnet = '10.0.0.0/16'
relay_router = inc_ip(relay_subnet, 1)
@@ -394,12 +392,12 @@ class TestServiceDHCPServer(unittest.TestCase):
range_0_stop = '10.0.250.255'
pool = base_path + ['shared-network-name', 'RELAY', 'subnet', relay_subnet]
- self.session.set(pool + ['default-router', relay_router])
- self.session.set(pool + ['range', '0', 'start', range_0_start])
- self.session.set(pool + ['range', '0', 'stop', range_0_stop])
+ self.cli_set(pool + ['default-router', relay_router])
+ self.cli_set(pool + ['range', '0', 'start', range_0_start])
+ self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(DHCPD_CONF)
network = address_from_cidr(subnet)
diff --git a/smoketest/scripts/cli/test_service_dhcpv6-relay.py b/smoketest/scripts/cli/test_service_dhcpv6-relay.py
index e36c237bc..5a9dd1aa6 100755
--- a/smoketest/scripts/cli/test_service_dhcpv6-relay.py
+++ b/smoketest/scripts/cli/test_service_dhcpv6-relay.py
@@ -14,15 +14,14 @@
# 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 re
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.template import address_from_cidr
-from vyos.util import cmd
from vyos.util import process_named_running
from vyos.util import read_file
@@ -35,52 +34,50 @@ upstream_if_addr = '2001:db8::1/64'
listen_addr = '2001:db8:ffff::1/64'
interfaces = []
-class TestServiceDHCPv6Relay(unittest.TestCase):
+class TestServiceDHCPv6Relay(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
for tmp in interfaces:
listen = listen_addr
if tmp == upstream_if:
listen = upstream_if_addr
- self.session.set(['interfaces', 'ethernet', tmp, 'address', listen])
+ self.cli_set(['interfaces', 'ethernet', tmp, 'address', listen])
def tearDown(self):
- self.session.delete(base_path)
+ self.cli_delete(base_path)
for tmp in interfaces:
listen = listen_addr
if tmp == upstream_if:
listen = upstream_if_addr
- self.session.delete(['interfaces', 'ethernet', tmp, 'address', listen])
+ self.cli_delete(['interfaces', 'ethernet', tmp, 'address', listen])
- self.session.commit()
- del self.session
+ self.cli_commit()
def test_relay_default(self):
dhcpv6_server = '2001:db8::ffff'
hop_count = '20'
- self.session.set(base_path + ['use-interface-id-option'])
- self.session.set(base_path + ['max-hop-count', hop_count])
+ self.cli_set(base_path + ['use-interface-id-option'])
+ self.cli_set(base_path + ['max-hop-count', hop_count])
# check validate() - Must set at least one listen and upstream
# interface addresses.
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + ['upstream-interface', upstream_if, 'address', dhcpv6_server])
+ self.cli_commit()
+ self.cli_set(base_path + ['upstream-interface', upstream_if, 'address', dhcpv6_server])
# check validate() - Must set at least one listen and upstream
# interface addresses.
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
# add listener on all ethernet interfaces except the upstream interface
for tmp in interfaces:
if tmp == upstream_if:
continue
- self.session.set(base_path + ['listen-interface', tmp, 'address', listen_addr.split('/')[0]])
+ self.cli_set(base_path + ['listen-interface', tmp, 'address', listen_addr.split('/')[0]])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check configured port
config = read_file(RELAY_CONF)
diff --git a/smoketest/scripts/cli/test_service_dhcpv6-server.py b/smoketest/scripts/cli/test_service_dhcpv6-server.py
index 319891a94..e85a055c7 100755
--- a/smoketest/scripts/cli/test_service_dhcpv6-server.py
+++ b/smoketest/scripts/cli/test_service_dhcpv6-server.py
@@ -14,14 +14,13 @@
# 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 re
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.template import inc_ip
-from vyos.util import cmd
from vyos.util import process_named_running
from vyos.util import read_file
@@ -37,16 +36,14 @@ nis_servers = ['2001:db8:ffff::1', '2001:db8:ffff::2']
interface = 'eth1'
interface_addr = inc_ip(subnet, 1) + '/64'
-class TestServiceDHCPServer(unittest.TestCase):
+class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
- self.session.set(['interfaces', 'ethernet', interface, 'address', interface_addr])
+ self.cli_set(['interfaces', 'ethernet', interface, 'address', interface_addr])
def tearDown(self):
- self.session.delete(base_path)
- self.session.delete(['interfaces', 'ethernet', interface, 'address', interface_addr])
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_delete(['interfaces', 'ethernet', interface, 'address', interface_addr])
+ self.cli_commit()
def test_single_pool(self):
shared_net_name = 'SMOKE-1'
@@ -62,37 +59,37 @@ class TestServiceDHCPServer(unittest.TestCase):
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
- self.session.set(base_path + ['preference', preference])
+ self.cli_set(base_path + ['preference', preference])
# we use the first subnet IP address as default gateway
- self.session.set(pool + ['name-server', dns_1])
- self.session.set(pool + ['name-server', dns_2])
- self.session.set(pool + ['name-server', dns_2])
- self.session.set(pool + ['lease-time', 'default', lease_time])
- self.session.set(pool + ['lease-time', 'maximum', max_lease_time])
- self.session.set(pool + ['lease-time', 'minimum', min_lease_time])
- self.session.set(pool + ['nis-domain', domain])
- self.session.set(pool + ['nisplus-domain', domain])
- self.session.set(pool + ['sip-server', sip_server])
- self.session.set(pool + ['sntp-server', sntp_server])
- self.session.set(pool + ['address-range', 'start', range_start, 'stop', range_stop])
+ self.cli_set(pool + ['name-server', dns_1])
+ self.cli_set(pool + ['name-server', dns_2])
+ self.cli_set(pool + ['name-server', dns_2])
+ self.cli_set(pool + ['lease-time', 'default', lease_time])
+ self.cli_set(pool + ['lease-time', 'maximum', max_lease_time])
+ self.cli_set(pool + ['lease-time', 'minimum', min_lease_time])
+ self.cli_set(pool + ['nis-domain', domain])
+ self.cli_set(pool + ['nisplus-domain', domain])
+ self.cli_set(pool + ['sip-server', sip_server])
+ self.cli_set(pool + ['sntp-server', sntp_server])
+ self.cli_set(pool + ['address-range', 'start', range_start, 'stop', range_stop])
for server in nis_servers:
- self.session.set(pool + ['nis-server', server])
- self.session.set(pool + ['nisplus-server', server])
+ self.cli_set(pool + ['nis-server', server])
+ self.cli_set(pool + ['nisplus-server', server])
for search in search_domains:
- self.session.set(pool + ['domain-search', search])
+ self.cli_set(pool + ['domain-search', search])
client_base = 1
for client in ['client1', 'client2', 'client3']:
cid = '00:01:00:01:12:34:56:78:aa:bb:cc:dd:ee:{}'.format(client_base)
- self.session.set(pool + ['static-mapping', client, 'identifier', cid])
- self.session.set(pool + ['static-mapping', client, 'ipv6-address', inc_ip(subnet, client_base)])
+ self.cli_set(pool + ['static-mapping', client, 'identifier', cid])
+ self.cli_set(pool + ['static-mapping', client, 'ipv6-address', inc_ip(subnet, client_base)])
client_base += 1
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(DHCPD_CONF)
self.assertIn(f'option dhcp6.preference {preference};', config)
@@ -136,12 +133,12 @@ class TestServiceDHCPServer(unittest.TestCase):
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
- self.session.set(pool + ['address-range', 'start', range_start, 'stop', range_stop])
- self.session.set(pool + ['prefix-delegation', 'start', delegate_start, 'stop', delegate_stop])
- self.session.set(pool + ['prefix-delegation', 'start', delegate_start, 'prefix-length', delegate_len])
+ self.cli_set(pool + ['address-range', 'start', range_start, 'stop', range_stop])
+ self.cli_set(pool + ['prefix-delegation', 'start', delegate_start, 'stop', delegate_stop])
+ self.cli_set(pool + ['prefix-delegation', 'start', delegate_start, 'prefix-length', delegate_len])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(DHCPD_CONF)
self.assertIn(f'subnet6 {subnet}' + r' {', config)
@@ -151,5 +148,26 @@ class TestServiceDHCPServer(unittest.TestCase):
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
+ def test_global_nameserver(self):
+ shared_net_name = 'SMOKE-3'
+ ns_global_1 = '2001:db8::1111'
+ ns_global_2 = '2001:db8::2222'
+
+ self.cli_set(base_path + ['global-parameters', 'name-server', ns_global_1])
+ self.cli_set(base_path + ['global-parameters', 'name-server', ns_global_2])
+ self.cli_set(base_path + ['shared-network-name', shared_net_name, 'subnet', subnet])
+
+ # commit changes
+ self.cli_commit()
+
+ config = read_file(DHCPD_CONF)
+ self.assertIn(f'option dhcp6.name-servers {ns_global_1};', config)
+ self.assertIn(f'option dhcp6.name-servers {ns_global_2};', config)
+ self.assertIn(f'subnet6 {subnet}' + r' {', config)
+ self.assertIn(f'set shared-networkname = "{shared_net_name}";', config)
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py
index 83eede64a..d8a87ffd4 100755
--- a/smoketest/scripts/cli/test_service_dns_dynamic.py
+++ b/smoketest/scripts/cli/test_service_dns_dynamic.py
@@ -18,10 +18,11 @@ import re
import os
import unittest
-from getpass import getuser
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
-from vyos.util import read_file
+from vyos.util import cmd
from vyos.util import process_named_running
PROCESS_NAME = 'ddclient'
@@ -29,21 +30,17 @@ DDCLIENT_CONF = '/run/ddclient/ddclient.conf'
base_path = ['service', 'dns', 'dynamic']
def get_config_value(key):
- tmp = read_file(DDCLIENT_CONF)
+ tmp = cmd(f'sudo cat {DDCLIENT_CONF}')
tmp = re.findall(r'\n?{}=+(.*)'.format(key), tmp)
tmp = tmp[0].rstrip(',')
return tmp
-class TestServiceDDNS(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
+class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
# Delete DDNS configuration
- self.session.delete(base_path)
- self.session.commit()
-
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_dyndns_service(self):
ddns = ['interface', 'eth0', 'service']
@@ -53,45 +50,44 @@ class TestServiceDDNS(unittest.TestCase):
user = 'vyos_user'
password = 'vyos_pass'
zone = 'vyos.io'
- self.session.delete(base_path)
- self.session.set(base_path + ddns + [service, 'host-name', 'test.ddns.vyos.io'])
- self.session.set(base_path + ddns + [service, 'login', user])
- self.session.set(base_path + ddns + [service, 'password', password])
- self.session.set(base_path + ddns + [service, 'zone', zone])
+ self.cli_delete(base_path)
+ self.cli_set(base_path + ddns + [service, 'host-name', 'test.ddns.vyos.io'])
+ self.cli_set(base_path + ddns + [service, 'login', user])
+ self.cli_set(base_path + ddns + [service, 'password', password])
+ self.cli_set(base_path + ddns + [service, 'zone', zone])
# commit changes
if service == 'cloudflare':
- self.session.commit()
+ self.cli_commit()
else:
# zone option only works on cloudflare, an exception is raised
# for all others
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.delete(base_path + ddns + [service, 'zone', 'vyos.io'])
+ self.cli_commit()
+ self.cli_delete(base_path + ddns + [service, 'zone', 'vyos.io'])
# commit changes again - now it should work
- self.session.commit()
+ self.cli_commit()
# we can only read the configuration file when we operate as 'root'
- if getuser() == 'root':
- protocol = get_config_value('protocol')
- login = get_config_value('login')
- pwd = get_config_value('password')
-
- # some services need special treatment
- protoname = service
- if service == 'cloudflare':
- tmp = get_config_value('zone')
- self.assertTrue(tmp == zone)
- elif service == 'afraid':
- protoname = 'freedns'
- elif service == 'dyndns':
- protoname = 'dyndns2'
- elif service == 'zoneedit':
- protoname = 'zoneedit1'
-
- self.assertTrue(protocol == protoname)
- self.assertTrue(login == user)
- self.assertTrue(pwd == "'" + password + "'")
+ protocol = get_config_value('protocol')
+ login = get_config_value('login')
+ pwd = get_config_value('password')
+
+ # some services need special treatment
+ protoname = service
+ if service == 'cloudflare':
+ tmp = get_config_value('zone')
+ self.assertTrue(tmp == zone)
+ elif service == 'afraid':
+ protoname = 'freedns'
+ elif service == 'dyndns':
+ protoname = 'dyndns2'
+ elif service == 'zoneedit':
+ protoname = 'zoneedit1'
+
+ self.assertTrue(protocol == protoname)
+ self.assertTrue(login == user)
+ self.assertTrue(pwd == "'" + password + "'")
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
@@ -101,11 +97,11 @@ class TestServiceDDNS(unittest.TestCase):
ddns = ['interface', 'eth0', 'rfc2136', 'vyos']
ddns_key_file = '/config/auth/my.key'
- self.session.set(base_path + ddns + ['key', ddns_key_file])
- self.session.set(base_path + ddns + ['record', 'test.ddns.vyos.io'])
- self.session.set(base_path + ddns + ['server', 'ns1.vyos.io'])
- self.session.set(base_path + ddns + ['ttl', '300'])
- self.session.set(base_path + ddns + ['zone', 'vyos.io'])
+ self.cli_set(base_path + ddns + ['key', ddns_key_file])
+ self.cli_set(base_path + ddns + ['record', 'test.ddns.vyos.io'])
+ self.cli_set(base_path + ddns + ['server', 'ns1.vyos.io'])
+ self.cli_set(base_path + ddns + ['ttl', '300'])
+ self.cli_set(base_path + ddns + ['zone', 'vyos.io'])
# ensure an exception will be raised as no key is present
if os.path.exists(ddns_key_file):
@@ -113,13 +109,13 @@ class TestServiceDDNS(unittest.TestCase):
# check validate() - the key file does not exist yet
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
with open(ddns_key_file, 'w') as f:
f.write('S3cretKey')
# commit changes
- self.session.commit()
+ self.cli_commit()
# TODO: inspect generated configuration file
diff --git a/smoketest/scripts/cli/test_service_dns_forwarding.py b/smoketest/scripts/cli/test_service_dns_forwarding.py
index ada53e8dd..8005eb319 100755
--- a/smoketest/scripts/cli/test_service_dns_forwarding.py
+++ b/smoketest/scripts/cli/test_service_dns_forwarding.py
@@ -15,10 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
-import os
import unittest
-from vyos.configsession import ConfigSession, ConfigSessionError
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
from vyos.util import read_file
from vyos.util import process_named_running
@@ -37,44 +39,40 @@ def get_config_value(key, file=CONFIG_FILE):
tmp = re.findall(r'\n{}=+(.*)'.format(key), tmp)
return tmp[0]
-class TestServicePowerDNS(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
# Delete DNS forwarding configuration
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_basic_forwarding(self):
# Check basic DNS forwarding settings
cache_size = '20'
negative_ttl = '120'
- self.session.set(base_path + ['cache-size', cache_size])
- self.session.set(base_path + ['negative-ttl', negative_ttl])
+ self.cli_set(base_path + ['cache-size', cache_size])
+ self.cli_set(base_path + ['negative-ttl', negative_ttl])
# check validate() - allow from must be defined
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
for network in allow_from:
- self.session.set(base_path + ['allow-from', network])
+ self.cli_set(base_path + ['allow-from', network])
# check validate() - listen-address must be defined
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
for address in listen_adress:
- self.session.set(base_path + ['listen-address', address])
+ self.cli_set(base_path + ['listen-address', address])
# configure DNSSEC
- self.session.set(base_path + ['dnssec', 'validate'])
+ self.cli_set(base_path + ['dnssec', 'validate'])
# Do not use local /etc/hosts file in name resolution
- self.session.set(base_path + ['ignore-hosts-file'])
+ self.cli_set(base_path + ['ignore-hosts-file'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check configured cache-size
tmp = get_config_value('max-cache-entries')
@@ -103,16 +101,16 @@ class TestServicePowerDNS(unittest.TestCase):
# DNSSEC option testing
for network in allow_from:
- self.session.set(base_path + ['allow-from', network])
+ self.cli_set(base_path + ['allow-from', network])
for address in listen_adress:
- self.session.set(base_path + ['listen-address', address])
+ self.cli_set(base_path + ['listen-address', address])
options = ['off', 'process-no-validate', 'process', 'log-fail', 'validate']
for option in options:
- self.session.set(base_path + ['dnssec', option])
+ self.cli_set(base_path + ['dnssec', option])
# commit changes
- self.session.commit()
+ self.cli_commit()
tmp = get_config_value('dnssec')
self.assertEqual(tmp, option)
@@ -124,16 +122,16 @@ class TestServicePowerDNS(unittest.TestCase):
# Externe Domain Name Servers (DNS) addresses
for network in allow_from:
- self.session.set(base_path + ['allow-from', network])
+ self.cli_set(base_path + ['allow-from', network])
for address in listen_adress:
- self.session.set(base_path + ['listen-address', address])
+ self.cli_set(base_path + ['listen-address', address])
nameservers = ['192.0.2.1', '192.0.2.2']
for nameserver in nameservers:
- self.session.set(base_path + ['name-server', nameserver])
+ self.cli_set(base_path + ['name-server', nameserver])
# commit changes
- self.session.commit()
+ self.cli_commit()
tmp = get_config_value(r'\+.', file=FORWARD_FILE)
self.assertEqual(tmp, ', '.join(nameservers))
@@ -148,26 +146,26 @@ class TestServicePowerDNS(unittest.TestCase):
def test_domain_forwarding(self):
for network in allow_from:
- self.session.set(base_path + ['allow-from', network])
+ self.cli_set(base_path + ['allow-from', network])
for address in listen_adress:
- self.session.set(base_path + ['listen-address', address])
+ self.cli_set(base_path + ['listen-address', address])
domains = ['vyos.io', 'vyos.net', 'vyos.com']
nameservers = ['192.0.2.1', '192.0.2.2']
for domain in domains:
for nameserver in nameservers:
- self.session.set(base_path + ['domain', domain, 'server', nameserver])
+ self.cli_set(base_path + ['domain', domain, 'server', nameserver])
# Test 'recursion-desired' flag for only one domain
if domain == domains[0]:
- self.session.set(base_path + ['domain', domain, 'recursion-desired'])
+ self.cli_set(base_path + ['domain', domain, 'recursion-desired'])
# Test 'negative trust anchor' flag for the second domain only
if domain == domains[1]:
- self.session.set(base_path + ['domain', domain, 'addnta'])
+ self.cli_set(base_path + ['domain', domain, 'addnta'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Test configured name-servers
hosts_conf = read_file(HOSTSD_FILE)
diff --git a/smoketest/scripts/cli/test_service_https.py b/smoketest/scripts/cli/test_service_https.py
index fd0f6bfbd..3ed7655e9 100755
--- a/smoketest/scripts/cli/test_service_https.py
+++ b/smoketest/scripts/cli/test_service_https.py
@@ -14,28 +14,27 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.util import run
base_path = ['service', 'https']
-class TestHTTPSService(unittest.TestCase):
+class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
- self.session.delete(base_path)
+ self.cli_delete(base_path)
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_default(self):
- self.session.set(base_path)
- self.session.commit()
+ self.cli_set(base_path)
+ self.cli_commit()
ret = run('sudo /usr/sbin/nginx -t')
self.assertEqual(ret, 0)
@@ -48,11 +47,11 @@ class TestHTTPSService(unittest.TestCase):
test_path = base_path + ['virtual-host', vhost_id]
- self.session.set(test_path + ['listen-address', address])
- self.session.set(test_path + ['listen-port', port])
- self.session.set(test_path + ['server-name', name])
+ self.cli_set(test_path + ['listen-address', address])
+ self.cli_set(test_path + ['listen-port', port])
+ self.cli_set(test_path + ['server-name', name])
- self.session.commit()
+ self.cli_commit()
ret = run('sudo /usr/sbin/nginx -t')
self.assertEqual(ret, 0)
diff --git a/smoketest/scripts/cli/test_service_mdns-repeater.py b/smoketest/scripts/cli/test_service_mdns-repeater.py
index e6986b92a..b1092c3e5 100755
--- a/smoketest/scripts/cli/test_service_mdns-repeater.py
+++ b/smoketest/scripts/cli/test_service_mdns-repeater.py
@@ -14,35 +14,32 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.util import process_named_running
base_path = ['service', 'mdns', 'repeater']
intf_base = ['interfaces', 'dummy']
-class TestServiceMDNSrepeater(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestServiceMDNSrepeater(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
- self.session.delete(base_path)
- self.session.delete(intf_base + ['dum10'])
- self.session.delete(intf_base + ['dum20'])
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_delete(intf_base + ['dum10'])
+ self.cli_delete(intf_base + ['dum20'])
+ self.cli_commit()
def test_service(self):
# Service required a configured IP address on the interface
- self.session.set(intf_base + ['dum10', 'address', '192.0.2.1/30'])
- self.session.set(intf_base + ['dum20', 'address', '192.0.2.5/30'])
+ self.cli_set(intf_base + ['dum10', 'address', '192.0.2.1/30'])
+ self.cli_set(intf_base + ['dum20', 'address', '192.0.2.5/30'])
- self.session.set(base_path + ['interface', 'dum10'])
- self.session.set(base_path + ['interface', 'dum20'])
- self.session.commit()
+ self.cli_set(base_path + ['interface', 'dum10'])
+ self.cli_set(base_path + ['interface', 'dum20'])
+ self.cli_commit()
# Check for running process
self.assertTrue(process_named_running('mdns-repeater'))
diff --git a/smoketest/scripts/cli/test_service_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py
index a4bb6e9f9..2b11ee362 100755
--- a/smoketest/scripts/cli/test_service_pppoe-server.py
+++ b/smoketest/scripts/cli/test_service_pppoe-server.py
@@ -27,7 +27,7 @@ local_if = ['interfaces', 'dummy', 'dum667']
ac_name = 'ACN'
interface = 'eth0'
-class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
+class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
def setUp(self):
self._base_path = ['service', 'pppoe-server']
self._process_name = 'accel-pppd'
@@ -37,7 +37,7 @@ class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
super().setUp()
def tearDown(self):
- self.session.delete(local_if)
+ self.cli_delete(local_if)
super().tearDown()
def verify(self, conf):
@@ -66,7 +66,7 @@ class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
super().verify(conf)
def basic_config(self):
- self.session.set(local_if + ['address', '192.0.2.1/32'])
+ self.cli_set(local_if + ['address', '192.0.2.1/32'])
self.set(['access-concentrator', ac_name])
self.set(['interface', interface])
@@ -92,7 +92,7 @@ class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
self.set(['ppp-options', 'mru', mru])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
@@ -124,7 +124,7 @@ class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
self.set( ['authentication', 'protocols', 'mschap-v2'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True)
@@ -144,12 +144,13 @@ class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
start = '192.0.2.10'
stop = '192.0.2.20'
- start_stop = f'{start}-{stop}'
+ stop_octet = stop.split('.')[3]
+ start_stop = f'{start}-{stop_octet}'
self.set(['client-ip-pool', 'start', start])
self.set(['client-ip-pool', 'stop', stop])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True)
@@ -186,7 +187,7 @@ class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
self.set(['client-ipv6-pool', 'delegate', delegate_prefix, 'delegation-prefix', delegate_mask])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
diff --git a/smoketest/scripts/cli/test_service_router-advert.py b/smoketest/scripts/cli/test_service_router-advert.py
index b80eb3c43..b19c49c6e 100755
--- a/smoketest/scripts/cli/test_service_router-advert.py
+++ b/smoketest/scripts/cli/test_service_router-advert.py
@@ -15,9 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.util import read_file
from vyos.util import process_named_running
@@ -33,26 +34,24 @@ def get_config_value(key):
tmp = re.findall(r'\n?{}\s+(.*)'.format(key), tmp)
return tmp[0].split()[0].replace(';','')
-class TestServiceRADVD(unittest.TestCase):
+class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
- self.session.set(address_base + ['2001:db8::1/64'])
+ self.cli_set(address_base + ['2001:db8::1/64'])
def tearDown(self):
- self.session.delete(address_base)
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(address_base)
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_single(self):
- self.session.set(base_path + ['prefix', '::/64', 'no-on-link-flag'])
- self.session.set(base_path + ['prefix', '::/64', 'no-autonomous-flag'])
- self.session.set(base_path + ['prefix', '::/64', 'valid-lifetime', 'infinity'])
- self.session.set(base_path + ['dnssl', '2001:db8::1234'])
- self.session.set(base_path + ['other-config-flag'])
+ self.cli_set(base_path + ['prefix', '::/64', 'no-on-link-flag'])
+ self.cli_set(base_path + ['prefix', '::/64', 'no-autonomous-flag'])
+ self.cli_set(base_path + ['prefix', '::/64', 'valid-lifetime', 'infinity'])
+ self.cli_set(base_path + ['dnssl', '2001:db8::1234'])
+ self.cli_set(base_path + ['other-config-flag'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# verify values
tmp = get_config_value('interface')
diff --git a/smoketest/scripts/cli/test_service_snmp.py b/smoketest/scripts/cli/test_service_snmp.py
index 81045d0b4..008271102 100755
--- a/smoketest/scripts/cli/test_service_snmp.py
+++ b/smoketest/scripts/cli/test_service_snmp.py
@@ -14,10 +14,10 @@
# 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 re
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
@@ -35,15 +35,11 @@ def get_config_value(key):
tmp = re.findall(r'\n?{}\s+(.*)'.format(key), tmp)
return tmp[0]
-class TestSNMPService(unittest.TestCase):
+class TestSNMPService(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
- self.session.delete(base_path)
-
- def tearDown(self):
- del self.session
+ self.cli_delete(base_path)
def test_snmp_basic(self):
# Check if SNMP can be configured and service runs
@@ -53,19 +49,19 @@ class TestSNMPService(unittest.TestCase):
for auth in ['ro', 'rw']:
community = 'VyOS' + auth
- self.session.set(base_path + ['community', community, 'authorization', auth])
+ self.cli_set(base_path + ['community', community, 'authorization', auth])
for client in clients:
- self.session.set(base_path + ['community', community, 'client', client])
+ self.cli_set(base_path + ['community', community, 'client', client])
for network in networks:
- self.session.set(base_path + ['community', community, 'network', network])
+ self.cli_set(base_path + ['community', community, 'network', network])
for addr in listen:
- self.session.set(base_path + ['listen-address', addr])
+ self.cli_set(base_path + ['listen-address', addr])
- self.session.set(base_path + ['contact', 'maintainers@vyos.io'])
- self.session.set(base_path + ['location', 'qemu'])
+ self.cli_set(base_path + ['contact', 'maintainers@vyos.io'])
+ self.cli_set(base_path + ['location', 'qemu'])
- self.session.commit()
+ self.cli_commit()
# verify listen address, it will be returned as
# ['unix:/run/snmpd.socket,udp:127.0.0.1:161,udp6:[::1]:161']
@@ -88,30 +84,30 @@ class TestSNMPService(unittest.TestCase):
# Check if SNMPv3 can be configured with SHA authentication
# and service runs
- self.session.set(base_path + ['v3', 'engineid', '000000000000000000000002'])
- self.session.set(base_path + ['v3', 'group', 'default', 'mode', 'ro'])
+ self.cli_set(base_path + ['v3', 'engineid', '000000000000000000000002'])
+ self.cli_set(base_path + ['v3', 'group', 'default', 'mode', 'ro'])
# check validate() - a view must be created before this can be comitted
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
- self.session.set(base_path + ['v3', 'view', 'default', 'oid', '1'])
- self.session.set(base_path + ['v3', 'group', 'default', 'view', 'default'])
+ self.cli_set(base_path + ['v3', 'view', 'default', 'oid', '1'])
+ self.cli_set(base_path + ['v3', 'group', 'default', 'view', 'default'])
# create user
- self.session.set(base_path + ['v3', 'user', 'vyos', 'auth', 'plaintext-password', 'vyos12345678'])
- self.session.set(base_path + ['v3', 'user', 'vyos', 'auth', 'type', 'sha'])
- self.session.set(base_path + ['v3', 'user', 'vyos', 'privacy', 'plaintext-password', 'vyos12345678'])
- self.session.set(base_path + ['v3', 'user', 'vyos', 'privacy', 'type', 'aes'])
- self.session.set(base_path + ['v3', 'user', 'vyos', 'group', 'default'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'auth', 'plaintext-password', 'vyos12345678'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'auth', 'type', 'sha'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'privacy', 'plaintext-password', 'vyos12345678'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'privacy', 'type', 'aes'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'group', 'default'])
- self.session.commit()
+ self.cli_commit()
# commit will alter the CLI values - check if they have been updated:
hashed_password = '4e52fe55fd011c9c51ae2c65f4b78ca93dcafdfe'
- tmp = self.session.show_config(base_path + ['v3', 'user', 'vyos', 'auth', 'encrypted-password']).split()[1]
+ tmp = self._session.show_config(base_path + ['v3', 'user', 'vyos', 'auth', 'encrypted-password']).split()[1]
self.assertEqual(tmp, hashed_password)
- tmp = self.session.show_config(base_path + ['v3', 'user', 'vyos', 'privacy', 'encrypted-password']).split()[1]
+ tmp = self._session.show_config(base_path + ['v3', 'user', 'vyos', 'privacy', 'encrypted-password']).split()[1]
self.assertEqual(tmp, hashed_password)
# TODO: read in config file and check values
@@ -123,30 +119,30 @@ class TestSNMPService(unittest.TestCase):
# Check if SNMPv3 can be configured with MD5 authentication
# and service runs
- self.session.set(base_path + ['v3', 'engineid', '000000000000000000000002'])
- self.session.set(base_path + ['v3', 'group', 'default', 'mode', 'ro'])
+ self.cli_set(base_path + ['v3', 'engineid', '000000000000000000000002'])
+ self.cli_set(base_path + ['v3', 'group', 'default', 'mode', 'ro'])
# check validate() - a view must be created before this can be comitted
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
- self.session.set(base_path + ['v3', 'view', 'default', 'oid', '1'])
- self.session.set(base_path + ['v3', 'group', 'default', 'view', 'default'])
+ self.cli_set(base_path + ['v3', 'view', 'default', 'oid', '1'])
+ self.cli_set(base_path + ['v3', 'group', 'default', 'view', 'default'])
# create user
- self.session.set(base_path + ['v3', 'user', 'vyos', 'auth', 'plaintext-password', 'vyos12345678'])
- self.session.set(base_path + ['v3', 'user', 'vyos', 'auth', 'type', 'md5'])
- self.session.set(base_path + ['v3', 'user', 'vyos', 'privacy', 'plaintext-password', 'vyos12345678'])
- self.session.set(base_path + ['v3', 'user', 'vyos', 'privacy', 'type', 'des'])
- self.session.set(base_path + ['v3', 'user', 'vyos', 'group', 'default'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'auth', 'plaintext-password', 'vyos12345678'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'auth', 'type', 'md5'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'privacy', 'plaintext-password', 'vyos12345678'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'privacy', 'type', 'des'])
+ self.cli_set(base_path + ['v3', 'user', 'vyos', 'group', 'default'])
- self.session.commit()
+ self.cli_commit()
# commit will alter the CLI values - check if they have been updated:
hashed_password = '4c67690d45d3dfcd33d0d7e308e370ad'
- tmp = self.session.show_config(base_path + ['v3', 'user', 'vyos', 'auth', 'encrypted-password']).split()[1]
+ tmp = self._session.show_config(base_path + ['v3', 'user', 'vyos', 'auth', 'encrypted-password']).split()[1]
self.assertEqual(tmp, hashed_password)
- tmp = self.session.show_config(base_path + ['v3', 'user', 'vyos', 'privacy', 'encrypted-password']).split()[1]
+ tmp = self._session.show_config(base_path + ['v3', 'user', 'vyos', 'privacy', 'encrypted-password']).split()[1]
self.assertEqual(tmp, hashed_password)
# TODO: read in config file and check values
diff --git a/smoketest/scripts/cli/test_service_ssh.py b/smoketest/scripts/cli/test_service_ssh.py
index 0bb907c3a..c76f709b1 100755
--- a/smoketest/scripts/cli/test_service_ssh.py
+++ b/smoketest/scripts/cli/test_service_ssh.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 re
import os
+import re
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.util import cmd
@@ -25,40 +27,41 @@ from vyos.util import process_named_running
from vyos.util import read_file
PROCESS_NAME = 'sshd'
-SSHD_CONF = '/run/ssh/sshd_config'
+SSHD_CONF = '/run/sshd/sshd_config'
base_path = ['service', 'ssh']
-vrf = 'ssh-test'
+vrf = 'mgmt'
+
+key_rsa = '/etc/ssh/ssh_host_rsa_key'
+key_dsa = '/etc/ssh/ssh_host_dsa_key'
+key_ed25519 = '/etc/ssh/ssh_host_ed25519_key'
def get_config_value(key):
tmp = read_file(SSHD_CONF)
tmp = re.findall(f'\n?{key}\s+(.*)', tmp)
return tmp
-class TestServiceSSH(unittest.TestCase):
+class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
- self.session.delete(base_path)
+ self.cli_delete(base_path)
def tearDown(self):
# delete testing SSH config
- self.session.delete(base_path)
- # restore "plain" SSH access
- self.session.set(base_path)
- # delete VRF
- self.session.delete(['vrf', 'name', vrf])
+ self.cli_delete(base_path)
+ self.cli_commit()
- self.session.commit()
- del self.session
+ self.assertTrue(os.path.isfile(key_rsa))
+ self.assertTrue(os.path.isfile(key_dsa))
+ self.assertTrue(os.path.isfile(key_ed25519))
def test_ssh_default(self):
# Check if SSH service runs with default settings - used for checking
# behavior of <defaultValue> in XML definition
- self.session.set(base_path)
+ self.cli_set(base_path)
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check configured port
port = get_config_value('Port')[0]
@@ -69,15 +72,15 @@ class TestServiceSSH(unittest.TestCase):
def test_ssh_single_listen_address(self):
# Check if SSH service can be configured and runs
- self.session.set(base_path + ['port', '1234'])
- self.session.set(base_path + ['disable-host-validation'])
- self.session.set(base_path + ['disable-password-authentication'])
- self.session.set(base_path + ['loglevel', 'verbose'])
- self.session.set(base_path + ['client-keepalive-interval', '100'])
- self.session.set(base_path + ['listen-address', '127.0.0.1'])
+ self.cli_set(base_path + ['port', '1234'])
+ self.cli_set(base_path + ['disable-host-validation'])
+ self.cli_set(base_path + ['disable-password-authentication'])
+ self.cli_set(base_path + ['loglevel', 'verbose'])
+ self.cli_set(base_path + ['client-keepalive-interval', '100'])
+ self.cli_set(base_path + ['listen-address', '127.0.0.1'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check configured port
port = get_config_value('Port')[0]
@@ -109,16 +112,16 @@ class TestServiceSSH(unittest.TestCase):
def test_ssh_multiple_listen_addresses(self):
# Check if SSH service can be configured and runs with multiple
# listen ports and listen-addresses
- ports = ['22', '2222']
+ ports = ['22', '2222', '2223', '2224']
for port in ports:
- self.session.set(base_path + ['port', port])
+ self.cli_set(base_path + ['port', port])
addresses = ['127.0.0.1', '::1']
for address in addresses:
- self.session.set(base_path + ['listen-address', address])
+ self.cli_set(base_path + ['listen-address', address])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check configured port
tmp = get_config_value('Port')
@@ -136,17 +139,17 @@ class TestServiceSSH(unittest.TestCase):
def test_ssh_vrf(self):
# Check if SSH service can be bound to given VRF
port = '22'
- self.session.set(base_path + ['port', port])
- self.session.set(base_path + ['vrf', vrf])
+ self.cli_set(base_path + ['port', port])
+ self.cli_set(base_path + ['vrf', vrf])
# VRF does yet not exist - an error must be thrown
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
- self.session.set(['vrf', 'name', vrf, 'table', '1001'])
+ self.cli_set(['vrf', 'name', vrf, 'table', '1338'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check configured port
tmp = get_config_value('Port')
@@ -159,5 +162,8 @@ class TestServiceSSH(unittest.TestCase):
tmp = cmd(f'ip vrf pids {vrf}')
self.assertIn(PROCESS_NAME, tmp)
+ # delete VRF
+ self.cli_delete(['vrf', 'name', vrf])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_tftp-server.py b/smoketest/scripts/cli/test_service_tftp-server.py
index 82e5811ff..aed4c6beb 100755
--- a/smoketest/scripts/cli/test_service_tftp-server.py
+++ b/smoketest/scripts/cli/test_service_tftp-server.py
@@ -14,11 +14,10 @@
# 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 re
-import os
import unittest
from psutil import process_iter
+from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
@@ -32,28 +31,26 @@ dummy_if_path = ['interfaces', 'dummy', 'dum69']
address_ipv4 = '192.0.2.1'
address_ipv6 = '2001:db8::1'
-class TestServiceTFTPD(unittest.TestCase):
+class TestServiceTFTPD(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
- self.session.set(dummy_if_path + ['address', address_ipv4 + '/32'])
- self.session.set(dummy_if_path + ['address', address_ipv6 + '/128'])
+ self.cli_set(dummy_if_path + ['address', address_ipv4 + '/32'])
+ self.cli_set(dummy_if_path + ['address', address_ipv6 + '/128'])
def tearDown(self):
- self.session.delete(base_path)
- self.session.delete(dummy_if_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_delete(dummy_if_path)
+ self.cli_commit()
def test_01_tftpd_single(self):
directory = '/tmp'
port = '69' # default port
- self.session.set(base_path + ['allow-upload'])
- self.session.set(base_path + ['directory', directory])
- self.session.set(base_path + ['listen-address', address_ipv4])
+ self.cli_set(base_path + ['allow-upload'])
+ self.cli_set(base_path + ['directory', directory])
+ self.cli_set(base_path + ['listen-address', address_ipv4])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file('/etc/default/tftpd0')
# verify listen IP address
@@ -71,13 +68,13 @@ class TestServiceTFTPD(unittest.TestCase):
address = [address_ipv4, address_ipv6]
port = '70'
- self.session.set(base_path + ['directory', directory])
+ self.cli_set(base_path + ['directory', directory])
for addr in address:
- self.session.set(base_path + ['listen-address', addr])
- self.session.set(base_path + ['port', port])
+ self.cli_set(base_path + ['listen-address', addr])
+ self.cli_set(base_path + ['port', port])
# commit changes
- self.session.commit()
+ self.cli_commit()
for idx in range(0, len(address)):
config = read_file(f'/etc/default/tftpd{idx}')
diff --git a/smoketest/scripts/cli/test_service_webproxy.py b/smoketest/scripts/cli/test_service_webproxy.py
index 3db2daa8f..d47bd452d 100755
--- a/smoketest/scripts/cli/test_service_webproxy.py
+++ b/smoketest/scripts/cli/test_service_webproxy.py
@@ -14,9 +14,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.util import cmd
@@ -29,23 +30,21 @@ base_path = ['service', 'webproxy']
listen_if = 'dum3632'
listen_ip = '192.0.2.1'
-class TestServiceWebProxy(unittest.TestCase):
+class TestServiceWebProxy(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
- self.session.set(['interfaces', 'dummy', listen_if, 'address', listen_ip + '/32'])
+ self.cli_set(['interfaces', 'dummy', listen_if, 'address', listen_ip + '/32'])
def tearDown(self):
- self.session.delete(['interfaces', 'dummy', listen_if])
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(['interfaces', 'dummy', listen_if])
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_01_basic_proxy(self):
default_cache = '100'
- self.session.set(base_path + ['listen-address', listen_ip])
+ self.cli_set(base_path + ['listen-address', listen_ip])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(PROXY_CONF)
self.assertIn(f'http_port {listen_ip}:3128 intercept', config)
@@ -84,24 +83,24 @@ class TestServiceWebProxy(unittest.TestCase):
block_mine = ['application/pdf', 'application/x-sh']
body_max_size = '4096'
- self.session.set(base_path + ['listen-address', listen_ip])
- self.session.set(base_path + ['append-domain', domain])
- self.session.set(base_path + ['default-port', port])
- self.session.set(base_path + ['cache-size', cache_size])
- self.session.set(base_path + ['disable-access-log'])
+ self.cli_set(base_path + ['listen-address', listen_ip])
+ self.cli_set(base_path + ['append-domain', domain])
+ self.cli_set(base_path + ['default-port', port])
+ self.cli_set(base_path + ['cache-size', cache_size])
+ self.cli_set(base_path + ['disable-access-log'])
- self.session.set(base_path + ['minimum-object-size', min_obj_size])
- self.session.set(base_path + ['maximum-object-size', max_obj_size])
+ self.cli_set(base_path + ['minimum-object-size', min_obj_size])
+ self.cli_set(base_path + ['maximum-object-size', max_obj_size])
- self.session.set(base_path + ['outgoing-address', listen_ip])
+ self.cli_set(base_path + ['outgoing-address', listen_ip])
for mime in block_mine:
- self.session.set(base_path + ['reply-block-mime', mime])
+ self.cli_set(base_path + ['reply-block-mime', mime])
- self.session.set(base_path + ['reply-body-max-size', body_max_size])
+ self.cli_set(base_path + ['reply-body-max-size', body_max_size])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(PROXY_CONF)
self.assertIn(f'http_port {listen_ip}:{port} intercept', config)
@@ -132,34 +131,34 @@ class TestServiceWebProxy(unittest.TestCase):
ldap_attr = 'cn'
ldap_filter = '(cn=%s)'
- self.session.set(base_path + ['listen-address', listen_ip, 'disable-transparent'])
- self.session.set(base_path + ['authentication', 'children', auth_children])
- self.session.set(base_path + ['authentication', 'credentials-ttl', cred_ttl])
+ self.cli_set(base_path + ['listen-address', listen_ip, 'disable-transparent'])
+ self.cli_set(base_path + ['authentication', 'children', auth_children])
+ self.cli_set(base_path + ['authentication', 'credentials-ttl', cred_ttl])
- self.session.set(base_path + ['authentication', 'realm', realm])
- self.session.set(base_path + ['authentication', 'method', 'ldap'])
+ self.cli_set(base_path + ['authentication', 'realm', realm])
+ self.cli_set(base_path + ['authentication', 'method', 'ldap'])
# check validate() - LDAP authentication is enabled, but server not set
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + ['authentication', 'ldap', 'server', ldap_server])
+ self.cli_commit()
+ self.cli_set(base_path + ['authentication', 'ldap', 'server', ldap_server])
# check validate() - LDAP password can not be set when bind-dn is not define
- self.session.set(base_path + ['authentication', 'ldap', 'password', ldap_password])
+ self.cli_set(base_path + ['authentication', 'ldap', 'password', ldap_password])
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + ['authentication', 'ldap', 'bind-dn', ldap_bind_dn])
+ self.cli_commit()
+ self.cli_set(base_path + ['authentication', 'ldap', 'bind-dn', ldap_bind_dn])
# check validate() - LDAP base-dn must be set
with self.assertRaises(ConfigSessionError):
- self.session.commit()
- self.session.set(base_path + ['authentication', 'ldap', 'base-dn', ldap_base_dn])
+ self.cli_commit()
+ self.cli_set(base_path + ['authentication', 'ldap', 'base-dn', ldap_base_dn])
- self.session.set(base_path + ['authentication', 'ldap', 'username-attribute', ldap_attr])
- self.session.set(base_path + ['authentication', 'ldap', 'filter-expression', ldap_filter])
- self.session.set(base_path + ['authentication', 'ldap', 'use-ssl'])
+ self.cli_set(base_path + ['authentication', 'ldap', 'username-attribute', ldap_attr])
+ self.cli_set(base_path + ['authentication', 'ldap', 'filter-expression', ldap_filter])
+ self.cli_set(base_path + ['authentication', 'ldap', 'use-ssl'])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(PROXY_CONF)
self.assertIn(f'http_port {listen_ip}:3128', config) # disable-transparent
@@ -175,7 +174,7 @@ class TestServiceWebProxy(unittest.TestCase):
self.assertTrue(process_named_running(PROCESS_NAME))
def test_04_cache_peer(self):
- self.session.set(base_path + ['listen-address', listen_ip])
+ self.cli_set(base_path + ['listen-address', listen_ip])
cache_peers = {
'foo' : '192.0.2.1',
@@ -183,12 +182,12 @@ class TestServiceWebProxy(unittest.TestCase):
'baz' : '192.0.2.3',
}
for peer in cache_peers:
- self.session.set(base_path + ['cache-peer', peer, 'address', cache_peers[peer]])
+ self.cli_set(base_path + ['cache-peer', peer, 'address', cache_peers[peer]])
if peer == 'baz':
- self.session.set(base_path + ['cache-peer', peer, 'type', 'sibling'])
+ self.cli_set(base_path + ['cache-peer', peer, 'type', 'sibling'])
# commit changes
- self.session.commit()
+ self.cli_commit()
config = read_file(PROXY_CONF)
self.assertIn('never_direct allow all', config)
@@ -214,22 +213,22 @@ class TestServiceWebProxy(unittest.TestCase):
local_ok = ['10.0.0.0', 'vyos.net']
local_ok_url = ['vyos.net', 'vyos.io']
- self.session.set(base_path + ['listen-address', listen_ip])
- self.session.set(base_path + ['url-filtering', 'squidguard', 'log', 'all'])
+ self.cli_set(base_path + ['listen-address', listen_ip])
+ self.cli_set(base_path + ['url-filtering', 'squidguard', 'log', 'all'])
for block in local_block:
- self.session.set(base_path + ['url-filtering', 'squidguard', 'local-block', block])
+ self.cli_set(base_path + ['url-filtering', 'squidguard', 'local-block', block])
for ok in local_ok:
- self.session.set(base_path + ['url-filtering', 'squidguard', 'local-ok', ok])
+ self.cli_set(base_path + ['url-filtering', 'squidguard', 'local-ok', ok])
for url in local_block_url:
- self.session.set(base_path + ['url-filtering', 'squidguard', 'local-block-url', url])
+ self.cli_set(base_path + ['url-filtering', 'squidguard', 'local-block-url', url])
for url in local_ok_url:
- self.session.set(base_path + ['url-filtering', 'squidguard', 'local-ok-url', url])
+ self.cli_set(base_path + ['url-filtering', 'squidguard', 'local-ok-url', url])
for pattern in local_block_pattern:
- self.session.set(base_path + ['url-filtering', 'squidguard', 'local-block-keyword', pattern])
+ self.cli_set(base_path + ['url-filtering', 'squidguard', 'local-block-keyword', pattern])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check regular Squid config
config = read_file(PROXY_CONF)
diff --git a/smoketest/scripts/cli/test_system_acceleration_qat.py b/smoketest/scripts/cli/test_system_acceleration_qat.py
index cadb263f5..9584888d6 100755
--- a/smoketest/scripts/cli/test_system_acceleration_qat.py
+++ b/smoketest/scripts/cli/test_system_acceleration_qat.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 Francois Mertz fireboxled@gmail.com
+# Copyright (C) 2020-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -14,34 +14,31 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
base_path = ['system', 'acceleration', 'qat']
-class TestSystemLCD(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestIntelQAT(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
- def test_basic(self):
- """ Check if configuration script is in place and that the config
- script throws an error as QAT device is not present in Qemu. This *must*
- be extended with QAT autodetection once run on a QAT enabled device """
+ def test_simple_unsupported(self):
+ # Check if configuration script is in place and that the config script
+ # throws an error as QAT device is not present in Qemu. This *must* be
+ # extended with QAT autodetection once run on a QAT enabled device
# configure some system display
- self.session.set(base_path)
+ self.cli_set(base_path)
# An error must be thrown if QAT device could not be found
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py
index 8fc18ba88..e98a4e234 100755
--- a/smoketest/scripts/cli/test_system_ip.py
+++ b/smoketest/scripts/cli/test_system_ip.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 Francois Mertz fireboxled@gmail.com
+# Copyright (C) 2020 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -14,22 +14,18 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.util import read_file
base_path = ['system', 'ip']
-class TestSystemIP(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestSystemIP(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_system_ip_forwarding(self):
# Test if IPv4 forwarding can be disabled globally, default is '1'
@@ -37,8 +33,8 @@ class TestSystemIP(unittest.TestCase):
all_forwarding = '/proc/sys/net/ipv4/conf/all/forwarding'
self.assertEqual(read_file(all_forwarding), '1')
- self.session.set(base_path + ['disable-forwarding'])
- self.session.commit()
+ self.cli_set(base_path + ['disable-forwarding'])
+ self.cli_commit()
self.assertEqual(read_file(all_forwarding), '0')
@@ -50,9 +46,9 @@ class TestSystemIP(unittest.TestCase):
self.assertEqual(read_file(use_neigh), '0')
self.assertEqual(read_file(hash_policy), '0')
- self.session.set(base_path + ['multipath', 'ignore-unreachable-nexthops'])
- self.session.set(base_path + ['multipath', 'layer4-hashing'])
- self.session.commit()
+ self.cli_set(base_path + ['multipath', 'ignore-unreachable-nexthops'])
+ self.cli_set(base_path + ['multipath', 'layer4-hashing'])
+ self.cli_commit()
self.assertEqual(read_file(use_neigh), '1')
self.assertEqual(read_file(hash_policy), '1')
@@ -69,8 +65,8 @@ class TestSystemIP(unittest.TestCase):
self.assertEqual(read_file(gc_thresh1), '1024')
for size in [1024, 2048, 4096, 8192, 16384, 32768]:
- self.session.set(base_path + ['arp', 'table-size', str(size)])
- self.session.commit()
+ self.cli_set(base_path + ['arp', 'table-size', str(size)])
+ self.cli_commit()
self.assertEqual(read_file(gc_thresh3), str(size))
self.assertEqual(read_file(gc_thresh2), str(size // 2))
diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py
new file mode 100755
index 000000000..c9c9e833d
--- /dev/null
+++ b/smoketest/scripts/cli/test_system_ipv6.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSession
+from vyos.util import read_file
+
+base_path = ['system', 'ipv6']
+
+file_forwarding = '/proc/sys/net/ipv6/conf/all/forwarding'
+file_disable = '/etc/modprobe.d/vyos_disable_ipv6.conf'
+file_dad = '/proc/sys/net/ipv6/conf/all/accept_dad'
+file_multipath = '/proc/sys/net/ipv6/fib_multipath_hash_policy'
+
+class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_system_ipv6_forwarding(self):
+ # Test if IPv6 forwarding can be disabled globally, default is '1'
+ # which means forwearding enabled
+ self.assertEqual(read_file(file_forwarding), '1')
+
+ self.cli_set(base_path + ['disable-forwarding'])
+ self.cli_commit()
+
+ self.assertEqual(read_file(file_forwarding), '0')
+
+ def test_system_ipv6_disable(self):
+ # Do not assign any IPv6 address on interfaces, this requires a reboot
+ # which can not be tested, but we can read the config file :)
+ self.cli_set(base_path + ['disable'])
+ self.cli_commit()
+
+ # Verify configuration file
+ self.assertEqual(read_file(file_disable), 'options ipv6 disable_ipv6=1')
+
+ def test_system_ipv6_strict_dad(self):
+ # This defaults to 1
+ self.assertEqual(read_file(file_dad), '1')
+
+ # Do not assign any IPv6 address on interfaces, this requires a reboot
+ # which can not be tested, but we can read the config file :)
+ self.cli_set(base_path + ['strict-dad'])
+ self.cli_commit()
+
+ # Verify configuration file
+ self.assertEqual(read_file(file_dad), '2')
+
+ def test_system_ipv6_multipath(self):
+ # This defaults to 0
+ self.assertEqual(read_file(file_multipath), '0')
+
+ # Do not assign any IPv6 address on interfaces, this requires a reboot
+ # which can not be tested, but we can read the config file :)
+ self.cli_set(base_path + ['multipath', 'layer4-hashing'])
+ self.cli_commit()
+
+ # Verify configuration file
+ self.assertEqual(read_file(file_multipath), '1')
+
+ def test_system_ipv6_neighbor_table_size(self):
+ # Maximum number of entries to keep in the ARP cache, the
+ # default is 8192
+
+ gc_thresh3 = '/proc/sys/net/ipv6/neigh/default/gc_thresh3'
+ gc_thresh2 = '/proc/sys/net/ipv6/neigh/default/gc_thresh2'
+ gc_thresh1 = '/proc/sys/net/ipv6/neigh/default/gc_thresh1'
+ self.assertEqual(read_file(gc_thresh3), '8192')
+ self.assertEqual(read_file(gc_thresh2), '4096')
+ self.assertEqual(read_file(gc_thresh1), '1024')
+
+ for size in [1024, 2048, 4096, 8192, 16384, 32768]:
+ self.cli_set(base_path + ['neighbor', 'table-size', str(size)])
+ self.cli_commit()
+
+ self.assertEqual(read_file(gc_thresh3), str(size))
+ self.assertEqual(read_file(gc_thresh2), str(size // 2))
+ self.assertEqual(read_file(gc_thresh1), str(size // 8))
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_lcd.py b/smoketest/scripts/cli/test_system_lcd.py
index 2bf601e3b..7a39e2986 100755
--- a/smoketest/scripts/cli/test_system_lcd.py
+++ b/smoketest/scripts/cli/test_system_lcd.py
@@ -14,32 +14,29 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
from configparser import ConfigParser
+
from vyos.configsession import ConfigSession
from vyos.util import process_named_running
config_file = '/run/LCDd/LCDd.conf'
base_path = ['system', 'lcd']
-class TestSystemLCD(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestSystemLCD(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_system_display(self):
# configure some system display
- self.session.set(base_path + ['device', 'ttyS1'])
- self.session.set(base_path + ['model', 'cfa-533'])
+ self.cli_set(base_path + ['device', 'ttyS1'])
+ self.cli_set(base_path + ['model', 'cfa-533'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# load up ini-styled LCDd.conf
conf = ConfigParser()
diff --git a/smoketest/scripts/cli/test_system_login.py b/smoketest/scripts/cli/test_system_login.py
index 6188cf38b..aa97511e0 100755
--- a/smoketest/scripts/cli/test_system_login.py
+++ b/smoketest/scripts/cli/test_system_login.py
@@ -14,47 +14,46 @@
# 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 re
import platform
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from distutils.version import LooseVersion
from platform import release as kernel_version
from subprocess import Popen, PIPE
from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
from vyos.util import cmd
from vyos.util import read_file
+from vyos.template import inc_ip
base_path = ['system', 'login']
users = ['vyos1', 'vyos2']
-class TestSystemLogin(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestSystemLogin(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
# Delete individual users from configuration
for user in users:
- self.session.delete(base_path + ['user', user])
+ self.cli_delete(base_path + ['user', user])
- self.session.commit()
- del self.session
+ self.cli_commit()
- def test_local_user(self):
+ def test_system_login_user(self):
# Check if user can be created and we can SSH to localhost
- self.session.set(['service', 'ssh', 'port', '22'])
+ self.cli_set(['service', 'ssh', 'port', '22'])
for user in users:
name = "VyOS Roxx " + user
home_dir = "/tmp/" + user
- self.session.set(base_path + ['user', user, 'authentication', 'plaintext-password', user])
- self.session.set(base_path + ['user', user, 'full-name', 'VyOS Roxx'])
- self.session.set(base_path + ['user', user, 'home-directory', home_dir])
+ self.cli_set(base_path + ['user', user, 'authentication', 'plaintext-password', user])
+ self.cli_set(base_path + ['user', user, 'full-name', 'VyOS Roxx'])
+ self.cli_set(base_path + ['user', user, 'home-directory', home_dir])
- self.session.commit()
+ self.cli_commit()
for user in users:
cmd = ['su','-', user]
@@ -82,7 +81,7 @@ class TestSystemLogin(unittest.TestCase):
for option in options:
self.assertIn(f'{option}=y', kernel_config)
- def test_radius_config(self):
+ def test_system_login_radius_ipv4(self):
# Verify generated RADIUS configuration files
radius_key = 'VyOSsecretVyOS'
@@ -91,12 +90,18 @@ class TestSystemLogin(unittest.TestCase):
radius_port = '2000'
radius_timeout = '1'
- self.session.set(base_path + ['radius', 'server', radius_server, 'key', radius_key])
- self.session.set(base_path + ['radius', 'server', radius_server, 'port', radius_port])
- self.session.set(base_path + ['radius', 'server', radius_server, 'timeout', radius_timeout])
- self.session.set(base_path + ['radius', 'source-address', radius_source])
+ self.cli_set(base_path + ['radius', 'server', radius_server, 'key', radius_key])
+ self.cli_set(base_path + ['radius', 'server', radius_server, 'port', radius_port])
+ self.cli_set(base_path + ['radius', 'server', radius_server, 'timeout', radius_timeout])
+ self.cli_set(base_path + ['radius', 'source-address', radius_source])
+ self.cli_set(base_path + ['radius', 'source-address', inc_ip(radius_source, 1)])
+
+ # check validate() - Only one IPv4 source-address supported
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['radius', 'source-address', inc_ip(radius_source, 1)])
- self.session.commit()
+ self.cli_commit()
# this file must be read with higher permissions
pam_radius_auth_conf = cmd('sudo cat /etc/pam_radius_auth.conf')
@@ -130,5 +135,59 @@ class TestSystemLogin(unittest.TestCase):
tmp = re.findall(r'group:\s+mapname\s+files', nsswitch_conf)
self.assertTrue(tmp)
+ def test_system_login_radius_ipv6(self):
+ # Verify generated RADIUS configuration files
+
+ radius_key = 'VyOS-VyOS'
+ radius_server = '2001:db8::1'
+ radius_source = '::1'
+ radius_port = '4000'
+ radius_timeout = '4'
+
+ self.cli_set(base_path + ['radius', 'server', radius_server, 'key', radius_key])
+ self.cli_set(base_path + ['radius', 'server', radius_server, 'port', radius_port])
+ self.cli_set(base_path + ['radius', 'server', radius_server, 'timeout', radius_timeout])
+ self.cli_set(base_path + ['radius', 'source-address', radius_source])
+ self.cli_set(base_path + ['radius', 'source-address', inc_ip(radius_source, 1)])
+
+ # check validate() - Only one IPv4 source-address supported
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['radius', 'source-address', inc_ip(radius_source, 1)])
+
+ self.cli_commit()
+
+ # this file must be read with higher permissions
+ pam_radius_auth_conf = cmd('sudo cat /etc/pam_radius_auth.conf')
+ tmp = re.findall(r'\n?\[{}\]:{}\s+{}\s+{}\s+\[{}\]'.format(radius_server,
+ radius_port, radius_key, radius_timeout,
+ radius_source), pam_radius_auth_conf)
+ self.assertTrue(tmp)
+
+ # required, static options
+ self.assertIn('priv-lvl 15', pam_radius_auth_conf)
+ self.assertIn('mapped_priv_user radius_priv_user', pam_radius_auth_conf)
+
+ # PAM
+ pam_common_account = read_file('/etc/pam.d/common-account')
+ self.assertIn('pam_radius_auth.so', pam_common_account)
+
+ pam_common_auth = read_file('/etc/pam.d/common-auth')
+ self.assertIn('pam_radius_auth.so', pam_common_auth)
+
+ pam_common_session = read_file('/etc/pam.d/common-session')
+ self.assertIn('pam_radius_auth.so', pam_common_session)
+
+ pam_common_session_noninteractive = read_file('/etc/pam.d/common-session-noninteractive')
+ self.assertIn('pam_radius_auth.so', pam_common_session_noninteractive)
+
+ # NSS
+ nsswitch_conf = read_file('/etc/nsswitch.conf')
+ tmp = re.findall(r'passwd:\s+mapuid\s+files\s+mapname', nsswitch_conf)
+ self.assertTrue(tmp)
+
+ tmp = re.findall(r'group:\s+mapname\s+files', nsswitch_conf)
+ self.assertTrue(tmp)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_nameserver.py b/smoketest/scripts/cli/test_system_nameserver.py
index 5610c90c7..50dc466c2 100755
--- a/smoketest/scripts/cli/test_system_nameserver.py
+++ b/smoketest/scripts/cli/test_system_nameserver.py
@@ -14,12 +14,15 @@
# 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 re
import unittest
-from vyos.configsession import ConfigSession, ConfigSessionError
-import vyos.util as util
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+
+from vyos.util import read_file
RESOLV_CONF = '/etc/resolv.conf'
@@ -27,25 +30,20 @@ test_servers = ['192.0.2.10', '2001:db8:1::100']
base_path = ['system', 'name-server']
def get_name_servers():
- resolv_conf = util.read_file(RESOLV_CONF)
+ resolv_conf = read_file(RESOLV_CONF)
return re.findall(r'\n?nameserver\s+(.*)', resolv_conf)
-class TestSystemNameServer(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestSystemNameServer(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
# Delete existing name servers
- self.session.delete(base_path)
- self.session.commit()
-
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_nameserver_add(self):
# Check if server is added to resolv.conf
for s in test_servers:
- self.session.set(base_path + [s])
- self.session.commit()
+ self.cli_set(base_path + [s])
+ self.cli_commit()
servers = get_name_servers()
for s in servers:
@@ -54,8 +52,8 @@ class TestSystemNameServer(unittest.TestCase):
def test_nameserver_delete(self):
# Test if a deleted server disappears from resolv.conf
for s in test_servers:
- self.session.delete(base_path + [s])
- self.session.commit()
+ self.cli_delete(base_path + [s])
+ self.cli_commit()
servers = get_name_servers()
for s in servers:
diff --git a/smoketest/scripts/cli/test_system_ntp.py b/smoketest/scripts/cli/test_system_ntp.py
index 7d1bc144f..2b86ebd7c 100755
--- a/smoketest/scripts/cli/test_system_ntp.py
+++ b/smoketest/scripts/cli/test_system_ntp.py
@@ -15,9 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.template import address_from_cidr
@@ -26,7 +27,7 @@ from vyos.util import read_file
from vyos.util import process_named_running
PROCESS_NAME = 'ntpd'
-NTP_CONF = '/etc/ntp.conf'
+NTP_CONF = '/run/ntpd/ntpd.conf'
base_path = ['system', 'ntp']
def get_config_value(key):
@@ -35,17 +36,17 @@ def get_config_value(key):
# remove possible trailing whitespaces
return [item.strip() for item in tmp]
-class TestSystemNTP(unittest.TestCase):
+class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.session = ConfigSession(os.getpid())
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
- self.session.delete(base_path)
+ self.cli_delete(base_path)
def tearDown(self):
- self.session.delete(base_path)
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ self.assertFalse(process_named_running(PROCESS_NAME))
def test_ntp_options(self):
# Test basic NTP support with multiple servers and their options
@@ -55,13 +56,13 @@ class TestSystemNTP(unittest.TestCase):
for server in servers:
for option in options:
- self.session.set(base_path + ['server', server, option])
+ self.cli_set(base_path + ['server', server, option])
# Test NTP pool
- self.session.set(base_path + ['server', ntp_pool, 'pool'])
+ self.cli_set(base_path + ['server', ntp_pool, 'pool'])
# commit changes
- self.session.commit()
+ self.cli_commit()
# Check generated configuration
tmp = get_config_value('server')
@@ -77,19 +78,23 @@ class TestSystemNTP(unittest.TestCase):
def test_ntp_clients(self):
# Test the allowed-networks statement
+ listen_address = ['127.0.0.1', '::1']
+ for listen in listen_address:
+ self.cli_set(base_path + ['listen-address', listen])
+
networks = ['192.0.2.0/24', '2001:db8:1000::/64']
for network in networks:
- self.session.set(base_path + ['allow-clients', 'address', network])
+ self.cli_set(base_path + ['allow-clients', 'address', network])
# Verify "NTP server not configured" verify() statement
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
servers = ['192.0.2.1', '192.0.2.2']
for server in servers:
- self.session.set(base_path + ['server', server])
+ self.cli_set(base_path + ['server', server])
- self.session.commit()
+ self.cli_commit()
# Check generated client address configuration
for network in networks:
@@ -102,7 +107,9 @@ class TestSystemNTP(unittest.TestCase):
# Check listen address
tmp = get_config_value('interface')
- test = ['ignore wildcard', 'listen 127.0.0.1', 'listen ::1']
+ test = ['ignore wildcard']
+ for listen in listen_address:
+ test.append(f'listen {listen}')
self.assertEqual(tmp, test)
# Check for running process
diff --git a/smoketest/scripts/cli/test_vpn_openconnect.py b/smoketest/scripts/cli/test_vpn_openconnect.py
index e27216e09..bf528c8b7 100755
--- a/smoketest/scripts/cli/test_vpn_openconnect.py
+++ b/smoketest/scripts/cli/test_vpn_openconnect.py
@@ -14,9 +14,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+
from vyos.configsession import ConfigSession
from vyos.util import process_named_running
@@ -25,29 +26,24 @@ base_path = ['vpn', 'openconnect']
cert = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
cert_key = '/etc/ssl/private/ssl-cert-snakeoil.key'
-class TestVpnOpenconnect(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
-
+class TestVpnOpenconnect(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
# Delete vpn openconnect configuration
- self.session.delete(base_path)
- self.session.commit()
-
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
def test_vpn(self):
user = 'vyos_user'
password = 'vyos_pass'
- self.session.delete(base_path)
- self.session.set(base_path + ["authentication", "local-users", "username", user, "password", password])
- self.session.set(base_path + ["authentication", "mode", "local"])
- self.session.set(base_path + ["network-settings", "client-ip-settings", "subnet", "192.0.2.0/24"])
- self.session.set(base_path + ["ssl", "ca-cert-file", cert])
- self.session.set(base_path + ["ssl", "cert-file", cert])
- self.session.set(base_path + ["ssl", "key-file", cert_key])
-
- self.session.commit()
+ self.cli_delete(base_path)
+ self.cli_set(base_path + ["authentication", "local-users", "username", user, "password", password])
+ self.cli_set(base_path + ["authentication", "mode", "local"])
+ self.cli_set(base_path + ["network-settings", "client-ip-settings", "subnet", "192.0.2.0/24"])
+ self.cli_set(base_path + ["ssl", "ca-cert-file", cert])
+ self.cli_set(base_path + ["ssl", "cert-file", cert])
+ self.cli_set(base_path + ["ssl", "key-file", cert_key])
+
+ self.cli_commit()
# Check for running process
self.assertTrue(process_named_running('ocserv-main'))
diff --git a/smoketest/scripts/cli/test_vpn_sstp.py b/smoketest/scripts/cli/test_vpn_sstp.py
index 95fe38dd9..033338685 100755
--- a/smoketest/scripts/cli/test_vpn_sstp.py
+++ b/smoketest/scripts/cli/test_vpn_sstp.py
@@ -23,18 +23,14 @@ ca_cert = '/tmp/ca.crt'
ssl_cert = '/tmp/server.crt'
ssl_key = '/tmp/server.key'
-class TestVPNSSTPServer(BasicAccelPPPTest.BaseTest):
+class TestVPNSSTPServer(BasicAccelPPPTest.TestCase):
def setUp(self):
self._base_path = ['vpn', 'sstp']
self._process_name = 'accel-pppd'
self._config_file = '/run/accel-pppd/sstp.conf'
self._chap_secrets = '/run/accel-pppd/sstp.chap-secrets'
-
super().setUp()
- def tearDown(self):
- super().tearDown()
-
def basic_config(self):
# SSL is mandatory
self.set(['ssl', 'ca-cert-file', ca_cert])
diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py
index 7bcfea861..591630c46 100755
--- a/smoketest/scripts/cli/test_vrf.py
+++ b/smoketest/scripts/cli/test_vrf.py
@@ -14,53 +14,151 @@
# 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 re
import os
+import json
import unittest
-from vyos.configsession import ConfigSession, ConfigSessionError
+from netifaces import interfaces
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+from vyos.ifconfig import Interface
+from vyos.ifconfig import Section
+from vyos.template import is_ipv6
+from vyos.util import cmd
from vyos.util import read_file
from vyos.validate import is_intf_addr_assigned
-class VRFTest(unittest.TestCase):
- def setUp(self):
- self.session = ConfigSession(os.getpid())
- self._vrfs = ['red', 'green', 'blue']
+base_path = ['vrf']
+vrfs = ['red', 'green', 'blue', 'foo-bar', 'baz_foo']
+
+class VRFTest(VyOSUnitTestSHIM.TestCase):
+ _interfaces = []
+
+ @classmethod
+ def setUpClass(cls):
+ # we need to filter out VLAN interfaces identified by a dot (.)
+ # in their name - just in case!
+ if 'TEST_ETH' in os.environ:
+ tmp = os.environ['TEST_ETH'].split()
+ cls._interfaces = tmp
+ else:
+ for tmp in Section.interfaces('ethernet'):
+ if not '.' in tmp:
+ cls._interfaces.append(tmp)
+ # call base-classes classmethod
+ super(cls, cls).setUpClass()
def tearDown(self):
# delete all VRFs
- self.session.delete(['vrf'])
- self.session.commit()
- del self.session
+ self.cli_delete(base_path)
+ self.cli_commit()
+ for vrf in vrfs:
+ self.assertNotIn(vrf, interfaces())
def test_vrf_table_id(self):
- table = 1000
- for vrf in self._vrfs:
- base = ['vrf', 'name', vrf]
- description = "VyOS-VRF-" + vrf
- self.session.set(base + ['description', description])
+ table = '1000'
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ description = f'VyOS-VRF-{vrf}'
+ self.cli_set(base + ['description', description])
# check validate() - a table ID is mandatory
with self.assertRaises(ConfigSessionError):
- self.session.commit()
+ self.cli_commit()
- self.session.set(base + ['table', str(table)])
- table += 1
+ self.cli_set(base + ['table', table])
+ if vrf == 'green':
+ self.cli_set(base + ['disable'])
+
+ table = str(int(table) + 1)
# commit changes
- self.session.commit()
+ self.cli_commit()
+
+ # Verify VRF configuration
+ table = '1000'
+ iproute2_config = read_file('/etc/iproute2/rt_tables.d/vyos-vrf.conf')
+ for vrf in vrfs:
+ description = f'VyOS-VRF-{vrf}'
+ self.assertTrue(vrf in interfaces())
+ vrf_if = Interface(vrf)
+ # validate proper interface description
+ self.assertEqual(vrf_if.get_alias(), description)
+ # validate admin up/down state of VRF
+ state = 'up'
+ if vrf == 'green':
+ state = 'down'
+ self.assertEqual(vrf_if.get_admin_state(), state)
+
+ # Test the iproute2 lookup file, syntax is as follows:
+ #
+ # # id vrf name comment
+ # 1000 red # VyOS-VRF-red
+ # 1001 green # VyOS-VRF-green
+ # ...
+ regex = f'{table}\s+{vrf}\s+#\s+{description}'
+ self.assertTrue(re.findall(regex, iproute2_config))
+ table = str(int(table) + 1)
def test_vrf_loopback_ips(self):
- table = 1000
- for vrf in self._vrfs:
- base = ['vrf', 'name', vrf]
- self.session.set(base + ['table', str(table)])
- table += 1
+ table = '2000'
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['table', str(table)])
+ table = str(int(table) + 1)
# commit changes
- self.session.commit()
- for vrf in self._vrfs:
+ self.cli_commit()
+
+ # Verify VRF configuration
+ for vrf in vrfs:
+ self.assertTrue(vrf in interfaces())
self.assertTrue(is_intf_addr_assigned(vrf, '127.0.0.1'))
self.assertTrue(is_intf_addr_assigned(vrf, '::1'))
+ def test_vrf_table_id_is_unalterable(self):
+ # Linux Kernel prohibits the change of a VRF table on the fly.
+ # VRF must be deleted and recreated!
+ table = '1000'
+ vrf = vrfs[0]
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['table', table])
+
+ # commit changes
+ self.cli_commit()
+
+ # Check if VRF has been created
+ self.assertTrue(vrf in interfaces())
+
+ table = str(int(table) + 1)
+ self.cli_set(base + ['table', table])
+ # check validate() - table ID can not be altered!
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ def test_vrf_assign_interface(self):
+ vrf = vrfs[0]
+ table = '5000'
+ self.cli_set(['vrf', 'name', vrf, 'table', table])
+
+ for interface in self._interfaces:
+ section = Section.section(interface)
+ self.cli_set(['interfaces', section, interface, 'vrf', vrf])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify & cleanup
+ for interface in self._interfaces:
+ # os.readlink resolves to: '../../../../../virtual/net/foovrf'
+ tmp = os.readlink(f'/sys/class/net/{interface}/master').split('/')[-1]
+ self.assertEqual(tmp, vrf)
+ # cleanup
+ section = Section.section(interface)
+ self.cli_delete(['interfaces', section, interface, 'vrf'])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/system/test_iproute2.py b/smoketest/scripts/system/test_iproute2.py
new file mode 100755
index 000000000..2d2fe195b
--- /dev/null
+++ b/smoketest/scripts/system/test_iproute2.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import unittest
+
+class TestIproute2(unittest.TestCase):
+ def test_ip_is_symlink(self):
+ # For an unknown reason VyOS 1.3.0-rc2 did not have a symlink from
+ # /usr/sbin/ip -> /bin/ip - verify this now and forever
+ real_file = '/bin/ip'
+ symlink = '/usr/sbin/ip'
+ self.assertTrue(os.path.islink(symlink))
+ self.assertFalse(os.path.islink(real_file))
+ self.assertEqual(os.readlink(symlink), real_file)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)