Dynamic configuration of SR

Change-Id: I847d1cf66f146f213947a336ca0619a3e28ace36
diff --git a/TestON/drivers/common/api/controller/onosrestdriver.py b/TestON/drivers/common/api/controller/onosrestdriver.py
old mode 100644
new mode 100755
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamic/README.md b/TestON/tests/USECASE/SegmentRouting/SRDynamic/README.md
new file mode 100755
index 0000000..e84af0b
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamic/README.md
@@ -0,0 +1,22 @@
+This test verifies connectivity in face of dynamic configuration and Onos failures using SegmentRouting
+
+It consists of
+
+1) Configure and Install ONOS
+2) Start Mininet and check flow state
+3) Connectivity test
+4) Add Hosts dynamically
+5) Connectivity test
+6) Onos Failure
+7) Remove host configuration
+
+Requirements
+
+ - An updated version of the CPQD switch has to be running to make sure it supports group chaining.
+
+The test is executed using the netcfg subsystem:
+    1) APPS=openflow-base,netcfghostprovider,netcfglinksprovider
+The test runs for different topologies:
+ - 2x2 Leaf-Spine and 3-node ONOS cluster
+ - 4x4 Leaf-Spine and 3-node ONOS cluster
+ - Single switch and 3-node ONOS cluster
\ No newline at end of file
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.params b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.params
new file mode 100755
index 0000000..a757a48
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.params
@@ -0,0 +1,46 @@
+<PARAMS>
+
+    <testcases>1,2,3,4,5,6</testcases>
+
+    <SCALE>
+        <size>3</size>
+        <max>3</max>
+    </SCALE>
+
+    <DEPENDENCY>
+        <wrapper1>startUp</wrapper1>
+        <topology>cord_fabric.py</topology>
+    </DEPENDENCY>
+
+    <ENV>
+        <cellName>productionCell</cellName>
+        <cellApps>drivers,segmentrouting</cellApps>
+        <diffApps>openflow-base,netcfghostprovider,netcfglinksprovider</diffApps>
+        <cellUser>sdn</cellUser>
+    </ENV>
+
+    <GIT>
+        <pull>False</pull>
+        <branch>master</branch>
+    </GIT>
+
+    <CTRL>
+        <port>6653</port>
+    </CTRL>
+
+    <timers>
+        <LinkDiscovery>12</LinkDiscovery>
+        <SwitchDiscovery>12</SwitchDiscovery>
+    </timers>
+
+    <kill>
+        <switch> spine101 </switch>
+        <dpid> 000000000101 </dpid>
+        <links> leaf1 leaf2 </links>
+    </kill>
+
+    <SLEEP>
+        <startup>10</startup>
+    </SLEEP>
+
+</PARAMS>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.py b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.py
new file mode 100755
index 0000000..9d84bb4
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.py
@@ -0,0 +1,173 @@
+# CASE1: 2x2 Leaf-Spine topo and test IP connectivity
+# CASE2: 4x4 topo + IP connectivity test
+# CASE3: Single switch topo + IP connectivity test
+# CASE4: 2x2 topo + 3-node ONOS CLUSTER + IP connectivity test
+# CASE5: 4x4 topo + 3-node ONOS CLUSTER + IP connectivity test
+# CASE6: Single switch + 3-node ONOS CLUSTER + IP connectivity test
+
+class SRDynamic:
+    def __init__( self ):
+        self.default = ''
+
+    def CASE1( self, main ):
+        """
+        Sets up 1-node Onos-cluster
+        Start 2x2 Leaf-Spine topology
+        Pingall
+        """
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+            Testcaselib as run
+        if not hasattr( main, 'apps' ):
+            run.initTest( main )
+
+        description = "Bridging and Routing sanity test with 2x2 Leaf-spine "
+        main.case( description )
+
+        main.cfgName = '2x2'
+        main.numCtrls = 1
+        run.installOnos( main, vlanCfg=False )
+        run.startMininet( main, 'cord_fabric.py' )
+        # pre-configured routing and bridging test
+        run.checkFlows( main, minFlowCount=116 )
+        run.pingAll( main, dumpflows=False, )
+        run.addHostCfg( main )
+        run.checkFlows( main, minFlowCount=140, dumpflows=False )
+        run.pingAll( main, "CASE1" )
+        run.cleanup( main )
+
+    def CASE2( self, main ):
+        """
+        Sets up 1-node Onos-cluster
+        Start 4x4 Leaf-Spine topology
+        Pingall
+        """
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+            Testcaselib as run
+        if not hasattr( main, 'apps' ):
+            run.initTest( main )
+        description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
+        main.case( description )
+        main.cfgName = '4x4'
+        main.numCtrls = 1
+        run.installOnos( main, vlanCfg=False )
+        run.startMininet( main, 'cord_fabric.py',
+                          args="--leaf=4 --spine=4" )
+        # pre-configured routing and bridging test
+        run.checkFlows( main, minFlowCount=350 )
+        run.pingAll( main, dumpflows=False )
+        run.addHostCfg( main )
+        run.checkFlows( main, minFlowCount=380, dumpflows=False )
+        run.pingAll( main, 'CASE2' )
+        run.cleanup( main )
+
+    def CASE3( self, main ):
+        """
+        Sets up 1-node Onos-cluster
+        Start single switch topology
+        Pingall
+        """
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+            Testcaselib as run
+        if not hasattr( main, 'apps' ):
+            run.initTest( main )
+        description = "Bridging and Routing sanity test with single switch "
+        main.case( description )
+        main.cfgName = '0x1'
+        main.numCtrls = 1
+        run.installOnos( main, vlanCfg=False )
+        run.startMininet( main, 'cord_fabric.py',
+                          args="--leaf=1 --spine=0" )
+        # pre-configured routing and bridging test
+        run.checkFlows( main, minFlowCount=15 )
+        run.pingAll( main, dumpflows=False )
+        run.addHostCfg( main )
+        run.checkFlows( main, minFlowCount=18, dumpflows=False )
+        run.pingAll( main, 'CASE3' )
+        run.cleanup( main )
+
+    def CASE4( self, main ):
+        """
+        Sets up 3-node Onos-cluster
+        Start 2x2 Leaf-Spine topology
+        Pingall
+        """
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+            Testcaselib as run
+        if not hasattr( main, 'apps' ):
+            run.initTest( main )
+        description = "Bridging and Routing sanity test with 2x2 Leaf-spine "
+        main.case( description )
+
+        main.cfgName = '2x2'
+        main.numCtrls = 3
+        run.installOnos( main, vlanCfg=False )
+        run.startMininet( main, 'cord_fabric.py' )
+        # pre-configured routing and bridging test
+        run.checkFlows( main, minFlowCount=116 )
+        run.pingAll( main, dumpflows=False )
+        run.addHostCfg( main )
+        run.checkFlows( main, minFlowCount=140, dumpflows=False )
+        run.pingAll( main, "CASE4" )
+        run.killOnos( main, [ 0 ], '4', '8', '2' )
+        run.delHostCfg( main )
+        run.checkFlows( main, minFlowCount=116, dumpflows=False )
+        run.pingAll( main, "CASE4_after" )
+        run.cleanup( main )
+
+    def CASE5( self, main ):
+        """
+        Sets up 3-node Onos-cluster
+        Start 4x4 Leaf-Spine topology
+        Pingall
+        """
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+            Testcaselib as run
+        if not hasattr( main, 'apps' ):
+            run.initTest( main )
+        description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
+        main.case( description )
+        main.cfgName = '4x4'
+        main.numCtrls = 3
+        run.installOnos( main, vlanCfg=False )
+        run.startMininet( main, 'cord_fabric.py',
+                          args="--leaf=4 --spine=4" )
+        # pre-configured routing and bridging test
+        run.checkFlows( main, minFlowCount=350 )
+        run.pingAll( main, dumpflows=False )
+        run.addHostCfg( main )
+        run.checkFlows( main, minFlowCount=380, dumpflows=False )
+        run.pingAll( main, 'CASE5' )
+        run.killOnos( main, [ 0 ], '8', '32', '2' )
+        run.delHostCfg( main )
+        run.checkFlows( main, minFlowCount=350, dumpflows=False )
+        run.pingAll( main, "CASE5_After" )
+        run.cleanup( main )
+
+    def CASE6( self, main ):
+        """
+        Sets up 3-node Onos-cluster
+        Start single switch topology
+        Pingall
+        """
+        from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+            Testcaselib as run
+        if not hasattr( main, 'apps' ):
+            run.initTest( main )
+        description = "Bridging and Routing sanity test with single switch "
+        main.case( description )
+        main.cfgName = '0x1'
+        main.numCtrls = 3
+        run.installOnos( main, vlanCfg=False )
+        run.startMininet( main, 'cord_fabric.py',
+                          args="--leaf=1 --spine=0" )
+        # pre-configured routing and bridging test
+        run.checkFlows( main, minFlowCount=15 )
+        run.pingAll( main, dumpflows=False )
+        run.addHostCfg( main )
+        run.checkFlows( main, minFlowCount=20, dumpflows=False )
+        run.pingAll( main, 'CASE6' )
+        run.killOnos( main, [ 0 ], '1', '0', '2' )
+        run.delHostCfg( main )
+        run.checkFlows( main, minFlowCount=15, dumpflows=False )
+        run.pingAll( main, "CASE6_After" )
+        run.cleanup( main )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo
new file mode 100755
index 0000000..c531f7d
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo
@@ -0,0 +1,90 @@
+<TOPOLOGY>
+    <COMPONENT>
+
+        <ONOSbench>
+            <host>localhost</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosDriver</type>
+            <connect_order>1</connect_order>
+            <COMPONENTS>
+                <nodes>1</nodes>
+            </COMPONENTS>
+        </ONOSbench>
+
+        <ONOScli1>
+            <host>OC1</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosCliDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOScli1>
+        
+        <ONOScli2>
+            <host>OC2</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosCliDriver</type>
+            <connect_order>3</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOScli2>
+
+        <ONOScli3>
+            <host>OC3</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosCliDriver</type>
+            <connect_order>4</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOScli3>
+
+        <ONOSrest1>
+            <host>OC1</host>
+            <port>8181</port>
+            <user>onos</user>
+            <password>rocks</password>
+            <type>OnosRestDriver</type>
+            <connect_order>5</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOSrest1>
+
+        <ONOSrest2>
+            <host>OC2</host>
+            <port>8181</port>
+            <user>onos</user>
+            <password>rocks</password>
+            <type>OnosRestDriver</type>
+            <connect_order>6</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOSrest2>
+
+        <ONOSrest3>
+            <host>OC3</host>
+            <port>8181</port>
+            <user>onos</user>
+            <password>rocks</password>
+            <type>OnosRestDriver</type>
+            <connect_order>6</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOSrest3>
+
+        <Mininet1>
+            <host>OCN</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>MininetCliDriver</type>
+            <connect_order>7</connect_order>
+            <COMPONENTS>
+                <home>~/mininet/custom/</home>
+            </COMPONENTS>
+        </Mininet1>
+
+    </COMPONENT>
+</TOPOLOGY>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamic/__init__.py b/TestON/tests/USECASE/SegmentRouting/SRDynamic/__init__.py
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamic/__init__.py
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
index c1efd93..38e013e 100755
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
@@ -2,7 +2,7 @@
 import imp

 import time

 import json

