Merge "Fix HA test on Fabric"
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index 08d8505..bd00623 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -593,10 +593,9 @@
                 pingResponse += str( str( host ) + " -> " )
                 for temp in dstList:
                     failedPings = 0
-                    if ipv6:
-                        pingCmd = str( host ) + cmd + str( self.getIPAddress( temp, proto='IPv6' ) )
-                    else:
-                        pingCmd = str( host ) + cmd + str( temp )
+                    dstIP = self.getIPAddress( temp, proto='IPV6' if ipv6 else 'IPV4' )
+                    assert dstIP, "Not able to get IP address of host {}".format( temp )
+                    pingCmd = str( host ) + cmd + str( dstIP )
                     while failedPings <= acceptableFailed:
                         main.log.debug( "Pinging from " + str( host ) + " to " + str( temp ) )
                         self.handle.sendline( pingCmd )
@@ -616,7 +615,9 @@
                 pingResponse += "\n"
             main.log.info( pingResponse + "Failed pings: " + str( failedPingsTotal ) )
             return isReachable
-
+        except AssertionError:
+            main.log.exception( "" )
+            return main.FALSE
         except pexpect.TIMEOUT:
             main.log.exception( self.name + ": TIMEOUT exception" )
             response = self.handle.before
@@ -750,6 +751,10 @@
                                           '\*\*\* Unknown command: ' + pingCmd,
                                           pexpect.TIMEOUT ],
                                         timeout=wait + 1 )
+                # For some reason we need to send something
+                # Otherwise ping results won't be read by handle
+                self.handle.sendline( "" )
+                self.handle.expect( self.hostPrompt )
                 if i == 0:
                     response = self.handle.before
                     if not re.search( ',\s0\%\spacket\sloss', response ):
@@ -1268,7 +1273,7 @@
         else:
             main.log.error( "Connection failed to the host" )
 
-    def getIPAddress( self, host , proto='IPV4' ):
+    def getIPAddress( self, host, proto='IPV4' ):
         """
            Verifies the host's ip configured or not."""
         if self.handle:
@@ -1288,7 +1293,7 @@
 
             pattern = ''
             if proto == 'IPV4':
-                pattern = "inet\saddr:(\d+\.\d+\.\d+\.\d+)"
+                pattern = "inet\saddr:(\d+\.\d+\.\d+\.\d+)\s\sBcast"
             else:
                 pattern = "inet6\saddr:\s([\w,:]*)/\d+\sScope:Global"
             ipAddressSearch = re.search( pattern, response )
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index 09aa7a4..d6039e3 100755
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -6243,7 +6243,7 @@
         Delete multicast sink(s) by calling 'mcast-host-delete' command
         sAddr: we can provide * for ASM or a specific address for SSM
         gAddr: specifies multicast group address
-        hosts: HostId of the sink e.g. "00:AA:00:00:01:05/40",
+        host: HostId of the sink e.g. "00:AA:00:00:01:05/40",
                will delete the route if not specified
         Returns main.TRUE if the mcast sink is deleted; Otherwise main.FALSE
         """
@@ -6319,3 +6319,107 @@
         except Exception:
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanAndExit()
+
+    def netcfg( self, jsonFormat=True, args="" ):
+        """
+        Run netcfg cli command with given args
+        """
+        try:
+            cmdStr = "netcfg"
+            if jsonFormat:
+                cmdStr = cmdStr + " -j"
+            if args:
+                cmdStr = cmdStr + " " + str( args )
+            handle = self.sendline( cmdStr )
+            assert handle is not None, "Error in sendline"
+            assert "Command not found:" not in handle, handle
+            assert "Unsupported command:" not in handle, handle
+            assert "Error executing command" not in handle, handle
+            return handle
+        except AssertionError:
+            main.log.exception( "" )
+            return None
+        except TypeError:
+            main.log.exception( self.name + ": Object not as expected" )
+            return None
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanAndExit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanAndExit()
+
+    def composeT3Command( self, sAddr, dAddr, ipv6=False, verbose=True ):
+        """
+        Compose and return t3-troubleshoot cli command for given source and destination addresses
+        Options:
+            sAddr: IP address of the source host
+            dAddr: IP address of the destination host
+        """
+        try:
+            # Collect information of both hosts from onos
+            hosts = self.hosts()
+            hosts = json.loads( hosts )
+            sHost = None
+            dHost = None
+            for host in hosts:
+                if sAddr in host[ "ipAddresses" ]:
+                    sHost = host
+                elif dAddr in host[ "ipAddresses" ]:
+                    dHost = host
+                if sHost and dHost:
+                    break
+            assert sHost, "Not able to find host with IP {}".format( sAddr )
+            assert dHost, "Not able to find host with IP {}".format( dAddr )
+            cmdStr = "t3-troubleshoot"
+            if verbose:
+                cmdStr += " -vv"
+            cmdStr += " -s " + str( sAddr )
+            # TODO: collect t3 for all locations of source host?
+            cmdStr += " -sp " + str( sHost[ "locations" ][ 0 ][ "elementId" ] ) + "/" + str( sHost[ "locations" ][ 0 ][ "port" ] )
+            cmdStr += " -sm " + str( sHost[ "mac" ] )
+            cmdStr += " -d " + str( dAddr )
+            netcfg = self.netcfg( args="devices {}".format( sHost[ "locations" ][ 0 ][ "elementId" ] ) )
+            netcfg = json.loads( netcfg )
+            assert netcfg, "Failed to get netcfg"
+            cmdStr += " -dm " + str( netcfg[ "segmentrouting" ][ "routerMac" ] )
+            if ipv6:
+                cmdStr += " -et ipv6"
+            return cmdStr
+        except AssertionError:
+            main.log.exception( "" )
+            return None
+        except ( KeyError, TypeError ):
+            main.log.exception( self.name + ": Object not as expected" )
+            return None
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanAndExit()
+
+    def t3( self, sAddr, dAddr, ipv6=False ):
+        """
+        Run t3-troubleshoot cli command for given source and destination addresses
+        Options:
+            sAddr: IP address of the source host
+            dAddr: IP address of the destination host
+        """
+        try:
+            cmdStr = self.composeT3Command( sAddr, dAddr, ipv6 )
+            handle = self.sendline( cmdStr )
+            assert handle is not None, "Error in sendline"
+            assert "Command not found:" not in handle, handle
+            assert "Unsupported command:" not in handle, handle
+            assert "Error executing command" not in handle, handle
+            assert "Tracing packet" in handle
+            return handle
+        except AssertionError:
+            main.log.exception( "" )
+            return None
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanAndExit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanAndExit()
diff --git a/TestON/tests/SCPF/SCPFswitchLat/dependencies/switchFunc.py b/TestON/tests/SCPF/SCPFswitchLat/dependencies/switchFunc.py
index b097166..b9463c2 100644
--- a/TestON/tests/SCPF/SCPFswitchLat/dependencies/switchFunc.py
+++ b/TestON/tests/SCPF/SCPFswitchLat/dependencies/switchFunc.py
@@ -100,6 +100,9 @@
     for line in resultText:
         for term in keyTerm:
             if term in line:
+                # Exclude non-openflow FIN packets
+                if term == "[FIN, ACK]" and "openflow" not in line:
+                    continue
                 path = '/tmp/Tshark_' + str( keyTerm[ term ] )
                 with open( path, 'a' ) as outputfile:
                     outputfile.write( line )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.topo b/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.topo
index a672a8e..7b188e2 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.topo
@@ -27,7 +27,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.topo b/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.topo
index 5c4cc02..ad2c2b0 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.topo
@@ -28,7 +28,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDhcprelay/SRDhcprelay.topo b/TestON/tests/USECASE/SegmentRouting/SRDhcprelay/SRDhcprelay.topo
index 01316b6..dbb415d 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRDhcprelay/SRDhcprelay.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRDhcprelay/SRDhcprelay.topo
@@ -27,7 +27,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo
index 5c4cc02..ad2c2b0 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo
@@ -28,7 +28,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamicConf/SRDynamicConf.topo b/TestON/tests/USECASE/SegmentRouting/SRDynamicConf/SRDynamicConf.topo
index a672a8e..7b188e2 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRDynamicConf/SRDynamicConf.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamicConf/SRDynamicConf.topo
@@ -27,7 +27,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.topo b/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.topo
index 5c4cc02..ad2c2b0 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.topo
@@ -28,7 +28,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.topo b/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.topo
index 5c4cc02..ad2c2b0 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.topo
@@ -28,7 +28,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/dependencies/SRLinkFailFuncs.py b/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/dependencies/SRLinkFailFuncs.py
index 1837cf4..1ed1c55 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/dependencies/SRLinkFailFuncs.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/dependencies/SRLinkFailFuncs.py
@@ -57,8 +57,8 @@
         # link failure
         run.killLink( main, self.switchOne, self.switchTwo, switches='{}'.format( switch ), links='{}'.format( link - 2 ) )
         run.pingAll( main, "CASE{}_Failure".format( caseNum ) )
-        run.restoreLink( main, self.switchOne, self.switchTwo, self.dpidOne,
-                         self.dpidTwo, self.portOne, self.portTwo, '{}'.format( switch ), '{}'.format( link ) )
+        run.restoreLink( main, self.switchOne, self.switchTwo, '{}'.format( switch ), '{}'.format( link ),
+                         True, self.dpidOne, self.dpidTwo, self.portOne, self.portTwo )
         run.pingAll( main, "CASE{}_Recovery".format( caseNum ) )
         # TODO Dynamic config of hosts in subnet
         # TODO Dynamic config of host not in subnet
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.params b/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.params
index 6af0cde..f687a40 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.params
+++ b/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.params
@@ -1,5 +1,5 @@
 <PARAMS>
-    <testcases>1,2,3,4,5,6,7,8,101,102,103,201</testcases>
+    <testcases>1,2,3,4,5,6,7,8,101,102,103,104,105,106,201,202,203,204,205,301,401,402,403,404</testcases>
 
     <GRAPH>
         <nodeCluster>Fabric</nodeCluster>
@@ -34,9 +34,9 @@
     </CTRL>
 
     <timers>
-        <LinkDiscovery>30</LinkDiscovery>
-        <SwitchDiscovery>30</SwitchDiscovery>
-        <OnosDiscovery>30</OnosDiscovery>
+        <LinkDiscovery>45</LinkDiscovery>
+        <SwitchDiscovery>45</SwitchDiscovery>
+        <OnosDiscovery>45</OnosDiscovery>
         <loadNetcfgSleep>5</loadNetcfgSleep>
         <startMininetSleep>60</startMininetSleep>
         <balanceMasterSleep>10</balanceMasterSleep>
@@ -44,7 +44,12 @@
     </timers>
 
     <SCAPY>
-        <HOSTNAMES>h1v4,h3v4,h4v4,h8v4,h1v6,h3v6,h4v6,h8v6</HOSTNAMES>
+        <HOSTNAMES>h3v4,h4v4,h8v4,h10v4,h1v6,h3v6</HOSTNAMES>
     </SCAPY>
 
+    <TOPO>
+        <switchNum>10</switchNum>
+        <linkNum>48</linkNum>
+    </TOPO>
+
 </PARAMS>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.py b/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.py
index b2a7139..67614f4 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.py
@@ -11,19 +11,16 @@
         Remove sink
         Verify flows and groups
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=1,
-                            onosNodes=3,
-                            description="Create a Multicast flow between a source and sink on the same dual-tor leaf" )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Create a Multicast flow between a source and sink on the same dual-tor leaf" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=1, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyMcastSinkRemoval( main, "ipv4", 0, False )
+        verifyMcastSourceRemoval( main, "ipv4", 0, False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE2( self, main ):
         """
