summaryrefslogtreecommitdiffstats
path: root/tests/topotests/nhrp_redundancy
diff options
context:
space:
mode:
Diffstat (limited to 'tests/topotests/nhrp_redundancy')
-rw-r--r--tests/topotests/nhrp_redundancy/host/zebra.conf4
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_cache.json51
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_cache_nhs1_down.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_route.json71
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_route_nhs1_down.json49
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut.json118
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut_nhs1_down.json96
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_absent.json5
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_present.json9
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrpd.conf11
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/zebra.conf16
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrp_cache.json51
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrp_cache_nhs1_down.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrp_route.json71
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrp_route_nhs1_down.json49
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrpd.conf11
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/zebra.conf16
-rw-r--r--tests/topotests/nhrp_redundancy/nhs1/nhrp_cache.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhs1/nhrp_route.json48
-rw-r--r--tests/topotests/nhrp_redundancy/nhs1/nhrpd.conf9
-rw-r--r--tests/topotests/nhrp_redundancy/nhs1/zebra.conf12
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrp_cache.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrp_cache_nhs1_down.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrp_route.json48
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrp_route_nhs1_down.json48
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrpd.conf9
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/zebra.conf12
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrp_cache.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrp_cache_nhs1_down.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrp_route.json48
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrp_route_nhs1_down.json48
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrpd.conf9
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/zebra.conf12
-rw-r--r--tests/topotests/nhrp_redundancy/router/zebra.conf7
-rw-r--r--tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot103
-rw-r--r--tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py534
36 files changed, 1855 insertions, 0 deletions
diff --git a/tests/topotests/nhrp_redundancy/host/zebra.conf b/tests/topotests/nhrp_redundancy/host/zebra.conf
new file mode 100644
index 00000000..8bb7da0a
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/host/zebra.conf
@@ -0,0 +1,4 @@
+interface host-eth0
+ ip address 10.4.4.7/24
+!
+ip route 0.0.0.0/0 10.4.4.4
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache.json
new file mode 100644
index 00000000..9e8a5c99
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache.json
@@ -0,0 +1,51 @@
+{
+ "attr": {
+ "entriesCount": 4
+ },
+ "table": [
+ {
+ "interface": "nhc1-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc1-gre0",
+ "type": "local",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhc1-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc1-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.1",
+ "nbma": "192.168.1.1",
+ "claimed_nbma": "192.168.1.1",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache_nhs1_down.json
new file mode 100644
index 00000000..5b91f3bc
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache_nhs1_down.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhc1-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc1-gre0",
+ "type": "local",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhc1-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route.json
new file mode 100644
index 00000000..08367565
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route.json
@@ -0,0 +1,71 @@
+{
+ "172.16.1.1\/32": [
+ {
+ "prefix": "172.16.1.1\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_nhs1_down.json
new file mode 100644
index 00000000..bfb468b0
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_nhs1_down.json
@@ -0,0 +1,49 @@
+{
+ "172.16.1.1\/32": null,
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut.json
new file mode 100644
index 00000000..3a91f1ba
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut.json
@@ -0,0 +1,118 @@
+{
+ "10.5.5.0\/24": [
+ {
+ "prefix": "10.5.5.0\/24",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "ip": "172.16.1.5",
+ "afi": "ipv4",
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.1\/32": [
+ {
+ "prefix": "172.16.1.1\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut_nhs1_down.json
new file mode 100644
index 00000000..0f38feb6
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut_nhs1_down.json
@@ -0,0 +1,96 @@
+{
+ "10.5.5.0\/24": [
+ {
+ "prefix": "10.5.5.0\/24",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "ip": "172.16.1.5",
+ "afi": "ipv4",
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.1\/32": null,
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_absent.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_absent.json
new file mode 100644
index 00000000..78563cb9
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_absent.json
@@ -0,0 +1,5 @@
+{
+ "attr":{
+ "entriesCount":0
+ }
+}
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_present.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_present.json
new file mode 100644
index 00000000..4547c59c
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_present.json
@@ -0,0 +1,9 @@
+{
+ "table":[
+ {
+ "type":"dynamic",
+ "prefix":"10.5.5.0/24",
+ "via":"172.16.1.5"
+ }
+ ]
+}
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhc1/nhrpd.conf
new file mode 100644
index 00000000..a0862f77
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrpd.conf
@@ -0,0 +1,11 @@
+!debug nhrp all
+interface nhc1-gre0
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ ip nhrp nhs dynamic nbma 192.168.1.1
+ ip nhrp nhs dynamic nbma 192.168.1.2
+ ip nhrp nhs dynamic nbma 192.168.1.3
+ ip nhrp shortcut
+ tunnel source nhc1-eth0
+exit
diff --git a/tests/topotests/nhrp_redundancy/nhc1/zebra.conf b/tests/topotests/nhrp_redundancy/nhc1/zebra.conf
new file mode 100644
index 00000000..07d91754
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/zebra.conf
@@ -0,0 +1,16 @@
+ip forwarding
+interface nhc1-eth0
+ ip address 192.168.2.4/24
+!
+ip route 192.168.1.0/24 192.168.2.6
+interface nhc1-gre0
+ ip address 172.16.1.4/32
+ no link-detect
+ ipv6 nd suppress-ra
+!
+interface nhc1-eth1
+ ip address 10.4.4.4/24
+!
+ip route 0.0.0.0/0 172.16.1.1 50
+ip route 0.0.0.0/0 172.16.1.2 60
+ip route 0.0.0.0/0 172.16.1.3 70 \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache.json
new file mode 100644
index 00000000..8ee02a7c
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache.json
@@ -0,0 +1,51 @@
+{
+ "attr": {
+ "entriesCount": 4
+ },
+ "table": [
+ {
+ "interface": "nhc2-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc2-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc2-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.1",
+ "nbma": "192.168.1.1",
+ "claimed_nbma": "192.168.1.1",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc2-gre0",
+ "type": "local",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache_nhs1_down.json
new file mode 100644
index 00000000..bb1c4837
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache_nhs1_down.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhc2-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc2-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc2-gre0",
+ "type": "local",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc2/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhc2/nhrp_route.json
new file mode 100644
index 00000000..a69c0cae
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrp_route.json
@@ -0,0 +1,71 @@
+{
+ "172.16.1.1\/32": [
+ {
+ "prefix": "172.16.1.1\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc2/nhrp_route_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc2/nhrp_route_nhs1_down.json
new file mode 100644
index 00000000..e2dd9dde
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrp_route_nhs1_down.json
@@ -0,0 +1,49 @@
+{
+ "172.16.1.1\/32": null,
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc2/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhc2/nhrpd.conf
new file mode 100644
index 00000000..16a6d87c
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrpd.conf
@@ -0,0 +1,11 @@
+!debug nhrp all
+interface nhc2-gre0
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp nhs dynamic nbma 192.168.1.1
+ ip nhrp nhs dynamic nbma 192.168.1.2
+ ip nhrp nhs dynamic nbma 192.168.1.3
+ ip nhrp registration no-unique
+ ip nhrp shortcut
+ tunnel source nhc2-eth0
+exit
diff --git a/tests/topotests/nhrp_redundancy/nhc2/zebra.conf b/tests/topotests/nhrp_redundancy/nhc2/zebra.conf
new file mode 100644
index 00000000..30ea6d4d
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/zebra.conf
@@ -0,0 +1,16 @@
+ip forwarding
+interface nhc2-eth0
+ ip address 192.168.2.5/24
+!
+ip route 192.168.1.0/24 192.168.2.6
+interface nhc2-gre0
+ ip address 172.16.1.5/32
+ no link-detect
+ ipv6 nd suppress-ra
+!
+interface nhc2-eth1
+ ip address 10.5.5.5/24
+!
+ip route 0.0.0.0/0 172.16.1.1 50
+ip route 0.0.0.0/0 172.16.1.2 60
+ip route 0.0.0.0/0 172.16.1.3 70
diff --git a/tests/topotests/nhrp_redundancy/nhs1/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhs1/nhrp_cache.json
new file mode 100644
index 00000000..11d41d1b
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs1/nhrp_cache.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhs1-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhs1-gre0",
+ "type": "local",
+ "protocol": "172.16.1.1",
+ "nbma": "192.168.1.1",
+ "claimed_nbma": "192.168.1.1",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhs1-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs1/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhs1/nhrp_route.json
new file mode 100644
index 00000000..2574b1a5
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs1/nhrp_route.json
@@ -0,0 +1,48 @@
+{
+ "172.16.1.4\/32": [
+ {
+ "prefix": "172.16.1.4\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs1/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhs1/nhrpd.conf
new file mode 100644
index 00000000..c0c8c28f
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs1/nhrpd.conf
@@ -0,0 +1,9 @@
+!debug nhrp all
+nhrp nflog-group 1
+interface nhs1-gre0
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ ip nhrp redirect
+ tunnel source nhs1-eth0
+exit
diff --git a/tests/topotests/nhrp_redundancy/nhs1/zebra.conf b/tests/topotests/nhrp_redundancy/nhs1/zebra.conf
new file mode 100644
index 00000000..718e01b9
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs1/zebra.conf
@@ -0,0 +1,12 @@
+ip forwarding
+interface nhs1-eth0
+ ip address 192.168.1.1/24
+!
+ip route 192.168.2.0/24 192.168.1.6
+interface nhs1-gre0
+ ip address 172.16.1.1/32
+ no link-detect
+ ipv6 nd suppress-ra
+!
+ip route 10.4.4.0/24 172.16.1.4
+ip route 10.5.5.0/24 172.16.1.5
diff --git a/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache.json
new file mode 100644
index 00000000..6343c4de
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhs2-gre0",
+ "type": "local",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhs2-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhs2-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache_nhs1_down.json
new file mode 100644
index 00000000..6343c4de
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache_nhs1_down.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhs2-gre0",
+ "type": "local",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhs2-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhs2-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs2/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhs2/nhrp_route.json
new file mode 100644
index 00000000..0ad37fc3
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrp_route.json
@@ -0,0 +1,48 @@
+{
+ "172.16.1.4\/32": [
+ {
+ "prefix": "172.16.1.4\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs2/nhrp_route_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhs2/nhrp_route_nhs1_down.json
new file mode 100644
index 00000000..0ad37fc3
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrp_route_nhs1_down.json
@@ -0,0 +1,48 @@
+{
+ "172.16.1.4\/32": [
+ {
+ "prefix": "172.16.1.4\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs2/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhs2/nhrpd.conf
new file mode 100644
index 00000000..df86d279
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrpd.conf
@@ -0,0 +1,9 @@
+!debug nhrp all
+nhrp nflog-group 1
+interface nhs2-gre0
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ ip nhrp redirect
+ tunnel source nhs2-eth0
+exit
diff --git a/tests/topotests/nhrp_redundancy/nhs2/zebra.conf b/tests/topotests/nhrp_redundancy/nhs2/zebra.conf
new file mode 100644
index 00000000..6001bf21
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/zebra.conf
@@ -0,0 +1,12 @@
+ip forwarding
+interface nhs2-eth0
+ ip address 192.168.1.2/24
+!
+ip route 192.168.2.0/24 192.168.1.6
+interface nhs2-gre0
+ ip address 172.16.1.2/32
+ no link-detect
+ ipv6 nd suppress-ra
+!
+ip route 10.4.4.0/24 172.16.1.4
+ip route 10.5.5.0/24 172.16.1.5
diff --git a/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache.json
new file mode 100644
index 00000000..d911de34
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhs3-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhs3-gre0",
+ "type": "local",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhs3-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache_nhs1_down.json
new file mode 100644
index 00000000..d911de34
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache_nhs1_down.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhs3-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhs3-gre0",
+ "type": "local",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhs3-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs3/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhs3/nhrp_route.json
new file mode 100644
index 00000000..29a4f8f1
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrp_route.json
@@ -0,0 +1,48 @@
+{
+ "172.16.1.4\/32": [
+ {
+ "prefix": "172.16.1.4\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs3-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs3-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs3/nhrp_route_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhs3/nhrp_route_nhs1_down.json
new file mode 100644
index 00000000..29a4f8f1
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrp_route_nhs1_down.json
@@ -0,0 +1,48 @@
+{
+ "172.16.1.4\/32": [
+ {
+ "prefix": "172.16.1.4\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs3-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs3-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs3/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhs3/nhrpd.conf
new file mode 100644
index 00000000..e7c3504f
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrpd.conf
@@ -0,0 +1,9 @@
+!debug nhrp all
+nhrp nflog-group 1
+interface nhs3-gre0
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ ip nhrp redirect
+ tunnel source nhs3-eth0
+exit
diff --git a/tests/topotests/nhrp_redundancy/nhs3/zebra.conf b/tests/topotests/nhrp_redundancy/nhs3/zebra.conf
new file mode 100644
index 00000000..7c154388
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/zebra.conf
@@ -0,0 +1,12 @@
+ip forwarding
+interface nhs3-eth0
+ ip address 192.168.1.3/24
+!
+ip route 192.168.2.0/24 192.168.1.6
+interface nhs3-gre0
+ ip address 172.16.1.3/32
+ no link-detect
+ ipv6 nd suppress-ra
+!
+ip route 10.4.4.0/24 172.16.1.4
+ip route 10.5.5.0/24 172.16.1.5 \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/router/zebra.conf b/tests/topotests/nhrp_redundancy/router/zebra.conf
new file mode 100644
index 00000000..c0eb19ca
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/router/zebra.conf
@@ -0,0 +1,7 @@
+ip forwarding
+interface router-eth0
+ ip address 192.168.1.6/24
+!
+interface router-eth1
+ ip address 192.168.2.6/24
+exit
diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot
new file mode 100644
index 00000000..e94e1d07
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot
@@ -0,0 +1,103 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="nhrp-topo-redundant-nhs";
+
+ # Routers
+ nhs1 [
+ shape=doubleoctagon,
+ label="NHS 1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ nhs2 [
+ shape=doubleoctagon
+ label="NHS 2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ nhs3 [
+ shape=doubleoctagon
+ label="NHS 3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ nhc1 [
+ shape=doubleoctagon
+ label="NHC 1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ nhc2 [
+ shape=doubleoctagon
+ label="NHC 2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ router [
+ shape=doubleoctagon
+ label="router",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ host [
+ shape=doubleoctagon
+ label="host",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n192.168.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n10.4.4.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw4 [
+ shape=oval,
+ label="sw4\n10.5.5.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ nhs1 -- sw1 [label="eth0"];
+ nhs2 -- sw1 [label="eth0"];
+ nhs3 -- sw1 [label="eth0"];
+ router -- sw1 [label="eth0"];
+
+ nhc1 -- sw2 [label="eth0"];
+ nhc2 -- sw2 [label="eth0"];
+ router -- sw2 [label="eth1"];
+
+ nhc1 -- sw3 [label="eth1"];
+ host -- sw3 [label="eth0"];
+
+ nhc2 -- sw4 [label="eth1"];
+
+}
diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py
new file mode 100644
index 00000000..06777aaa
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py
@@ -0,0 +1,534 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# test_nhrp_redundancy.py
+#
+# Copyright 2024, LabN Consulting, L.L.C.
+# Dave LeRoy
+#
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import (
+ required_linux_kernel_version,
+ shutdown_bringup_interface,
+ retry,
+)
+
+"""
+test_nhrp_redundancy.py: Test NHS redundancy for NHRP
+"""
+
+TOPOLOGY = """
++------------+ +------------+ +------------+
+| | | | | |
+| | | | | |
+| NHS 1 | | NHS 2 | | NHS 3 |
+| | | | | |
++-----+------+ +-----+------+ +-----+------+
+ |.1 |.2 |.3
+ | | |
+ | | 192.168.1.0/24 |
+------+-------------------------------+------------------+-------------+------
+ |
+ |.6
+ GRE P2MP between all NHS and NHC +-----+------+
+ 172.16.1.x/32 | |
+ | |
+ | Router |
+ | |
+ +-----+------+
+ |
+ |
+ ---------+----------------+-------------+------
+ | 192.168.2.0/24 |
+ | |
+ | |.4 |.5
++------------+ | +-------+----+ +------+-----+ |
+| | | | | | | |
+| | +--------+ | | | |
+| Host |.7 | | NHC 1 | | NHC 2 +-----+10.5.5.0/24
+| +---------+ | | | | |
++------------+ | +------------+ +------------+ |
+ | |
+ 10.4.4.0/24
+"""
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# Required to instantiate the topology builder class.
+
+pytestmark = [pytest.mark.nhrpd]
+
+
+def build_topo(tgen):
+ "Build function"
+
+ # Create 7 routers
+ for rname in ["nhs1", "nhs2", "nhs3", "nhc1", "nhc2", "router", "host"]:
+ tgen.add_router(rname)
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["nhs1"])
+ switch.add_link(tgen.gears["nhs2"])
+ switch.add_link(tgen.gears["nhs3"])
+ switch.add_link(tgen.gears["router"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["nhc1"])
+ switch.add_link(tgen.gears["nhc2"])
+ switch.add_link(tgen.gears["router"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["nhc1"])
+ switch.add_link(tgen.gears["host"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["nhc2"])
+
+
+def _populate_iface():
+ tgen = get_topogen()
+ cmds_tot_hub = [
+ "ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 192.168.1.{1} remote 0.0.0.0",
+ "ip link set dev {0}-gre0 up",
+ "echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu",
+ "echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6",
+ "echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6",
+ "iptables -A FORWARD -i {0}-gre0 -o {0}-gre0 -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 --hashlimit-dstmask 24 --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-size 128",
+ ]
+
+ cmds_tot = [
+ "ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 192.168.2.{1} remote 0.0.0.0",
+ "ip link set dev {0}-gre0 up",
+ "echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu",
+ "echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6",
+ "echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6",
+ ]
+
+ for cmd in cmds_tot_hub:
+ input = cmd.format("nhs1", "1")
+ logger.info("input: " + input)
+ output = tgen.net["nhs1"].cmd(input)
+ logger.info("output: " + output)
+
+ input = cmd.format("nhs2", "2")
+ logger.info("input: " + input)
+ output = tgen.net["nhs2"].cmd(input)
+ logger.info("output: " + output)
+
+ input = cmd.format("nhs3", "3")
+ logger.info("input: " + input)
+ output = tgen.net["nhs3"].cmd(input)
+ logger.info("output: " + output)
+
+ for cmd in cmds_tot:
+ input = cmd.format("nhc1", "4")
+ logger.info("input: " + input)
+ output = tgen.net["nhc1"].cmd(input)
+ logger.info("output: " + output)
+
+ input = cmd.format("nhc2", "5")
+ logger.info("input: " + input)
+ output = tgen.net["nhc2"].cmd(input)
+ logger.info("output: " + output)
+
+
+def _verify_iptables():
+ tgen = get_topogen()
+ # Verify iptables is installed. Required for shortcuts
+ rc, _, _ = tgen.net["nhs1"].cmd_status("iptables")
+ return False if rc == 127 else True
+
+
+def setup_module(mod):
+ logger.info("NHRP Redundant NHS:\n {}".format(TOPOLOGY))
+
+ result = required_linux_kernel_version("5.0")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ # Starting Routers
+ router_list = tgen.routers()
+ _populate_iface()
+
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, "{}/zebra.conf".format(rname)),
+ )
+ if rname in ("nhs1", "nhs2", "nhs3", "nhc1", "nhc2"):
+ router.load_config(
+ TopoRouter.RD_NHRP, os.path.join(CWD, "{}/nhrpd.conf".format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged before checking for the NHRP
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking NHRP cache for convergence")
+ router_list = tgen.routers()
+
+ # Check NHRP cache on servers and clients
+ for rname, router in router_list.items():
+ if "nh" not in rname:
+ continue
+
+ json_file = "{}/{}/nhrp_cache.json".format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip nhrp cache json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = router.vtysh_cmd("show ip nhrp cache")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Check NHRP IPV4 routes on servers and clients
+ logger.info("Checking IPv4 routes for convergence")
+ for rname, router in router_list.items():
+ if "nh" not in rname:
+ continue
+
+ json_file = "{}/{}/nhrp_route.json".format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = router.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Test connectivity from 1 NHRP server to all clients
+ nhs1 = tgen.gears["nhs1"]
+ logger.info("Check Ping IPv4 from nhs1 to nhc1 = 172.16.1.4)")
+ output = nhs1.run("ping 172.16.1.4 -f -c 1000")
+ logger.info(output)
+ if "1000 packets transmitted, 1000 received" not in output:
+ assertmsg = "expected ping IPv4 from nhs1 to nhc1 should be ok"
+ assert 0, assertmsg
+ else:
+ logger.info("Check Ping IPv4 from nhs1 to nhc1 OK")
+
+ logger.info("Check Ping IPv4 from nhs1 to nhc2 = 172.16.1.5)")
+ output = nhs1.run("ping 172.16.1.5 -f -c 1000")
+ logger.info(output)
+ if "1000 packets transmitted, 1000 received" not in output:
+ assertmsg = "expected ping IPv4 from nhs1 to nhc2 should be ok"
+ assert 0, assertmsg
+ else:
+ logger.info("Check Ping IPv4 from nhs1 to nhc2 OK")
+
+ # Test connectivity from 1 NHRP client to all servers
+ nhc1 = tgen.gears["nhc1"]
+ logger.info("Check Ping IPv4 from nhc1 to nhs1 = 172.16.1.1)")
+ output = nhc1.run("ping 172.16.1.1 -f -c 1000")
+ logger.info(output)
+ if "1000 packets transmitted, 1000 received" not in output:
+ assertmsg = "expected ping IPv4 from nhc1 to nhs1 should be ok"
+ assert 0, assertmsg
+ else:
+ logger.info("Check Ping IPv4 from nhc1 to nhs1 OK")
+
+ logger.info("Check Ping IPv4 from nhc1 to nhs2 = 172.16.1.2)")
+ output = nhc1.run("ping 172.16.1.2 -f -c 1000")
+ logger.info(output)
+ if "1000 packets transmitted, 1000 received" not in output:
+ assertmsg = "expected ping IPv4 from nhc1 to nhs2 should be ok"
+ assert 0, assertmsg
+ else:
+ logger.info("Check Ping IPv4 from nhc1 to nhs2 OK")
+
+ logger.info("Check Ping IPv4 from nhc1 to nhs3 = 172.16.1.3)")
+ output = nhc1.run("ping 172.16.1.3 -f -c 1000")
+ logger.info(output)
+ if "1000 packets transmitted, 1000 received" not in output:
+ assertmsg = "expected ping IPv4 from nhc1 to nhs3 should be ok"
+ assert 0, assertmsg
+ else:
+ logger.info("Check Ping IPv4 from nhc1 to nhs3 OK")
+
+
+@retry(retry_timeout=30, initial_wait=5)
+def verify_shortcut_path():
+ """
+ Verifying that traffic flows through shortcut path
+ """
+ tgen = get_topogen()
+ host = tgen.gears["host"]
+ logger.info("Check Ping IPv4 from host to nhc2 = 10.5.5.5")
+
+ output = host.run("ping 10.5.5.5 -f -c 1000")
+ logger.info(output)
+ if "1000 packets transmitted, 1000 received" not in output:
+ assertmsg = "expected ping IPv4 from host to nhc2 should be ok"
+ assert 0, assertmsg
+ else:
+ logger.info("Check Ping IPv4 from host to nhc2 OK")
+
+
+def test_redundancy_shortcut():
+ """
+ Assert that if shortcut created and then NHS goes down, there is no traffic disruption
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ if not _verify_iptables():
+ pytest.skip("iptables not installed")
+
+ logger.info("Testing NHRP shortcuts with redundant servers")
+
+ # Verify nhc1 nhrp routes before shortcut creation
+ nhc1 = tgen.gears["nhc1"]
+ json_file = "{}/{}/nhrp_route.json".format(CWD, nhc1.name)
+ assertmsg = "No nhrp_route file found"
+ assert os.path.isfile(json_file), assertmsg
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+ # Initiate shortcut by pinging between clients
+ host = tgen.gears["host"]
+ logger.info("Check Ping IPv4 from host to nhc2 via shortcut = 10.5.5.5")
+
+ output = host.run("ping 10.5.5.5 -f -c 1000")
+ logger.info(output)
+ if "1000 packets transmitted, 1000 received" not in output:
+ assertmsg = "expected ping IPv4 from host to nhc2 via shortcut should be ok"
+ assert 0, assertmsg
+ else:
+ logger.info("Check Ping IPv4 from host to nhc2 via shortcut OK")
+
+ # Now check that NHRP shortcut route installed
+ json_file = "{}/{}/nhrp_route_shortcut.json".format(CWD, nhc1.name)
+ assertmsg = "No nhrp_route file found"
+ assert os.path.isfile(json_file), assertmsg
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+ json_file = "{}/{}/nhrp_shortcut_present.json".format(CWD, nhc1.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip nhrp shortcut json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip nhrp shortcut")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+ # check the shortcut disappears because of no traffic
+ json_file = "{}/{}/nhrp_shortcut_absent.json".format(CWD, nhc1.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip nhrp shortcut json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip nhrp shortcut")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+
+def test_redundancy_shortcut_backup():
+ """
+ Stop traffic and verify next time traffic started, shortcut is initiated by backup NHS
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ if not _verify_iptables():
+ pytest.skip("iptables not installed")
+
+ nhc1 = tgen.gears["nhc1"]
+ router_list = tgen.routers()
+
+ # Bring down primary GRE interface and verify shortcut is not disturbed
+ logger.info("Bringing down nhs1, primary NHRP server.")
+ shutdown_bringup_interface(tgen, "nhs1", "nhs1-gre0", False)
+
+ # Check NHRP cache on servers and clients
+ for rname, router in router_list.items():
+ if "nh" not in rname:
+ continue
+ if "nhs1" in rname:
+ continue
+
+ json_file = "{}/{}/nhrp_cache_nhs1_down.json".format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip nhrp cache json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = router.vtysh_cmd("show ip nhrp cache")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Check NHRP IPV4 routes on servers and clients
+ logger.info("Checking IPv4 routes for convergence")
+ for rname, router in router_list.items():
+ if "nh" not in rname:
+ continue
+ if "nhs1" in rname:
+ continue
+
+ json_file = "{}/{}/nhrp_route_nhs1_down.json".format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = router.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Verify shortcut is still active
+ host = tgen.gears["host"]
+ logger.info("Check Ping IPv4 from host to nhc2 via shortcut = 10.5.5.5")
+
+ output = host.run("ping 10.5.5.5 -f -c 1000")
+ logger.info(output)
+ if "1000 packets transmitted, 1000 received" not in output:
+ assertmsg = "expected ping IPv4 from host to nhc2 via shortcut should be ok"
+ assert 0, assertmsg
+ else:
+ logger.info("Check Ping IPv4 from host to nhc2 via shortcut OK")
+
+ # Verify shortcut is present in routing table
+ json_file = "{}/{}/nhrp_route_shortcut_nhs1_down.json".format(CWD, nhc1.name)
+ assertmsg = "No nhrp_route file found"
+ assert os.path.isfile(json_file), assertmsg
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ json_file = "{}/{}/nhrp_shortcut_present.json".format(CWD, nhc1.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip nhrp shortcut json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip nhrp shortcut")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+ # Now verify shortcut is purged with lack of traffic
+ json_file = "{}/{}/nhrp_route_nhs1_down.json".format(CWD, nhc1.name)
+ assertmsg = "No nhrp_route file found"
+ assert os.path.isfile(json_file), assertmsg
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+ json_file = "{}/{}/nhrp_shortcut_absent.json".format(CWD, nhc1.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip nhrp shortcut json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip nhrp shortcut")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))