-

+import urllib

 from core import utilities

 

 

@@ -66,7 +66,7 @@
                                  onfail="Failed to construct test variables" )

 

     @staticmethod

-    def installOnos( main ):

+    def installOnos( main, vlanCfg=True ):

         """

         - Set up cell

             - Create cell file

@@ -87,6 +87,7 @@
         print "NODE COUNT = ", main.numCtrls

         print main.ONOSip

         tempOnosIp = [ ]

+        main.dynamicHosts = [ 'in1', 'out1' ]

         for i in range( main.numCtrls ):

             tempOnosIp.append( main.ONOSip[ i ] )

         onosUser = main.params[ 'ENV' ][ 'cellUser' ]

@@ -167,9 +168,12 @@
                                  onpass="ONOS summary command succeded",

                                  onfail="ONOS summary command failed" )

 

-        with open( main.dependencyPath + "/" + main.cfgName + ".json" ) as cfg:

+        with open( "%s/json/%s.json" % (

+                main.dependencyPath, main.cfgName) ) as cfg:

             main.RESTs[ main.active ].setNetCfg( json.load( cfg ) )

-

+        with open( "%s/json/%s.chart" % (

+                main.dependencyPath, main.cfgName) ) as chart:

+            main.pingChart = json.load( chart )

         if not ready:

             main.log.error( "ONOS startup failed!" )

             main.cleanup( )

@@ -200,7 +204,7 @@
             main.exit( )

 

     @staticmethod

-    def checkFlows( main, minFlowCount ):

+    def checkFlows( main, minFlowCount, dumpflows=True ):

         main.step(

                 " Check whether the flow count is bigger than %s" % minFlowCount )

         count = utilities.retry( main.CLIs[ main.active ].checkFlowCount,

@@ -218,36 +222,34 @@
         flowCheck = utilities.retry( main.CLIs[ main.active ].checkFlowsState,

                                      main.FALSE,

                                      kwargs={ 'isPENDING': False },

-                                     attempts=10,

+                                     attempts=2,

                                      sleep=10 )

         utilities.assertEquals( \

                 expect=main.TRUE,

                 actual=flowCheck,

                 onpass="Flow status is correct!",

                 onfail="Flow status is wrong!" )

-        main.ONOSbench.dumpFlows( main.ONOSip[ main.active ],

-                                  main.logdir, "flowsBefore" + main.cfgName )

-        main.ONOSbench.dumpGroups( main.ONOSip[ 0 ],

-                                   main.logdir, "groupsBefore" + main.cfgName )

+        if dumpflows:

+            main.ONOSbench.dumpFlows( main.ONOSip[ main.active ],

+                                      main.logdir,

+                                      "flowsBefore" + main.cfgName )

+            main.ONOSbench.dumpGroups( main.ONOSip[ main.active ],

+                                       main.logdir,

+                                       "groupsBefore" + main.cfgName )

 

     @staticmethod

     def pingAll( main, tag="", dumpflows=True ):

         main.log.report( "Check full connectivity" )

-        main.step("Check IP connectivity %s" %tag)

-        hosts = main.Mininet1.getHosts().keys()

-        vlan10 = [ '%s10' % s for s in [ 'olt', 'vsg' ] ]

-        vlan5 = [ '%s5' % s for s in [ 'olt', 'vsg' ] ]

-        IPHosts = [ host for host in hosts if host not in ( vlan10 + vlan5 ) ]

-        pa = main.Mininet1.pingallHosts(IPHosts)

-        utilities.assert_equals( expect=main.TRUE, actual=pa,

-                                 onpass="IP connectivity successfully tested",

-                                 onfail="IP connectivity failed" )

-        main.step("Check VLAN  connectivity %s" %tag)

-        p1 = main.Mininet1.pingallHosts(vlan5)

-        p2 = main.Mininet1.pingallHosts(vlan10)

-        utilities.assert_equals( expect=main.TRUE, actual=p1&p2,

-                             onpass="Vlan connectivity successfully tested",

-                             onfail="Vlan connectivity failed" )

+        print main.pingChart

+        for entry in main.pingChart.itervalues( ):

+            print entry

+            hosts, expect = entry[ 'hosts' ], entry[ 'expect' ]

+            expect = main.TRUE if expect else main.FALSE

+            main.step( "Connectivity for %s %s" % (str( hosts ), tag) )

+            pa = main.Mininet1.pingallHosts( hosts )

+            utilities.assert_equals( expect=expect, actual=pa,

+                                     onpass="IP connectivity successfully tested",

+                                     onfail="IP connectivity failed" )

         if dumpflows:

             main.ONOSbench.dumpFlows( main.ONOSip[ main.active ],

                                       main.logdir, "flowsOn" + tag )

@@ -439,7 +441,6 @@
         utilities.assert_equals( expect=main.TRUE, actual=topology,

                                  onpass="ONOS Instance down successful",

                                  onfail="Failed to turn off ONOS Instance" )

-

         for i in range( 10 ):

             ready = True

             output = main.CLIs[ main.active ].summary( )

@@ -455,3 +456,72 @@
             main.log.error( "ONOS startup failed!" )

             main.cleanup( )

             main.exit( )

+

+    @staticmethod

+    def addHostCfg( main ):

+        """