@@ -34,19 +31,16 @@
         Remove sink
         Verify flows and groups
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=2,
-                            onosNodes=3,
-                            description="Create a Multicast flow between a source and sink on different dual-tor leaves" )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Create a Multicast flow between a source and sink on different dual-tor leaves" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 1 ] } }
+        setupTest( main, test_idx=2, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyMcastSinkRemoval( main, "ipv4", 1, False )
+        verifyMcastSourceRemoval( main, "ipv4", 0, False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE3( self, main ):
         """
@@ -57,19 +51,15 @@
         Remove sink
         Verify flows and groups
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=3,
-                            onosNodes=3,
-                            description="Create a Multicast flow between a source and sink on different leaves (sink on single-tor)" )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Create a Multicast flow between a source and sink on different leaves (sink on single-tor)" )
+        main.mcastRoutes = { "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=3, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyMcastRouteRemoval( main, "ipv6" )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE4( self, main ):
         """
@@ -80,19 +70,17 @@
         Remove sinks
         Verify flows and groups
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=4,
-                            onosNodes=3,
-                            description="Combines CASE1 and CASE2" )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE1 and CASE2" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1 ] } }
+        setupTest( main, test_idx=4, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyMcastSinkRemoval( main, "ipv4", 0, False )
+        verifyMcastSinkRemoval( main, "ipv4", 1, False )
+        verifyMcastSourceRemoval( main, "ipv4", 0, False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE5( self, main ):
         """
@@ -103,19 +91,17 @@
         Remove sinks
         Verify flows and groups
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=5,
-                            onosNodes=3,
-                            description="Combines CASE2 and CASE3" )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE2 and CASE3" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 1 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=5, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyMcastRouteRemoval( main, "ipv6" )
+        verifyMcastSinkRemoval( main, "ipv4", 1, False )
+        verifyMcastSourceRemoval( main, "ipv4", 0, False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE6( self, main ):
         """
@@ -126,19 +112,17 @@
         Remove sinks
         Verify flows and groups
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=5,
-                            onosNodes=3,
-                            description="Combines CASE1 and CASE3" )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE1 and CASE3" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=6, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyMcastRouteRemoval( main, "ipv6" )
+        verifyMcastSinkRemoval( main, "ipv4", 0, False )
+        verifyMcastSourceRemoval( main, "ipv4", 0, False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE7( self, main ):
         """
@@ -149,179 +133,372 @@
         Remove sinks
         Verify flows and groups
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=7,
-                            onosNodes=3,
-                            description="Combines CASE7 with route removal" )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE1, CASE2 and CASE3" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=7, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyMcastRouteRemoval( main, "ipv6" )
+        verifyMcastSinkRemoval( main, "ipv4", 0, False )
+        verifyMcastSinkRemoval( main, "ipv4", 1, False )
+        verifyMcastSourceRemoval( main, "ipv4", 0, False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE8( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with route removal
+        Use all of the four sinks
+        Verify flows and groups
+        Verify traffic
+        Remove sinks
         Verify flows and groups
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=8,
-                            onosNodes=3,
-                            description="Combines CASE7 with route removal",
-                            removeRoute=True )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Use all of the four sinks" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=8, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyMcastRemoval( main )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE101( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with a link failure (link ingress-spine)
+        Combines CASE8 with a link failure (link ingress-spine)
         Verify flows and groups
         Verify traffic
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=101,
-                            onosNodes=3,
-                            description="Combines CASE7 with a link failure (link ingress-spine)",
-                            linkFailure=True )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with a link failure (link ingress-spine)" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=101, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyLinkDown( main, [ "leaf2", "spine101" ], 4 )
+        verifyMcastRemoval( main )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE102( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with a link failure (link spine-egress-dt-leaf)
+        Combines CASE8 with a link failure (link spine-egress-dt-leaf)
         Verify flows and groups
         Verify traffic
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=102,
-                            onosNodes=3,
-                            description="Combines CASE7 with a link failure (link spine-engress-dt-leaf)",
-                            linkFailure=True )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with a link failure (link spine-engress-dt-leaf)" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=102, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyLinkDown( main, [ "leaf5", "spine101" ], 4 )
+        verifyMcastRemoval( main )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE103( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with a link failure (link spine-egress-st-leaf)
+        Combines CASE8 with a link failure (link spine-egress-st-leaf)
         Verify flows and groups
         Verify traffic
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=103,
-                            onosNodes=3,
-                            description="Combines CASE7 with a link failure (link spine-engress-st-leaf)",
-                            linkFailure=True )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with a link failure (link spine-engress-st-leaf)" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=103, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyLinkDown( main, [ "spine103", "spine101" ], 4 )
+        verifyMcastRemoval( main )
+        lib.cleanup( main, copyKarafLog=False )
+
+    def CASE104( self, main ):
+        """
+        Sets up 3 ONOS instances, start H-AGG topology
+        Combines CASE8 with a link failure (link spine-egress-st-leaf-2)
+        Verify flows and groups
+        Verify traffic
+        """
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with a link failure (link spine-engress-st-leaf-2)" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=104, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyLinkDown( main, [ "leaf4", "spine101" ], 4 )
+        verifyMcastRemoval( main )
+        lib.cleanup( main, copyKarafLog=False )
+
+    def CASE105( self, main ):
+        """
+        Sets up 3 ONOS instances, start H-AGG topology
+        Combines CASE8 with a link failure (link dt-leaf-sink)
+        Verify flows and groups
+        Verify traffic
+        """
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with a link failure (link dt-leaf-sink)" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=105, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyLinkDown( main, [ "leaf2", "h4v4" ], 0 )
+        verifyMcastRemoval( main )
+        lib.cleanup( main, copyKarafLog=False )
+
+    def CASE106( self, main ):
+        """
+        Sets up 3 ONOS instances, start H-AGG topology
+        Combines CASE8 with a link failure (link dt-leaf-sink-2)
+        Verify flows and groups
+        Verify traffic
+        """
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with a link failure (link dt-leaf-sink-2)" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=106, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyLinkDown( main, [ "leaf5", "h10v4" ], 0 )
+        verifyMcastRemoval( main )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE201( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with spine failure
+        Combines CASE8 with spine failure
         Verify flows and groups
         Verify traffic
         """
-        try:
-            from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import SRMulticastTest
-        except ImportError:
-            main.log.error( "SRMulticastTest not found. Exiting the test" )
-            main.cleanAndExit()
-        try:
-            main.funcs
-        except ( NameError, AttributeError ):
-            main.funcs = SRMulticastTest()
-        main.funcs.runTest( main,
-                            test_idx=201,
-                            onosNodes=3,
-                            description="Combines CASE7 with spine failure",
-                            switchFailure=True )
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with spine failure" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=201, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifySwitchDown( main, "spine101", 18 )
+        verifySwitchDown( main, "spine102", 18 )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE202( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with ingress failure and recovery
+        Combines CASE8 with ingress failure and recovery
         Verify flows and groups are removed (failure)
         Verify flows and groups (recovery)
         Verify traffic (recovery)
         """
-        pass
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with ingress failure and recovery" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=202, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifySwitchDown( main, "leaf2", 10, { "ipv4": False, "ipv6": False } )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE203( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with egress-dt-leaf failure and recovery
+        Combines CASE8 with egress-dt-leaf failure and recovery
         Verify flows and groups are removed for the failing sink (failure)
         Verify traffic on remaining sinks (failure)
         Verify flows and groups (recovery)
         Verify traffic (recovery)
         """
-        pass
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with egress-dt-leaf failure and recovery" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=203, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifySwitchDown( main, "leaf5", 10 )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE204( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with egress-st-leaf failure and recovery
+        Combines CASE8 with egress-st-leaf failure and recovery
         Verify flows and groups are removed for the failing sink (failure)
         Verify traffic on remaining sinks (failure)
         Verify flows and groups (recovery)
         Verify traffic (recovery)
         """
-        pass
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with egress-st-leaf failure and recovery" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=204, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifySwitchDown( main, "leaf4", 10, { "ipv4": [ True, False, True ], "ipv6": True } )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE205( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with egress leaves failure and recovery
+        Combines CASE8 with egress leaves failure and recovery
         Verify flows and groups are removed for the failing sinks (failure)
         Verify traffic on remaining sink (failure)
         Verify flows and groups (recovery)
         Verify traffic (recovery)
         """
-        pass
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with leaves failure and recovery" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=205, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifySwitchDown( main, [ "leaf1", "leaf3", "leaf4", "leaf5" ], 32, { "ipv4": [ True, False, False ], "ipv6": False } )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
 
     def CASE301( self, main ):
         """
         Sets up 3 ONOS instances, start H-AGG topology
-        Combines CASE7 with ONOS failure and recovery
+        Combines CASE8 with ONOS failure and recovery
         Verify flows and groups (failure)
         Verify traffic (failure)
         Verify flows and groups (recovery)
         Verify traffic (recovery)
         """
-        pass
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Combines CASE8 with leaves failure and recovery" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=205, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyOnosDown( main )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
+
+    def CASE401( self, main ):
+        """
+        Extends MCAST105
+        Create sinks and verify traffic is working
+        Bring down host port and verify traffic is still working for all sinks
+        Bring up host port again and start ping from DTH1 to STS
+        Verify host has both location and stop the ping
+        Kill LEAFA and verify traffic is still working for all sinks
+        Remove IPv6 route
+        Remove DTH2 sink
+        Remove STH2 sink
+        Remove STS
+        """
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Extends MCAST105" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=401, onosNodes=3 )
+        verifyMcastRoutes( main )
+        #TODO: Verify host has both locations
+        # Verify killing one link of dual-homed host h4
+        verifyLinkDown( main, [ "leaf2", "h4v4" ], 0 )
+        verifyLinkDown( main, [ "leaf3", "h4v4" ], 0 )
+        # Verify killing one link of dual-homed host h10
+        verifyLinkDown( main, [ "leaf4", "h10v4" ], 0 )
+        verifyLinkDown( main, [ "leaf5", "h10v4" ], 0 )
+        verifySwitchDown( main, "leaf3", 10 )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
+
+    def CASE402( self, main ):
+        """
+        No downstream path for DTH2
+        Create sinks and verify traffic is working
+        Kill all up-links of the LEAFB and verify traffic is still working
+        Remove IPv6 route
+        Remove DTH2 sink
+        Remove STH2 sink
+        Remove STS
+        """
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "No downstream path for DTH2" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=402, onosNodes=3 )
+        verifyMcastRoutes( main )
+        verifyLinkDown( main, [ [ "leaf5", "spine101" ], [ "leaf5", "spine102" ] ], 8 )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
+
+    def CASE403( self, main ):
+        """
+        No downstream path for DTH1
+        Create sinks and verify traffic is working
+        Bring down host port and verify traffic is still working for all sinks
+        Bring up host port again and start ping from DTH1 to STS
+        Verify host has both location and stop the ping
+        Kill all up-links of the LEAFA and verify traffic is still working
+        Remove IPv6 route
+        Remove DTH2 sink
+        Remove STH2 sink
+        Remove STS
+        """
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "No downstream path for DTH1" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=403, onosNodes=3 )
+        verifyMcastRoutes( main )
+        # Verify killing one link of dual-homed host h4
+        verifyLinkDown( main, [ "leaf2", "h4v4" ], 0 )
+        verifyLinkDown( main, [ "leaf3", "h4v4" ], 0 )
+        # Verify killing one link of dual-homed host h10
+        verifyLinkDown( main, [ "leaf4", "h10v4" ], 0 )
+        verifyLinkDown( main, [ "leaf5", "h10v4" ], 0 )
+        verifyLinkDown( main, [ [ "leaf3", "spine101" ], [ "leaf3", "spine102" ] ], 8 )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
+
+    def CASE404( self, main ):
+        """
+        Extends MCAST 403
+        Create sinks and verify traffic is working
+        Bring down host port and verify traffic is still working for all sinks
+        Bring up host port again and start ping from DTH1 to STS
+        Verify host has both location and stop the ping
+        Kill up-links of the LEAFA towards SPINEA, kill up-links of the SOURCE LEAF towards SPINEC and verify traffic is still working for all sinks
+        Remove IPv6 route
+        Remove DTH2 sink
+        Remove STH2 sink
+        Remove STS
+        """
+        import time
+        from tests.USECASE.SegmentRouting.SRMulticast.dependencies.SRMulticastTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Extends MCASR 403" )
+        main.mcastRoutes = { "ipv4": { "src": [ 0 ], "dst": [ 0, 1, 2 ] }, "ipv6": { "src": [ 0 ], "dst": [ 0 ] } }
+        setupTest( main, test_idx=404, onosNodes=3 )
+        verifyMcastRoutes( main )
+        # Verify killing one link of dual-homed host h4
+        verifyLinkDown( main, [ "leaf2", "h4v4" ], 0 )
+        verifyLinkDown( main, [ "leaf3", "h4v4" ], 0 )
+        # Verify killing one link of dual-homed host h10
+        verifyLinkDown( main, [ "leaf4", "h10v4" ], 0 )
+        verifyLinkDown( main, [ "leaf5", "h10v4" ], 0 )
+        verifyLinkDown( main, [ [ "leaf3", "spine101" ], [ "leaf2", "spine102" ] ], 8 )
+        verifyMcastRemoval( main, removeDHT1=False )
+        lib.cleanup( main, copyKarafLog=False )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.topo b/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.topo
index 1c3f8a6..b5da976 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.topo
@@ -27,7 +27,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/SRMulticastTest.py b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/SRMulticastTest.py
index 42e646a..30b7e92 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/SRMulticastTest.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/SRMulticastTest.py
@@ -20,96 +20,163 @@
 """
 
 import time
-from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as run
 
-class SRMulticastTest ():
+def setupTest( main, test_idx, onosNodes ):
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    skipPackage = False
+    init = False
+    if not hasattr( main, "apps" ):
+        init = True
+        lib.initTest( main )
+    # Skip onos packaging if the cluster size stays the same
+    if not init and onosNodes == main.Cluster.numCtrls:
+        skipPackage = True
 
-    def __init__( self ):
-        self.default = ''
-        self.switchNames = [ "leaf205", "leaf206", "spine227", "spine228" ]
+    main.resultFileName = "CASE%03d" % test_idx
+    main.Cluster.setRunningNode( onosNodes )
+    lib.installOnos( main, skipPackage=skipPackage, cliSleep=5 )
+    # Load configuration files
+    main.step( "Load configurations" )
+    main.cfgName = "TEST_CONFIG_ipv4=1_ipv6=1_dhcp=1_routers=1"
+    lib.loadJson( main )
+    time.sleep( float( main.params[ "timers" ][ "loadNetcfgSleep" ] ) )
+    main.cfgName = "common"
+    lib.loadMulticastConfig( main )
 
-    def runTest( self, main, test_idx, onosNodes, description, removeRoute=False, linkFailure=False, switchFailure=False ):
-        skipPackage = False
-        init = False
-        if not hasattr( main, 'apps' ):
-            init = True
-            run.initTest( main )
-        # Skip onos packaging if the cluster size stays the same
-        if not init and onosNodes == main.Cluster.numCtrls:
-            skipPackage = True
+    if hasattr( main, "Mininet1" ):
+        # Run the test with Mininet
+        mininet_args = " --dhcp=1 --routers=1 --ipv6=1 --ipv4=1"
+        lib.startMininet( main, main.params[ "DEPENDENCY" ][ "topology" ], args=mininet_args )
+        time.sleep( float( main.params[ "timers" ][ "startMininetSleep" ] ) )
+    else:
+        # Run the test with physical devices
+        lib.connectToPhysicalNetwork( main, self.switchNames )
+        # Check if the devices are up
+        lib.checkDevices( main, switches=len( self.switchNames ) )
 
-        main.case( '%s, ONOS cluster size: %s' % ( description, onosNodes ) )
+    # Create scapy components
+    lib.startScapyHosts( main )
 
-        main.resultFileName = 'CASE%03d' % test_idx
-        main.Cluster.setRunningNode( onosNodes )
-        run.installOnos( main, skipPackage=skipPackage, cliSleep=5 )
-        # Load configuration files
-        main.step("Load configurations")
-        main.cfgName = 'TEST_CONFIG_ipv4=1_ipv6=1_dhcp=1_routers=1'
-        run.loadJson( main )
-        main.cfgName = 'CASE%03d' % test_idx
-        run.loadMulticastConfig( main )
-        if linkFailure:
-            run.loadLinkFailureChart( main )
-        if switchFailure:
-            run.loadSwitchFailureChart( main )
-        time.sleep( float( main.params[ 'timers' ][ 'loadNetcfgSleep' ] ) )
+def verifyMcastRoutes( main ):
+    """
+    Install multicast routes and check traffic
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    for routeName in main.mcastRoutes.keys():
+        main.step( "Verify {} multicast route".format( routeName ) )
+        installMcastRoute( main, routeName )
+        lib.verifyMulticastTraffic( main, routeName, True )
 
-        if hasattr( main, 'Mininet1' ):
-            # Run the test with Mininet
-            mininet_args = ' --dhcp=1 --routers=1 --ipv6=1 --ipv4=1'
-            run.startMininet( main, main.params['DEPENDENCY']['topology'], args=mininet_args )
-            time.sleep( float( main.params[ 'timers' ][ 'startMininetSleep' ] ) )
-        else:
-            # Run the test with physical devices
-            run.connectToPhysicalNetwork( main, self.switchNames )
-            # Check if the devices are up
-            run.checkDevices( main, switches=len( self.switchNames ) )
+def installMcastRoute( main, routeName ):
+    """
+    Install a multicast route
+    """
+    routeData = main.multicastConfig[ routeName ]
+    src = main.mcastRoutes[ routeName ][ "src" ]
+    dst = main.mcastRoutes[ routeName ][ "dst" ]
+    main.Cluster.active( 0 ).CLI.mcastHostJoin( routeData[ "src" ][ src[ 0 ] ][ "ip" ], routeData[ "group" ],
+                                                [ routeData[ "src" ][ i ][ "port" ] for i in src ],
+                                                [ routeData[ "dst" ][ i ][ "id" ] for i in dst ] )
+    time.sleep( float( main.params[ "timers" ][ "mcastSleep" ] ) )
 
-        # Create scapy components
-        run.startScapyHosts( main )
+def verifyMcastRouteRemoval( main, routeName ):
+    """
+    Verify removal of a multicast route
+    """
+    routeData = main.multicastConfig[ routeName ]
+    main.step( "Verify removal of {} route".format( routeName ) )
+    main.Cluster.active( 0 ).CLI.mcastHostDelete( routeData[ "src" ][ 0 ][ "ip" ], routeData[ "group" ] )
+    # TODO: verify the deletion
 
-        for entry in main.multicastConfig:
-            main.step("Verify adding multicast route with group IP {}".format(entry["group"]))
-            # Create a multicast route
-            main.Cluster.active( 0 ).CLI.mcastHostJoin( entry["sIP"], entry["group"], entry["sPorts"], entry["dHosts"] )
-            time.sleep( float( main.params[ 'timers' ][ 'mcastSleep' ] ) )
-            # Check the flows against the devices
-            # run.checkFlows( main, minFlowCount=2, sleep=5 )
-            # Verify multicast traffic
-            run.verifyMulticastTraffic( main, entry, True, skipOnFail=True )
+def verifyMcastSinkRemoval( main, routeName, sinkIndex, expect ):
+    """
+    Verify removal of a multicast sink
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    routeData = main.multicastConfig[ routeName ]
+    sinkId = routeData[ "dst" ][ sinkIndex ][ "id" ]
+    main.step( "Verify removal of {} sink {}".format( routeName, sinkId ) )
+    main.Cluster.active( 0 ).CLI.mcastHostDelete( routeData[ "src" ][ 0 ][ "ip" ], routeData[ "group" ], sinkId )
+    time.sleep( float( main.params[ "timers" ][ "mcastSleep" ] ) )
+    lib.verifyMulticastTraffic( main, routeName, expect )
 
-            # Test switch failures
-            if switchFailure:
-                for switch, expected in main.switchFailureChart.items():
-                    run.killSwitch( main, switch, expected['switches_after_failure'], expected['links_after_failure'] )
-                    run.verifyMulticastTraffic( main, entry, True, skipOnFail=True )
+def verifyMcastSourceRemoval( main, routeName, sourceIndex, expect ):
+    """
+    Verify removal of a multicast source
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    routeData = main.multicastConfig[ routeName ]
+    sourcePort = [ routeData[ "src" ][ sourceIndex ][ "port" ] ]
+    main.step( "Verify removal of {} source {}".format( routeName, sourcePort ) )
+    main.Cluster.active( 0 ).CLI.mcastSourceDelete( routeData[ "src" ][ 0 ][ "ip" ], routeData[ "group" ], sourcePort )
+    time.sleep( float( main.params[ "timers" ][ "mcastSleep" ] ) )
+    lib.verifyMulticastTraffic( main, routeName, expect )
 
-                    run.recoverSwitch( main, switch, expected['switches_before_failure'], expected['links_before_failure'] )
-                    run.verifyMulticastTraffic( main, entry, True, skipOnFail=True )
+def verifyMcastRemoval( main, removeDHT1=True ):
+    """
+    Verify removal of IPv6 route, IPv4 sinks and IPv4 source
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    verifyMcastRouteRemoval( main, "ipv6" )
+    if removeDHT1:
+        verifyMcastSinkRemoval( main, "ipv4", 0, [ False, True, True ] )
+        verifyMcastSinkRemoval( main, "ipv4", 1, [ False, False, True ] )
+    else:
+        verifyMcastSinkRemoval( main, "ipv4", 2, [ True, True, False ] )
+        verifyMcastSinkRemoval( main, "ipv4", 1, [ True, False, False ] )
+    verifyMcastSourceRemoval( main, "ipv4", 0, False )
 
-            # Test link failures
-            if linkFailure:
-                for link_batch_name, info in main.linkFailureChart.items():
-                    linksToRemove = info['links'].values()
-                    linksBefore = info['links_before']
-                    linksAfter = info['links_after']
+def verifyLinkDown( main, link, affectedLinkNum, expectList={ "ipv4": True, "ipv6": True } ):
+    """
+    Kill a batch of links and verify traffic
+    Restore the links and verify traffic
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    link = link if ( isinstance( link, list ) and isinstance( link[ 0 ], list ) ) else [ link ]
+    # Kill the link(s)
+    lib.killLinkBatch( main, link, int( main.params[ "TOPO" ][ "linkNum" ] ) - affectedLinkNum, int( main.params[ "TOPO" ][ "switchNum" ] ) )
+    for routeName in expectList.keys():
+        lib.verifyMulticastTraffic( main, routeName, expectList[ routeName ] )
+    # Restore the link(s)
+    lib.restoreLinkBatch( main, link, int( main.params[ "TOPO" ][ "linkNum" ] ), int( main.params[ "TOPO" ][ "switchNum" ] ) )
+    for routeName in expectList.keys():
+        lib.verifyMulticastTraffic( main, routeName, True )
 
-                    run.killLinkBatch( main, linksToRemove, linksAfter, switches=10 )
-                    run.verifyMulticastTraffic( main, entry, True, skipOnFail=True )
+def verifySwitchDown( main, switchName, affectedLinkNum, expectList={ "ipv4": True, "ipv6": True } ):
+    """
+    Kill a batch of switches and verify traffic
+    Recover the swithces and verify traffic
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    switchName = switchName if isinstance( switchName, list ) else [ switchName ]
+    # Kill the switch(es)
+    lib.killSwitch( main, switchName, int( main.params[ "TOPO" ][ "switchNum" ] ) - len( switchName ), int( main.params[ "TOPO" ][ "linkNum" ] ) - affectedLinkNum )
+    for routeName in expectList.keys():
+        lib.verifyMulticastTraffic( main, routeName, expectList[ routeName ] )
+    # Recover the switch(es)
+    lib.recoverSwitch( main, switchName, int( main.params[ "TOPO" ][ "switchNum" ] ), int( main.params[ "TOPO" ][ "linkNum" ] ) )
+    for routeName in expectList.keys():
+        lib.verifyMulticastTraffic( main, routeName, True )
 
-                    run.restoreLinkBatch( main, linksToRemove, linksBefore, switches=10 )
-                    run.verifyMulticastTraffic( main, entry, True, skipOnFail=True )
-
-            if removeRoute:
-                main.step("Verify deleting multicast route with group IP {}".format(entry["group"]))
-                # delete a multicast route
-                main.Cluster.active( 0 ).CLI.mcastHostDelete( entry["sIP"], entry["group"] )
-                time.sleep( float( main.params[ 'timers' ][ 'mcastSleep' ] ) )
-                # Check the flows against the devices
-                # run.checkFlows( main, minFlowCount=2, sleep=5 )
-                # Verify multicast traffic (traffic check is expected to fail)
-                run.verifyMulticastTraffic( main, entry, False, skipOnFail=True )
-
-        # Clean up the environment
-        run.cleanup( main, copyKarafLog=False )
+def verifyOnosDown( main, expectList={ "ipv4": True, "ipv6": True } ):
+    """
+    Kill and recover ONOS instances Sequencially and check traffic
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    import json
+    numCtrls = len( main.Cluster.runningNodes )
+    links = len( json.loads( main.Cluster.next().links() ) )
+    switches = len( json.loads( main.Cluster.next().devices() ) )
+    for ctrl in xrange( numCtrls ):
+        # Kill node
+        lib.killOnos( main, [ ctrl ], switches, links, ( numCtrls - 1 ) )
+        main.Cluster.active(0).CLI.balanceMasters()
+        time.sleep( float( main.params[ 'timers' ][ 'balanceMasterSleep' ] ) )
+        for routeName in expectList.keys():
+            lib.verifyMulticastTraffic( main, routeName, True )
+        # Recover node
+        lib.recoverOnos( main, [ ctrl ], switches, links, numCtrls )
+        main.Cluster.active(0).CLI.balanceMasters()
+        time.sleep( float( main.params[ 'timers' ][ 'balanceMasterSleep' ] ) )
+        for routeName in expectList.keys():
+            lib.verifyMulticastTraffic( main, routeName, True )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE101.linkFailureChart b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE101.linkFailureChart
deleted file mode 100644
index 8a9e052..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE101.linkFailureChart
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "link_batch_1" : { "links" : { "link1" : ["leaf2", "spine101"] },
-                       "links_before" : 48,
-                       "links_after" : 44 },
-    "link_batch_2" : { "links" : { "link1" : ["leaf2", "spine102"] },
-                       "links_before" : 48,
-                       "links_after" : 44 }
-}
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE102.linkFailureChart b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE102.linkFailureChart
deleted file mode 100644
index f102be4..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE102.linkFailureChart
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "link_batch_1" : { "links" : { "link1" : ["leaf4", "spine101"] },
-                       "links_before" : 48,
-                       "links_after" : 44 },
-    "link_batch_2" : { "links" : { "link1" : ["leaf4", "spine102"] },
-                       "links_before" : 48,
-                       "links_after" : 44 }
-}
-
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE103.linkFailureChart b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE103.linkFailureChart
deleted file mode 100644
index 8041a05..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/linkFailure/CASE103.linkFailureChart
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "link_batch_1" : { "links" : { "link1" : ["spine103", "spine101"] },
-                       "links_before" : 48,
-                       "links_after" : 46 },
-    "link_batch_2" : { "links" : { "link1" : ["spine104", "spine102"] },
-                       "links_before" : 48,
-                       "links_after" : 46 }
-}
-
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE001.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE001.multicastConfig
deleted file mode 100644
index 990507e..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE001.multicastConfig
+++ /dev/null
@@ -1,48 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE002.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE002.multicastConfig
deleted file mode 100644
index 14f770e..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE002.multicastConfig
+++ /dev/null
@@ -1,46 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:06/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h8v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:06/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h8v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE003.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE003.multicastConfig
deleted file mode 100644
index ffd2e6c..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE003.multicastConfig
+++ /dev/null
@@ -1,46 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE004.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE004.multicastConfig
deleted file mode 100644
index 8fc69d1..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE004.multicastConfig
+++ /dev/null
@@ -1,54 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None", "00:AA:00:00:00:06/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                },
-                {
-                    "host": "h8v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None", "00:BB:00:00:00:06/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                },
-                {
-                    "host": "h8v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE005.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE005.multicastConfig
deleted file mode 100644
index 7d089ae..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE005.multicastConfig
+++ /dev/null
@@ -1,52 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:06/None", "00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h8v4"
-                },
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:06/None", "00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h8v6"
-                },
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE006.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE006.multicastConfig
deleted file mode 100644
index 9c1029a..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE006.multicastConfig
+++ /dev/null
@@ -1,54 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None", "00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                },
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None", "00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                },
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE007.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE007.multicastConfig
deleted file mode 100644
index 218ed4d..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE007.multicastConfig
+++ /dev/null
@@ -1,60 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None", "00:AA:00:00:00:06/None", "00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                },
-                {
-                    "host": "h8v4"
-                },
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None", "00:BB:00:00:00:06/None", "00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                },
-                {
-                    "host": "h8v6"
-                },
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE008.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE008.multicastConfig
deleted file mode 100644
index 218ed4d..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE008.multicastConfig
+++ /dev/null
@@ -1,60 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None", "00:AA:00:00:00:06/None", "00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                },
-                {
-                    "host": "h8v4"
-                },
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None", "00:BB:00:00:00:06/None", "00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                },
-                {
-                    "host": "h8v6"
-                },
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE101.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE101.multicastConfig
deleted file mode 100644
index 218ed4d..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE101.multicastConfig
+++ /dev/null
@@ -1,60 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None", "00:AA:00:00:00:06/None", "00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                },
-                {
-                    "host": "h8v4"
-                },
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None", "00:BB:00:00:00:06/None", "00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                },
-                {
-                    "host": "h8v6"
-                },
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE102.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE102.multicastConfig
deleted file mode 100644
index 218ed4d..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE102.multicastConfig
+++ /dev/null
@@ -1,60 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None", "00:AA:00:00:00:06/None", "00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                },
-                {
-                    "host": "h8v4"
-                },
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None", "00:BB:00:00:00:06/None", "00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                },
-                {
-                    "host": "h8v6"
-                },
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE103.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE103.multicastConfig
deleted file mode 100644
index 218ed4d..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE103.multicastConfig
+++ /dev/null
@@ -1,60 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None", "00:AA:00:00:00:06/None", "00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                },
-                {
-                    "host": "h8v4"
-                },
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None", "00:BB:00:00:00:06/None", "00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                },
-                {
-                    "host": "h8v6"
-                },
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE201.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE201.multicastConfig
deleted file mode 100644
index 218ed4d..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/CASE201.multicastConfig
+++ /dev/null
@@ -1,60 +0,0 @@
-[
-    {
-        "ipVersion": 4,
-        "sIP": "10.2.0.1",
-        "group": "224.2.0.1",
-        "sPorts": ["of:0000000000000002/9"],
-        "dHosts": ["00:AA:00:00:00:03/None", "00:AA:00:00:00:06/None", "00:AA:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v4",
-                "interface": "h3v4-eth0",
-                "Ether": "01:00:5e:02:00:01",
-                "UDP": 40051,
-                "filter": "ip multicast and dst host 224.2.0.1 and udp dst port 40051",
-                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v4",
-                    "interface": "h4v4-bond0"
-                },
-                {
-                    "host": "h8v4"
-                },
-                {
-                    "host": "h1v4"
-                }
-            ]
-        }
-    },
-    {
-        "ipVersion": 6,
-        "sIP": "1002::3fe",
-        "group": "ff08::3fe",
-        "sPorts": ["of:0000000000000002/6"],
-        "dHosts": ["00:BB:00:00:00:03/None", "00:BB:00:00:00:06/None", "00:BB:00:00:00:01/None"],
-        "scapy": {
-            "src": {
-                "host": "h3v6",
-                "interface": "h3v6-eth0",
-                "Ether": "33:33:00:00:03:fe",
-                "UDP": 40051,
-                "filter": "ip6 multicast and dst host ff08::3fe and udp dst port 40051",
-                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
-            },
-            "dst": [
-                {
-                    "host": "h4v6",
-                    "interface": "h4v6-bond0"
-                },
-                {
-                    "host": "h8v6"
-                },
-                {
-                    "host": "h1v6"
-                }
-            ]
-        }
-    }
-]
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/common.multicastConfig b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/common.multicastConfig
new file mode 100644
index 0000000..842d540
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/multicast/common.multicastConfig
@@ -0,0 +1,58 @@
+{
+    "ipv4": {
+        "ipVersion": 4,
+        "group": "224.2.0.1",
+        "src": [
+            {
+                "host": "h3v4",
+                "ip": "10.2.0.1",
+                "port": "of:0000000000000002/9",
+                "interface": "h3v4-eth0",
+                "Ether": "01:00:5e:02:00:01",
+                "UDP": 40051,
+                "filter": "ip host 224.2.0.1",
+                "packet": "dst=01:00:5e:02:00:01 src=00:aa:00:00:00:02"
+            }
+        ],
+        "dst": [
+            {
+                "host": "h4v4",
+                "id": "00:AA:00:00:00:03/None",
+                "interface": "h4v4-bond0",
+                "dualHomed": "True"
+            },
+            {
+                "host": "h8v4",
+                "id": "00:AA:00:00:00:06/None",
+                "dualHomed": "False"
+            },
+            {
+                "host": "h10v4",
+                "id": "00:AA:00:00:00:08/40",
+                "dualHomed": "True"
+            }
+        ]
+    },
+    "ipv6": {
+        "ipVersion": 6,
+        "group": "ff08::3fe",
+        "src": [
+            {
+                "host": "h3v6",
+                "ip": "1002::3fe",
+                "port": "of:0000000000000002/6",
+                "interface": "h3v6-eth0",
+                "Ether": "33:33:00:00:03:fe",
+                "UDP": 40051,
+                "filter": "ip6 host ff08::3fe",
+                "packet": "dst=33:33:00:00:03:fe src=00:bb:00:00:00:02"
+            }
+        ],
+        "dst": [
+            {
+                "host": "h1v6",
+                "id": "00:BB:00:00:00:01/None"
+            }
+        ]
+    }
+}
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/switchFailure/CASE201.switchFailureChart b/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/switchFailure/CASE201.switchFailureChart
deleted file mode 100644
index 6614e5f..0000000
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/dependencies/switchFailure/CASE201.switchFailureChart
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "spine101": { "switches_before_failure": 10,
-                  "links_before_failure": 48,
-                  "switches_after_failure": 9,
-                  "links_after_failure": 30 },
-    "spine102": { "switches_before_failure": 10,
-                  "links_before_failure": 48,
-                  "switches_after_failure": 9,
-                  "links_after_failure": 30 },
-    "spine103": { "switches_before_failure": 10,
-                  "links_before_failure": 48,
-                  "switches_after_failure": 9,
-                  "links_after_failure": 42 },
-    "spine104": { "switches_before_failure": 10,
-                  "links_before_failure": 48,
-                  "switches_after_failure": 9,
-                  "links_after_failure": 42 }
-}
diff --git a/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.topo b/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.topo
index 28ecb9a..9ee92d6 100755
--- a/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.topo
@@ -28,7 +28,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params
index a7461aa..e699d81 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params
+++ b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params
@@ -21,7 +21,7 @@
 
     <ENV>
         <cellName>productionCell</cellName>
