Example #1
0
def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ):
    """Wait until server is listening on port.
       returns True if server is listening"""
    runCmd = ( client.cmd if client else
               partial( quietRun, shell=True ) )
    if not runCmd( 'which telnet' ):
        raise Exception('Could not find telnet' )
    # pylint: disable=maybe-no-member
    serverIP = server if isinstance( server, BaseString ) else server.IP()
    cmd = ( 'echo A | telnet -e A %s %s' % ( serverIP, port ) )
    time = 0
    result = runCmd( cmd )
    while 'Connected' not in result:
        if 'No route' in result:
            rtable = runCmd( 'route' )
            error( 'no route to %s:\n%s' % ( server, rtable ) )
            return False
        if timeout and time >= timeout:
            error( 'could not connect to %s on port %d\n' % ( server, port ) )
            return False
        debug( 'waiting for', server, 'to listen on port', port, '\n' )
        info( '.' )
        sleep( .5 )
        time += .5
        result = runCmd( cmd )
    return True
Example #2
0
def tunnelX11(node, display=None):
    """Create an X11 tunnel from node:6000 to the root host
       display: display on root host (optional)
       returns: node $DISPLAY, Popen object for tunnel"""
    if display is None and 'DISPLAY' in environ:
        display = environ['DISPLAY']
    if display is None:
        error("Error: Cannot connect to display\n")
        return None, None
    host, screen = display.split(':')
    # Unix sockets should work
    if not host or host == 'unix':
        # GDM3 doesn't put credentials in .Xauthority,
        # so allow root to just connect
        quietRun('xhost +si:localuser:root')
        return display, None
    else:
        # Create a tunnel for the TCP connection
        port = 6000 + int(float(screen))
        connection = r'TCP\:%s\:%s' % (host, port)
        cmd = [
            "socat",
            "TCP-LISTEN:%d,fork,reuseaddr" % port,
            "EXEC:'mnexec -a 1 socat STDIO %s'" % connection
        ]
    return 'localhost:' + screen, node.popen(cmd)
Example #3
0
    def default(self, line):
        """Called on an input line when the command prefix is not recognized.
           Overridden to run shell commands when a node is the first
           CLI argument.  Past the first CLI argument, node names are
           automatically replaced with corresponding IP addrs."""

        first, args, line = self.parseline(line)

        if first in self.mn:
            if not args:
                error('*** Please enter a command for node: %s <cmd>\n' %
                      first)
                return
            node = self.mn[first]
            rest = args.split(' ')
            # Substitute IP addresses for node names in command
            # If updateIP() returns None, then use node name
            rest = [
                self.mn[arg].defaultIntf().updateIP() or arg
                if arg in self.mn else arg for arg in rest
            ]
            rest = ' '.join(rest)
            # Run cmd on node:
            node.sendCmd(rest)
            self.waitForNode(node)
        else:
            error('*** Unknown command: %s\n' % line)
Example #4
0
 def delayCmds(parent,
               delay=None,
               jitter=None,
               loss=None,
               max_queue_size=None):
     "Internal method: return tc commands for delay and loss"
     cmds = []
     # if delay and float(delay) < 0:
     #     error( 'Negative delay', delay, '\n' )
     # elif jitter and float(jitter) < 0:
     #     error( 'Negative jitter', jitter, '\n' )
     # elif loss and ( float(loss) < 0 or float(loss) > 100 ):
     if loss and (loss < 0 or loss > 100):
         error('Bad loss percentage', loss, '%%\n')
     else:
         # Delay/jitter/loss/max queue size
         netemargs = '%s%s%s%s' % (
             'delay %s ' % delay if delay is not None else '', '%s ' %
             jitter if jitter is not None else '', 'loss %.5f ' % loss if
             (loss is not None and loss > 0) else '', 'limit %d' %
             max_queue_size if max_queue_size is not None else '')
         if netemargs:
             cmds = [
                 '%s qdisc add dev %s ' + parent + ' handle 10: netem ' +
                 netemargs
             ]
             parent = ' parent 10:1 '
     return cmds, parent
Example #5
0
def ensureRoot():
    """Ensure that we are running as root.

    Probably we should only sudo when needed as per Big Switch's patch.
    """
    if os.getuid() != 0:
        error( '*** Mininet must run as root.\n' )
        exit( 1 )
    return
