Merge "[ONOS-7904] Run CHO test with Segment Routing and H-AGG topology"
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 1966a63..80e0246 100755
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -5337,7 +5337,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" ] )
diff --git a/TestON/tests/CHOTestMonkey/CHOTestMonkey.params b/TestON/tests/CHOTestMonkey/CHOTestMonkey.params
index ff85c56..80a0b0b 100644
--- a/TestON/tests/CHOTestMonkey/CHOTestMonkey.params
+++ b/TestON/tests/CHOTestMonkey/CHOTestMonkey.params
@@ -1,8 +1,9 @@
<PARAMS>
# 0. Initialize CHOTestMonkey
- # 1. Load topology and balances all switches
- # 2. Collect and store device and link data from ONOS
- # 3. Collect and store host data from ONOS
+ # 1. Set IPv6 configure
+ # 5. Load topology and balances all switches
+ # 6. Collect and store device and link data from ONOS
+ # 7. Collect and store host data from ONOS
# 10. Run all enabled checks
# 20. Bring down/up links and check topology and ping
# 21. Bring down/up a group of links and check topology and ping
@@ -20,35 +21,40 @@
# 90. Sleep for some time
# 100. Do nothing
# Sample sequence: 0,1,2,3,[10,30,21,31,10,32,21,33,50,10,30,21,31,10,32,21,33,51,40,60,10,30,21,31,10,32,21,33,50,10,30,21,31,10,32,21,33,51,41,60]*500,100
+
<testcases>
- 0,1,2,3,70
+ 0,1,5,6,7,70
</testcases>
+
<GIT>
<pull>False</pull>
<branch>master</branch>
</GIT>
+
<TEST>
<topo>1</topo>
<IPv6>on</IPv6>
+ <dataPlaneConnectivity>False</dataPlaneConnectivity>
<numCtrl>3</numCtrl>
<pauseTest>off</pauseTest>
<caseSleep>0</caseSleep>
- <setIPv6CfgSleep>5</setIPv6CfgSleep>
- <loadTopoSleep>5</loadTopoSleep>
- <ipv6Prefix>1000::</ipv6Prefix>
- <ipv4Prefix>10.1.</ipv4Prefix>
+ <ipv6Regex>1000::[0-9]+</ipv6Regex>
+ <ipv4Regex>10\.1\.[0-9]+\.[0-9]+</ipv4Regex>
<karafCliTimeout>7200000</karafCliTimeout>
<testDuration>86400</testDuration>
<package>on</package>
</TEST>
+
<GRAPH>
<nodeCluster>CHO</nodeCluster>
<builds>20</builds>
</GRAPH>
+
<ENV>
<cellName>choCell</cellName>
<cellApps>drivers,openflow,proxyarp,events</cellApps>
</ENV>
+
<EVENT>
<Event>
<status>on</status>
@@ -399,8 +405,14 @@
<topo4>
<fileName>topoRingIpv6.py</fileName>
</topo4>
+ <mininetArgs></mininetArgs>
+ <loadTopoSleep>5</loadTopoSleep>
</TOPO>
+ <CASE1>
+ <setIPv6CfgSleep>5</setIPv6CfgSleep>
+ </CASE1>
+
<CASE20>
<linkToggleNum>5</linkToggleNum>
<linkDownUpInterval>1</linkDownUpInterval>
@@ -426,11 +438,13 @@
<addPointIntentWeight>3</addPointIntentWeight>
<linkDownWeight>3</linkDownWeight>
<deviceDownWeight>2</deviceDownWeight>
+ <portDownWeight>0</portDownWeight>
+ <onosDownWeight>1</onosDownWeight>
<toggleFlowObj>0</toggleFlowObj>
</CASE70>
<CASE80>
- <filePath>/home/admin/log-for-replay</filePath>
+ <filePath>/home/sdn/log-for-replay</filePath>
<sleepTime>0.1</sleepTime>
<skipChecks>on</skipChecks>
</CASE80>
diff --git a/TestON/tests/CHOTestMonkey/CHOTestMonkey.params.trellis b/TestON/tests/CHOTestMonkey/CHOTestMonkey.params.trellis
new file mode 100644
index 0000000..fc839ec
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/CHOTestMonkey.params.trellis
@@ -0,0 +1,337 @@
+<PARAMS>
+ # 0. Initialize CHOTestMonkey
+ # 1. Set IPv6 configure
+ # 2. Load network configuration files
+ # 4. Copy topology libs and config files to Mininet
+ # 5. Load topology and balances all switches
+ # 6. Collect and store device and link data from ONOS
+ # 7. Collect and store host data from ONOS
+ # 70. Run randomly generated events
+ # 100. Do nothing
+
+ <testcases>
+ 0,2,4,5,6,7,70
+ </testcases>
+
+ <GIT>
+ <pull>False</pull>
+ <branch>master</branch>
+ </GIT>
+
+ <TEST>
+ <topo>10</topo>
+ <IPv6>on</IPv6>
+ <dataPlaneConnectivity>True</dataPlaneConnectivity>
+ <numCtrl>3</numCtrl>
+ <pauseTest>on</pauseTest>
+ <caseSleep>0</caseSleep>
+ <ipv6Regex>10[0-9]+::[0-9]+</ipv6Regex>
+ <ipv4Regex>10\.[0-9]+\.[0-9]+\.[0-9]+</ipv4Regex>
+ <karafCliTimeout>7200000</karafCliTimeout>
+ <testDuration>86400</testDuration>
+ <package>on</package>
+ </TEST>
+
+ <GRAPH>
+ <nodeCluster>CHO</nodeCluster>
+ <builds>20</builds>
+ </GRAPH>
+
+ <ENV>
+ <cellName>choTrellisCell</cellName>
+ <cellApps>drivers,openflow,segmentrouting,fpm,dhcprelay,netcfghostprovider,routeradvertisement,t3,hostprobingprovider</cellApps>
+ </ENV>
+
+ <EVENT>
+ <Event>
+ <status>on</status>
+ <typeIndex>0</typeIndex>
+ <typeString>NULL</typeString>
+ <CLI>null</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ <rerunInterval>5</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ </Event>
+
+ <TestPause>
+ <status>on</status>
+ <typeIndex>1</typeIndex>
+ <typeString>TEST_PAUSE</typeString>
+ <CLI>pause-test</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ </TestPause>
+
+ <TestResume>
+ <status>on</status>
+ <typeIndex>2</typeIndex>
+ <typeString>TEST_RESUME</typeString>
+ <CLI>resume-test</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ </TestResume>
+
+ <TestSleep>
+ <status>on</status>
+ <typeIndex>3</typeIndex>
+ <typeString>TEST_SLEEP</typeString>
+ <CLI>sleep</CLI>
+ <CLIParamNum>1</CLIParamNum>
+ </TestSleep>
+
+ <TestDebug>
+ <status>on</status>
+ <typeIndex>4</typeIndex>
+ <typeString>TEST_DEBUG</typeString>
+ <CLI>debug-test</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ </TestDebug>
+
+ <IntentCheck>
+ <status>off</status>
+ <typeIndex>10</typeIndex>
+ <typeString>CHECK_INTENT</typeString>
+ <CLI>check-intent</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ <rerunInterval>5</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ </IntentCheck>
+
+ <FlowCheck>
+ <status>off</status>
+ <typeIndex>11</typeIndex>
+ <typeString>CHECK_FLOW</typeString>
+ <CLI>check-flow</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ <rerunInterval>5</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ <coreFlowNum>3</coreFlowNum>
+ <coreFlowNum6>5</coreFlowNum6>
+ </FlowCheck>
+
+ <TrafficCheck>
+ <status>on</status>
+ <typeIndex>12</typeIndex>
+ <typeString>CHECK_TRAFFIC</typeString>
+ <CLI>check-traffic</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ <rerunInterval>10</rerunInterval>
+ <maxRerunNum>10</maxRerunNum>
+ <pingWait>1</pingWait>
+ <pingTimeout>10</pingTimeout>
+ </TrafficCheck>
+
+ <TopoCheck>
+ <status>on</status>
+ <typeIndex>13</typeIndex>
+ <typeString>CHECK_TOPO</typeString>
+ <CLI>check-topo</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ <rerunInterval>5</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ </TopoCheck>
+
+ <ONOSCheck>
+ <status>on</status>
+ <typeIndex>14</typeIndex>
+ <typeString>CHECK_ONOS</typeString>
+ <CLI>check-onos</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ <rerunInterval>10</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ </ONOSCheck>
+
+ <RaftLogSizeCheck>
+ <status>on</status>
+ <typeIndex>15</typeIndex>
+ <typeString>CHECK_RAFT_LOG_SIZE</typeString>
+ <CLI>check-raft-size</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ </RaftLogSizeCheck>
+
+ <LinkDown>
+ <status>on</status>
+ <typeIndex>20</typeIndex>
+ <typeString>NETWORK_LINK_DOWN</typeString>
+ <CLI>link-down</CLI>
+ <CLIParamNum>2</CLIParamNum>
+ </LinkDown>
+
+ <LinkUp>
+ <status>on</status>
+ <typeIndex>21</typeIndex>
+ <typeString>NETWORK_LINK_UP</typeString>
+ <CLI>link-up</CLI>
+ <CLIParamNum>2</CLIParamNum>
+ </LinkUp>
+
+ <DeviceDown>
+ <status>on</status>
+ <typeIndex>22</typeIndex>
+ <typeString>NETWORK_DEVICE_DOWN</typeString>
+ <CLI>device-down</CLI>
+ <CLIParamNum>1</CLIParamNum>
+ </DeviceDown>
+
+ <DeviceUp>
+ <status>on</status>
+ <typeIndex>23</typeIndex>
+ <typeString>NETWORK_DEVICE_UP</typeString>
+ <CLI>device-up</CLI>
+ <CLIParamNum>1</CLIParamNum>
+ </DeviceUp>
+
+ <PortDown>
+ <status>on</status>
+ <typeIndex>24</typeIndex>
+ <typeString>NETWORK_PORT_DOWN</typeString>
+ <CLI>port-down</CLI>
+ <CLIParamNum>2</CLIParamNum>
+ </PortDown>
+
+ <PortUp>
+ <status>on</status>
+ <typeIndex>25</typeIndex>
+ <typeString>NETWORK_PORT_UP</typeString>
+ <CLI>port-up</CLI>
+ <CLIParamNum>2</CLIParamNum>
+ </PortUp>
+
+ <ONOSDown>
+ <status>on</status>
+ <typeIndex>40</typeIndex>
+ <typeString>ONOS_ONOS_DOWN</typeString>
+ <CLI>onos-down</CLI>
+ <CLIParamNum>1</CLIParamNum>
+ <rerunInterval>5</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ </ONOSDown>
+
+ <ONOSUp>
+ <status>on</status>
+ <typeIndex>41</typeIndex>
+ <typeString>ONOS_ONOS_UP</typeString>
+ <CLI>onos-up</CLI>
+ <CLIParamNum>1</CLIParamNum>
+ <rerunInterval>5</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ </ONOSUp>
+
+ <SetCfg>
+ <status>on</status>
+ <typeIndex>42</typeIndex>
+ <typeString>ONOS_SET_CFG</typeString>
+ <CLI>set-cfg</CLI>
+ <CLIParamNum>3</CLIParamNum>
+ <rerunInterval>5</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ </SetCfg>
+
+ <BalanceMasters>
+ <status>on</status>
+ <typeIndex>44</typeIndex>
+ <typeString>ONOS_BALANCE_MASTERS</typeString>
+ <CLI>balance-masters</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ <rerunInterval>5</rerunInterval>
+ <maxRerunNum>5</maxRerunNum>
+ </BalanceMasters>
+
+ <addAllChecks>
+ <status>on</status>
+ <typeIndex>110</typeIndex>
+ <typeString>CHECK_ALL</typeString>
+ <CLI>check-all</CLI>
+ <CLIParamNum>0</CLIParamNum>
+ </addAllChecks>
+
+ <randomLinkToggle>
+ <status>on</status>
+ <typeIndex>120</typeIndex>
+ <typeString>NETWORK_LINK_RANDOM_TOGGLE</typeString>
+ <CLI>link-toggle-random</CLI>
+ <CLIParamNum>1</CLIParamNum>
+ <sleepBeforeCheck>10</sleepBeforeCheck>
+ </randomLinkToggle>
+
+ <randomLinkGroupToggle>
+ <status>on</status>
+ <typeIndex>121</typeIndex>
+ <typeString>NETWORK_LINK_GROUP_RANDOM_TOGGLE</typeString>
+ <CLI>link-group-toggle-random</CLI>
+ <CLIParamNum>3</CLIParamNum>
+ <sleepBeforeCheck>10</sleepBeforeCheck>
+ </randomLinkGroupToggle>
+
+ <randomDeviceToggle>
+ <status>on</status>
+ <typeIndex>122</typeIndex>
+ <typeString>NETWORK_DEVICE_RANDOM_TOGGLE</typeString>
+ <CLI>device-toggle-random</CLI>
+ <CLIParamNum>1</CLIParamNum>
+ <sleepBeforeCheck>10</sleepBeforeCheck>
+ </randomDeviceToggle>
+
+ <randomDeviceGroupToggle>
+ <status>on</status>
+ <typeIndex>123</typeIndex>
+ <typeString>NETWORK_DEVICE_GROUP_RANDOM_TOGGLE</typeString>
+ <CLI>device-group-toggle-random</CLI>
+ <CLIParamNum>3</CLIParamNum>
+ <sleepBeforeCheck>10</sleepBeforeCheck>
+ </randomDeviceGroupToggle>
+
+ <randomONOSToggle>
+ <status>on</status>
+ <typeIndex>140</typeIndex>
+ <typeString>ONOS_ONOS_RANDOM_TOGGLE</typeString>
+ <CLI>onos-toggle-random</CLI>
+ <CLIParamNum>1</CLIParamNum>
+ <sleepBeforeCheck>10</sleepBeforeCheck>
+ </randomONOSToggle>
+ </EVENT>
+
+ <SCHEDULER>
+ <pendingEventsCapacity>1</pendingEventsCapacity>
+ <runningEventsCapacity>10</runningEventsCapacity>
+ <scheduleLoopSleep>0.1</scheduleLoopSleep>
+ </SCHEDULER>
+
+ <GENERATOR>
+ <listenerPort>6000</listenerPort>
+ <insertEventRetryInterval>1</insertEventRetryInterval>
+ </GENERATOR>
+
+ <TOPO>
+ <topo10>
+ <fileName>hagg.py</fileName>
+ </topo10>
+ <mininetArgs>--dhcp=1 --routers=1 --ipv6=1 --ipv4=1</mininetArgs>
+ <loadTopoSleep>90</loadTopoSleep>
+ </TOPO>
+
+ <CASE2>
+ <fileName>hagg.json</fileName>
+ <hostFileName>hagg.host</hostFileName>
+ </CASE2>
+
+ <CASE4>
+ <lib>routinglib.py,trellislib.py,trellis_fabric.py</lib>
+ <conf>bgpdbgp1.conf,bgpdbgp2.conf,bgpdr1.conf,bgpdr2.conf,dhcpd6.conf,dhcpd.conf,zebradbgp1.conf,zebradbgp2.conf</conf>
+ </CASE4>
+
+ <CASE70>
+ <sleepSec>30</sleepSec>
+ <addHostIntentWeight>0</addHostIntentWeight>
+ <addPointIntentWeight>0</addPointIntentWeight>
+ <linkDownWeight>0</linkDownWeight>
+ <deviceDownWeight>2</deviceDownWeight>
+ <portDownWeight>3</portDownWeight>
+ <onosDownWeight>1</onosDownWeight>
+ <toggleFlowObj>0</toggleFlowObj>
+ </CASE70>
+
+ <CASE80>
+ <filePath>/home/sdn/log-for-replay</filePath>
+ <sleepTime>10</sleepTime>
+ <skipChecks>on</skipChecks>
+ </CASE80>
+</PARAMS>
diff --git a/TestON/tests/CHOTestMonkey/CHOTestMonkey.py b/TestON/tests/CHOTestMonkey/CHOTestMonkey.py
index 9791388..000dfe3 100644
--- a/TestON/tests/CHOTestMonkey/CHOTestMonkey.py
+++ b/TestON/tests/CHOTestMonkey/CHOTestMonkey.py
@@ -67,8 +67,7 @@
try:
onosPackage = main.params[ 'TEST' ][ 'package' ]
karafTimeout = main.params[ 'TEST' ][ 'karafCliTimeout' ]
- main.enableIPv6 = main.params[ 'TEST' ][ 'IPv6' ]
- main.enableIPv6 = True if main.enableIPv6 == "on" else False
+ main.enableIPv6 = main.params[ 'TEST' ][ 'IPv6' ].lower() == "on"
main.caseSleep = int( main.params[ 'TEST' ][ 'caseSleep' ] )
main.onosCell = main.params[ 'ENV' ][ 'cellName' ]
main.apps = main.params[ 'ENV' ][ 'cellApps' ]
@@ -82,7 +81,6 @@
for eventName in main.params[ 'EVENT' ].keys():
if main.params[ 'EVENT' ][ eventName ][ 'status' ] == 'on':
main.enabledEvents[ int( main.params[ 'EVENT' ][ eventName ][ 'typeIndex' ] ) ] = eventName
- print main.enabledEvents
main.graph = Graph()
main.eventScheduler = EventScheduler()
main.eventGenerator = EventGenerator()
@@ -102,30 +100,9 @@
cellName=main.onosCell )
for i in range( 1, main.Cluster.numCtrls + 1 ):
newController = Controller( i )
- newController.setCLI( main.Cluster.active( i - 1 ).CLI )
+ newController.setCLI( main.Cluster.runningNodes[ i - 1 ].CLI )
main.controllers.append( newController )
- main.step( "Set IPv6 cfg parameters for Neighbor Discovery" )
- setIPv6CfgSleep = int( main.params[ 'TEST' ][ 'setIPv6CfgSleep' ] )
- if main.enableIPv6:
- time.sleep( setIPv6CfgSleep )
- cfgResult1 = main.controllers[ 0 ].CLI.setCfg( "org.onosproject.net.neighbour.impl.NeighbourResolutionManager",
- "ndpEnabled",
- "true" )
- time.sleep( setIPv6CfgSleep )
- cfgResult2 = main.controllers[ 0 ].CLI.setCfg( "org.onosproject.provider.host.impl.HostLocationProvider",
- "requestIpv6ND",
- "true" )
- else:
- main.log.info( "Skipped setting IPv6 cfg parameters as it is disabled in params file" )
- cfgResult1 = main.TRUE
- cfgResult2 = main.TRUE
- cfgResult = cfgResult1 and cfgResult2
- utilities.assert_equals( expect=main.TRUE,
- actual=cfgResult,
- onpass="ipv6NeighborDiscovery cfg is set to true",
- onfail="Failed to cfg set ipv6NeighborDiscovery" )
-
main.step( "Start a thread for the scheduler" )
t = main.Thread( target=main.eventScheduler.startScheduler,
threadID=main.threadID,
@@ -150,7 +127,7 @@
with main.variableLock:
main.threadID = main.threadID + 1
- caseResult = setupResult and cfgResult
+ caseResult = setupResult
utilities.assert_equals( expect=main.TRUE,
actual=caseResult,
onpass="Set up test environment PASS",
@@ -158,28 +135,118 @@
def CASE1( self, main ):
"""
- Load Mininet topology and balances all switches
+ Set IPv6 cfg parameters for Neighbor Discovery
+ """
+ main.step( "Set IPv6 cfg parameters for Neighbor Discovery" )
+ setIPv6CfgSleep = int( main.params[ 'CASE1' ][ 'setIPv6CfgSleep' ] )
+ if main.enableIPv6:
+ time.sleep( setIPv6CfgSleep )
+ cfgResult1 = main.Cluster.active( 0 ).CLI.setCfg( "org.onosproject.net.neighbour.impl.NeighbourResolutionManager",
+ "ndpEnabled",
+ "true" )
+ time.sleep( setIPv6CfgSleep )
+ cfgResult2 = main.Cluster.active( 0 ).CLI.setCfg( "org.onosproject.provider.host.impl.HostLocationProvider",
+ "requestIpv6ND",
+ "true" )
+ else:
+ main.log.info( "Skipped setting IPv6 cfg parameters as it is disabled in params file" )
+ cfgResult1 = main.TRUE
+ cfgResult2 = main.TRUE
+ cfgResult = cfgResult1 and cfgResult2
+ utilities.assert_equals( expect=main.TRUE,
+ actual=cfgResult,
+ onpass="ipv6NeighborDiscovery cfg is set to true",
+ onfail="Failed to cfg set ipv6NeighborDiscovery" )
+
+ def CASE2( self, main ):
+ """
+ Load network configuration files
+ """
+ import json
+ main.case( "Load json files for configuring the network" )
+
+ main.step( "Load json files for configuring the network" )
+ cfgResult = main.TRUE
+ jsonFileName = main.params[ 'CASE2' ][ 'fileName' ]
+ jsonFile = main.testDir + "/dependencies/topologies/json/" + jsonFileName
+ with open( jsonFile ) as cfg:
+ main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
+
+ main.step( "Load host files" )
+ hostFileName = main.params[ 'CASE2' ][ 'hostFileName' ]
+ hostFile = main.testDir + "/dependencies/topologies/host/" + hostFileName
+ with open( hostFile ) as cfg:
+ main.expectedHosts = json.load( cfg )
+
+ utilities.assert_equals( expect=main.TRUE,
+ actual=cfgResult,
+ onpass="Correctly loaded network configurations",
+ onfail="Failed to load network configurations" )
+
+ def CASE4( self, main ):
+ """
+ Copy topology lib and config files to Mininet node
"""
import re
+ main.case( "Copy topology lib and config files to Mininet node" )
+
+ copyResult = main.TRUE
+ main.step( "Copy topology lib files to Mininet node" )
+ for libFileName in main.params[ 'CASE4' ][ 'lib' ].split(","):
+ libFile = main.testDir + "/dependencies/topologies/lib/" + libFileName
+ copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
+ libFile,
+ main.Mininet1.home + "/custom",
+ direction="to" )
+
+ main.step( "Copy topology config files to Mininet node" )
+ controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
+ index = 0
+ for confFileName in main.params[ 'CASE4' ][ 'conf' ].split(","):
+ confFile = main.testDir + "/dependencies/topologies/conf/" + confFileName
+ # Update zebra configurations with correct ONOS instance IP
+ if confFileName in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
+ ip = controllerIPs[ index ]
+ index = ( index + 1 ) % len( controllerIPs )
+ with open( confFile ) as f:
+ s = f.read()
+ s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
+ with open( confFile, "w" ) as f:
+ f.write( s )
+ copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
+ confFile,
+ "~/",
+ direction="to" )
+
+ utilities.assert_equals( expect=main.TRUE,
+ actual=copyResult,
+ onpass="Successfully copied topo lib/conf files",
+ onfail="Failed to copy topo lib/conf files" )
+
+ def CASE5( self, main ):
+ """
+ Load Mininet topology and balances all switches
+ """
import time
- import copy
-
- main.topoIndex = "topo" + str( main.params[ 'TEST' ][ 'topo' ] )
-
+ import re
main.log.report( "Load Mininet topology and Balance all Mininet switches across controllers" )
main.log.report( "________________________________________________________________________" )
main.case( "Assign and Balance all Mininet switches across controllers" )
+ main.step( "Copy Mininet topology files" )
+ main.topoIndex = "topo" + str( main.params[ 'TEST' ][ 'topo' ] )
+ topoFileName = main.params[ 'TOPO' ][ main.topoIndex ][ 'fileName' ]
+ topoFile = main.testDir + "/dependencies/topologies/" + topoFileName
+ copyResult = main.ONOSbench.scp( main.Mininet1, topoFile, main.Mininet1.home + "/custom", direction="to" )
+ utilities.assert_equals( expect=main.TRUE,
+ actual=copyResult,
+ onpass="Successfully copied topo files",
+ onfail="Failed to copy topo files" )
+
main.step( "Start Mininet topology" )
- newTopo = main.params[ 'TOPO' ][ main.topoIndex ][ 'fileName' ]
- mininetDir = main.Mininet1.home + "/custom/"
- topoPath = main.testDir + "/dependencies/topologies/" + newTopo
- main.ONOSbench.secureCopy( main.Mininet1.user_name, main.Mininet1.ip_address, topoPath, mininetDir, direction="to" )
- topoPath = mininetDir + newTopo
- startStatus = main.Mininet1.startNet( topoFile=topoPath )
- main.mininetSwitches = main.Mininet1.getSwitches()
- main.mininetHosts = main.Mininet1.getHosts()
- main.mininetLinks = main.Mininet1.getLinks( timeout=60 )
+ startStatus = main.Mininet1.startNet( topoFile=main.Mininet1.home + "/custom/" + topoFileName,
+ args=main.params[ 'TOPO' ][ 'mininetArgs' ] )
+ main.mininetSwitches = main.Mininet1.getSwitches( switchClasses=r"(OVSSwitch)" )
utilities.assert_equals( expect=main.TRUE,
actual=startStatus,
onpass="Start Mininet topology test PASS",
@@ -191,7 +258,7 @@
ips = main.Cluster.getIps()
main.Mininet1.assignSwController( sw=switchName, ip=ips )
response = main.Mininet1.getSwController( switchName )
- print( "Response is " + str( response ) )
+ main.log.debug( "Response is " + str( response ) )
if re.search( "tcp:" + main.Cluster.active( 0 ).ipAddress, response ):
switchMastership = switchMastership and main.TRUE
else:
@@ -201,13 +268,22 @@
onpass="Assign switches to controllers test PASS",
onfail="Assign switches to controllers test FAIL" )
# Waiting here to make sure topology converges across all nodes
- sleep = int( main.params[ 'TEST' ][ 'loadTopoSleep' ] )
+ sleep = int( main.params[ 'TOPO' ][ 'loadTopoSleep' ] )
time.sleep( sleep )
main.step( "Balance devices across controllers" )
balanceResult = main.Cluster.active( 0 ).CLI.balanceMasters()
# giving some breathing time for ONOS to complete re-balance
- time.sleep( sleep )
+ time.sleep( 5 )
+
+ # Get mininet hosts and links
+ main.mininetHosts = main.Mininet1.getHosts()
+ if hasattr( main, "expectedHosts" ):
+ main.mininetHosts = { key: value for key, value in main.mininetHosts.items() if key in main.expectedHosts[ "network" ].keys() }
+ main.mininetLinks = main.Mininet1.getLinks( timeout=60 )
+ main.mininetLinks = [ link for link in main.mininetLinks if
+ link[ 'node1' ] in main.mininetHosts.keys() + main.mininetSwitches.keys() and
+ link[ 'node2' ] in main.mininetHosts.keys() + main.mininetSwitches.keys() ]
caseResult = ( startStatus and switchMastership and balanceResult )
utilities.assert_equals( expect=main.TRUE,
@@ -215,7 +291,7 @@
onpass="Starting new Att topology test PASS",
onfail="Starting new Att topology test FAIL" )
- def CASE2( self, main ):
+ def CASE6( self, main ):
"""
Collect and store device and link data from ONOS
"""
@@ -225,6 +301,7 @@
main.log.report( "Collect and Store topology details from ONOS" )
main.log.report( "____________________________________________________________________" )
main.case( "Collect and Store Topology Details from ONOS" )
+
topoResult = main.TRUE
topologyOutput = main.Cluster.active( 0 ).CLI.topology()
topologyResult = main.Cluster.active( 0 ).CLI.getTopology( topologyOutput )
@@ -238,13 +315,13 @@
dpidToName = {}
for key, value in main.mininetSwitches.items():
dpidToName[ 'of:' + str( value[ 'dpid' ] ) ] = key
- devicesRaw = main.Cluster.active( 0 ).CLI.devices()
- devices = json.loads( devicesRaw )
+ main.devicesRaw = main.Cluster.active( 0 ).CLI.devices()
+ devices = json.loads( main.devicesRaw )
deviceInitIndex = 0
for device in devices:
name = dpidToName[ device[ 'id' ] ]
newDevice = Device( deviceInitIndex, name, device[ 'id' ] )
- print newDevice
+ main.log.info( 'New device: {}'.format( newDevice ) )
main.devices.append( newDevice )
deviceInitIndex += 1
utilities.assert_equals( expect=main.TRUE,
@@ -254,8 +331,8 @@
main.step( "Collect and store link data" )
stepResult = main.TRUE
- linksRaw = main.Cluster.active( 0 ).CLI.links()
- links = json.loads( linksRaw )
+ main.linksRaw = main.Cluster.active( 0 ).CLI.links()
+ links = json.loads( main.linksRaw )
linkInitIndex = 0
for link in links:
for device in main.devices:
@@ -265,7 +342,7 @@
deviceB = device
assert deviceA is not None and deviceB is not None
newLink = Link( linkInitIndex, deviceA, link[ 'src' ][ 'port' ], deviceB, link[ 'dst' ][ 'port' ] )
- print newLink
+ main.log.info( 'New link: {}'.format( newLink ) )
main.links.append( newLink )
linkInitIndex += 1
# Set backward links and outgoing links of devices
@@ -301,7 +378,7 @@
main.log.info( "Topology does not match, exiting test..." )
main.cleanAndExit()
- def CASE3( self, main ):
+ def CASE7( self, main ):
"""
Collect and store host data from ONOS
"""
@@ -310,28 +387,41 @@
main.log.report( "Collect and store host adta from ONOS" )
main.log.report( "______________________________________________" )
- main.case( "Use fwd app and pingall to discover all the hosts, then collect and store host data" )
+ main.case( "Use fwd app and pingall to discover all the hosts if necessary, then collect and store host data" )
- main.step( "Enable Reactive forwarding" )
- appResult = main.controllers[ 0 ].CLI.activateApp( "org.onosproject.fwd" )
- cfgResult1 = main.TRUE
- cfgResult2 = main.TRUE
- if main.enableIPv6:
- cfgResult1 = main.controllers[ 0 ].CLI.setCfg( "org.onosproject.fwd.ReactiveForwarding", "ipv6Forwarding", "true" )
- cfgResult2 = main.controllers[ 0 ].CLI.setCfg( "org.onosproject.fwd.ReactiveForwarding", "matchIpv6Address", "true" )
- stepResult = appResult and cfgResult1 and cfgResult2
- utilities.assert_equals( expect=main.TRUE,
- actual=stepResult,
- onpass="Successfully enabled reactive forwarding",
- onfail="Failed to enable reactive forwarding" )
+ if main.params[ 'TEST' ][ 'dataPlaneConnectivity' ] == 'False':
+ main.step( "Enable Reactive forwarding" )
+ appResult = main.Cluster.active( 0 ).CLI.activateApp( "org.onosproject.fwd" )
+ cfgResult1 = main.TRUE
+ cfgResult2 = main.TRUE
+ if main.enableIPv6:
+ cfgResult1 = main.Cluster.active( 0 ).CLI.setCfg( "org.onosproject.fwd.ReactiveForwarding", "ipv6Forwarding", "true" )
+ cfgResult2 = main.Cluster.active( 0 ).CLI.setCfg( "org.onosproject.fwd.ReactiveForwarding", "matchIpv6Address", "true" )
+ stepResult = appResult and cfgResult1 and cfgResult2
+ utilities.assert_equals( expect=main.TRUE,
+ actual=stepResult,
+ onpass="Successfully enabled reactive forwarding",
+ onfail="Failed to enable reactive forwarding" )
- main.step( "Discover hosts using pingall" )
+ main.step( "Discover hosts using pingall" )
+ main.Mininet1.pingall()
+ if main.enableIPv6:
+ ping6Result = main.Mininet1.pingall( protocol="IPv6" )
+
+ main.step( "Disable Reactive forwarding" )
+ appResult = main.Cluster.active( 0 ).CLI.deactivateApp( "org.onosproject.fwd" )
+ stepResult = appResult
+ utilities.assert_equals( expect=main.TRUE,
+ actual=stepResult,
+ onpass="Successfully deactivated fwd app",
+ onfail="Failed to deactivate fwd app" )
+
+ main.step( "Verify host discovery" )
stepResult = main.TRUE
- main.Mininet1.pingall()
- if main.enableIPv6:
- ping6Result = main.Mininet1.pingall( protocol="IPv6" )
- hosts = main.controllers[ 0 ].CLI.hosts()
- hosts = json.loads( hosts )
+ main.hostsRaw = main.Cluster.active( 0 ).CLI.hosts()
+ hosts = json.loads( main.hostsRaw )
+ if hasattr( main, "expectedHosts" ):
+ hosts = [ host for host in hosts if host[ 'id' ] in main.expectedHosts[ 'onos' ].keys() ]
if not len( hosts ) == len( main.mininetHosts ):
stepResult = main.FALSE
utilities.assert_equals( expect=main.TRUE,
@@ -342,14 +432,6 @@
main.log.debug( hosts )
main.cleanAndExit()
- main.step( "Disable Reactive forwarding" )
- appResult = main.controllers[ 0 ].CLI.deactivateApp( "org.onosproject.fwd" )
- stepResult = appResult
- utilities.assert_equals( expect=main.TRUE,
- actual=stepResult,
- onpass="Successfully deactivated fwd app",
- onfail="Failed to deactivate fwd app" )
-
main.step( "Collect and store host data" )
stepResult = main.TRUE
macToName = {}
@@ -361,33 +443,52 @@
hostInitIndex = 0
for host in hosts:
name = macToName[ host[ 'mac' ] ]
- dpid = host[ 'locations' ][ 0 ][ 'elementId' ]
- device = dpidToDevice[ dpid ]
+ devices = {}
+ for location in host[ 'locations' ]:
+ device = dpidToDevice[ location[ 'elementId' ] ]
+ devices[ device ] = location[ 'port' ]
newHost = Host( hostInitIndex,
name, host[ 'id' ], host[ 'mac' ],
- device, host[ 'locations' ][ 0 ][ 'port' ],
+ devices,
host[ 'vlan' ], host[ 'ipAddresses' ] )
- print newHost
+ main.log.info( 'New host: {}'.format( newHost ) )
main.hosts.append( newHost )
- main.devices[ device.index ].hosts.append( newHost )
hostInitIndex += 1
+ for location in host[ 'locations' ]:
+ device = dpidToDevice[ location[ 'elementId' ] ]
+ main.devices[ device.index ].hosts[ newHost ] = location[ 'port' ]
+
+ # Collect IPv4 and IPv6 hosts
+ main.ipv4Hosts = []
+ main.ipv6Hosts = []
+ for host in main.hosts:
+ if any( re.match( str( main.params[ 'TEST' ][ 'ipv6Regex' ] ), ipAddress ) for ipAddress in host.ipAddresses ):
+ main.ipv6Hosts.append( host )
+ if any( re.match( str( main.params[ 'TEST' ][ 'ipv4Regex' ] ), ipAddress ) for ipAddress in host.ipAddresses ):
+ main.ipv4Hosts.append( host )
utilities.assert_equals( expect=main.TRUE,
actual=stepResult,
onpass="Successfully collected and stored host data",
onfail="Failed to collect and store host data" )
main.step( "Create one host component for each host and then start host cli" )
+ startCLIResult = main.TRUE
for host in main.hosts:
main.Mininet1.createHostComponent( host.name )
hostHandle = getattr( main, host.name )
main.log.info( "Starting CLI on host " + str( host.name ) )
- startCLIResult = hostHandle.startHostCli()
+ startCLIResult = startCLIResult and hostHandle.startHostCli()
host.setHandle( hostHandle )
- stepResult = startCLIResult
- utilities.assert_equals( expect=main.TRUE,
- actual=startCLIResult,
- onpass="Host CLI started",
- onfail="Failed to start host CLI" )
+ if main.params[ 'TEST' ][ 'dataPlaneConnectivity' ] == 'True':
+ # Hosts should already be able to ping each other
+ if host in main.ipv4Hosts:
+ host.correspondents += main.ipv4Hosts
+ if host in main.ipv6Hosts:
+ host.correspondents += main.ipv6Hosts
+ utilities.assert_equals( expect=main.TRUE,
+ actual=startCLIResult,
+ onpass="Host CLI started",
+ onfail="Failed to start host CLI" )
def CASE10( self, main ):
"""
@@ -711,8 +812,10 @@
pointIntentNum = 0
downDeviceNum = 0
downLinkNum = 0
+ downPortNum = 0
+ downOnosNum = 0
flowObj = False
- upControllers = [ 1, 2, 3 ]
+ upControllers = range( 1, int( main.params[ 'TEST' ][ 'numCtrl' ] ) + 1 )
while True:
events = []
for i in range( int( main.params[ 'CASE70' ][ 'toggleFlowObj' ] ) ):
@@ -725,14 +828,23 @@
events.append( 'link-down' )
for i in range( int( main.params[ 'CASE70' ][ 'deviceDownWeight' ] ) ):
events.append( 'device-down' )
+ for i in range( int( main.params[ 'CASE70' ][ 'portDownWeight' ] ) ):
+ events.append( 'port-down' )
+ if downOnosNum == 0:
+ for i in range( int( main.params[ 'CASE70' ][ 'onosDownWeight' ] ) ):
+ events.append( 'onos-down' )
for i in range( int( pow( hostIntentNum, 1.5 ) / 100 ) ):
events.append( 'del-host-intent' )
for i in range( int( pow( pointIntentNum, 1.5 ) / 100 ) ):
events.append( 'del-point-intent' )
- for i in range( pow( 2, downLinkNum ) - 1 ):
+ for i in range( pow( 4, downLinkNum ) - 1 ):
events.append( 'link-up' )
- for i in range( pow( 5, downDeviceNum ) - 1 ):
+ for i in range( pow( 4, downDeviceNum ) - 1 ):
events.append( 'device-up' )
+ for i in range( pow( 4, downPortNum ) - 1 ):
+ events.append( 'port-up' )
+ for i in range( pow( 4, downOnosNum ) - 1 ):
+ events.append( 'onos-up' )
main.log.debug( events )
event = random.sample( events, 1 )[ 0 ]
if event == 'add-host-intent':
@@ -771,6 +883,19 @@
elif event == 'device-up':
main.eventGenerator.triggerEvent( EventType().NETWORK_DEVICE_UP, EventScheduleMethod().RUN_BLOCK, 'random' )
downDeviceNum -= 1
+ elif event == 'port-down':
+ main.eventGenerator.triggerEvent( EventType().NETWORK_PORT_DOWN, EventScheduleMethod().RUN_BLOCK, 'random', 'random' )
+ downPortNum += 1
+ elif event == 'port-up':
+ main.eventGenerator.triggerEvent( EventType().NETWORK_PORT_UP, EventScheduleMethod().RUN_BLOCK, 'random', 'random' )
+ downPortNum -= 1
+ elif event == 'onos-down':
+ main.eventGenerator.triggerEvent( EventType().ONOS_ONOS_DOWN, EventScheduleMethod().RUN_BLOCK, 1 )
+ downOnosNum += 1
+ elif event == 'onos-up':
+ main.eventGenerator.triggerEvent( EventType().ONOS_ONOS_UP, EventScheduleMethod().RUN_BLOCK, 1 )
+ downOnosNum -= 1
+ main.eventGenerator.triggerEvent( EventType().ONOS_BALANCE_MASTERS, EventScheduleMethod().RUN_BLOCK )
elif event == 'toggle-flowobj':
if not flowObj:
main.eventGenerator.triggerEvent( EventType().ONOS_SET_FLOWOBJ, EventScheduleMethod().RUN_BLOCK, 'true' )
@@ -828,7 +953,7 @@
main.eventGenerator.triggerEvent( eventIndex, EventScheduleMethod().RUN_BLOCK, *args )
time.sleep( float( main.params[ 'CASE80' ][ 'sleepTime' ] ) )
except Exception as e:
- print e
+ main.log.error( "Uncaught exception: {}".format( e ) )
utilities.assert_equals( expect=main.TRUE,
actual=main.caseResult,
onpass="Replay from log file passed",
diff --git a/TestON/tests/CHOTestMonkey/dependencies/EventScheduler.py b/TestON/tests/CHOTestMonkey/dependencies/EventScheduler.py
index 480fb9a..3685a70 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/EventScheduler.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/EventScheduler.py
@@ -60,7 +60,7 @@
param:
index: the position to insert into pendingEvents, default value -1 implies the tail of pendingEvents
"""
- if not typeIndex in main.enabledEvents.keys():
+ if typeIndex not in main.enabledEvents.keys():
main.log.warn( "Event Scheduler - event type %s not enabled" % ( typeIndex ) )
return
if main.enabledEvents[ typeIndex ] in main.params[ 'EVENT' ].keys():
@@ -84,7 +84,7 @@
else:
main.log.warn( "Event Scheduler - invalid index when isnerting event: %s" % ( index ) )
self.pendingEventsCondition.notify()
- #self.printEvents()
+ # self.printEvents()
def startScheduler( self ):
"""
@@ -133,7 +133,7 @@
with self.runningEventsCondition:
self.runningEvents.append( eventTuple )
- #self.printEvents()
+ # self.printEvents()
rerunNum = 0
result = eventTuple.startEvent()
while result == EventStates().FAIL and rerunNum < eventTuple.maxRerunNum:
@@ -145,9 +145,8 @@
main.log.error( eventTuple.typeString + " failed" )
main.caseResult = main.FALSE
if main.params[ 'TEST' ][ 'pauseTest' ] == 'on':
- #self.isRunning = False
- #main.log.error( "Event Scheduler - Test paused. To resume test, run \'resume-test\' command in CLI debugging mode" )
- main.stop()
+ self.isRunning = False
+ main.log.error( "Event Scheduler - Test paused. To resume test, run \'resume-test\' command in CLI debugging mode" )
with self.runningEventsCondition:
self.runningEvents.remove( eventTuple )
if len( self.runningEvents ) == 0:
@@ -156,7 +155,7 @@
if len( self.pendingEvents ) == 0:
with self.idleCondition:
self.idleCondition.notify()
- #self.printEvents()
+ # self.printEvents()
def printEvents( self ):
"""
@@ -198,5 +197,5 @@
self.pendingEventsCapacity = capacity
def setRunningState( self, state ):
- assert state or state == False
+ assert state or state is False
self.isRunning = state
diff --git a/TestON/tests/CHOTestMonkey/dependencies/cli.py b/TestON/tests/CHOTestMonkey/dependencies/cli.py
index 6e67107..8985242 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/cli.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/cli.py
@@ -114,7 +114,7 @@
if __name__ == '__main__':
import xml.etree.ElementTree
try:
- root = xml.etree.ElementTree.parse( '../CHOTestMonkey.params' ).getroot()
+ root = xml.etree.ElementTree.parse( '../CHOTestMonkey.params.trellis' ).getroot()
except Exception:
print "Uncaught exception!"
for child in root:
diff --git a/TestON/tests/CHOTestMonkey/dependencies/elements/NetworkElement.py b/TestON/tests/CHOTestMonkey/dependencies/elements/NetworkElement.py
index 50d6159..97cc92c 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/elements/NetworkElement.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/elements/NetworkElement.py
@@ -54,7 +54,8 @@
NetworkElement.__init__( self, index )
self.name = name
self.dpid = dpid
- self.hosts = []
+ self.hosts = {}
+ self.downPorts = []
# For each bidirectional link, we only store one direction here
self.outgoingLinks = []
@@ -64,24 +65,27 @@
class Host( NetworkElement ):
- def __init__( self, index, name, id, mac, device, devicePort, vlan, ipAddresses ):
+ def __init__( self, index, name, id, mac, devices, vlan, ipAddresses ):
NetworkElement.__init__( self, index )
self.name = name
self.id = id
self.mac = mac
- self.device = device
- self.devicePort = devicePort
+ self.devices = devices
self.vlan = vlan
self.ipAddresses = ipAddresses
self.correspondents = []
self.handle = None
+ self.isDualHomed = True if len( self.devices ) == 2 else False
def __str__( self ):
- return "name: " + self.name + ", mac: " + self.mac + ", device: " + self.device.dpid + ", ipAddresses: " + str( self.ipAddresses ) + ", status: " + self.status
+ return "name: " + self.name + ", mac: " + self.mac + ", devices: " + str( [ device.dpid for device in self.devices ] ) + ", ipAddresses: " + str( self.ipAddresses ) + ", status: " + self.status
def setHandle( self, handle ):
self.handle = handle
+ def setRemoved( self ):
+ if all( device.isRemoved() for device in self.devices ):
+ self.status = 'removed'
class Link( NetworkElement ):
diff --git a/TestON/tests/CHOTestMonkey/dependencies/elements/ONOSElement.py b/TestON/tests/CHOTestMonkey/dependencies/elements/ONOSElement.py
index 688324c..182ecf2 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/elements/ONOSElement.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/elements/ONOSElement.py
@@ -46,9 +46,13 @@
def bringDown( self ):
self.status = 'down'
+ main.Cluster.runningNodes[ self.index - 1 ].active = False
+ main.Cluster.reset()
def bringUp( self ):
self.status = 'up'
+ main.Cluster.runningNodes[ self.index - 1 ].active = True
+ main.Cluster.reset()
class Intent:
diff --git a/TestON/tests/CHOTestMonkey/dependencies/events/CheckEvent.py b/TestON/tests/CHOTestMonkey/dependencies/events/CheckEvent.py
index 7361c8f..ccb5831 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/events/CheckEvent.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/events/CheckEvent.py
@@ -147,20 +147,23 @@
upHostNum += 1
clusterNum = 1
with main.mininetLock:
- graphDictMininet = main.Mininet1.getGraphDict( useId=True )
+ graphDictMininet = main.Mininet1.getGraphDict( useId=True, switchClasses=r"(OVSSwitch)",
+ excludeNodes=[ 'bgp', 'cs', 'nat', 'dhcp', 'r' ] )
for controller in main.controllers:
if controller.isUp():
with controller.CLILock:
+ '''
topoState = controller.CLI.checkStatus( upDeviceNum, upLinkNum )
- # if not topoState:
- # main.log.warn( "Topo Check - link or device number discoverd by ONOS%s is incorrect" % ( controller.index ) )
- # checkResult = EventStates().FAIL
+ if not topoState:
+ main.log.warn( "Topo Check - link or device number discoverd by ONOS%s is incorrect" % ( controller.index ) )
+ checkResult = EventStates().FAIL
# Compare ONOS and Mininet topologies
graphDictONOS = controller.CLI.getGraphDict()
compareResult = main.graph.compareGraphs( graphDictONOS, graphDictMininet )
if not compareResult:
checkResult = EventStates().FAIL
main.log.warn( "Topo Check - ONOS and Mininet topologies do not match" )
+ '''
try:
# Check links
links = controller.CLI.links()
@@ -181,8 +184,10 @@
# Check hosts
hosts = controller.CLI.hosts()
hosts = json.loads( hosts )
+ if hasattr( main, "expectedHosts" ):
+ hosts = [ host for host in hosts if host[ 'id' ] in main.expectedHosts[ 'onos' ].keys() ]
if not len( hosts ) == upHostNum:
- checkResult = EventStates().FAIL
+ # checkResult = EventStates().FAIL
main.log.warn( "Topo Check - host number discoverd by ONOS%s is incorrect: %s expected and %s actual" % ( controller.index, upHostNum, len( hosts ) ) )
# Check clusters
clusters = controller.CLI.clusters()
@@ -288,6 +293,7 @@
for host in main.hosts:
if host.isUp():
upHosts.append( host )
+ import re
for host in upHosts:
dstIPv4List[ host.index ] = []
dstIPv6List[ host.index ] = []
@@ -295,10 +301,12 @@
if correspondent not in upHosts:
continue
for ipAddress in correspondent.ipAddresses:
- if ipAddress.startswith( str( main.params[ 'TEST' ][ 'ipv6Prefix' ] ) ):
+ if re.match( str( main.params[ 'TEST' ][ 'ipv6Regex' ] ), ipAddress ):
dstIPv6List[ host.index ].append( ipAddress )
- elif ipAddress.startswith( str( main.params[ 'TEST' ][ 'ipv4Prefix' ] ) ):
+ elif re.match( str( main.params[ 'TEST' ][ 'ipv4Regex' ] ), ipAddress ):
dstIPv4List[ host.index ].append( ipAddress )
+ if dstIPv4List[ host.index ]:
+ main.log.debug( "Check ping from host {} to {}".format( host.name, dstIPv4List[ host.index ] ) )
thread = main.Thread( target=host.handle.pingHostSetAlternative,
threadID=main.threadID,
name="pingHostSetAlternative",
@@ -317,6 +325,8 @@
return checkResult
# Check ipv6 ping
for host in upHosts:
+ if dstIPv6List[ host.index ]:
+ main.log.debug( "Check ping from host {} to {}".format( host.name, dstIPv6List[ host.index ] ) )
thread = main.Thread( target=host.handle.pingHostSetAlternative,
threadID=main.threadID,
name="pingHostSetAlternative",
diff --git a/TestON/tests/CHOTestMonkey/dependencies/events/NetworkEvent.py b/TestON/tests/CHOTestMonkey/dependencies/events/NetworkEvent.py
index 5632e12..935226c 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/events/NetworkEvent.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/events/NetworkEvent.py
@@ -51,7 +51,8 @@
if args[ 0 ] == 'random' or args[ 1 ] == 'random':
if self.typeIndex == EventType().NETWORK_LINK_DOWN:
with main.mininetLock:
- linkRandom = main.Mininet1.getLinkRandom()
+ linkRandom = main.Mininet1.getLinkRandom( switchClasses=r"(OVSSwitch)",
+ excludeNodes=[ 'bgp', 'cs', 'nat', 'dhcp', 'r' ] )
if linkRandom is None:
main.log.warn( "No link available, aborting event" )
return EventStates().ABORT
@@ -188,7 +189,8 @@
import random
if self.typeIndex == EventType().NETWORK_DEVICE_DOWN:
with main.mininetLock:
- switchRandom = main.Mininet1.getSwitchRandom()
+ switchRandom = main.Mininet1.getSwitchRandom( switchClasses=r"(OVSSwitch)",
+ excludeNodes=[ 'bgp', 'cs', 'nat', 'dhcp', 'r' ] )
if switchRandom is None:
main.log.warn( "No switch available, aborting event" )
return EventStates().ABORT
@@ -232,8 +234,15 @@
main.log.warn( "Device Down - device has been removed" )
return EventStates().ABORT
main.log.info( "Event recorded: {} {} {}".format( self.typeIndex, self.typeString, self.device.name ) )
+ result = main.TRUE
with main.mininetLock:
- result = main.Mininet1.delSwitch( self.device.name )
+ # Disable ports toward dual-homed hosts
+ for host, port in self.device.hosts.items():
+ if host.isDualHomed:
+ main.log.info( "Disable port {}/{} which connects to a dual-homed host before bringing down this device".format( self.device.dpid, port ) )
+ result = result and main.Cluster.active( 0 ).CLI.portstate( dpid=self.device.dpid, port=port, state="disable" )
+ # result = main.Mininet1.delSwitch( self.device.name )
+ result = result and main.Mininet1.switch( SW=self.device.name, OPTION="stop" )
if not result:
main.log.warn( "%s - failed to bring down device" % ( self.typeString ) )
return EventStates().FAIL
@@ -269,12 +278,14 @@
# Re-add the device
main.log.info( "Event recorded: {} {} {}".format( self.typeIndex, self.typeString, self.device.name ) )
with main.mininetLock:
- result = main.Mininet1.addSwitch( self.device.name, dpid=self.device.dpid[ 3: ] )
+ # result = main.Mininet1.addSwitch( self.device.name, dpid=self.device.dpid[ 3: ] )
+ result = main.Mininet1.switch( SW=self.device.name, OPTION='start' )
if not result:
main.log.warn( "%s - failed to re-add device" % ( self.typeString ) )
return EventStates().FAIL
with main.variableLock:
self.device.bringUp()
+ '''
# Re-add links
# We add host-device links first since we did the same in mininet topology file
# TODO: a more rubust way is to add links according to the port info of the device
@@ -303,35 +314,168 @@
if intent.deviceA == self.device and intent.deviceB.isUp() or\
intent.deviceB == self.device and intent.deviceA.isUp():
intent.setInstalled()
+ '''
# Re-assign mastership for the device
with main.mininetLock:
ips = main.Cluster.getIps()
main.Mininet1.assignSwController( sw=self.device.name, ip=ips )
- # Re-discover hosts
- for host in self.device.hosts:
- correspondent = None
- for h in main.hosts:
- if h.isUp() and h != host:
- correspondent = h
- break
- if correspondent is None:
- with main.mininetLock:
- main.Mininet1.pingall()
- if main.enableIPv6:
- main.Mininet1.pingall( protocol="IPv6" )
+ for link in self.device.outgoingLinks:
+ neighbor = link.deviceB
+ # Skip bringing up any link that connecting this device to a removed neighbor
+ if neighbor.isRemoved():
+ continue
+ # Bring down again any link that was brought down before the device was down
+ if int( link.portB ) in link.deviceB.downPorts:
+ with main.variableLock:
+ link.bringDown()
+ link.backwardLink.bringDown()
else:
- ipv4Addr = None
- ipv6Addr = None
- for ipAddress in correspondent.ipAddresses:
- if ipAddress.startswith( str( main.params[ 'TEST' ][ 'ipv6Prefix' ] ) ) and ipv6Addr is None:
- ipv6Addr = ipAddress
- elif ipAddress.startswith( str( main.params[ 'TEST' ][ 'ipv4Prefix' ] ) ) and ipv4Addr is None:
- ipv4Addr = ipAddress
- assert ipv4Addr is not None
- host.handle.pingHostSetAlternative( [ ipv4Addr ], 1 )
- if main.enableIPv6:
- assert ipv6Addr is not None
- host.handle.pingHostSetAlternative( [ ipv6Addr ], 1, True )
+ with main.variableLock:
+ link.bringUp()
+ link.backwardLink.bringUp()
+ # Re-discover hosts
+ if self.device.hosts:
+ main.Mininet1.discoverHosts( hostList=[ host.name for host in self.device.hosts ] )
+ for host in self.device.hosts:
with main.variableLock:
host.bringUp()
+ self.device.downPorts = []
+ return EventStates().PASS
+
+
+class PortEvent( Event ):
+
+ def __init__( self ):
+ Event.__init__( self )
+ self.device = None
+ self.port = None
+ self.link = None
+
+ def startPortEvent( self ):
+ return EventStates().PASS
+
+ def startEvent( self, args ):
+ """
+ args are the device name and port number, e.g. [ 's1', '5' ]
+ """
+ with self.eventLock:
+ # main.log.info( "%s - starting event" % ( self.typeString ) )
+ if len( args ) < 2:
+ main.log.warn( "%s - Not enough arguments: %s" % ( self.typeString, args ) )
+ return EventStates().ABORT
+ elif len( args ) > 2:
+ main.log.warn( "%s - Too many arguments: %s" % ( self.typeString, args ) )
+ return EventStates().ABORT
+ if args[ 0 ] == 'random' or args[ 1 ] == 'random':
+ if self.typeIndex == EventType().NETWORK_PORT_DOWN:
+ with main.mininetLock:
+ linkRandom = main.Mininet1.getLinkRandom( switchClasses=r"(OVSSwitch)",
+ excludeNodes=[ 'bgp', 'cs', 'nat', 'dhcp', 'r' ])
+ if linkRandom is None:
+ main.log.warn( "No link available, aborting event" )
+ return EventStates().ABORT
+ for link in main.links:
+ if link.deviceA.name == linkRandom[ 0 ] and link.deviceB.name == linkRandom[ 1 ]:
+ self.device = link.deviceA
+ self.port = int( link.portA )
+ if not self.device:
+ main.log.warn( "Failed to get a radnom device port, aborting event" )
+ return EventStates().ABORT
+ elif self.typeIndex == EventType().NETWORK_PORT_UP:
+ import random
+ with main.variableLock:
+ downPorts = {}
+ for link in main.links:
+ if link.isDown():
+ if int( link.portA ) in link.deviceA.downPorts:
+ downPorts[ link.deviceA ] = link.portA
+ if len( downPorts ) == 0:
+ main.log.warn( "None of the links are in 'down' state, aborting event" )
+ return EventStates().ABORT
+ deviceList = random.sample( downPorts, 1 )
+ self.device = deviceList[ 0 ]
+ self.port = int( downPorts[ self.device ] )
+ if self.device is None:
+ for device in main.devices:
+ if device.name == args[ 0 ]:
+ self.device = device
+ if self.device is None:
+ main.log.warn( "Device %s does not exist: " % ( args[ 0 ] ) )
+ return EventStates().ABORT
+ if self.port is None:
+ try:
+ self.port = int( args[ 1 ] )
+ except Exception:
+ main.log.warn( "Device port is not a number: {}".format( args[ 1 ] ) )
+ return EventStates().ABORT
+ if self.link is None:
+ for link in main.links:
+ if link.deviceA.name == self.device.name and int( link.portA ) == self.port:
+ self.link = link
+ if self.link is None:
+ main.log.warn( "There's no link on device {} port {}".format( self.device.name, self.port ) )
+ return EventStates().ABORT
+ main.log.debug( "%s - %s:%s" % ( self.typeString, self.device, self.port ) )
+ return self.startPortEvent()
+
+
+class PortDown( PortEvent ):
+
+ """
+ Generate a port down event giving the device name and port number
+ """
+ def __init__( self ):
+ PortEvent.__init__( self )
+ self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
+ self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
+
+ def startPortEvent( self ):
+ assert self.device is not None and self.port is not None and self.link is not None
+ if self.link.isDown():
+ main.log.warn( "port Down - link already down" )
+ return EventStates().ABORT
+ elif self.link.isRemoved():
+ main.log.warn( "port Down - link has been removed" )
+ return EventStates().ABORT
+ main.log.info( "Event recorded: {} {} {} {}".format( self.typeIndex, self.typeString, self.device.name, self.port ) )
+ with main.mininetLock:
+ result = main.Cluster.active( 0 ).CLI.portstate( dpid=self.device.dpid, port=self.port, state="disable" )
+ if not result:
+ main.log.warn( "%s - failed to bring down port" % ( self.typeString ) )
+ return EventStates().FAIL
+ with main.variableLock:
+ self.device.downPorts.append( self.port )
+ self.link.bringDown()
+ self.link.backwardLink.bringDown()
+ return EventStates().PASS
+
+
+class PortUp( PortEvent ):
+
+ """
+ Generate a port up event giving the device name and port number
+ """
+ def __init__( self ):
+ PortEvent.__init__( self )
+ self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
+ self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
+
+ def startPortEvent( self ):
+ assert self.device is not None and self.port is not None and self.link is not None
+ if self.link.isUp():
+ main.log.warn( "port up - link already up" )
+ return EventStates().ABORT
+ elif self.link.isRemoved():
+ main.log.warn( "port up - link has been removed" )
+ return EventStates().ABORT
+ main.log.info( "Event recorded: {} {} {} {}".format( self.typeIndex, self.typeString, self.device.name, self.port ) )
+ with main.mininetLock:
+ result = main.Cluster.active( 0 ).CLI.portstate( dpid=self.device.dpid, port=self.port, state="enable" )
+ if not result:
+ main.log.warn( "%s - failed to bring up port " % ( self.typeString ) )
+ return EventStates().FAIL
+ with main.variableLock:
+ self.device.downPorts.remove( self.port )
+ self.link.bringUp()
+ self.link.backwardLink.bringUp()
return EventStates().PASS
diff --git a/TestON/tests/CHOTestMonkey/dependencies/events/ONOSEvent.py b/TestON/tests/CHOTestMonkey/dependencies/events/ONOSEvent.py
index 1630066..0fa7f25 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/events/ONOSEvent.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/events/ONOSEvent.py
@@ -68,7 +68,7 @@
return EventStates().ABORT
main.log.info( "Event recorded: {} {} {}".format( self.typeIndex, self.typeString, self.ONOSIndex ) )
with main.ONOSbenchLock:
- result = main.ONOSbench.onosStop( main.controllers[ self.ONOSIndex - 1 ].ip )
+ result = main.ONOSbench.onosDie( main.controllers[ self.ONOSIndex - 1 ].ip )
if not result:
main.log.warn( "%s - failed to bring down ONOS" % ( self.typeString ) )
return EventStates().FAIL
diff --git a/TestON/tests/CHOTestMonkey/dependencies/events/TestEvent.py b/TestON/tests/CHOTestMonkey/dependencies/events/TestEvent.py
index 866c219..912487e 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/events/TestEvent.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/events/TestEvent.py
@@ -85,3 +85,16 @@
sleepTime = int( args[ 0 ] )
time.sleep( sleepTime )
return result
+
+
+class TestDebug( TestEvent ):
+
+ def __init__( self ):
+ TestEvent.__init__( self )
+ self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
+ self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
+
+ def startTestEvent( self, args=None ):
+ result = EventStates().PASS
+ main.stop()
+ return result
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdbgp1.conf b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdbgp1.conf
new file mode 100644
index 0000000..474bf02
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdbgp1.conf
@@ -0,0 +1,141 @@
+log file /var/log/quagga/bgpdbgp1.log
+hostname bgp1
+password quagga
+!
+! Different next hop for IPv4
+!
+ip prefix-list 1 seq 10 permit 10.0.2.0/24
+ip prefix-list 1 seq 20 permit 10.1.2.0/24
+ip prefix-list 1 seq 30 permit 10.0.3.0/24
+ip prefix-list 1 seq 40 permit 10.0.4.0/24
+
+ip prefix-list 1 seq 50 permit 10.1.0.0/24
+ip prefix-list 1 seq 70 permit 10.1.10.0/24
+ip prefix-list 1 seq 80 permit 10.2.0.0/24
+ip prefix-list 1 seq 90 permit 10.2.30.0/24
+ip prefix-list 1 seq 100 permit 10.2.20.0/24
+ip prefix-list 1 seq 110 permit 10.2.10.0/24
+ip prefix-list 1 seq 120 permit 10.2.40.0/24
+ip prefix-list 1 seq 130 permit 10.3.0.0/24
+ip prefix-list 1 seq 140 permit 10.3.30.0/24
+ip prefix-list 1 seq 150 permit 10.3.10.0/24
+ip prefix-list 1 seq 160 permit 10.3.20.0/24
+ip prefix-list 1 seq 170 permit 10.5.10.0/24
+ip prefix-list 1 seq 180 permit 10.5.20.0/24
+
+!
+route-map NEXTHOP41 permit 10
+match ip address prefix-list 1
+set ip next-hop 10.0.1.254
+!
+!
+route-map NEXTHOP47 permit 10
+match ip address prefix-list 1
+set ip next-hop 10.0.7.254
+!
+! Different next hop for IPv6
+!
+ipv6 prefix-list 2 seq 10 permit 2000::200/120
+ipv6 prefix-list 2 seq 20 permit 2000::300/120
+
+ipv6 prefix-list 2 seq 30 permit 1000::300/120
+ipv6 prefix-list 2 seq 40 permit 1001::300/120
+ipv6 prefix-list 2 seq 50 permit 1002::300/120
+ipv6 prefix-list 2 seq 60 permit 1003::300/120
+ipv6 prefix-list 2 seq 70 permit 1004::300/120
+ipv6 prefix-list 2 seq 80 permit 1005::300/120
+ipv6 prefix-list 2 seq 90 permit 1006::300/120
+ipv6 prefix-list 2 seq 100 permit 1007::300/120
+ipv6 prefix-list 2 seq 110 permit 1008::300/120
+ipv6 prefix-list 2 seq 120 permit 1009::300/120
+ipv6 prefix-list 2 seq 130 permit 1010::300/120
+ipv6 prefix-list 2 seq 140 permit 1011::300/120
+ipv6 prefix-list 2 seq 150 permit 1012::300/120
+!
+route-map NEXTHOP61 permit 10
+match ipv6 address prefix-list 2
+set ipv6 next-hop global 2000::1ff
+set ipv6 next-hop local 2000::1ff
+!
+!
+route-map NEXTHOP67 permit 10
+match ipv6 address prefix-list 2
+set ipv6 next-hop global 2000::7ff
+set ipv6 next-hop local 2000::7ff
+!
+! Basic router config
+!
+router bgp 65003
+bgp router-id 172.16.0.3
+timers bgp 3 9
+!
+! IPv4
+!
+neighbor 10.0.1.1 remote-as 65001
+neighbor 10.0.1.1 ebgp-multihop
+neighbor 10.0.1.1 timers connect 5
+neighbor 10.0.1.1 advertisement-interval 5
+neighbor 10.0.1.1 route-map NEXTHOP41 out
+!
+neighbor 2000::101 remote-as 65001
+neighbor 2000::101 timers connect 5
+neighbor 2000::101 advertisement-interval 1
+no neighbor 2000::101 activate
+!
+neighbor 10.0.7.1 remote-as 65002
+neighbor 10.0.7.1 ebgp-multihop
+neighbor 10.0.7.1 timers connect 5
+neighbor 10.0.7.1 advertisement-interval 5
+neighbor 10.0.7.1 route-map NEXTHOP47 out
+!
+neighbor 2000::701 remote-as 65002
+neighbor 2000::701 timers connect 5
+neighbor 2000::701 advertisement-interval 1
+no neighbor 2000::701 activate
+!
+
+network 10.1.0.0/24
+network 10.1.10.0/24
+network 10.2.0.0/24
+network 10.2.30.0/24
+network 10.2.20.0/24
+network 10.2.10.0/24
+network 10.2.40.0/24
+network 10.3.0.0/24
+network 10.3.30.0/24
+network 10.3.10.0/24
+network 10.3.20.0/24
+network 10.5.10.0/24
+network 10.5.20.0/24
+
+network 10.0.2.0/24
+network 10.1.2.0/24
+network 10.0.3.0/24
+network 10.0.4.0/24
+!
+! IPv6
+!
+address-family ipv6
+
+network 1000::300/120
+network 1001::300/120
+network 1002::300/120
+network 1003::300/120
+network 1004::300/120
+network 1005::300/120
+network 1006::300/120
+network 1007::300/120
+network 1008::300/120
+network 1009::300/120
+network 1010::300/120
+network 1011::300/120
+network 1012::300/120
+
+network 2000::200/120
+network 2000::300/120
+
+neighbor 2000::101 activate
+neighbor 2000::101 route-map NEXTHOP61 out
+neighbor 2000::701 activate
+neighbor 2000::701 route-map NEXTHOP67 out
+exit-address-family
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdbgp2.conf b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdbgp2.conf
new file mode 100644
index 0000000..421d5c2
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdbgp2.conf
@@ -0,0 +1,143 @@
+log file /var/log/quagga/bgpdbgp2.log
+hostname bgp2
+password quagga
+!
+! Different next hop for IPv4
+!
+ip prefix-list 1 seq 10 permit 10.0.2.0/24
+ip prefix-list 1 seq 20 permit 10.1.2.0/24
+ip prefix-list 1 seq 30 permit 10.0.3.0/24
+ip prefix-list 1 seq 40 permit 10.0.4.0/24
+
+ip prefix-list 1 seq 50 permit 10.1.0.0/24
+ip prefix-list 1 seq 60 permit 10.1.10.0/24
+ip prefix-list 1 seq 70 permit 10.2.0.0/24
+ip prefix-list 1 seq 80 permit 10.2.30.0/24
+ip prefix-list 1 seq 90 permit 10.2.20.0/24
+ip prefix-list 1 seq 100 permit 10.2.10.0/24
+ip prefix-list 1 seq 110 permit 10.2.40.0/24
+ip prefix-list 1 seq 120 permit 10.3.0.0/24
+ip prefix-list 1 seq 130 permit 10.3.30.0/24
+ip prefix-list 1 seq 140 permit 10.3.10.0/24
+ip prefix-list 1 seq 150 permit 10.3.20.0/24
+ip prefix-list 1 seq 160 permit 10.5.10.0/24
+ip prefix-list 1 seq 170 permit 10.5.20.0/24
+
+!
+route-map NEXTHOP45 permit 10
+match ip address prefix-list 1
+set ip next-hop 10.0.5.254
+!
+!
+route-map NEXTHOP46 permit 10
+match ip address prefix-list 1
+set ip next-hop 10.0.6.254
+!
+! Different next hop for IPv6
+!
+ipv6 prefix-list 2 seq 10 permit 2000::200/120
+ipv6 prefix-list 2 seq 20 permit 2000::300/120
+
+ipv6 prefix-list 2 seq 30 permit 1000::300/120
+ipv6 prefix-list 2 seq 40 permit 1001::300/120
+ipv6 prefix-list 2 seq 50 permit 1002::300/120
+ipv6 prefix-list 2 seq 60 permit 1003::300/120
+ipv6 prefix-list 2 seq 70 permit 1004::300/120
+ipv6 prefix-list 2 seq 80 permit 1005::300/120
+ipv6 prefix-list 2 seq 90 permit 1006::300/120
+ipv6 prefix-list 2 seq 100 permit 1007::300/120
+ipv6 prefix-list 2 seq 110 permit 1008::300/120
+ipv6 prefix-list 2 seq 120 permit 1009::300/120
+ipv6 prefix-list 2 seq 130 permit 1010::300/120
+ipv6 prefix-list 2 seq 140 permit 1011::300/120
+ipv6 prefix-list 2 seq 150 permit 1012::300/120
+!
+
+!
+route-map NEXTHOP65 permit 10
+match ipv6 address prefix-list 2
+set ipv6 next-hop global 2000::5ff
+set ipv6 next-hop local 2000::5ff
+!
+!
+route-map NEXTHOP66 permit 10
+match ipv6 address prefix-list 2
+set ipv6 next-hop global 2000::6ff
+set ipv6 next-hop local 2000::6ff
+!
+! Basic router config
+!
+router bgp 65003
+bgp router-id 172.16.0.4
+timers bgp 3 9
+!
+! IPv4
+!
+neighbor 10.0.5.1 remote-as 65001
+neighbor 10.0.5.1 ebgp-multihop
+neighbor 10.0.5.1 timers connect 5
+neighbor 10.0.5.1 advertisement-interval 5
+neighbor 10.0.5.1 route-map NEXTHOP45 out
+!
+neighbor 2000::501 remote-as 65001
+neighbor 2000::501 timers connect 5
+neighbor 2000::501 advertisement-interval 1
+no neighbor 2000::501 activate
+!
+neighbor 10.0.6.1 remote-as 65002
+neighbor 10.0.6.1 ebgp-multihop
+neighbor 10.0.6.1 timers connect 5
+neighbor 10.0.6.1 advertisement-interval 5
+neighbor 10.0.6.1 route-map NEXTHOP46 out
+!
+neighbor 2000::601 remote-as 65002
+neighbor 2000::601 timers connect 5
+neighbor 2000::601 advertisement-interval 1
+no neighbor 2000::601 activate
+!
+
+network 10.1.0.0/24
+network 10.1.10.0/24
+network 10.2.0.0/24
+network 10.2.30.0/24
+network 10.2.20.0/24
+network 10.2.10.0/24
+network 10.2.40.0/24
+network 10.3.0.0/24
+network 10.3.30.0/24
+network 10.3.10.0/24
+network 10.3.20.0/24
+network 10.5.10.0/24
+network 10.5.20.0/24
+
+network 10.1.0.0/24
+network 10.0.2.0/24
+network 10.1.2.0/24
+network 10.0.3.0/24
+network 10.0.4.0/24
+!
+! IPv6
+!
+address-family ipv6
+
+network 1000::300/120
+network 1001::300/120
+network 1002::300/120
+network 1003::300/120
+network 1004::300/120
+network 1005::300/120
+network 1006::300/120
+network 1007::300/120
+network 1008::300/120
+network 1009::300/120
+network 1010::300/120
+network 1011::300/120
+network 1012::300/120
+
+network 2000::200/120
+network 2000::300/120
+neighbor 2000::501 activate
+neighbor 2000::501 route-map NEXTHOP65 out
+neighbor 2000::601 activate
+neighbor 2000::601 route-map NEXTHOP66 out
+exit-address-family
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdr1.conf b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdr1.conf
new file mode 100644
index 0000000..9e526b8
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdr1.conf
@@ -0,0 +1,42 @@
+log file /var/log/quagga/bgpdr1.log
+hostname r1
+password quagga
+!
+! Basic router config
+!
+router bgp 65001
+bgp router-id 10.0.1.1
+timers bgp 3 9
+!
+! IPv4
+!
+neighbor 10.0.1.2 remote-as 65003
+neighbor 10.0.1.2 ebgp-multihop
+neighbor 10.0.1.2 timers connect 5
+neighbor 10.0.1.2 advertisement-interval 5
+!
+neighbor 2000::102 remote-as 65003
+neighbor 2000::102 timers connect 5
+neighbor 2000::102 advertisement-interval 1
+no neighbor 2000::102 activate
+!
+neighbor 10.0.5.2 remote-as 65003
+neighbor 10.0.5.2 ebgp-multihop
+neighbor 10.0.5.2 timers connect 5
+neighbor 10.0.5.2 advertisement-interval 5
+!
+neighbor 2000::502 remote-as 65003
+neighbor 2000::502 timers connect 5
+neighbor 2000::502 advertisement-interval 1
+no neighbor 2000::502 activate
+!
+network 10.0.99.0/24
+!
+! IPv6
+!
+address-family ipv6
+network 2000::7700/120
+network 2000::9900/120
+neighbor 2000::102 activate
+neighbor 2000::502 activate
+exit-address-family
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdr2.conf b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdr2.conf
new file mode 100644
index 0000000..49553e2
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/bgpdr2.conf
@@ -0,0 +1,42 @@
+log file /var/log/quagga/bgpdr2.log
+hostname r2
+password quagga
+!
+! Basic router config
+!
+router bgp 65002
+bgp router-id 10.0.6.1
+timers bgp 3 9
+!
+! IPv4
+!
+neighbor 10.0.6.2 remote-as 65003
+neighbor 10.0.6.2 ebgp-multihop
+neighbor 10.0.6.2 timers connect 5
+neighbor 10.0.6.2 advertisement-interval 5
+!
+neighbor 2000::602 remote-as 65003
+neighbor 2000::602 timers connect 5
+neighbor 2000::602 advertisement-interval 1
+no neighbor 2000::602 activate
+!
+neighbor 10.0.7.2 remote-as 65003
+neighbor 10.0.7.2 ebgp-multihop
+neighbor 10.0.7.2 timers connect 5
+neighbor 10.0.7.2 advertisement-interval 5
+!
+neighbor 2000::702 remote-as 65003
+neighbor 2000::702 timers connect 5
+neighbor 2000::702 advertisement-interval 1
+no neighbor 2000::702 activate
+!
+network 10.0.99.0/24
+!
+! IPv6
+!
+address-family ipv6
+network 2000::8800/120
+network 2000::9900/120
+neighbor 2000::602 activate
+neighbor 2000::702 activate
+exit-address-family
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/dhcpd.conf b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/dhcpd.conf
new file mode 100644
index 0000000..4208774
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/dhcpd.conf
@@ -0,0 +1,142 @@
+ddns-update-style none;
+
+default-lease-time 600;
+max-lease-time 7200;
+
+option domain-name-servers 8.8.8.8, 8.8.4.4;
+option domain-name "trellis.local";
+
+subnet 10.0.3.0 netmask 255.255.255.0 {
+ range 10.0.3.100 10.0.3.240;
+ option routers 10.0.3.254;
+}
+
+subnet 10.1.0.0 netmask 255.255.255.0 {
+ range 10.1.0.1 10.1.0.100;
+ option routers 10.1.0.254;
+}
+
+subnet 10.1.10.0 netmask 255.255.255.0 {
+ range 10.1.10.1 10.1.10.100;
+ option routers 10.1.10.254;
+}
+
+subnet 10.2.0.0 netmask 255.255.255.0 {
+ range 10.2.0.1 10.2.0.100;
+ option routers 10.2.0.254;
+}
+
+subnet 10.2.30.0 netmask 255.255.255.0 {
+ range 10.2.30.1 10.2.30.100;
+ option routers 10.2.30.254;
+}
+
+subnet 10.2.20.0 netmask 255.255.255.0 {
+ range 10.2.20.1 10.2.20.100;
+ option routers 10.2.20.254;
+}
+
+subnet 10.2.10.0 netmask 255.255.255.0 {
+ range 10.2.10.1 10.2.10.100;
+ option routers 10.2.10.254;
+}
+
+subnet 10.2.40.0 netmask 255.255.255.0 {
+ range 10.2.40.1 10.2.40.100;
+ option routers 10.2.40.254;
+}
+
+subnet 10.3.0.0 netmask 255.255.255.0 {
+ range 10.3.0.1 10.3.0.100;
+ option routers 10.3.0.254;
+}
+
+subnet 10.3.10.0 netmask 255.255.255.0 {
+ range 10.3.10.1 10.3.10.100;
+ option routers 10.3.10.254;
+}
+
+subnet 10.3.30.0 netmask 255.255.255.0 {
+ range 10.3.30.1 10.3.30.100;
+ option routers 10.3.30.254;
+}
+
+subnet 10.3.20.0 netmask 255.255.255.0 {
+ range 10.3.20.1 10.3.20.100;
+ option routers 10.3.20.254;
+}
+
+subnet 10.5.10.0 netmask 255.255.255.0 {
+ range 10.5.10.1 10.5.10.100;
+ option routers 10.5.10.254;
+}
+
+subnet 10.5.20.0 netmask 255.255.255.0 {
+ range 10.5.20.1 10.5.20.100;
+ option routers 10.5.20.254;
+}
+
+host h1v4 {
+ hardware ethernet 00:aa:00:00:00:01;
+ fixed-address 10.1.0.1;
+}
+
+host h2v4 {
+ hardware ethernet 00:aa:00:00:01:01;
+ fixed-address 10.1.10.1;
+}
+
+host h3v4 {
+ hardware ethernet 00:aa:00:00:00:02;
+ fixed-address 10.2.0.1;
+}
+
+host h4v4 {
+ hardware ethernet 00:aa:00:00:00:03;
+ fixed-address 10.2.30.1;
+}
+
+host h5v4 {
+ hardware ethernet 00:aa:00:00:00:04;
+ fixed-address 10.2.20.1;
+}
+
+host h6v4 {
+ hardware ethernet 00:aa:00:00:00:05;
+ fixed-address 10.2.10.1;
+}
+
+host h7v4 {
+ hardware ethernet 00:aa:00:00:01:05;
+ fixed-address 10.2.40.1;
+}
+
+host h8v4 {
+ hardware ethernet 00:aa:00:00:00:06;
+ fixed-address 10.3.0.1;
+}
+
+host h9v4 {
+ hardware ethernet 00:aa:00:00:00:07;
+ fixed-address 10.3.10.1;
+}
+
+host h10v4 {
+ hardware ethernet 00:aa:00:00:00:08;
+ fixed-address 10.3.30.1;
+}
+
+host h11v4 {
+ hardware ethernet 00:aa:00:00:00:0a;
+ fixed-address 10.3.20.1;
+}
+
+host h12v4 {
+ hardware ethernet 00:aa:00:00:02:01;
+ fixed-address 10.5.10.1;
+}
+
+host h13v4 {
+ hardware ethernet 00:aa:00:00:02:02;
+ fixed-address 10.5.20.1;
+}
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/dhcpd6.conf b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/dhcpd6.conf
new file mode 100644
index 0000000..6f7ec9e
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/dhcpd6.conf
@@ -0,0 +1,139 @@
+default-lease-time 600;
+max-lease-time 7200;
+
+option dhcp6.next-hop code 242 = ip6-address;
+
+subnet6 2000::300/120 {
+ range6 2000::360 2000::3fe;
+ option dhcp6.next-hop 2000::03ff;
+}
+
+subnet6 1000::300/120 {
+ range6 1000::360 1000::3fe;
+ option dhcp6.next-hop 1000::03ff;
+}
+
+subnet6 1001::300/120 {
+ range6 1001::360 1001::3fe;
+ option dhcp6.next-hop 1001::03ff;
+}
+
+subnet6 1002::300/120 {
+ range6 1002::360 1002::3fe;
+ option dhcp6.next-hop 1002::03ff;
+}
+
+subnet6 1003::300/120 {
+ range6 1003::360 1003::3fe;
+ option dhcp6.next-hop 1003::03ff;
+}
+
+subnet6 1004::300/120 {
+ range6 1004::360 1004::3fe;
+ option dhcp6.next-hop 1004::03ff;
+}
+
+subnet6 1005::300/120 {
+ range6 1005::360 1005::3fe;
+ option dhcp6.next-hop 1005::03ff;
+}
+
+subnet6 1006::300/120 {
+ range6 1006::360 1006::3fe;
+ option dhcp6.next-hop 1006::03ff;
+}
+
+subnet6 1007::300/120 {
+ range6 1007::360 1007::3fe;
+ option dhcp6.next-hop 1007::03ff;
+}
+
+subnet6 1008::300/120 {
+ range6 1008::360 1008::3fe;
+ option dhcp6.next-hop 1008::03ff;
+}
+
+subnet6 1009::300/120 {
+ range6 1009::360 1009::3fe;
+ option dhcp6.next-hop 1009::03ff;
+}
+
+subnet6 1010::300/120 {
+ range6 1010::360 1010::3fe;
+ option dhcp6.next-hop 1010::03ff;
+}
+
+subnet6 1011::300/120 {
+ range6 1011::360 1011::3fe;
+ option dhcp6.next-hop 1011::03ff;
+}
+
+subnet6 1012::300/120 {
+ range6 1012::360 1012::3fe;
+ option dhcp6.next-hop 1012::03ff;
+}
+
+host h1v6 {
+ hardware ethernet 00:bb:00:00:00:01;
+ fixed-address6 1000::3fe;
+}
+
+host h2v6 {
+ hardware ethernet 00:bb:00:00:01:01;
+ fixed-address6 1001::3fe;
+}
+
+host h3v6 {
+ hardware ethernet 00:bb:00:00:00:02;
+ fixed-address6 1002::3fe;
+}
+
+host h4v6 {
+ hardware ethernet 00:bb:00:00:00:03;
+ fixed-address6 1003::3fe;
+}
+
+host h5v6 {
+ hardware ethernet 00:bb:00:00:00:04;
+ fixed-address6 1004::3fe;
+}
+
+host h6v6 {
+ hardware ethernet 00:bb:00:00:00:05;
+ fixed-address6 1005::3fe;
+}
+
+host h7v6 {
+ hardware ethernet 00:bb:00:00:01:05;
+ fixed-address6 1006::3fe;
+}
+
+host h8v6 {
+ hardware ethernet 00:bb:00:00:00:06;
+ fixed-address6 1007::3fe;
+}
+
+host h9v6 {
+ hardware ethernet 00:bb:00:00:00:07;
+ fixed-address6 1008::3fe;
+}
+
+host h10v6 {
+ hardware ethernet 00:bb:00:00:00:08;
+ fixed-address6 1009::3fe;
+}
+
+host h11v6 {
+ hardware ethernet 00:bb:00:00:00:0a;
+ fixed-address6 1010::3fe;
+}
+
+host h12v6 {
+ hardware ethernet 00:bb:00:00:01:0a;
+ fixed-address6 1011::3fe;
+}
+
+host h13v6 {
+ hardware ethernet 00:bb:00:00:02:0a;
+ fixed-address6 1012::3fe;
+}
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/zebradbgp1.conf b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/zebradbgp1.conf
new file mode 100644
index 0000000..8c93f7d
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/zebradbgp1.conf
@@ -0,0 +1,9 @@
+log file /var/log/quagga/zebradbgp1.log
+hostname zebra-bgp1
+password quagga
+!
+! Default route via virtual management switch
+!
+ip route 0.0.0.0/0 172.16.0.1
+!
+fpm connection ip 10.192.19.68 port 2620
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/zebradbgp2.conf b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/zebradbgp2.conf
new file mode 100644
index 0000000..6205880
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/conf/zebradbgp2.conf
@@ -0,0 +1,9 @@
+log file /var/log/quagga/zebradbgp2.log
+hostname zebra-bgp2
+password quagga
+!
+! Default route via virtual management switch
+!
+ip route 0.0.0.0/0 172.16.0.1
+!
+fpm connection ip 10.192.19.67 port 2620
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/hagg.py b/TestON/tests/CHOTestMonkey/dependencies/topologies/hagg.py
new file mode 100644
index 0000000..4afc9d5
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/hagg.py
@@ -0,0 +1,425 @@
+#!/usr/bin/python
+import os
+import re
+from optparse import OptionParser
+from ipaddress import ip_network
+from mininet.node import RemoteController, OVSBridge, Host
+from mininet.link import TCLink
+from mininet.log import setLogLevel
+from mininet.net import Mininet
+from mininet.topo import Topo
+from mininet.nodelib import NAT
+from mininet.cli import CLI
+
+from routinglib import BgpRouter, RoutedHost
+from trellislib import DhcpServer, TaggedRoutedHost, DualHomedRoutedHost, DualHomedTaggedRoutedHost, DhcpClient, Dhcp6Client, DhcpServer, Dhcp6Server, TrellisHost
+
+# Parse command line options and dump results
+def parseOptions():
+ "Parse command line options"
+ parser = OptionParser()
+ parser.add_option( '--dhcp', dest='dhcp', type='int', default=0,
+ help='Configure hosts with dhcp or not' )
+ parser.add_option( '--routers', dest='routers', type='int', default=0,
+ help='Configure external routers or not in the topology' )
+ parser.add_option( '--ipv6', dest='ipv6', type='int', default=0,
+ help='Configure hosts with ipv6 or not' )
+ parser.add_option( '--ipv4', dest='ipv4', type='int', default=1,
+ help='Configure hosts with ipv4 or not' )
+ parser.add_option( '--onos-ip', dest='onosIp', type='str', default='',
+ help='IP address list of ONOS instances, separated by comma(,). Overrides --onos option' )
+
+ ( options, args ) = parser.parse_args()
+ return options, args
+
+opts, args = parseOptions()
+
+class ComcastLeafSpineFabric(Topo):
+
+ spines = dict()
+ leafs = dict()
+ hosts_dict = dict()
+
+ def createIpv4Hosts(self, dhcp):
+
+ h1 = self.addHost('h1v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:01', ips=['10.1.0.1/24'],
+ gateway='10.1.0.254', dhcpClient=dhcp)
+ self.addLink(h1, self.leafs[0])
+ self.hosts_dict['h1v4'] = h1
+
+ h2 = self.addHost('h2v4', cls=TrellisHost,
+ mac='00:aa:00:00:01:01', ips=['10.1.10.1/24'],
+ gateway='10.1.10.254', dhcpClient=dhcp)
+ self.addLink(h2, self.leafs[0])
+ self.hosts_dict['h2v4'] = h2
+
+ h3 = self.addHost('h3v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:02', ips=['10.2.0.1/24'],
+ gateway='10.2.0.254', dhcpClient=dhcp)
+ self.addLink(h3, self.leafs[1])
+ self.hosts_dict['h3v4'] = h3
+
+ h4 = self.addHost('h4v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:03', ips=['10.2.30.1/24'],
+ gateway='10.2.30.254', dhcpClient=dhcp,
+ dualHomed=True)
+ self.addLink(h4, self.leafs[1])
+ self.addLink(h4, self.leafs[2])
+ self.hosts_dict['h4v4'] = h4
+
+ h5 = self.addHost('h5v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:04', ips=['10.2.20.1/24'],
+ gateway='10.2.20.254', dhcpClient=dhcp, vlan=30,
+ dualHomed=True)
+ self.addLink(h5, self.leafs[1])
+ self.addLink(h5, self.leafs[2])
+ self.hosts_dict['h5v4'] = h5
+
+ h6 = self.addHost('h6v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:05', ips=['10.2.10.1/24'],
+ gateway='10.2.10.254', dhcpClient=dhcp, vlan=20)
+ self.addLink(h6, self.leafs[2])
+ self.hosts_dict['h6v4'] = h6
+
+ h7 = self.addHost('h7v4', cls=TrellisHost,
+ mac='00:aa:00:00:01:05', ips=['10.2.40.1/24'],
+ gateway='10.2.40.254', dhcpClient=dhcp, vlan=40)
+ self.addLink(h7, self.leafs[2])
+ self.hosts_dict['h7v4'] = h7
+
+ h8 = self.addHost('h8v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:06', ips=['10.3.0.1/24'],
+ gateway='10.3.0.254', dhcpClient=dhcp)
+ self.addLink(h8, self.leafs[3])
+ self.hosts_dict['h8v4'] = h8
+
+ h9 = self.addHost('h9v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:07', ips=['10.3.10.1/24'],
+ gateway='10.3.10.254', dhcpClient=dhcp, vlan=50,
+ dualHomed=True)
+ self.addLink(h9, self.leafs[3])
+ self.addLink(h9, self.leafs[4])
+ self.hosts_dict['h9v4'] = h9
+
+ h10 = self.addHost('h10v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:08', ips=['10.3.30.1/24'],
+ gateway='10.3.30.254', dhcpClient=dhcp, vlan=60,
+ dualHomed=True)
+ self.addLink(h10, self.leafs[3])
+ self.addLink(h10, self.leafs[4])
+ self.hosts_dict['h10v4'] = h10
+
+ h11 = self.addHost('h11v4', cls=TrellisHost,
+ mac='00:aa:00:00:00:0a', ips=['10.3.20.1/24'],
+ gateway='10.3.20.254', dhcpClient=dhcp, vlan=70)
+ self.addLink(h11, self.leafs[4])
+ self.hosts_dict['h11v4'] = h11
+
+ h12 = self.addHost('h12v4', cls=TrellisHost,
+ mac='00:aa:00:00:02:01', ips=['10.5.10.1/24'],
+ gateway='10.5.10.254', dhcpClient=dhcp, vlan=80)
+ self.addLink(h12, self.leafs[5])
+ self.hosts_dict['h12v4'] = h12
+
+ h13 = self.addHost('h13v4', cls=TrellisHost,
+ mac='00:aa:00:00:02:02', ips=['10.5.20.1/24'],
+ gateway='10.5.20.254', dhcpClient=dhcp)
+ self.addLink(h13, self.leafs[5])
+ self.hosts_dict['h13v4'] = h13
+ return
+
+ def createIpv6Hosts(self, dhcp):
+
+ h1 = self.addHost('h1v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:01', ips=["1000::3fe/120"],
+ gateway='1000::3ff', dhcpClient=dhcp, ipv6=1)
+ self.addLink(h1, self.leafs[0])
+ self.hosts_dict['h1v6'] = h1
+
+ h2 = self.addHost('h2v6', cls=TrellisHost,
+ mac='00:bb:00:00:01:01', ips=['1001::3fe/120'],
+ gateway='1001::3ff', dhcpClient=dhcp, ipv6=1)
+ self.addLink(h2, self.leafs[0])
+ self.hosts_dict['h2v6'] = h2
+
+ h3 = self.addHost('h3v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:02', ips=['1002::3fe/120'],
+ gateway='1002::3ff', dhcpClient=dhcp, ipv6=1)
+ self.addLink(h3, self.leafs[1])
+ self.hosts_dict['h3v6'] = h3
+
+ h4 = self.addHost('h4v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:03', ips=['1003::3fe/120'],
+ gateway='1003::3ff', dhcpClient=dhcp, ipv6=1,
+ dualHomed=True)
+ self.addLink(h4, self.leafs[1])
+ self.addLink(h4, self.leafs[2])
+ self.hosts_dict['h4v6'] = h4
+
+ h5 = self.addHost('h5v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:04', ips=['1004::3fe/120'],
+ gateway='1004::3ff', dhcpClient=False, ipv6=1,
+ vlan=121,
+ dualHomed=True)
+ self.addLink(h5, self.leafs[1])
+ self.addLink(h5, self.leafs[2])
+ self.hosts_dict['h5v6'] = h5
+
+ h6 = self.addHost('h6v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:05', ips=['1005::3fe/120'],
+ gateway='1005::3ff', dhcpClient=False, ipv6=1,
+ vlan=122)
+ self.addLink(h6, self.leafs[2])
+ self.hosts_dict['h6v6'] = h6
+
+ h7 = self.addHost('h7v6', cls=TrellisHost,
+ mac='00:bb:00:00:01:05', ips=['1006::3fe/120'],
+ gateway='1006::3ff', dhcpClient=False, ipv6=1,
+ vlan=123)
+ self.addLink(h7, self.leafs[2])
+ self.hosts_dict['h7v6'] = h7
+
+ h8 = self.addHost('h8v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:06', ips=['1007::3fe/120'],
+ gateway='1007::3ff', dhcpClient=dhcp, ipv6=1)
+ self.addLink(h8, self.leafs[3])
+ self.hosts_dict['h8v6'] = h8
+
+ h9 = self.addHost('h9v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:07', ips=['1008::3fe/120'],
+ gateway='1008::3ff', dhcpClient=False, vlan=124,
+ dualHomed=True, ipv6=1)
+ self.addLink(h9, self.leafs[3])
+ self.addLink(h9, self.leafs[4])
+ self.hosts_dict['h9v6'] = h9
+
+ h10 = self.addHost('h10v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:08', ips=['1009::3fe/120'],
+ gateway='1009::3ff', dhcpClient=False, vlan=125,
+ dualHomed=True, ipv6=1)
+ self.addLink(h10, self.leafs[3])
+ self.addLink(h10, self.leafs[4])
+ self.hosts_dict['h10v6'] = h10
+
+ h11 = self.addHost('h11v6', cls=TrellisHost,
+ mac='00:bb:00:00:00:0a', ips=['1010::3fe/120'],
+ gateway='1010::3ff', dhcpClient=False, vlan=126,
+ ipv6=1)
+ self.addLink(h11, self.leafs[4])
+ self.hosts_dict['h11v6'] = h11
+
+ h12 = self.addHost('h12v6', cls=TrellisHost,
+ mac='00:bb:00:00:01:0a', ips=['1011::3fe/120'],
+ gateway='1011::3ff', dhcpClient=False, vlan=127,
+ ipv6=1)
+ self.addLink(h12, self.leafs[5])
+ self.hosts_dict['h12v6'] = h12
+
+ h13 = self.addHost('h13v6', cls=TrellisHost,
+ mac='00:bb:00:00:02:0a', ips=['1012::3fe/120'],
+ gateway='1012::3ff', dhcpClient=dhcp, ipv6=1)
+ self.addLink(h13, self.leafs[5])
+ self.hosts_dict['h13v6'] = h13
+
+ return
+
+ '''
+ Creates the HAGG topology employed by Comcast.
+ '''
+ def __init__(self, dhcp=False, routers=False, ipv4=False, ipv6=False, **opts):
+ Topo.__init__(self, **opts)
+
+ linkopts = dict( bw=10 )
+
+ spine = 4
+ leaf = 6
+
+ # Create spine switches
+ for s in range(spine):
+ self.spines[s] = self.addSwitch('spine10%s' % (s + 1), dpid = "00000000010%s" % (s + 1) )
+
+ # Create leaf switches
+ for ls in range(leaf):
+ self.leafs[ls] = self.addSwitch('leaf%s' % (ls + 1), dpid = "00000000000%s" % ( ls + 1) )
+
+ # connecting leaf and spines, leafs 1-5 have double links
+ for s in range(2):
+ spine_switch = self.spines[s]
+
+ for ls in range(1, 5):
+ leaf_switch = self.leafs[ls]
+
+ self.addLink( spine_switch, leaf_switch, **linkopts )
+ self.addLink( spine_switch, leaf_switch, **linkopts )
+
+ # connect paired leafs
+ self.addLink(self.leafs[1], self.leafs[2], **linkopts)
+ self.addLink(self.leafs[3], self.leafs[4], **linkopts)
+
+ # build second fabric with single links
+ for s in range(2, 4):
+ spine_switch = self.spines[s]
+
+ for ls in [0, 5]:
+ leaf_switch = self.leafs[ls]
+ self.addLink( spine_switch, leaf_switch, **linkopts )
+
+ # connect spines together
+ self.addLink(self.spines[2], self.spines[0], **linkopts)
+ self.addLink(self.spines[3], self.spines[1], **linkopts)
+
+ # create hosts
+ if ipv6:
+ self.createIpv6Hosts(dhcp)
+
+ if ipv4:
+ self.createIpv4Hosts(dhcp)
+
+ if not ipv4 and not ipv6:
+ print("No hosts were created!")
+
+ # create quagga routers
+ # Note: Change "fpm connection ip" to $OC1 in zebradbgp1.conf and zebradbgp2.conf to make quagga work correctly
+ if routers:
+ last_ls = self.leafs[4]
+ last_paired_ls = self.leafs[3]
+
+ # Control plane switch (for quagga fpm)
+ cs0 = self.addSwitch('cs0', cls=OVSBridge)
+
+ # Control plane NAT (for quagga fpm)
+ nat = self.addHost('nat', cls=NAT,
+ ip='172.16.0.1/12',
+ subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
+ self.addLink(cs0, nat)
+
+ # Internal Quagga bgp1
+ intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'},
+ {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}],
+ 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/12']}}
+ bgp1 = self.addHost('bgp1', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdbgp1.conf',
+ zebraConfFile='./zebradbgp1.conf')
+ self.addLink(bgp1, last_paired_ls)
+ self.addLink(bgp1, cs0)
+
+ # Internal Quagga bgp2
+ intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
+ {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
+ 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
+ bgp2 = self.addHost('bgp2', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdbgp2.conf',
+ zebraConfFile='./zebradbgp2.conf')
+ self.addLink(bgp2, last_ls)
+ self.addLink(bgp2, cs0)
+
+ # External Quagga r1
+ intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
+ 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'},
+ 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']},
+ 'r1-eth3': {'ipAddrs': ['2000::9901/120']},
+ 'r1-eth4': {'ipAddrs': ['2000::7701/120']},
+ 'r1-eth5': {'ipAddrs': ['10.0.88.1/24']},
+ 'r1-eth6': {'ipAddrs': ['2000::8701/120']}}
+ r1 = self.addHost('r1', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdr1.conf')
+ self.addLink(r1, last_paired_ls)
+ self.addLink(r1, last_ls)
+
+ # External IPv4 Host behind r1
+ rh1v4 = self.addHost('rh1v4', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+ self.addLink(r1, rh1v4)
+
+ # External IPv6 Host behind r1
+ rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
+ self.addLink(r1, rh1v6)
+
+ # Another external IPv6 Host behind r1
+ rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701')
+ self.addLink(r1, rh11v6)
+
+ # Add an external ipv4 hosts that is not configured in the bgp conf
+ # files
+ rh5v4 = self.addHost('rh5v4', cls=RoutedHost, ips=['10.0.88.2/24'], gateway='10.0.88.1')
+ self.addLink(r1, rh5v4)
+
+ # Add an external ipv6 hosts that is not configured in the bgp conf
+ # files
+ rh5v6 = self.addHost('rh5v6', cls=RoutedHost, ips=['2000::8702/120'], gateway='2000::8701')
+ self.addLink(r1, rh5v6)
+
+ # External Quagga r2
+ intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'},
+ 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'},
+ 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']},
+ 'r2-eth3': {'ipAddrs': ['2000::9901/120']},
+ 'r2-eth4': {'ipAddrs': ['2000::8801/120']}}
+ r2 = self.addHost('r2', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdr2.conf')
+ self.addLink(r2, last_ls)
+ self.addLink(r2, last_paired_ls)
+
+ # External IPv4 Host behind r2
+ rh2v4 = self.addHost('rh2v4', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+ self.addLink(r2, rh2v4)
+
+ # External IPv6 Host behind r2
+ rh2v6 = self.addHost('rh2v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
+ self.addLink(r2, rh2v6)
+
+ # Another external IPv6 Host behind r1
+ rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801')
+ self.addLink(r2, rh22v6)
+
+ # create dhcp servers
+ if dhcp:
+ cs1 = self.addSwitch('cs1', cls=OVSBridge)
+ self.addLink(cs1, self.leafs[4])
+ if ipv4:
+ dhcp4 = self.addHost( 'dhcp', cls=TrellisHost,
+ mac="00:cc:00:00:00:01", ips=["10.0.3.253/24"],
+ gateway="10.0.3.254", dhcpServer=True)
+ self.addLink(dhcp4, cs1, **linkopts)
+ if ipv6:
+ dhcp6 = self.addHost( 'dhcp6', cls=TrellisHost,
+ mac="00:dd:00:00:00:01", ips=["2000::3fd/120"],
+ gateway="2000::3ff", dhcpServer=True, ipv6=True)
+ self.addLink(dhcp6, cs1, **linkopts)
+
+
+def config( opts ):
+
+ dhcp = bool(opts.dhcp)
+ routers = bool(opts.routers)
+ ipv6 = bool(opts.ipv6)
+ ipv4 = bool(opts.ipv4)
+
+ if opts.onosIp != '':
+ controllers = opts.onosIp.split( ',' )
+ else:
+ controllers = ['127.0.0.1']
+ topo = ComcastLeafSpineFabric(dhcp=dhcp, routers=routers, ipv6=ipv6,
+ ipv4=ipv4)
+
+ net = Mininet( topo=topo, link=TCLink, build=False,
+ controller=None, autoSetMacs=True )
+ i = 0
+ for ip in controllers:
+ net.addController( "c%s" % ( i ), controller=RemoteController, ip=ip )
+ i += 1
+
+ net.build()
+ net.start()
+ CLI( net )
+ net.stop()
+
+
+if __name__ == '__main__':
+ setLogLevel('info')
+ config(opts)
+ os.system('sudo mn -c')
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/host/hagg.host b/TestON/tests/CHOTestMonkey/dependencies/topologies/host/hagg.host
new file mode 100644
index 0000000..91a1f0f
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/host/hagg.host
@@ -0,0 +1,60 @@
+{
+ "onos":
+ {
+ "00:AA:00:00:00:01/None": "10.1.0.1",
+ "00:AA:00:00:01:01/None": "10.1.10.1",
+ "00:AA:00:00:00:02/None": "10.2.0.1",
+ "00:AA:00:00:00:03/None": "10.2.30.1",
+ "00:AA:00:00:00:04/30": "10.2.20.1",
+ "00:AA:00:00:00:05/20": "10.2.10.1",
+ "00:AA:00:00:01:05/40": "10.2.40.1",
+ "00:AA:00:00:00:06/None": "10.3.0.1",
+ "00:AA:00:00:00:07/50": "10.3.10.1",
+ "00:AA:00:00:00:08/60": "10.3.30.1",
+ "00:AA:00:00:00:0A/70": "10.3.20.1",
+ "00:AA:00:00:02:01/80": "10.5.10.1",
+ "00:AA:00:00:02:02/None": "10.5.20.1",
+ "00:BB:00:00:00:01/None": "1000::3fe",
+ "00:BB:00:00:01:01/None": "1001::3fe",
+ "00:BB:00:00:00:02/None": "1002::3fe",
+ "00:BB:00:00:00:03/None": "1003::3fe",
+ "00:BB:00:00:00:04/121": "1004::3fe",
+ "00:BB:00:00:00:05/122": "1005::3fe",
+ "00:BB:00:00:01:05/123": "1006::3fe",
+ "00:BB:00:00:00:06/None": "1007::3fe",
+ "00:BB:00:00:00:07/124": "1008::3fe",
+ "00:BB:00:00:00:08/125": "1009::3fe",
+ "00:BB:00:00:00:0A/126": "1010::3fe",
+ "00:BB:00:00:01:0A/127": "1011::3fe",
+ "00:BB:00:00:02:0A/None": "1012::3fe"
+ },
+ "network":
+ {
+ "h1v4": "10.1.0.1",
+ "h2v4": "10.1.10.1",
+ "h3v4": "10.2.0.1",
+ "h4v4": "10.2.30.1",
+ "h5v4": "10.2.20.1",
+ "h6v4": "10.2.10.1",
+ "h7v4": "10.2.40.1",
+ "h8v4": "10.3.0.1",
+ "h9v4": "10.3.10.1",
+ "h10v4": "10.3.30.1",
+ "h11v4": "10.3.20.1",
+ "h12v4": "10.5.10.1",
+ "h13v4": "10.5.20.1",
+ "h1v6": "1000::3fe",
+ "h2v6": "1001::3fe",
+ "h3v6": "1002::3fe",
+ "h4v6": "1003::3fe",
+ "h5v6": "1004::3fe",
+ "h6v6": "1005::3fe",
+ "h7v6": "1006::3fe",
+ "h8v6": "1007::3fe",
+ "h9v6": "1008::3fe",
+ "h10v6": "1009::3fe",
+ "h11v6": "1010::3fe",
+ "h12v6": "1011::3fe",
+ "h13v6": "1012::3fe"
+ }
+}
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/json/hagg.json b/TestON/tests/CHOTestMonkey/dependencies/topologies/json/hagg.json
new file mode 100644
index 0000000..b1b9965
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/json/hagg.json
@@ -0,0 +1,611 @@
+{
+ "ports" : {
+ "of:0000000000000006/3" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1011::3ff/120" ],
+ "vlan-tagged": [127]
+ }
+ ]
+ },
+ "of:0000000000000006/4" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1012::3ff/120" ],
+ "vlan-untagged": 26
+ }
+ ]
+ },
+ "of:0000000000000006/5" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.5.10.254/24" ],
+ "vlan-tagged": [80]
+ }
+ ]
+ },
+ "of:0000000000000006/6" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.5.20.254/24" ],
+ "vlan-untagged": 35
+ }
+ ]
+ },
+ "of:0000000000000002/5" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1003::3ff/120" , "1004::3ff/120", "10.2.30.254/24", "10.2.20.254/24"],
+ "vlan-tagged": [ 121 , 30 ]
+ }
+ ]
+ },
+ "of:0000000000000003/5" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1003::3ff/120" , "1004::3ff/120", "10.2.30.254/24", "10.2.20.254/24"],
+ "vlan-tagged": [ 121, 30 ]
+ }
+ ]
+ },
+ "of:0000000000000004/5" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1008::3ff/120", "1009::3ff/120", "10.3.10.254/24", "10.3.30.254/24" ],
+ "vlan-tagged": [ 124, 125, 50, 60 ]
+ }
+ ]
+ },
+ "of:0000000000000005/5" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1008::3ff/120", "1009::3ff/120", "10.3.10.254/24", "10.3.30.254/24" ],
+ "vlan-tagged": [ 124, 125, 50, 60 ]
+ }
+ ]
+ },
+ "of:0000000000000001/3" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1000::3ff/120" ],
+ "vlan-untagged": 21
+ }
+ ]
+ },
+ "of:0000000000000001/4" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1001::3ff/120" ],
+ "vlan-untagged": 22
+ }
+ ]
+ },
+ "of:0000000000000001/5" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.1.0.254/24" ],
+ "vlan-untagged": 10
+ }
+ ]
+ },
+ "of:0000000000000001/6" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.1.10.254/24" ],
+ "vlan-untagged": 11
+ }
+ ]
+ },
+ "of:0000000000000002/6" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1002::3ff/120" ],
+ "vlan-untagged": 23
+ }
+ ]
+ },
+ "of:0000000000000002/7" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1003::3ff/120" ],
+ "vlan-untagged": 24
+ }
+ ]
+ },
+ "of:0000000000000002/8" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1004::3ff/120" ],
+ "vlan-tagged": [121]
+ }
+ ]
+ },
+ "of:0000000000000002/9" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.2.0.254/24" ],
+ "vlan-untagged": 12
+ }
+ ]
+ },
+ "of:0000000000000002/10" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.2.30.254/24" ],
+ "vlan-untagged": 16
+ }
+ ]
+ },
+ "of:0000000000000002/11" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.2.20.254/24" ],
+ "vlan-tagged": [30]
+ }
+ ]
+ },
+ "of:0000000000000003/6" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1003::3ff/120" ],
+ "vlan-untagged": 24
+ }
+ ]
+ },
+ "of:0000000000000003/7" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1004::3ff/120" ],
+ "vlan-tagged": [121]
+ }
+ ]
+ },
+ "of:0000000000000003/8" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1005::3ff/120" ],
+ "vlan-tagged": [122]
+ }
+ ]
+ },
+ "of:0000000000000003/9" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1006::3ff/120" ],
+ "vlan-tagged": [123]
+ }
+ ]
+ },
+ "of:0000000000000003/10" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.2.30.254/24" ],
+ "vlan-untagged": 16
+ }
+ ]
+ },
+ "of:0000000000000003/11" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.2.20.254/24" ],
+ "vlan-tagged": [30]
+ }
+ ]
+ },
+ "of:0000000000000003/12" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.2.10.254/24" ],
+ "vlan-tagged": [20]
+ }
+ ]
+ },
+ "of:0000000000000003/13" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.2.40.254/24" ],
+ "vlan-tagged": [40]
+ }
+ ]
+ },
+ "of:0000000000000004/6" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1007::3ff/120" ],
+ "vlan-untagged": 25
+ }
+ ]
+ },
+ "of:0000000000000004/7" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1008::3ff/120" ],
+ "vlan-tagged": [124]
+ }
+ ]
+ },
+ "of:0000000000000004/8" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1009::3ff/120" ],
+ "vlan-tagged": [125]
+ }
+ ]
+ },
+ "of:0000000000000004/9" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.3.0.254/24" ],
+ "vlan-untagged": 25
+ }
+ ]
+ },
+ "of:0000000000000004/10" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.3.10.254/24" ],
+ "vlan-tagged": [50]
+ }
+ ]
+ },
+ "of:0000000000000004/11" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.3.30.254/24" ],
+ "vlan-tagged": [60]
+ }
+ ]
+ },
+ "of:0000000000000004/12" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.0.1.254/24", "10.0.7.254/24", "2000::1ff/120", "2000::7ff/120" ],
+ "vlan-tagged": [110, 170]
+
+ }
+ ]
+ },
+ "of:0000000000000004/13" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.0.1.254/24", "2000::1ff/120"],
+ "vlan-untagged": 110
+
+ }
+ ]
+ },
+ "of:0000000000000004/14" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.0.7.254/24", "2000::7ff/120" ],
+ "vlan-untagged": 170
+
+ }
+ ]
+ },
+ "of:0000000000000005/6" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1008::3ff/120" ],
+ "vlan-tagged": [124]
+ }
+ ]
+ },
+ "of:0000000000000005/7" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1009::3ff/120" ],
+ "vlan-tagged": [125]
+ }
+ ]
+ },
+ "of:0000000000000005/8" : {
+ "interfaces" : [
+ {
+ "ips" : [ "1010::3ff/120" ],
+ "vlan-tagged": [126]
+ }
+ ]
+ },
+ "of:0000000000000005/9" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.3.10.254/24" ],
+ "vlan-tagged": [50]
+ }
+ ]
+ },
+ "of:0000000000000005/10" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.3.30.254/24" ],
+ "vlan-tagged": [60]
+ }
+ ]
+ },
+ "of:0000000000000005/11" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.3.20.254/24" ],
+ "vlan-tagged": [70]
+ }
+ ]
+ },
+ "of:0000000000000005/12" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.0.5.254/24", "10.0.6.254/24", "2000::5ff/120", "2000::6ff/120" ],
+ "vlan-tagged": [150, 160]
+ }
+ ]
+ },
+ "of:0000000000000005/13" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.0.5.254/24", "2000::5ff/120"],
+ "vlan-untagged": 150
+ }
+ ]
+ },
+ "of:0000000000000005/14" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.0.6.254/24", "2000::6ff/120" ],
+ "vlan-untagged": 160
+ }
+ ]
+ },
+ "of:0000000000000005/15" : {
+ "interfaces" : [
+ {
+ "ips" : [ "10.0.3.254/24", "2000::3ff/120" ],
+ "vlan-untagged": 15
+ }
+ ]
+ }
+ },
+ "hosts" : {
+ "00:BB:00:00:01:0A/127" : {
+ "basic": {
+ "locations": ["of:0000000000000006/3"],
+ "ips": ["1011::3fe"]
+ }
+ },
+ "00:bb:00:00:00:04/121" : {
+ "basic": {
+ "locations": ["of:0000000000000003/7","of:0000000000000002/8"],
+ "ips": ["1004::3fe"]
+ }
+ },
+ "00:bb:00:00:00:05/122" : {
+ "basic": {
+ "locations": ["of:0000000000000003/8"],
+ "ips": ["1005::3fe"]
+ }
+ },
+ "00:bb:00:00:01:05/123" : {
+ "basic": {
+ "locations": ["of:0000000000000003/9"],
+ "ips": ["1006::3fe"]
+ }
+ },
+ "00:bb:00:00:00:07/124" : {
+ "basic": {
+ "locations": ["of:0000000000000005/6", "of:0000000000000004/7"],
+ "ips": ["1008::3fe"]
+ }
+ },
+ "00:bb:00:00:00:08/125" : {
+ "basic": {
+ "locations": ["of:0000000000000004/8","of:0000000000000005/7"],
+ "ips": ["1009::3fe"]
+ }
+ },
+ "00:bb:00:00:00:0A/126" : {
+ "basic": {
+ "locations": ["of:0000000000000005/8"],
+ "ips": ["1010::3fe"]
+ }
+ }
+ },
+ "devices" : {
+ "of:0000000000000006" : {
+ "segmentrouting" : {
+ "name" : "s006",
+ "ipv4NodeSid" : 1006,
+ "ipv6NodeSid" : 2006,
+ "ipv6Loopback" : "2000::c0a8:0006",
+ "ipv4Loopback" : "192.168.0.6",
+ "routerMac" : "00:00:00:00:00:06",
+ "isEdgeRouter" : true,
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s006",
+ "driver" : "ofdpa-ovs",
+ "latitude": 30,
+ "longitude": -110
+ }
+ },
+ "of:0000000000000103" : {
+ "segmentrouting" : {
+ "name" : "s103",
+ "ipv4NodeSid" : 1103,
+ "ipv4Loopback" : "192.168.0.103",
+ "ipv6NodeSid" : 2103,
+ "ipv6Loopback" : "2000::c0a8:0203",
+ "routerMac" : "00:00:00:00:01:03",
+ "isEdgeRouter" : false,
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s103",
+ "driver" : "ofdpa-ovs",
+ "latitude": 35,
+ "longitude": -115
+ }
+ },
+ "of:0000000000000104" : {
+ "segmentrouting" : {
+ "name" : "s104",
+ "ipv4NodeSid" : 1104,
+ "ipv4Loopback" : "192.168.0.104",
+ "ipv6NodeSid" : 2104,
+ "ipv6Loopback" : "2000::c0a8:0204",
+ "routerMac" : "00:00:00:00:01:04",
+ "isEdgeRouter" : false,
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s104",
+ "driver" : "ofdpa-ovs",
+ "latitude": 35,
+ "longitude": -110
+ }
+ },
+ "of:0000000000000001" : {
+ "segmentrouting" : {
+ "name" : "s001",
+ "ipv4NodeSid" : 1001,
+ "ipv6NodeSid" : 2001,
+ "ipv6Loopback" : "2000::c0a8:0001",
+ "ipv4Loopback" : "192.168.0.1",
+ "routerMac" : "00:00:00:00:00:01",
+ "isEdgeRouter" : true,
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s001",
+ "driver" : "ofdpa-ovs",
+ "latitude": 30,
+ "longitude": -105
+ }
+ },
+ "of:0000000000000002" : {
+ "segmentrouting" : {
+ "name" : "s002",
+ "ipv4NodeSid" : 1002,
+ "ipv4Loopback" : "192.168.0.2",
+ "ipv6NodeSid" : 2002,
+ "ipv6Loopback" : "2000::c0a8:0002",
+ "routerMac" : "00:00:00:00:00:02",
+ "isEdgeRouter" : true,
+ "pairLocalPort" : 5,
+ "pairDeviceId": "of:0000000000000003",
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s002",
+ "driver" : "ofdpa-ovs",
+ "latitude": 34,
+ "longitude": -95
+ }
+ },
+ "of:0000000000000003" : {
+ "segmentrouting" : {
+ "name" : "s003",
+ "ipv4NodeSid" : 1003,
+ "ipv4Loopback" : "192.168.0.3",
+ "ipv6NodeSid" : 2003,
+ "ipv6Loopback" : "2000::c0a8:0003",
+ "routerMac" : "00:00:00:00:00:02",
+ "isEdgeRouter" : true,
+ "pairLocalPort" : 5,
+ "pairDeviceId": "of:0000000000000002",
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s003",
+ "driver" : "ofdpa-ovs",
+ "latitude": 34,
+ "longitude": -90
+ }
+ },
+ "of:0000000000000004" : {
+ "segmentrouting" : {
+ "name" : "s004",
+ "ipv4NodeSid" : 1004,
+ "ipv4Loopback" : "192.168.0.4",
+ "ipv6NodeSid" : 2004,
+ "ipv6Loopback" : "2000::c0a8:0004",
+ "routerMac" : "00:00:00:00:00:04",
+ "isEdgeRouter" : true,
+ "pairLocalPort" : 5,
+ "pairDeviceId": "of:0000000000000005",
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s004",
+ "driver" : "ofdpa-ovs",
+ "latitude": 34,
+ "longitude": -85
+ }
+ },
+ "of:0000000000000005" : {
+ "segmentrouting" : {
+ "name" : "s005",
+ "ipv4NodeSid" : 1005,
+ "ipv4Loopback" : "192.168.0.5",
+ "ipv6NodeSid" : 2005,
+ "ipv6Loopback" : "2000::c0a8:0005",
+ "routerMac" : "00:00:00:00:00:04",
+ "isEdgeRouter" : true,
+ "pairLocalPort" : 5,
+ "pairDeviceId": "of:0000000000000004",
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s005",
+ "driver" : "ofdpa-ovs",
+ "latitude": 34,
+ "longitude": -80
+ }
+ },
+ "of:0000000000000101" : {
+ "segmentrouting" : {
+ "name" : "s101",
+ "ipv4NodeSid" : 1101,
+ "ipv4Loopback" : "192.168.0.101",
+ "ipv6NodeSid" : 2101,
+ "ipv6Loopback" : "2000::c0a8:0101",
+ "routerMac" : "00:00:00:00:01:01",
+ "isEdgeRouter" : false,
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s101",
+ "driver" : "ofdpa-ovs",
+ "latitude": 42,
+ "longitude": -100
+ }
+ },
+ "of:0000000000000102" : {
+ "segmentrouting" : {
+ "name" : "s102",
+ "ipv4NodeSid" : 1102,
+ "ipv4Loopback" : "192.168.0.102",
+ "ipv6NodeSid" : 2102,
+ "ipv6Loopback" : "2000::c0a8:0202",
+ "routerMac" : "00:00:00:00:01:02",
+ "isEdgeRouter" : false,
+ "adjacencySids" : []
+ },
+ "basic" : {
+ "name" : "s102",
+ "driver" : "ofdpa-ovs",
+ "latitude": 42,
+ "longitude": -95
+ }
+ }
+ },
+ "apps" : {
+ "org.onosproject.dhcprelay" : {
+ "default": [
+ {
+ "dhcpServerConnectPoint": "of:0000000000000005/15",
+ "serverIps": ["10.0.3.253", "2000::3fd"]
+ }
+ ]
+ }
+ }
+}
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/routinglib.py b/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/routinglib.py
new file mode 100644
index 0000000..13a75e2
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/routinglib.py
@@ -0,0 +1,702 @@
+#!/usr/bin/python
+
+"""
+Libraries for creating L3 topologies with routing protocols.
+"""
+
+from mininet.node import Host, OVSBridge
+from mininet.nodelib import NAT
+from mininet.log import info, debug, error
+from mininet.cli import CLI
+from ipaddress import ip_network, ip_address, ip_interface
+import os
+
+class RoutedHost(Host):
+ """Host that can be configured with multiple IP addresses."""
+ def __init__(self, name, ips, gateway, *args, **kwargs):
+ super(RoutedHost, self).__init__(name, *args, **kwargs)
+
+ self.ips = ips
+ self.gateway = gateway
+
+ def config(self, **kwargs):
+ Host.config(self, **kwargs)
+
+ self.cmd('ip -4 addr flush dev %s' % self.defaultIntf())
+ for ip in self.ips:
+ self.cmd('ip addr add %s dev %s' % (ip, self.defaultIntf()))
+
+ self.cmd('ip route add default via %s' % self.gateway)
+
+class RoutedHost6(Host):
+ """Host that can be configured with multiple IP addresses."""
+ def __init__(self, name, ips, gateway, *args, **kwargs):
+ super(RoutedHost6, self).__init__(name, *args, **kwargs)
+
+ self.ips = ips
+ self.gateway = gateway
+
+ def config(self, **kwargs):
+ Host.config(self, **kwargs)
+
+ self.cmd('ip -6 addr flush dev %s' % self.defaultIntf())
+ for ip in self.ips:
+ self.cmd('ip -6 addr add %s dev %s' % (ip, self.defaultIntf()))
+
+ self.cmd('ip -6 route add default via %s' % self.gateway)
+
+class Router(Host):
+
+ """An L3 router.
+ Configures the Linux kernel for L3 forwarding and supports rich interface
+ configuration of IP addresses, MAC addresses and VLANs."""
+
+ def __init__(self, name, interfaces, *args, **kwargs):
+ super(Router, self).__init__(name, **kwargs)
+
+ self.interfaces = interfaces
+
+ def config(self, **kwargs):
+ super(Host, self).config(**kwargs)
+
+ self.cmd('sysctl net.ipv4.ip_forward=1')
+ self.cmd('sysctl net.ipv4.conf.all.rp_filter=0')
+ self.cmd('sysctl net.ipv6.conf.all.forwarding=1')
+
+ for intf, configs in self.interfaces.items():
+ self.cmd('ip -4 addr flush dev %s' % intf)
+ self.cmd( 'sysctl net.ipv4.conf.%s.rp_filter=0' % intf )
+
+ if not isinstance(configs, list):
+ configs = [configs]
+
+ for attrs in configs:
+ # Configure the vlan if there is one
+ if 'vlan' in attrs:
+ vlanName = '%s.%s' % (intf, attrs['vlan'])
+ self.cmd('ip link add link %s name %s type vlan id %s' %
+ (intf, vlanName, attrs['vlan']))
+ self.cmd('ip link set %s up' % vlanName)
+ addrIntf = vlanName
+ else:
+ addrIntf = intf
+
+ # Now configure the addresses on the vlan/native interface
+ if 'mac' in attrs:
+ self.cmd('ip link set %s down' % addrIntf)
+ self.cmd('ip link set %s address %s' % (addrIntf, attrs['mac']))
+ self.cmd('ip link set %s up' % addrIntf)
+ for addr in attrs['ipAddrs']:
+ self.cmd('ip addr add %s dev %s' % (addr, addrIntf))
+
+class QuaggaRouter(Router):
+
+ """Runs Quagga to create a router that can speak routing protocols."""
+
+ binDir = '/usr/lib/quagga'
+ logDir = '/var/log/quagga'
+
+ def __init__(self, name, interfaces,
+ defaultRoute=None,
+ zebraConfFile=None,
+ protocols= [],
+ fpm=None,
+ runDir='/var/run/quagga', *args, **kwargs):
+ super(QuaggaRouter, self).__init__(name, interfaces, **kwargs)
+
+ self.protocols = protocols
+ self.fpm = fpm
+
+ for p in self.protocols:
+ p.setQuaggaRouter(self)
+
+ self.runDir = runDir
+ self.defaultRoute = defaultRoute
+
+ # Ensure required directories exist
+ try:
+ original_umask = os.umask(0)
+ if (not os.path.isdir(QuaggaRouter.logDir)):
+ os.makedirs(QuaggaRouter.logDir, 0777)
+ if (not os.path.isdir(self.runDir)):
+ os.makedirs(self.runDir, 0777)
+ finally:
+ os.umask(original_umask)
+
+ self.zebraConfFile = zebraConfFile
+ if (self.zebraConfFile is None):
+ self.zebraConfFile = '%s/zebrad%s.conf' % (self.runDir, self.name)
+ self.generateZebra()
+
+ self.socket = '%s/zebra%s.api' % (self.runDir, self.name)
+
+ self.zebraPidFile = '%s/zebra%s.pid' % (self.runDir, self.name)
+
+ def generateZebra(self):
+ configFile = open(self.zebraConfFile, 'w+')
+ configFile.write('log file %s/zebrad%s.log\n' % (QuaggaRouter.logDir, self.name))
+ configFile.write('hostname zebra-%s\n' % self.name)
+ configFile.write('password %s\n' % 'quagga')
+ if (self.fpm is not None):
+ configFile.write('fpm connection ip %s port 2620' % self.fpm)
+ configFile.close()
+
+ def config(self, **kwargs):
+ super(QuaggaRouter, self).config(**kwargs)
+
+ self.cmd('%s/zebra -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.zebraConfFile, self.socket, self.zebraPidFile))
+ print("\n")
+ print('%s/zebra -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.zebraConfFile, self.socket, self.zebraPidFile))
+
+ for p in self.protocols:
+ p.config(**kwargs)
+
+ if self.defaultRoute:
+ self.cmd('ip route add default via %s' % self.defaultRoute)
+
+ def stopProtocols(self, **kwargs):
+ for p in self.protocols:
+ p.stop(**kwargs)
+
+ def startProtocols(self, **kwargs):
+ for p in self.protocols:
+ p.start(**kwargs)
+
+ def terminate(self, **kwargs):
+ self.cmd("ps ax | grep '%s' | awk '{print $1}' | xargs kill"
+ % (self.socket))
+
+ for p in self.protocols:
+ p.terminate(**kwargs)
+
+ super(QuaggaRouter, self).terminate()
+
+class Protocol(object):
+
+ """Base abstraction of a protocol that the QuaggaRouter can run."""
+
+ def setQuaggaRouter(self, qr):
+ self.qr = qr
+
+ def config(self, **kwargs):
+ pass
+
+ def stop(self, **kwargs):
+ pass
+
+ def start(self, **kwargs):
+ pass
+
+ def terminate(self, **kwargs):
+ pass
+
+class BgpProtocol(Protocol):
+
+ """Configures and runs the BGP protocol in Quagga."""
+
+ def __init__(self, configFile=None, asNum=None, neighbors=[], routes=[], *args, **kwargs):
+ self.configFile = configFile
+
+ self.asNum = asNum
+ self.neighbors = neighbors
+ self.routes = routes
+
+ def config(self, **kwargs):
+ if self.configFile is None:
+ self.configFile = '%s/bgpd%s.conf' % (self.qr.runDir, self.qr.name)
+ self.generateConfig()
+
+ bgpdPidFile = '%s/bgpd%s.pid' % (self.qr.runDir, self.qr.name)
+
+ self.qr.cmd('%s/bgpd -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.configFile, self.qr.socket, bgpdPidFile))
+
+ def stop(self, **kwargs):
+ self.qr.cmd('pkill -f %s' % self.configFile)
+
+ def start(self, **kwargs):
+ bgpdPidFile = '%s/bgpd%s.pid' % (self.qr.runDir, self.qr.name)
+ self.qr.cmd('%s/bgpd -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.configFile, self.qr.socket, bgpdPidFile))
+
+ def generateConfig(self):
+ conf = ConfigurationWriter(self.configFile)
+
+ def getRouterId(interfaces):
+ intfAttributes = interfaces.itervalues().next()
+ print intfAttributes
+ if isinstance(intfAttributes, list):
+ # Try use the first set of attributes, but if using vlans they might not have addresses
+ intfAttributes = intfAttributes[1] if not intfAttributes[0]['ipAddrs'] else intfAttributes[0]
+ return intfAttributes['ipAddrs'][0].split('/')[0]
+
+ conf.writeLine('log file %s/bgpd%s.log' % (QuaggaRouter.logDir, self.qr.name))
+ conf.writeLine('hostname bgp-%s' % self.qr.name)
+ conf.writeLine('password %s' % 'quagga')
+ conf.writeLine('!')
+ conf.writeLine('router bgp %s' % self.asNum)
+
+ conf.indent()
+
+ conf.writeLine('bgp router-id %s' % getRouterId(self.qr.interfaces))
+ conf.writeLine('timers bgp %s' % '3 9')
+ conf.writeLine('!')
+
+ for neighbor in self.neighbors:
+ conf.writeLine('neighbor %s remote-as %s' % (neighbor['address'], neighbor['as']))
+ conf.writeLine('neighbor %s ebgp-multihop' % neighbor['address'])
+ conf.writeLine('neighbor %s timers connect %s' % (neighbor['address'], '5'))
+ conf.writeLine('neighbor %s advertisement-interval %s' % (neighbor['address'], '5'))
+ if 'port' in neighbor:
+ conf.writeLine('neighbor %s port %s' % (neighbor['address'], neighbor['port']))
+ conf.writeLine('!')
+
+ for route in self.routes:
+ conf.writeLine('network %s' % route)
+
+ conf.close()
+
+class OspfProtocol(Protocol):
+
+ """Configures and runs the OSPF protocol in Quagga."""
+
+ def __init__(self, configFile=None, *args, **kwargs):
+ self.configFile = configFile
+
+ def config(self, **kwargs):
+ if self.configFile is None:
+ self.configFile = '%s/ospfd%s.conf' % (self.qr.runDir, self.qr.name)
+ self.generateConfig()
+
+ ospfPidFile = '%s/ospf%s.pid' % (self.qr.runDir, self.qr.name)
+
+ self.qr.cmd('%s/ospfd -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.configFile, self.qr.socket, ospfPidFile))
+
+ def generateConfig(self):
+ conf = ConfigurationWriter(self.configFile)
+
+ def getRouterId(interfaces):
+ intfAttributes = interfaces.itervalues().next()
+ print intfAttributes
+ if isinstance(intfAttributes, list):
+ # Try use the first set of attributes, but if using vlans they might not have addresses
+ intfAttributes = intfAttributes[1] if not intfAttributes[0]['ipAddrs'] else intfAttributes[0]
+ return intfAttributes['ipAddrs'][0].split('/')[0]
+
+ conf.writeLine('hostname ospf-%s' % self.qr.name)
+ conf.writeLine('password %s' % 'hello')
+ conf.writeLine('!')
+ conf.writeLine('router ospf')
+
+ conf.indent()
+
+ conf.writeLine('ospf router-id %s' % getRouterId(self.qr.interfaces))
+ conf.writeLine('!')
+
+ for name, intf in self.qr.interfaces.items():
+ for ip in intf['ipAddrs']:
+ conf.writeLine('network %s area 0' % ip)
+ # if intf['ipAddrs'][0].startswith('192.168'):
+ # writeLine(1, 'passive-interface %s' % name)
+
+ conf.close()
+
+class PimProtocol(Protocol):
+
+ """Configures and runs the PIM protcol in Quagga."""
+
+ def __init__(self, configFile=None, *args, **kwargs):
+ self.configFile = configFile
+
+ def config(self, **kwargs):
+ pimPidFile = '%s/pim%s.pid' % (self.qr.runDir, self.qr.name)
+
+ self.qr.cmd('%s/pimd -Z -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.configFile, self.qr.socket, pimPidFile))
+
+class ConfigurationWriter(object):
+
+ """Utility class for writing a configuration file."""
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.indentValue = 0
+
+ self.configFile = open(self.filename, 'w+')
+
+ def indent(self):
+ self.indentValue += 1
+
+ def unindent(self):
+ if (self.indentValue > 0):
+ self.indentValue -= 1
+
+ def write(self, string):
+ self.configFile.write(string)
+
+ def writeLine(self, string):
+ intentStr = ''
+ for _ in range(0, self.indentValue):
+ intentStr += ' '
+ self.write('%s%s\n' % (intentStr, string))
+
+ def close(self):
+ self.configFile.close()
+
+# Backward compatibility for BGP-only use case
+class BgpRouter(QuaggaRouter):
+
+ """Quagga router running the BGP protocol."""
+
+ def __init__(self, name, interfaces,
+ asNum=0, neighbors=[], routes=[],
+ defaultRoute=None,
+ quaggaConfFile=None,
+ zebraConfFile=None,
+ *args, **kwargs):
+ bgp = BgpProtocol(configFile=quaggaConfFile, asNum=asNum, neighbors=neighbors, routes=routes)
+
+ super(BgpRouter, self).__init__(name, interfaces,
+ zebraConfFile=zebraConfFile,
+ defaultRoute=defaultRoute,
+ protocols=[bgp],
+ *args, **kwargs)
+
+class RouterData(object):
+
+ """Internal data structure storing information about a router."""
+
+ def __init__(self, index):
+ self.index = index
+ self.neighbors = []
+ self.interfaces = {}
+ self.switches = []
+
+ def addNeighbor(self, theirAddress, theirAsNum):
+ self.neighbors.append({'address': theirAddress.ip, 'as': theirAsNum})
+
+ def addInterface(self, intf, vlan, address):
+ if intf not in self.interfaces:
+ self.interfaces[intf] = InterfaceData(intf)
+
+ self.interfaces[intf].addAddress(vlan, address)
+
+ def setSwitch(self, switch):
+ self.switches.append(switch)
+
+class InterfaceData(object):
+
+ """Internal data structure storing information about an interface."""
+
+ def __init__(self, number):
+ self.number = number
+ self.addressesByVlan = {}
+
+ def addAddress(self, vlan, address):
+ if vlan not in self.addressesByVlan:
+ self.addressesByVlan[vlan] = []
+
+ self.addressesByVlan[vlan].append(address.with_prefixlen)
+
+class RoutedNetwork(object):
+
+ """Creates a host behind a router. This is common boilerplate topology
+ segment in routed networks."""
+
+ @staticmethod
+ def build(topology, router, hostName, networks):
+ # There's a convention that the router's addresses are already set up,
+ # and it has the last address in the network.
+
+ def getFirstAddress(network):
+ return '%s/%s' % (network[1], network.prefixlen)
+
+ defaultRoute = AutonomousSystem.getLastAddress(networks[0]).ip
+
+ host = topology.addHost(hostName, cls=RoutedHost,
+ ips=[getFirstAddress(network) for network in networks],
+ gateway=defaultRoute)
+
+ topology.addLink(router, host)
+
+class AutonomousSystem(object):
+
+ """Base abstraction of an autonomous system, which implies some internal
+ topology and connections to other topology elements (switches/other ASes)."""
+
+ psIdx = 1
+
+ def __init__(self, asNum, numRouters):
+ self.asNum = asNum
+ self.numRouters = numRouters
+ self.routers = {}
+ for i in range(1, numRouters + 1):
+ self.routers[i] = RouterData(i)
+
+ self.routerNodes = {}
+
+ self.neighbors = []
+ self.vlanAddresses = {}
+
+ def peerWith(self, myRouter, myAddress, theirAddress, theirAsNum, intf=1, vlan=None):
+ router = self.routers[myRouter]
+
+ router.addInterface(intf, vlan, myAddress)
+ router.addNeighbor(theirAddress, theirAsNum)
+
+ def getRouter(self, i):
+ return self.routerNodes[i]
+
+ @staticmethod
+ def generatePeeringAddresses():
+ network = ip_network(u'10.0.%s.0/24' % AutonomousSystem.psIdx)
+ AutonomousSystem.psIdx += 1
+
+ return ip_interface('%s/%s' % (network[1], network.prefixlen)), \
+ ip_interface('%s/%s' % (network[2], network.prefixlen))
+
+ @staticmethod
+ def addPeering(as1, as2, router1=1, router2=1, intf1=1, intf2=1, address1=None, address2=None, useVlans=False):
+ vlan = AutonomousSystem.psIdx if useVlans else None
+
+ if address1 is None or address2 is None:
+ (address1, address2) = AutonomousSystem.generatePeeringAddresses()
+
+ as1.peerWith(router1, address1, address2, as2.asNum, intf=intf1, vlan=vlan)
+ as2.peerWith(router2, address2, address1, as1.asNum, intf=intf2, vlan=vlan)
+
+ @staticmethod
+ def getLastAddress(network):
+ return ip_interface(network.network_address + network.num_addresses - 2)
+
+ @staticmethod
+ def getIthAddress(network, i):
+ return ip_interface('%s/%s' % (network[i], network.prefixlen))
+
+class BasicAutonomousSystem(AutonomousSystem):
+
+ """Basic autonomous system containing one host and one or more routers
+ which peer with other ASes."""
+
+ def __init__(self, num, routes, numRouters=1):
+ super(BasicAutonomousSystem, self).__init__(65000+num, numRouters)
+ self.num = num
+ self.routes = routes
+
+ def addLink(self, switch, router=1):
+ self.routers[router].setSwitch(switch)
+
+ def build(self, topology):
+ self.addRouterAndHost(topology)
+
+ def addRouterAndHost(self, topology):
+
+ # TODO implementation is messy and needs to be cleaned up
+
+ intfs = {}
+
+ router = self.routers[1]
+ for i, router in self.routers.items():
+
+ # routerName = 'r%i%i' % (self.num, i)
+ routerName = 'r%i' % self.num
+ if not i == 1:
+ routerName += ('%i' % i)
+
+ hostName = 'h%i' % self.num
+
+ for j, interface in router.interfaces.items():
+ nativeAddresses = interface.addressesByVlan.pop(None, [])
+ peeringIntf = [{'mac' : '00:00:%02x:00:%02x:%02x' % (self.num, i, j),
+ 'ipAddrs' : nativeAddresses}]
+
+ for vlan, addresses in interface.addressesByVlan.items():
+ peeringIntf.append({'vlan': vlan,
+ 'mac': '00:00:%02x:%02x:%02x:%02x' % (self.num, vlan, i, j),
+ 'ipAddrs': addresses})
+
+ intfs.update({'%s-eth%s' % (routerName, j-1) : peeringIntf})
+
+ # Only add the host to the first router for now
+ if i == 1:
+ internalAddresses = []
+ for route in self.routes:
+ internalAddresses.append('%s/%s' % (AutonomousSystem.getLastAddress(route).ip, route.prefixlen))
+
+ internalIntf = {'ipAddrs' : internalAddresses}
+
+ # This is the configuration of the next interface after all the peering interfaces
+ intfs.update({'%s-eth%s' % (routerName, len(router.interfaces.keys())) : internalIntf})
+
+ routerNode = topology.addHost(routerName,
+ asNum=self.asNum, neighbors=router.neighbors,
+ routes=self.routes,
+ cls=BgpRouter, interfaces=intfs)
+
+ self.routerNodes[i] = routerNode
+
+ for switch in router.switches:
+ topology.addLink(switch, routerNode)
+
+ # Only add the host to the first router for now
+ if i == 1:
+ defaultRoute = internalAddresses[0].split('/')[0]
+
+ host = topology.addHost(hostName, cls=RoutedHost,
+ ips=[self.getFirstAddress(route) for route in self.routes],
+ gateway=defaultRoute)
+
+ topology.addLink(routerNode, host)
+
+ # def getLastAddress(self, network):
+ # return ip_address(network.network_address + network.num_addresses - 2)
+
+ def getFirstAddress(self, network):
+ return '%s/%s' % (network[1], network.prefixlen)
+
+# TODO fix this AS - doesn't currently work
+class RouteServerAutonomousSystem(BasicAutonomousSystem):
+
+ def __init__(self, routerAddress, *args, **kwargs):
+ BasicAutonomousSystem.__init__(self, *args, **kwargs)
+
+ self.routerAddress = routerAddress
+
+ def build(self, topology, connectAtSwitch):
+
+ switch = topology.addSwitch('as%isw' % self.num, cls=OVSBridge)
+
+ self.addRouterAndHost(topology, self.routerAddress, switch)
+
+ rsName = 'rs%i' % self.num
+ routeServer = topology.addHost(rsName,
+ self.asnum, self.neighbors,
+ cls=BgpRouter,
+ interfaces={'%s-eth0' % rsName : {'ipAddrs': [self.peeringAddress]}})
+
+ topology.addLink(routeServer, switch)
+ topology.addLink(switch, connectAtSwitch)
+
+class SdnAutonomousSystem(AutonomousSystem):
+
+ """Runs the internal BGP speakers needed for ONOS routing apps like
+ SDN-IP."""
+
+ routerIdx = 1
+
+ def __init__(self, onosIps, num=1, numBgpSpeakers=1, asNum=65000, externalOnos=True,
+ peerIntfConfig=None, withFpm=False):
+ super(SdnAutonomousSystem, self).__init__(asNum, numBgpSpeakers)
+ self.onosIps = onosIps
+ self.num = num
+ self.numBgpSpeakers = numBgpSpeakers
+ self.peerIntfConfig = peerIntfConfig
+ self.withFpm = withFpm
+ self.externalOnos = externalOnos
+ self.internalPeeringSubnet = ip_network(u'1.1.1.0/24')
+
+ for router in self.routers.values():
+ # Add iBGP sessions to ONOS nodes
+ for onosIp in onosIps:
+ router.neighbors.append({'address': onosIp, 'as': asNum, 'port': 2000})
+
+ # Add iBGP sessions to other BGP speakers
+ for i, router2 in self.routers.items():
+ if router == router2:
+ continue
+ cpIpBase = self.num*10
+ ip = AutonomousSystem.getIthAddress(self.internalPeeringSubnet, cpIpBase+i)
+ router.neighbors.append({'address': ip.ip, 'as': asNum})
+
+ def build(self, topology, connectAtSwitch, controlSwitch):
+
+ natIp = AutonomousSystem.getLastAddress(self.internalPeeringSubnet)
+
+ for i, router in self.routers.items():
+ num = SdnAutonomousSystem.routerIdx
+ SdnAutonomousSystem.routerIdx += 1
+ name = 'bgp%s' % num
+
+ cpIpBase = self.num*10
+ ip = AutonomousSystem.getIthAddress(self.internalPeeringSubnet, cpIpBase+i)
+
+ eth0 = { 'ipAddrs' : [ str(ip) ] }
+ if self.peerIntfConfig is not None:
+ eth1 = self.peerIntfConfig
+ else:
+ nativeAddresses = router.interfaces[1].addressesByVlan.pop(None, [])
+ eth1 = [{ 'mac': '00:00:00:00:00:%02x' % num,
+ 'ipAddrs' : nativeAddresses }]
+
+ for vlan, addresses in router.interfaces[1].addressesByVlan.items():
+ eth1.append({'vlan': vlan,
+ 'mac': '00:00:00:%02x:%02x:00' % (num, vlan),
+ 'ipAddrs': addresses})
+
+ intfs = { '%s-eth0' % name : eth0,
+ '%s-eth1' % name : eth1 }
+
+ bgp = topology.addHost( name, cls=BgpRouter, asNum=self.asNum,
+ neighbors=router.neighbors,
+ interfaces=intfs,
+ defaultRoute=str(natIp.ip),
+ fpm=self.onosIps[0] if self.withFpm else None )
+
+ topology.addLink( bgp, controlSwitch )
+ topology.addLink( bgp, connectAtSwitch )
+
+ if self.externalOnos:
+ nat = topology.addHost('nat', cls=NAT,
+ ip='%s/%s' % (natIp.ip, self.internalPeeringSubnet.prefixlen),
+ subnet=str(self.internalPeeringSubnet), inNamespace=False)
+ topology.addLink(controlSwitch, nat)
+
+def generateRoutes(baseRange, numRoutes, subnetSize=None):
+ baseNetwork = ip_network(baseRange)
+
+ # We need to get at least 2 addresses out of each subnet, so the biggest
+ # prefix length we can have is /30
+ maxPrefixLength = baseNetwork.max_prefixlen - 2
+
+ if subnetSize is not None:
+ return list(baseNetwork.subnets(new_prefix=subnetSize))
+
+ trySubnetSize = baseNetwork.prefixlen + 1
+ while trySubnetSize <= maxPrefixLength and \
+ len(list(baseNetwork.subnets(new_prefix=trySubnetSize))) < numRoutes:
+ trySubnetSize += 1
+
+ if trySubnetSize > maxPrefixLength:
+ raise Exception("Can't get enough routes from input parameters")
+
+ return list(baseNetwork.subnets(new_prefix=trySubnetSize))[:numRoutes]
+
+class RoutingCli( CLI ):
+
+ """CLI command that can bring a host up or down. Useful for simulating router failure."""
+
+ def do_host( self, line ):
+ args = line.split()
+ if len(args) != 2:
+ error( 'invalid number of args: host <host name> {up, down}\n' )
+ return
+
+ host = args[ 0 ]
+ command = args[ 1 ]
+ if host not in self.mn or self.mn.get( host ) not in self.mn.hosts:
+ error( 'invalid host: %s\n' % args[ 1 ] )
+ else:
+ if command == 'up':
+ op = 'up'
+ elif command == 'down':
+ op = 'down'
+ else:
+ error( 'invalid command: host <host name> {up, down}\n' )
+ return
+
+ for intf in self.mn.get( host ).intfList( ):
+ intf.link.intf1.ifconfig( op )
+ intf.link.intf2.ifconfig( op )
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/trellis_fabric.py b/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/trellis_fabric.py
new file mode 100644
index 0000000..73bfda3
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/trellis_fabric.py
@@ -0,0 +1,434 @@
+#!/usr/bin/python
+import os
+import re
+from optparse import OptionParser
+
+from ipaddress import ip_network
+from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch
+from mininet.link import TCLink
+from mininet.log import setLogLevel
+from mininet.net import Mininet
+from mininet.topo import Topo
+from mininet.nodelib import NAT
+from mininet.cli import CLI
+
+from routinglib import BgpRouter
+from trellislib import TrellisHost, DhcpRelay
+from functools import partial
+
+# Parse command line options and dump results
+def parseOptions():
+ "Parse command line options"
+ parser = OptionParser()
+ parser.add_option( '--spine', dest='spine', type='int', default=2,
+ help='number of spine switches, default=2' )
+ parser.add_option( '--leaf', dest='leaf', type='int', default=2,
+ help='number of leaf switches, default=2' )
+ parser.add_option( '--fanout', dest='fanout', type='int', default=2,
+ help='number of hosts per leaf switch, default=2' )
+ parser.add_option( '--onos-ip', dest='onosIp', type='str', default='',
+ help='IP address list of ONOS instances, separated by comma(,). Overrides --onos option' )
+ parser.add_option( '--ipv6', action="store_true", dest='ipv6',
+ help='hosts are capable to use also ipv6' )
+ parser.add_option( '--dual-homed', action="store_true", dest='dualhomed', default=False,
+ help='True if the topology is dual-homed, default=False' )
+ parser.add_option( '--vlan', dest='vlan', type='str', default='',
+ help='list of vlan id for hosts, separated by comma(,).'
+ 'Empty or id with 0 will be unconfigured.' )
+ parser.add_option( '--dhcp-client', action="store_true", dest='dhcpClient', default=False,
+ help='Set hosts as DhcpClient if True' )
+ parser.add_option( '--dhcp-relay', action="store_true", dest='dhcpRelay', default=False,
+ help='Connect half of the hosts to switch indirectly (via DHCP relay) if True' )
+ parser.add_option( '--multiple-dhcp-server', action="store_true", dest='multipleServer', default=False,
+ help='Use another DHCP server for indirectly connected DHCP clients if True' )
+ parser.add_option( '--remote-dhcp-server', action="store_true", dest='remoteServer', default=False,
+ help='Connect DHCP server indirectly (via gateway) if True' )
+ ( options, args ) = parser.parse_args()
+ return options, args
+
+
+opts, args = parseOptions()
+
+IP6_SUBNET_CLASS = 120
+IP4_SUBNET_CLASS = 24
+
+# TODO: DHCP support
+class IpHost( Host ):
+
+ def __init__( self, name, *args, **kwargs ):
+ super( IpHost, self ).__init__( name, *args, **kwargs )
+ gateway = re.split( '\.|/', kwargs[ 'ip' ] )
+ gateway[ 3 ] = '254'
+ self.gateway = '.'.join( gateway[ 0:4 ] )
+
+ def config( self, **kwargs ):
+ Host.config( self, **kwargs )
+ mtu = "ifconfig " + self.name + "-eth0 mtu 1490"
+ self.cmd( mtu )
+ self.cmd( 'ip route add default via %s' % self.gateway )
+
+class DualHomedIpHost(IpHost):
+ def __init__(self, name, *args, **kwargs):
+ super(DualHomedIpHost, self).__init__(name, **kwargs)
+ self.bond0 = None
+
+ def config(self, **kwargs):
+ super(DualHomedIpHost, self).config(**kwargs)
+ intf0 = self.intfs[0].name
+ intf1 = self.intfs[1].name
+ self.bond0 = "%s-bond0" % self.name
+ self.cmd('modprobe bonding')
+ self.cmd('ip link add %s type bond' % self.bond0)
+ self.cmd('ip link set %s down' % intf0)
+ self.cmd('ip link set %s down' % intf1)
+ self.cmd('ip link set %s master %s' % (intf0, self.bond0))
+ self.cmd('ip link set %s master %s' % (intf1, self.bond0))
+ self.cmd('ip addr flush dev %s' % intf0)
+ self.cmd('ip addr flush dev %s' % intf1)
+ self.cmd('ip link set %s up' % self.bond0)
+
+ def terminate(self, **kwargs):
+ self.cmd('ip link set %s down' % self.bond0)
+ self.cmd('ip link delete %s' % self.bond0)
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ super(DualHomedIpHost, self).terminate()
+
+
+# TODO: Implement IPv6 support
+class DualHomedLeafSpineFabric (Topo) :
+ def __init__(self, spine = 2, leaf = 2, fanout = 2, vlan_id = [], ipv6 = False,
+ dhcp_client = False, dhcp_relay = False,
+ multiple_server = False, remote_server = False, **opts):
+ # TODO: add support to dhcp_relay, multiple_server and remote_server
+ Topo.__init__(self, **opts)
+ spines = dict()
+ leafs = dict()
+
+ # leaf should be 2 or 4
+
+ # calculate the subnets to use and set options
+ linkopts = dict( bw=100 )
+ # Create spine switches
+ for s in range(spine):
+ spines[s] = self.addSwitch('spine10%s' % (s + 1), dpid = "00000000010%s" % (s + 1) )
+
+ # Create leaf switches
+ for ls in range(leaf):
+ leafs[ls] = self.addSwitch('leaf%s' % (ls + 1), dpid = "00000000000%s" % ( ls + 1) )
+
+ # Connect leaf to all spines with dual link
+ for s in range( spine ):
+ switch = spines[ s ]
+ self.addLink(leafs[ls], switch, **linkopts)
+ self.addLink(leafs[ls], switch, **linkopts)
+
+ # Add hosts after paired ToR switches are added.
+ if ls % 2 == 0:
+ continue
+
+ # Add leaf-leaf link
+ self.addLink(leafs[ls], leafs[ls-1])
+
+ dual_ls = ls / 2
+ # Add hosts
+ for f in range(fanout):
+ name = 'h%s%s' % (dual_ls * fanout + f + 1, "v6" if ipv6 else "")
+ if ipv6:
+ ips = ['2000::%d0%d/%d' % (dual_ls+2, f+1, IP6_SUBNET_CLASS)]
+ gateway = '2000::%dff' % (dual_ls+2)
+ mac = '00:bb:00:00:00:%02x' % (dual_ls * fanout + f + 1)
+ else:
+ ips = ['10.0.%d.%d/%d' % (dual_ls+2, f+1, IP4_SUBNET_CLASS)]
+ gateway = '10.0.%d.254' % (dual_ls+2)
+ mac = '00:aa:00:00:00:%02x' % (dual_ls * fanout + f + 1)
+ host = self.addHost( name=name, cls=TrellisHost, ips=ips, gateway=gateway, mac=mac,
+ vlan=vlan_id[ dual_ls*fanout + f ] if vlan_id[dual_ls * fanout + f] != 0 else None,
+ dhcpClient=dhcp_client, ipv6=ipv6, dualHomed=True )
+ self.addLink(host, leafs[ls], **linkopts)
+ self.addLink(host, leafs[ls-1], **linkopts)
+
+ last_ls = leafs[leaf-2]
+ last_paired_ls = leafs[leaf-1]
+ # Create common components
+ # Control plane switch (for DHCP servers)
+ cs1 = self.addSwitch('cs1', cls=OVSBridge)
+ self.addLink(cs1, last_ls)
+
+ # Control plane switch (for quagga fpm)
+ cs0 = self.addSwitch('cs0', cls=OVSBridge)
+
+ # Control plane NAT (for quagga fpm)
+ nat = self.addHost('nat', cls=NAT,
+ ip='172.16.0.1/12',
+ subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
+ self.addLink(cs0, nat)
+
+ # Internal Quagga bgp1
+ intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03'},
+ 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
+ bgp1 = self.addHost('bgp1', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdbgp1.conf',
+ zebraConfFile='./zebradbgp1.conf')
+ self.addLink(bgp1, last_ls)
+ self.addLink(bgp1, cs0)
+
+ # Internal Quagga bgp2
+ intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
+ {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
+ 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
+ bgp2 = self.addHost('bgp2', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdbgp2.conf',
+ zebraConfFile='./zebradbgp2.conf')
+ self.addLink(bgp2, last_paired_ls)
+ self.addLink(bgp2, cs0)
+
+ # External Quagga r1
+ intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
+ 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'},
+ 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']}}
+ r1 = self.addHost('r1', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdr1.conf')
+ self.addLink(r1, last_ls)
+ self.addLink(r1, last_paired_ls)
+
+ # External IPv4 Host behind r1
+ rh1 = self.addHost('rh1', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+ self.addLink(r1, rh1)
+
+ # External Quagga r2
+ intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'},
+ 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'},
+ 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']}}
+ r2 = self.addHost('r2', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdr2.conf')
+ self.addLink(r2, last_ls)
+ self.addLink(r2, last_paired_ls)
+
+ # External IPv4 Host behind r2
+ rh2 = self.addHost('rh2', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+ self.addLink(r2, rh2)
+
+ # DHCP server
+ if ipv6:
+ dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
+ ips=['2000::3fd/120'], gateway='2000::3ff',
+ dhcpServer=True, ipv6=True)
+ self.addLink(dhcp, cs1)
+ else:
+ dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
+ ips=['10.0.3.253/24'], gateway='10.0.3.254',
+ dhcpServer=True)
+ self.addLink(dhcp, cs1)
+
+
+class LeafSpineFabric (Topo) :
+ def __init__(self, spine = 2, leaf = 2, fanout = 2, vlan_id = [], ipv6 = False,
+ dhcp_client = False, dhcp_relay = False,
+ multiple_server = False, remote_server = False, **opts):
+ Topo.__init__(self, **opts)
+ spines = dict()
+ leafs = dict()
+
+ # TODO: support IPv6 hosts
+ linkopts = dict( bw=100 )
+
+ # Create spine switches
+ for s in range(spine):
+ spines[s] = self.addSwitch('spine10%s' % (s + 1), dpid = "00000000010%s" % (s + 1) )
+
+ # Create leaf switches
+ for ls in range(leaf):
+ leafs[ls] = self.addSwitch('leaf%s' % (ls + 1), dpid = "00000000000%s" % ( ls + 1) )
+
+ # Connect leaf to all spines
+ for s in range( spine ):
+ switch = spines[ s ]
+ self.addLink( leafs[ ls ], switch, **linkopts )
+
+ # If dual-homed ToR, add hosts only when adding second switch at each edge-pair
+ # When the number of leaf switches is odd, leave the last switch as a single ToR
+
+ # Add hosts
+ for f in range(fanout):
+ name = 'h%s%s' % (ls * fanout + f + 1, "v6" if ipv6 else "")
+ if ipv6:
+ ips = ['2000::%d0%d/%d' % (ls+2, f+1, IP6_SUBNET_CLASS)]
+ gateway = '2000::%dff' % (ls+2)
+ mac = '00:bb:00:00:00:%02x' % (ls * fanout + f + 1)
+ else:
+ ips = ['10.0.%d.%d/%d' % (ls+2, f+1, IP4_SUBNET_CLASS)]
+ gateway = '10.0.%d.254' % (ls+2)
+ mac = '00:aa:00:00:00:%02x' % (ls * fanout + f + 1)
+ host = self.addHost( name=name, cls=TrellisHost, ips=ips, gateway=gateway, mac=mac,
+ vlan=vlan_id[ ls*fanout + f ] if vlan_id[ls * fanout + f] != 0 else None,
+ dhcpClient=dhcp_client, ipv6=ipv6 )
+ if dhcp_relay and f % 2:
+ relayIndex = ls * fanout + f + 1
+ if ipv6:
+ intfs = {
+ 'relay%s-eth0' % relayIndex: { 'ipAddrs': ['2000::%dff/%d' % (leaf + ls + 2, IP6_SUBNET_CLASS)] },
+ 'relay%s-eth1' % relayIndex: { 'ipAddrs': ['2000::%d5%d/%d' % (ls + 2, f, IP6_SUBNET_CLASS)] }
+ }
+ if remote_server:
+ serverIp = '2000::99fd'
+ elif multiple_server:
+ serverIp = '2000::3fc'
+ else:
+ serverIp = '2000::3fd'
+ dhcpRelay = self.addHost(name='relay%s' % relayIndex, cls=DhcpRelay, serverIp=serverIp,
+ gateway='2000::%dff' % (ls+2), interfaces=intfs)
+ else:
+ intfs = {
+ 'relay%s-eth0' % relayIndex: { 'ipAddrs': ['10.0.%d.254/%d' % (leaf + ls + 2, IP4_SUBNET_CLASS)] },
+ 'relay%s-eth1' % relayIndex: { 'ipAddrs': ['10.0.%d.%d/%d' % (ls + 2, f + 99, IP4_SUBNET_CLASS)] }
+ }
+ if remote_server:
+ serverIp = '10.0.99.3'
+ elif multiple_server:
+ serverIp = '10.0.3.252'
+ else:
+ serverIp = '10.0.3.253'
+ dhcpRelay = self.addHost(name='relay%s' % relayIndex, cls=DhcpRelay, serverIp=serverIp,
+ gateway='10.0.%d.254' % (ls+2), interfaces=intfs)
+ self.addLink(host, dhcpRelay, **linkopts)
+ self.addLink(dhcpRelay, leafs[ls], **linkopts)
+ else:
+ self.addLink(host, leafs[ls], **linkopts)
+
+ last_ls = leafs[leaf-1]
+ # Create common components
+ # Control plane switch (for DHCP servers)
+ cs1 = self.addSwitch('cs1', cls=OVSBridge)
+ self.addLink(cs1, last_ls)
+
+ # Control plane switch (for quagga fpm)
+ cs0 = self.addSwitch('cs0', cls=OVSBridge)
+
+ # Control plane NAT (for quagga fpm)
+ nat = self.addHost('nat', cls=NAT,
+ ip='172.16.0.1/12',
+ subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
+ self.addLink(cs0, nat)
+
+ # Internal Quagga bgp1
+ intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'},
+ 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
+ bgp1 = self.addHost('bgp1', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdbgp1.conf',
+ zebraConfFile='./zebradbgp1.conf')
+ self.addLink(bgp1, last_ls)
+ self.addLink(bgp1, cs0)
+
+ # External Quagga r1
+ intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
+ 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']},
+ 'r1-eth2': {'ipAddrs': ['2000::9901/120']}}
+ r1 = self.addHost('r1', cls=BgpRouter,
+ interfaces=intfs,
+ quaggaConfFile='./bgpdr1.conf')
+ self.addLink(r1, last_ls)
+
+ # External switch behind r1
+ rs0 = self.addSwitch('rs0', cls=OVSBridge)
+ self.addLink(r1, rs0)
+
+ # External IPv4 Host behind r1
+ rh1 = self.addHost('rh1', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+ self.addLink(r1, rh1)
+
+ # External IPv6 Host behind r1
+ rh1v6 = self.addHost('rh1v6', cls=TrellisHost, ips=['2000::9902/120'], gateway='2000::9901')
+ self.addLink(r1, rh1v6)
+
+ # DHCP server
+ if ipv6:
+ if remote_server:
+ dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
+ ips=['2000::99fd/120'], gateway='2000::9901',
+ dhcpServer=True, ipv6=True)
+ self.addLink(rs0, dhcp)
+ else:
+ dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
+ ips=['2000::3fd/120'], gateway='2000::3ff',
+ dhcpServer=True, ipv6=True)
+ self.addLink(dhcp, cs1)
+ if multiple_server:
+ dhcp2 = self.addHost('dhcp2', cls=TrellisHost, mac='00:99:00:00:00:02',
+ ips=['2000::3fc/120'], gateway='2000::3ff',
+ dhcpServer=True, ipv6=True)
+ self.addLink(dhcp2, cs1)
+ else:
+ if remote_server:
+ dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
+ ips=['10.0.99.3/24'], gateway='10.0.99.1',
+ dhcpServer=True)
+ self.addLink(rs0, dhcp)
+ else:
+ dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
+ ips=['10.0.3.253/24'], gateway='10.0.3.254',
+ dhcpServer=True)
+ self.addLink(dhcp, cs1)
+ if multiple_server:
+ dhcp2 = self.addHost('dhcp2', cls=TrellisHost, mac='00:99:00:00:00:02',
+ ips=['10.0.3.252/24'], gateway='10.0.3.254',
+ dhcpServer=True)
+ self.addLink(dhcp2, cs1)
+
+def config( opts ):
+ spine = opts.spine
+ leaf = opts.leaf
+ fanout = opts.fanout
+ dualhomed = opts.dualhomed
+ if opts.vlan == '':
+ vlan = [0] * (((leaf / 2) if dualhomed else leaf) * fanout)
+ else:
+ vlan = [int(vlan_id) if vlan_id != '' else 0 for vlan_id in opts.vlan.split(',')]
+
+ if opts.onosIp != '':
+ controllers = opts.onosIp.split( ',' )
+ else:
+ controllers = ['127.0.0.1']
+
+ if len(vlan) != ((leaf / 2) if dualhomed else leaf ) * fanout:
+ print "Invalid vlan configuration is given."
+ return
+
+ if dualhomed:
+ if leaf % 2 == 1 or leaf == 0:
+ print "Even number of leaf switches (at least two) are needed to build dual-homed topology."
+ return
+ else:
+ topo = DualHomedLeafSpineFabric(spine=spine, leaf=leaf, fanout=fanout, vlan_id=vlan,
+ ipv6=opts.ipv6,
+ dhcp_client=opts.dhcpClient,
+ dhcp_relay=opts.dhcpRelay,
+ multiple_server=opts.multipleServer,
+ remote_server=opts.remoteServer)
+ else:
+ topo = LeafSpineFabric(spine=spine, leaf=leaf, fanout=fanout, vlan_id=vlan, ipv6=opts.ipv6,
+ dhcp_client=opts.dhcpClient,
+ dhcp_relay=opts.dhcpRelay,
+ multiple_server=opts.multipleServer,
+ remote_server=opts.remoteServer)
+
+ net = Mininet( topo=topo, link=TCLink, build=False,
+ controller=None, autoSetMacs=True )
+ i = 0
+ for ip in controllers:
+ net.addController( "c%s" % ( i ), controller=RemoteController, ip=ip )
+ i += 1
+ net.build()
+ net.start()
+ CLI( net )
+ net.stop()
+
+if __name__ == '__main__':
+ setLogLevel('info')
+ config(opts)
+ os.system('sudo mn -c')
diff --git a/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/trellislib.py b/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/trellislib.py
new file mode 100644
index 0000000..ebf6910
--- /dev/null
+++ b/TestON/tests/CHOTestMonkey/dependencies/topologies/lib/trellislib.py
@@ -0,0 +1,401 @@
+#!/usr/bin/python
+
+"""
+Libraries for Trellis hosts.
+"""
+
+import time
+import sys
+sys.path.append('..')
+from mininet.node import Host
+from routinglib import RoutedHost, RoutedHost6, Router
+
+class TaggedRoutedHost(RoutedHost):
+ """Host that can be configured with multiple IP addresses."""
+ def __init__(self, name, ips, gateway, vlan, *args, **kwargs):
+ super(RoutedHost, self).__init__(name, *args, **kwargs)
+ self.ips = ips
+ self.gateway = gateway
+ self.vlan = vlan
+ self.vlanIntf = None
+
+ def config(self, **kwargs):
+ Host.config(self, **kwargs)
+ intf = self.defaultIntf()
+ self.vlanIntf = "%s.%s" % (intf, self.vlan)
+ self.cmd('ip -4 addr flush dev %s' % intf)
+ self.cmd('ip link add link %s name %s type vlan id %s' % (intf, self.vlanIntf, self.vlan))
+ self.cmd('ip link set up %s' % self.vlanIntf)
+
+ for ip in self.ips:
+ self.cmd('ip addr add %s dev %s' % (ip, self.vlanIntf))
+
+ self.cmd('ip route add default via %s' % self.gateway)
+ intf.name = self.vlanIntf
+ self.nameToIntf[self.vlanIntf] = intf
+
+ def terminate(self, **kwargs):
+ self.cmd('ip link remove link %s' % self.vlanIntf)
+ super(TaggedRoutedHost, self).terminate()
+
+class DualHomedRoutedHost(Host):
+ def __init__(self, name, ips, gateway, *args, **kwargs):
+ super(DualHomedRoutedHost, self).__init__(name, **kwargs)
+ self.bond0 = None
+ self.ips = ips
+ self.gateway = gateway
+
+ def config(self, **kwargs):
+ super(DualHomedRoutedHost, self).config(**kwargs)
+ self.bondIntfs( self.intfs[0], self.intfs[1] )
+
+ for ip in self.ips:
+ self.cmd('ip addr add %s dev %s' % (ip, self.bond0))
+
+ self.cmd('ip route add default via %s' % self.gateway)
+
+ def bondIntfs( self, intf1, intf2, bondedName="bond0" ):
+ '''
+ Bond two interfaces together
+ intf1 - the first interface to bond
+ intf2 - the second interface to bond
+ bondedName - the prefix of the new interface name
+ '''
+ # Setup bonded interface
+ # TODO: support multiple bonded interfaces. Maybe just changed self.bond0 to a list of bonded intf names?
+ self.bond0 = "%s-%s" % ( self.name, bondedName )
+ self.cmd('modprobe bonding')
+ self.cmd('ip link add %s type bond' % self.bond0)
+ self.cmd('ip link set %s down' % intf1.name)
+ self.cmd('ip link set %s down' % intf2.name)
+ self.cmd('ip link set %s master %s' % (intf1.name, self.bond0))
+ self.cmd('ip link set %s master %s' % (intf2.name, self.bond0))
+ self.cmd('ip addr flush dev %s' % intf1.name)
+ self.cmd('ip addr flush dev %s' % intf2.name)
+ self.cmd('ip link set %s up' % self.bond0)
+ # NOTE: Issues with bonded intfs in mn data structures. Either only show bonded intf
+ # or create a custom class to handle bonded infs??
+ lowestIntf = min( [ intf1, intf2 ] )
+ highestIntf = max( [ intf1, intf2 ] )
+ lowestIntf.name = self.bond0
+ self.nameToIntf[self.bond0] = lowestIntf
+ del self.intfs[ self.ports[ highestIntf ] ]
+ del self.ports[ highestIntf ]
+
+ def terminate(self, **kwargs):
+ self.cmd('ip link set %s down' % self.bond0)
+ self.cmd('ip link delete %s' % self.bond0)
+ super(DualHomedRoutedHost, self).terminate()
+
+class DualHomedTaggedRoutedHost(DualHomedRoutedHost):
+ def __init__(self, name, ips, gateway, vlan, *args, **kwargs):
+ super(DualHomedTaggedRoutedHost, self).__init__(name, ips, gateway, *args, **kwargs)
+ self.ips = ips
+ self.gateway = gateway
+ self.vlan = vlan
+ self.vlanIntf = None
+
+ def config(self, **kwargs):
+ super(DualHomedTaggedRoutedHost, self).config(**kwargs)
+ default_intf = self.defaultIntf()
+ self.vlanIntf = "%s.%s" % (default_intf, self.vlan)
+ self.cmd('ip -4 addr flush dev %s' % default_intf)
+ self.cmd('ip link add link %s name %s type vlan id %s' % (default_intf, self.vlanIntf, self.vlan))
+ self.cmd('ip link set up %s' % self.vlanIntf)
+
+ for ip in self.ips:
+ self.cmd('ip addr add %s dev %s' % (ip, self.vlanIntf))
+
+ self.cmd('ip route add default via %s' % self.gateway)
+ default_intf.name = self.vlanIntf
+ self.nameToIntf[self.vlanIntf] = default_intf
+
+ def terminate(self, **kwargs):
+ self.cmd('ip link remove link %s' % self.vlanIntf)
+ super(DualHomedTaggedRoutedHost, self).terminate()
+
+class DhcpClient(Host):
+ def __init__(self, name, *args, **kwargs):
+ super(DhcpClient, self).__init__(name, **kwargs)
+ self.pidFile = '/run/dhclient-%s.pid' % self.name
+ self.leaseFile = '/var/lib/dhcp/dhcpclient-%s.lease' % (self.name, )
+
+ def config(self, **kwargs):
+ super(DhcpClient, self).config(**kwargs)
+ self.cmd('ip addr flush dev %s' % self.defaultIntf())
+ self.cmd('dhclient -q -4 -nw -pf %s -lf %s %s' % (self.pidFile, self.leaseFile, self.defaultIntf()))
+
+ def terminate(self, **kwargs):
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ super(DhcpClient, self).terminate()
+
+class Dhcp6Client(Host):
+ def __init__(self, name, *args, **kwargs):
+ super(Dhcp6Client, self).__init__(name, **kwargs)
+ self.pidFile = '/run/dhclient-%s.pid' % self.name
+ self.leaseFile = '/var/lib/dhcp/dhcpclient6-%s.lease' % (self.name, )
+
+ def config(self, **kwargs):
+ super(Dhcp6Client, self).config(**kwargs)
+ self.cmd('ip -4 addr flush dev %s' % self.defaultIntf())
+ self.cmd('dhclient -q -6 -nw -pf %s -lf %s %s' % (self.pidFile, self.leaseFile, self.defaultIntf()))
+
+ def terminate(self, **kwargs):
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ super(Dhcp6Client, self).terminate()
+
+class DhcpServer(RoutedHost):
+ binFile = '/usr/sbin/dhcpd'
+ pidFile = '/run/dhcp-server-dhcpd.pid'
+ configFile = './dhcpd.conf'
+ leasesFile = '/var/lib/dhcp/dhcpd.leases'
+
+ def config(self, **kwargs):
+ super(DhcpServer, self).config(**kwargs)
+ self.cmd('touch %s' % self.leasesFile)
+ self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.defaultIntf()))
+
+ def terminate(self, **kwargs):
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ super(DhcpServer, self).terminate()
+
+class Dhcp6Server(RoutedHost6):
+ binFile = '/usr/sbin/dhcpd'
+ pidFile = '/run/dhcp-server-dhcpd6.pid'
+ configFile = './dhcpd6.conf'
+ leasesFile = '/var/lib/dhcp/dhcpd6.leases'
+
+ def config(self, **kwargs):
+ super(Dhcp6Server, self).config(**kwargs)
+ linkLocalAddr = mac_to_ipv6_linklocal(kwargs['mac'])
+ self.cmd('ip -6 addr add dev %s scope link %s' % (self.defaultIntf(), linkLocalAddr))
+ self.cmd('touch %s' % self.leasesFile)
+ self.cmd('%s -q -6 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.defaultIntf()))
+
+ def terminate(self, **kwargs):
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ self.cmd('rm -rf %s' % self.leasesFile)
+ super(Dhcp6Server, self).terminate()
+
+class DhcpRelay(Router):
+ binFile = '/usr/sbin/dhcrelay'
+ pidFile = '/run/dhcp-relay.pid'
+ serverIp = None
+ gateway = None
+
+ def __init__(self, name, serverIp, gateway, *args, **kwargs):
+ super(DhcpRelay, self).__init__(name, **kwargs)
+ self.serverIp = serverIp
+ self.gateway = gateway
+
+ def config(self, **kwargs):
+ super(DhcpRelay, self).config(**kwargs)
+ ifacesStr = ' '.join(["-i " + ifaceName for ifaceName in self.interfaces.keys()])
+ self.cmd('route add default gw %s' % self.gateway)
+ self.cmd('%s -4 -a -pf %s %s %s' % (self.binFile, self.pidFile, ifacesStr, self.serverIp))
+
+ def terminate(self, **kwargs):
+ self.cmd('kill -9 `cat %s`', self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ super(DhcpRelay, self).terminate()
+
+class TaggedDhcpClient(Host):
+ def __init__(self, name, vlan, *args, **kwargs):
+ super(TaggedDhcpClient, self).__init__(name, **kwargs)
+ self.pidFile = '/run/dhclient-%s.pid' % self.name
+ self.vlan = vlan
+ self.vlanIntf = None
+
+ def config(self, **kwargs):
+ super(TaggedDhcpClient, self).config(**kwargs)
+ self.vlanIntf = "%s.%s" % (self.defaultIntf(), self.vlan)
+ self.cmd('ip addr flush dev %s' % self.defaultIntf())
+ self.cmd('ip link add link %s name %s type vlan id %s' % (self.defaultIntf(), self.vlanIntf, self.vlan))
+ self.cmd('ip link set up %s' % self.vlanIntf)
+ self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.vlanIntf))
+
+ def terminate(self, **kwargs):
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ self.cmd('ip link remove link %s' % self.vlanIntf)
+ super(TaggedDhcpClient, self).terminate()
+
+class TaggedDhcpServer(TaggedRoutedHost):
+ binFile = '/usr/sbin/dhcpd'
+ pidFile = '/run/dhcp-server/dhcpd.pid'
+ configFile = './dhcpd.conf'
+
+ def config(self, **kwargs):
+ super(TaggedDhcpServer, self).config(**kwargs)
+ self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.vlanIntf))
+
+ def terminate(self, **kwargs):
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ super(TaggedDhcpServer, self).terminate()
+
+class DualHomedDhcpClient(Host):
+ def __init__(self, name, *args, **kwargs):
+ super(DualHomedDhcpClient, self).__init__(name, **kwargs)
+ self.pidFile = '/run/dhclient-%s.pid' % self.name
+ self.bond0 = None
+
+ def config(self, **kwargs):
+ super(DualHomedDhcpClient, self).config(**kwargs)
+ self.bondIntfs( self.intfs[0], self.intfs[1] )
+ self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.bond0))
+
+ def bondIntfs( self, intf1, intf2, bondedName="bond0" ):
+ '''
+ Bond two interfaces together
+ intf1 - the first interface to bond
+ intf2 - the second interface to bond
+ bondedName - the prefix of the new interface name
+ '''
+ # Setup bonded interface
+ # TODO: support multiple bonded interfaces. Maybe just changed self.bond0 to a list of bonded intf names?
+ self.bond0 = "%s-%s" % ( self.name, bondedName )
+ self.cmd('modprobe bonding')
+ self.cmd('ip link add %s type bond' % self.bond0)
+ self.cmd('ip link set %s down' % intf1.name)
+ self.cmd('ip link set %s down' % intf2.name)
+ self.cmd('ip link set %s master %s' % (intf1.name, self.bond0))
+ self.cmd('ip link set %s master %s' % (intf2.name, self.bond0))
+ self.cmd('ip addr flush dev %s' % intf1.name)
+ self.cmd('ip addr flush dev %s' % intf2.name)
+ self.cmd('ip link set %s up' % self.bond0)
+ # NOTE: Issues with bonded intfs in mn data structures. Either only show bonded intf
+ # or create a custom class to handle bonded infs??
+ lowestIntf = min( [ intf1, intf2 ] )
+ highestIntf = max( [ intf1, intf2 ] )
+ lowestIntf.name = self.bond0
+ self.nameToIntf[self.bond0] = lowestIntf
+ del self.intfs[ self.ports[ highestIntf ] ]
+ del self.ports[ highestIntf ]
+
+ def terminate(self, **kwargs):
+ self.cmd('ip link set %s down' % self.bond0)
+ self.cmd('ip link delete %s' % self.bond0)
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ super(DualHomedDhcpClient, self).terminate()
+
+class TrellisHost(Host):
+ def __init__(self, name, ips=[], gateway="", dualHomed=False, vlan=None, dhcpClient=False, dhcpServer=False, ipv6=False, *args, **kwargs):
+ super(TrellisHost, self).__init__(name, *args, **kwargs)
+ self.dualHomed = dualHomed
+ self.bond0 = None
+ self.vlan = vlan
+ self.vlanIntf = None
+ self.dhcpClient = dhcpClient
+ self.dhcpServer = dhcpServer
+ if dhcpClient:
+ self.pidFile = '/run/dhclient-%s.pid' % self.name
+ self.leaseFile = '/var/lib/dhcp/dhcpclient%s-%s.lease' % ("6" if ipv6 else "", self.name)
+ else:
+ self.ips = ips
+ self.gateway = gateway
+ if dhcpServer:
+ self.binFile = '/usr/sbin/dhcpd'
+ self.pidFile = '/run/dhcp-server-dhcpd%s.pid' % ("6" if ipv6 else "")
+ self.configFile = './dhcpd%s.conf' % ("6" if ipv6 else "")
+ self.leasesFile = '/var/lib/dhcp/dhcpd%s.leases' % ("6" if ipv6 else "")
+ self.ipv6 = ipv6
+
+ def config(self, **kwargs):
+ super(TrellisHost, self).config(**kwargs)
+
+ if self.dualHomed:
+ self.bondIntfs( self.intfs[0], self.intfs[1] )
+
+ self.cmd('ip %s addr flush dev %s' % ("-4" if self.ipv6 else "", self.defaultIntf()))
+
+ if self.vlan:
+ # Setup vlan interface
+ defaultIntf = self.defaultIntf()
+ self.vlanIntf = "%s.%s" % (defaultIntf, self.vlan)
+ self.cmd('ip link add link %s name %s type vlan id %s' % (defaultIntf, self.vlanIntf, self.vlan))
+ self.cmd('ip link set up %s' % self.vlanIntf)
+ defaultIntf.name = self.vlanIntf
+ self.nameToIntf[self.vlanIntf] = defaultIntf
+
+ if self.dhcpClient:
+ time.sleep(3)
+ self.cmd('dhclient -q -%s -nw -pf %s -lf %s %s' % (6 if self.ipv6 else 4, self.pidFile, self.leaseFile, self.defaultIntf()))
+ else:
+ # Setup IP addresses
+ for ip in self.ips:
+ self.cmd('ip addr add %s dev %s' % (ip, self.defaultIntf()))
+ self.cmd('ip route add default via %s' % self.gateway)
+
+ if self.dhcpServer:
+ if self.ipv6:
+ linkLocalAddr = mac_to_ipv6_linklocal(kwargs['mac'])
+ self.cmd('ip -6 addr add dev %s scope link %s' % (self.defaultIntf(), linkLocalAddr))
+ self.cmd('touch %s' % self.leasesFile)
+ self.cmd('%s -q -%s -pf %s -cf %s %s' % (self.binFile, 6 if self.ipv6 else 4, self.pidFile, self.configFile, self.defaultIntf()))
+
+ def bondIntfs( self, intf1, intf2, bondedName="bond0" ):
+ '''
+ Bond two interfaces together
+ intf1 - the first interface to bond
+ intf2 - the second interface to bond
+ bondedName - the prefix of the new interface name
+ '''
+ # Setup bonded interface
+ # TODO: support multiple bonded interfaces. Maybe just changed self.bond0 to a list of bonded intf names?
+ self.bond0 = "%s-%s" % ( self.name, bondedName )
+ self.cmd('modprobe bonding')
+ self.cmd('ip link add %s type bond' % self.bond0)
+ self.cmd('ip link set %s down' % intf1.name)
+ self.cmd('ip link set %s down' % intf2.name)
+ self.cmd('ip link set %s master %s' % (intf1.name, self.bond0))
+ self.cmd('ip link set %s master %s' % (intf2.name, self.bond0))
+ self.cmd('ip addr flush dev %s' % intf1.name)
+ self.cmd('ip addr flush dev %s' % intf2.name)
+ self.cmd('ip link set %s up' % self.bond0)
+ # NOTE: Issues with bonded intfs in mn data structures. Either only show bonded intf
+ # or create a custom class to handle bonded infs??
+ lowestIntf = min( [ intf1, intf2 ] )
+ highestIntf = max( [ intf1, intf2 ] )
+ lowestIntf.name = self.bond0
+ self.nameToIntf[self.bond0] = lowestIntf
+ del self.intfs[ self.ports[ highestIntf ] ]
+ del self.ports[ highestIntf ]
+
+ def terminate(self, **kwargs):
+ if self.vlan:
+ self.cmd('ip link remove link %s' % self.vlanIntf)
+ if self.dualHomed:
+ self.cmd('ip link set %s down' % self.bond0)
+ self.cmd('ip link delete %s' % self.bond0)
+ if self.dhcpClient:
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ self.cmd('rm -rf %s' % self.leaseFile)
+ if self.dhcpServer:
+ self.cmd('kill -9 `cat %s`' % self.pidFile)
+ self.cmd('rm -rf %s' % self.pidFile)
+ super(TrellisHost, self).terminate()
+
+# Utility for IPv6
+def mac_to_ipv6_linklocal(mac):
+ '''
+ Convert mac address to link-local IPv6 address
+ '''
+ # Remove the most common delimiters; dots, dashes, etc.
+ mac_value = int(mac.translate(None, ' .:-'), 16)
+
+ # Split out the bytes that slot into the IPv6 address
+ # XOR the most significant byte with 0x02, inverting the
+ # Universal / Local bit
+ high2 = mac_value >> 32 & 0xffff ^ 0x0200
+ high1 = mac_value >> 24 & 0xff
+ low1 = mac_value >> 16 & 0xff
+ low2 = mac_value & 0xffff
+
+ return 'fe80::{:04x}:{:02x}ff:fe{:02x}:{:04x}'.format(high2, high1, low1, low2)