diff options
Diffstat (limited to 'smoketest')
27 files changed, 2983 insertions, 225 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 index df3ae015c..694243d1e 100644 --- a/smoketest/configs/bgp-big-as-cloud +++ b/smoketest/configs/bgp-big-as-cloud @@ -1186,6 +1186,10 @@ protocols { } } } + maximum-paths { + ebgp 8 + ibgp 16 + } neighbor 192.0.16.209 { address-family { ipv4-unicast { diff --git a/smoketest/configs/bgp-small-internet-exchange b/smoketest/configs/bgp-small-internet-exchange index de6213b50..d51f87c4a 100644 --- a/smoketest/configs/bgp-small-internet-exchange +++ b/smoketest/configs/bgp-small-internet-exchange @@ -11,6 +11,100 @@ interfaces { } } 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 @@ -21,6 +115,88 @@ policy { 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 @@ -31,6 +207,88 @@ policy { 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 @@ -43,6 +301,18 @@ policy { } } } + 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 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-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_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py index 1426e80c2..50cfa2607 100644 --- a/smoketest/scripts/cli/base_interfaces_test.py +++ b/smoketest/scripts/cli/base_interfaces_test.py @@ -14,7 +14,6 @@ import os import unittest -import json from binascii import hexlify @@ -30,6 +29,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 @@ -292,6 +292,42 @@ class BasicInterfaceTest: 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.session.set(base + option.split()) + + # disable the lower interface + self.session.set(base + ['disable']) + + for vlan in self._vlan_range: + vlan_base = self._base_path + [interface, 'vif', vlan] + # disable the vlan interface + self.session.set(vlan_base + ['disable']) + + self.session.commit() + + # re-enable all lower interfaces + for interface in self._interfaces: + base = self._base_path + [interface] + self.session.delete(base + ['disable']) + + self.session.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 @@ -317,7 +353,7 @@ class BasicInterfaceTest: 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: diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py index f64b527b3..7e10f12c4 100755 --- a/smoketest/scripts/cli/test_interfaces_bridge.py +++ b/smoketest/scripts/cli/test_interfaces_bridge.py @@ -99,6 +99,12 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest): self.session.set(base + ['enable-vlan']) super().test_vif_8021q_interfaces() + def test_vif_8021q_lower_up_down(self): + for interface in self._interfaces: + base = self._base_path + [interface] + self.session.set(base + ['enable-vlan']) + super().test_vif_8021q_interfaces() + def test_bridge_vlan_filter(self): vif_vlan = 2 diff --git a/smoketest/scripts/cli/test_interfaces_erspan.py b/smoketest/scripts/cli/test_interfaces_erspan.py index c180f0a34..4575c61ce 100755 --- a/smoketest/scripts/cli/test_interfaces_erspan.py +++ b/smoketest/scripts/cli/test_interfaces_erspan.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,65 +15,15 @@ # 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 vyos.util import get_interface_config from base_interfaces_test import BasicInterfaceTest mtu = 1500 -def erspan_conf(interface): - tmp = cmd(f'ip -d -j link show {interface}') - ''' - [ - { - "ifindex": 17, - "link": null, - "ifname": "ersp0", - "flags": [ - "BROADCAST", - "MULTICAST" - ], - "mtu": 1450, - "qdisc": "noop", - "operstate": "DOWN", - "linkmode": "DEFAULT", - "group": "default", - "txqlen": 1000, - "link_type": "ether", - "address": "22:27:14:7b:0d:79", - "broadcast": "ff:ff:ff:ff:ff:ff", - "promiscuity": 0, - "min_mtu": 68, - "max_mtu": 0, - "linkinfo": { - "info_kind": "erspan", - "info_data": { - "remote": "10.2.2.2", - "local": "10.1.1.1", - "ttl": 0, - "pmtudisc": true, - "ikey": "0.0.0.123", - "okey": "0.0.0.123", - "iseq": true, - "oseq": true, - "erspan_index": 0, - "erspan_ver": 1 - } - }, - "inet6_addr_gen_mode": "eui64", - "num_tx_queues": 1, - "num_rx_queues": 1, - "gso_max_size": 65536, - "gso_max_segs": 65535 - } - ] - ''' - return json.loads(tmp)[0] - class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest): def setUp(self): super().setUp() @@ -96,19 +46,19 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest): key = 123 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', self.remote_v4]) + self.session.set(self._base_path + [interface, 'source-address', self.local_v4]) + self.session.set(self._base_path + [interface, 'remote', self.remote_v4]) self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)]) self.session.commit() - conf = erspan_conf(interface) + conf = get_interface_config(interface) self.assertEqual(interface, conf['ifname']) self.assertEqual(encapsulation, conf['linkinfo']['info_kind']) self.assertEqual(mtu, conf['mtu']) - self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local']) - self.assertEqual(self.remote_v4, conf['linkinfo']['info_data']['remote']) + self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local']) + self.assertEqual(self.remote_v4, conf['linkinfo']['info_data']['remote']) def test_erspan_ipv6(self): @@ -117,19 +67,19 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest): key = 123 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', self.remote_v6]) + self.session.set(self._base_path + [interface, 'source-address', self.local_v6]) + self.session.set(self._base_path + [interface, 'remote', self.remote_v6]) self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)]) self.session.commit() - conf = erspan_conf(interface) + conf = get_interface_config(interface) self.assertEqual(interface, conf['ifname']) self.assertEqual(encapsulation, conf['linkinfo']['info_kind']) self.assertEqual(mtu, conf['mtu']) - self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local']) - self.assertEqual(self.remote_v6, conf['linkinfo']['info_data']['remote']) + self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local']) + self.assertEqual(self.remote_v6, conf['linkinfo']['info_data']['remote']) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_geneve.py b/smoketest/scripts/cli/test_interfaces_geneve.py index b708b5437..e8e8e5a2c 100755 --- a/smoketest/scripts/cli/test_interfaces_geneve.py +++ b/smoketest/scripts/cli/test_interfaces_geneve.py @@ -17,6 +17,9 @@ 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): @@ -28,8 +31,49 @@ class GeneveInterfaceTest(BasicInterfaceTest.BaseTest): 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'], } cls._interfaces = list(cls._options) + def test_geneve_parameters(self): + tos = '40' + ttl = 20 + for intf in self._interfaces: + for option in self._options.get(intf, []): + self.session.set(self._base_path + [intf] + option.split()) + + self.session.set(self._base_path + [intf, 'parameters', 'ip', 'dont-fragment']) + self.session.set(self._base_path + [intf, 'parameters', 'ip', 'tos', tos]) + self.session.set(self._base_path + [intf, 'parameters', 'ip', 'ttl', str(ttl)]) + ttl += 10 + + self.session.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 a89895b92..74fd4f6c6 100755 --- a/smoketest/scripts/cli/test_interfaces_l2tpv3.py +++ b/smoketest/scripts/cli/test_interfaces_l2tpv3.py @@ -27,12 +27,12 @@ class GeneveInterfaceTest(BasicInterfaceTest.BaseTest): cls._test_ipv6 = True cls._base_path = ['interfaces', 'l2tpv3'] cls._options = { - 'l2tpeth10': ['local-ip 127.0.0.1', 'remote-ip 127.10.10.10', + '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'], } diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py index 3a3e7bff3..31071a0f7 100755 --- a/smoketest/scripts/cli/test_interfaces_macsec.py +++ b/smoketest/scripts/cli/test_interfaces_macsec.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +import os import 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,6 +33,10 @@ def get_config_value(interface, key): tmp = re.findall(r'\n?{}=(.*)'.format(key), tmp) return tmp[0] +def get_cipher(interface): + tmp = get_interface_config(interface) + return tmp['linkinfo']['info_data']['cipher_suite'].lower() + class MACsecInterfaceTest(BasicInterfaceTest.BaseTest): @classmethod def setUpClass(cls): @@ -107,8 +114,30 @@ 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' + cipher = 'gcm-aes-128' + self.session.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']) + + # check validate() - cipher is mandatory + with self.assertRaises(ConfigSessionError): + self.session.commit() + self.session.set(self._base_path + [interface, 'security', 'cipher', cipher]) + + # final commit and verify + self.session.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.session.set(self._base_path + [interface]) # check validate() - source interface is mandatory @@ -119,11 +148,12 @@ class MACsecInterfaceTest(BasicInterfaceTest.BaseTest): # 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.session.set(self._base_path + [interface, 'security', 'cipher', cipher]) # final commit and verify self.session.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 diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py index a9250e3e5..3dddb5ef0 100755 --- a/smoketest/scripts/cli/test_interfaces_tunnel.py +++ b/smoketest/scripts/cli/test_interfaces_tunnel.py @@ -15,11 +15,11 @@ # 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 vyos.util import get_interface_config +from vyos.template import inc_ip from base_interfaces_test import BasicInterfaceTest @@ -28,38 +28,6 @@ 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): @classmethod def setUpClass(cls): @@ -70,8 +38,8 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): cls.local_v4 = '192.0.2.1' cls.local_v6 = '2001:db8::1' cls._options = { - 'tun10': ['encapsulation ipip', 'remote-ip 192.0.2.10', 'local-ip ' + cls.local_v4], - 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'local-ip ' + cls.local_v4], + '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) @@ -90,25 +58,25 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): interface = f'tun1000' local_if_addr = f'10.10.200.1/24' - for encapsulation in ['ipip', 'sit', 'gre', 'gre-bridge']: + for encapsulation in ['ipip', 'sit', 'gre', 'gretap']: 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]) + self.session.set(self._base_path + [interface, 'source-address', self.local_v6]) + self.session.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.session.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.session.set(self._base_path + [interface, 'remote', remote_ip4]) self.session.set(self._base_path + [interface, 'source-interface', source_if]) - # Source interface can not be used with sit and gre-bridge - if encapsulation in ['sit', 'gre-bridge']: + # Source interface can not be used with sit and gretap + if encapsulation in ['sit', 'gretap']: with self.assertRaises(ConfigSessionError): self.session.commit() self.session.delete(self._base_path + [interface, 'source-interface']) @@ -116,18 +84,15 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): # Check if commit is ok self.session.commit() - conf = tunnel_conf(interface) - self.assertEqual(interface, conf['ifname']) - self.assertEqual(mtu, conf['mtu']) - - if encapsulation not in ['sit', 'gre-bridge']: + conf = get_interface_config(interface) + if encapsulation not in ['sit', 'gretap']: self.assertEqual(source_if, conf['link']) - self.assertEqual(encapsulation, conf['link_type']) - elif encapsulation in ['gre-bridge']: - self.assertEqual('ether', conf['link_type']) + 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.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote']) self.assertTrue(conf['linkinfo']['info_data']['pmtudisc']) # cleanup this instance @@ -140,41 +105,49 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): interface = f'tun1010' local_if_addr = f'10.10.200.1/24' - for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre']: + for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre', 'ip6gretap']: 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]) + self.session.set(self._base_path + [interface, 'source-address', self.local_v4]) + self.session.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.session.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.session.set(self._base_path + [interface, 'remote', remote_ip6]) # Configure Tunnel Source interface self.session.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.session.commit() + self.session.delete(self._base_path + [interface, 'source-interface']) # Check if commit is ok self.session.commit() - conf = tunnel_conf(interface) + conf = get_interface_config(interface) + if encapsulation not in ['ip6gretap']: + self.assertEqual(source_if, conf['link']) + self.assertEqual(interface, conf['ifname']) self.assertEqual(mtu, conf['mtu']) - self.assertEqual(source_if, conf['link']) - # remap encapsulation protocol(s) - if encapsulation in ['ipip6', 'ip6ip6']: - encapsulation = 'tunnel6' - elif encapsulation in ['ip6gre']: - encapsulation = 'gre6' + # Not applicable for ip6gre + if 'proto' in conf['linkinfo']['info_data']: + self.assertEqual(encapsulation, conf['linkinfo']['info_data']['proto']) - self.assertEqual(encapsulation, conf['link_type']) + # remap encapsulation protocol(s) only for ipip6, ip6ip6 + if encapsulation in ['ipip6', 'ip6ip6']: + encapsulation = 'ip6tnl' + 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']) @@ -183,18 +156,18 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): self.session.commit() def test_tunnel_verify_local_dhcp(self): - # We can not use local-ip and dhcp-interface at the same time + # We can not use source-address and dhcp-interface at the same time interface = f'tun1020' local_if_addr = f'10.0.0.1/24' 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, 'source-address', self.local_v4]) + self.session.set(self._base_path + [interface, 'remote', remote_ip4]) self.session.set(self._base_path + [interface, 'dhcp-interface', 'eth0']) - # local-ip and dhcp-interface can not be used at the same time + # source-address 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']) @@ -209,8 +182,8 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): tos = '20' 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]) + self.session.set(self._base_path + [interface, 'source-address', self.local_v4]) + self.session.set(self._base_path + [interface, 'remote', remote_ip4]) self.session.set(self._base_path + [interface, 'parameters', 'ip', 'no-pmtu-discovery']) self.session.set(self._base_path + [interface, 'parameters', 'ip', 'key', gre_key]) @@ -219,14 +192,44 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): # Check if commit is ok self.session.commit() - conf = tunnel_conf(interface) + conf = get_interface_config(interface) self.assertEqual(mtu, conf['mtu']) self.assertEqual(interface, conf['ifname']) - self.assertEqual(encapsulation, conf['link_type']) + 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(0, conf['linkinfo']['info_data']['ttl']) self.assertFalse( conf['linkinfo']['info_data']['pmtudisc']) + def test_gretap_parameters_change(self): + interface = f'tun1040' + gre_key = '10' + encapsulation = 'gretap' + tos = '20' + + self.session.set(self._base_path + [interface, 'encapsulation', encapsulation]) + self.session.set(self._base_path + [interface, 'source-address', self.local_v4]) + self.session.set(self._base_path + [interface, 'remote', remote_ip4]) + + # Check if commit is ok + self.session.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(0, conf['linkinfo']['info_data']['ttl']) + + # Change remote ip address (inc host by 2 + new_remote = inc_ip(remote_ip4, 2) + self.session.set(self._base_path + [interface, 'remote', new_remote]) + # Check if commit is ok + self.session.commit() + + conf = get_interface_config(interface) + self.assertEqual(new_remote, conf['linkinfo']['info_data']['remote']) + if __name__ == '__main__': - unittest.main(verbosity=2) + unittest.main(verbosity=2, failfast=True) diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py index fcc1b15ce..2a04b0477 100755 --- a/smoketest/scripts/cli/test_interfaces_vxlan.py +++ b/smoketest/scripts/cli/test_interfaces_vxlan.py @@ -16,7 +16,10 @@ 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): @@ -27,10 +30,59 @@ class VXLANInterfaceTest(BasicInterfaceTest.BaseTest): cls._test_mtu = True cls._base_path = ['interfaces', 'vxlan'] cls._options = { - 'vxlan0': ['vni 10', 'remote 127.0.0.2'], - 'vxlan1': ['vni 20', 'group 239.1.1.1', 'source-interface eth0'], + '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'], } cls._interfaces = list(cls._options) + def test_vxlan_parameters(self): + tos = '40' + ttl = 20 + for intf in self._interfaces: + for option in self._options.get(intf, []): + self.session.set(self._base_path + [intf] + option.split()) + + self.session.set(self._base_path + [intf, 'parameters', 'ip', 'dont-fragment']) + self.session.set(self._base_path + [intf, 'parameters', 'ip', 'tos', tos]) + self.session.set(self._base_path + [intf, 'parameters', 'ip', 'ttl', str(ttl)]) + ttl += 10 + + self.session.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_nat66.py b/smoketest/scripts/cli/test_nat66.py index ccc4196e0..4838fb8d8 100755 --- a/smoketest/scripts/cli/test_nat66.py +++ b/smoketest/scripts/cli/test_nat66.py @@ -44,7 +44,7 @@ class TestNAT66(unittest.TestCase): translation_prefix = 'fc01::/64' self.session.set(src_path + ['rule', '1', 'outbound-interface', 'eth1']) self.session.set(src_path + ['rule', '1', 'source', 'prefix', source_prefix]) - self.session.set(src_path + ['rule', '1', 'translation', 'prefix', translation_prefix]) + self.session.set(src_path + ['rule', '1', 'translation', 'address', translation_prefix]) # check validate() - outbound-interface must be defined self.session.commit() @@ -70,6 +70,36 @@ class TestNAT66(unittest.TestCase): 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.session.set(src_path + ['rule', '1', 'outbound-interface', 'eth1']) + self.session.set(src_path + ['rule', '1', 'source', 'prefix', source_prefix]) + self.session.set(src_path + ['rule', '1', 'translation', 'address', translation_address]) + + # check validate() - outbound-interface must be defined + self.session.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' @@ -127,7 +157,6 @@ class TestNAT66(unittest.TestCase): # T2813: Ensure translation address is specified rule = '5' source_prefix = 'fc00::/64' - translation_prefix = 'fc00:2::/64' self.session.set(src_path + ['rule', rule, 'source', 'prefix', source_prefix]) # check validate() - outbound-interface must be defined @@ -139,7 +168,7 @@ class TestNAT66(unittest.TestCase): with self.assertRaises(ConfigSessionError): self.session.commit() - self.session.set(src_path + ['rule', rule, 'translation', 'prefix', translation_prefix]) + self.session.set(src_path + ['rule', rule, 'translation', 'address', 'masquerade']) self.session.commit() def test_nat66_no_rules(self): diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py new file mode 100755 index 000000000..8efbab7e5 --- /dev/null +++ b/smoketest/scripts/cli/test_policy.py @@ -0,0 +1,681 @@ +#!/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 vyos.util import cmd +from vyos.configsession import ConfigSession +from vyos.configsession import ConfigSessionError + +base_path = ['policy'] + +def getFRRconfig(section): + return cmd(f'vtysh -c "show run" | sed -n "/^{section}/,/^!/p"') + +class TestPolicy(unittest.TestCase): + def setUp(self): + self.session = ConfigSession(os.getpid()) + + def tearDown(self): + self.session.delete(base_path) + self.session.commit() + del self.session + + 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.session.set(path + ['description', f'VyOS-ACL-{acl}']) + if 'rule' not in acl_config: + continue + + for rule, rule_config in acl_config['rule'].items(): + self.session.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.session.set(path + ['rule', rule, direction, 'any']) + if 'host' in rule_config[direction]: + self.session.set(path + ['rule', rule, direction, 'host', rule_config[direction]['host']]) + if 'network' in rule_config[direction]: + self.session.set(path + ['rule', rule, direction, 'network', rule_config[direction]['network']]) + self.session.set(path + ['rule', rule, direction, 'inverse-mask', rule_config[direction]['inverse-mask']]) + + self.session.commit() + + config = getFRRconfig('access-list') + 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.session.set(path + ['description', f'VyOS-ACL-{acl}']) + if 'rule' not in acl_config: + continue + + for rule, rule_config in acl_config['rule'].items(): + self.session.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.session.set(path + ['rule', rule, direction, 'any']) + if 'network' in rule_config[direction]: + self.session.set(path + ['rule', rule, direction, 'network', rule_config[direction]['network']]) + if 'exact-match' in rule_config[direction]: + self.session.set(path + ['rule', rule, direction, 'exact-match']) + + self.session.commit() + + config = getFRRconfig('ipv6 access-list') + 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.session.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.session.set(path + ['rule', rule, 'action', rule_config['action']]) + if 'regex' in rule_config: + self.session.set(path + ['rule', rule, 'regex', rule_config['regex']]) + + self.session.commit() + + config = getFRRconfig('bgp as-path access-list') + 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.session.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.session.set(path + ['rule', rule, 'action', rule_config['action']]) + if 'regex' in rule_config: + self.session.set(path + ['rule', rule, 'regex', rule_config['regex']]) + + self.session.commit() + + config = getFRRconfig('bgp community-list') + 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.session.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.session.set(path + ['rule', rule, 'action', rule_config['action']]) + if 'regex' in rule_config: + self.session.set(path + ['rule', rule, 'regex', rule_config['regex']]) + + self.session.commit() + + config = getFRRconfig('bgp extcommunity-list') + 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.session.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.session.set(path + ['rule', rule, 'action', rule_config['action']]) + if 'regex' in rule_config: + self.session.set(path + ['rule', rule, 'regex', rule_config['regex']]) + + self.session.commit() + + config = getFRRconfig('bgp large-community-list') + 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.session.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.session.set(path + ['rule', rule, 'action', rule_config['action']]) + if 'prefix' in rule_config: + self.session.set(path + ['rule', rule, 'prefix', rule_config['prefix']]) + if 'ge' in rule_config: + self.session.set(path + ['rule', rule, 'ge', rule_config['ge']]) + if 'le' in rule_config: + self.session.set(path + ['rule', rule, 'le', rule_config['le']]) + + self.session.commit() + + config = getFRRconfig('ip prefix-list') + 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.session.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.session.set(path + ['rule', rule, 'action', rule_config['action']]) + if 'prefix' in rule_config: + self.session.set(path + ['rule', rule, 'prefix', rule_config['prefix']]) + if 'ge' in rule_config: + self.session.set(path + ['rule', rule, 'ge', rule_config['ge']]) + if 'le' in rule_config: + self.session.set(path + ['rule', rule, 'le', rule_config['le']]) + + self.session.commit() + + config = getFRRconfig('ipv6 prefix-list') + 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) + +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 index 044b4b92e..80e5daa7c 100755 --- a/smoketest/scripts/cli/test_protocols_bfd.py +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -25,38 +25,57 @@ from vyos.util import process_named_running PROCESS_NAME = 'bfdd' base_path = ['protocols', 'bfd'] -neighbor_config = { - '192.0.2.1' : { +dum_if = 'dum1001' +peers = { + '192.0.2.10' : { 'intv_rx' : '500', 'intv_tx' : '600', 'multihop' : '', 'source_addr': '192.0.2.254', }, - '192.0.2.2' : { + '192.0.2.20' : { 'echo_mode' : '', 'intv_echo' : '100', - 'intv_mult' : '111', + 'intv_mult' : '100', 'intv_rx' : '222', 'intv_tx' : '333', 'shutdown' : '', - 'source_intf': 'lo', + 'source_intf': dum_if, }, - '2001:db8::1' : { - 'source_addr': 'fe80::1', - 'source_intf': 'eth0', + '2001:db8::a' : { + 'source_addr': '2001:db8::1', + 'source_intf': dum_if, }, - '2001:db8::2' : { - 'source_addr': 'fe80::1', + '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', + }, +} + def getFRRconfig(): return cmd('vtysh -c "show run" | sed -n "/^bfd/,/^!/p"') def getBFDPeerconfig(peer): return cmd(f'vtysh -c "show run" | sed -n "/^ {peer}/,/^!/p"') +def getBFDProfileconfig(profile): + return cmd(f'vtysh -c "show run" | sed -n "/^ {profile}/,/^!/p"') + class TestProtocolsBFD(unittest.TestCase): def setUp(self): self.session = ConfigSession(os.getpid()) @@ -69,8 +88,8 @@ class TestProtocolsBFD(unittest.TestCase): # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) - def test_bfd_simple(self): - for peer, peer_config in neighbor_config.items(): + def test_bfd_peer(self): + for peer, peer_config in peers.items(): if 'echo_mode' in peer_config: self.session.set(base_path + ['peer', peer, 'echo-mode']) if 'intv_echo' in peer_config: @@ -95,7 +114,7 @@ class TestProtocolsBFD(unittest.TestCase): # Verify FRR bgpd configuration frrconfig = getFRRconfig() - for peer, peer_config in neighbor_config.items(): + for peer, peer_config in peers.items(): tmp = f'peer {peer}' if 'multihop' in peer_config: tmp += f' multihop' @@ -120,5 +139,43 @@ class TestProtocolsBFD(unittest.TestCase): if 'shutdown' not in peer_config: self.assertIn(f' no 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.session.set(base_path + ['profile', profile, 'echo-mode']) + if 'intv_echo' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'echo-interval', profile_config["intv_echo"]]) + if 'intv_mult' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'multiplier', profile_config["intv_mult"]]) + if 'intv_rx' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'receive', profile_config["intv_rx"]]) + if 'intv_tx' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'transmit', profile_config["intv_tx"]]) + if 'shutdown' in profile_config: + self.session.set(base_path + ['profile', profile, 'shutdown']) + + self.session.set(base_path + ['peer', peer, 'profile', list(profiles)[0]]) + + # commit changes + self.session.commit() + + # Verify FRR bgpd configuration + for profile, profile_config in profiles.items(): + config = getBFDProfileconfig(f'profile {profile}') + 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' not in profile_config: + self.assertIn(f' no 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 1de51a1fc..7d397b55e 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -128,14 +128,19 @@ peer_group_config = { }, } -def getFRRBGPconfig(): - return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}/,/^!/p"') +def getFRRBGPconfig(vrf=None): + if vrf: + return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN} vrf {vrf}$/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}$/,/^!/p"') + +def getFRRBgpAfiConfig(afi): + return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}$/,/^!/p" | sed -n "/^ address-family {afi} unicast/,/^ exit-address-family/p"') def getFRRBGPVNIconfig(vni): - return cmd(f'vtysh -c "show run" | sed -n "/^ vni {vni}/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^ vni {vni}$/,/^!/p"') def getFRRRPKIconfig(): - return cmd(f'vtysh -c "show run" | sed -n "/^rpki/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^rpki$/,/^!/p"') class TestProtocolsBGP(unittest.TestCase): def setUp(self): @@ -218,15 +223,26 @@ class TestProtocolsBGP(unittest.TestCase): router_id = '127.0.0.1' local_pref = '500' stalepath_time = '60' + max_path_v4 = '2' + max_path_v4ibgp = '4' + max_path_v6 = '8' + max_path_v6ibgp = '16' 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) + # Default local preference (higher = more preferred, default value is 100) self.session.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.session.set(base_path + ['parameters', 'graceful-restart', 'stalepath-time', stalepath_time]) self.session.set(base_path + ['parameters', 'graceful-shutdown']) + self.session.set(base_path + ['parameters', 'ebgp-requires-policy']) + + # AFI maximum path support + self.session.set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ebgp', max_path_v4]) + self.session.set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ibgp', max_path_v4ibgp]) + self.session.set(base_path + ['address-family', 'ipv6-unicast', 'maximum-paths', 'ebgp', max_path_v6]) + self.session.set(base_path + ['address-family', 'ipv6-unicast', 'maximum-paths', 'ibgp', max_path_v6ibgp]) # commit changes self.session.commit() @@ -240,6 +256,15 @@ class TestProtocolsBGP(unittest.TestCase): 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 = getFRRBgpAfiConfig('ipv4') + self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config) + self.assertIn(f' maximum-paths ibgp {max_path_v4ibgp}', afiv4_config) + + afiv6_config = getFRRBgpAfiConfig('ipv6') + self.assertIn(f' maximum-paths {max_path_v6}', afiv6_config) + self.assertIn(f' maximum-paths ibgp {max_path_v6ibgp}', afiv6_config) def test_bgp_02_neighbors(self): @@ -388,7 +413,7 @@ class TestProtocolsBGP(unittest.TestCase): } # 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', 'redistribute', redistribute]) @@ -453,6 +478,9 @@ class TestProtocolsBGP(unittest.TestCase): frrconfig = getFRRBGPconfig() 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 @@ -525,5 +553,27 @@ class TestProtocolsBGP(unittest.TestCase): 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 OSPF 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.session.set(vrf_base + ['table', table]) + self.session.set(vrf_base + ['protocols', 'bgp', ASN, 'parameters', 'router-id', router_id]) + table = str(int(table) + 1000) + + self.session.commit() + + for vrf in vrfs: + # Verify FRR bgpd configuration + frrconfig = getFRRBGPconfig(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_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index ce30f6a7d..532d84cc8 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -27,8 +27,10 @@ base_path = ['protocols', 'ospf'] route_map = 'foo-bar-baz10' -def getFRROSPFconfig(): - return cmd('vtysh -c "show run" | sed -n "/router ospf/,/^!/p"') +def getFRRconfig(vrf=None): + if vrf: + return cmd(f'vtysh -c "show run" | sed -n "/^router ospf vrf {vrf}$/,/^!/p"') + return cmd('vtysh -c "show run" | sed -n "/^router ospf$/,/^!/p"') def getFRRInterfaceConfig(interface): return cmd(f'vtysh -c "show run" | sed -n "/^interface {interface}$/,/^!/p"') @@ -45,6 +47,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.delete(['policy', 'route-map', route_map]) self.session.delete(base_path) + self.session.commit() del self.session @@ -54,12 +57,11 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() 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' @@ -76,7 +78,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() self.assertIn(f'router ospf', frrconfig) self.assertIn(f' auto-cost reference-bandwidth {bandwidth}', frrconfig) self.assertIn(f' ospf router-id {router_id}', frrconfig) @@ -88,7 +90,7 @@ class TestProtocolsOSPF(unittest.TestCase): def test_ospf_03_access_list(self): acl = '100' seq = '10' - protocols = ['bgp', 'connected', 'kernel', 'rip', 'static'] + protocols = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static'] self.session.set(['policy', 'access-list', acl, 'rule', seq, 'action', 'permit']) self.session.set(['policy', 'access-list', acl, 'rule', seq, 'source', 'any']) @@ -100,7 +102,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() self.assertIn(f'router ospf', frrconfig) self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults for ptotocol in protocols: @@ -121,7 +123,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() 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) @@ -131,7 +133,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig) @@ -158,7 +160,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() 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 @@ -173,7 +175,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.set(base_path + ['distance', 'ospf', 'inter-area', inter_area]) self.session.commit() - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() self.assertIn(f' distance ospf intra-area {intra_area} inter-area {inter_area} external {external}', frrconfig) @@ -189,7 +191,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() self.assertIn(f'router ospf', frrconfig) for neighbor in neighbors: self.assertIn(f' neighbor {neighbor} priority {priority} poll-interval {poll_interval}', frrconfig) # default @@ -205,7 +207,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() self.assertIn(f'router ospf', frrconfig) self.assertIn(f' passive-interface default', frrconfig) # default for interface in interfaces: @@ -215,7 +217,7 @@ class TestProtocolsOSPF(unittest.TestCase): def test_ospf_08_redistribute(self): metric = '15' metric_type = '1' - redistribute = ['bgp', 'connected', 'kernel', 'rip', 'static'] + redistribute = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static'] for protocol in redistribute: self.session.set(base_path + ['redistribute', protocol, 'metric', metric]) @@ -227,7 +229,7 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() self.assertIn(f'router ospf', frrconfig) for protocol in redistribute: if protocol in ['kernel', 'static']: @@ -235,6 +237,7 @@ class TestProtocolsOSPF(unittest.TestCase): 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' @@ -257,13 +260,27 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.commit() # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() + frrconfig = getFRRconfig() + import pprint + # From time to time the CI fails with an error like: + # ====================================================================== + # FAIL: test_ospf_09_virtual_link (__main__.TestProtocolsOSPF) + # ---------------------------------------------------------------------- + # Traceback (most recent call last): + # File "/usr/libexec/vyos/tests/smoke/cli/test_protocols_ospf.py", line 261, in test_ospf_09_virtual_link + # self.assertIn(f'router ospf', frrconfig) + # AssertionError: 'router ospf' not found in '' + # + # Add some debug code so we can find the root cause + pprint.pprint(frrconfig) + 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' @@ -295,5 +312,37 @@ class TestProtocolsOSPF(unittest.TestCase): self.assertIn(f' ip ospf priority {priority}', config) self.assertIn(f' bandwidth {bandwidth}', config) + + def test_ospf_11_vrfs(self): + vrfs = ['red', 'green', 'blue'] + # 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' + for vrf in vrfs: + vrf_base = ['vrf', 'name', vrf] + self.session.set(vrf_base + ['table', table]) + self.session.set(vrf_base + ['protocols', 'ospf']) + table = str(int(table) + 1000) + + # Also set a default VRF OSPF config + self.session.set(base_path) + self.session.commit() + + # Verify FRR ospfd configuration + frrconfig = getFRRconfig() + 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 + + for vrf in vrfs: + frrconfig = getFRRconfig(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.session.delete(['vrf', 'name', 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 index 297d5d996..754c4488f 100755 --- a/smoketest/scripts/cli/test_protocols_ospfv3.py +++ b/smoketest/scripts/cli/test_protocols_ospfv3.py @@ -25,10 +25,15 @@ from vyos.util import process_named_running PROCESS_NAME = 'ospf6d' base_path = ['protocols', 'ospfv3'] +router_id = '192.0.2.1' +default_area = '0' def getFRROSPFconfig(): return cmd('vtysh -c "show run" | sed -n "/router ospf6/,/^!/p"') +def getFRRIFconfig(iface): + return cmd(f'vtysh -c "show run" | sed -n "/^interface {iface}/,/^!/p"') + class TestProtocolsOSPFv3(unittest.TestCase): def setUp(self): self.session = ConfigSession(os.getpid()) @@ -43,23 +48,21 @@ class TestProtocolsOSPFv3(unittest.TestCase): def test_ospfv3_01_basic(self): - area = '0' seq = '10' prefix = '2001:db8::/32' acl_name = 'foo-acl-100' - router_id = '192.0.2.1' self.session.set(['policy', 'access-list6', acl_name, 'rule', seq, 'action', 'permit']) self.session.set(['policy', 'access-list6', acl_name, 'rule', seq, 'source', 'any']) self.session.set(base_path + ['parameters', 'router-id', router_id]) - self.session.set(base_path + ['area', area, 'range', prefix, 'advertise']) - self.session.set(base_path + ['area', area, 'export-list', acl_name]) - self.session.set(base_path + ['area', area, 'import-list', acl_name]) + self.session.set(base_path + ['area', default_area, 'range', prefix, 'advertise']) + self.session.set(base_path + ['area', default_area, 'export-list', acl_name]) + self.session.set(base_path + ['area', default_area, 'import-list', acl_name]) interfaces = Section.interfaces('ethernet') for interface in interfaces: - self.session.set(base_path + ['area', area, 'interface', interface]) + self.session.set(base_path + ['area', default_area, 'interface', interface]) # commit changes self.session.commit() @@ -67,13 +70,13 @@ class TestProtocolsOSPFv3(unittest.TestCase): # Verify FRR ospfd configuration frrconfig = getFRROSPFconfig() self.assertIn(f'router ospf6', frrconfig) - self.assertIn(f' area {area} range {prefix}', frrconfig) + self.assertIn(f' area {default_area} range {prefix}', frrconfig) self.assertIn(f' ospf6 router-id {router_id}', frrconfig) - self.assertIn(f' area {area} import-list {acl_name}', frrconfig) - self.assertIn(f' area {area} export-list {acl_name}', 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 {area}', frrconfig) + self.assertIn(f' interface {interface} area {default_area}', frrconfig) self.session.delete(['policy', 'access-list6', acl_name]) @@ -118,6 +121,46 @@ class TestProtocolsOSPFv3(unittest.TestCase): for protocol in redistribute: self.assertIn(f' redistribute {protocol} route-map {route_map}', frrconfig) + def test_ospfv3_0104_interfaces(self): + + self.session.set(base_path + ['parameters', 'router-id', router_id]) + self.session.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.session.set(if_base + ['bfd']) + self.session.set(if_base + ['cost', cost]) + self.session.set(if_base + ['instance-id', '0']) + self.session.set(if_base + ['mtu-ignore']) + self.session.set(if_base + ['network', 'point-to-point']) + self.session.set(if_base + ['passive']) + self.session.set(if_base + ['priority', priority]) + cost = str(int(cost) + 10) + priority = str(int(priority) + 5) + + # commit changes + self.session.commit() + + # Verify FRR ospfd configuration + frrconfig = getFRROSPFconfig() + self.assertIn(f'router ospf6', frrconfig) + + cost = '100' + priority = '10' + for interface in interfaces: + if_config = getFRRIFconfig(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 index 2c5c9030a..f42ea0c0a 100755 --- a/smoketest/scripts/cli/test_protocols_rip.py +++ b/smoketest/scripts/cli/test_protocols_rip.py @@ -71,7 +71,7 @@ class TestProtocolsRIP(unittest.TestCase): 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', 'kernel', 'ospf', 'static'] + redistribute = ['bgp', 'connected', 'isis', 'kernel', 'ospf', 'static'] timer_garbage = '888' timer_timeout = '1000' timer_update = '90' diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py index cf591f060..28ae5e2dd 100755 --- a/smoketest/scripts/cli/test_protocols_static.py +++ b/smoketest/scripts/cli/test_protocols_static.py @@ -21,6 +21,7 @@ from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError from vyos.template import is_ipv6 from vyos.util import cmd +from vyos.util import get_interface_config base_path = ['protocols', 'static'] vrf_path = ['protocols', 'vrf'] @@ -85,7 +86,6 @@ routes = { }, } -vrfs = ['red', 'green', 'blue'] tables = ['80', '81', '82'] class StaticRouteTest(unittest.TestCase): @@ -99,9 +99,6 @@ class StaticRouteTest(unittest.TestCase): route_type = 'route6' self.session.delete(base_path + [route_type, route]) - for vrf in vrfs: - self.session.delete(vrf_path + [vrf]) - for table in tables: self.session.delete(base_path + ['table', table]) @@ -290,47 +287,65 @@ class StaticRouteTest(unittest.TestCase): def test_protocols_vrf_static(self): - for vrf in vrfs: + # 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.session.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' - base = vrf_path + [vrf, 'static', route_type, route] + 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.session.set(base + ['next-hop', next_hop]) + self.session.set(route_base_path + ['next-hop', next_hop]) if 'disable' in next_hop_config: - self.session.set(base + ['next-hop', next_hop, 'disable']) + self.session.set(route_base_path + ['next-hop', next_hop, 'disable']) if 'distance' in next_hop_config: - self.session.set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']]) + self.session.set(route_base_path + ['next-hop', next_hop, 'distance', next_hop_config['distance']]) if 'interface' in next_hop_config: - self.session.set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']]) + self.session.set(route_base_path + ['next-hop', next_hop, 'interface', next_hop_config['interface']]) if 'vrf' in next_hop_config: - self.session.set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']]) + self.session.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.session.set(base + ['interface', interface]) + self.session.set(route_base_path + ['interface', interface]) if 'disable' in interface_config: - self.session.set(base + ['interface', interface, 'disable']) + self.session.set(route_base_path + ['interface', interface, 'disable']) if 'distance' in interface_config: - self.session.set(base + ['interface', interface, 'distance', interface_config['distance']]) + self.session.set(route_base_path + ['interface', interface, 'distance', interface_config['distance']]) if 'vrf' in interface_config: - self.session.set(base + ['interface', interface, 'vrf', interface_config['vrf']]) + self.session.set(route_base_path + ['interface', interface, 'vrf', interface_config['vrf']]) if 'blackhole' in route_config: - self.session.set(base + ['blackhole']) + self.session.set(route_base_path + ['blackhole']) if 'distance' in route_config['blackhole']: - self.session.set(base + ['blackhole', 'distance', route_config['blackhole']['distance']]) + self.session.set(route_base_path + ['blackhole', 'distance', route_config['blackhole']['distance']]) if 'tag' in route_config['blackhole']: - self.session.set(base + ['blackhole', 'tag', route_config['blackhole']['tag']]) + self.session.set(route_base_path + ['blackhole', 'tag', route_config['blackhole']['tag']]) # commit changes self.session.commit() - for vrf in vrfs: + 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 = getFRRCconfig(vrf) self.assertIn(f'vrf {vrf}', frrconfig) @@ -380,6 +395,7 @@ class StaticRouteTest(unittest.TestCase): self.assertIn(tmp, frrconfig) + self.session.delete(['vrf']) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py index db7b2dda4..e74e22a5c 100755 --- a/smoketest/scripts/cli/test_service_dhcp-server.py +++ b/smoketest/scripts/cli/test_service_dhcp-server.py @@ -200,6 +200,7 @@ 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 diff --git a/smoketest/scripts/cli/test_service_dhcpv6-server.py b/smoketest/scripts/cli/test_service_dhcpv6-server.py index 319891a94..a364eee11 100755 --- a/smoketest/scripts/cli/test_service_dhcpv6-server.py +++ b/smoketest/scripts/cli/test_service_dhcpv6-server.py @@ -151,5 +151,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.session.set(base_path + ['global-parameters', 'name-server', ns_global_1]) + self.session.set(base_path + ['global-parameters', 'name-server', ns_global_2]) + self.session.set(base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]) + + # commit changes + self.session.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_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py index a4bb6e9f9..e8f9facbb 100755 --- a/smoketest/scripts/cli/test_service_pppoe-server.py +++ b/smoketest/scripts/cli/test_service_pppoe-server.py @@ -144,7 +144,8 @@ 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]) diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 8e977d407..aac115663 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -33,12 +33,6 @@ from vyos.validate import is_intf_addr_assigned base_path = ['vrf'] vrfs = ['red', 'green', 'blue', 'foo-bar', 'baz_foo'] -def get_vrf_ipv4_routes(vrf): - return json.loads(cmd(f'ip -4 -j route show vrf {vrf}')) - -def get_vrf_ipv6_routes(vrf): - return json.loads(cmd(f'ip -6 -j route show vrf {vrf}')) - class VRFTest(unittest.TestCase): _interfaces = [] |