]> git.puffer.fish Git - mirror/frr.git/commitdiff
tests: add a topotest for ospf metric propagation across vrfs/protocols
authorJafar Al-Gharaibeh <jafar@atcorp.com>
Thu, 23 Mar 2023 04:15:01 +0000 (23:15 -0500)
committerJafar Al-Gharaibeh <jafar@atcorp.com>
Tue, 18 Apr 2023 05:48:16 +0000 (00:48 -0500)
Signed-off-by: Jafar Al-Gharaibeh <jafar@atcorp.com>
17 files changed:
tests/topotests/ospf_metric_propagation/__init__.py [new file with mode: 0755]
tests/topotests/ospf_metric_propagation/h1/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/h2/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r1/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r2/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r3/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/r4/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/ra/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/rb/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/rc/frr.conf [new file with mode: 0644]
tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py [new file with mode: 0644]

diff --git a/tests/topotests/ospf_metric_propagation/__init__.py b/tests/topotests/ospf_metric_propagation/__init__.py
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/tests/topotests/ospf_metric_propagation/h1/frr.conf b/tests/topotests/ospf_metric_propagation/h1/frr.conf
new file mode 100644 (file)
index 0000000..1196a19
--- /dev/null
@@ -0,0 +1,10 @@
+!
+hostname h1
+password zebra
+log file /tmp/h1-frr.log
+!
+ip route 0.0.0.0/0 10.0.91.1
+!
+interface h1-eth0
+ ip address 10.0.91.2/24
+!
\ No newline at end of file
diff --git a/tests/topotests/ospf_metric_propagation/h2/frr.conf b/tests/topotests/ospf_metric_propagation/h2/frr.conf
new file mode 100644 (file)
index 0000000..f951fe6
--- /dev/null
@@ -0,0 +1,10 @@
+!
+hostname h2
+password zebra
+log file /tmp/h2-frr.log
+!
+ip route 0.0.0.0/0 10.0.94.4
+!
+interface h2-eth0
+ ip address 10.0.94.2/24
+!
\ No newline at end of file
diff --git a/tests/topotests/ospf_metric_propagation/r1/frr.conf b/tests/topotests/ospf_metric_propagation/r1/frr.conf
new file mode 100644 (file)
index 0000000..9f388db
--- /dev/null
@@ -0,0 +1,96 @@
+!
+hostname r1
+password zebra
+log file /tmp/r1-frr.log
+ip forwarding
+!
+interface r1-eth0
+ ip address 10.0.1.1/24
+ ip ospf cost 100
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface r1-eth1 vrf blue
+ ip address 10.0.10.1/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+!
+interface r1-eth2 vrf green
+ ip address 10.0.91.1/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+!
+router ospf
+  ospf router-id 10.0.255.1
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.1.0/24 area 0
+!
+router ospf vrf blue
+  ospf router-id 10.0.255.1
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.10.0/24 area 0
+!
+router ospf vrf green
+  ospf router-id 10.0.255.1
+    distance 20
+  redistribute bgp route-map costplus
+  network 10.0.91.0/24 area 0
+!
+router bgp 99
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf route-map rmap
+    import vrf route-map rmap
+    import vrf blue
+    import vrf green
+  !
+!
+router bgp 99 vrf blue
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf route-map rmap
+    import vrf route-map rmap
+    import vrf default
+    import vrf green
+  !
+router bgp 99 vrf green
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf default
+    import vrf blue
+  !
+!
+route-map rmap permit 10
+  set metric-type type-1
+  set metric +1
+  exit
+!
+ip prefix-list min seq 5 permit 10.0.80.0/24
+route-map costmax permit 20
+  set metric-type type-1
+  set metric +1
+  set metric-min 713
+  match ip address prefix-list min
+  exit
+!
+ip prefix-list max seq 10 permit 10.0.70.0/24
+route-map costplus permit 30
+  set metric-type type-1
+  set metric +1
+  set metric-max 13
+  match ip address prefix-list max
+  exit
+!
+route-map costplus permit 40
+  set metric-type type-1
+  set metric +1
+  exit
\ No newline at end of file
diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json
new file mode 100644 (file)
index 0000000..e3a5cc4
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  "10.0.94.0/24":[
+    {
+      "prefix":"10.0.94.0/24",
+      "prefixLen":24,
+      "protocol":"bgp",
+      "vrfId":9,
+      "vrfName":"green",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":34,
+      "installed":true,
+      "table":12,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthopGroupId":"*",
+      "installedNexthopGroupId":"*",
+      "uptime":"*",
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"10.0.10.5",
+          "afi":"ipv4",
+          "interfaceIndex":6,
+          "interfaceName":"r1-eth1",
+          "vrf":"blue",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json
new file mode 100644 (file)
index 0000000..f3597bf
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  "10.0.94.0/24":[
+    {
+      "prefix":"10.0.94.0/24",
+      "prefixLen":24,
+      "protocol":"bgp",
+      "vrfId":9,
+      "vrfName":"green",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":136,
+      "installed":true,
+      "table":12,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthopGroupId":"*",
+      "installedNexthopGroupId":"*",
+      "uptime":"*",
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceIndex":5,
+          "interfaceName":"r1-eth0",
+          "vrf":"default",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json
new file mode 100644 (file)
index 0000000..eebcab8
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  "10.0.94.0/24":[
+    {
+      "prefix":"10.0.94.0/24",
+      "prefixLen":24,
+      "protocol":"bgp",
+      "vrfId":9,
+      "vrfName":"green",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":1138,
+      "installed":true,
+      "table":12,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthopGroupId":"*",
+      "installedNexthopGroupId":"*",
+      "uptime":"*",
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceIndex":5,
+          "interfaceName":"r1-eth0",
+          "vrf":"default",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json
new file mode 100644 (file)
index 0000000..d0e3d81
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  "10.0.94.0/24":[
+    {
+      "prefix":"10.0.94.0/24",
+      "prefixLen":24,
+      "protocol":"bgp",
+      "vrfId":9,
+      "vrfName":"green",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":1218,
+      "installed":true,
+      "table":12,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthopGroupId":"*",
+      "installedNexthopGroupId":"*",
+      "uptime":"*",
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceIndex":5,
+          "interfaceName":"r1-eth0",
+          "vrf":"default",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json
new file mode 100644 (file)
index 0000000..989ccf7
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  "10.0.94.0/24":[
+    {
+      "prefix":"10.0.94.0/24",
+      "prefixLen":24,
+      "protocol":"bgp",
+      "vrfId":9,
+      "vrfName":"green",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":238,
+      "installed":true,
+      "table":12,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthopGroupId":"*",
+      "installedNexthopGroupId":"*",
+      "uptime":"*",
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceIndex":5,
+          "interfaceName":"r1-eth0",
+          "vrf":"default",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json
new file mode 100644 (file)
index 0000000..84b1188
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  "10.0.94.0/24":[
+    {
+      "prefix":"10.0.94.0/24",
+      "prefixLen":24,
+      "protocol":"bgp",
+      "vrfId":9,
+      "vrfName":"green",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":136,
+      "installed":true,
+      "table":12,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthopGroupId":"*",
+      "installedNexthopGroupId":"*",
+      "uptime":"*",
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"10.0.10.5",
+          "afi":"ipv4",
+          "interfaceIndex":6,
+          "interfaceName":"r1-eth1",
+          "vrf":"blue",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf_metric_propagation/r2/frr.conf b/tests/topotests/ospf_metric_propagation/r2/frr.conf
new file mode 100644 (file)
index 0000000..469ae5d
--- /dev/null
@@ -0,0 +1,81 @@
+!
+hostname r2
+password zebra
+log file /tmp/r2-frr.log
+ip forwarding
+!
+interface r2-eth0
+ ip address 10.0.1.2/24
+ ip ospf cost 100
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface r2-eth1 vrf blue
+ ip address 10.0.20.2/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface r2-eth2 vrf green
+ ip address 10.0.70.2/24
+ ip ospf cost 1000
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+router ospf
+  ospf router-id 10.0.255.2
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.1.0/24 area 0
+!
+router ospf vrf blue
+  ospf router-id 10.0.255.2
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.20.0/24 area 0
+!
+
+router ospf vrf green
+  ospf router-id 10.0.255.2
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.70.0/24 area 0
+!
+
+router bgp 99
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf blue
+    import vrf green
+  !
+!
+router bgp 99 vrf blue
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf default
+    import vrf green
+  !
+router bgp 99 vrf green
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf default
+    import vrf blue
+  !
+!
+route-map rmap permit 10
+  set metric-type type-1
+  set metric +1
+  exit
+!
+route-map costplus permit 1
+  set metric-type type-1
+  set metric +1
+  exit
diff --git a/tests/topotests/ospf_metric_propagation/r3/frr.conf b/tests/topotests/ospf_metric_propagation/r3/frr.conf
new file mode 100644 (file)
index 0000000..8dbbaf0
--- /dev/null
@@ -0,0 +1,79 @@
+!
+hostname r3
+password zebra
+log file /tmp/r3-frr.log
+ip forwarding
+!
+interface r3-eth0
+ ip address 10.0.3.3/24
+ ip ospf cost 100
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface r3-eth1 vrf blue
+ ip address 10.0.30.3/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface r3-eth2 vrf green
+ ip address 10.0.80.3/24
+ ip ospf cost 1000
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+router ospf
+  ospf router-id 10.0.255.3
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.3.0/24 area 0
+!
+router ospf vrf blue
+  ospf router-id 10.0.255.3
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.30.0/24 area 0
+!
+router ospf vrf green
+  ospf router-id 10.0.255.3
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.80.0/24 area 0
+!
+router bgp 99
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf blue
+    import vrf green
+  !
+!
+router bgp 99 vrf blue
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf default
+    import vrf green
+  !
+router bgp 99 vrf green
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf default
+    import vrf blue
+  !
+!
+route-map rmap permit 10
+  set metric-type type-1
+  set metric +1
+  exit
+!
+route-map costplus permit 1
+  set metric-type type-1
+  set metric +1
+  exit
diff --git a/tests/topotests/ospf_metric_propagation/r4/frr.conf b/tests/topotests/ospf_metric_propagation/r4/frr.conf
new file mode 100644 (file)
index 0000000..af10050
--- /dev/null
@@ -0,0 +1,78 @@
+!
+hostname r4
+password zebra
+log file /tmp/r4-frr.log
+ip forwarding
+!
+interface r4-eth0
+ ip address 10.0.3.4/24
+ ip ospf cost 100
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface r4-eth1 vrf blue
+ ip address 10.0.40.4/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface r4-eth2 vrf green
+ ip address 10.0.94.4/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+router ospf
+  ospf router-id 10.0.255.4
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.3.0/24 area 0
+!
+router ospf vrf blue
+  ospf router-id 10.0.255.4
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.40.0/24 area 0
+!
+router ospf vrf green
+  ospf router-id 10.0.255.1
+  distance 20
+  redistribute bgp route-map costplus
+  network 10.0.94.0/24 area 0
+!
+router bgp 99
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf route-map costplus
+    import vrf route-map rmap
+    import vrf blue
+    import vrf green
+  !
+!
+router bgp 99 vrf blue
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf default
+    import vrf green
+  !
+router bgp 99 vrf green
+  no bgp ebgp-requires-policy
+  address-family ipv4 unicast
+    redistribute connected
+    redistribute ospf
+    import vrf route-map rmap
+    import vrf default
+    import vrf blue
+  !
+!
+route-map rmap permit 10
+  set metric-type type-1
+  set metric +1
+  exit
+!
+route-map costplus permit 1
+  set metric-type type-1
+  set metric +1
+  exit
diff --git a/tests/topotests/ospf_metric_propagation/ra/frr.conf b/tests/topotests/ospf_metric_propagation/ra/frr.conf
new file mode 100644 (file)
index 0000000..0bc2ec5
--- /dev/null
@@ -0,0 +1,27 @@
+!
+hostname ra
+password zebra
+log file /tmp/ra-frr.log
+ip forwarding
+!
+interface ra-eth0
+ ip address 10.0.50.5/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface ra-eth1
+ ip address 10.0.10.5/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface ra-eth2
+ ip address 10.0.20.5/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+router ospf
+  ospf router-id 10.0.255.5
+  network 10.0.10.0/24 area 0
+  network 10.0.20.0/24 area 0
+  network 10.0.50.0/24 area 0
+!
diff --git a/tests/topotests/ospf_metric_propagation/rb/frr.conf b/tests/topotests/ospf_metric_propagation/rb/frr.conf
new file mode 100644 (file)
index 0000000..6f540d1
--- /dev/null
@@ -0,0 +1,27 @@
+!
+hostname rb
+password zebra
+log file /tmp/rb-frr.log
+ip forwarding
+!
+interface rb-eth0
+ ip address 10.0.50.6/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface rb-eth1
+ ip address 10.0.30.6/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface rb-eth2
+ ip address 10.0.40.6/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+router ospf
+  ospf router-id 10.0.255.6
+  network 10.0.30.0/24 area 0
+  network 10.0.40.0/24 area 0
+  network 10.0.50.0/24 area 0
+!
diff --git a/tests/topotests/ospf_metric_propagation/rc/frr.conf b/tests/topotests/ospf_metric_propagation/rc/frr.conf
new file mode 100644 (file)
index 0000000..9fc0ef7
--- /dev/null
@@ -0,0 +1,21 @@
+!
+hostname rc
+password zebra
+log file /tmp/rc-frr.log
+ip forwarding
+!
+interface rc-eth0
+ ip address 10.0.70.7/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+interface rc-eth1
+ ip address 10.0.80.7/24
+ ip ospf hello-interval 1
+ ip ospf dead-interval 3
+!
+router ospf
+  ospf router-id 10.0.255.7
+  network 10.0.70.0/24 area 0
+  network 10.0.80.0/24 area 0
+!
diff --git a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py
new file mode 100644 (file)
index 0000000..709e076
--- /dev/null
@@ -0,0 +1,374 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# test_ospf_metric_propagation.py
+#
+# Copyright (c) 2023 ATCorp
+# Jafar Al-Gharaibeh
+#
+
+import os
+import sys
+import json
+from time import sleep
+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
+
+
+"""
+test_ospf_metric_propagation.py: Test OSPF/BGP metric propagation
+"""
+
+TOPOLOGY = """
+                                      +-----+                           +-----+
+                                 eth1 |     |           eth0            |     | eth2
+                        +-------------+ rA  +---------------------------+ rB  +---------------+
+                        |          .5 |     | .5                     .6 |     | .6            |
+                        |             +--+--+     10.0.50.0/24          +--+--+ .6            |
+                        |                |.5                               |.6                |
+                        |            eth2|                             eth1|                  |
+                 10.0.10.0/24            |                                 |                  |
+                        |            10.0.20.0/24                   10.0.30.0/24          10.0.40.0/24
+                        |blue            |blue                             |blue              |blue
+                        |                |                                 |                  |
+                    eth1|.1          eth1|.2                           eth1|.3            eth1|.4
+    +-----+          +--+--+          +--+--+           +-----+          +-+---+            +-+---+         +------+
+    |     |eth0  eth2|     |   eth0   |     |eth2   eth1|     |eth2  eth3|     |   eth0     |     |eth2 eth0|      |
+    | h1  +----------+ R1  +----------+ R2  +-----------+ rC  +----------+ R3  +------------+ R4  +---------+ h2   |
+    |     |          |     |          |     |           |     |          |     |            |     |         |      |
+    +-----+.2     .1 +-----+.1      .2+-----+.2      .7 +-----+.7      .3+-----+.3        .4+-----+.4     .2+------+
+                  green                    green                      green                       green
+
+       10.0.91.0/24        10.0.1.0/24      10.0.70.0/24      10.0.80.0/24     10.0.3.0/24        10.0.94.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.ospfd, pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+    "Build function"
+
+    # Create 4 routers
+    for routern in range(1, 5):
+        tgen.add_router("r{}".format(routern))
+
+    tgen.add_router("ra")
+    tgen.add_router("rb")
+    tgen.add_router("rc")
+    tgen.add_router("h1")
+    tgen.add_router("h2")
+
+
+    # Interconect router 1, 2
+    switch = tgen.add_switch("s1-2")
+    switch.add_link(tgen.gears["r1"])
+    switch.add_link(tgen.gears["r2"])
+
+    # Interconect router 3, 4
+    switch = tgen.add_switch("s3-4")
+    switch.add_link(tgen.gears["r3"])
+    switch.add_link(tgen.gears["r4"])
+
+    # Interconect router a, b
+    switch = tgen.add_switch("sa-b")
+    switch.add_link(tgen.gears["ra"])
+    switch.add_link(tgen.gears["rb"])
+
+    # Interconect router 1, a
+    switch = tgen.add_switch("s1-a")
+    switch.add_link(tgen.gears["r1"])
+    switch.add_link(tgen.gears["ra"])
+
+    # Interconect router 2, a
+    switch = tgen.add_switch("s2-a")
+    switch.add_link(tgen.gears["r2"])
+    switch.add_link(tgen.gears["ra"])
+
+    # Interconect router 3, b
+    switch = tgen.add_switch("s3-b")
+    switch.add_link(tgen.gears["r3"])
+    switch.add_link(tgen.gears["rb"])
+
+    # Interconect router 4, b
+    switch = tgen.add_switch("s4-b")
+    switch.add_link(tgen.gears["r4"])
+    switch.add_link(tgen.gears["rb"])
+
+    # Interconect router 1, h1
+    switch = tgen.add_switch("s1-h1")
+    switch.add_link(tgen.gears["r1"])
+    switch.add_link(tgen.gears["h1"])
+
+    # Interconect router 4, h2
+    switch = tgen.add_switch("s4-h2")
+    switch.add_link(tgen.gears["r4"])
+    switch.add_link(tgen.gears["h2"])
+
+    # Interconect router 2, c
+    switch = tgen.add_switch("s2-c")
+    switch.add_link(tgen.gears["r2"])
+    switch.add_link(tgen.gears["rc"])
+
+    # Interconect router 3, c
+    switch = tgen.add_switch("s3-c")
+    switch.add_link(tgen.gears["r3"])
+    switch.add_link(tgen.gears["rc"])
+
+def setup_module(mod):
+    logger.info("OSPF Metric Propagation:\n {}".format(TOPOLOGY))
+
+    tgen = Topogen(build_topo, mod.__name__)
+    tgen.start_topology()
+
+    vrf_setup_cmds = [
+        "ip link add name blue type vrf table 11",
+        "ip link set dev blue up",
+        "ip link add name green type vrf table 12",
+        "ip link set dev green up",
+    ]
+
+    # Starting Routers
+    router_list = tgen.routers()
+
+    # Create VRFs and bind to interfaces
+    for routern in range(1, 5):
+        for cmd in vrf_setup_cmds:
+            tgen.net["r{}".format(routern)].cmd(cmd)
+    for routern in range(1, 5):
+        tgen.net["r{}".format(routern)].cmd("ip link set dev r{}-eth1 vrf blue up".format(routern))
+        tgen.net["r{}".format(routern)].cmd("ip link set dev r{}-eth2 vrf green up".format(routern))
+
+    for rname, router in router_list.items():
+        logger.info("Loading router %s" % rname)
+        router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+    # Initialize all routers.
+    tgen.start_router()
+    for router in router_list.values():
+        if router.has_version("<", "4.20"):
+            tgen.set_error("unsupported version")
+
+
+def teardown_module(mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+
+def test_all_links_up():
+    "Test path R1 -> Ra -> Rb -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    r1 = tgen.gears["r1"]
+    json_file = "{}/r1/show_ip_route-1.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=40, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    assert result is None, assertmsg
+
+
+def test_link_1_down():
+    "Test path R1 -> R2 -> Ra -> Rb -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    tgen.net["r1"].cmd("ip link set dev r1-eth1 down")
+    r1 = tgen.gears["r1"]
+
+    json_file = "{}/r1/show_ip_route-2.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    assert result is None, assertmsg
+
+
+def test_link_1_2_down():
+    "Test path R1 -> R2 -> Rc -> R3 -> Rb -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    tgen.net["r2"].cmd("ip link set dev r2-eth1 down")
+    r1 = tgen.gears["r1"]
+
+    json_file = "{}/r1/show_ip_route-3.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    assert result is None, assertmsg
+
+
+def test_link_1_2_3_down():
+    "Test path R1 -> R2 -> Rc -> R3  -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    tgen.net["r3"].cmd("ip link set dev r3-eth0 down")
+    tgen.net["r3"].cmd("ip link set dev r3-eth1 down")
+    # ospf dead-interval is set to 3 seconds, wait 5 seconds to clear the neighbor
+    sleep(5)
+    tgen.net["r3"].cmd("ip link set dev r3-eth0 up")
+    r1 = tgen.gears["r1"]
+
+    json_file = "{}/r1/show_ip_route-4.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    assert result is None, assertmsg
+
+def test_link_1_2_3_4_down():
+    "Test path R1 -> R2 -> Rc -> R3  -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    tgen.net["r4"].cmd("ip link set dev r4-eth1 down")
+    r1 = tgen.gears["r1"]
+
+    json_file = "{}/r1/show_ip_route-4.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    assert result is None, assertmsg
+
+def test_link_1_2_4_down():
+    "Test path R1 -> R2 -> Rc -> R3  -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    # bring link 3 back up
+    tgen.net["r3"].cmd("ip link set dev r3-eth1 up")
+    r1 = tgen.gears["r1"]
+
+    json_file = "{}/r1/show_ip_route-4.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    assert result is None, assertmsg
+
+def test_link_1_4_down():
+    "Test path R1 -> R2 -> Ra -> Rb -> R3  -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    # bring back link 2 up
+    tgen.net["r2"].cmd("ip link set dev r2-eth1 up")
+    r1 = tgen.gears["r1"]
+
+    json_file = "{}/r1/show_ip_route-5.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    assert result is None, assertmsg
+
+
+def test_link_4_down():
+    "Test path R1 -> Ra -> Rb -> R3  -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    # bring back link 1 up
+    tgen.net["r1"].cmd("ip link set dev r1-eth1 up")
+    r1 = tgen.gears["r1"]
+
+    json_file = "{}/r1/show_ip_route-6.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    assert result is None, assertmsg
+
+
+def test_link_1_2_3_4_up():
+    "Test path R1 -> Ra -> Rb -> R4"
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    # bring back link 4 up
+    tgen.net["r4"].cmd("ip link set dev r4-eth1 up")
+    r1 = tgen.gears["r1"]
+
+    json_file = "{}/r1/show_ip_route-1.json".format(CWD)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+
+    assertmsg = "r1 JSON output mismatches"
+    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))