Example #6
0
def pathCheck( *args, **kwargs ):
    "Make sure each program in *args can be found in $PATH."
    moduleName = kwargs.get( 'moduleName', 'it' )
    for arg in args:
        if not quietRun( 'which ' + arg ):
            error( 'Cannot find required executable %s.\n' % arg +
                   'Please make sure that %s is installed ' % moduleName +
                   'and available in your $PATH:\n(%s)\n' % environ[ 'PATH' ] )
            exit( 1 )
Example #7
0
 def do_dpctl(self, line):
     """Run dpctl (or ovs-ofctl) command on all switches.
        Usage: dpctl command [arg1] [arg2] ..."""
     args = line.split()
     if len(args) < 1:
         error('usage: dpctl command [arg1] [arg2] ...\n')
         return
     for sw in self.mn.switches:
         output('*** ' + sw.name + ' ' + ('-' * 72) + '\n')
         output(sw.dpctl(*args))
Example #8
0
 def do_link(self, line):
     """Bring link(s) between two nodes up or down.
        Usage: link node1 node2 [up/down]"""
     args = line.split()
     if len(args) != 3:
         error('invalid number of args: link end1 end2 [up down]\n')
     elif args[2] not in ['up', 'down']:
         error('invalid type: link end1 end2 [up down]\n')
     else:
         self.mn.configLinkStatus(*args)
Example #9
0
def makeTerm(node, title='Node', term='xterm', display=None, cmd='bash'):
    """Create an X11 tunnel to the node and start up a terminal.
       node: Node object
       title: base title
       term: 'xterm' or 'gterm'
       returns: two Popen objects, tunnel and terminal"""
    title = '"%s: %s"' % (title, node.name)
    if not node.inNamespace:
        title += ' (root)'
    cmds = {
        'xterm': ['xterm', '-title', title, '-display'],
        'gterm': ['gnome-terminal', '--title', title, '--display']
    }
    if term not in cmds:
        error('invalid terminal type: %s' % term)
        return
    # Docker Hosts don't have DISPLAY. So instead of
    # X11 tunnel, we use terminals from outside Docker
    from mininet.node import Docker
    if isinstance(node, Docker):
        if not node._is_container_running():
            return []
        if display is None:
            cmds[term] = cmds[term][:-1]
        else:
            cmds[term].append(display)
        cmds[term].append('-e')
        from subprocess import Popen, PIPE
        term = Popen(cmds[term] + [
            'env TERM=ansi docker exec -it %s.%s %s' %
            (node.dnameprefix, node.name, cmd)
        ],
                     stdout=PIPE,
                     stdin=PIPE,
                     stderr=PIPE)
        if term:
            return [term]
        # Failover alternative for Docker
        # host = None --> Needs docker interface
        # port = 6000
        # from mininet.log import warn
        # warn('Warning: Docker Exec Failed. Trying TCP Connection for Terminal\n')
        # pipe = node.popen( [ 'socat', 'TCP-LISTEN:%d,fork,reuseaddr' % port,
        #     'EXEC:\'%s\',pty,stderr,setsid,sigint,sane' % cmd ] );
        # term = Popen( cmds[ term ] +
        #     [ 'socat FILE:`tty`,raw,echo=0 TCP:%s:%s' % (
        #      host, port ) ], stdout=PIPE, stdin=PIPE, stderr=PIPE )
        # return [ pipe, term ] if pipe else [ term ]
        return []
    display, tunnel = tunnelX11(node, display)
    if display is None:
        return []
    term = node.popen(cmds[term] + [display, '-e', 'env TERM=ansi %s' % cmd])
    return [tunnel, term] if tunnel else [term]
Example #10
0
 def do_x(self, line):
     """Create an X11 tunnel to the given node,
        optionally starting a client.
        Usage: x node [cmd args]"""
     args = line.split()
     if not args:
         error('usage: x node [cmd args]...\n')
     else:
         node = self.mn[args[0]]
         cmd = args[1:]
         self.mn.terms += runX11(node, cmd)
Example #11
0
 def isUp(self, setUp=False):
     "Return whether interface is up"
     if setUp:
         cmdOutput = self.ifconfig('up')
         # no output / command output indicates success
         if (len(cmdOutput) > 0 and "ifconfig" not in cmdOutput):
             error("Error setting %s up: %s " % (self.name, cmdOutput))
             return False
         else:
             return True
     else:
         return "UP" in self.ifconfig()
