Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added iperfmulti cli and net command. #683

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions mininet/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,26 @@ def do_iperfudp( self, line ):
error( 'invalid number of args: iperfudp bw src dst\n' +
'bw examples: 10M\n' )

def do_iperfmulti(self, line):
"""TCP iperf test between a server and multiple clients
Usage: iperfmulti server client1 client2 ... clientN"""
args = line.split()
if not args:
self.mn.iperfMulti()
elif len(args) < 2:
error('invalid number of args: iperfmulti server client1 ... clientN\n')
else:
hosts = []
err = False
for arg in args:
if arg not in self.mn:
err = True
ouput("node '%s' not in netwrok\n" % arg)
else:
hosts.append(self.mn[arg])
if not err:
self.mn.iperfMulti( hosts )

def do_intfs( self, _line ):
"List interfaces."
for node in self.mn.values():
Expand Down
107 changes: 107 additions & 0 deletions mininet/net.py
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,37 @@ def _parseIperf( iperfOutput ):

# XXX This should be cleaned up

@staticmethod
def _parseIperfServer( iperfOutput ):
"""Parse iperf server output for multiple clients
and return bandwidth
iperfOutput: string
returns: dictionary formated {'IP':'bandwidth'}
"""
idReg = r'(\[.+\d+\])'
ipReg = r'(\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b)'
valReg = r'([\d\.]+ \w+/sec)'

idToIP = {}
idToRes = {}

splitOut = iperfOutput.splitlines()
for line in splitOut:
# iperf id to ip
if len(re.findall(idReg, line)) == 1 and len(re.findall(ipReg, line)) == 2:
idToIP[re.findall(idReg, line)[0]] = re.findall(ipReg, line)[1]
# iperf id to result
elif len(re.findall(idReg, line)) == 1 and len(re.findall(valReg, line)) == 1:
idToRes[re.findall(idReg, line)[0]] = re.findall(valReg, line)[0]

results = {}
for _id in idToRes:
# Remove wait listen connections
if idToRes[_id] != '0.00 bits/sec' and _id in idToIP:
results[idToIP[_id]] = idToRes[_id]

return results

def iperf( self, hosts=None, l4Type='TCP', udpBw='10M', fmt=None,
seconds=5, port=5001):
"""Run iperf between two hosts.
Expand Down Expand Up @@ -838,6 +869,82 @@ def iperf( self, hosts=None, l4Type='TCP', udpBw='10M', fmt=None,
output( '*** Results: %s\n' % result )
return result

def iperfMulti( self, hosts=None, seconds=5, port=5001):
"""Run iperf between a server and multiple clients.
hosts: list of hosts with the server as the first; if None, all of the hosts are used
seconds: iperf time to transmit
port: iperf port
returns: A key-value dictinary with the client as the key and a two-element array
of [serverSpeed, clientSpeed] as the value.
notes:
- send() is buffered, so client rate can be much higher than
the actual transmission rate; on an unloaded system, server
rate should be much closer to the actual receive rate
- if a client cannot connect to the server its results will be [None, None]
- in the rare case that the server results cannot be parsed correctly
its results will be [None, clientSpeed]
"""

#sort server and clients
hosts = hosts or self.hosts
server = hosts[0]
clients = hosts[1:]

output('*** Iperf server: ', server, '\n')
output('*** Iperf clinets: ', *clients)
output('\n')

#start server
server.cmd('killall -9 iperf')
iperfArgs = 'iperf -p %d ' % port
server.sendCmd(iperfArgs + '-s')

#start clients
workingClients = []
for client in clients:
if not waitListening(client, server.IP(), 5001):
output('Client', client, 'could not connect to server', server,'\n')
else:
workingClients.append(client)
output('Client', client, 'connected to server', server,'\n')
client.sendCmd(iperfArgs + '-t %d -c ' % seconds + server.IP())

#get server output
serverout = ''
count = 2 * len(workingClients)
while len( re.findall( '/sec', serverout ) ) < count:
serverout += server.monitor( timeoutms=5000 )
server.sendInt()
serverout += server.waitOutput()

#get client output
clientout = {}
while len(workingClients) > 0:
for client in workingClients:
if client not in clientout:
clientout[client] = ''
if len( re.findall('/sec', clientout[client])) < 1:
clientout[client] += client.monitor( timeoutms=5000 )
else:
clientout[client] += client.waitOutput()
workingClients.remove(client)

# need to match iperf ID to host IP for iperf server output
serverIPtoRes = self._parseIperfServer(serverout)
results = {}
for client in clients:
if client not in clientout:
output('*** Client ' + client.name + ' failed to connect to ' + server.name + '\n')
results[client] = [None, None]
elif client.IP() in serverIPtoRes:
output('*** ' + client.name + '\nClient speed: ' + self._parseIperf(clientout[client]) + '\nServer speed: ' + serverIPtoRes[client.IP()] + '\n')
results[client] = [serverIPtoRes[client.IP()], self._parseIperf(clientout[client])]
else:
output('*** ' + client.name + '\nClient speed: ' + self._parseIperf(clientout[client]) + '\nServer speed: None\n')
results[client] = [None, self._parseIperf(clientout[client])]

return results

def runCpuLimitTest( self, cpu, duration=5 ):
"""run CPU limit test with 'while true' processes.
cpu: desired CPU fraction of each host
Expand Down