[ONOS-7904] Run CHO test with Segment Routing and H-AGG topology
Change-Id: I493d8762028dc61339e1a8d061e7ab331201917f
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index 8d474cb..27e1bf6 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -1211,7 +1211,8 @@
response = self.execute(
cmd=cmd,
prompt="mininet>",
- timeout=10 )
+ timeout=10,
+ logCmd=False )
except pexpect.EOF:
main.log.error( self.name + ": EOF exception found" )
main.log.error( self.name + ": " + self.handle.before )
@@ -1930,7 +1931,7 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def getSwitchRandom( self, timeout=60, nonCut=True ):
+ def getSwitchRandom( self, timeout=60, nonCut=True, switchClasses=None, excludeNodes=[] ):
"""
Randomly get a switch from Mininet topology.
If nonCut is True, it gets a list of non-cut switches (the deletion
@@ -1938,18 +1939,21 @@
components of a graph) and randomly returns one of them, otherwise
it just randomly returns one switch from all current switches in
Mininet.
+ excludeNodes will be pased to getGraphDict method
Returns the name of the chosen switch.
"""
import random
candidateSwitches = []
try:
if not nonCut:
- switches = self.getSwitches( timeout=timeout )
+ switches = self.getSwitches( timeout=timeout, switchClasses=switchClasses )
assert len( switches ) != 0
for switchName in switches.keys():
candidateSwitches.append( switchName )
else:
- graphDict = self.getGraphDict( timeout=timeout, useId=False )
+ graphDict = self.getGraphDict( timeout=timeout, useId=False,
+ switchClasses=switchClasses,
+ excludeNodes=excludeNodes )
if graphDict is None:
return None
self.graph.update( graphDict )
@@ -2066,7 +2070,7 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def getLinkRandom( self, timeout=60, nonCut=True ):
+ def getLinkRandom( self, timeout=60, nonCut=True, switchClasses=None, excludeNodes=[] ):
"""
Randomly get a link from Mininet topology.
If nonCut is True, it gets a list of non-cut links (the deletion
@@ -2074,13 +2078,14 @@
component of a graph) and randomly returns one of them, otherwise
it just randomly returns one link from all current links in
Mininet.
+ excludeNodes will be passed to getLinks method to exclude unexpected links.
Returns the link as a list, e.g. [ 's1', 's2' ]
"""
import random
candidateLinks = []
try:
if not nonCut:
- links = self.getLinks( timeout=timeout )
+ links = self.getLinks( timeout=timeout, excludeNodes=excludeNodes )
assert len( links ) != 0
for link in links:
# Exclude host-switch link
@@ -2088,7 +2093,9 @@
continue
candidateLinks.append( [ link[ 'node1' ], link[ 'node2' ] ] )
else:
- graphDict = self.getGraphDict( timeout=timeout, useId=False )
+ graphDict = self.getGraphDict( timeout=timeout, useId=False,
+ switchClasses=switchClasses,
+ excludeNodes=excludeNodes )
if graphDict is None:
return None
self.graph.update( graphDict )
@@ -2779,7 +2786,8 @@
response = self.execute(
cmd=command,
prompt="mininet>",
- timeout=10 )
+ timeout=10,
+ logCmd=False )
ports = []
if response:
for line in response.split( "\n" ):
@@ -2807,7 +2815,7 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def getSwitches( self, verbose=False, updateTimeout=1000 ):
+ def getSwitches( self, verbose=False, updateTimeout=1000, switchClasses=None ):
"""
Read switches from Mininet.
@@ -2824,8 +2832,9 @@
# <OVSSwitchNS s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None,s1-eth3:None pid=22550>
# <OVSBridge s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=26830>
# <UserSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=14737>
- try:
+ if not switchClasses:
switchClasses = r"(OVSSwitch)|(OVSBridge)|(OVSSwitchNS)|(IVSSwitch)|(LinuxBridge)|(UserSwitch)"
+ try:
swRE = r"<(?P<class>" + switchClasses + r")" +\
r"(?P<options>\{.*\})?\s" +\
r"(?P<name>[^:]+)\:\s" +\
@@ -2939,7 +2948,7 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def getLinks( self, timeout=20, updateTimeout=1000 ):
+ def getLinks( self, timeout=20, updateTimeout=1000, excludeNodes=[] ):
"""
Gathers information about current Mininet links. These links may not
be up if one of the ports is down.
@@ -2951,6 +2960,10 @@
'node2': str( node2 name )
'port1': str( port1 of_port )
'port2': str( port2 of_port ) }
+
+ If either node1 or node2 name starts with any of the strings sepcified
+ in excludeNodes, the link will be excluded from the returned value
+
Note: The port number returned is the eth#, not necessarily the of_port
number. In Mininet, for OVS switch, these should be the same. For
hosts, this is just the eth#.
@@ -2962,14 +2975,17 @@
# Examples:
# s1-eth3<->s2-eth1 (OK OK)
# s13-eth3<->h27-eth0 (OK OK)
- linkRE = "(?P<node1>[\w]+)\-eth(?P<port1>[\d]+)\<\-\>" +\
- "(?P<node2>[\w]+)\-eth(?P<port2>[\d]+)"
+ linkRE = "(?P<node1>[\w]+)\-eth(?P<port1>[\d\.]+)\<\-\>" +\
+ "(?P<node2>[\w]+)\-eth(?P<port2>[\d\.]+)"
links = []
for line in response:
match = re.search( linkRE, line )
if match:
node1 = match.group( 'node1' )
node2 = match.group( 'node2' )
+ if any( node1.startswith( node ) for node in excludeNodes ) or \
+ any( node2.startswith( node ) for node in excludeNodes ):
+ continue
port1 = match.group( 'port1' )
port2 = match.group( 'port2' )
links.append( { 'node1': node1,
@@ -3438,7 +3454,8 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def getGraphDict( self, timeout=60, useId=True, includeHost=False ):
+ def getGraphDict( self, timeout=60, useId=True, includeHost=False,
+ switchClasses=None, excludeNodes=[] ):
"""
Return a dictionary which describes the latest Mininet topology data as a
graph.
@@ -3457,6 +3474,9 @@
topology.
If includeHost == True, all hosts (and host-switch links) will be included
in topology data.
+ if switchClasses == None, default switchClasses will be used when calling
+ getSwitches method.
+ excludeNodes will be passed to getLinks method to exclude unexpected links.
Note that link or switch that are brought down by 'link x x down' or 'switch
x down' commands still show in the output of Mininet CLI commands such as
'links', 'dump', etc. Thus, to ensure the correctness of this function, it is
@@ -3465,10 +3485,9 @@
"""
graphDict = {}
try:
- links = self.getLinks( timeout=timeout )
+ links = self.getLinks( timeout=timeout, excludeNodes=excludeNodes )
portDict = {}
- if useId:
- switches = self.getSwitches()
+ switches = self.getSwitches( switchClasses=switchClasses )
if includeHost:
hosts = self.getHosts()
for link in links:
@@ -3477,6 +3496,9 @@
continue
nodeName1 = link[ 'node1' ]
nodeName2 = link[ 'node2' ]
+ if not self.getOVSPorts( nodeName1 ) or not self.getOVSPorts( nodeName2 ):
+ # The device is probably offline
+ continue
port1 = link[ 'port1' ]
port2 = link[ 'port2' ]
# Loop for two nodes
@@ -3516,11 +3538,29 @@
graphDict[ node1 ] = { 'edges': {} }
else:
# Assert node2 is not connected to any current links of node1
- assert node2 not in graphDict[ node1 ][ 'edges' ].keys()
- graphDict[ node1 ][ 'edges' ][ node2 ] = { 'port': portIndex }
+ # assert node2 not in graphDict[ node1 ][ 'edges' ].keys()
+ pass
+ for port in switches[ nodeName1 ][ 'ports' ]:
+ if port[ 'of_port' ] == str( portIndex ):
+ # Use -1 as index for disabled port
+ if port[ 'enabled' ] == True:
+ graphDict[ node1 ][ 'edges' ][ node2 ] = { 'port': portIndex }
+ else:
+ graphDict[ node1 ][ 'edges' ][ node2 ] = { 'port': -1 }
# Swap two nodes/ports
nodeName1, nodeName2 = nodeName2, nodeName1
port1, port2 = port2, port1
+ # Remove links with disabled ports
+ linksToRemove = []
+ for node, edges in graphDict.items():
+ for neighbor, port in edges[ 'edges' ].items():
+ if port[ 'port' ] == -1:
+ linksToRemove.append( ( node, neighbor ) )
+ for node1, node2 in linksToRemove:
+ for i in range( 2 ):
+ if graphDict.get( node1 )[ 'edges' ].get( node2 ):
+ graphDict[ node1 ][ 'edges' ].pop( node2 )
+ node1, node2 = node2, node1
return graphDict
except KeyError:
main.log.exception( self.name + ": KeyError exception found" )
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index 4bfd45a..f8e54fe 100755
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -5336,7 +5336,8 @@
'annotations': idToDevice[ nodeA ][ 'annotations' ]}
else:
# Assert nodeB is not connected to any current links of nodeA
- assert nodeB not in graphDict[ nodeA ][ 'edges' ].keys()
+ # assert nodeB not in graphDict[ nodeA ][ 'edges' ].keys()
+ pass
graphDict[ nodeA ][ 'edges' ][ nodeB ] = { 'port': link[ 'src' ][ 'port' ],
'type': link[ 'type' ],
'state': link[ 'state' ] }
diff --git a/TestON/drivers/common/clidriver.py b/TestON/drivers/common/clidriver.py
index 81b33b2..25986b3 100644
--- a/TestON/drivers/common/clidriver.py
+++ b/TestON/drivers/common/clidriver.py
@@ -156,6 +156,7 @@
prompt => represents expect command prompt or output,
timeout => timeout for command execution,
more => to provide a key press if it is on.
+ logCmd => log the command executed if True
It will return output of command exection.
"""
@@ -164,7 +165,8 @@
args = utilities.parse_args( [ "CMD",
"TIMEOUT",
"PROMPT",
- "MORE" ],
+ "MORE",
+ "LOGCMD" ],
**execparams )
expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
@@ -188,9 +190,10 @@
if index == 0:
self.LASTRSP = self.LASTRSP + \
self.handle.before + self.handle.after
- main.log.info( "Executed :" + str( cmd ) +
- " \t\t Expected Prompt '" + str( expectPrompt ) +
- "' Found" )
+ if not args[ "LOGCMD" ] is False:
+ main.log.info( "Executed :" + str( cmd ) +
+ " \t\t Expected Prompt '" + str( expectPrompt ) +
+ "' Found" )
elif index == 1:
self.LASTRSP = self.LASTRSP + self.handle.before
self.handle.send( args[ "MORE" ] )