+        Adds Host Configuration to ONOS

+        Updates expected state of the network (pingChart)

+        """

+        import json

+        hostCfg = { }

+        with open( main.dependencyPath + "/json/extra.json" ) as template:

+            hostCfg = json.load( template )

+        main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]

+        main.step( "Pushing new configuration" )

+        mac, cfg = hostCfg[ 'hosts' ].popitem( )

+        main.RESTs[ main.active ].setNetCfg( cfg[ 'basic' ],

+                                             subjectClass="hosts",

+                                             subjectKey=urllib.quote( mac,

+                                                                      safe='' ),

+                                             configKey="basic" )

+        main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]

+        main.step( "Pushing new configuration" )

+        mac, cfg = hostCfg[ 'hosts' ].popitem( )

+        main.RESTs[ main.active ].setNetCfg( cfg[ 'basic' ],

+                                             subjectClass="hosts",

+                                             subjectKey=urllib.quote( mac,

+                                                                      safe='' ),

+                                             configKey="basic" )

+        main.pingChart.update( { 'vlan1': { "expect": "True",

+                                            "hosts": [ "olt1", "vsg1" ] } } )

+        main.pingChart[ 'vlan5' ][ 'expect' ] = 0

+        main.pingChart[ 'vlan10' ][ 'expect' ] = 0

+        ports = "[%s,%s]" % (5, 6)

+        cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports

+        main.RESTs[ main.active ].setNetCfg( json.loads( cfg ),

+                                             subjectClass="apps",

+                                             subjectKey="org.onosproject.segmentrouting",

+                                             configKey="xconnect" )

+

+    @staticmethod

+    def delHostCfg( main ):

+        """