Example #12
0
def retry( retries, delaySecs, fn, *args, **keywords ):
    """Try something several times before giving up.
       n: number of times to retry
       delaySecs: wait this long between tries
       fn: function to call
       args: args to apply to function call"""
    tries = 0
    while not fn( *args, **keywords ) and tries < retries:
        sleep( delaySecs )
        tries += 1
    if tries >= retries:
        error( "*** gave up after %i retries\n" % tries )
        exit( 1 )
Example #13
0
 def do_xterm(self, line, term='xterm'):
     """Spawn xterm(s) for the given node(s).
        Usage: xterm node1 node2 ..."""
     args = line.split()
     if not args:
         error('usage: %s node1 node2 ...\n' % term)
     else:
         for arg in args:
             if arg not in self.mn:
                 error("node '%s' not in network\n" % arg)
             else:
                 node = self.mn[arg]
                 self.mn.terms += makeTerms([node], term=term)
Example #14
0
def moduleDeps( subtract=None, add=None ):
    """Handle module dependencies.
       subtract: string or list of module names to remove, if already loaded
       add: string or list of module names to add, if not already loaded"""
    subtract = subtract if subtract is not None else []
    add = add if add is not None else []
    if isinstance( subtract, BaseString ):
        subtract = [ subtract ]
    if isinstance( add, BaseString ):
        add = [ add ]
    for mod in subtract:
        if mod in lsmod():
            info( '*** Removing ' + mod + '\n' )
            rmmodOutput = rmmod( mod )
            if rmmodOutput:
                error( 'Error removing ' + mod + ': "%s">\n' % rmmodOutput )
                exit( 1 )
            if mod in lsmod():
                error( 'Failed to remove ' + mod + '; still there!\n' )
                exit( 1 )
    for mod in add:
        if mod not in lsmod():
            info( '*** Loading ' + mod + '\n' )
            modprobeOutput = modprobe( mod )
            if modprobeOutput:
                error( 'Error inserting ' + mod +
                       ' - is it installed and available via modprobe?\n' +
                       'Error was: "%s"\n' % modprobeOutput )
            if mod not in lsmod():
                error( 'Failed to insert ' + mod + ' - quitting.\n' )
                exit( 1 )
        else:
            debug( '*** ' + mod + ' already loaded\n' )
Example #15
0
 def waitForNode(self, node):
     "Wait for a node to finish, and print its output."
     # Pollers
     nodePoller = poll()
     nodePoller.register(node.stdout)
     bothPoller = poll()
     bothPoller.register(self.stdin, POLLIN)
     bothPoller.register(node.stdout, POLLIN)
     if self.isatty():
         # Buffer by character, so that interactive
         # commands sort of work
         quietRun('stty -isig -icanon min 1')
     while node.shell:
         try:
             bothPoller.poll()
             # XXX BL: this doesn't quite do what we want.
             if False and self.inputFile:
                 key = self.inputFile.read(1)
                 if key is not '':
                     node.write(key)
                 else:
                     self.inputFile = None
             if isReadable(self.inPoller):
                 key = self.stdin.read(1)
                 node.write(key)
             if isReadable(nodePoller):
                 data = node.monitor()
                 output(data)
             if not node.waiting:
                 quietRun('stty isig')
                 break
         except KeyboardInterrupt:
             # There is an at least one race condition here, since
             # it's possible to interrupt ourselves after we've
             # read data but before it has been printed.
             node.sendInt()
             """
                 #TODO THERE ARE YOU NEED TO SEND OWN INTERRUPT
             """
         except select.error as e:
             # pylint: disable=unpacking-non-sequence
             errno_, errmsg = e.args
             # pylint: enable=unpacking-non-sequence
             if errno_ != errno.EINTR:
                 error("select.error: %d, %s" % (errno_, errmsg))
                 node.sendInt()
Example #16
0
def moveIntfNoRetry( intf, dstNode, printError=False ):
    """Move interface to node, without retrying.
       intf: string, interface
        dstNode: destination Node
        printError: if true, print error"""
    intf = str( intf )
    cmd = 'ip link set %s netns %s' % ( intf, dstNode.pid )
    cmdOutput = quietRun( cmd )
    # If ip link set does not produce any output, then we can assume
    # that the link has been moved successfully.
    if cmdOutput:
        if printError:
            error( '*** Error: moveIntf: ' + intf +
                   ' not successfully moved to ' + dstNode.name + ':\n',
                   cmdOutput )
        return False
    return True
