Thomas Vachuska | 9ee4979 | 2016-03-01 16:51:14 -0800 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | import sys |
Brian O'Connor | d6c73fb | 2016-03-04 15:24:52 -0800 | [diff] [blame] | 4 | import itertools |
| 5 | from time import sleep |
Thomas Vachuska | 9ee4979 | 2016-03-01 16:51:14 -0800 | [diff] [blame] | 6 | |
| 7 | from mininet.net import Mininet |
| 8 | from mininet.log import setLogLevel |
| 9 | from mininet.node import RemoteController |
Brian O'Connor | d6c73fb | 2016-03-04 15:24:52 -0800 | [diff] [blame] | 10 | from mininet.log import info, debug, output |
Thomas Vachuska | 9ee4979 | 2016-03-01 16:51:14 -0800 | [diff] [blame] | 11 | from mininet.util import quietRun |
| 12 | from mininet.link import TCLink |
| 13 | from mininet.cli import CLI |
| 14 | |
| 15 | class ONOSMininet( Mininet ): |
| 16 | |
| 17 | @classmethod |
| 18 | def setup( cls ): |
| 19 | cls.useArping = True if quietRun( 'which arping' ) else False |
| 20 | |
| 21 | def __init__( self, controllers=[], gratuitousArp=True, build=True, *args, **kwargs ): |
| 22 | """Create Mininet object for ONOS. |
| 23 | controllers: List of controller IP addresses |
| 24 | gratuitousArp: Send an ARP from each host to aid controller's host discovery""" |
| 25 | # discarding provided controller (if any), |
| 26 | # using list of remote controller IPs instead |
| 27 | kwargs[ 'controller' ] = None |
| 28 | |
| 29 | # delay building for a second |
| 30 | kwargs[ 'build' ] = False |
| 31 | |
| 32 | Mininet.__init__(self, *args, **kwargs ) |
| 33 | |
| 34 | self.gratArp = gratuitousArp |
| 35 | self.useArping = ONOSMininet.useArping |
| 36 | |
| 37 | info ( '*** Adding controllers\n' ) |
| 38 | ctrl_count = 0 |
| 39 | for controllerIP in controllers: |
| 40 | self.addController( 'c%d' % ctrl_count, RemoteController, ip=controllerIP ) |
| 41 | info( ' c%d (%s)\n' % ( ctrl_count, controllerIP ) ) |
| 42 | ctrl_count = ctrl_count + 1 |
| 43 | |
| 44 | if self.topo and build: |
| 45 | self.build() |
| 46 | |
| 47 | def start( self ): |
| 48 | Mininet.start( self ) |
| 49 | if self.gratArp: |
| 50 | self.waitConnected() |
| 51 | info ( '*** Sending a gratuitious ARP from each host\n' ) |
| 52 | self.gratuitousArp() |
| 53 | |
| 54 | |
| 55 | def gratuitousArp( self ): |
| 56 | "Send an ARP from each host to aid controller's host discovery; fallback to ping if necessary" |
| 57 | if self.useArping: |
| 58 | for host in self.hosts: |
| 59 | info( '%s ' % host.name ) |
| 60 | debug( host.cmd( 'arping -U -c 1 ' + host.IP() ) ) |
| 61 | info ( '\n' ) |
| 62 | else: |
| 63 | info( '\nWARNING: arping is not found, using ping instead.\n' |
| 64 | 'For higher performance, install arping: sudo apt-get install iputils-arping\n\n' ) |
| 65 | |
Brian O'Connor | d6c73fb | 2016-03-04 15:24:52 -0800 | [diff] [blame] | 66 | procs = [ s.popen( 'ping -w 0.1 -W 0.1 -c1 %s > /dev/null; printf "%s "' |
| 67 | % ( d.IP(), s.name ), shell=True ) |
| 68 | for (s, d) in zip( self.hosts, self.hosts[1:] + self.hosts[0:1] ) ] |
| 69 | for t in procs: |
| 70 | out, err = t.communicate() |
| 71 | if err: |
| 72 | info ( err ) |
| 73 | else: |
| 74 | info ( out ) |
| 75 | info ( '\n' ) |
Thomas Vachuska | 9ee4979 | 2016-03-01 16:51:14 -0800 | [diff] [blame] | 76 | |
| 77 | def pingloop( self ): |
| 78 | "Loop forever pinging the full mesh of hosts" |
| 79 | setLogLevel( 'error' ) |
| 80 | try: |
| 81 | while True: |
| 82 | self.ping() |
| 83 | finally: |
| 84 | setLogLevel( 'info' ) |
| 85 | |
Brian O'Connor | d6c73fb | 2016-03-04 15:24:52 -0800 | [diff] [blame] | 86 | def bgIperf( self, hosts=[], seconds=10 ): |
| 87 | #TODO check if the hosts are strings or objects |
| 88 | # h1 = net.getNodeByName('h1') |
| 89 | servers = [ host.popen("iperf -s") for host in hosts ] |
| 90 | |
| 91 | clients = [] |
| 92 | for pair in itertools.combinations(hosts, 2): |
| 93 | info ( '%s <--> %s\n' % ( pair[0].name, pair[1].name )) |
| 94 | cmd = "iperf -c %s -t %s" % (pair[1].IP(), seconds) |
| 95 | clients.append(pair[0].popen(cmd)) |
| 96 | |
| 97 | progress( seconds ) |
| 98 | |
| 99 | for c in clients: |
| 100 | out, err = c.communicate() |
| 101 | if err: |
| 102 | info( err ) |
| 103 | else: |
| 104 | debug( out ) |
| 105 | #TODO parse output and print summary |
| 106 | |
| 107 | for s in servers: |
| 108 | s.terminate() |
| 109 | |
| 110 | def progress(t): |
| 111 | while t > 0: |
| 112 | sys.stdout.write( '.' ) |
| 113 | t -= 1 |
| 114 | sys.stdout.flush() |
| 115 | sleep(1) |
| 116 | print |
| 117 | |
Thomas Vachuska | 9ee4979 | 2016-03-01 16:51:14 -0800 | [diff] [blame] | 118 | # Initialize ONOSMininet the first time that the class is loaded |
| 119 | ONOSMininet.setup() |
| 120 | |
Brian O'Connor | d6c73fb | 2016-03-04 15:24:52 -0800 | [diff] [blame] | 121 | def do_iperf( self, line ): |
| 122 | args = line.split() |
| 123 | if not args: |
| 124 | output( 'Provide a list of hosts.\n' ) |
| 125 | hosts = [] |
| 126 | err = False |
| 127 | for arg in args: |
| 128 | if arg not in self.mn: |
| 129 | err = True |
| 130 | error( "node '%s' not in network\n" % arg ) |
| 131 | else: |
| 132 | hosts.append( self.mn[ arg ] ) |
| 133 | if "bgIperf" in dir(self.mn) and not err: |
| 134 | self.mn.bgIperf( hosts ) |
| 135 | |
| 136 | def do_gratuitousArp( self, _line ): |
| 137 | if "gratuitousArp" in dir(self.mn): |
| 138 | self.mn.gratuitousArp() |
| 139 | else: |
| 140 | output( 'Gratuitous ARP is not support.\n' ) |
| 141 | |
| 142 | CLI.do_bgIperf = do_iperf |
| 143 | CLI.do_gratuitousArp = do_gratuitousArp |
| 144 | |
Thomas Vachuska | 9ee4979 | 2016-03-01 16:51:14 -0800 | [diff] [blame] | 145 | def run( topo, controllers=None, link=TCLink, autoSetMacs=True ): |
| 146 | if not controllers and len( sys.argv ) > 1: |
| 147 | controllers = sys.argv[ 1: ] |
| 148 | else: |
| 149 | print 'Need to provide a topology and list of controllers' |
| 150 | exit( 1 ) |
| 151 | |
| 152 | setLogLevel( 'info' ) |
| 153 | |
| 154 | net = ONOSMininet( topo=topo, controllers=controllers, link=link, autoSetMacs=autoSetMacs ) |
| 155 | net.start() |
| 156 | CLI( net ) |
| 157 | net.stop() |