-        <cellApps>drivers,openflow,segmentrouting,fpm,dhcprelay,netcfghostprovider,routeradvertisement</cellApps>
+        <cellApps>drivers,openflow,segmentrouting,fpm,dhcprelay,netcfghostprovider,routeradvertisement,t3</cellApps>
     </ENV>
 
     <GIT>
@@ -39,8 +39,17 @@
         <OnosDiscovery>30</OnosDiscovery>
         <loadNetcfgSleep>5</loadNetcfgSleep>
         <startMininetSleep>25</startMininetSleep>
-        <dhcpSleep>60</dhcpSleep>
+        <dhcpSleep>30</dhcpSleep>
         <balanceMasterSleep>10</balanceMasterSleep>
     </timers>
 
+    <TOPO>
+        <internalIpv4Hosts>h1v4,h2v4,h3v4,h4v4,h5v4,h6v4,h7v4,h8v4,h9v4,h10v4,h11v4,h12v4,h13v4</internalIpv4Hosts>
+        <internalIpv6Hosts>h1v6,h2v6,h3v6,h4v6,h5v6,h6v6,h7v6,h8v6,h9v6,h10v6,h11v6,h12v6,h13v6</internalIpv6Hosts>
+        <externalIpv4Hosts>rh1v4,rh2v4</externalIpv4Hosts>
+        <externalIpv6Hosts>rh1v6,rh11v6,rh2v6,rh22v6</externalIpv6Hosts>
+        <switchNum>10</switchNum>
+        <linkNum>48</linkNum>
+    </TOPO>
+
 </PARAMS>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.py b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.py
