blob: 2d7c0a57aeb0bda0dfbfae2453506869b2fff5bb [file] [log] [blame]
kaouthera3f13ca22015-05-05 15:01:41 -07001#!/usr/bin/env python
2"""
3Created on 26-Oct-2012
4
5author: Anil Kumar ( anilkumar.s@paxterrasolutions.com )
6
7
8TestON is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 2 of the License, or
11( at your option ) any later version.
12
13TestON is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with TestON. If not, see <http://www.gnu.org/licenses/>.
20
21
22MininetCliDriver is the basic driver which will handle the Mininet functions
23
24Some functions rely on STS module. To install this,
25 git clone https://github.com/jhall11/sts.git
26
27Some functions rely on a modified version of Mininet. These functions
28should all be noted in the comments. To get this MN version run these commands
29from within your Mininet folder:
30 git remote add jhall11 https://github.com/jhall11/mininet.git
31 git fetch jhall11
32 git checkout -b dynamic_topo remotes/jhall11/dynamic_topo
33 git pull
34
35
36 Note that you may need to run 'sudo make develop' if your mnexec.c file
37changed when switching branches."""
38import pexpect
39import re
40import sys
41sys.path.append( "../" )
42from math import pow
43from drivers.common.cli.emulatordriver import Emulator
44
45
46class MininetCliDriver( Emulator ):
47
48 """
49 MininetCliDriver is the basic driver which will handle
50 the Mininet functions"""
51 def __init__( self ):
52 super( Emulator, self ).__init__()
53 self.handle = self
54 self.name = None
55 self.wrapped = sys.modules[ __name__ ]
56 self.flag = 0
57
58 def connect( self, **connectargs ):
59 """
60 Here the main is the TestON instance after creating
61 all the log handles."""
62 try:
63 for key in connectargs:
64 vars( self )[ key ] = connectargs[ key ]
65
66 self.name = self.options[ 'name' ]
67 self.handle = super(
68 MininetCliDriver,
69 self ).connect(
70 user_name=self.user_name,
71 ip_address=self.ip_address,
72 port=None,
73 pwd=self.pwd )
74
75 if self.handle:
76 main.log.info( "Connection successful to the host " +
77 self.user_name +
78 "@" +
79 self.ip_address )
80 return main.TRUE
81 else:
82 main.log.error( "Connection failed to the host " +
83 self.user_name +
84 "@" +
85 self.ip_address )
86 main.log.error( "Failed to connect to the Mininet CLI" )
87 return main.FALSE
88 except pexpect.EOF:
89 main.log.error( self.name + ": EOF exception found" )
90 main.log.error( self.name + ": " + self.handle.before )
91 main.cleanup()
92 main.exit()
93 except Exception:
94 main.log.exception( self.name + ": Uncaught exception!" )
95 main.cleanup()
96 main.exit()
97
98 def startNet( self, topoFile='', args='', timeout=120 ):
99 """
100 Starts Mininet accepts a topology(.py) file and/or an optional
101 argument ,to start the mininet, as a parameter.
102 Returns main.TRUE if the mininet starts successfully and
103 main.FALSE otherwise
104 """
105 if self.handle:
106 # make sure old networks are cleaned up
107 main.log.info( self.name +
108 ": Clearing any residual state or processes" )
109 self.handle.sendline( "sudo mn -c" )
110 i = self.handle.expect( [ 'password\sfor\s',
111 'Cleanup\scomplete',
112 pexpect.EOF,
113 pexpect.TIMEOUT ],
114 timeout )
115 if i == 0:
116 # Sudo asking for password
117 main.log.info( self.name + ": Sending sudo password" )
118 self.handle.sendline( self.pwd )
119 i = self.handle.expect( [ '%s:' % self.user,
120 '\$',
121 pexpect.EOF,
122 pexpect.TIMEOUT ],
123 timeout )
124 if i == 1:
125 main.log.info( self.name + ": Clean" )
126 elif i == 2:
127 main.log.error( self.name + ": Connection terminated" )
128 elif i == 3: # timeout
129 main.log.error( self.name + ": Something while cleaning " +
130 "Mininet took too long... " )
131 # Craft the string to start mininet
132 cmdString = "sudo "
133 if topoFile is None or topoFile == '': # If no file is given
134 main.log.info( self.name + ": building fresh Mininet" )
135 cmdString += "mn "
136 if args is None or args == '':
137 # If no args given, use args from .topo file
138 args = self.options[ 'arg1' ] +\
139 " " + self.options[ 'arg2' ] +\
140 " --mac --controller " +\
141 self.options[ 'controller' ] + " " +\
142 self.options[ 'arg3' ]
143 else: # else only use given args
144 pass
145 # TODO: allow use of topo args and method args?
146 else: # Use given topology file
147 main.log.info( "Starting Mininet from topo file " + topoFile )
148 cmdString += topoFile + " "
149 if args is None:
150 args = ''
151 # TODO: allow use of args from .topo file?
152 cmdString += args
153 # Send the command and check if network started
154 self.handle.sendline( "" )
155 self.handle.expect( '\$' )
156 main.log.info( "Sending '" + cmdString + "' to " + self.name )
157 self.handle.sendline( cmdString )
158 while True:
159 i = self.handle.expect( [ 'mininet>',
160 'Exception',
161 '\*\*\*',
162 pexpect.EOF,
163 pexpect.TIMEOUT ],
164 timeout )
165 if i == 0:
166 main.log.info( self.name + ": Mininet built" )
167 return main.TRUE
168 elif i == 1:
169 response = str( self.handle.before +
170 self.handle.after )
171 self.handle.expect( '\$' )
172 response += str( self.handle.before +
173 self.handle.after )
174 main.log.error(
175 self.name +
176 ": Launching Mininet failed: " + response )
177 return main.FALSE
178 elif i == 2:
179 self.handle.expect( [ "\n",
180 pexpect.EOF,
181 pexpect.TIMEOUT ],
182 timeout )
183 main.log.info( self.handle.before )
184 elif i == 3:
185 main.log.error( self.name + ": Connection timeout" )
186 return main.FALSE
187 elif i == 4: # timeout
188 main.log.error(
189 self.name +
190 ": Something took too long... " )
191 return main.FALSE
192 # Why did we hit this part?
193 main.log.error( "startNet did not return correctly" )
194 return main.FASLE
195 else: # if no handle
196 main.log.error( self.name + ": Connection failed to the host " +
197 self.user_name + "@" + self.ip_address )
198 main.log.error( self.name + ": Failed to connect to the Mininet" )
199 return main.FALSE
200
201 def numSwitchesNlinks( self, topoType, depth, fanout ):
202 if topoType == 'tree':
203 # In tree topology, if fanout arg is not given, by default it is 2
204 if fanout is None:
205 fanout = 2
206 k = 0
207 count = 0
208 while( k <= depth - 1 ):
209 count = count + pow( fanout, k )
210 k = k + 1
211 numSwitches = count
212 while( k <= depth - 2 ):
213 # depth-2 gives you only core links and not considering
214 # edge links as seen by ONOS. If all the links including
215 # edge links are required, do depth-1
216 count = count + pow( fanout, k )
217 k = k + 1
218 numLinks = count * fanout
219 # print "num_switches for %s(%d,%d) = %d and links=%d" %(
220 # topoType,depth,fanout,numSwitches,numLinks )
221
222 elif topoType == 'linear':
223 # In linear topology, if fanout or numHostsPerSw is not given,
224 # by default it is 1
225 if fanout is None:
226 fanout = 1
227 numSwitches = depth
228 numHostsPerSw = fanout
229 totalNumHosts = numSwitches * numHostsPerSw
230 numLinks = totalNumHosts + ( numSwitches - 1 )
231 print "num_switches for %s(%d,%d) = %d and links=%d" %\
232 ( topoType, depth, fanout, numSwitches, numLinks )
233 topoDict = { "num_switches": int( numSwitches ),
234 "num_corelinks": int( numLinks ) }
235 return topoDict
236
237 def calculateSwAndLinks( self ):
238 """
239 Calculate the number of switches and links in a topo."""
240 # TODO: combine this function and numSwitchesNlinks
241 argList = self.options[ 'arg1' ].split( "," )
242 topoArgList = argList[ 0 ].split( " " )
243 argList = map( int, argList[ 1: ] )
244 topoArgList = topoArgList[ 1: ] + argList
245
246 topoDict = self.numSwitchesNlinks( *topoArgList )
247 return topoDict
248
249 def pingall( self, timeout=300, shortCircuit=False, acceptableFailed=0):
250 """
251 Verifies the reachability of the hosts using pingall command.
252 Optional parameter timeout allows you to specify how long to
253 wait for pingall to complete
254 Optional:
255 timeout(seconds) - This is the pexpect timeout; The function will
256 timeout if the amount of time between failed
257 pings exceedes this time and pingall is still
258 running
259 shortCircuit - Break the pingall based on the number of failed hosts
260 ping
261 acceptableFailed - Set the number of acceptable failed pings for the
262 function to still return main.TRUE
263 Returns:
264 main.TRUE if pingall completes with no pings dropped
265 otherwise main.FALSE"""
266 try:
267 if self.handle:
268 main.log.info(
269 self.name +
270 ": Checking reachabilty to the hosts using pingall" )
271 response = ""
272 failedPings = 0
273 returnValue = main.TRUE
274 self.handle.sendline( "pingall" )
275 while True:
276 i = self.handle.expect( [ "mininet>","X",
277 pexpect.EOF,
278 pexpect.TIMEOUT ],
279 timeout )
280 if i == 0:
281 main.log.info( self.name + ": pingall finished")
282 response += self.handle.before
283 break
284 elif i == 1:
285 response += self.handle.before + self.handle.after
286 failedPings = failedPings + 1
287 if failedPings > acceptableFailed:
288 returnValue = main.FALSE
289 if shortCircuit:
290 main.log.error( self.name +
291 ": Aborting pingall - "
292 + str( failedPings ) +
293 " pings failed" )
294 break
295 elif i == 2:
296 main.log.error( self.name +
297 ": EOF exception found" )
298 main.log.error( self.name + ": " +
299 self.handle.before )
300 main.cleanup()
301 main.exit()
302 elif i == 3:
303 response += self.handle.before
304 main.log.error( self.name +
305 ": TIMEOUT exception found" )
306 main.log.error( self.name +
307 ": " +
308 str( response ) )
309 # NOTE: Send ctrl-c to make sure pingall is done
310 self.handle.sendline( "\x03" )
311 self.handle.expect( "Interrupt" )
312 self.handle.expect( "mininet>" )
313 break
314 pattern = "Results\:"
315 main.log.info( "Pingall output: " + str( response ) )
316 if re.search( pattern, response ):
317 main.log.info( self.name + ": Pingall finished with "
318 + str( failedPings ) + " failed pings" )
319 return returnValue
320 else:
321 # NOTE: Send ctrl-c to make sure pingall is done
322 self.handle.sendline( "\x03" )
323 self.handle.expect( "Interrupt" )
324 self.handle.expect( "mininet>" )
325 return main.FALSE
326 else:
327 main.log.error( self.name + ": Connection failed to the host" )
328 main.cleanup()
329 main.exit()
330 except pexpect.TIMEOUT:
331 if response:
332 main.log.info( "Pingall output: " + str( response ) )
333 main.log.error( self.name + ": pexpect.TIMEOUT found" )
334 return main.FALSE
335 except pexpect.EOF:
336 main.log.error( self.name + ": EOF exception found" )
337 main.log.error( self.name + ": " + self.handle.before )
338 main.cleanup()
339 main.exit()
340
341 def fpingHost( self, **pingParams ):
342 """
343 Uses the fping package for faster pinging...
344 *requires fping to be installed on machine running mininet"""
345 args = utilities.parse_args( [ "SRC", "TARGET" ], **pingParams )
346 command = args[ "SRC" ] + \
347 " fping -i 100 -t 20 -C 1 -q " + args[ "TARGET" ]
348 self.handle.sendline( command )
349 self.handle.expect(
350 [ args[ "TARGET" ], pexpect.EOF, pexpect.TIMEOUT ] )
351 self.handle.expect( [ "mininet", pexpect.EOF, pexpect.TIMEOUT ] )
352 response = self.handle.before
353 if re.search( ":\s-", response ):
354 main.log.info( self.name + ": Ping fail" )
355 return main.FALSE
356 elif re.search( ":\s\d{1,2}\.\d\d", response ):
357 main.log.info( self.name + ": Ping good!" )
358 return main.TRUE
359 main.log.info( self.name + ": Install fping on mininet machine... " )
360 main.log.info( self.name + ": \n---\n" + response )
361 return main.FALSE
362
363 def pingHost( self, **pingParams ):
364 """
365 Ping from one mininet host to another
366 Currently the only supported Params: SRC and TARGET"""
367 args = utilities.parse_args( [ "SRC", "TARGET" ], **pingParams )
368 command = args[ "SRC" ] + " ping " + \
369 args[ "TARGET" ] + " -c 1 -i 1 -W 8"
370 try:
371 main.log.info( "Sending: " + command )
372 self.handle.sendline( command )
373 i = self.handle.expect( [ command, pexpect.TIMEOUT ] )
374 if i == 1:
375 main.log.error(
376 self.name +
377 ": timeout when waiting for response from mininet" )
378 main.log.error( "response: " + str( self.handle.before ) )
379 i = self.handle.expect( [ "mininet>", pexpect.TIMEOUT ] )
380 if i == 1:
381 main.log.error(
382 self.name +
383 ": timeout when waiting for response from mininet" )
384 main.log.error( "response: " + str( self.handle.before ) )
385 response = self.handle.before
386 except pexpect.EOF:
387 main.log.error( self.name + ": EOF exception found" )
388 main.log.error( self.name + ": " + self.handle.before )
389 main.cleanup()
390 main.exit()
391 main.log.info( self.name + ": Ping Response: " + response )
392 if re.search( ',\s0\%\spacket\sloss', response ):
393 main.log.info( self.name + ": no packets lost, host is reachable" )
394 main.lastResult = main.TRUE
395 return main.TRUE
396 else:
397 main.log.error(
398 self.name +
399 ": PACKET LOST, HOST IS NOT REACHABLE" )
400 main.lastResult = main.FALSE
401 return main.FALSE
402
403 def checkIP( self, host ):
404 """
405 Verifies the host's ip configured or not."""
406 if self.handle:
407 try:
408 response = self.execute(
409 cmd=host +
410 " ifconfig",
411 prompt="mininet>",
412 timeout=10 )
413 except pexpect.EOF:
414 main.log.error( self.name + ": EOF exception found" )
415 main.log.error( self.name + ": " + self.handle.before )
416 main.cleanup()
417 main.exit()
418
419 pattern = "inet\s(addr|Mask):([0-1]{1}[0-9]{1,2}|" +\
420 "2[0-4][0-9]|25[0-5]|[0-9]{1,2}).([0-1]{1}" +\
421 "[0-9]{1,2}|2[0-4][0-9]|25[0-5]|[0-9]{1,2})." +\
422 "([0-1]{1}[0-9]{1,2}|2[0-4][0-9]|25[0-5]|" +\
423 "[0-9]{1,2}).([0-1]{1}[0-9]{1,2}|2[0-4]" +\
424 "[0-9]|25[0-5]|[0-9]{1,2})"
425 # pattern = "inet addr:10.0.0.6"
426 if re.search( pattern, response ):
427 main.log.info( self.name + ": Host Ip configured properly" )
428 return main.TRUE
429 else:
430 main.log.error( self.name + ": Host IP not found" )
431 return main.FALSE
432 else:
433 main.log.error( self.name + ": Connection failed to the host" )
434
435 def verifySSH( self, **connectargs ):
436 # FIXME: Who uses this and what is the purpose? seems very specific
437 try:
438 response = self.execute(
439 cmd="h1 /usr/sbin/sshd -D&",
440 prompt="mininet>",
441 timeout=10 )
442 response = self.execute(
443 cmd="h4 /usr/sbin/sshd -D&",
444 prompt="mininet>",
445 timeout=10 )
446 for key in connectargs:
447 vars( self )[ key ] = connectargs[ key ]
448 response = self.execute(
449 cmd="xterm h1 h4 ",
450 prompt="mininet>",
451 timeout=10 )
452 except pexpect.EOF:
453 main.log.error( self.name + ": EOF exception found" )
454 main.log.error( self.name + ": " + self.handle.before )
455 main.cleanup()
456 main.exit()
457 import time
458 time.sleep( 20 )
459 if self.flag == 0:
460 self.flag = 1
461 return main.FALSE
462 else:
463 return main.TRUE
464
465 def moveHost( self, host, oldSw, newSw, ):
466 """
467 Moves a host from one switch to another on the fly
468 Note: The intf between host and oldSw when detached
469 using detach(), will still show up in the 'net'
470 cmd, because switch.detach() doesn't affect switch.intfs[]
471 (which is correct behavior since the interfaces
472 haven't moved).
473 """
474 if self.handle:
475 try:
476 # Bring link between oldSw-host down
477 cmd = "py net.configLinkStatus('" + oldSw + "'," + "'"+ host +\
478 "'," + "'down')"
479 print "cmd1= ", cmd
480 response = self.execute( cmd=cmd,
481 prompt="mininet>",
482 timeout=10 )
483
484 # Determine hostintf and Oldswitchintf
485 cmd = "px hintf,sintf = " + host + ".connectionsTo(" + oldSw +\
486 ")[0]"
487 print "cmd2= ", cmd
488 self.handle.sendline( cmd )
489 self.handle.expect( "mininet>" )
490
491 # Determine ip and mac address of the host-oldSw interface
492 cmd = "px ipaddr = hintf.IP()"
493 print "cmd3= ", cmd
494 self.handle.sendline( cmd )
495 self.handle.expect( "mininet>" )
496
497 cmd = "px macaddr = hintf.MAC()"
498 print "cmd3= ", cmd
499 self.handle.sendline( cmd )
500 self.handle.expect( "mininet>" )
501
502 # Detach interface between oldSw-host
503 cmd = "px " + oldSw + ".detach( sintf )"
504 print "cmd4= ", cmd
505 self.handle.sendline( cmd )
506 self.handle.expect( "mininet>" )
507
508 # Add link between host-newSw
509 cmd = "py net.addLink(" + host + "," + newSw + ")"
510 print "cmd5= ", cmd
511 self.handle.sendline( cmd )
512 self.handle.expect( "mininet>" )
513
514 # Determine hostintf and Newswitchintf
515 cmd = "px hintf,sintf = " + host + ".connectionsTo(" + newSw +\
516 ")[0]"
517 print "cmd6= ", cmd
518 self.handle.sendline( cmd )
519 self.handle.expect( "mininet>" )
520
521 # Attach interface between newSw-host
522 cmd = "px " + newSw + ".attach( sintf )"
523 print "cmd3= ", cmd
524 self.handle.sendline( cmd )
525 self.handle.expect( "mininet>" )
526
527 # Set ipaddress of the host-newSw interface
528 cmd = "px " + host + ".setIP( ip = ipaddr, intf = hintf)"
529 print "cmd7 = ", cmd
530 self.handle.sendline( cmd )
531 self.handle.expect( "mininet>" )
532
533 # Set macaddress of the host-newSw interface
534 cmd = "px " + host + ".setMAC( mac = macaddr, intf = hintf)"
535 print "cmd8 = ", cmd
536 self.handle.sendline( cmd )
537 self.handle.expect( "mininet>" )
538
539 cmd = "net"
540 print "cmd9 = ", cmd
541 self.handle.sendline( cmd )
542 self.handle.expect( "mininet>" )
543 print "output = ", self.handle.before
544
545 # Determine ipaddress of the host-newSw interface
546 cmd = host + " ifconfig"
547 print "cmd10= ", cmd
548 self.handle.sendline( cmd )
549 self.handle.expect( "mininet>" )
550 print "ifconfig o/p = ", self.handle.before
551
552 return main.TRUE
553 except pexpect.EOF:
554 main.log.error( self.name + ": EOF exception found" )
555 main.log.error( self.name + ": " + self.handle.before )
556 return main.FALSE
557
558 def changeIP( self, host, intf, newIP, newNetmask ):
559 """
560 Changes the ip address of a host on the fly
561 Ex: h2 ifconfig h2-eth0 10.0.1.2 netmask 255.255.255.0"""
562 if self.handle:
563 try:
564 cmd = host + " ifconfig " + intf + " " + \
565 newIP + " " + 'netmask' + " " + newNetmask
566 self.handle.sendline( cmd )
567 self.handle.expect( "mininet>" )
568 response = self.handle.before
569 main.log.info( "response = " + response )
570 main.log.info(
571 "Ip of host " +
572 host +
573 " changed to new IP " +
574 newIP )
575 return main.TRUE
576 except pexpect.EOF:
577 main.log.error( self.name + ": EOF exception found" )
578 main.log.error( self.name + ": " + self.handle.before )
579 return main.FALSE
580
581 def changeDefaultGateway( self, host, newGW ):
582 """
583 Changes the default gateway of a host
584 Ex: h1 route add default gw 10.0.1.2"""
585 if self.handle:
586 try:
587 cmd = host + " route add default gw " + newGW
588 self.handle.sendline( cmd )
589 self.handle.expect( "mininet>" )
590 response = self.handle.before
591 main.log.info( "response = " + response )
592 main.log.info(
593 "Default gateway of host " +
594 host +
595 " changed to " +
596 newGW )
597 return main.TRUE
598 except pexpect.EOF:
599 main.log.error( self.name + ": EOF exception found" )
600 main.log.error( self.name + ": " + self.handle.before )
601 return main.FALSE
602
603 def addStaticMACAddress( self, host, GW, macaddr ):
604 """
605 Changes the mac address of a gateway host"""
606 if self.handle:
607 try:
608 # h1 arp -s 10.0.1.254 00:00:00:00:11:11
609 cmd = host + " arp -s " + GW + " " + macaddr
610 self.handle.sendline( cmd )
611 self.handle.expect( "mininet>" )
612 response = self.handle.before
613 main.log.info( "response = " + response )
614 main.log.info(
615 "Mac address of gateway " +
616 GW +
617 " changed to " +
618 macaddr )
619 return main.TRUE
620 except pexpect.EOF:
621 main.log.error( self.name + ": EOF exception found" )
622 main.log.error( self.name + ": " + self.handle.before )
623 return main.FALSE
624
625 def verifyStaticGWandMAC( self, host ):
626 """
627 Verify if the static gateway and mac address assignment"""
628 if self.handle:
629 try:
630 # h1 arp -an
631 cmd = host + " arp -an "
632 self.handle.sendline( cmd )
633 self.handle.expect( "mininet>" )
634 response = self.handle.before
635 main.log.info( host + " arp -an = " + response )
636 return main.TRUE
637 except pexpect.EOF:
638 main.log.error( self.name + ": EOF exception found" )
639 main.log.error( self.name + ": " + self.handle.before )
640 return main.FALSE
641
642 def getMacAddress( self, host ):
643 """
644 Verifies the host's ip configured or not."""
645 if self.handle:
646 try:
647 response = self.execute(
648 cmd=host +
649 " ifconfig",
650 prompt="mininet>",
651 timeout=10 )
652 except pexpect.EOF:
653 main.log.error( self.name + ": EOF exception found" )
654 main.log.error( self.name + ": " + self.handle.before )
655 main.cleanup()
656 main.exit()
657
658 pattern = r'HWaddr\s([0-9A-F]{2}[:-]){5}([0-9A-F]{2})'
659 macAddressSearch = re.search( pattern, response, re.I )
660 macAddress = macAddressSearch.group().split( " " )[ 1 ]
661 main.log.info(
662 self.name +
663 ": Mac-Address of Host " +
664 host +
665 " is " +
666 macAddress )
667 return macAddress
668 else:
669 main.log.error( self.name + ": Connection failed to the host" )
670
671 def getInterfaceMACAddress( self, host, interface ):
672 """
673 Return the IP address of the interface on the given host"""
674 if self.handle:
675 try:
676 response = self.execute( cmd=host + " ifconfig " + interface,
677 prompt="mininet>", timeout=10 )
678 except pexpect.EOF:
679 main.log.error( self.name + ": EOF exception found" )
680 main.log.error( self.name + ": " + self.handle.before )
681 main.cleanup()
682 main.exit()
683
684 pattern = r'HWaddr\s([0-9A-F]{2}[:-]){5}([0-9A-F]{2})'
685 macAddressSearch = re.search( pattern, response, re.I )
686 if macAddressSearch is None:
687 main.log.info( "No mac address found in %s" % response )
688 return main.FALSE
689 macAddress = macAddressSearch.group().split( " " )[ 1 ]
690 main.log.info(
691 "Mac-Address of " +
692 host +
693 ":" +
694 interface +
695 " is " +
696 macAddress )
697 return macAddress
698 else:
699 main.log.error( "Connection failed to the host" )
700
701 def getIPAddress( self, host ):
702 """
703 Verifies the host's ip configured or not."""
704 if self.handle:
705 try:
706 response = self.execute(
707 cmd=host +
708 " ifconfig",
709 prompt="mininet>",
710 timeout=10 )
711 except pexpect.EOF:
712 main.log.error( self.name + ": EOF exception found" )
713 main.log.error( self.name + ": " + self.handle.before )
714 main.cleanup()
715 main.exit()
716
717 pattern = "inet\saddr:(\d+\.\d+\.\d+\.\d+)"
718 ipAddressSearch = re.search( pattern, response )
719 main.log.info(
720 self.name +
721 ": IP-Address of Host " +
722 host +
723 " is " +
724 ipAddressSearch.group( 1 ) )
725 return ipAddressSearch.group( 1 )
726 else:
727 main.log.error( self.name + ": Connection failed to the host" )
728
729 def getSwitchDPID( self, switch ):
730 """
731 return the datapath ID of the switch"""
732 if self.handle:
733 cmd = "py %s.dpid" % switch
734 try:
735 response = self.execute(
736 cmd=cmd,
737 prompt="mininet>",
738 timeout=10 )
739 except pexpect.EOF:
740 main.log.error( self.name + ": EOF exception found" )
741 main.log.error( self.name + ": " + self.handle.before )
742 main.cleanup()
743 main.exit()
744 pattern = r'^(?P<dpid>\w)+'
745 result = re.search( pattern, response, re.MULTILINE )
746 if result is None:
747 main.log.info(
748 "Couldn't find DPID for switch %s, found: %s" %
749 ( switch, response ) )
750 return main.FALSE
751 return str( result.group( 0 ) ).lower()
752 else:
753 main.log.error( "Connection failed to the host" )
754
755 def getDPID( self, switch ):
756 if self.handle:
757 self.handle.sendline( "" )
758 self.expect( "mininet>" )
759 cmd = "py %s.dpid" % switch
760 try:
761 response = self.execute(
762 cmd=cmd,
763 prompt="mininet>",
764 timeout=10 )
765 self.handle.expect( "mininet>" )
766 response = self.handle.before
767 return response
768 except pexpect.EOF:
769 main.log.error( self.name + ": EOF exception found" )
770 main.log.error( self.name + ": " + self.handle.before )
771 main.cleanup()
772 main.exit()
773
774 def getInterfaces( self, node ):
775 """
776 return information dict about interfaces connected to the node"""
777 if self.handle:
778 cmd = 'py "\\n".join(["name=%s,mac=%s,ip=%s,enabled=%s"' +\
779 ' % (i.name, i.MAC(), i.IP(), i.isUp())'
780 cmd += ' for i in %s.intfs.values()])' % node
781 try:
782 response = self.execute(
783 cmd=cmd,
784 prompt="mininet>",
785 timeout=10 )
786 except pexpect.EOF:
787 main.log.error( self.name + ": EOF exception found" )
788 main.log.error( self.name + ": " + self.handle.before )
789 main.cleanup()
790 main.exit()
791 return response
792 else:
793 main.log.error( "Connection failed to the node" )
794
795 def dump( self ):
796 main.log.info( self.name + ": Dump node info" )
797 try:
798 response = self.execute(
799 cmd='dump',
800 prompt='mininet>',
801 timeout=10 )
802 except pexpect.EOF:
803 main.log.error( self.name + ": EOF exception found" )
804 main.log.error( self.name + ": " + self.handle.before )
805 main.cleanup()
806 main.exit()
807 return response
808
809 def intfs( self ):
810 main.log.info( self.name + ": List interfaces" )
811 try:
812 response = self.execute(
813 cmd='intfs',
814 prompt='mininet>',
815 timeout=10 )
816 except pexpect.EOF:
817 main.log.error( self.name + ": EOF exception found" )
818 main.log.error( self.name + ": " + self.handle.before )
819 main.cleanup()
820 main.exit()
821 return response
822
823 def net( self ):
824 main.log.info( self.name + ": List network connections" )
825 try:
826 response = self.execute( cmd='net', prompt='mininet>', timeout=10 )
827 except pexpect.EOF:
828 main.log.error( self.name + ": EOF exception found" )
829 main.log.error( self.name + ": " + self.handle.before )
830 main.cleanup()
831 main.exit()
832 return response
833
834 def iperf( self, host1, host2 ):
835 main.log.info(
836 self.name +
837 ": Simple iperf TCP test between two hosts" )
838 try:
839 cmd1 = 'iperf ' + host1 + " " + host2
840 self.handle.sendline( cmd1 )
841 self.handle.expect( "mininet>" )
842 response = self.handle.before
843 if re.search( 'Results:', response ):
844 main.log.info( self.name + ": iperf test successful" )
845 return main.TRUE
846 else:
847 main.log.error( self.name + ": iperf test failed" )
848 return main.FALSE
849 except pexpect.EOF:
850 main.log.error( self.name + ": EOF exception found" )
851 main.log.error( self.name + ": " + self.handle.before )
852 main.cleanup()
853 main.exit()
854
855 def iperfudp( self ):
856 main.log.info(
857 self.name +
858 ": Simple iperf TCP test between two " +
859 "(optionally specified) hosts" )
860 try:
861 response = self.execute(
862 cmd='iperfudp',
863 prompt='mininet>',
864 timeout=10 )
865 except pexpect.EOF:
866 main.log.error( self.name + ": EOF exception found" )
867 main.log.error( self.name + ": " + self.handle.before )
868 main.cleanup()
869 main.exit()
870 return response
871
872 def nodes( self ):
873 main.log.info( self.name + ": List all nodes." )
874 try:
875 response = self.execute(
876 cmd='nodes',
877 prompt='mininet>',
878 timeout=10 )
879 except pexpect.EOF:
880 main.log.error( self.name + ": EOF exception found" )
881 main.log.error( self.name + ": " + self.handle.before )
882 main.cleanup()
883 main.exit()
884 return response
885
886 def pingpair( self ):
887 main.log.info( self.name + ": Ping between first two hosts" )
888 try:
889 response = self.execute(
890 cmd='pingpair',
891 prompt='mininet>',
892 timeout=20 )
893 except pexpect.EOF:
894 main.log.error( self.name + ": EOF exception found" )
895 main.log.error( self.name + ": " + self.handle.before )
896 main.cleanup()
897 main.exit()
898
899 if re.search( ',\s0\%\spacket\sloss', response ):
900 main.log.info( self.name + ": Ping between two hosts SUCCESSFUL" )
901 main.lastResult = main.TRUE
902 return main.TRUE
903 else:
904 main.log.error( self.name + ": PACKET LOST, HOSTS NOT REACHABLE" )
905 main.lastResult = main.FALSE
906 return main.FALSE
907
908 def link( self, **linkargs ):
909 """
910 Bring link( s ) between two nodes up or down"""
911 args = utilities.parse_args( [ "END1", "END2", "OPTION" ], **linkargs )
912 end1 = args[ "END1" ] if args[ "END1" ] is not None else ""
913 end2 = args[ "END2" ] if args[ "END2" ] is not None else ""
914 option = args[ "OPTION" ] if args[ "OPTION" ] is not None else ""
915 main.log.info(
916 "Bring link between '" +
917 end1 +
918 "' and '" +
919 end2 +
920 "' '" +
921 option +
922 "'" )
923 command = "link " + \
924 str( end1 ) + " " + str( end2 ) + " " + str( option )
925 try:
926 self.handle.sendline( command )
927 self.handle.expect( "mininet>" )
928 except pexpect.EOF:
929 main.log.error( self.name + ": EOF exception found" )
930 main.log.error( self.name + ": " + self.handle.before )
931 main.cleanup()
932 main.exit()
933 return main.TRUE
934
935 def yank( self, **yankargs ):
936 """
937 yank a mininet switch interface to a host"""
938 main.log.info( 'Yank the switch interface attached to a host' )
939 args = utilities.parse_args( [ "SW", "INTF" ], **yankargs )
940 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
941 intf = args[ "INTF" ] if args[ "INTF" ] is not None else ""
942 command = "py " + str( sw ) + '.detach("' + str(intf) + '")'
943 try:
944 response = self.execute(
945 cmd=command,
946 prompt="mininet>",
947 timeout=10 )
948 except pexpect.EOF:
949 main.log.error( self.name + ": EOF exception found" )
950 main.log.error( self.name + ": " + self.handle.before )
951 main.cleanup()
952 main.exit()
953 return main.TRUE
954
955 def plug( self, **plugargs ):
956 """
957 plug the yanked mininet switch interface to a switch"""
958 main.log.info( 'Plug the switch interface attached to a switch' )
959 args = utilities.parse_args( [ "SW", "INTF" ], **plugargs )
960 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
961 intf = args[ "INTF" ] if args[ "INTF" ] is not None else ""
962 command = "py " + str( sw ) + '.attach("' + str(intf) + '")'
963 try:
964 response = self.execute(
965 cmd=command,
966 prompt="mininet>",
967 timeout=10 )
968 except pexpect.EOF:
969 main.log.error( self.name + ": EOF exception found" )
970 main.log.error( self.name + ": " + self.handle.before )
971 main.cleanup()
972 main.exit()
973 return main.TRUE
974
975 def dpctl( self, **dpctlargs ):
976 """
977 Run dpctl command on all switches."""
978 main.log.info( 'Run dpctl command on all switches' )
979 args = utilities.parse_args( [ "CMD", "ARGS" ], **dpctlargs )
980 cmd = args[ "CMD" ] if args[ "CMD" ] is not None else ""
981 cmdargs = args[ "ARGS" ] if args[ "ARGS" ] is not None else ""
982 command = "dpctl " + cmd + " " + str( cmdargs )
983 try:
984 response = self.execute(
985 cmd=command,
986 prompt="mininet>",
987 timeout=10 )
988 except pexpect.EOF:
989 main.log.error( self.name + ": EOF exception found" )
990 main.log.error( self.name + ": " + self.handle.before )
991 main.cleanup()
992 main.exit()
993 return main.TRUE
994
995 def getVersion( self ):
996 #FIXME: What uses this? This should be refactored to get
997 # version from MN and not some other file
998 fileInput = path + '/lib/Mininet/INSTALL'
999 version = super( Mininet, self ).getVersion()
1000 pattern = 'Mininet\s\w\.\w\.\w\w*'
1001 for line in open( fileInput, 'r' ).readlines():
1002 result = re.match( pattern, line )
1003 if result:
1004 version = result.group( 0 )
1005 return version
1006
1007 def getSwController( self, sw ):
1008 """
1009 Parameters:
1010 sw: The name of an OVS switch. Example "s1"
1011 Return:
1012 The output of the command from the mininet cli
1013 or main.FALSE on timeout"""
1014 command = "sh ovs-vsctl get-controller " + str( sw )
1015 try:
1016 response = self.execute(
1017 cmd=command,
1018 prompt="mininet>",
1019 timeout=10 )
1020 if response:
1021 return response
1022 else:
1023 return main.FALSE
1024 except pexpect.EOF:
1025 main.log.error( self.name + ": EOF exception found" )
1026 main.log.error( self.name + ": " + self.handle.before )
1027 main.cleanup()
1028 main.exit()
1029
1030 def assignSwController( self, **kwargs ):
1031 """
1032 count is only needed if there is more than 1 controller"""
1033 args = utilities.parse_args( [ "COUNT" ], **kwargs )
1034 count = args[ "COUNT" ] if args != {} else 1
1035
1036 argstring = "SW"
1037 for j in range( count ):
1038 argstring = argstring + ",IP" + \
1039 str( j + 1 ) + ",PORT" + str( j + 1 )
1040 args = utilities.parse_args( argstring.split( "," ), **kwargs )
1041
1042 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1043 ptcpA = int( args[ "PORT1" ] ) + \
1044 int( sw ) if args[ "PORT1" ] is not None else ""
1045 ptcpB = "ptcp:" + str( ptcpA ) if ptcpA != "" else ""
1046
1047 command = "sh ovs-vsctl set-controller s" + \
1048 str( sw ) + " " + ptcpB + " "
1049 for j in range( count ):
1050 i = j + 1
1051 args = utilities.parse_args(
1052 [ "IP" + str( i ), "PORT" + str( i ) ], **kwargs )
1053 ip = args[
1054 "IP" +
1055 str( i ) ] if args[
1056 "IP" +
1057 str( i ) ] is not None else ""
1058 port = args[
1059 "PORT" +
1060 str( i ) ] if args[
1061 "PORT" +
1062 str( i ) ] is not None else ""
1063 tcp = "tcp:" + str( ip ) + ":" + str( port ) + \
1064 " " if ip != "" else ""
1065 command = command + tcp
1066 try:
1067 self.execute( cmd=command, prompt="mininet>", timeout=5 )
1068 except pexpect.EOF:
1069 main.log.error( self.name + ": EOF exception found" )
1070 main.log.error( self.name + ": " + self.handle.before )
1071 main.cleanup()
1072 main.exit()
1073 except Exception:
1074 main.log.exception( self.name + ": Uncaught exception!" )
1075 main.cleanup()
1076 main.exit()
1077
1078 def deleteSwController( self, sw ):
1079 """
1080 Removes the controller target from sw"""
1081 command = "sh ovs-vsctl del-controller " + str( sw )
1082 try:
1083 response = self.execute(
1084 cmd=command,
1085 prompt="mininet>",
1086 timeout=10 )
1087 except pexpect.EOF:
1088 main.log.error( self.name + ": EOF exception found" )
1089 main.log.error( self.name + ": " + self.handle.before )
1090 main.cleanup()
1091 main.exit()
1092 else:
1093 main.log.info( response )
1094
1095 def addSwitch( self, sw, **kwargs ):
1096 """
1097 adds a switch to the mininet topology
1098 NOTE: This uses a custom mn function. MN repo should be on
1099 dynamic_topo branch
1100 NOTE: cannot currently specify what type of switch
1101 required params:
1102 sw = name of the new switch as a string
1103 optional keywords:
1104 dpid = "dpid"
1105 returns: main.FALSE on an error, else main.TRUE
1106 """
1107 dpid = kwargs.get( 'dpid', '' )
1108 command = "addswitch " + str( sw ) + " " + str( dpid )
1109 try:
1110 response = self.execute(
1111 cmd=command,
1112 prompt="mininet>",
1113 timeout=10 )
1114 if re.search( "already exists!", response ):
1115 main.log.warn( response )
1116 return main.FALSE
1117 elif re.search( "Error", response ):
1118 main.log.warn( response )
1119 return main.FALSE
1120 elif re.search( "usage:", response ):
1121 main.log.warn( response )
1122 return main.FALSE
1123 else:
1124 return main.TRUE
1125 except pexpect.EOF:
1126 main.log.error( self.name + ": EOF exception found" )
1127 main.log.error( self.name + ": " + self.handle.before )
1128 main.cleanup()
1129 main.exit()
1130
1131 def delSwitch( self, sw ):
1132 """
1133 delete a switch from the mininet topology
1134 NOTE: This uses a custom mn function. MN repo should be on
1135 dynamic_topo branch
1136 required params:
1137 sw = name of the switch as a string
1138 returns: main.FALSE on an error, else main.TRUE"""
1139 command = "delswitch " + str( sw )
1140 try:
1141 response = self.execute(
1142 cmd=command,
1143 prompt="mininet>",
1144 timeout=10 )
1145 if re.search( "no switch named", response ):
1146 main.log.warn( response )
1147 return main.FALSE
1148 elif re.search( "Error", response ):
1149 main.log.warn( response )
1150 return main.FALSE
1151 elif re.search( "usage:", response ):
1152 main.log.warn( response )
1153 return main.FALSE
1154 else:
1155 return main.TRUE
1156 except pexpect.EOF:
1157 main.log.error( self.name + ": EOF exception found" )
1158 main.log.error( self.name + ": " + self.handle.before )
1159 main.cleanup()
1160 main.exit()
1161
1162 def addLink( self, node1, node2 ):
1163 """
1164 add a link to the mininet topology
1165 NOTE: This uses a custom mn function. MN repo should be on
1166 dynamic_topo branch
1167 NOTE: cannot currently specify what type of link
1168 required params:
1169 node1 = the string node name of the first endpoint of the link
1170 node2 = the string node name of the second endpoint of the link
1171 returns: main.FALSE on an error, else main.TRUE"""
1172 command = "addlink " + str( node1 ) + " " + str( node2 )
1173 try:
1174 response = self.execute(
1175 cmd=command,
1176 prompt="mininet>",
1177 timeout=10 )
1178 if re.search( "doesnt exist!", response ):
1179 main.log.warn( response )
1180 return main.FALSE
1181 elif re.search( "Error", response ):
1182 main.log.warn( response )
1183 return main.FALSE
1184 elif re.search( "usage:", response ):
1185 main.log.warn( response )
1186 return main.FALSE
1187 else:
1188 return main.TRUE
1189 except pexpect.EOF:
1190 main.log.error( self.name + ": EOF exception found" )
1191 main.log.error( self.name + ": " + self.handle.before )
1192 main.cleanup()
1193 main.exit()
1194
1195 def delLink( self, node1, node2 ):
1196 """
1197 delete a link from the mininet topology
1198 NOTE: This uses a custom mn function. MN repo should be on
1199 dynamic_topo branch
1200 required params:
1201 node1 = the string node name of the first endpoint of the link
1202 node2 = the string node name of the second endpoint of the link
1203 returns: main.FALSE on an error, else main.TRUE"""
1204 command = "dellink " + str( node1 ) + " " + str( node2 )
1205 try:
1206 response = self.execute(
1207 cmd=command,
1208 prompt="mininet>",
1209 timeout=10 )
1210 if re.search( "no node named", response ):
1211 main.log.warn( response )
1212 return main.FALSE
1213 elif re.search( "Error", response ):
1214 main.log.warn( response )
1215 return main.FALSE
1216 elif re.search( "usage:", response ):
1217 main.log.warn( response )
1218 return main.FALSE
1219 else:
1220 return main.TRUE
1221 except pexpect.EOF:
1222 main.log.error( self.name + ": EOF exception found" )
1223 main.log.error( self.name + ": " + self.handle.before )
1224 main.cleanup()
1225 main.exit()
1226
1227 def addHost( self, hostname, **kwargs ):
1228 """
1229 Add a host to the mininet topology
1230 NOTE: This uses a custom mn function. MN repo should be on
1231 dynamic_topo branch
1232 NOTE: cannot currently specify what type of host
1233 required params:
1234 hostname = the string hostname
1235 optional key-value params
1236 switch = "switch name"
1237 returns: main.FALSE on an error, else main.TRUE
1238 """
1239 switch = kwargs.get( 'switch', '' )
1240 command = "addhost " + str( hostname ) + " " + str( switch )
1241 try:
1242 response = self.execute(
1243 cmd=command,
1244 prompt="mininet>",
1245 timeout=10 )
1246 if re.search( "already exists!", response ):
1247 main.log.warn( response )
1248 return main.FALSE
1249 elif re.search( "doesnt exists!", response ):
1250 main.log.warn( response )
1251 return main.FALSE
1252 elif re.search( "Error", response ):
1253 main.log.warn( response )
1254 return main.FALSE
1255 elif re.search( "usage:", response ):
1256 main.log.warn( response )
1257 return main.FALSE
1258 else:
1259 return main.TRUE
1260 except pexpect.EOF:
1261 main.log.error( self.name + ": EOF exception found" )
1262 main.log.error( self.name + ": " + self.handle.before )
1263 main.cleanup()
1264 main.exit()
1265
1266 def delHost( self, hostname ):
1267 """
1268 delete a host from the mininet topology
1269 NOTE: This uses a custom mn function. MN repo should be on
1270 dynamic_topo branch
1271 NOTE: this uses a custom mn function
1272 required params:
1273 hostname = the string hostname
1274 returns: main.FALSE on an error, else main.TRUE"""
1275 command = "delhost " + str( hostname )
1276 try:
1277 response = self.execute(
1278 cmd=command,
1279 prompt="mininet>",
1280 timeout=10 )
1281 if re.search( "no host named", response ):
1282 main.log.warn( response )
1283 return main.FALSE
1284 elif re.search( "Error", response ):
1285 main.log.warn( response )
1286 return main.FALSE
1287 elif re.search( "usage:", response ):
1288 main.log.warn( response )
1289 return main.FALSE
1290 else:
1291 return main.TRUE
1292 except pexpect.EOF:
1293 main.log.error( self.name + ": EOF exception found" )
1294 main.log.error( self.name + ": " + self.handle.before )
1295 main.cleanup()
1296 main.exit()
1297
1298 def disconnect( self ):
1299 """
1300 Called at the end of the test to stop the mininet and
1301 disconnect the handle.
1302 """
1303 self.handle.sendline('')
1304 i = self.handle.expect( [ 'mininet>', pexpect.EOF, pexpect.TIMEOUT ],
1305 timeout=2)
1306 if i == 0:
1307 self.stopNet()
1308 elif i == 1:
1309 return main.TRUE
1310 response = main.TRUE
1311 # print "Disconnecting Mininet"
1312 if self.handle:
1313 self.handle.sendline( "exit" )
1314 self.handle.expect( "exit" )
1315 self.handle.expect( "(.*)" )
1316 else:
1317 main.log.error( "Connection failed to the host" )
1318 return response
1319
1320 def stopNet( self, fileName = "", timeout=5):
1321 """
1322 Stops mininet.
1323 Returns main.TRUE if the mininet successfully stops and
1324 main.FALSE if the pexpect handle does not exist.
1325
1326 Will cleanup and exit the test if mininet fails to stop
1327 """
1328
1329 main.log.info( self.name + ": Stopping mininet..." )
1330 response = ''
1331 if self.handle:
1332 try:
1333 self.handle.sendline("")
1334 i = self.handle.expect( [ 'mininet>',
1335 '\$',
1336 pexpect.EOF,
1337 pexpect.TIMEOUT ],
1338 timeout )
1339 if i == 0:
1340 main.log.info( "Exiting mininet..." )
1341
1342 response = self.execute(
1343 cmd="exit",
1344 prompt="(.*)",
1345 timeout=120 )
1346 main.log.info( self.name + ": Stopped")
1347 self.handle.sendline( "sudo mn -c" )
1348 response = main.TRUE
1349
1350 if i == 1:
1351 main.log.info( " Mininet trying to exit while not " +
1352 "in the mininet prompt" )
1353 elif i == 2:
1354 main.log.error( "Something went wrong exiting mininet" )
1355 elif i == 3: # timeout
1356 main.log.error( "Something went wrong exiting mininet " +
1357 "TIMEOUT" )
1358
1359 if fileName:
1360 self.handle.sendline("")
1361 self.handle.expect('\$')
1362 self.handle.sendline("sudo kill -9 \`ps -ef | grep \""+ fileName +"\" | grep -v grep | awk '{print $2}'\`")
1363 except pexpect.EOF:
1364 main.log.error( self.name + ": EOF exception found" )
1365 main.log.error( self.name + ": " + self.handle.before )
1366 main.cleanup()
1367 main.exit()
1368 else:
1369 main.log.error( self.name + ": Connection failed to the host" )
1370 response = main.FALSE
1371 return response
1372
1373 def arping( self, src, dest, destmac ):
1374 self.handle.sendline( '' )
1375 self.handle.expect( [ "mininet", pexpect.EOF, pexpect.TIMEOUT ] )
1376
1377 self.handle.sendline( src + ' arping ' + dest )
1378 try:
1379 self.handle.expect( [ destmac, pexpect.EOF, pexpect.TIMEOUT ] )
1380 main.log.info( self.name + ": ARP successful" )
1381 self.handle.expect( [ "mininet", pexpect.EOF, pexpect.TIMEOUT ] )
1382 return main.TRUE
1383 except Exception:
1384 main.log.warn( self.name + ": ARP FAILURE" )
1385 self.handle.expect( [ "mininet", pexpect.EOF, pexpect.TIMEOUT ] )
1386 return main.FALSE
1387
1388 def decToHex( self, num ):
1389 return hex( num ).split( 'x' )[ 1 ]
1390
1391 def getSwitchFlowCount( self, switch ):
1392 """
1393 return the Flow Count of the switch"""
1394 if self.handle:
1395 cmd = "sh ovs-ofctl dump-aggregate %s" % switch
1396 try:
1397 response = self.execute(
1398 cmd=cmd,
1399 prompt="mininet>",
1400 timeout=10 )
1401 except pexpect.EOF:
1402 main.log.error( self.name + ": EOF exception found" )
1403 main.log.error( self.name + " " + self.handle.before )
1404 main.cleanup()
1405 main.exit()
1406 pattern = "flow_count=(\d+)"
1407 result = re.search( pattern, response, re.MULTILINE )
1408 if result is None:
1409 main.log.info(
1410 "Couldn't find flows on switch %s, found: %s" %
1411 ( switch, response ) )
1412 return main.FALSE
1413 return result.group( 1 )
1414 else:
1415 main.log.error( "Connection failed to the Mininet host" )
1416
1417 def checkFlows( self, sw, dumpFormat=None ):
1418 if dumpFormat:
1419 command = "sh ovs-ofctl -F " + \
1420 dumpFormat + " dump-flows " + str( sw )
1421 else:
1422 command = "sh ovs-ofctl dump-flows " + str( sw )
1423 try:
1424 response = self.execute(
1425 cmd=command,
1426 prompt="mininet>",
1427 timeout=10 )
1428 return response
1429 except pexpect.EOF:
1430 main.log.error( self.name + ": EOF exception found" )
1431 main.log.error( self.name + ": " + self.handle.before )
1432 main.cleanup()
1433 main.exit()
1434
1435 def startTcpdump( self, filename, intf="eth0", port="port 6633" ):
1436 """
1437 Runs tpdump on an interface and saves the file
1438 intf can be specified, or the default eth0 is used"""
1439 try:
1440 self.handle.sendline( "" )
1441 self.handle.expect( "mininet>" )
1442 self.handle.sendline(
1443 "sh sudo tcpdump -n -i " +
1444 intf +
1445 " " +
1446 port +
1447 " -w " +
1448 filename.strip() +
1449 " &" )
1450 self.handle.sendline( "" )
1451 i = self.handle.expect( [ 'No\ssuch\device',
1452 'listening\son',
1453 pexpect.TIMEOUT,
1454 "mininet>" ],
1455 timeout=10 )
1456 main.log.warn( self.handle.before + self.handle.after )
1457 self.handle.sendline( "" )
1458 self.handle.expect( "mininet>" )
1459 if i == 0:
1460 main.log.error(
1461 self.name +
1462 ": tcpdump - No such device exists. " +
1463 "tcpdump attempted on: " +
1464 intf )
1465 return main.FALSE
1466 elif i == 1:
1467 main.log.info( self.name + ": tcpdump started on " + intf )
1468 return main.TRUE
1469 elif i == 2:
1470 main.log.error(
1471 self.name +
1472 ": tcpdump command timed out! Check interface name," +
1473 " given interface was: " +
1474 intf )
1475 return main.FALSE
1476 elif i == 3:
1477 main.log.info( self.name + ": " + self.handle.before )
1478 return main.TRUE
1479 else:
1480 main.log.error( self.name + ": tcpdump - unexpected response" )
1481 return main.FALSE
1482 except pexpect.EOF:
1483 main.log.error( self.name + ": EOF exception found" )
1484 main.log.error( self.name + ": " + self.handle.before )
1485 main.cleanup()
1486 main.exit()
1487 except Exception:
1488 main.log.exception( self.name + ": Uncaught exception!" )
1489 main.cleanup()
1490 main.exit()
1491
1492 def stopTcpdump( self ):
1493 """
1494 pkills tcpdump"""
1495 try:
1496 self.handle.sendline( "sh sudo pkill tcpdump" )
1497 self.handle.expect( "mininet>" )
1498 self.handle.sendline( "" )
1499 self.handle.expect( "mininet>" )
1500 except pexpect.EOF:
1501 main.log.error( self.name + ": EOF exception found" )
1502 main.log.error( self.name + ": " + self.handle.before )
1503 main.cleanup()
1504 main.exit()
1505 except Exception:
1506 main.log.exception( self.name + ": Uncaught exception!" )
1507 main.cleanup()
1508 main.exit()
1509
1510 def compareSwitches( self, topo, switchesJson ):
1511 """
1512 Compare mn and onos switches
1513 topo: sts TestONTopology object
1514 switchesJson: parsed json object from the onos devices api
1515
1516 This uses the sts TestONTopology object"""
1517 # main.log.debug( "Switches_json string: ", switchesJson )
1518 output = { "switches": [] }
1519 # iterate through the MN topology and pull out switches and and port
1520 # info
1521 for switch in topo.graph.switches:
1522 ports = []
1523 for port in switch.ports.values():
1524 ports.append( { 'of_port': port.port_no,
1525 'mac': str( port.hw_addr ).replace( '\'', '' ),
1526 'name': port.name } )
1527 output[ 'switches' ].append( {
1528 "name": switch.name,
1529 "dpid": str( switch.dpid ).zfill( 16 ),
1530 "ports": ports } )
1531
1532 # print "mn"
1533 # print json.dumps( output,
1534 # sort_keys=True,
1535 # indent=4,
1536 # separators=( ',', ': ' ) )
1537 # print "onos"
1538 # print json.dumps( switchesJson,
1539 # sort_keys=True,
1540 # indent=4,
1541 # separators=( ',', ': ' ) )
1542
1543 # created sorted list of dpid's in MN and ONOS for comparison
1544 mnDPIDs = []
1545 for switch in output[ 'switches' ]:
1546 mnDPIDs.append( switch[ 'dpid' ].lower() )
1547 mnDPIDs.sort()
1548 # print "List of Mininet switch DPID's"
1549 # print mnDPIDs
1550 if switchesJson == "": # if rest call fails
1551 main.log.error(
1552 self.name +
1553 ".compare_switches(): Empty JSON object given from ONOS" )
1554 return main.FALSE
1555 onos = switchesJson
1556 onosDPIDs = []
1557 for switch in onos:
1558 if switch[ 'available' ]:
1559 onosDPIDs.append(
1560 switch[ 'id' ].replace(
1561 ":",
1562 '' ).replace(
1563 "of",
1564 '' ).lower() )
1565 # else:
1566 # print "Switch is unavailable:"
1567 # print switch
1568 onosDPIDs.sort()
1569 # print "List of ONOS switch DPID's"
1570 # print onosDPIDs
1571
1572 if mnDPIDs != onosDPIDs:
1573 switchResults = main.FALSE
1574 main.log.report( "Switches in MN but not in ONOS:" )
1575 list1 = [ switch for switch in mnDPIDs if switch not in onosDPIDs ]
1576 main.log.report( str( list1 ) )
1577 main.log.report( "Switches in ONOS but not in MN:" )
1578 list2 = [ switch for switch in onosDPIDs if switch not in mnDPIDs ]
1579 main.log.report( str( list2 ) )
1580 else: # list of dpid's match in onos and mn
1581 switchResults = main.TRUE
1582 return switchResults
1583
1584 def comparePorts( self, topo, portsJson ):
1585 """
1586 Compare mn and onos ports
1587 topo: sts TestONTopology object
1588 portsJson: parsed json object from the onos ports api
1589
1590 Dependencies:
1591 1. This uses the sts TestONTopology object
1592 2. numpy - "sudo pip install numpy"
1593
1594 """
1595 # FIXME: this does not look for extra ports in ONOS, only checks that
1596 # ONOS has what is in MN
1597 from numpy import uint64
1598 portsResults = main.TRUE
1599 output = { "switches": [] }
1600 # iterate through the MN topology and pull out switches and and port
1601 # info
1602 for switch in topo.graph.switches:
1603 ports = []
1604 for port in switch.ports.values():
1605 # print port.hw_addr.toStr( separator='' )
1606 tmpPort = { 'of_port': port.port_no,
1607 'mac': str( port.hw_addr ).replace( '\'', '' ),
1608 'name': port.name,
1609 'enabled': port.enabled }
1610
1611 ports.append( tmpPort )
1612 tmpSwitch = { 'name': switch.name,
1613 'dpid': str( switch.dpid ).zfill( 16 ),
1614 'ports': ports }
1615
1616 output[ 'switches' ].append( tmpSwitch )
1617
1618 # PORTS
1619 for mnSwitch in output[ 'switches' ]:
1620 mnPorts = []
1621 onosPorts = []
1622 switchResult = main.TRUE
1623 for port in mnSwitch[ 'ports' ]:
1624 if port[ 'enabled' ]:
1625 mnPorts.append( port[ 'of_port' ] )
1626 for onosSwitch in portsJson:
1627 # print "Iterating through a new switch as seen by ONOS"
1628 # print onosSwitch
1629 if onosSwitch[ 'device' ][ 'available' ]:
1630 if onosSwitch[ 'device' ][ 'id' ].replace(
1631 ':',
1632 '' ).replace(
1633 "of",
1634 '' ) == mnSwitch[ 'dpid' ]:
1635 for port in onosSwitch[ 'ports' ]:
1636 if port[ 'isEnabled' ]:
1637 if port[ 'port' ] == 'local':
1638 # onosPorts.append( 'local' )
1639 onosPorts.append( long( uint64( -2 ) ) )
1640 else:
1641 onosPorts.append( int( port[ 'port' ] ) )
1642 break
1643 mnPorts.sort( key=float )
1644 onosPorts.sort( key=float )
1645 # print "\nPorts for Switch %s:" % ( mnSwitch[ 'name' ] )
1646 # print "\tmn_ports[] = ", mnPorts
1647 # print "\tonos_ports[] = ", onosPorts
1648 mnPortsLog = mnPorts
1649 onosPortsLog = onosPorts
1650 mnPorts = [ x for x in mnPorts ]
1651 onosPorts = [ x for x in onosPorts ]
1652
1653 # TODO: handle other reserved port numbers besides LOCAL
1654 # NOTE: Reserved ports
1655 # Local port: -2 in Openflow, ONOS shows 'local', we store as
1656 # long( uint64( -2 ) )
1657 for mnPort in mnPortsLog:
1658 if mnPort in onosPorts:
1659 # don't set results to true here as this is just one of
1660 # many checks and it might override a failure
1661 mnPorts.remove( mnPort )
1662 onosPorts.remove( mnPort )
1663 # NOTE: OVS reports this as down since there is no link
1664 # So ignoring these for now
1665 # TODO: Come up with a better way of handling these
1666 if 65534 in mnPorts:
1667 mnPorts.remove( 65534 )
1668 if long( uint64( -2 ) ) in onosPorts:
1669 onosPorts.remove( long( uint64( -2 ) ) )
1670 if len( mnPorts ): # the ports of this switch don't match
1671 switchResult = main.FALSE
1672 main.log.warn( "Ports in MN but not ONOS: " + str( mnPorts ) )
1673 if len( onosPorts ): # the ports of this switch don't match
1674 switchResult = main.FALSE
1675 main.log.warn(
1676 "Ports in ONOS but not MN: " +
1677 str( onosPorts ) )
1678 if switchResult == main.FALSE:
1679 main.log.report(
1680 "The list of ports for switch %s(%s) does not match:" %
1681 ( mnSwitch[ 'name' ], mnSwitch[ 'dpid' ] ) )
1682 main.log.warn( "mn_ports[] = " + str( mnPortsLog ) )
1683 main.log.warn( "onos_ports[] = " + str( onosPortsLog ) )
1684 portsResults = portsResults and switchResult
1685 return portsResults
1686
1687 def compareLinks( self, topo, linksJson ):
1688 """
1689 Compare mn and onos links
1690 topo: sts TestONTopology object
1691 linksJson: parsed json object from the onos links api
1692
1693 This uses the sts TestONTopology object"""
1694 # FIXME: this does not look for extra links in ONOS, only checks that
1695 # ONOS has what is in MN
1696 output = { "switches": [] }
1697 onos = linksJson
1698 # iterate through the MN topology and pull out switches and and port
1699 # info
1700 for switch in topo.graph.switches:
1701 # print "Iterating though switches as seen by Mininet"
1702 # print switch
1703 ports = []
1704 for port in switch.ports.values():
1705 # print port.hw_addr.toStr( separator='' )
1706 ports.append( { 'of_port': port.port_no,
1707 'mac': str( port.hw_addr ).replace( '\'', '' ),
1708 'name': port.name } )
1709 output[ 'switches' ].append( {
1710 "name": switch.name,
1711 "dpid": str( switch.dpid ).zfill( 16 ),
1712 "ports": ports } )
1713 # LINKS
1714
1715 mnLinks = [
1716 link for link in topo.patch_panel.network_links if (
1717 link.port1.enabled and link.port2.enabled ) ]
1718 if 2 * len( mnLinks ) == len( onos ):
1719 linkResults = main.TRUE
1720 else:
1721 linkResults = main.FALSE
1722 main.log.report(
1723 "Mininet has " + str( len( mnLinks ) ) +
1724 " bidirectional links and ONOS has " +
1725 str( len( onos ) ) + " unidirectional links" )
1726
1727 # iterate through MN links and check if an ONOS link exists in
1728 # both directions
1729 # NOTE: Will currently only show mn links as down if they are
1730 # cut through STS. We can either do everything through STS or
1731 # wait for upNetworkLinks and downNetworkLinks to be
1732 # fully implemented.
1733 for link in mnLinks:
1734 # print "Link: %s" % link
1735 # TODO: Find a more efficient search method
1736 node1 = None
1737 port1 = None
1738 node2 = None
1739 port2 = None
1740 firstDir = main.FALSE
1741 secondDir = main.FALSE
1742 for switch in output[ 'switches' ]:
1743 # print "Switch: %s" % switch[ 'name' ]
1744 if switch[ 'name' ] == link.node1.name:
1745 node1 = switch[ 'dpid' ]
1746 for port in switch[ 'ports' ]:
1747 if str( port[ 'name' ] ) == str( link.port1 ):
1748 port1 = port[ 'of_port' ]
1749 if node1 is not None and node2 is not None:
1750 break
1751 if switch[ 'name' ] == link.node2.name:
1752 node2 = switch[ 'dpid' ]
1753 for port in switch[ 'ports' ]:
1754 if str( port[ 'name' ] ) == str( link.port2 ):
1755 port2 = port[ 'of_port' ]
1756 if node1 is not None and node2 is not None:
1757 break
1758
1759 for onosLink in onos:
1760 onosNode1 = onosLink[ 'src' ][ 'device' ].replace(
1761 ":",
1762 '' ).replace(
1763 "of",
1764 '' )
1765 onosNode2 = onosLink[ 'dst' ][ 'device' ].replace(
1766 ":",
1767 '' ).replace(
1768 "of",
1769 '' )
1770 onosPort1 = onosLink[ 'src' ][ 'port' ]
1771 onosPort2 = onosLink[ 'dst' ][ 'port' ]
1772
1773 # check onos link from node1 to node2
1774 if str( onosNode1 ) == str( node1 ) and str(
1775 onosNode2 ) == str( node2 ):
1776 if int( onosPort1 ) == int( port1 ) and int(
1777 onosPort2 ) == int( port2 ):
1778 firstDir = main.TRUE
1779 else:
1780 main.log.warn(
1781 'The port numbers do not match for ' +
1782 str( link ) +
1783 ' between ONOS and MN. When checking ONOS for ' +
1784 'link %s/%s -> %s/%s' %
1785 ( node1,
1786 port1,
1787 node2,
1788 port2 ) +
1789 ' ONOS has the values %s/%s -> %s/%s' %
1790 ( onosNode1,
1791 onosPort1,
1792 onosNode2,
1793 onosPort2 ) )
1794
1795 # check onos link from node2 to node1
1796 elif ( str( onosNode1 ) == str( node2 ) and
1797 str( onosNode2 ) == str( node1 ) ):
1798 if ( int( onosPort1 ) == int( port2 )
1799 and int( onosPort2 ) == int( port1 ) ):
1800 secondDir = main.TRUE
1801 else:
1802 main.log.warn(
1803 'The port numbers do not match for ' +
1804 str( link ) +
1805 ' between ONOS and MN. When checking ONOS for ' +
1806 'link %s/%s -> %s/%s' %
1807 ( node2,
1808 port2,
1809 node1,
1810 port1 ) +
1811 ' ONOS has the values %s/%s -> %s/%s' %
1812 ( onosNode2,
1813 onosPort2,
1814 onosNode1,
1815 onosPort1 ) )
1816 else: # this is not the link you're looking for
1817 pass
1818 if not firstDir:
1819 main.log.report(
1820 'ONOS does not have the link %s/%s -> %s/%s' %
1821 ( node1, port1, node2, port2 ) )
1822 if not secondDir:
1823 main.log.report(
1824 'ONOS does not have the link %s/%s -> %s/%s' %
1825 ( node2, port2, node1, port1 ) )
1826 linkResults = linkResults and firstDir and secondDir
1827 return linkResults
1828
1829 def compareHosts( self, topo, hostsJson ):
1830 """
1831 Compare mn and onos Hosts.
1832 Since Mininet hosts are quiet, ONOS will only know of them when they
1833 speak. For this reason, we will only check that the hosts in ONOS
1834 stores are in Mininet, and not vice versa.
1835 topo: sts TestONTopology object
1836 hostsJson: parsed json object from the onos hosts api
1837
1838 This uses the sts TestONTopology object"""
1839 import json
1840 hostResults = main.TRUE
1841 hosts = []
1842 # iterate through the MN topology and pull out hosts
1843 for mnHost in topo.graph.hosts:
1844 interfaces = []
1845 for intf in mnHost.interfaces:
1846 interfaces.append( {
1847 "name": intf.name, # str
1848 "ips": [ str( ip ) for ip in intf.ips ], # list of IPAddrs
1849 # hw_addr is of type EthAddr, Not JSON serializable
1850 "hw_addr": str( intf.hw_addr ) } )
1851 hosts.append( {
1852 "name": mnHost.name, # str
1853 "interfaces": interfaces } ) # list
1854 for onosHost in hostsJson:
1855 onosMAC = onosHost[ 'mac' ].lower()
1856 match = False
1857 for mnHost in hosts:
1858 for mnIntf in mnHost[ 'interfaces' ]:
1859 if onosMAC == mnIntf[ 'hw_addr' ].lower() :
1860 match = True
1861 for ip in mnIntf[ 'ips' ]:
1862 if ip in onosHost[ 'ips' ]:
1863 pass # all is well
1864 else:
1865 # misssing ip
1866 main.log.error( "ONOS host " + onosHost[ 'id' ]
1867 + " has a different IP than " +
1868 "the Mininet host." )
1869 output = json.dumps(
1870 onosHost,
1871 sort_keys=True,
1872 indent=4,
1873 separators=( ',', ': ' ) )
1874 main.log.info( output )
1875 hostResults = main.FALSE
1876 if not match:
1877 hostResults = main.FALSE
1878 main.log.error( "ONOS host " + onosHost[ 'id' ] + " has no " +
1879 "corresponding Mininet host." )
1880 output = json.dumps( onosHost,
1881 sort_keys=True,
1882 indent=4,
1883 separators=( ',', ': ' ) )
1884 main.log.info( output )
1885 return hostResults
1886
1887 def getHosts( self ):
1888 """
1889 Returns a list of all hosts
1890 Don't ask questions just use it"""
1891 self.handle.sendline( "" )
1892 self.handle.expect( "mininet>" )
1893
1894 self.handle.sendline( "py [ host.name for host in net.hosts ]" )
1895 self.handle.expect( "mininet>" )
1896
1897 handlePy = self.handle.before
1898 handlePy = handlePy.split( "]\r\n", 1 )[ 1 ]
1899 handlePy = handlePy.rstrip()
1900
1901 self.handle.sendline( "" )
1902 self.handle.expect( "mininet>" )
1903
1904 hostStr = handlePy.replace( "]", "" )
1905 hostStr = hostStr.replace( "'", "" )
1906 hostStr = hostStr.replace( "[", "" )
1907 hostList = hostStr.split( "," )
1908
1909 return hostList
1910
1911 def update( self ):
1912 """
1913 updates the port address and status information for
1914 each port in mn"""
1915 # TODO: Add error checking. currently the mininet command has no output
1916 main.log.info( "Updating MN port information" )
1917 try:
1918 self.handle.sendline( "" )
1919 self.handle.expect( "mininet>" )
1920
1921 self.handle.sendline( "update" )
1922 self.handle.expect( "update" )
1923 self.handle.expect( "mininet>" )
1924
1925 self.handle.sendline( "" )
1926 self.handle.expect( "mininet>" )
1927
1928 return main.TRUE
1929 except pexpect.EOF:
1930 main.log.error( self.name + ": EOF exception found" )
1931 main.log.error( self.name + ": " + self.handle.before )
1932 main.cleanup()
1933 main.exit()
1934
1935if __name__ != "__main__":
1936 import sys
1937 sys.modules[ __name__ ] = MininetCliDriver()