+        Removest Host Configuration from ONOS

+        Updates expected state of the network (pingChart)

+        """

+        import json

+        hostCfg = { }

+        with open( main.dependencyPath + "/json/extra.json" ) as template:

+            hostCfg = json.load( template )

+        main.step( "Removing host configuration" )

+        main.pingChart[ 'ip' ][ 'expect' ] = 0

+        mac, cfg = hostCfg[ 'hosts' ].popitem( )

+        main.RESTs[ main.active ].removeNetCfg( subjectClass="hosts",

+                                                subjectKey=urllib.quote(

+                                                        mac,

+                                                        safe='' ),

+                                                configKey="basic" )

+        main.step( "Removing configuration" )

+        main.pingChart[ 'ip' ][ 'expect' ] = 0

+        mac, cfg = hostCfg[ 'hosts' ].popitem( )

+        main.RESTs[ main.active ].removeNetCfg( subjectClass="hosts",

+                                                subjectKey=urllib.quote(

+                                                        mac,

+                                                        safe='' ),

+                                                configKey="basic" )

+        main.step( "Removing vlan configuration" )

+        main.pingChart[ 'vlan1' ][ 'expect' ] = 0

+        main.RESTs[ main.active ].removeNetCfg( subjectClass="apps",

+                                                subjectKey="org.onosproject.segmentrouting",

+                                                configKey="xconnect" )

diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/cord_fabric.py b/TestON/tests/USECASE/SegmentRouting/dependencies/cord_fabric.py
index 4f52689..6348632 100755
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/cord_fabric.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/cord_fabric.py
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 
 import os
+import re
 from optparse import OptionParser
 
 from mininet.net import Mininet
@@ -23,6 +24,8 @@
                        help='number of hosts per leaf switch, default=2' )
     parser.add_option( '--onos', dest='onos', type='int', default=0,
                        help='number of ONOS Instances, default=0, 0 means localhost, 1 will use OC1 and so on' )
+    parser.add_option( '--vlan', dest='vlan', type='int', default=-1,
+                       help='vid of cross connect, default=-1, -1 means utilize default value' )
     (options, args) = parser.parse_args( )
     return options, args
 
@@ -46,10 +49,6 @@
         for ls in range( leaf ):
             leafs[ ls ] = self.addSwitch( 'leaf%s' % (ls + 1),
                                           dpid="00000000000%s" % (1 + ls) )
-            # Connect leaf to all spines
-            for s in range( spine ):
-                switch = spines[ s ]
-                self.addLink( leafs[ ls ], switch, **linkopts )
             # Add hosts under a leaf, fanout hosts per leaf switch
             for f in range( fanout ):
                 host = self.addHost( 'h%s' % (ls * fanout + f + 1),
@@ -58,23 +57,34 @@
                                      gateway='10.0.%s.254' % (ls + 1) )
                 self.addLink( host, leafs[ ls ], **linkopts )
                 # Add Xconnect simulation
-        br1 = self.addSwitch( 'br1', cls=OVSBridge )
-        self.addLink( br1, leafs[ 0 ], **linkopts )
-        for vid in [ 5, 10 ]:
-            olt = self.addHost( 'olt%s' % vid, cls=VLANHost, vlan=vid,
-                                ip="10.%s.0.1/24" % vid
-                                , mac="00:00:%02d:00:00:01" % vid )
-            vsg = self.addHost( 'vsg%s' % vid, cls=VLANHost, vlan=vid,
-                                ip="10.%s.0.2/24" % vid
-                                , mac="00:00:%02d:00:00:02" % vid )
-            self.addLink( olt, leafs[ 0 ], **linkopts )
-            self.addLink( vsg, br1, **linkopts )
-
+            if ls is 0:
+                in1 = self.addHost( 'in1', cls=IpHost, ip='10.0.1.9/24', mac="00:00:00:00:00:09" )
+                self.addLink( in1, leafs[0], **linkopts )
+                out1 = self.addHost( 'out1', cls=IpHost, ip='10.0.9.1/24', mac="00:00:00:00:09:01" )
+                self.addLink( out1, leafs[0], **linkopts )
+                br1 = self.addSwitch( 'br1', cls=OVSBridge )
+                self.addLink( br1, leafs[ 0 ], **linkopts )
+                vlans = [ 1, 5, 10 ]
+                for vid in vlans:
+                    olt = self.addHost( 'olt%s' % vid, cls=VLANHost, vlan=vid,
+                                        ip="10.%s.0.1/24" % vid
+                                        , mac="00:00:%02d:00:00:01" % vid )
+                    vsg = self.addHost( 'vsg%s' % vid, cls=VLANHost, vlan=vid,
+                                        ip="10.%s.0.2/24" % vid
+                                        , mac="00:00:%02d:00:00:02" % vid )
+                    self.addLink( olt, leafs[ 0 ], **linkopts )
+                    self.addLink( vsg, br1, **linkopts )
+            # Connect leaf to all spines
+            for s in range( spine ):
+                switch = spines[ s ]
+                self.addLink( leafs[ ls ], switch, **linkopts )
 
 class IpHost( Host ):
-    def __init__( self, name, gateway, *args, **kwargs ):
+    def __init__( self, name, *args, **kwargs ):
         super( IpHost, self ).__init__( name, *args, **kwargs )
-        self.gateway = gateway
+        gateway = re.split('\.|/', kwargs['ip'])
+        gateway[3] = '254'
+        self.gateway = '.'.join(gateway[0:4])
 
     def config( self, **kwargs ):
         Host.config( self, **kwargs )
@@ -105,15 +115,43 @@
         # add VLAN interface to host's name to intf map
         self.nameToIntf[ newName ] = intf
 
+class ExtendedCLI( CLI ):
+    """
+    Extends mininet CLI with the following commands:
+    addvlanhost
+    addiphost
+    """
+    def do_addhost( self, line ):
+        #Parsing args from CLI
+        args = line.split( )
+        if len( args ) < 3 or len( args ) :
+            "usage: addhost hostname switch **params"
+        hostname, switch = args[0],  args[1]
+        params = eval(line.split( ' ', 3 )[2])
+        if 'cls' in params:
+            params['cls'] = eval( params[ 'cls' ] )
+        if hostname in self.mn:
+            #error( '%s already exists!\n' % hostname )
+            return
+        if switch not in self.mn:
+            #error( '%s does not exist!\n' % switch )
+            return
+        print params
+        host = self.mn.addHostCfg( hostname, **params )
+        #switch.attach( link.intf2 )
+        #host.config()
+        link = self.mn.addLink( host, switch )
+        host.config(**params)
 
 def config( opts ):
     spine = opts.spine
     leaf = opts.leaf
     fanout = opts.fanout
+    vlan = opts.vlan
     controllers = [ os.environ[ 'OC%s' % i ] for i in
                     range( 1, opts.onos + 1 ) ] if (opts.onos) else [
         '127.0.0.1' ]
-    topo = LeafAndSpine( spine=spine, leaf=leaf, fanout=fanout )
+    topo = LeafAndSpine( spine=spine, leaf=leaf, fanout=fanout, vlan=vlan )
     net = Mininet( topo=topo, link=TCLink, build=False,
                    switch=UserSwitch, controller=None, autoSetMacs=True )
     i = 0
@@ -122,7 +160,9 @@
         i += 1;
     net.build( )
     net.start( )
-    CLI( net )
+    out1 = net.get( 'out1' )
+    out1.cmd( "arp -s 10.0.9.254 10:00:00:00:00:01 -i %s " % (out1.intf()) )
+    CLI(net)
     net.stop( )
 
 
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/json/0x1.chart b/TestON/tests/USECASE/SegmentRouting/dependencies/json/0x1.chart
new file mode 100755
index 0000000..0714893
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/json/0x1.chart
@@ -0,0 +1,8 @@
+{

+  "ip": {"expect": "True",

+    "hosts":["h1", "h2"]},

+  "vlan5": {"expect":"True",

+    "hosts":["olt5", "vsg5"]},

+  "vlan10": {"expect":"True",

+    "hosts":["olt10", "vsg10"]}

+}
\ No newline at end of file
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/0x1.json b/TestON/tests/USECASE/SegmentRouting/dependencies/json/0x1.json
similarity index 62%
rename from TestON/tests/USECASE/SegmentRouting/dependencies/0x1.json
rename to TestON/tests/USECASE/SegmentRouting/dependencies/json/0x1.json
index 867785a..36955e1 100755
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/0x1.json
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/json/0x1.json
@@ -13,6 +13,20 @@
             "ips" : [ "10.0.1.254/24" ]
         }
         ]
+    },
+    "of:0000000000000001/3" : {
+      "interfaces" : [
+        {
+          "ips" : [ "10.0.1.254/24" ]
+        }
+      ]
+    },
+    "of:0000000000000001/4" : {
+      "interfaces" : [
+        {
+          "ips" : [ "10.0.1.254/24" ]
+        }
+      ]
     }
     },
     "devices" : {
@@ -44,21 +58,20 @@
     },
     "apps": {
         "org.onosproject.segmentrouting": {
-          "xconnect": {
-            "of:0000000000000001": [
-              {
-                "vlan": 5,
-                "ports": [3, 4],
-                "name": "OLT 1"
-              },
-              {
-                "vlan": 10,
-                "ports": [3, 5],
-                "name": "OLT 2"
-              }
-            ]
-          }
+            "xconnect": {
+                "of:0000000000000001": [
+                    {
+                        "vlan": 5,
+                        "ports": [5, 7],
+                        "name": "OLT 1"
+                    },
+                    {
+                        "vlan": 10,
+                        "ports": [5, 8],
+                        "name": "OLT 2"
+                    }
+                ]
+            }
         }
     }
-
 }
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/json/2x2.chart b/TestON/tests/USECASE/SegmentRouting/dependencies/json/2x2.chart
new file mode 100755
index 0000000..572f85a
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/json/2x2.chart
@@ -0,0 +1,8 @@
+{

+  "ip": {"expect": "True",

+    "hosts":["h1", "h2", "h3", "h4"]},

+  "vlan5": {"expect":"True",

+    "hosts":["olt5", "vsg5"]},

+  "vlan10": {"expect":"True",

+    "hosts":["olt10", "vsg10"]}

+}
\ No newline at end of file
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/2x2.json b/TestON/tests/USECASE/SegmentRouting/dependencies/json/2x2.json
similarity index 73%
rename from TestON/tests/USECASE/SegmentRouting/dependencies/2x2.json
rename to TestON/tests/USECASE/SegmentRouting/dependencies/json/2x2.json
index d4fa3fb..433b594 100755
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/2x2.json
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/json/2x2.json
@@ -1,5 +1,19 @@
 {
     "ports" : {
+    "of:0000000000000001/1" : {
+        "interfaces" : [
+        {
+            "ips" : [ "10.0.1.254/24" ]
+        }
+        ]
+    },
+    "of:0000000000000001/2" : {
+        "interfaces" : [
+        {
+            "ips" : [ "10.0.1.254/24" ]
+        }
+        ]
+    },
     "of:0000000000000001/3" : {
         "interfaces" : [
         {
@@ -14,14 +28,14 @@
         }
         ]
     },
-    "of:0000000000000002/3" : {
+    "of:0000000000000002/1" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.2.254/24" ]
         }
         ]
     },
-    "of:0000000000000002/4" : {
+    "of:0000000000000002/2" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.2.254/24" ]
@@ -79,44 +93,44 @@
         "00:00:00:00:00:01/-1" : {
             "basic": {
                 "ips": ["10.0.1.1"],
-                "location": "of:0000000000000001/3"
+                "location": "of:0000000000000001/1"
             }
         },
         "00:00:00:00:00:02/-1" : {
             "basic": {
                 "ips": ["10.0.1.2"],
-                "location": "of:0000000000000001/4"
+                "location": "of:0000000000000001/2"
             }
         },
         "00:00:00:00:00:03/-1" : {
             "basic": {
                 "ips": ["10.0.2.1"],
-                "location": "of:0000000000000002/3"
+                "location": "of:0000000000000002/1"
             }
         },
         "00:00:00:00:00:04/-1" : {
             "basic": {
                 "ips": ["10.0.2.2"],
-                "location": "of:0000000000000002/4"
+                "location": "of:0000000000000002/2"
             }
         }
     },
     "apps": {
         "org.onosproject.segmentrouting": {
-          "xconnect": {
-            "of:0000000000000001": [
-              {
-                "vlan": 5,
-                "ports": [5, 6],
-                "name": "OLT 1"
-              },
-              {
-                "vlan": 10,
-                "ports": [5, 7],
-                "name": "OLT 2"
-              }
-            ]
-          }
+            "xconnect": {
+                "of:0000000000000001": [
+                    {
+                        "vlan": 5,
+                        "ports": [5,7],
+                        "name": "OLT 1"
+                    },
+                    {
+                        "vlan": 10,
+                        "ports": [5,8],
+                        "name": "OLT 2"
+                    }
+                ]
+            }
         }
     }
 }
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/json/4x4.chart b/TestON/tests/USECASE/SegmentRouting/dependencies/json/4x4.chart
new file mode 100755
index 0000000..31fada0
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/json/4x4.chart
@@ -0,0 +1,8 @@
+{

+  "ip": {"expect": "True",

+    "hosts":["h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8"]},

+  "vlan5": {"expect":"True",

+    "hosts":["olt5", "vsg5"]},

+  "vlan10": {"expect":"True",

+    "hosts":["olt10", "vsg10"]}

+}
\ No newline at end of file
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/4x4.json b/TestON/tests/USECASE/SegmentRouting/dependencies/json/4x4.json
similarity index 78%
rename from TestON/tests/USECASE/SegmentRouting/dependencies/4x4.json
rename to TestON/tests/USECASE/SegmentRouting/dependencies/json/4x4.json
index 55f3225..8230261 100755
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/4x4.json
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/json/4x4.json
@@ -1,55 +1,69 @@
 {
     "ports" : {
-    "of:0000000000000001/5" : {
+    "of:0000000000000001/1" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.1.254/24" ]
         }
         ]
     },
-    "of:0000000000000001/6" : {
+    "of:0000000000000001/2" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.1.254/24" ]
         }
         ]
     },
-    "of:0000000000000002/5" : {
+    "of:0000000000000001/3" : {
+        "interfaces" : [
+            {
+                "ips" : [ "10.0.1.254/24" ]
+            }
+        ]
+    },
+    "of:0000000000000001/4" : {
+        "interfaces" : [
+            {
+                "ips" : [ "10.0.1.254/24" ]
+            }
+        ]
+    },
+    "of:0000000000000002/1" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.2.254/24" ]
         }
         ]
     },
-    "of:0000000000000002/6" : {
+    "of:0000000000000002/2" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.2.254/24" ]
         }
         ]
     },
-    "of:0000000000000003/5" : {
+    "of:0000000000000003/1" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.3.254/24" ]
         }
         ]
     },
-    "of:0000000000000003/6" : {
+    "of:0000000000000003/2" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.3.254/24" ]
         }
         ]
     },
-    "of:0000000000000004/5" : {
+    "of:0000000000000004/1" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.4.254/24" ]
         }
         ]
     },
-    "of:0000000000000004/6" : {
+    "of:0000000000000004/2" : {
         "interfaces" : [
         {
             "ips" : [ "10.0.4.254/24"]
@@ -151,68 +165,68 @@
         "00:00:00:00:00:01/-1" : {
             "basic": {
                 "ips": ["10.0.1.1"],
-                "location": "of:0000000000000001/5"
+                "location": "of:0000000000000001/1"
             }
         },
         "00:00:00:00:00:02/-1" : {
             "basic": {
                 "ips": ["10.0.1.2"],
-                "location": "of:0000000000000001/6"
+                "location": "of:0000000000000001/2"
             }
         },
         "00:00:00:00:00:03/-1" : {
             "basic": {
                 "ips": ["10.0.2.1"],
-                "location": "of:0000000000000002/5"
+                "location": "of:0000000000000002/1"
             }
         },
         "00:00:00:00:00:04/-1" : {
             "basic": {
                 "ips": ["10.0.2.2"],
-                "location": "of:0000000000000002/6"
+                "location": "of:0000000000000002/2"
             }
         },
         "00:00:00:00:00:05/-1" : {
             "basic": {
                 "ips": ["10.0.3.1"],
-                "location": "of:0000000000000003/5"
+                "location": "of:0000000000000003/1"
             }
         },
         "00:00:00:00:00:06/-1" : {
             "basic": {
                 "ips": ["10.0.3.2"],
-                "location": "of:0000000000000003/6"
+                "location": "of:0000000000000003/2"
             }
         },
         "00:00:00:00:00:07/-1" : {
             "basic": {
                 "ips": ["10.0.4.1"],
-                "location": "of:0000000000000004/5"
+                "location": "of:0000000000000004/1"
             }
         },
         "00:00:00:00:00:08/-1" : {
             "basic": {
                 "ips": ["10.0.4.2"],
-                "location": "of:0000000000000004/6"
+                "location": "of:0000000000000004/2"
             }
         }
     },
     "apps": {
         "org.onosproject.segmentrouting": {
-          "xconnect": {
-            "of:0000000000000001": [
-              {
-                "vlan": 5,
-                "ports": [7, 8],
-                "name": "OLT 1"
-              },
-              {
-                "vlan": 10,
-                "ports": [7, 9],
-                "name": "OLT 2"
-              }
-            ]
-          }
+            "xconnect": {
+                "of:0000000000000001": [
+                    {
+                        "vlan": 5,
+                        "ports": [5,7],
+                        "name": "OLT 1"
+                    },
+                    {
+                        "vlan": 10,
+                        "ports": [5,8],
+                        "name": "OLT 2"
+                    }
+                ]
+            }
         }
     }
 }
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/json/extra.json b/TestON/tests/USECASE/SegmentRouting/dependencies/json/extra.json
new file mode 100755
index 0000000..992a04c
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/json/extra.json
@@ -0,0 +1,16 @@
+{
+    "hosts" : {
+        "00:00:00:00:00:09/-1" : {
+            "basic": {
+                "ips": ["10.0.1.9"],
+                "location": "of:0000000000000001/3"
+            }
+        },
+        "00:00:00:00:09:01/-1" : {
+            "basic": {
+                "ips": ["10.0.9.1"],
+                "location": "of:0000000000000001/4"
+            }
+        }
+    }
+}