index 07f1260..5f4157f 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.py
@@ -738,3 +738,34 @@
                                staticRouteConfigure=True,
                                nodeFailure=True )
 
+    def CASE606( self, main ):
+        """
+        Drop SPINE-1 and test connectivity
+        Drop paired leaf and test connectivity (expect some failures)
+        Bring up SPINE-1 and test connectivity (still expect some failures)
+        Bring up the paired leaf and test connectivity
+        Repeat above with SPINE-2 and a different paired leaf
+        """
+        import time
+        from tests.USECASE.SegmentRouting.SRRouting.dependencies.SRRoutingTest import *
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+        main.case( "Drop spine and paired leaf" )
+        setupTest( main, test_idx=606, onosNodes=3 )
+        main.disconnectedIpv4Hosts = []
+        main.disconnectedIpv6Hosts = []
+        verifyPing( main )
+        lib.killSwitch( main, "spine101", int( main.params[ "TOPO" ][ "switchNum" ] ) - 1, int( main.params[ "TOPO" ][ "linkNum" ] ) - 18 )
+        verifyPing( main )
+        lib.killSwitch( main, "leaf2", int( main.params[ "TOPO" ][ "switchNum" ] ) - 2, int( main.params[ "TOPO" ][ "linkNum" ] ) - 24 )
+        lib.killSwitch( main, "leaf3", int( main.params[ "TOPO" ][ "switchNum" ] ) - 3, int( main.params[ "TOPO" ][ "linkNum" ] ) - 28 )
+        main.disconnectedIpv4Hosts = [ "h3v4", "h4v4", "h5v4", "h6v4", "h7v4" ]
+        main.disconnectedIpv6Hosts = [ "h3v6", "h4v6", "h5v6", "h6v6", "h7v6" ]
+        verifyPing( main )
+        lib.recoverSwitch( main, "spine101", int( main.params[ "TOPO" ][ "switchNum" ] ) - 2, int( main.params[ "TOPO" ][ "linkNum" ] ) - 18 )
+        verifyPing( main )
+        lib.recoverSwitch( main, "leaf3", int( main.params[ "TOPO" ][ "switchNum" ] ) - 1, int( main.params[ "TOPO" ][ "linkNum" ] ) - 10 )
+        lib.recoverSwitch( main, "leaf2", int( main.params[ "TOPO" ][ "switchNum" ] ), int( main.params[ "TOPO" ][ "linkNum" ] ) )
+        main.disconnectedIpv4Hosts = []
+        main.disconnectedIpv6Hosts = []
+        verifyPing( main )
+        lib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.topo b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.topo
index 01316b6..dbb415d 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.topo
@@ -27,7 +27,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRRouting/dependencies/SRRoutingTest.py b/TestON/tests/USECASE/SegmentRouting/SRRouting/dependencies/SRRoutingTest.py
index 68533bb..a9a24bb 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRRouting/dependencies/SRRoutingTest.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRRouting/dependencies/SRRoutingTest.py
@@ -154,3 +154,97 @@
             run.checkFlowsGroupsFromFile( main )
         # ping hosts
         run.pingAll( main, 'CASE%03d' % test_idx, False, acceptableFailed=5, basedOnIp=True, skipOnFail=True )
