コード例 #1
0
ファイル: net.py プロジェクト: ZhenyaKh/coco-beholder
 def _parsePingFull(pingOutput):
     "Parse ping output and return all data."
     errorTuple = (1, 0, 0, 0, 0, 0)
     # Check for downed link
     r = r'[uU]nreachable'
     m = re.search(r, pingOutput)
     if m is not None:
         return errorTuple
     r = r'(\d+) packets transmitted, (\d+)( packets)? received'
     m = re.search(r, pingOutput)
     if m is None:
         error('*** Error: could not parse ping output: %s\n' % pingOutput)
         return errorTuple
     sent, received = int(m.group(1)), int(m.group(2))
     r = r'rtt min/avg/max/mdev = '
     r += r'(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+) ms'
     m = re.search(r, pingOutput)
     if m is None:
         if received == 0:
             return errorTuple
         error('*** Error: could not parse ping output: %s\n' % pingOutput)
         return errorTuple
     rttmin = float(m.group(1))
     rttavg = float(m.group(2))
     rttmax = float(m.group(3))
     rttdev = float(m.group(4))
     return sent, received, rttmin, rttavg, rttmax, rttdev
コード例 #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:'vdlocalmnexec -a 1 socat STDIO %s'" % connection
        ]
    return 'localhost:' + screen, node.popen(cmd)
コード例 #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)
コード例 #4
0
ファイル: net.py プロジェクト: ZhenyaKh/coco-beholder
 def configureRoutedControlNetwork(self, ip='192.168.123.1', prefixLen=16):
     """Configure a routed control network on controller and switches.
        For use with the user datapath only right now."""
     controller = self.controllers[0]
     info(controller.name + ' <->')
     cip = ip
     snum = ipParse(ip)
     for switch in self.switches:
         info(' ' + switch.name)
         link = self.link(switch, controller, port1=0)
         sintf, cintf = link.intf1, link.intf2
         switch.controlIntf = sintf
         snum += 1
         while snum & 0xff in [0, 255]:
             snum += 1
         sip = ipStr(snum)
         cintf.setIP(cip, prefixLen)
         sintf.setIP(sip, prefixLen)
         controller.setHostRoute(sip, cintf)
         switch.setHostRoute(cip, sintf)
     info('\n')
     info('*** Testing control network\n')
     while not cintf.isUp():
         info('*** Waiting for', cintf, 'to come up\n')
         sleep(1)
     for switch in self.switches:
         while not sintf.isUp():
             info('*** Waiting for', sintf, 'to come up\n')
             sleep(1)
         if self.ping(hosts=[switch, controller]) != 0:
             error('*** Error: control network test failed\n')
             exit(1)
     info('\n')
コード例 #5
0
ファイル: moduledeps.py プロジェクト: ZhenyaKh/coco-beholder
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 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)
コード例 #6
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))
コード例 #7
0
ファイル: net.py プロジェクト: ZhenyaKh/coco-beholder
 def startTerms(self):
     "Start a terminal for each node."
     if 'DISPLAY' not in os.environ:
         error("Error starting terms: Cannot connect to display\n")
         return
     info("*** Running terms on %s\n" % os.environ['DISPLAY'])
     cleanUpScreens()
     self.terms += makeTerms(self.controllers, 'controller')
     self.terms += makeTerms(self.switches, 'switch')
     self.terms += makeTerms(self.hosts, 'host')
コード例 #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)
コード例 #9
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)
コード例 #10
0
ファイル: net.py プロジェクト: ZhenyaKh/coco-beholder
 def _parseIperf(iperfOutput):
     """Parse iperf output and return bandwidth.
        iperfOutput: string
        returns: result string"""
     r = r'([\d\.]+ \w+/sec)'
     m = re.findall(r, iperfOutput)
     if m:
         return m[-1]
     else:
         # was: raise Exception(...)
         error('could not parse iperf output: ' + iperfOutput)
         return ''
