def runCpuLimitTest(self, cpu, duration=5): """run CPU limit test with 'while true' processes. cpu: desired CPU fraction of each host duration: test duration in seconds returns a single list of measured CPU fractions as floats. """ pct = cpu * 100 info("*** Testing CPU %.0f%% bandwidth limit\n" % pct) hosts = self.hosts for h in hosts: h.cmd("while true; do a=1; done &") pids = [h.cmd("echo $!").strip() for h in hosts] pids_str = ",".join(["%s" % pid for pid in pids]) cmd = "ps -p %s -o pid,%%cpu,args" % pids_str # It's a shame that this is what pylint prefers outputs = [] for _ in range(duration): sleep(1) outputs.append(quietRun(cmd).strip()) for h in hosts: h.cmd("kill $!") cpu_fractions = [] for test_output in outputs: # Split by line. Ignore first line, which looks like this: # PID %CPU COMMAND\n for line in test_output.split("\n")[1:]: r = r"\d+\s*(\d+\.\d+)" m = re.search(r, line) if m is None: error("*** Error: could not extract CPU fraction: %s\n" % line) return None cpu_fractions.append(float(m.group(1))) output("*** Results: %s\n" % cpu_fractions) return cpu_fractions
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: print "*** Enter a command for node: %s <cmd>" % 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: builtin = isShellBuiltin( first ) node.sendCmd( rest, printPid=( not builtin ) ) self.waitForNode( node ) else: error( '*** Unknown command: %s\n' % line )
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+) 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: 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
def do_detach( self, line ): "Detach a host from a switch" args = line.split() if len(args) < 1 or len(args) > 2: error( 'invalid number of args: detach host [switch]\n' ) else: self.mn.detachHost(*args)
def findTap(node, port, path=None): """utility function to parse through a sys.config file to find tap interfaces for a switch""" switch = False portLine = "" intfLines = [] if path is None: path = "%s/rel/linc/releases/1.0/sys.config" % LINCSwitch.lincDir with open(path) as f: for line in f: if "tap" in line: intfLines.append(line) if node.dpid in line.translate(None, ":"): switch = True continue if switch: if "switch" in line: switch = False if "port_no,%s}" % port in line: portLine = line break if portLine: m = re.search("port,\d+", portLine) port = m.group(0).split(",")[1] else: error("***ERROR: Could not find any ports in sys.config\n") return for intfLine in intfLines: if "port,%s" % port in intfLine: return re.findall("tap\d+", intfLine)[0]
def startShell( self ): if self.shell: error( "%s: shell is already running" ) return subprocess.call(["docker stop "+self.name], shell=True, stdout=output) subprocess.call(["docker rm -f "+self.name], shell=True, stdout=output) cmd = ["docker","run","--privileged","-h",self.name ,"--name="+self.name,"-v", "/vagrant:/home/ubuntu"] if self.dargs is not None: cmd.extend([self.dargs]) cmd.extend(["--net='none'",self.image, self.startString]) self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True ) self.stdin = self.shell.stdin self.stdout = self.shell.stdout self.pid = self.shell.pid self.pollOut = select.poll() self.pollOut.register( self.stdout ) self.outToNode[ self.stdout.fileno() ] = self self.inToNode[ self.stdin.fileno() ] = self self.execed = False self.lastCmd = None self.lastPid = None self.readbuf = '' self.waiting = False call("sleep 1", shell=True) pid_cmd = ["docker","inspect","--format='{{ .State.Pid }}'",""+self.name] pidp = Popen( pid_cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=False ) ps_out = pidp.stdout.readlines() self.pid = int(ps_out[0])
def startShell( self ): "Start a shell process for running commands" if self.shell: error( "%s: shell is already running" ) return # mnexec: (c)lose descriptors, (d)etach from tty, # (p)rint pid, and run in (n)amespace opts = '-cdp' if self.inNamespace: opts += 'n' # bash -m: enable job control cmd = [ 'mnexec', opts, 'bash', '-m' ] self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True ) self.stdin = self.shell.stdin self.stdout = self.shell.stdout self.pid = self.shell.pid self.pollOut = select.poll() self.pollOut.register( self.stdout ) # Maintain mapping between file descriptors and nodes # This is useful for monitoring multiple nodes # using select.poll() self.outToNode[ self.stdout.fileno() ] = self self.inToNode[ self.stdin.fileno() ] = self self.execed = False self.lastCmd = None self.lastPid = None self.readbuf = '' self.waiting = False
def default( self, line ): """Called on an input line when the command prefix is not recognized. Overridden to run shell commands when a component is the first CLI argument. Past the first CLI argument, component names are then automatically replaced with corresponding node IP addrs.""" first, args, line = self.parseline( line ) if not args: return if args and len(args) > 0 and args[ -1 ] == '\n': args = args[ :-1 ] rest = args.split( ' ' ) if first in self.cn: comp = self.cn[ first ] # Substitute IP addresses for node names in command rest = [ self.cn[ arg ].node.defaultIntf().updateIP() if arg in self.cn else arg for arg in rest ] rest = ' '.join( rest ) # Run cmd on node: builtin = isShellBuiltin( first ) comp.node.sendCmd( rest, printPid=( not builtin ) ) self.waitForNode( comp.node ) else: error( '*** Unknown command: %s\n' % first )
def _configLinkIntfs(srcIntf, dstIntf, status): 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 )
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 ) sintf, cintf = createLink( switch, controller ) snum += 1 while snum & 0xff in [ 0, 255 ]: snum += 1 sip = ipStr( snum ) controller.setIP( cintf, cip, prefixLen ) switch.setIP( sintf, sip, prefixLen ) controller.setHostRoute( sip, cintf ) switch.setHostRoute( cip, sintf ) info( '\n' ) info( '*** Testing control network\n' ) while not controller.intfIsUp( cintf ): info( '*** Waiting for', cintf, 'to come up\n' ) sleep( 1 ) for switch in self.switches: while not switch.intfIsUp( sintf ): 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' )
def attachHost( self, hostName, switchName ): if hostName not in self.nameToNode: error( 'host not in network: %s\n' % hostName ) return if switchName not in self.nameToNode: error( 'switch not in network: %s\n' % switchName ) return host = self.nameToNode[hostName] if not isinstance(host, Host): error('%s is not a host' % hostName) return sw = self.nameToNode[switchName] if not isinstance(sw, Switch): error('%s is not a switch' % switchName) return if not isinstance(sw, OVSKernelSwitch) and not isinstance(sw, OVSKernelSwitchNew): error('attachHost only works with OVS kernel switches') return hostIntf, swIntf = host.linkTo(sw) host.setIP( hostIntf, host.defaultIP, self.cparams.prefixLen ) host.setDefaultRoute( hostIntf ) if self.autoSetMacs: host.setMAC( hostIntf, host.defaultMAC )
def get_if_index(self, in_if_name): output = self.cmd('ovs-vsctl --db=unix:%s/db.sock --no-wait find Interface name=%s' %(self.path_ovs, in_if_name)) if output != None and output != "" : return re.search( r'ofport(.*): (\d*)', output).group(2) else: error("ERROR port not available\n") sys.exit(-2)
def translate_rule(self, rule): # ports reg exp out_port = re.compile('output:(.*?),') in_port = re.compile('in_port=(.*?),') out_port_end = "," #test if rule has in_port if 'in_port' in rule and not re.search(in_port, rule): error("ERROR wrong format for in_port\n") sys.exit(-2) elif 'in_port' in rule and re.search(in_port, rule): in_if_name = in_port.search(rule).group(1) in_if_index = self.get_if_index(in_if_name) rule = re.sub(in_port, "in_port="+in_if_index+",", rule) #test if rule has output_port if 'output' in rule and not re.search(out_port, rule): #print "output: not followed by comma, retry.." out_port = re.compile('output:(.*?)\"(\Z)') out_port_end = "\"" if not re.search(out_port, rule): error("ERROR wrong format for out_put port\n") sys.exit(-2) out_if_name = out_port.search(rule).group(1) out_if_index = self.get_if_index(out_if_name) rule = re.sub(out_port, "output:"+out_if_index+out_port_end, rule) elif 'output' in rule and re.search(out_port, rule): out_if_name = out_port.search(rule).group(1) out_if_index = self.get_if_index(out_if_name) rule = re.sub(out_port, "output:"+out_if_index+out_port_end, rule) return rule
def start( self, controllers = [], intfs_to_data = [], coex={}): info("%s " % self.name) if len(controllers) == 0: info("WARNING %s Controllers\n" % len(controllers)) if len(intfs_to_data) == 0: error("ERROR configuration is not possibile for %s\n" % self.name) sys.exit(-2) # Running SSHD self.cmd('chown root:root /var/run/sshd') self.cmd('chmod 711 /var/run/sshd') self.cmd('/usr/sbin/sshd -o UseDNS=no -u0') if coex == {}: error("ERROR coexistence is {}\n") sys.exit(-2) lo_data = {'intfname':'lo', 'ip':'%s' %(self.loopback), 'ingrtype':None, 'ingrdata':None, 'net':{ 'net':self.loopback, 'netbit':32, 'cost':1, 'hello':5, 'area':'0.0.0.0'}} self.initial_configuration(controllers) self.configure_ovs(intfs_to_data, coex) self.configure_quagga(intfs_to_data, lo_data, coex) self.final_configuration(intfs_to_data)
def start_pw( self, table, pws_data = []): if self.OF_V != "OpenFlow13" and len(pws_data) != 0: error("ERROR PW configuration is not possibile for %s - OpenFlow version != 1.3\n" % self.name) sys.exit(-2) rules = [] # TODO In futuro incapsularlo for pw_data in pws_data: eth = pw_data['eth'] v_eth1 = pw_data['v_eth1'] v_eth2 = pw_data['v_eth2'] if eth: self.cmd("ifconfig %s 0" % eth) if v_eth1: self.cmd("ifconfig %s 0" % v_eth1) self.cmd("ifconfig %s 0" % v_eth2) if eth: self.cmd("ovs-vsctl --db=unix:%s/db.sock --no-wait add-port %s %s" %(self.path_ovs, self.name, eth)) if v_eth1: self.cmd("ovs-vsctl --db=unix:%s/db.sock --no-wait add-port %s %s" %(self.path_ovs, self.name, v_eth1)) self.cmd("ovs-vsctl --db=unix:%s/db.sock --no-wait add-port %s %s" %(self.path_ovs, self.name, v_eth2)) if eth and v_eth1: rules.append('ovs-ofctl -O %s add-flow %s "table=%s,hard_timeout=0,priority=%s,in_port=%s,action=output:%s"' %(self.OF_V, self.name, table, 32768, eth, v_eth1)) rules.append('ovs-ofctl -O %s add-flow %s "table=%s,hard_timeout=0,priority=%s,in_port=%s,action=output:%s"' %(self.OF_V, self.name, table, 32768, v_eth1, eth)) for rule in rules: rule = self.translate_rule(rule) self.cmd(rule)
def checkSR(self): root = Node( 'root', inNamespace=False) sr = root.cmd('ls %s 2> /dev/null | wc -l' % self.SR_exec) if '1' not in sr: error( 'Cannot find required executable fpm-of.bin\nPlease make sure that fpm-of.bin is properly installed in ' + self.SR_path + '\n' 'Otherwise change sr_path variable according to your configuration\n' ) exit( 1 )
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")
def detachHost( self, hostName, switchName=None ): if hostName not in self.nameToNode: error( 'host not in network: %s\n' % hostName ) return host = self.nameToNode[hostName] if not isinstance(host, Host): error('%s is not a host' % hostName) return if switchName: if switchName not in self.nameToNode: error( 'switch not in network: %s\n' % switchName ) return sw = self.nameToNode[switchName] if not isinstance(sw, Switch): error('%s is not a switch' % switchName) return if not isinstance(sw, OVSKernelSwitch) and not isinstance(sw, OVSKernelSwitchNew): error('attachHost only works with OVS kernel switches') return else: sw = None host.unlinkFrom(sw)
def do_add( self, line ): "Create a virtual machine image." args = line.split() vm_name = None vm_script = None # TODO: Still working on extra options. vm_ip = None # Current there is no point in these variables. vm_extra_params = {} if len(args) == 1: vm_name = args[0] elif len(args) == 2: vm_name = args[0] vm_script = args[1] elif len(args) == 3: vm_name = args[0] vm_script = args[1] vm_ip = args[2] else: error('invalid number of args: add vm_name [vm_script [vm_ip]]\n') return err = self._check_vm_name(vm_name, exp_exist=False, exp_running=None) if not err: self.cn.createVM(vm_name)
def start(self, controllers): "Start up a new P4 switch" info("Starting P4 switch {}.\n".format(self.name)) args = [self.sw_path] for port, intf in self.intfs.items(): if not intf.IP(): args.extend(['-i', str(port) + "@" + intf.name]) if self.pcap_dump: args.append("--pcap") # args.append("--useFiles") if self.thrift_port: args.extend(['--thrift-port', str(self.thrift_port)]) if self.nanomsg: args.extend(['--nanolog', self.nanomsg]) args.extend(['--device-id', str(self.device_id)]) P4Switch.device_id += 1 args.append(self.json_path) if self.enable_debugger: args.append("--debugger") if self.log_console: args.append("--log-console") logfile = "/tmp/p4s.{}.log".format(self.name) info(' '.join(args) + "\n") pid = None with tempfile.NamedTemporaryFile() as f: # self.cmd(' '.join(args) + ' > /dev/null 2>&1 &') self.cmd(' '.join(args) + ' >' + logfile + ' 2>&1 & echo $! >> ' + f.name) pid = int(f.read()) debug("P4 switch {} PID is {}.\n".format(self.name, pid)) if not self.check_switch_started(pid): error("P4 switch {} did not start correctly.\n".format(self.name)) exit(1) info("P4 switch {} has been started.\n".format(self.name))
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[1:] 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 result = node.cmd( 'ping -c1 %s %s' % (opts, dest.IP()) ) sent, received = self._parsePing( result ) 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' ) ploss = 100 * lost / packets output( "*** Results: %i%% dropped (%d/%d lost)\n" % ( ploss, lost, packets ) ) return ploss
def __init__(self, name, sw_path = None, json_path = None, thrift_port = None, pcap_dump = False, log_console = False, verbose = False, device_id = None, enable_debugger = False, **kwargs): Switch.__init__(self, name, **kwargs) assert(sw_path) assert(json_path) # make sure that the provided sw_path is valid pathCheck(sw_path) # make sure that the provided JSON file exists if not os.path.isfile(json_path): error("Invalid JSON file.\n") exit(1) self.sw_path = sw_path self.json_path = json_path self.verbose = verbose logfile = "/tmp/p4s.{}.log".format(self.name) self.output = open(logfile, 'w') self.thrift_port = thrift_port self.pcap_dump = pcap_dump self.enable_debugger = enable_debugger self.log_console = log_console if device_id is not None: self.device_id = device_id P4Switch.device_id = max(P4Switch.device_id, device_id) else: self.device_id = P4Switch.device_id P4Switch.device_id += 1 self.nanomsg = "ipc:///tmp/bm-{}-log.ipc".format(self.device_id)
def precheck( self ): """Pre-check to make sure connection works and that we can call sudo without a password""" result = 0 info( '*** Checking servers\n' ) for server in self.servers: ip = self.serverIP[ server ] if not server or server == 'localhost': continue info( server, '' ) dest = '%s@%s' % ( self.user, ip ) cmd = [ 'sudo', '-E', '-u', self.user ] cmd += self.sshcmd + [ '-n', dest, 'sudo true' ] debug( ' '.join( cmd ), '\n' ) _out, _err, code = errRun( cmd ) if code != 0: error( '\nstartConnection: server connection check failed ' 'to %s using command:\n%s\n' % ( server, ' '.join( cmd ) ) ) result |= code if result: error( '*** Server precheck failed.\n' '*** Make sure that the above ssh command works' ' correctly.\n' '*** You may also need to run mn -c on all nodes, and/or\n' '*** use sudo -E.\n' ) sys.exit( 1 ) info( '\n' )
def do_info( self, line ): "Noise node info." args = line.split() if len(args) != 1: error( 'invalid number of args: info [device]\n' ) else: self.mn.deviceInfo( *args )
def findTap(node, port, path=None): '''utility function to parse through a sys.config file to find tap interfaces for a switch''' switch = False portLine = '' intfLines = [] if path is None: path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir with open(path) as f: for line in f: if 'tap' in line: intfLines.append(line) if node.dpid in line.translate(None, ':'): switch = True continue if switch: if 'switch' in line: switch = False if 'port_no,%s}' % port in line: portLine = line break if portLine: m = re.search('port,\d+', portLine) port = m.group(0).split(',')[ 1 ] else: error('***ERROR: Could not find any ports in sys.config\n') return for intfLine in intfLines: if 'port,%s' % port in intfLine: return re.findall('tap\d+', intfLine)[ 0 ]
def do_position( self, line ): "Position node info." args = line.split() if len(args) != 1: error( 'invalid number of args: position [sta ou ap]\n' ) else: self.mn.getCurrentPosition( *args )
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 args and len(args) > 0 and args[ -1 ] == '\n': args = args[ :-1 ] rest = args.split( ' ' ) if first in self.nodemap: node = self.nodemap[ first ] # Substitute IP addresses for node names in command for index in range(len(rest)): arg = rest[index] if arg in self.nodemap: ip = self.nodemap[arg].IP() if not ip: error('%s is an unreachable, detached host\n' % arg) return rest[index] = ip #rest = [ self.nodemap[ arg ].IP() # if arg in self.nodemap else arg # for arg in rest ] rest = ' '.join( rest ) # Run cmd on node: builtin = isShellBuiltin( first ) node.sendCmd( rest, printPid=( not builtin ) ) self.waitForNode( node ) else: error( '*** Unknown command: %s\n' % first )
def bwCmds( self, bw=None, speedup=0, use_hfsc=False, use_tbf=False): "Return tc commands to set bandwidth" #print "RED BURST: " + str(red_burst) + "XXXXXXXXXXXXXXXX" cmds, parent = [], ' root ' if bw and ( bw < 0 or bw > 1000 ): error( 'Bandwidth', bw, 'is outside range 0..1000 Mbps\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 1:0 hfsc default 1', '%s class add dev %s parent 1:0 classid 1:1 hfsc sc ' + 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ] elif use_tbf: latency_us = 10 * 1500 * 8 / bw cmds += ['%s qdisc add dev %s root handle 1: tbf ' + 'rate %fMbit burst 15000 latency %fus' % ( bw, latency_us ) ] else: cmds += [ '%s qdisc add dev %s root handle 1:0 htb default 1', '%s class add dev %s parent 1:0 classid 1:1 htb ' + 'rate %fMbit burst 15k' % bw ] parent = ' parent 1:1 ' return cmds, parent
def do_attach( self, line ): "Create new link between a host and a switch" args = line.split() if len(args) != 2: error( 'invalid number of args: attach host switch\n' ) else: self.mn.attachHost(*args)
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
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')
def __create_hwsim_mgmt_devices(cls, n_radios): # generate prefix phys = subprocess.check_output( "find /sys/kernel/debug/ieee80211 -name " "hwsim | cut -d/ -f 6 | sort", shell=True).split("\n") num = 0 numokay = False cls.prefix = "" while not numokay: cls.prefix = "mn%02ds" % num numokay = True for phy in phys: if phy.startswith(cls.prefix): num += 1 numokay = False break try: for i in range(0, n_radios): p = subprocess.Popen( ["hwsim_mgmt", "-c", "-n", cls.prefix + ("%02d" % i)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=-1) output, err_out = p.communicate() if p.returncode == 0: m = re.search("ID (\d+)", output) debug("Created mac80211_hwsim device with ID %s\n" % m.group(1)) cls.hwsim_ids.append(m.group(1)) else: error( "\nError on creating mac80211_hwsim device with name %s" % (cls.prefix + ("%02d" % i))) error("\nOutput: %s" % output) error("\nError: %s" % err_out) except: info("Warning! If you already had Mininet-WiFi installed " "please run util/install.sh -W and then sudo make install.\n")
def do_host(self, line): args = line.split() if len(args) != 2: error('invalid number of args: host <host name> {up, down}\n') return host = args[0] command = args[1] if host not in self.mn or self.mn.get(host) not in self.mn.hosts: error('invalid host: %s\n' % args[1]) else: if command == 'up': op = 'up' elif command == 'down': op = 'down' else: error('invalid command: host <host name> {up, down}\n') return for intf in self.mn.get(host).intfList(): intf.link.intf1.ifconfig(op) intf.link.intf2.ifconfig(op)
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 delay < 0: error('Negative delay', delay, '\n') elif jitter and jitter < 0: error('Negative jitter', jitter, '\n') elif 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 %0.4f ' % loss if loss is not None else '', # The fix '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
def create_hwsim(self, n): # generate prefix num = 0 numokay = False self.prefix = "" cmd = 'find /sys/kernel/debug/ieee80211 -name hwsim | grep %05d | cut -d/ -f 6 | sort' % os.getpid( ) # grep on PID in devicelist phys = subprocess.check_output(cmd, shell=True).decode('utf-8').split("\n") while not numokay: self.prefix = "mn%05dp%02ds" % (os.getpid(), num ) # Add PID to mn-devicenames numokay = True for phy in phys: if phy.startswith(self.prefix): num += 1 numokay = False break p = subprocess.Popen( ["hwsim_mgmt", "-c", "-n", self.prefix + ("%02d" % n)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=-1) output, err_out = p.communicate() if p.returncode == 0: m = re.search("ID (\d+)", output.decode()) debug("Created mac80211_hwsim device with ID %s\n" % m.group(1)) Mac80211Hwsim.hwsim_ids.append(m.group(1)) else: error("\nError on creating mac80211_hwsim device with name %s" % (self.prefix + ("%02d" % n))) error("\nOutput: %s" % output) error("\nError: %s" % err_out)
logging.basicConfig(filename=args.sync_event_log,level=logging.WARNING) if args.kern: print('kernel switch used') else: print('user switch detected') if args.stp and args.onos: warn("stp and onos enabled") if args.stp and args.onos: warn("rstp and onos enabled") if args.stp and args.rstp: error("stp and rstp can not both be enabled") exit(1) if args.stp: print('stp enabled') elif args.rstp: print('rstp enabled') elif args.onos: print('onos enabled') else: print('custom controller') if args.ovs_vt:
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 * 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
def end_to_end_test(cert_dir=CERT_DIR, target=TARGET, gnmi_addr=GNMI_ADDR, gnmi_port=GNMI_PORT, cfile=FAUCET.cfile, prom_addr='http://localhost', prom_port=9302, nohup=False, config_stat_reload=0): """Simple end-to-end test of FAUCET config agent cert_dir: directory to store fake certs target: hostname for certs and gnmi_* -target gnmi_addr: gNMI address that agent will listen on gnmi_port: gNMI port that agent will listen on prom_addr: FAUCET prometheus address (http://localhost) prom_port: FAUCET prometheus port (9302) nohup: send HUP to FAUCET to reload config? (False) config_stat_reload: tell FAUCET to automatically reload (0)""" info('\n* Generating certificates\n') make_certs(cert_dir=cert_dir) client_auth = (' -ca {cert_dir}/fakeca.crt -cert {cert_dir}/fakeclient.crt' ' -key {cert_dir}/fakeclient.key' ' -target_name {target}').format(**locals()).split() info('* Starting network\n') faucet = partial(FAUCET, config_stat_reload=config_stat_reload) net = Mininet(topo=TestTopo(), controller=faucet, autoSetMacs=True) net.start() info('* Shutting down any agents listening on %d\n' % GNMI_PORT) kill_server(port=gnmi_port) info('* Starting agent\n') agent_log = open('faucetagent.log', 'w') nohup = '--nohup' if nohup else '' agent_cmd = ('./faucetagent.py --cert {cert_dir}/fakeserver.crt' ' --key {cert_dir}/fakeserver.key' ' --gnmiaddr {gnmi_addr}' ' --gnmiport {gnmi_port}' ' --configfile {cfile}' ' --promaddr {prom_addr}' ' --promport {prom_port}' ' --dpwait 1.0' ' {nohup}').format(**locals()).split() agent = Popen(agent_cmd, stdout=agent_log, stderr=agent_log) info('* Waiting for agent to start up\n') wait_server(port=gnmi_port) info('* Checking gNMI capabilities\n') result = run(['gnmi_capabilities'] + client_auth, stdout=PIPE, check=True) items = [ 'capabilitiesResponse:', 'name: "FAUCET"', 'organization: "faucet.nz"' ] capabilities = result.stdout.decode() for item in items: assert item in capabilities, ("missing capability field <%s>" % item) fail_count = 0 for test_num, test_case in enumerate(TEST_CASES): # Get the test case configuration config = CONFIG.format(**test_case) info('* Sending test configuration to agent\n') cmd = ['gnmi_set'] + client_auth + ['-replace=/:' + config] result = run(cmd, stdout=PIPE, check=True) sent = string_val(result.stdout.decode()) info('* Fetching configuration from agent\n') cmd = ['gnmi_get'] + client_auth + ['-xpath=/'] result = run(cmd, stdout=PIPE, check=True) received = string_val(result.stdout.decode()) info('* Verifying received configuration\n') if sent != received: error('ERROR: received config differs from sent config\n') # Assume state is good after all switches have some new flows info('* Waiting for VLAN flows\n') wait_for_flows(net.switches, ['dl_vlan=%d' % test_case['vid1']]) info('* Sending gratuitous ARPs\n') send_arps(net.hosts) info('* Waiting for MAC learning\n') wait_for_flows(net.switches, ['dl_dst=%s' % host.MAC() for host in net.hosts]) groups = test_case['groups'] info('* Verifying connectivity for', groups, '\n') host_groups = [net.get(*group) for group in groups] errors = check(hosts=net.hosts, groups=host_groups) info('Test Case #%d:' % test_num, 'OK' if errors == 0 else 'FAIL (%d errors)' % errors, '\n') if errors: fail_count += 1 info('* Stopping agent\n') agent.send_signal(SIGINT) agent.wait() agent_log.close() info('* Stopping network\n') net.stop() return fail_count
def runTopo(topoFile, simParams, hostOptions, checkLevel, controller, switch): topo = CustomTopo(topoFilePath=topoFile, simParams=simParams, hostOptions=hostOptions) if checkLevel > 1: topo.setNetOption('link', TCLink) # net = CustomMininet(topo = topo, controller = Beacon, autoSetMacs = True, **topo.getNetOptions()) # net = CustomMininet(topo = topo, controller = Beacon, **topo.getNetOptions()) net = CustomMininet(topo=topo, controller=controller, switch=switch, **topo.getNetOptions()) global netprobes netprobes = collections.OrderedDict() try: lg.output('Constructing virtual network..\n') start(net) check(net, checkLevel) lg.output("Starting hosts") lg.info(": ") for host in net.hosts: lg.info("%s " % host.name) if host.monitor_rules is not None: monitor.start(host, host.monitor_rules) if host.command is not None: lg.info("cmd ") host.command = host.command.format( commandOpts=host.commandOpts, name=host.name).format(name=host.name) if host.isXHost: t = makeTerm(host, cmd=host.command) if len(t) < 1: lg.error( "Error while starting terminal for host %s\n" % host.name) continue if len(t) == 2: tunnel, term = t else: term = t try: if term.poll() is not None: lg.error( "Terminal with command %s ended early for host %s : %s\n" % (host.command, host.name, repr(term.communicate()))) except: pass netprobes[host.name] = term else: netprobes[host.name] = runCommand(host) # print(netprobes[host.name].communicate()) else: if host.isXHost: makeTerm(host) lg.info("term ") lg.info("done ") lg.output("\n") EventsManager.startClock(net) interract(net) mon = False counter = monitor.Counter() for host in net.hosts: if host.monitor_rules is not None: monitor.collect(host, monitor_file, counter) monitor.stop(host, host.monitor_rules) mon = True for name, probe in netprobes.iteritems(): lg.info("Send sigint to probe %s\n" % name) import signal try: probe.send_signal(signal.SIGINT) time.sleep(0.05) except OSError as e: lg.error("Failed to send SIGINT to %s : %s\n" % (name, e)) if mon: monitor.writeSummary(monitor_file, counter) finally: stop(net) # cleanup ! lg.info("Stopping remaining processes...\n") kill = 0 for name, probe in netprobes.iteritems(): if probe.poll() is None: kill += 1 if kill > 0: lg.info("Found %s process(es) to kill\n" % kill) time.sleep(3) for name, probe in netprobes.iteritems(): if probe.poll() is None: try: lg.info("Send terminate signal to %s\n" % name) probe.terminate() time.sleep(0.001) except OSError as e: lg.error("Failed to terminate %s : %s\n" % (name, e)) time.sleep(3) for name, probe in netprobes.iteritems(): if probe.poll() is None: try: lg.info("Send kill signal to %s\n" % name) probe.kill() except OSError as e: lg.error("Failed to kill %s : %s\n" % (name, e)) lg.output("\nAll done\n")
def show_watch_dropped(): print "显示 tc dropped 丢包情况" DROPPED = "dropped" show_class_watch_values(DROPPED) def runner(): #show_qdisc() #show_class() #show_qdisc_errors_once() show_watch_dropped() if __name__ == "__main__": try: runner() except KeyboardInterrupt: info("\n\nKeyboard Interrupt. Shutting down and cleaning up...\n\n") #cleanup() except Exception: # Print exception type_, val_, trace_ = sys.exc_info() errorMsg = ("-" * 80 + "\n" + "Caught exception. Cleaning up...\n\n" + "%s: %s\n" % (type_.__name__, val_) + "-" * 80 + "\n") error(errorMsg) # Print stack trace to debug log import traceback stackTrace = traceback.format_exc() debug(stackTrace + "\n") #cleanup()
import os import socket import re import json import urllib2 from mininet.log import info, warn, error from mininet.node import Switch if 'ONOS_ROOT' not in os.environ: error("ERROR: environment var $ONOS_ROOT not set") exit() BMV2_TARGET = 'simple_switch_grpc' ONOS_ROOT = os.environ["ONOS_ROOT"] CPU_PORT = 255 class ONOSBmv2Switch(Switch): """BMv2 software switch with gRPC server""" deviceId = 0 instanceCount = 0 def __init__(self, name, json=None, debugger=False, loglevel="warn", elogger=False, persistent=False, grpcPort=None, thriftPort=None, netcfg=True, **kwargs): Switch.__init__(self, name, **kwargs) self.grpcPort = ONOSBmv2Switch.pickUnusedPort() if not grpcPort else grpcPort self.thriftPort = ONOSBmv2Switch.pickUnusedPort() if not thriftPort else thriftPort if self.dpid: self.deviceId = int(self.dpid, 0 if 'x' in self.dpid else 16)
def resetTarget(target): try: target.reset() except Exception as e: error("Error while resetting event on %s : %s" % (target.name, e)) error(traceback.format_exc())
class LINCSwitch(OpticalSwitch): """ LINCSwitch class """ # FIXME:Sometimes LINC doesn't remove pipes and on restart increase the pipe # number from erlang.pipe.1.* to erlang.pipe.2.*, so should read and write # from latest pipe files. For now we are removing all the pipes before # starting LINC. ### User Name ### user = os.getlogin() ### pipes ### readPipe = "/tmp/home/{}/linc-oe/rel/linc/erlang.pipe.1.r".format(user) writePipe = "/tmp/home/{}/linc-oe/rel/linc/erlang.pipe.1.w".format(user) ### sys.config path ### sysConfig = "/home/{}/linc-oe/rel/linc/releases/1.0/sys.config".format( user) ### method, mapping dpid to LINC switchId ### @staticmethod def dpids_to_ids(sysConfig): ''' return the dict containing switch dpids as key and LINC switch id as values ''' dpids_to_ids = {} fd = None try: with open(sysConfig, 'r', 0) as fd: switch_id = 1 for line in fd: dpid = re.search( r'([0-9A-Fa-f]{2}[:-]){7}([0-9A-Fa-f]{2})+', line, re.I) if dpid: dpids_to_ids[dpid.group().replace(':', '')] = switch_id switch_id += 1 return dpids_to_ids except: print "Error working with {}\nError: {}\n".format( sysConfig, sys.exc_info()) fd.close() return None ### dict of containing dpids as key and corresponding LINC switchId as values ### dpidsToLINCSwitchId = dpids_to_ids.__func__(sysConfig) @staticmethod def findDir(directory, userName): "finds and returns the path of any directory in the user's home directory" homeDir = '/home/' + userName Dir = quietRun('find %s -maxdepth 1 -name %s -type d' % (homeDir, directory)).strip('\n') DirList = Dir.split('\n') if not Dir: return None elif len(DirList) > 1: warn('***WARNING: Found multiple instances of %s; using %s\n' % (directory, DirList[0])) return DirList[0] else: return Dir ### ONOS Directory ### try: onosDir = os.environ['ONOS_ROOT'] except: onosDir = findDir('onos', user) if not onosDir: error('Please set ONOS_ROOT environment variable!\n') else: os.environ['ONOS_ROOT'] = onosDir ### LINC-directory lincDir = findDir.__func__('linc-oe', user) if not lincDir: error("***ERROR: Could not find linc-oe in user's home directory\n") ### LINC config generator directory### configGen = findDir.__func__('LINC-config-generator', user) if not configGen: error( "***ERROR: Could not find LINC-config-generator in user's home directory\n" ) # list of all the controllers controllers = None def __init__(self, name, dpid=None, allowed=True, switchType='ROADM', topo=None, annotations={}, controller=None, **params): params['inNamespace'] = False Switch.__init__(self, name, dpid=dpid, **params) self.name = name self.annotations = annotations self.allowed = allowed self.switchType = switchType self.configDict = { } # dictionary that holds all of the JSON configuration data self.crossConnects = [] self.deletedCrossConnects = [] self.controller = controller self.lincId = self._get_linc_id() # use to communicate with LINC self.lincStarted = False def start(self, *opts, **params): '''Instead of starting a virtual switch, we build the JSON dictionary for the emulated optical switch''' # TODO:Once LINC has the ability to spawn network element dynamically # we need to use this method to spawn new logical LINC switch rather then # bulding JSON. # if LINC is started then we can start and stop logical switches else create JSON if self.lincStarted: return self.start_oe() self.configDict['uri'] = 'of:' + self.dpid self.configDict['annotations'] = self.annotations self.configDict['annotations'].setdefault('name', self.name) self.configDict['hw'] = 'LINC-OE' self.configDict['mfr'] = 'Linc' self.configDict['mac'] = 'ffffffffffff' + self.dpid[-2] + self.dpid[-1] self.configDict['type'] = self.switchType self.configDict['ports'] = [] for port, intf in self.intfs.items(): if intf.name == 'lo': continue else: self.configDict['ports'].append(intf.json()) self.lincStarted = True def stop(self, deleteIntfs=False): ''' stop the existing switch ''' # TODO:Add support for deleteIntf self.stop_oe() def dpctl(self, *args): "Run dpctl command: ignore for now" pass def write_to_cli(self, command): ''' send command to LINC ''' fd = None try: fd = open(self.writePipe, 'w', 0) fd.write(command) fd.close() except: print "Error working with {}\nError: {}\n".format( self.writePipe, sys.exc_info()) if fd: fd.close() def read_from_cli(self): ''' read the output from the LINC CLI ''' response = None fd = None try: fd = open(self.readPipe, 'r', 0) fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK) # for non-blocking read # FIXME:Due to non-blocking read most for the time we read nothing response = fd.read() fd.close() except: # print "Error working with {}\nError: {}\n".format(self.readPipe, sys.exc_info()) if fd: fd.close() return response def _get_linc_id(self): ''' return the corresponding LINC switchId. ''' return LINCSwitch.dpidsToLINCSwitchId.get(self.dpid) #-------------------------------------------------------------------------- # LINC CLI commands #-------------------------------------------------------------------------- def start_oe(self): ''' start the existing LINC switch ''' #starting Switch cmd = "linc:start_switch({}).\r\n".format(self.lincId) self.write_to_cli(cmd) #hanlding taps interfaces related to the switch crossConnectJSON = {} linkConfig = [] for i in range(0, len(self.deletedCrossConnects)): crossConnect = self.deletedCrossConnects.pop() tap = None if isinstance(crossConnect.intf1.node, LINCSwitch): intf = crossConnect.intf2 tapPort = crossConnect.intf1.port else: intf = crossConnect.intf1 tapPort = crossConnect.intf2.port tap = LINCSwitch.findTap(self, tapPort) if tap: LINCSwitch.setupInts([tap]) intf.node.attach(tap) self.crossConnects.append(crossConnect) linkConfig.append(crossConnect.json()) #Sending crossConnect info to the ONOS. crossConnectJSON['links'] = linkConfig with open("crossConnect.json", 'w') as fd: json.dump(crossConnectJSON, fd, indent=4, separators=(',', ': ')) info('*** Pushing crossConnect.json to ONOS\n') output = quietRun('%s/tools/test/bin/onos-topo-cfg %s\ Topology.json' % (self.onosDir, self.controllers[0].ip), shell=True) def stop_oe(self): ''' stop the existing LINC switch ''' cmd = "linc:stop_switch({}).\r\n".format(self.lincId) self.write_to_cli(cmd) #handling taps if any for i in range(0, len(self.crossConnects)): crossConnect = self.crossConnects.pop() if isinstance(crossConnect.intf1.node, LINCSwitch): intf = crossConnect.intf2 tapPort = crossConnect.intf1.port else: intf = crossConnect.intf1 tapPort = crossConnect.intf2.port intf.node.detach(LINCSwitch.findTap(self, tapPort)) self.deletedCrossConnects.append(crossConnect) def w_port_up(self, port): ''' port_up ''' cmd = "linc:port_up({},{}).\r\n".format(self.lincId, port) self.write_to_cli(cmd) def w_port_down(self, port): ''' port_down ''' cmd = "linc:port_down({},{}).\r\n".format(self.lincId, port) self.write_to_cli(cmd) # helper functions @staticmethod def switchJSON(switch): "Returns the json configuration for a packet switch" configDict = {} configDict['uri'] = 'of:' + switch.dpid configDict['mac'] = quietRun('cat /sys/class/net/%s/address' % switch.name).strip('\n').translate( None, ':') configDict['hw'] = 'PK' # FIXME what about OVS? configDict['mfr'] = 'Linc' # FIXME what about OVS? configDict['type'] = 'SWITCH' # FIXME what about OVS? annotations = switch.params.get('annotations', {}) annotations.setdefault('name', switch.name) configDict['annotations'] = annotations ports = [] for port, intf in switch.intfs.items(): if intf.name == 'lo': continue portDict = {} portDict['port'] = port portDict['type'] = 'FIBER' if isinstance(intf.link, LINCLink) else 'COPPER' intfList = [intf.link.intf1, intf.link.intf2] intfList.remove(intf) portDict['speed'] = intfList[0].speed if isinstance( intf.link, LINCLink) else 0 ports.append(portDict) configDict['ports'] = ports return configDict @staticmethod def bootOE(net): "Start the LINC optical emulator within a mininet instance" opticalJSON = {} linkConfig = [] devices = [] #setting up the controllers for LINCSwitch class LINCSwitch.controllers = net.controllers for switch in net.switches: if isinstance(switch, OpticalSwitch): devices.append(switch.json()) else: devices.append(LINCSwitch.switchJSON(switch)) opticalJSON['devices'] = devices for link in net.links: if isinstance(link, LINCLink): linkConfig.append(link.json()) opticalJSON['links'] = linkConfig info('*** Writing Topology.json file\n') with open('Topology.json', 'w') as outfile: json.dump(opticalJSON, outfile, indent=4, separators=(',', ': ')) info( '*** Converting Topology.json to linc-oe format (TopoConfig.json) file\n' ) output = quietRun( '%s/tools/test/bin/onos-oecfg ./Topology.json > TopoConfig.json' % LINCSwitch.onosDir, shell=True) if output: error('***ERROR: Error creating topology file: %s ' % output + '\n') return False info('*** Creating sys.config...\n') output = quietRun( '%s/config_generator TopoConfig.json %s/sys.config.template %s %s' % (LINCSwitch.configGen, LINCSwitch.configGen, LINCSwitch.controllers[0].ip, LINCSwitch.controllers[0].port), shell=True) if output: error('***ERROR: Error creating sys.config file: %s\n' % output) return False info('*** Setting multiple controllers in sys.config...\n') searchStr = '\[{"Switch.*$' ctrlStr = '' for index in range(len(LINCSwitch.controllers)): ctrlStr += '{"Switch%d-Controller","%s",%d,tcp},' % ( index, net.controllers[index].ip, net.controllers[index].port) replaceStr = '[%s]},' % ctrlStr[:-1] # Cut off last comma sedCmd = 'sed -i \'s/%s/%s/\' sys.config' % (searchStr, replaceStr) output = quietRun(sedCmd, shell=True) info('*** Copying sys.config to linc-oe directory: ', output + '\n') output = quietRun('cp -v sys.config %s/rel/linc/releases/1.0/' % LINCSwitch.lincDir, shell=True).strip('\n') info(output + '\n') info('*** Adding taps and bringing them up...\n') LINCSwitch.setupInts(LINCSwitch.getTaps()) info('*** removing pipes if any \n') quietRun('rm /tmp/home/%s/linc-oe/rel/linc/*' % LINCSwitch.user, shell=True) info('*** Starting linc OE...\n') output = quietRun('%s/rel/linc/bin/linc start' % LINCSwitch.lincDir, shell=True) if output: error('***ERROR: LINC-OE: %s' % output + '\n') quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True) return False info('*** Waiting for linc-oe to start...\n') LINCSwitch.waitStarted(net) info( '*** Adding cross-connect (tap) interfaces to packet switches...\n' ) for link in net.links: if isinstance(link, LINCLink): if link.annotations['optical.type'] == 'cross-connect': for intf in [link.intf1, link.intf2]: if not isinstance(intf, LINCIntf): intfList = [intf.link.intf1, intf.link.intf2] intfList.remove(intf) intf2 = intfList[0] intf.node.attach( LINCSwitch.findTap(intf2.node, intf2.node.ports[intf2])) info('*** Waiting for all devices to be available in ONOS...\n') url = 'http://%s:8181/onos/v1/devices' % LINCSwitch.controllers[0].ip time = 0 while True: response = json.load(urllib2.urlopen(url)) devs = response.get('devices') # Wait for all devices to be registered if (len(devices) != len(devs)): continue # Wait for all devices to available available = True for d in devs: available &= d['available'] if available: break if (time >= TIMEOUT): error( '***ERROR: ONOS did not register devices within %s seconds\n' % TIMEOUT) break time += SLEEP_TIME sleep(SLEEP_TIME) info('*** Pushing Topology.json to ONOS\n') for index in range(len(LINCSwitch.controllers)): output = quietRun( '%s/tools/test/bin/onos-topo-cfg %s Topology.json &' % (LINCSwitch.onosDir, LINCSwitch.controllers[index].ip), shell=True) # successful output contains the two characters '{}' # if there is more output than this, there is an issue if output.strip('{}'): warn('***WARNING: Could not push topology file to ONOS: %s\n' % output) @staticmethod def waitStarted(net, timeout=TIMEOUT): "wait until all tap interfaces are available" tapCount = 0 time = 0 for link in net.links: if isinstance(link, LINCLink): if link.annotations['optical.type'] == 'cross-connect': tapCount += 1 while True: if str(tapCount) == quietRun('ip addr | grep tap | wc -l', shell=True).strip('\n'): return True if timeout: if time >= TIMEOUT: error( '***ERROR: LINC OE did not start within %s seconds\n' % TIMEOUT) return False time += SLEEP_TIME sleep(SLEEP_TIME) @staticmethod def shutdownOE(): "stop the optical emulator" info('*** Stopping linc OE...\n') quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True) @staticmethod def setupInts(intfs): ''' add taps and bring them up. ''' for i in intfs: quietRun('ip tuntap add dev %s mode tap' % i) quietRun('ip link set dev %s up' % i) info('*** Intf %s set\n' % i) @staticmethod def getTaps(path=None): ''' return list of all the tops in sys.config ''' if path is None: path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir fd = open(path, 'r', 0) sys_data = fd.read() taps = re.findall('tap\d+', sys_data) fd.close() return taps @staticmethod def findUser(): "Try to return logged-in (usually non-root) user" try: # If we're running sudo return os.environ['SUDO_USER'] except: try: # Logged-in user (if we have a tty) return quietRun('who am i').split()[0] except: # Give up and return effective user return quietRun('whoami') @staticmethod def findTap(node, port, path=None): '''utility function to parse through a sys.config file to find tap interfaces for a switch''' switch = False portLine = '' intfLines = [] if path is None: path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir with open(path) as f: for line in f: if 'tap' in line: intfLines.append(line) if node.dpid in line.translate(None, ':'): switch = True continue if switch: if 'switch' in line: switch = False if 'port_no,%s}' % port in line: portLine = line break if portLine: m = re.search('port,\d+', portLine) port = m.group(0).split(',')[1] else: error('***ERROR: Could not find any ports in sys.config\n') return for intfLine in intfLines: if 'port,%s' % port in intfLine: return re.findall('tap\d+', intfLine)[0] def json(self): "return json configuration dictionary for switch" return self.configDict def terminate(self): pass
def intfsUp(self): """Bring all interfaces up""" for intf in self.intfs.values(): cmdOutput = intf.ifconfig('up') if cmdOutput: error("Error setting %s up: %s " % (intf.name, cmdOutput))
def do_x(self, line): """Create an X11 tunnel to the given node, optionally starting a client. Usage: x node [cmd args]""" error("not supported")
def do_gterm(self, line): """Spawn gnome-terminal(s) for the given node(s). Usage: gterm node1 node2 ...""" error("not supported")
def do_xterm(self, line, term='xterm'): """Spawn xterm(s) for the given node(s). Usage: xterm node1 node2 ...""" error("not supported")
def add_fault(self, name): """ Add a general/controller fault """ error('FAULT: %s\n' % name) self.fault_list.append(name)
def add(self, Type=None, Longitude=None, Latitude=None, MAC=None, Idx=None, Name='', Region='', IP='', PMU_IDX='', Delay='', BW='', Loss='', Jitter='', From='', To='', **kwargs): if not self._name: log.error('Device name not initialized') return if Type != self._name: return mac = None if MAC == 'None' else MAC idx = self._name + '_' + str(self.n) if not Idx else Idx pmu_idx = None if PMU_IDX == 'None' else int(PMU_IDX) if idx in self.idx: log.error('PMU Idx <{i}> has conflict.\n'.format(i=idx)) def to_type(var): """Helper function to convert field to a list or a None object """ if var == 'None': out = None else: out = var return out delay = to_type(Delay) bw = to_type(BW) loss = to_type(Loss) jitter = to_type(Jitter) fr = to_type(From) to = to_type(To) lat = None if Latitude == 'None' else float(Latitude) lon = None if Longitude == 'None' else float(Longitude) self.name.append(Name) self.region.append(Region) self.coords.append((lat, lon)) self.ip.append(IP) self.mac.append(mac) self.idx.append(idx) # self.connections.append(conn) self.pmu_idx.append(pmu_idx) self.delay.append(delay) self.bw.append(bw) self.loss.append(loss) self.jitter.append(jitter) self.fr.append(fr) self.to.append(to) self.n += 1
def __init__(self, name, sw_path=None, json_path=None, grpc_port=None, thrift_port=None, pcap_dump=False, log_console=False, verbose=False, device_id=None, enable_debugger=False, log_file=None, **kwargs): Switch.__init__(self, name, **kwargs) assert (sw_path) self.sw_path = sw_path # make sure that the provided sw_path is valid pathCheck(sw_path) if json_path is not None: # make sure that the provided JSON file exists if not os.path.isfile(json_path): error("Invalid JSON file.\n") exit(1) self.json_path = json_path else: self.json_path = None if grpc_port is not None: self.grpc_port = grpc_port else: self.grpc_port = P4RuntimeSwitch.next_grpc_port P4RuntimeSwitch.next_grpc_port += 1 if thrift_port is not None: self.thrift_port = thrift_port else: self.thrift_port = P4RuntimeSwitch.next_thrift_port P4RuntimeSwitch.next_thrift_port += 1 if check_listening_on_port(self.grpc_port): error( '%s cannot bind port %d because it is bound by another process\n' % (self.name, self.grpc_port)) exit(1) self.verbose = verbose self.pcap_dump = pcap_dump self.enable_debugger = enable_debugger self.log_console = log_console if log_file is not None: self.log_file = log_file else: self.log_file = "/tmp/p4s.{}.log".format(self.name) self.output = open(self.log_file, 'w') if device_id is not None: self.device_id = device_id P4Switch.device_id = max(P4Switch.device_id, device_id) else: self.device_id = P4Switch.device_id P4Switch.device_id += 1 self.nanomsg = "ipc:///tmp/bm-{}-log.ipc".format(self.device_id)
def bootOE(net): "Start the LINC optical emulator within a mininet instance" opticalJSON = {} linkConfig = [] devices = [] #setting up the controllers for LINCSwitch class LINCSwitch.controllers = net.controllers for switch in net.switches: if isinstance(switch, OpticalSwitch): devices.append(switch.json()) else: devices.append(LINCSwitch.switchJSON(switch)) opticalJSON['devices'] = devices for link in net.links: if isinstance(link, LINCLink): linkConfig.append(link.json()) opticalJSON['links'] = linkConfig info('*** Writing Topology.json file\n') with open('Topology.json', 'w') as outfile: json.dump(opticalJSON, outfile, indent=4, separators=(',', ': ')) info( '*** Converting Topology.json to linc-oe format (TopoConfig.json) file\n' ) output = quietRun( '%s/tools/test/bin/onos-oecfg ./Topology.json > TopoConfig.json' % LINCSwitch.onosDir, shell=True) if output: error('***ERROR: Error creating topology file: %s ' % output + '\n') return False info('*** Creating sys.config...\n') output = quietRun( '%s/config_generator TopoConfig.json %s/sys.config.template %s %s' % (LINCSwitch.configGen, LINCSwitch.configGen, LINCSwitch.controllers[0].ip, LINCSwitch.controllers[0].port), shell=True) if output: error('***ERROR: Error creating sys.config file: %s\n' % output) return False info('*** Setting multiple controllers in sys.config...\n') searchStr = '\[{"Switch.*$' ctrlStr = '' for index in range(len(LINCSwitch.controllers)): ctrlStr += '{"Switch%d-Controller","%s",%d,tcp},' % ( index, net.controllers[index].ip, net.controllers[index].port) replaceStr = '[%s]},' % ctrlStr[:-1] # Cut off last comma sedCmd = 'sed -i \'s/%s/%s/\' sys.config' % (searchStr, replaceStr) output = quietRun(sedCmd, shell=True) info('*** Copying sys.config to linc-oe directory: ', output + '\n') output = quietRun('cp -v sys.config %s/rel/linc/releases/1.0/' % LINCSwitch.lincDir, shell=True).strip('\n') info(output + '\n') info('*** Adding taps and bringing them up...\n') LINCSwitch.setupInts(LINCSwitch.getTaps()) info('*** removing pipes if any \n') quietRun('rm /tmp/home/%s/linc-oe/rel/linc/*' % LINCSwitch.user, shell=True) info('*** Starting linc OE...\n') output = quietRun('%s/rel/linc/bin/linc start' % LINCSwitch.lincDir, shell=True) if output: error('***ERROR: LINC-OE: %s' % output + '\n') quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True) return False info('*** Waiting for linc-oe to start...\n') LINCSwitch.waitStarted(net) info( '*** Adding cross-connect (tap) interfaces to packet switches...\n' ) for link in net.links: if isinstance(link, LINCLink): if link.annotations['optical.type'] == 'cross-connect': for intf in [link.intf1, link.intf2]: if not isinstance(intf, LINCIntf): intfList = [intf.link.intf1, intf.link.intf2] intfList.remove(intf) intf2 = intfList[0] intf.node.attach( LINCSwitch.findTap(intf2.node, intf2.node.ports[intf2])) info('*** Waiting for all devices to be available in ONOS...\n') url = 'http://%s:8181/onos/v1/devices' % LINCSwitch.controllers[0].ip time = 0 while True: response = json.load(urllib2.urlopen(url)) devs = response.get('devices') # Wait for all devices to be registered if (len(devices) != len(devs)): continue # Wait for all devices to available available = True for d in devs: available &= d['available'] if available: break if (time >= TIMEOUT): error( '***ERROR: ONOS did not register devices within %s seconds\n' % TIMEOUT) break time += SLEEP_TIME sleep(SLEEP_TIME) info('*** Pushing Topology.json to ONOS\n') for index in range(len(LINCSwitch.controllers)): output = quietRun( '%s/tools/test/bin/onos-topo-cfg %s Topology.json &' % (LINCSwitch.onosDir, LINCSwitch.controllers[index].ip), shell=True) # successful output contains the two characters '{}' # if there is more output than this, there is an issue if output.strip('{}'): warn('***WARNING: Could not push topology file to ONOS: %s\n' % output)
def exampleCustomTags(): """Simple example that exercises VLANStarTopo""" net = Mininet( topo=VLANStarTopo() ) net.start() CLI( net ) net.stop() if __name__ == '__main__': import sys from functools import partial from mininet.net import Mininet from mininet.cli import CLI from mininet.topo import SingleSwitchTopo from mininet.log import setLogLevel setLogLevel( 'info' ) if not quietRun( 'which vconfig' ): error( "Cannot find command 'vconfig'\nThe package", "'vlan' is required in Ubuntu or Debian,", "or 'vconfig' in Fedora\n" ) exit() if len( sys.argv ) >= 2: exampleAllHosts( vlan=int( sys.argv[ 1 ] ) ) else: exampleCustomTags()
def do_tcpall(self, line): if line != "": error("invalid number of arguments. tcpall doesn't take any ") return self.mn.tcptest()
def config(self, bw=None, delay=None, jitter=None, loss=None, gro=False, 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 = IntfWireless.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)) # 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 # 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
def config( self, bw=None, delay=None, jitter=None, loss=None, disable_gro=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." result = Intf.config( self, **params) # Disable GRO if disable_gro: self.cmd( 'ethtool -K %s gro off' % self ) # 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 cmds = [] tcoutput = self.tc( '%s qdisc show dev %s' ) if "priomap" not in tcoutput: if self.node.type != 'station': 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 [] ) + ( ['%d%% loss' % loss ] if loss is not None else [] ) + ( [ 'ECN' ] if enable_ecn else [ 'RED' ] if enable_red else [] ) ) #Print bw info if self.node.type != 'station': 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
ARGS.ECMP = True if os.getuid() != 0: logging.error("You are NOT root") exit(1) if ARGS.nonblocking: test_non_block() elif ARGS.ECMP: test_fattree(controller=None) elif ARGS.hedera: test_hedera() elif ARGS.iroko: test_fattree(controller='Iroko') elif ARGS.dumbbell: test_dumbbell() else: error('Please specify either hedera, iroko, ecmp, or nonblocking!\n') clean() # @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER) # def port_stats_reply_handler(self, ev): # ports = [] # for stat in ev.msg.body: # ports.append('port_no=%d ' # 'rx_packets=%d tx_packets=%d ' # 'rx_bytes=%d tx_bytes=%d ' # 'rx_dropped=%d tx_dropped=%d ' # 'rx_errors=%d tx_errors=%d ' # 'rx_frame_err=%d rx_over_err=%d rx_crc_err=%d ' # 'collisions=%d duration_sec=%d duration_nsec=%d' % # (stat.port_no, # stat.rx_packets, stat.tx_packets,
def twinning(self, aml_path): """Generates digital twins based on the specification provided via an AML artifact.""" # Validate path if not os.path.isfile(aml_path): error("The AML file path '{}' is not valid!\n".format(aml_path)) return if self.topo and self.build: error("Topology has already been built!\n") return # Invoke AML Parser parser = AmlParser(aml_path) aml_topo = { 'switches': parser.switches, 'plcs': parser.plcs, 'hmis': parser.hmis, 'aps': parser.aps, 'mqttbrkrs': parser.mqttbrkrs, 'rfidrs': parser.rfidrs, 'iiotgws': parser.iiotgws } # Create topology self.topo = CpsTwinningTopo(aml_topo=aml_topo) # Start net self.start() for motor in parser.motors: self.physical_devices.append( Motor(motor['name'], motor['vars'], self.get(motor['plc_name']), motor['plc_var_map'])) # Add candy sensor self.physical_devices.append( CandySensor('CandySensor1', self.get('PLC1'), {'EXTRACTORRUNNING': 1}, self.get('RFIDr1'))) security_rules = {} for rule_type, rules in parser.security_rules.iteritems(): if rule_type == RuleTypes().VARCONSTRAINT: constraints = [] for rule in rules: rule['plc'] = self.get(rule['plc_name']) constraints.append(rule) security_rules[rule_type] = constraints elif rule_type == RuleTypes().VARLINKCONSTRAINT: constraints = [] for rule in rules: side = 'a' for _ in range(2): for key_ab in rule[side]: ab = self.get(key_ab) if isinstance(ab, Plc): rule['plc'] = ab rule['plc_var'] = rule[side][key_ab] elif isinstance(ab, Hmi): rule['hmi'] = ab rule['hmi_var'] = rule[side][key_ab] del rule[side] side = 'b' constraints.append(rule) security_rules[rule_type] = constraints self.security_manager = SecurityManager(security_rules) self.replication = Replication(self) self.viz = Viz(self, parser) self.state_logging = StateLogging(self)
def stop(self): """ Stop wireless Module """ if glob.glob("*.apconf"): os.system('rm *.apconf') if glob.glob("*wifiDirect.conf"): os.system('rm *wifiDirect.conf') for hwsim_id in self.hwsim_ids: p = subprocess.Popen(["hwsim_mgmt", "-d", hwsim_id], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=-1) output, err_out = p.communicate() if p.returncode == 0: m = re.search("ID (\d+)", output) debug("\nDeleted mac80211_hwsim device with ID %s" % m.group(1)) else: error("\nError on deleting mac80211_hwsim device with ID %d" % hwsim_id) error("\nOutput: %s" % output) error("\nError: %s" % err_out) if not self.externally_managed: try: subprocess.check_output("lsmod | grep mac80211_hwsim", shell=True) os.system('rmmod mac80211_hwsim') except: pass try: (subprocess.check_output("lsmod | grep ifb", shell=True)) os.system('rmmod ifb') except: pass try: h = subprocess.check_output("ps -aux | grep -ic \'hostapd\'", shell=True) if h >= 2: os.system('pkill -f \'hostapd -B mn%d\'' % os.getpid()) except: pass try: confnames = "mn%d_" % os.getpid() os.system('pkill -f \'wpa_supplicant -B -Dnl80211 -c%s\'' % confnames) except: pass try: pidfiles = "mn%d_" % os.getpid() os.system('pkill -f \'wpa_supplicant -B -Dnl80211 -P %s\'' % pidfiles) except: pass if not self.externally_managed: try: info("*** Killing wmediumd\n") os.system('pkill wmediumd') except: pass
def iperf(self, hosts=None, l4Type='TCP', udpBw='10M'): """Run iperf between two hosts. hosts: list of hosts; if None, uses opposite hosts l4Type: string, one of [ TCP, UDP ] returns: results two-element array of server and client speeds""" """ Currently when the server side iperf service not reachable by the client, the mininet console either hangs forever (not responsive to to any keys Or continuously prints the message "waiting for iperf to startup" Actually there are two issues : 1. when iperf session end point was created in mininet , if connectivity exists client will know in matter of secs . Per per current login client waits forever without yielding. default telnet wait time of 60 secs is good enough. Therefore while loop is not necessary. If statement is good enough. 2. Since client to server connectivity can be verified within few secs, telnet with 60 sec timeout is overkill. You get console full of msgs or console doesnt yield or hangs till telnet timeout. We can accomplish the same verification . It is common practice to use netcat(nc) to accomplish the same. Fix has been verified with iperf between hosts, between unreachable hosts, switches. """ """ commented if not quietRun( 'which telnet' ): error( 'Cannot find telnet in $PATH - required for iperf test' ) return """ if not quietRun('which nc'): error('Cannot find nc in $PATH - required for iperf test') return if not hosts: hosts = [self.hosts[0], self.hosts[-1]] else: assert len(hosts) == 2 client, server = hosts output('*** Iperf: testing ' + l4Type + ' bandwidth between ') output("%s and %s\n" % (client.name, server.name)) server.cmd('killall -9 iperf') iperfArgs = 'iperf ' bwArgs = '' if l4Type == 'UDP': iperfArgs += '-u ' bwArgs = '-b ' + udpBw + ' ' elif l4Type != 'TCP': raise Exception('Unexpected l4 type: %s' % l4Type) server.sendCmd(iperfArgs + '-s', printPid=True) servout = '' while server.lastPid is None: servout += server.monitor() if l4Type == 'TCP': """ While loop is replaced by if block while 'Connected' not in client.cmd( 'sh -c "echo A | telnet -e A %s 5001"' % server.IP()): output('waiting for iperf to start up...') sleep(.5) """ if l4Type == 'TCP': sleep(0.5) ### Changed to handle a. hang issue when one of the hosts not reachable ### b. continuous waiting loop c. reduced waiting verification using Net cat vs telnet if ('succeeded' not in client.cmd('nc -w 3 -v -z %s 5001' % server.IP())): output('waiting for iperf to start up...\n') ## since session has failed, cleanup server end point and server.sendInt() servout += server.waitOutput() error( "\niperf Error: Unable to reach the server %s on port 5001. iperf failed \n\n" % server.IP()) return cliout = client.cmd(iperfArgs + '-t 5 -c ' + server.IP() + ' ' + bwArgs) debug('Client output: %s\n' % cliout) server.sendInt() servout += server.waitOutput() debug('Server output: %s\n' % servout) result = [self._parseIperf(servout), self._parseIperf(cliout)] if l4Type == 'UDP': result.insert(0, udpBw) output('*** Results: %s\n' % result) return result
def startShell(self): """Overrides the default shell start process to handle the addition of PID, UTS, and mount namespaces.""" if self.shell: error("%s: shell is already running") return # mnexec: (c)lose descriptors, (d)etach from tty, # (p)rint pid, and run in (n)etwork namespace, # (m)ount namespace, p(i)d namespace, mount proc(f)s opts = '-cdp' if self.inNamespace: opts += 'n' if self.inMountNamespace: opts += 'm' if self.inPIDNamespace: opts += 'if' if self.inUTSNamespace: opts += 'u' # bash -m: enable job control # -s: pass $* to shell, and make process easy to find in ps cmd = [ 'mxexec', opts, 'env', 'PS1=' + chr(127), 'bash', '--norc', '--noediting', '-is', 'mininet:' + self.name ] # Spawn a shell subprocess in a pseudo-tty, to disable buffering # in the subprocess and insulate it from signals (e.g. SIGINT) # received by the parent self.master, self.slave = pty.openpty() self.shell = self._popen(cmd, stdin=self.slave, stdout=self.slave, stderr=self.slave, close_fds=False) # XXX BL: This doesn't seem right, and we should also probably # close our files when we exit... self.stdin = os.fdopen(self.master, 'r') self.stdout = self.stdin self.pid = self.shell.pid self.pollOut = select.poll() self.pollOut.register(self.stdout) # Maintain mapping between file descriptors and nodes # This is useful for monitoring multiple nodes # using select.poll() self.outToNode[self.stdout.fileno()] = self self.inToNode[self.stdin.fileno()] = self self.execed = False self.lastCmd = None self.lastPid = None self.readbuf = '' # If this node has a private PID space, grab the PID to attach to # Otherwise, we use the same PID as the shell's PID if self.inPIDNamespace: # monitor() will grab shell's true PID and put in self.lastPid self.monitor() if self.lastPid is None: raise Exception('Unable to determine shell\'s PID') self.pid = self.lastPid self.lastPid = None # Wait for prompt while True: data = self.read(1024) if data[-1] == chr(127): break self.pollOut.poll() self.waiting = False # +m: disable job control notification self.cmd('unset HISTFILE; stty -echo; set +m')