+
+
+def setupTest( main, test_idx, onosNodes ):
+    """
+    SRRouting test setup
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    skipPackage = False
+    init = False
+    if not hasattr( main, 'apps' ):
+        init = True
+        run.initTest( main )
+    # Skip onos packaging if the cluster size stays the same
+    if not init and onosNodes == main.Cluster.numCtrls:
+        skipPackage = True
+
+    main.internalIpv4Hosts = main.params[ 'TOPO' ][ 'internalIpv4Hosts' ].split( ',' )
+    main.internalIpv6Hosts = main.params[ 'TOPO' ][ 'internalIpv6Hosts' ].split( ',' )
+    main.externalIpv4Hosts = main.params[ 'TOPO' ][ 'externalIpv4Hosts' ].split( ',' )
+    main.externalIpv6Hosts = main.params[ 'TOPO' ][ 'externalIpv6Hosts' ].split( ',' )
+    main.resultFileName = "CASE%03d" % test_idx
+    main.Cluster.setRunningNode( onosNodes )
+    lib.installOnos( main, skipPackage=skipPackage, cliSleep=5 )
+    # Load configuration files
+    main.step( "Load configurations" )
+    main.cfgName = "TEST_CONFIG_ipv4=1_ipv6=1_dhcp=1_routers=1_external=1"
+    lib.loadJson( main )
+    time.sleep( float( main.params[ "timers" ][ "loadNetcfgSleep" ] ) )
+
+    if hasattr( main, "Mininet1" ):
+        # Run the test with Mininet
+        mininet_args = " --dhcp=1 --routers=1 --ipv6=1 --ipv4=1"
+        lib.startMininet( main, main.params[ "DEPENDENCY" ][ "topology" ], args=mininet_args )
+        time.sleep( float( main.params[ "timers" ][ "startMininetSleep" ] ) )
+    else:
+        # Run the test with physical devices
+        lib.connectToPhysicalNetwork( main, self.switchNames )
+        # Check if the devices are up
+        lib.checkDevices( main, switches=len( self.switchNames ) )
+
+    # wait some time for onos to install the rules!
+    time.sleep( float( main.params[ "timers" ][ "startMininetSleep" ] ) )
+    time.sleep( float( main.params[ "timers" ][ "dhcpSleep" ] ) )
+
+def verifyPingInternal( main, verifyDisconnected=True ):
+    """
+    Verify all connected internal hosts are able to reach each other,
+    and disconnected internal hosts cannot reach any other internal host
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    # Verify connected hosts
+    main.step("Verify reachability of connected internal hosts")
+    lib.verifyPing( main,
+                    [ h for h in main.internalIpv4Hosts if h not in main.disconnectedIpv4Hosts ],
+                    [ h for h in main.internalIpv4Hosts if h not in main.disconnectedIpv4Hosts ] )
+    lib.verifyPing( main,
+                    [ h for h in main.internalIpv6Hosts if h not in main.disconnectedIpv6Hosts ],
+                    [ h for h in main.internalIpv6Hosts if h not in main.disconnectedIpv6Hosts ],
+                    ipv6=True, acceptableFailed=7 )
+    # Verify disconnected hosts
+    if verifyDisconnected and ( main.disconnectedIpv4Hosts or main.disconnectedIpv6Hosts ):
+        main.step("Verify unreachability of disconnected internal hosts")
+        lib.verifyPing( main, main.internalIpv4Hosts, main.disconnectedIpv4Hosts, expect=False )
+        lib.verifyPing( main, main.internalIpv6Hosts, main.disconnectedIpv6Hosts, ipv6=True, expect=False )
+
+def verifyPingExternal( main, verifyDisconnected=True ):
+    """
+    Verify all connected internal hosts are able to reach external hosts,
+    and disconnected internal hosts cannot reach any external host
+    """
+    from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as lib
+    # Verify connected hosts
+    main.step("Verify reachability of from connected internal hosts to external hosts")
+    lib.verifyPing( main,
+                    [ h for h in main.internalIpv4Hosts if h not in main.disconnectedIpv4Hosts ],
+                    main.externalIpv4Hosts )
+    lib.verifyPing( main,
+                    [ h for h in main.internalIpv6Hosts if h not in main.disconnectedIpv6Hosts ],
+                    main.externalIpv6Hosts,
+                    ipv6=True, acceptableFailed=7 )
+    # Verify disconnected hosts
+    '''
+    if verifyDisconnected and ( main.disconnectedIpv4Hosts or main.disconnectedIpv6Hosts ):
+        main.step("Verify unreachability of disconnected internal hosts to external hosts")
+        lib.verifyPing( main, main.disconnectedIpv4Hosts, main.externalIpv4Hosts, expect=False )
+        lib.verifyPing( main, main.disconnectedIpv6Hosts, main.externalIpv6Hosts, ipv6=True, expect=False )
+    '''
+
+def verifyPing( main ):
+    """
+    Verify reachability and unreachability of connected/disconnected hosts
+    """
+    verifyPingInternal( main )
+    verifyPingExternal( main )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.topo b/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.topo
index 28ecb9a..9ee92d6 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.topo
@@ -28,7 +28,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.topo b/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.topo
index 67a973e..a342504 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.topo
@@ -28,7 +28,7 @@
             <type>MininetCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS>