コード例 #11
0
ファイル: net.py プロジェクト: ZhenyaKh/coco-beholder
 def _parsePing(pingOutput):
     "Parse ping output and return packets sent, received."
     # Check for downed link
     if 'connect: Network is unreachable' in pingOutput:
         return 1, 0
     r = r'(\d+) packets transmitted, (\d+)( packets)? received'
     m = re.search(r, pingOutput)
     if m is None:
         error('*** Error: could not parse ping output: %s\n' % pingOutput)
         return 1, 0
     sent, received = int(m.group(1)), int(m.group(2))
     return sent, received
コード例 #12
0
 def isUp( self, setUp=False ):
     "Return whether interface is up"
     if setUp:
         cmdOutput = self.ifconfig( 'up' )
         # no output indicates success
         if cmdOutput:
             error( "Error setting %s up: %s " % ( self.name, cmdOutput ) )
             return False
         else:
             return True
     else:
         return "UP" in self.ifconfig()
コード例 #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)
コード例 #14
0
ファイル: moduledeps.py プロジェクト: ZhenyaKh/coco-beholder
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')
コード例 #15
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
コード例 #16
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
コード例 #17
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')
コード例 #18
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 -icanon min 1')
     while True:
         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:
                 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()
         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()
コード例 #19
0
ファイル: net.py プロジェクト: ZhenyaKh/coco-beholder
 def ping(self, hosts=None, timeout=None):
     """Ping between all specified hosts.
        hosts: list of hosts
        timeout: time to wait for a response, as string
        returns: ploss packet loss percentage"""
     # should we check if running?
     packets = 0
     lost = 0
     ploss = None
     if not hosts:
         hosts = self.hosts
         output('*** Ping: testing ping reachability\n')
     for node in hosts:
         output('%s -> ' % node.name)
         for dest in hosts:
             if node != dest:
                 opts = ''
                 if timeout:
                     opts = '-W %s' % timeout
                 if dest.intfs:
                     result = node.cmd('ping -c1 %s %s' % (opts, dest.IP()))
                     sent, received = self._parsePing(result)
                 else:
                     sent, received = 0, 0
                 packets += sent
                 if received > sent:
                     error('*** Error: received too many packets')
                     error('%s' % result)
                     node.cmdPrint('route')
                     exit(1)
                 lost += sent - received
                 output(('%s ' % dest.name) if received else 'X ')
         output('\n')
     if packets > 0:
         ploss = 100.0 * lost / packets
         received = packets - lost
         output("*** Results: %i%% dropped (%d/%d received)\n" %
                (ploss, received, packets))
     else:
         ploss = 0
         output("*** Warning: No packets sent\n")
     return ploss
コード例 #20
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 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
コード例 #21
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
    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]
コード例 #22
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')
コード例 #23
0
ファイル: net.py プロジェクト: ZhenyaKh/coco-beholder
 def configLinkStatus(self, src, dst, status):
     """Change status of src <-> dst links.
        src: node name
        dst: node name
        status: string {up, down}"""
     if src not in self.nameToNode:
         error('src not in network: %s\n' % src)
     elif dst not in self.nameToNode:
         error('dst not in network: %s\n' % dst)
     else:
         src = self.nameToNode[src]
         dst = self.nameToNode[dst]
         connections = src.connectionsTo(dst)
         if len(connections) == 0:
             error('src and dst not connected: %s %s\n' % (src, dst))
         for srcIntf, dstIntf in connections:
             result = srcIntf.ifconfig(status)
             if result:
                 error('link src status change failed: %s\n' % result)
             result = dstIntf.ifconfig(status)
             if result:
                 error('link dst status change failed: %s\n' % result)
コード例 #24
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')
コード例 #25
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 != '':
                error( "*** Error: %s" % output )
        debug( "cmds:", cmds, '\n' )
        debug( "outputs:", tcoutputs, '\n' )
        result[ 'tcoutputs'] = tcoutputs
        result[ 'parent' ] = parent

        return result