Example #17
0
 def do_source(self, line):
     """Read commands from an input file.
        Usage: source <file>"""
     args = line.split()
     if len(args) != 1:
         error('usage: source <file>\n')
         return
     try:
         self.inputFile = open(args[0])
         while True:
             line = self.inputFile.readline()
             if len(line) > 0:
                 self.onecmd(line)
             else:
                 break
     except IOError:
         error('error reading file %s\n' % args[0])
     self.inputFile.close()
     self.inputFile = None
Example #18
0
 def do_iperf(self, line):
     """Simple iperf TCP test between two (optionally specified) hosts.
        Usage: iperf node1 node2"""
     args = line.split()
     if not args:
         self.mn.iperf()
     elif len(args) == 2:
         hosts = []
         err = False
         for arg in args:
             if arg not in self.mn:
                 err = True
                 error("node '%s' not in network\n" % arg)
             else:
                 hosts.append(self.mn[arg])
         if not err:
             self.mn.iperf(hosts)
     else:
         error('invalid number of args: iperf src dst\n')
Example #19
0
 def do_iperfudp(self, line):
     """Simple iperf UDP test between two (optionally specified) hosts.
        Usage: iperfudp bw node1 node2"""
     args = line.split()
     if not args:
         self.mn.iperf(l4Type='UDP')
     elif len(args) == 3:
         udpBw = args[0]
         hosts = []
         err = False
         for arg in args[1:3]:
             if arg not in self.mn:
                 err = True
                 error("node '%s' not in network\n" % arg)
             else:
                 hosts.append(self.mn[arg])
         if not err:
             self.mn.iperf(hosts, l4Type='UDP', udpBw=udpBw)
     else:
         error('invalid number of args: iperfudp bw src dst\n' +
               'bw examples: 10M\n')
Example #20
0
 def do_switch(self, line):
     "Starts or stops a switch"
     args = line.split()
     if len(args) != 2:
         error('invalid number of args: switch <switch name>'
               '{start, stop}\n')
         return
     sw = args[0]
     command = args[1]
     if sw not in self.mn or self.mn.get(sw) not in self.mn.switches:
         error('invalid switch: %s\n' % args[1])
     else:
         sw = args[0]
         command = args[1]
         if command == 'start':
             self.mn.get(sw).start(self.mn.controllers)
         elif command == 'stop':
             self.mn.get(sw).stop(deleteIntfs=False)
         else:
             error('invalid command: '
                   'switch <switch name> {start, stop}\n')