-                <home>~/mininet/custom/</home>
+                <home>~/mininet/</home>
                 <prompt></prompt>
             </COMPONENTS>
         </Mininet1>
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
index 358ce47..7f4f780 100644
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
@@ -175,13 +175,13 @@
     def startMininet( main, topology, args="" ):
         copyResult = main.ONOSbench.scp( main.Mininet1,
                                          main.topoPath + main.topology,
-                                         main.Mininet1.home,
+                                         main.Mininet1.home + "custom",
                                          direction="to" )
         if main.topologyLib:
             for lib in main.topologyLib.split(","):
                 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
                                                                 main.topoPath + lib,
-                                                                main.Mininet1.home,
+                                                                main.Mininet1.home + "custom",
                                                                 direction="to" )
         if main.topologyConf:
             import re
@@ -210,7 +210,7 @@
         arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
         main.topology = topology
         topoResult = main.Mininet1.startNet(
-                topoFile=main.Mininet1.home + main.topology, args=arg )
+                topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
         stepResult = topoResult
         utilities.assert_equals( expect=main.TRUE,
                                  actual=stepResult,
@@ -588,11 +588,12 @@
                                  onfail="Link batch up failed" )
 
     @staticmethod
-    def restoreLink( main, end1, end2, dpid1, dpid2, port1, port2, switches,
-                     links ):
+    def restoreLink( main, end1, end2, switches, links,
+                     portUp=False, dpid1='', dpid2='', port1='', port2='' ):
         """
         Params:
             end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
+            portUp: enable portstate after restoring link
             dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
             port1, port2: respective port of the end switches that connects to the link, ex.:'1'
             switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
@@ -609,13 +610,10 @@
                     "Waiting %s seconds for link up to be discovered" % main.linkSleep )
             time.sleep( main.linkSleep )
 
-            for i in range( 0, main.Cluster.numCtrls ):
-                ctrl = main.Cluster.runningNodes[ i ]
-                onosIsUp = main.ONOSbench.isup( ctrl.ipAddress )
-                if onosIsUp == main.TRUE:
-                    ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
-                    ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
-            time.sleep( main.linkSleep )
+            if portUp:
+                ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
+                ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
+                time.sleep( main.linkSleep )
 
             result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
                                                                numolink=links )
@@ -632,9 +630,11 @@
         Completely kill a switch and verify ONOS can see the proper change
         """
         main.switchSleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
