]> git.puffer.fish Git - matthieu/frr.git/commitdiff
tests: Add IGMP/PIM VRF test
authorMartin Winter <mwinter@opensourcerouting.org>
Tue, 4 May 2021 02:07:45 +0000 (04:07 +0200)
committerMartin Winter <mwinter@opensourcerouting.org>
Tue, 6 Jul 2021 12:23:55 +0000 (14:23 +0200)
Signed-off-by: Martin Winter <mwinter@opensourcerouting.org>
24 files changed:
tests/topotests/pim_igmp_vrf/h1/zebra.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/h2/zebra.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/h3/zebra.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/h4/zebra.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/ospfd.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/pim_blue_join.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/pim_blue_neighbor.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/pim_blue_pimreg11.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/pim_red_join.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/pim_red_neighbor.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/pim_red_pimreg12.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/pimd.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r1/zebra.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r11/ospfd.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r11/pim_blue_join.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r11/pimd.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r11/zebra.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r12/ospfd.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r12/pim_red_join.json [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r12/pimd.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/r12/zebra.conf [new file with mode: 0644]
tests/topotests/pim_igmp_vrf/test_pim_vrf.py [new file with mode: 0755]

diff --git a/tests/topotests/pim_igmp_vrf/h1/zebra.conf b/tests/topotests/pim_igmp_vrf/h1/zebra.conf
new file mode 100644 (file)
index 0000000..3d6540d
--- /dev/null
@@ -0,0 +1,10 @@
+!
+hostname h1
+log file zebra.log
+!
+interface h1-eth0
+ description connection to r1 via sw1
+ ip address 192.168.100.10/24
+!
+ip route 0.0.0.0/0 192.168.100.1
+!
diff --git a/tests/topotests/pim_igmp_vrf/h2/zebra.conf b/tests/topotests/pim_igmp_vrf/h2/zebra.conf
new file mode 100644 (file)
index 0000000..95342f9
--- /dev/null
@@ -0,0 +1,8 @@
+hostname h2
+!
+interface h2-eth0
+ description connection to r1 via sw2
+ ip address 192.168.101.2/24
+!
+ip route 0.0.0.0/0 192.168.101.1
+!
diff --git a/tests/topotests/pim_igmp_vrf/h3/zebra.conf b/tests/topotests/pim_igmp_vrf/h3/zebra.conf
new file mode 100644 (file)
index 0000000..ef99b1c
--- /dev/null
@@ -0,0 +1,10 @@
+!
+hostname h3
+log file zebra.log
+!
+interface h3-eth0
+ description connection to r1 via sw3
+ ip address 192.168.100.20/24
+!
+ip route 0.0.0.0/0 192.168.100.1
+!
diff --git a/tests/topotests/pim_igmp_vrf/h4/zebra.conf b/tests/topotests/pim_igmp_vrf/h4/zebra.conf
new file mode 100644 (file)
index 0000000..6a2e466
--- /dev/null
@@ -0,0 +1,8 @@
+hostname h4
+!
+interface h4-eth0
+ description connection to r1 via sw4
+ ip address 192.168.101.4/24
+!
+ip route 0.0.0.0/0 192.168.101.1
+!
diff --git a/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json
new file mode 100644 (file)
index 0000000..604d25f
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "blue":{
+    "vrfName":"blue",
+    "neighbors":{
+      "192.168.0.11":[
+        {
+          "priority":10,
+          "state":"Full\/Backup",
+          "address":"192.168.101.11",
+          "ifaceName":"r1-eth1:192.168.101.1"
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json
new file mode 100644 (file)
index 0000000..456bb87
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "red":{
+    "vrfName":"red",
+    "neighbors":{
+      "192.168.0.12":[
+        {
+          "priority":10,
+          "state":"Full\/Backup",
+          "address":"192.168.101.12",
+          "ifaceName":"r1-eth3:192.168.101.1"
+        }
+      ]
+    }
+  }
+}
+
diff --git a/tests/topotests/pim_igmp_vrf/r1/ospfd.conf b/tests/topotests/pim_igmp_vrf/r1/ospfd.conf
new file mode 100644 (file)
index 0000000..263b586
--- /dev/null
@@ -0,0 +1,26 @@
+hostname r1
+!
+debug ospf event
+!
+!
+interface r1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 20
+!
+interface r1-eth3
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 20
+!
+router ospf vrf blue
+ ospf router-id 192.168.0.1
+ network 192.168.0.1/32 area 0
+ network 192.168.100.0/24 area 0
+ network 192.168.101.0/24 area 0
+router ospf vrf red
+ ospf router-id 192.168.0.1
+ network 192.168.0.1/32 area 0
+ network 192.168.100.0/24 area 0
+ network 192.168.101.0/24 area 0
+!
diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_blue_join.json b/tests/topotests/pim_igmp_vrf/r1/pim_blue_join.json
new file mode 100644 (file)
index 0000000..8568bae
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "r1-eth0":{
+    "name":"r1-eth0",
+    "state":"up",
+    "address":"192.168.100.1",
+    "flagMulticast":true,
+    "flagBroadcast":true,
+    "lanDelayEnabled":true,
+    "239.100.0.1":{
+      "*":{
+        "source":"*",
+        "group":"239.100.0.1",
+        "upTime":"--:--:--",
+        "expire":"--:--",
+        "prune":"--:--",
+        "channelJoinName":"NOINFO",
+        "protocolIgmp":1
+      }
+    }
+  }
+}
+
diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_blue_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/pim_blue_neighbor.json
new file mode 100644 (file)
index 0000000..ea7d4ac
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "blue":{
+  },
+  "r1-eth0":{
+  },
+  "r1-eth1":{
+    "192.168.101.11":{
+      "interface":"r1-eth1",
+      "neighbor":"192.168.101.11",
+      "drPriority":1
+    }
+  }
+}
diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_blue_pimreg11.json b/tests/topotests/pim_igmp_vrf/r1/pim_blue_pimreg11.json
new file mode 100644 (file)
index 0000000..d3642f8
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "pimreg11":{
+    "name":"pimreg11",
+    "state":"up",
+    "address":"0.0.0.0",
+    "flagAllMulticast":true,
+    "lanDelayEnabled":true,
+    "drAddress":"*",
+    "drPriority":1,
+    "drUptime":"--:--:--",
+    "drElections":0,
+    "drChanges":0
+  }
+}
diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_red_join.json b/tests/topotests/pim_igmp_vrf/r1/pim_red_join.json
new file mode 100644 (file)
index 0000000..d0037ca
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "r1-eth2":{
+    "name":"r1-eth2",
+    "state":"up",
+    "address":"192.168.100.1",
+    "flagMulticast":true,
+    "flagBroadcast":true,
+    "lanDelayEnabled":true,
+    "239.100.0.1":{
+      "*":{
+        "source":"*",
+        "group":"239.100.0.1",
+        "upTime":"--:--:--",
+        "expire":"--:--",
+        "prune":"--:--",
+        "channelJoinName":"NOINFO",
+        "protocolIgmp":1
+      }
+    }
+  }
+}
diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_red_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/pim_red_neighbor.json
new file mode 100644 (file)
index 0000000..e17b408
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "r1-eth2":{
+  },
+  "r1-eth3":{
+    "192.168.101.12":{
+      "interface":"r1-eth3",
+      "neighbor":"192.168.101.12",
+      "drPriority":1
+    }
+  },
+  "red":{
+  }
+}
diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_red_pimreg12.json b/tests/topotests/pim_igmp_vrf/r1/pim_red_pimreg12.json
new file mode 100644 (file)
index 0000000..45b6cd9
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "pimreg12":{
+    "name":"pimreg12",
+    "state":"up",
+    "address":"0.0.0.0",
+    "flagAllMulticast":true,
+    "lanDelayEnabled":true,
+    "drAddress":"*",
+    "drPriority":1,
+    "drUptime":"--:--:--",
+    "drElections":0,
+    "drChanges":0
+  }
+}
diff --git a/tests/topotests/pim_igmp_vrf/r1/pimd.conf b/tests/topotests/pim_igmp_vrf/r1/pimd.conf
new file mode 100644 (file)
index 0000000..6ee264d
--- /dev/null
@@ -0,0 +1,26 @@
+hostname r1
+!
+debug igmp events
+debug igmp packets
+debug pim events
+debug pim packets
+debug pim trace
+debug pim zebra
+debug pim bsm
+!
+interface r1-eth0
+ ip igmp
+ ip igmp version 2
+ ip pim
+!
+interface r1-eth1
+ ip pim
+!
+interface r1-eth2
+ ip igmp
+ ip igmp version 2
+ ip pim
+!
+interface r1-eth3
+ ip pim
+!
diff --git a/tests/topotests/pim_igmp_vrf/r1/zebra.conf b/tests/topotests/pim_igmp_vrf/r1/zebra.conf
new file mode 100644 (file)
index 0000000..9da9280
--- /dev/null
@@ -0,0 +1,30 @@
+!
+hostname r1
+log file zebra.log
+!
+ip forwarding
+ipv6 forwarding
+!
+interface blue vrf blue
+ ip address 192.168.0.1/32
+!
+interface red vrf red
+ ip address 192.168.0.1/32
+!
+interface r1-eth0 vrf blue
+ description connection to h1 via sw1
+ ip address 192.168.100.1/24
+!
+interface r1-eth1 vrf blue
+ description connection to r11 via sw2
+ ip address 192.168.101.1/24
+!
+interface r1-eth2 vrf red
+ description connection to h1 via sw3
+ ip address 192.168.100.1/24
+!
+interface r1-eth3 vrf red
+ description connection to r12 via sw4
+ ip address 192.168.101.1/24
+!
+
diff --git a/tests/topotests/pim_igmp_vrf/r11/ospfd.conf b/tests/topotests/pim_igmp_vrf/r11/ospfd.conf
new file mode 100644 (file)
index 0000000..e107220
--- /dev/null
@@ -0,0 +1,14 @@
+hostname r11
+!
+debug ospf event
+!
+interface r11-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 10
+!
+router ospf
+ ospf router-id 192.168.0.11
+ network 192.168.0.11/32 area 0
+ network 192.168.101.0/24 area 0
+!
diff --git a/tests/topotests/pim_igmp_vrf/r11/pim_blue_join.json b/tests/topotests/pim_igmp_vrf/r11/pim_blue_join.json
new file mode 100644 (file)
index 0000000..289bf51
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "r11-eth0":{
+    "name":"r11-eth0",
+    "state":"up",
+    "address":"192.168.101.11",
+    "flagMulticast":true,
+    "flagBroadcast":true,
+    "lanDelayEnabled":true,
+    "239.100.0.1":{
+      "*":{
+        "source":"*",
+        "group":"239.100.0.1",
+        "prune":"--:--",
+        "channelJoinName":"JOIN",
+        "protocolPim":1
+      }
+    }
+  }
+}
diff --git a/tests/topotests/pim_igmp_vrf/r11/pimd.conf b/tests/topotests/pim_igmp_vrf/r11/pimd.conf
new file mode 100644 (file)
index 0000000..05cd5ac
--- /dev/null
@@ -0,0 +1,16 @@
+hostname r11
+!
+debug pim events
+debug pim packets
+debug pim trace
+debug pim zebra
+debug pim bsm
+!
+ip pim rp 192.168.0.11 239.100.0.0/28
+!
+interface lo
+ ip pim
+!
+interface r11-eth0
+ ip pim
+!
diff --git a/tests/topotests/pim_igmp_vrf/r11/zebra.conf b/tests/topotests/pim_igmp_vrf/r11/zebra.conf
new file mode 100644 (file)
index 0000000..137706d
--- /dev/null
@@ -0,0 +1,13 @@
+!
+hostname r11
+log file zebra.log
+!
+interface lo
+ ip address 192.168.0.11/32
+!
+interface r11-eth0
+ description connection to r1 via sw1
+ ip address 192.168.101.11/24
+!
+ip route 0.0.0.0/0 192.168.101.1
+!
diff --git a/tests/topotests/pim_igmp_vrf/r12/ospfd.conf b/tests/topotests/pim_igmp_vrf/r12/ospfd.conf
new file mode 100644 (file)
index 0000000..03acc82
--- /dev/null
@@ -0,0 +1,14 @@
+hostname r12
+!
+debug ospf event
+!
+interface r12-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 10
+!
+router ospf
+ ospf router-id 192.168.0.12
+ network 192.168.0.12/32 area 0
+ network 192.168.101.0/24 area 0
+!
diff --git a/tests/topotests/pim_igmp_vrf/r12/pim_red_join.json b/tests/topotests/pim_igmp_vrf/r12/pim_red_join.json
new file mode 100644 (file)
index 0000000..6926246
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "r12-eth0":{
+    "name":"r12-eth0",
+    "state":"up",
+    "address":"192.168.101.12",
+    "flagMulticast":true,
+    "flagBroadcast":true,
+    "lanDelayEnabled":true,
+    "239.100.0.1":{
+      "*":{
+        "source":"*",
+        "group":"239.100.0.1",
+        "prune":"--:--",
+        "channelJoinName":"JOIN",
+        "protocolPim":1
+      }
+    }
+  }
+}
diff --git a/tests/topotests/pim_igmp_vrf/r12/pimd.conf b/tests/topotests/pim_igmp_vrf/r12/pimd.conf
new file mode 100644 (file)
index 0000000..531aec6
--- /dev/null
@@ -0,0 +1,16 @@
+hostname r12
+!
+debug pim events
+debug pim packets
+debug pim trace
+debug pim zebra
+debug pim bsm
+!
+ip pim rp 192.168.0.12 239.100.0.0/28
+!
+interface lo
+ ip pim
+!
+interface r12-eth0
+ ip pim
+!
diff --git a/tests/topotests/pim_igmp_vrf/r12/zebra.conf b/tests/topotests/pim_igmp_vrf/r12/zebra.conf
new file mode 100644 (file)
index 0000000..bede104
--- /dev/null
@@ -0,0 +1,13 @@
+!
+hostname r12
+log file zebra.log
+!
+interface lo
+ ip address 192.168.0.12/32
+!
+interface r12-eth0
+ description connection to r1 via sw1
+ ip address 192.168.101.12/24
+!
+ip route 0.0.0.0/0 192.168.101.1
+!
diff --git a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py
new file mode 100755 (executable)
index 0000000..298adef
--- /dev/null
@@ -0,0 +1,462 @@
+#!/usr/bin/env python
+
+#
+# test_pim_vrf.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_pim_vrf.py: Test PIM with VRFs.
+"""
+
+# Tests PIM with VRF
+#
+# R1 is split into 2 VRF: Blue and Red, the others are normal
+# routers and Hosts
+# There are 2 similar topologies with overlapping IPs in each
+# section. 
+#
+# Test steps:
+# - setup_module()
+#     Create topology. Hosts are only using zebra/staticd,
+#     no PIM, no OSPF (using IGMPv2 for multicast)
+# - test_ospf_convergence()
+#     Wait for OSPF convergence in each VRF. OSPF is run on
+#     R1, R11 and R12.
+# - test_pim_convergence()
+#     Wait for PIM convergence in each VRF. PIM is run on
+#     R1, R11 and R12. R11 is the RP for vrf blue, R12 is RP
+#     for vrf red.
+# - test_vrf_pimreg_interfaces()
+#     Adding PIM RP in VRF information and verify pimreg 
+#     interfaces in VRF blue and red
+# - test_mcast_vrf_blue()
+#     Start multicast stream for group 239.100.0.1 from Host 
+#     H2 and join from Host H1 on vrf blue
+#     Verify PIM JOIN status on R1 and R11
+#     Stop multicast after verification
+# - test_mcast_vrf_red()
+#     Start multicast stream for group 239.100.0.1 from Host 
+#     H4 and join from Host H3 on vrf blue
+#     Verify PIM JOIN status on R1 and R12
+#     Stop multicast after verification
+# - teardown_module(module)
+#     shutdown topology
+#
+
+TOPOLOGY = """
+                                               +----------+
+                                               |  Host H2 |
+                                               |  Source  |
+                                               +----------+
+                                                 .2 |
++---------+                  +------------+         |        +---------+
+| Host H1 | 192.168.100.0/24 |            | .1      |    .11 | Host H2 |
+| receive |------------------|  VRF Blue  |---------+--------| PIM RP  |
+|IGMP JOIN| .10           .1 |            | 192.168.101.0/24 |         |  
++---------+                  |            |                  +---------+
+                            =| = = R1 = = |=
++---------+                  |            |                  +---------+
+| Host H3 | 192.168.100.0/24 |            | 192.168.101.0/24 | Host H4 |
+| receive |------------------|  VRF Red   |---------+--------| PIM RP  |
+|IGMP JOIN| .20           .1 |            | .1      |    .12 |         |
++---------+                  +------------+         |        +---------+
+                                                 .4 | 
+                                               +----------+
+                                               |  Host H4 |
+                                               |  Source  |
+                                               +----------+
+"""
+
+import json
+import functools
+import os
+import sys
+import pytest
+import re
+import time
+from time import sleep
+import socket
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# 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.topotest import iproute2_is_vrf_capable
+from lib.common_config import (
+    required_linux_kernel_version)
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+pytestmark = [pytest.mark.pimd]
+
+
+#
+# Test global variables:
+# They are used to handle communicating with external application.
+#
+APP_SOCK_PATH = '/tmp/topotests/apps.sock'
+HELPER_APP_PATH = os.path.join(CWD, "../lib/mcast-tester.py")
+app_listener = None
+app_clients = {}
+
+def listen_to_applications():
+    "Start listening socket to connect with applications."
+    # Remove old socket.
+    try:
+        os.unlink(APP_SOCK_PATH)
+    except OSError:
+        pass
+
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
+    sock.bind(APP_SOCK_PATH)
+    sock.listen(10)
+    global app_listener
+    app_listener = sock
+
+def accept_host(host):
+    "Accept connection from application running in hosts."
+    global app_listener, app_clients
+    conn = app_listener.accept()
+    app_clients[host] = {
+        'fd': conn[0],
+        'address': conn[1]
+    }
+
+def close_applications():
+    "Signal applications to stop and close all sockets."
+    global app_listener, app_clients
+
+    if app_listener:
+        # Close listening socket.
+        app_listener.close()
+
+        # Remove old socket.
+        try:
+            os.unlink(APP_SOCK_PATH)
+        except OSError:
+            pass
+
+    # Close all host connections.
+    for host in ["h1", "h2"]:
+        if app_clients.get(host) is None:
+            continue
+        app_clients[host]["fd"].close()
+
+    # Reset listener and clients data struct
+    app_listener = None
+    app_clients = {}
+
+
+class PIMVRFTopo(Topo):
+    "PIM VRF Test Topology"
+
+    def build(self):
+        tgen = get_topogen(self)
+
+        # Create the hosts
+        for hostNum in range(1,5):
+            tgen.add_router("h{}".format(hostNum))
+
+        # Create the main router
+        tgen.add_router("r1")
+
+        # Create the PIM RP routers
+        for rtrNum in range(11, 13):
+            tgen.add_router("r{}".format(rtrNum))
+
+        # Setup Switches and connections
+        for swNum in range(1, 5):
+            tgen.add_switch("sw{}".format(swNum))
+        
+        ################
+        # 1st set of connections to routers for VRF red
+        ################
+
+        # Add connections H1 to R1 switch sw1
+        tgen.gears["h1"].add_link(tgen.gears["sw1"])
+        tgen.gears["r1"].add_link(tgen.gears["sw1"])
+
+        # Add connections R1 to R1x switch sw2
+        tgen.gears["r1"].add_link(tgen.gears["sw2"])
+        tgen.gears["h2"].add_link(tgen.gears["sw2"])
+        tgen.gears["r11"].add_link(tgen.gears["sw2"])
+
+        ################
+        # 2nd set of connections to routers for vrf blue
+        ################
+
+        # Add connections H1 to R1 switch sw1
+        tgen.gears["h3"].add_link(tgen.gears["sw3"])
+        tgen.gears["r1"].add_link(tgen.gears["sw3"])
+
+        # Add connections R1 to R1x switch sw2
+        tgen.gears["r1"].add_link(tgen.gears["sw4"])
+        tgen.gears["h4"].add_link(tgen.gears["sw4"])
+        tgen.gears["r12"].add_link(tgen.gears["sw4"])
+
+#####################################################
+#
+#   Tests starting
+#
+#####################################################
+
+def setup_module(module):
+    logger.info("PIM IGMP VRF Topology: \n {}".format(TOPOLOGY))
+
+    tgen = Topogen(PIMVRFTopo, module.__name__)
+    tgen.start_topology()
+
+    vrf_setup_cmds = [
+        "ip link add name blue type vrf table 11",
+        "ip link add name red type vrf table 12",
+        "ip link set dev blue up",
+        "ip link set dev red up",
+        "ip link set dev r1-eth0 vrf blue up",
+        "ip link set dev r1-eth1 vrf blue up",
+        "ip link set dev r1-eth2 vrf red up",
+        "ip link set dev r1-eth3 vrf red up",
+    ]
+
+    # Starting Routers
+    router_list = tgen.routers()
+
+    # Create VRF on r2 first and add it's interfaces
+    for cmd in vrf_setup_cmds:
+        tgen.net["r1"].cmd(cmd)
+
+    for rname, router in router_list.items():
+        logger.info("Loading router %s" % rname)
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        if rname[0] != 'h':
+            # Only load ospf on routers, not on end hosts
+            router.load_config(
+                TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+            )
+            router.load_config(
+                TopoRouter.RD_PIM, os.path.join(CWD, "{}/pimd.conf".format(rname))
+            )
+    tgen.start_router()
+
+
+def teardown_module(module):
+    tgen = get_topogen()
+    tgen.stop_topology()
+    close_applications()
+
+
+def test_ospf_convergence():
+    "Test for OSPFv2 convergence"
+    tgen = get_topogen()
+
+    # Required linux kernel version for this suite to run.
+    result = required_linux_kernel_version("4.15")
+    if result is not True:
+        pytest.skip("Kernel requirements are not met")
+
+    # iproute2 needs to support VRFs for this suite to run.
+    if not iproute2_is_vrf_capable():
+        pytest.skip("Installed iproute2 version does not support VRFs")
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Checking OSPFv2 convergence on router r1 for VRF blue")
+
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/ospf_blue_neighbor.json")
+    expected = json.loads(open(reffile).read())
+
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip ospf vrf blue neighbor json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=60, wait=2)
+    assertmsg = "OSPF router R1 did not converge on VRF blue"
+    assert res is None, assertmsg
+
+    logger.info("Checking OSPFv2 convergence on router r1 for VRF red")
+
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/ospf_red_neighbor.json")
+    expected = json.loads(open(reffile).read())
+
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip ospf vrf red neighbor json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=60, wait=2)
+    assertmsg = "OSPF router R1 did not converge on VRF red"
+    assert res is None, assertmsg
+
+
+def test_pim_convergence():
+    "Test for PIM convergence"
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Checking PIM convergence on router r1 for VRF red")
+
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/pim_red_neighbor.json")
+    expected = json.loads(open(reffile).read())
+
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip pim vrf red neighbor json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=30, wait=2)
+    assertmsg = "PIM router R1 did not converge for VRF red"
+    assert res is None, assertmsg
+
+    logger.info("Checking PIM convergence on router r1 for VRF blue")
+
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/pim_blue_neighbor.json")
+    expected = json.loads(open(reffile).read())
+
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip pim vrf blue neighbor json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=30, wait=2)
+    assertmsg = "PIM router R1 did not converge for VRF blue"
+    assert res is None, assertmsg
+
+
+def test_vrf_pimreg_interfaces():
+    "Adding PIM RP in VRF information and verify pimreg interfaces"
+    tgen = get_topogen()
+
+    r1 = tgen.gears["r1"]
+    r1.vtysh_cmd("conf\ninterface blue\nip pim")
+    r1.vtysh_cmd("conf\nvrf blue\nip pim rp 192.168.0.11 239.100.0.1/32\nexit-vrf")
+
+    # Check pimreg11 interface on R1, VRF blue
+    reffile = os.path.join(CWD, "r1/pim_blue_pimreg11.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, r1, "show ip pim vrf blue inter pimreg11 json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=5, wait=2)
+    assertmsg = "PIM router R1, VRF blue (table 11) pimreg11 interface missing or incorrect status"
+    assert res is None, assertmsg
+
+    r1.vtysh_cmd("conf\ninterface red\nip pim")
+    r1.vtysh_cmd("conf\nvrf red\nip pim rp 192.168.0.12 239.100.0.1/32\nexit-vrf")
+
+    # Check pimreg12 interface on R1, VRF red
+    reffile = os.path.join(CWD, "r1/pim_red_pimreg12.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, r1, "show ip pim vrf red inter pimreg12 json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=5, wait=2)
+    assertmsg = "PIM router R1, VRF red (table 12) pimreg12 interface missing or incorrect status"
+    assert res is None, assertmsg
+
+
+##################################
+###  Test PIM / IGMP with VRF
+##################################
+
+def check_mcast_entry(mcastaddr, pimrp, receiver, sender, vrf):
+    "Helper function to check RP"
+    tgen = get_topogen()
+
+    logger.info("Testing PIM for VRF {} entry using {}".format(vrf, mcastaddr));
+
+    # Start applications socket.
+    listen_to_applications()
+
+    tgen.gears[sender].run("{} --send='0.7' '{}' '{}' '{}' &".format(
+        HELPER_APP_PATH, APP_SOCK_PATH, mcastaddr, '{}-eth0'.format(sender)))
+    accept_host(sender)
+
+    tgen.gears[receiver].run("{} '{}' '{}' '{}' &".format(
+        HELPER_APP_PATH, APP_SOCK_PATH, mcastaddr, '{}-eth0'.format(receiver)))
+    accept_host(receiver)
+
+    logger.info("mcast join and source for {} started".format(mcastaddr))
+
+    # tgen.mininet_cli()
+
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/pim_{}_join.json".format(vrf))
+    expected = json.loads(open(reffile).read())
+
+    logger.info("verifying pim join on r1 for {} on VRF {}".format(mcastaddr, vrf))
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip pim vrf {} join json".format(vrf),
+        expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=2)
+    assertmsg = "PIM router r1 did not show join status on VRF".format(vrf)
+    assert res is None, assertmsg
+
+    logger.info("verifying pim join on PIM RP {} for {}".format(pimrp, mcastaddr))
+    router = tgen.gears[pimrp]
+    reffile = os.path.join(CWD, "{}/pim_{}_join.json".format(pimrp, vrf))
+    expected = json.loads(open(reffile).read())
+
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip pim join json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=2)
+    assertmsg = "PIM router {} did not get selected as the PIM RP for VRF {}".format(pimrp, vrf)
+    assert res is None, assertmsg
+
+    close_applications()
+    return
+
+
+def test_mcast_vrf_blue():
+    "Test vrf blue with 239.100.0.1"
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    check_mcast_entry('239.100.0.1', 'r11', 'h1', 'h2', 'blue')
+
+
+def test_mcast_vrf_red():
+    "Test vrf red with 239.100.0.1"
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    check_mcast_entry('239.100.0.1', 'r12', 'h3', 'h4', 'red')
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))