Example #21
0
    def config(self,
               bw=None,
               delay=None,
               jitter=None,
               loss=None,
               gro=False,
               txo=True,
               rxo=True,
               speedup=0,
               use_hfsc=False,
               use_tbf=False,
               latency_ms=None,
               enable_ecn=False,
               enable_red=False,
               max_queue_size=None,
               **params):
        """Configure the port and set its properties.
           bw: bandwidth in b/s (e.g. '10m')
           delay: transmit delay (e.g. '1ms' )
           jitter: jitter (e.g. '1ms')
           loss: loss (e.g. '1%' )
           gro: enable GRO (False)
           txo: enable transmit checksum offload (True)
           rxo: enable receive checksum offload (True)
           speedup: experimental switch-side bw option
           use_hfsc: use HFSC scheduling
           use_tbf: use TBF scheduling
           latency_ms: TBF latency parameter
           enable_ecn: enable ECN (False)
           enable_red: enable RED (False)
           max_queue_size: queue limit parameter for netem"""

        # Support old names for parameters
        gro = not params.pop('disable_gro', not gro)

        result = Intf.config(self, **params)

        def on(isOn):
            "Helper method: bool -> 'on'/'off'"
            return 'on' if isOn else 'off'

        # Set offload parameters with ethool
        self.cmd('ethtool -K', self, 'gro', on(gro), 'tx', on(txo), 'rx',
                 on(rxo))

        # Optimization: return if nothing else to configure
        # Question: what happens if we want to reset things?
        if (bw is None and not delay and not loss and max_queue_size is None):
            return

        # Clear existing configuration
        tcoutput = self.tc('%s qdisc show dev %s')
        if "priomap" not in tcoutput and "noqueue" not in tcoutput:
            cmds = ['%s qdisc del dev %s root']
        else:
            cmds = []

        # Bandwidth limits via various methods
        bwcmds, parent = self.bwCmds(bw=bw,
                                     speedup=speedup,
                                     use_hfsc=use_hfsc,
                                     use_tbf=use_tbf,
                                     latency_ms=latency_ms,
                                     enable_ecn=enable_ecn,
                                     enable_red=enable_red)
        cmds += bwcmds

        # Delay/jitter/loss/max_queue_size using netem
        delaycmds, parent = self.delayCmds(delay=delay,
                                           jitter=jitter,
                                           loss=loss,
                                           max_queue_size=max_queue_size,
                                           parent=parent)
        cmds += delaycmds

        # Ugly but functional: display configuration info
        stuff = ((['%.2fMbit' % bw] if bw is not None else []) +
                 (['%s delay' % delay] if delay is not None else []) +
                 (['%s jitter' % jitter] if jitter is not None else []) +
                 (['%.5f%% loss' % loss] if loss is not None else []) +
                 (['ECN'] if enable_ecn else ['RED'] if enable_red else []))
        info('(' + ' '.join(stuff) + ') ')

        # Execute all the commands in our node
        debug("at map stage w/cmds: %s\n" % cmds)
        tcoutputs = [self.tc(cmd) for cmd in cmds]
        for output in tcoutputs:
            if output != '' and output != 'RTNETLINK answers: No such file or directory\r\n':
                error("*** Error: %s" % output)
        debug("cmds:", cmds, '\n')
        debug("outputs:", tcoutputs, '\n')
        result['tcoutputs'] = tcoutputs
        result['parent'] = parent

        return result
Example #22
0
    def bwCmds(self,
               bw=None,
               speedup=0,
               use_hfsc=False,
               use_tbf=False,
               latency_ms=None,
               enable_ecn=False,
               enable_red=False):
        "Return tc commands to set bandwidth"

        cmds, parent = [], ' root '

        if bw and (bw < 0 or bw > self.bwParamMax):
            error('Bandwidth limit', bw,
                  'is outside supported range 0..%d' % self.bwParamMax,
                  '- ignoring\n')
        elif bw is not None:
            # BL: this seems a bit brittle...
            if (speedup > 0 and self.node.name[0:1] == 's'):
                bw = speedup
            # This may not be correct - we should look more closely
            # at the semantics of burst (and cburst) to make sure we
            # are specifying the correct sizes. For now I have used
            # the same settings we had in the mininet-hifi code.
            if use_hfsc:
                cmds += [
                    '%s qdisc add dev %s root handle 5:0 hfsc default 1',
                    '%s class add dev %s parent 5:0 classid 5:1 hfsc sc ' +
                    'rate %fMbit ul rate %fMbit' % (bw, bw)
                ]
            elif use_tbf:
                if latency_ms is None:
                    latency_ms = 15.0 * 8 / bw
                cmds += [
                    '%s qdisc add dev %s root handle 5: tbf ' +
                    'rate %fMbit burst 15000 latency %fms' % (bw, latency_ms)
                ]
            else:
                cmds += [
                    '%s qdisc add dev %s root handle 5:0 htb default 1',
                    '%s class add dev %s parent 5:0 classid 5:1 htb ' +
                    'rate %fMbit burst 15k' % bw
                ]
            parent = ' parent 5:1 '

            # ECN or RED
            if enable_ecn:
                cmds += [
                    '%s qdisc add dev %s' + parent +
                    'handle 6: red limit 1000000 ' +
                    'min 30000 max 35000 avpkt 1500 ' + 'burst 20 ' +
                    'bandwidth %fmbit probability 1 ecn' % bw
                ]
                parent = ' parent 6: '
            elif enable_red:
                cmds += [
                    '%s qdisc add dev %s' + parent +
                    'handle 6: red limit 1000000 ' +
                    'min 30000 max 35000 avpkt 1500 ' + 'burst 20 ' +
                    'bandwidth %fmbit probability 1' % bw
                ]
                parent = ' parent 6: '
        return cmds, parent