-        main.step( "Kill " + switch )
-        main.log.info( "Stopping" + switch )
-        main.Network.switch( SW=switch, OPTION="stop" )
+        switch = switch if isinstance( switch, list ) else [ switch ]
+        main.step( "Kill " + str( switch ) )
+        for s in switch:
+            main.log.info( "Stopping " + s )
+            main.Network.switch( SW=s, OPTION="stop" )
         # todo make this repeatable
         main.log.info( "Waiting %s seconds for switch down to be discovered" % (
             main.switchSleep ) )
@@ -656,9 +656,11 @@
         Recover a switch and verify ONOS can see the proper change
         """
         # todo make this repeatable
-        main.step( "Recovering " + switch )
-        main.log.info( "Starting" + switch )
-        main.Network.switch( SW=switch, OPTION="start" )
+        switch = switch if isinstance( switch, list ) else [ switch ]
+        main.step( "Recovering " + str( switch ) )
+        for s in switch:
+            main.log.info( "Starting " + s )
+            main.Network.switch( SW=s, OPTION="start" )
         main.log.info( "Waiting %s seconds for switch up to be discovered" % (
             main.switchSleep ) )
         time.sleep( main.switchSleep )
@@ -672,8 +674,27 @@
                                  onpass="Switch recovery successful",
                                  onfail="Failed to recover switch?" )
 
+    def portstate( main, dpid, port, state, switches, links ):
+        """
+        Disable/enable a switch port using 'portstate' and verify ONOS can see the proper link change
+        Params:
+            dpid: dpid of the switch, ex.: 'of:0000000000000002'
+            port: port of the switch to disable/enable, ex.:'1'
+            state: disable or enable
+            switches, links: number of expected switches and links after link change, ex.: '4', '6'
+        """
+        main.step( "Port %s on %s:%s" % ( state, dpid, port ) )
+        main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state=state )
+        main.log.info( "Waiting %s seconds for port %s to be discovered" % ( main.linkSleep, state ) )
+        time.sleep( main.linkSleep )
+        result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
+                                                           numolink=links )
+        utilities.assert_equals( expect=main.TRUE, actual=result,
+                                 onpass="Port %s successful" % state,
+                                 onfail="Port %s failed" % state )
+
     @staticmethod
-    def cleanup( main, copyKarafLog=True ):
+    def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
         """
         Stop Onos-cluster.
         Stops Mininet
@@ -699,6 +720,11 @@
                 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
             main.scapyHosts = []
 
+        if removeHostComponent:
+            for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
+                if hasattr( main, host ):
+                    main.Network.removeHostComponent( host )
+
         if hasattr( main, 'Mininet1' ):
             main.utils.mininetCleanup( main.Mininet1 )
 
@@ -978,50 +1004,87 @@
             main.log.debug( host.hostMac )
 
     @staticmethod
-    def verifyMulticastTraffic( main, entry, expect, skipOnFail=False ):
+    def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=3 ):
         """
         Verify multicast traffic using scapy
         """
-        srcEntry = entry["scapy"]["src"]
-        for dstEntry in entry["scapy"]["dst"]:
-            # Set up scapy receiver
-            receiver = getattr( main, dstEntry["host"] )
-            if "interface" in dstEntry.keys():
-                receiver.startFilter( ifaceName=dstEntry["interface"], pktFilter=srcEntry["filter"] )
-            else:
-                receiver.startFilter( pktFilter=srcEntry["filter"] )
-            # Set up scapy sender
-            main.Network.addRoute( str( srcEntry["host"] ),
-                                   str( entry["group"] ),
-                                   str( srcEntry["interface"] ),
-                                   True if entry["ipVersion"] == 6 else False )
-            sender = getattr( main, srcEntry["host"] )
-            sender.buildEther( dst=str( srcEntry["Ether"] ) )
-            if entry["ipVersion"] == 4:
-                sender.buildIP( dst=str( entry["group"] ) )
-            elif entry["ipVersion"] == 6:
-                sender.buildIPv6( dst=str( entry["group"] ) )
-            sender.buildUDP( ipVersion=entry["ipVersion"], dport=srcEntry["UDP"] )
-            # Send packet and check received packet
-            sender.sendPacket( iface=srcEntry["interface"] )
-            finished = receiver.checkFilter()
-            packet = ""
-            if finished:
-                packets = receiver.readPackets()
-                for packet in packets.splitlines():
-                    main.log.debug( packet )
-            else:
-                kill = receiver.killFilter()
-                main.log.debug( kill )
-                sender.handle.sendline( "" )
-                sender.handle.expect( sender.scapyPrompt )
-                main.log.debug( sender.handle.before )
-            packetCaptured = True if srcEntry["packet"] in packet else False
-            utilities.assert_equals( expect=expect,
-                                     actual=packetCaptured,
-                                     onpass="Pass",
-                                     onfail="Fail" )
-            if skipOnFail and packetCaptured != expect:
-                Testcaselib.saveOnosDiagnostics( main )
-                Testcaselib.cleanup( main, copyKarafLog=False )
-                main.skipCase()
+        routeData = main.multicastConfig[ routeName ]
+        srcs = main.mcastRoutes[ routeName ][ "src" ]
+        dsts = main.mcastRoutes[ routeName ][ "dst" ]
+        main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
+                                                                         [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
+        for src in srcs:
+            srcEntry = routeData[ "src" ][ src ]
+            for dst in dsts:
+                dstEntry = routeData[ "dst" ][ dst ]
+                sender = getattr( main, srcEntry[ "host" ] )
+                receiver = getattr( main, dstEntry[ "host" ] )
+                main.Network.addRoute( str( srcEntry[ "host" ] ),
+                                       str( routeData[ "group" ] ),
+                                       str( srcEntry[ "interface" ] ),
+                                       True if routeData[ "ipVersion" ] == 6 else False )
+                # Build the packet
+                sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
+                if routeData[ "ipVersion" ] == 4:
+                    sender.buildIP( dst=str( routeData[ "group" ] ) )
+                elif routeData[ "ipVersion" ] == 6:
+                    sender.buildIPv6( dst=str( routeData[ "group" ] ) )
+                sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
+                sIface = srcEntry[ "interface" ]
+                dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
+                pktFilter = srcEntry[ "filter" ]
+                pkt = srcEntry[ "packet" ]
+                # Send packet and check received packet
+                expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
+                trafficResult = utilities.retry( Testcaselib.sendMulticastTraffic,
+                                                 main.FALSE,
+                                                 args=( main, sender, receiver, pktFilter, pkt,
+                                                        sIface, dIface, expectedResult ),
+                                                 attempts=maxRetry,
+                                                 sleep=1 )
+                utilities.assert_equals( expect=main.TRUE,
+                                         actual=trafficResult,
+                                         onpass="{} to {}: Pass".format( srcEntry[ "host" ], dstEntry[ "host" ] ),
+                                         onfail="{} to {}: Fail".format( srcEntry[ "host" ], dstEntry[ "host" ] ) )
+                if skipOnFail and trafficResult != main.TRUE:
+                    Testcaselib.saveOnosDiagnostics( main )
+                    Testcaselib.cleanup( main, copyKarafLog=False )
+                    main.skipCase()
+
+    @staticmethod
+    def sendMulticastTraffic( main, sender, receiver, pktFilter, pkt, sIface=None, dIface=None, expect=True ):
+        """
+        Send multicast traffic using scapy
+        """
+        receiver.startFilter( ifaceName=dIface, pktFilter=pktFilter )
+        sender.sendPacket( iface=sIface )
+        finished = receiver.checkFilter()
+        packet = ""
+        if finished:
+            packets = receiver.readPackets()
+            for packet in packets.splitlines():
+                main.log.debug( packet )
+        else:
+            kill = receiver.killFilter()
+            main.log.debug( kill )
+            sender.handle.sendline( "" )
+            sender.handle.expect( sender.scapyPrompt )
+            main.log.debug( sender.handle.before )
+        packetCaptured = True if pkt in packet else False
+        return main.TRUE if packetCaptured == expect else main.FALSE
+
+    @staticmethod
+    def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1, acceptableFailed=0, skipOnFail=True ):
+        """
+        Verify reachability from each host in srcList to each host in dstList
+        """
+        from tests.dependencies.topology import Topology
+        try:
+            main.topo
+        except ( NameError, AttributeError ):
+            main.topo = Topology()
+        pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail )
+        if not pingResult and skipOnFail:
+            Testcaselib.saveOnosDiagnostics( main )
+            Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
+            main.skipCase()
diff --git a/TestON/tests/dependencies/topology.py b/TestON/tests/dependencies/topology.py
index 04e6246..6527a83 100644
--- a/TestON/tests/dependencies/topology.py
+++ b/TestON/tests/dependencies/topology.py
@@ -22,6 +22,7 @@
 import re
 import imp
 import json
+from core import utilities
 
 
 class Topology:
@@ -226,3 +227,78 @@
                                  onpass="ONOS correctly discovered the topology",
                                  onfail="ONOS incorrectly discovered the topology" )
         return topoResults
+
+    def ping( self, srcList, dstList, ipv6=False, expect=True, wait=1, acceptableFailed=0, collectT3=True ):
+        """
+        Description:
+            Ping from every host in srcList to every host in dstList and
+            verify if ping results are as expected.
+            Pings are executed in parallel from host components
+        Options:
+            src: a list of source host names, e.g. [ "h1", "h2" ]
+            dst: a list of destination host names, e.g. [ "h3", "h4" ]
+            expect: expect ping result to pass if True, otherwise fail
+            acceptableFailed: maximum number of failed pings acceptable for
+                              each src-dst host pair
+            collectT3: save t3-troubleshoot output for src and dst host that failed to ping
+        Returns:
+            main.TRUE if all ping results are expected, otherwise main.FALSE
+        """
+        main.log.info( "Pinging from {} to {}, expected result is {}".format( srcList, dstList,
+                                                                              "pass" if expect else "fail" ) )
+        # Verify host component has been created
+        srcIpList = {}
+        for src in srcList:
+            if not hasattr( main, src ):
+                main.log.info( "Creating component for host {}".format( src ) )
+                main.Network.createHostComponent( src )
+                hostHandle = getattr( main, src )
+                main.log.info( "Starting CLI on host {}".format( src ) )
+                hostHandle.startHostCli()
+            srcIpList[ src ] = main.Network.getIPAddress( src, proto='IPV6' if ipv6 else 'IPV4' )
+
+        unexpectedPings = []
+        for dst in dstList:
+            dstIp = main.Network.getIPAddress( dst, proto='IPV6' if ipv6 else 'IPV4' )
+            # Start pings from src hosts in parallel
+            pool = []
+            for src in srcList:
+                srcIp = srcIpList[ src ]
+                if srcIp == dstIp:
+                    continue
+                if expect and ( not srcIp or not dstIp ):
+                    unexpectedPings.append( [ src, dst, "no IP" ] )
+                    continue
+                hostHandle = getattr( main, src )
+                thread = main.Thread( target=utilities.retry,
+                                      name="{}-{}".format( srcIp, dstIp ),
+                                      args=[ hostHandle.pingHostSetAlternative, [ main.FALSE ] ],
+                                      kwargs={ "args":( [ dstIp ], wait, ipv6 ),
+                                               "attempts": acceptableFailed + 1,
+                                               "sleep": 1 } )
+                pool.append( thread )
+                thread.start()
+            # Wait for threads to finish and check ping result
+            for thread in pool:
+                thread.join( 10 )
+                srcIp, dstIp = thread.name.split( "-" )
+                if expect and not thread.result or not expect and thread.result:
+                    unexpectedPings.append( [ srcIp, dstIp, "fail" if expect else "pass" ] )
+
+        utilities.assert_equals( expect=[],
+                                 actual=unexpectedPings,
+                                 onpass="Pings from {} to {} all as expected".format( srcList, dstList ),
+                                 onfail="Unexpected pings: {}".format( unexpectedPings ) )
+        if collectT3:
+            for unexpectedPing in unexpectedPings:
+                if unexpectedPing[ 2 ] == "no IP":
+                    continue
+                srcIp = unexpectedPing[ 0 ]
+                dstIp = unexpectedPing[ 1 ]
+                main.log.debug( "Collecting t3 with source {} and destination {}".format( srcIp, dstIp ) )
+                cmd = main.Cluster.active( 0 ).CLI.composeT3Command( srcIp, dstIp, ipv6 )
+                main.log.debug( "t3 command: {}".format( cmd ) )
+                if cmd:
+                    main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress, cmd, main.logdir,
+                                                "t3-CASE{}-{}-{}-".format( main.CurrentTestCaseNumber, srcIp, dstIp ) )
+        return main.FALSE if unexpectedPings else main.TRUE