changes to fix flake8 issues
This commit is contained in:
parent
1fc8d647c3
commit
dee91e97bf
23 changed files with 51 additions and 1005 deletions
|
@ -21,4 +21,3 @@ repos:
|
||||||
language: system
|
language: system
|
||||||
entry: bash -c 'cd daemon && pipenv run flake8'
|
entry: bash -c 'cd daemon && pipenv run flake8'
|
||||||
types: [python]
|
types: [python]
|
||||||
exclude: setup.py
|
|
||||||
|
|
|
@ -550,7 +550,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
|
||||||
# TODO: this needs to be removed, make use of the broadcast message methods
|
# TODO: this needs to be removed, make use of the broadcast message methods
|
||||||
replies = message_handler(message)
|
replies = message_handler(message)
|
||||||
self.dispatch_replies(replies, message)
|
self.dispatch_replies(replies, message)
|
||||||
except:
|
except Exception:
|
||||||
logging.exception(
|
logging.exception(
|
||||||
"%s: exception while handling message: %s",
|
"%s: exception while handling message: %s",
|
||||||
threading.currentThread().getName(),
|
threading.currentThread().getName(),
|
||||||
|
@ -946,7 +946,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
|
||||||
session = self.coreemu.create_session(master=False)
|
session = self.coreemu.create_session(master=False)
|
||||||
try:
|
try:
|
||||||
session.open_xml(file_name, start=True)
|
session.open_xml(file_name, start=True)
|
||||||
except:
|
except Exception:
|
||||||
self.coreemu.delete_session(session.id)
|
self.coreemu.delete_session(session.id)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -4,6 +4,7 @@ commeffect.py: EMANE CommEffect model for CORE
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
from builtins import int
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from past.builtins import basestring
|
from past.builtins import basestring
|
||||||
|
@ -147,7 +148,7 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
|
||||||
jitter=convert_none(jitter),
|
jitter=convert_none(jitter),
|
||||||
loss=convert_none(loss),
|
loss=convert_none(loss),
|
||||||
duplicate=convert_none(duplicate),
|
duplicate=convert_none(duplicate),
|
||||||
unicast=long(convert_none(bw)),
|
unicast=int(convert_none(bw)),
|
||||||
broadcast=long(convert_none(mbw)),
|
broadcast=int(convert_none(mbw)),
|
||||||
)
|
)
|
||||||
service.publish(nemid2, event)
|
service.publish(nemid2, event)
|
||||||
|
|
|
@ -1136,7 +1136,7 @@ class Session(object):
|
||||||
for hook in self._state_hooks.get(state, []):
|
for hook in self._state_hooks.get(state, []):
|
||||||
try:
|
try:
|
||||||
hook(state)
|
hook(state)
|
||||||
except:
|
except Exception:
|
||||||
message = "exception occured when running %s state hook: %s" % (
|
message = "exception occured when running %s state hook: %s" % (
|
||||||
coreapi.state_name(state),
|
coreapi.state_name(state),
|
||||||
hook,
|
hook,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import logging
|
||||||
import random
|
import random
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
from builtins import bytes, range
|
from builtins import bytes, int, range
|
||||||
from socket import AF_INET, AF_INET6
|
from socket import AF_INET, AF_INET6
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,8 +43,8 @@ class MacAddress(object):
|
||||||
if not self.addr:
|
if not self.addr:
|
||||||
return IpAddress.from_string("::")
|
return IpAddress.from_string("::")
|
||||||
tmp = struct.unpack("!Q", "\x00\x00" + self.addr)[0]
|
tmp = struct.unpack("!Q", "\x00\x00" + self.addr)[0]
|
||||||
nic = long(tmp) & 0x000000FFFFFF
|
nic = int(tmp) & 0x000000FFFFFF
|
||||||
oui = long(tmp) & 0xFFFFFF000000
|
oui = int(tmp) & 0xFFFFFF000000
|
||||||
# toggle U/L bit
|
# toggle U/L bit
|
||||||
oui ^= 0x020000000000
|
oui ^= 0x020000000000
|
||||||
# append EUI-48 octets
|
# append EUI-48 octets
|
||||||
|
|
|
@ -147,7 +147,7 @@ class EbtablesQueue(object):
|
||||||
# TODO: if these are WlanNodes, this will never throw an exception
|
# TODO: if these are WlanNodes, this will never throw an exception
|
||||||
try:
|
try:
|
||||||
wlan.session
|
wlan.session
|
||||||
except:
|
except Exception:
|
||||||
# Just mark as updated to remove from self.updates.
|
# Just mark as updated to remove from self.updates.
|
||||||
self.updated(wlan)
|
self.updated(wlan)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -488,7 +488,7 @@ class CoreServices(object):
|
||||||
for service in boot_path:
|
for service in boot_path:
|
||||||
try:
|
try:
|
||||||
self.boot_service(node, service)
|
self.boot_service(node, service)
|
||||||
except:
|
except Exception:
|
||||||
logging.exception("exception booting service: %s", service.name)
|
logging.exception("exception booting service: %s", service.name)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
|
@ -179,9 +179,8 @@ bootdaemon()
|
||||||
flags="$flags -6"
|
flags="$flags -6"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
#force FRR to use CORE generated conf file
|
#force FRR to use CORE generated conf file
|
||||||
flags="$flags -d -f $FRR_CONF"
|
flags="$flags -d -f $FRR_CONF"
|
||||||
$FRR_SBIN_DIR/$1 $flags
|
$FRR_SBIN_DIR/$1 $flags
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
if [ "$?" != "0" ]; then
|
||||||
|
@ -207,7 +206,7 @@ bootfrr()
|
||||||
|
|
||||||
bootdaemon "zebra"
|
bootdaemon "zebra"
|
||||||
for r in rip ripng ospf6 ospf bgp babel; do
|
for r in rip ripng ospf6 ospf bgp babel; do
|
||||||
if grep -q "^router \<${r}\>" $FRR_CONF; then
|
if grep -q "^router \\<${r}\\>" $FRR_CONF; then
|
||||||
bootdaemon "${r}d"
|
bootdaemon "${r}d"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
@ -180,7 +180,7 @@ class NrlOlsr(NrlService):
|
||||||
cmd += " -rpipe %s_olsr" % node.name
|
cmd += " -rpipe %s_olsr" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x.name, node.services)
|
servicenames = map(lambda x: x.name, node.services)
|
||||||
if "SMF" in servicenames and not "NHDP" in servicenames:
|
if "SMF" in servicenames and "NHDP" not in servicenames:
|
||||||
cmd += " -flooding s-mpr"
|
cmd += " -flooding s-mpr"
|
||||||
cmd += " -smfClient %s_smf" % node.name
|
cmd += " -smfClient %s_smf" % node.name
|
||||||
if "zebra" in servicenames:
|
if "zebra" in servicenames:
|
||||||
|
|
|
@ -199,7 +199,7 @@ bootquagga()
|
||||||
|
|
||||||
bootdaemon "zebra"
|
bootdaemon "zebra"
|
||||||
for r in rip ripng ospf6 ospf bgp babel; do
|
for r in rip ripng ospf6 ospf bgp babel; do
|
||||||
if grep -q "^router \<${r}\>" $QUAGGA_CONF; then
|
if grep -q "^router \\<${r}\\>" $QUAGGA_CONF; then
|
||||||
bootdaemon "${r}d"
|
bootdaemon "${r}d"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
@ -156,7 +156,7 @@ class Nat(CoreService):
|
||||||
cfg += "# NAT out the first interface by default\n"
|
cfg += "# NAT out the first interface by default\n"
|
||||||
have_nat = False
|
have_nat = False
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, "control") and ifc.control == True:
|
if hasattr(ifc, "control") and ifc.control is True:
|
||||||
continue
|
continue
|
||||||
if have_nat:
|
if have_nat:
|
||||||
cfg += cls.generateifcnatrule(ifc, line_prefix="#")
|
cfg += cls.generateifcnatrule(ifc, line_prefix="#")
|
||||||
|
|
|
@ -143,7 +143,7 @@ exec 2> /dev/null
|
||||||
IP="${2}"
|
IP="${2}"
|
||||||
NET="${3}"
|
NET="${3}"
|
||||||
if [ -z "$NET" ]; then
|
if [ -z "$NET" ]; then
|
||||||
NET="24"
|
NET="24"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
/sbin/ip addr add ${IP}/${NET} dev "$1"
|
/sbin/ip addr add ${IP}/${NET} dev "$1"
|
||||||
|
@ -165,7 +165,7 @@ exec 2> /dev/null
|
||||||
IP="${2}"
|
IP="${2}"
|
||||||
NET="${3}"
|
NET="${3}"
|
||||||
if [ -z "$NET" ]; then
|
if [ -z "$NET" ]; then
|
||||||
NET="24"
|
NET="24"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
/sbin/ip addr del ${IP}/${NET} dev "$1"
|
/sbin/ip addr del ${IP}/${NET} dev "$1"
|
||||||
|
|
|
@ -495,7 +495,7 @@ Group ${APACHE_RUN_GROUP}
|
||||||
|
|
||||||
AccessFileName .htaccess
|
AccessFileName .htaccess
|
||||||
|
|
||||||
<Files ~ "^\.ht">
|
<Files ~ "^\\.ht">
|
||||||
"""
|
"""
|
||||||
cfg += permstr[version]
|
cfg += permstr[version]
|
||||||
cfg += """\
|
cfg += """\
|
||||||
|
@ -542,22 +542,22 @@ ServerSignature On
|
||||||
TraceEnable Off
|
TraceEnable Off
|
||||||
|
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
ServerAdmin webmaster@localhost
|
ServerAdmin webmaster@localhost
|
||||||
DocumentRoot /var/www
|
DocumentRoot /var/www
|
||||||
<Directory />
|
<Directory />
|
||||||
Options FollowSymLinks
|
Options FollowSymLinks
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
</Directory>
|
</Directory>
|
||||||
<Directory /var/www/>
|
<Directory /var/www/>
|
||||||
Options Indexes FollowSymLinks MultiViews
|
Options Indexes FollowSymLinks MultiViews
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
"""
|
"""
|
||||||
cfg += permstr2[version]
|
cfg += permstr2[version]
|
||||||
cfg += """\
|
cfg += """\
|
||||||
</Directory>
|
</Directory>
|
||||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||||
LogLevel warn
|
LogLevel warn
|
||||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -438,7 +438,7 @@ def load_classes(path, clazz):
|
||||||
for member in members:
|
for member in members:
|
||||||
valid_class = member[1]
|
valid_class = member[1]
|
||||||
classes.append(valid_class)
|
classes.append(valid_class)
|
||||||
except:
|
except Exception:
|
||||||
logging.exception(
|
logging.exception(
|
||||||
"unexpected error during import, skipping: %s", import_statement
|
"unexpected error during import, skipping: %s", import_statement
|
||||||
)
|
)
|
||||||
|
|
|
@ -47,7 +47,7 @@ def example(options):
|
||||||
node.client.term("bash")
|
node.client.term("bash")
|
||||||
|
|
||||||
# shutdown session
|
# shutdown session
|
||||||
raw_input("press enter to exit...")
|
input("press enter to exit...")
|
||||||
coreemu.shutdown()
|
coreemu.shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,8 @@ def main():
|
||||||
|
|
||||||
prefix = ipaddress.Ipv4Prefix("10.83.0.0/16")
|
prefix = ipaddress.Ipv4Prefix("10.83.0.0/16")
|
||||||
session = Session(1)
|
session = Session(1)
|
||||||
if "server" in globals():
|
server = globals().get("server")
|
||||||
|
if server:
|
||||||
server.addsession(session)
|
server.addsession(session)
|
||||||
|
|
||||||
# distributed setup - connect to daemon server
|
# distributed setup - connect to daemon server
|
||||||
|
@ -204,7 +205,7 @@ def main():
|
||||||
print(
|
print(
|
||||||
"To stop this session, use the core-cleanup script on the remote daemon server."
|
"To stop this session, use the core-cleanup script on the remote daemon server."
|
||||||
)
|
)
|
||||||
raw_input("press enter to exit")
|
input("press enter to exit")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__" or __name__ == "__builtin__":
|
if __name__ == "__main__" or __name__ == "__builtin__":
|
||||||
|
|
|
@ -67,7 +67,8 @@ def main():
|
||||||
|
|
||||||
prefix = ipaddress.Ipv4Prefix("10.83.0.0/16")
|
prefix = ipaddress.Ipv4Prefix("10.83.0.0/16")
|
||||||
session = Session(1)
|
session = Session(1)
|
||||||
if "server" in globals():
|
server = globals().get("server")
|
||||||
|
if server is not None:
|
||||||
server.addsession(session)
|
server.addsession(session)
|
||||||
|
|
||||||
# distributed setup - connect to slave server
|
# distributed setup - connect to slave server
|
||||||
|
|
|
@ -19,8 +19,6 @@ from string import Template
|
||||||
import core.nodes.base
|
import core.nodes.base
|
||||||
import core.nodes.network
|
import core.nodes.network
|
||||||
from core.constants import QUAGGA_STATE_DIR
|
from core.constants import QUAGGA_STATE_DIR
|
||||||
|
|
||||||
# this is the /etc/core/core.conf default
|
|
||||||
from core.emulator.session import Session
|
from core.emulator.session import Session
|
||||||
from core.nodes import ipaddress
|
from core.nodes import ipaddress
|
||||||
from core.utils import check_cmd
|
from core.utils import check_cmd
|
||||||
|
@ -149,7 +147,7 @@ class Route(object):
|
||||||
and self.gw == other.gw
|
and self.gw == other.gw
|
||||||
and self.metric == other.metric
|
and self.metric == other.metric
|
||||||
)
|
)
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -459,7 +457,7 @@ class Ospf6MdrLevel(VtyshCmd):
|
||||||
# TODO: handle multiple interfaces
|
# TODO: handle multiple interfaces
|
||||||
field = line.split()
|
field = line.split()
|
||||||
mdrlevel = field[4]
|
mdrlevel = field[4]
|
||||||
if not mdrlevel in ("MDR", "BMDR", "OTHER"):
|
if mdrlevel not in ("MDR", "BMDR", "OTHER"):
|
||||||
self.warn("mdrlevel: %s" % mdrlevel)
|
self.warn("mdrlevel: %s" % mdrlevel)
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
self.info(" %s is %s" % (self.node.routerid, mdrlevel))
|
self.info(" %s is %s" % (self.node.routerid, mdrlevel))
|
||||||
|
|
|
@ -1,958 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c)2011-2014 the Boeing Company.
|
|
||||||
# See the LICENSE file included in this distribution.
|
|
||||||
#
|
|
||||||
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
||||||
#
|
|
||||||
"""
|
|
||||||
wlanemanetests.py - This script tests the performance of the WLAN device in
|
|
||||||
CORE by measuring various metrics:
|
|
||||||
- delay experienced when pinging end-to-end
|
|
||||||
- maximum TCP throughput achieved using iperf end-to-end
|
|
||||||
- the CPU used and loss experienced when running an MGEN flow of UDP traffic
|
|
||||||
|
|
||||||
All MANET nodes are arranged in a row, so that any given node can only
|
|
||||||
communicate with the node to its right or to its left. Performance is measured
|
|
||||||
using traffic that travels across each hop in the network. Static /32 routing
|
|
||||||
is used instead of any dynamic routing protocol.
|
|
||||||
|
|
||||||
Various underlying network types are tested:
|
|
||||||
- bridged (the CORE default, uses ebtables)
|
|
||||||
- bridged with netem (add link effects to the bridge using tc queues)
|
|
||||||
- EMANE bypass - the bypass model just forwards traffic
|
|
||||||
- EMANE RF-PIPE - the bandwidth (bitrate) is set very high / no restrictions
|
|
||||||
- EMANE RF-PIPE - bandwidth is set similar to netem case
|
|
||||||
- EMANE RF-PIPE - default connectivity is off and pathloss events are
|
|
||||||
generated to connect the nodes in a line
|
|
||||||
|
|
||||||
Results are printed/logged in CSV format.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import math
|
|
||||||
import optparse
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
import core.nodes.base
|
|
||||||
import core.nodes.network
|
|
||||||
from core import emane
|
|
||||||
from core.emane.bypass import EmaneBypassModel
|
|
||||||
from core.emane.nodes import EmaneNode
|
|
||||||
from core.emane.rfpipe import EmaneRfPipeModel
|
|
||||||
from core.emulator.session import Session
|
|
||||||
from core.nodes import ipaddress
|
|
||||||
|
|
||||||
try:
|
|
||||||
from emane.events import EventService
|
|
||||||
from emane.events import PathlossEvent
|
|
||||||
except ImportError:
|
|
||||||
from emanesh.events import EventService
|
|
||||||
from emanesh.events import PathlossEvent
|
|
||||||
|
|
||||||
# global Experiment object (for interaction with "python -i")
|
|
||||||
exp = None
|
|
||||||
|
|
||||||
|
|
||||||
# move these to core.misc.utils
|
|
||||||
def readstat():
|
|
||||||
f = open("/proc/stat", "r")
|
|
||||||
lines = f.readlines()
|
|
||||||
f.close()
|
|
||||||
return lines
|
|
||||||
|
|
||||||
|
|
||||||
def numcpus():
|
|
||||||
lines = readstat()
|
|
||||||
n = 0
|
|
||||||
for l in lines[1:]:
|
|
||||||
if l[:3] != "cpu":
|
|
||||||
break
|
|
||||||
n += 1
|
|
||||||
return n
|
|
||||||
|
|
||||||
|
|
||||||
def getcputimes(line):
|
|
||||||
# return (user, nice, sys, idle) from a /proc/stat cpu line
|
|
||||||
# assume columns are:
|
|
||||||
# cpu# user nice sys idle iowait irq softirq steal guest (man 5 proc)
|
|
||||||
items = line.split()
|
|
||||||
(user, nice, sys, idle) = map(lambda x: int(x), items[1:5])
|
|
||||||
return [user, nice, sys, idle]
|
|
||||||
|
|
||||||
|
|
||||||
def calculatecpu(timesa, timesb):
|
|
||||||
for i in range(len(timesa)):
|
|
||||||
timesb[i] -= timesa[i]
|
|
||||||
total = sum(timesb)
|
|
||||||
if total == 0:
|
|
||||||
return 0.0
|
|
||||||
else:
|
|
||||||
# subtract % time spent in idle time
|
|
||||||
return 100 - ((100.0 * timesb[-1]) / total)
|
|
||||||
|
|
||||||
|
|
||||||
# end move these to core.misc.utils
|
|
||||||
|
|
||||||
|
|
||||||
class Cmd(object):
|
|
||||||
""" Helper class for running a command on a node and parsing the result. """
|
|
||||||
|
|
||||||
args = ""
|
|
||||||
|
|
||||||
def __init__(self, node, verbose=False):
|
|
||||||
""" Initialize with a CoreNode (LxcNode) """
|
|
||||||
self.id = None
|
|
||||||
self.stdin = None
|
|
||||||
self.out = None
|
|
||||||
self.node = node
|
|
||||||
self.verbose = verbose
|
|
||||||
|
|
||||||
def info(self, msg):
|
|
||||||
""" Utility method for writing output to stdout."""
|
|
||||||
print(msg)
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def warn(self, msg):
|
|
||||||
""" Utility method for writing output to stderr. """
|
|
||||||
sys.stderr.write("XXX %s:" % self.node.name, msg)
|
|
||||||
sys.stderr.flush()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
""" This is the primary method used for running this command. """
|
|
||||||
self.open()
|
|
||||||
status = self.id.wait()
|
|
||||||
r = self.parse()
|
|
||||||
self.cleanup()
|
|
||||||
return r
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
""" Exceute call to node.popen(). """
|
|
||||||
self.id, self.stdin, self.out, self.err = self.node.client.popen(self.args)
|
|
||||||
|
|
||||||
def parse(self):
|
|
||||||
""" This method is overloaded by child classes and should return some
|
|
||||||
result.
|
|
||||||
"""
|
|
||||||
return None
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
""" Close the Popen channels."""
|
|
||||||
self.stdin.close()
|
|
||||||
self.out.close()
|
|
||||||
self.err.close()
|
|
||||||
tmp = self.id.wait()
|
|
||||||
if tmp:
|
|
||||||
self.warn("nonzero exit status:", tmp)
|
|
||||||
|
|
||||||
|
|
||||||
class ClientServerCmd(Cmd):
|
|
||||||
""" Helper class for running a command on a node and parsing the result. """
|
|
||||||
|
|
||||||
args = ""
|
|
||||||
client_args = ""
|
|
||||||
|
|
||||||
def __init__(self, node, client_node, verbose=False):
|
|
||||||
""" Initialize with two CoreNodes, node is the server """
|
|
||||||
Cmd.__init__(self, node, verbose)
|
|
||||||
self.client_node = client_node
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
""" Run the server command, then the client command, then
|
|
||||||
kill the server """
|
|
||||||
self.open() # server
|
|
||||||
self.client_open() # client
|
|
||||||
status = self.client_id.wait()
|
|
||||||
# stop the server
|
|
||||||
self.node.cmd_output(["killall", self.args[0]])
|
|
||||||
r = self.parse()
|
|
||||||
self.cleanup()
|
|
||||||
return r
|
|
||||||
|
|
||||||
def client_open(self):
|
|
||||||
""" Exceute call to client_node.popen(). """
|
|
||||||
self.client_id, self.client_stdin, self.client_out, self.client_err = self.client_node.client.popen(
|
|
||||||
self.client_args
|
|
||||||
)
|
|
||||||
|
|
||||||
def parse(self):
|
|
||||||
""" This method is overloaded by child classes and should return some
|
|
||||||
result.
|
|
||||||
"""
|
|
||||||
return None
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
""" Close the Popen channels."""
|
|
||||||
self.stdin.close()
|
|
||||||
self.out.close()
|
|
||||||
self.err.close()
|
|
||||||
tmp = self.id.wait()
|
|
||||||
if tmp:
|
|
||||||
self.warn("nonzero exit status: %s" % tmp)
|
|
||||||
self.warn("command was: %s" % (self.args,))
|
|
||||||
|
|
||||||
|
|
||||||
class PingCmd(Cmd):
|
|
||||||
""" Test latency using ping.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, node, verbose=False, addr=None, count=50, interval=0.1):
|
|
||||||
Cmd.__init__(self, node, verbose)
|
|
||||||
self.addr = addr
|
|
||||||
self.count = count
|
|
||||||
self.interval = interval
|
|
||||||
self.args = ["ping", "-q", "-c", "%s" % count, "-i", "%s" % interval, addr]
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
if self.verbose:
|
|
||||||
self.info("%s initial test ping (max 1 second)..." % self.node.name)
|
|
||||||
(status, result) = self.node.cmd_output(
|
|
||||||
["ping", "-q", "-c", "1", "-w", "1", self.addr]
|
|
||||||
)
|
|
||||||
if status != 0:
|
|
||||||
self.warn(
|
|
||||||
"initial ping from %s to %s failed! result:\n%s"
|
|
||||||
% (self.node.name, self.addr, result)
|
|
||||||
)
|
|
||||||
return 0.0, 0.0
|
|
||||||
if self.verbose:
|
|
||||||
self.info(
|
|
||||||
"%s pinging %s (%d seconds)..."
|
|
||||||
% (self.node.name, self.addr, self.count * self.interval)
|
|
||||||
)
|
|
||||||
return Cmd.run(self)
|
|
||||||
|
|
||||||
def parse(self):
|
|
||||||
lines = self.out.readlines()
|
|
||||||
avg_latency = 0
|
|
||||||
mdev = 0
|
|
||||||
try:
|
|
||||||
stats_str = lines[-1].split("=")[1]
|
|
||||||
stats = stats_str.split("/")
|
|
||||||
avg_latency = float(stats[1])
|
|
||||||
mdev = float(stats[3].split(" ")[0])
|
|
||||||
except:
|
|
||||||
self.warn("ping parsing exception: %s" % e)
|
|
||||||
return avg_latency, mdev
|
|
||||||
|
|
||||||
|
|
||||||
class IperfCmd(ClientServerCmd):
|
|
||||||
""" Test throughput using iperf.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, node, client_node, verbose=False, addr=None, time=10):
|
|
||||||
# node is the server
|
|
||||||
ClientServerCmd.__init__(self, node, client_node, verbose)
|
|
||||||
self.addr = addr
|
|
||||||
self.time = time
|
|
||||||
# -s server, -y c CSV report output
|
|
||||||
self.args = ["iperf", "-s", "-y", "c"]
|
|
||||||
self.client_args = ["iperf", "-c", self.addr, "-t", "%s" % self.time]
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
if self.verbose:
|
|
||||||
self.info("Launching the iperf server on %s..." % self.node.name)
|
|
||||||
self.info(
|
|
||||||
"Running the iperf client on %s (%s seconds)..."
|
|
||||||
% (self.client_node.name, self.time)
|
|
||||||
)
|
|
||||||
return ClientServerCmd.run(self)
|
|
||||||
|
|
||||||
def parse(self):
|
|
||||||
lines = self.out.readlines()
|
|
||||||
try:
|
|
||||||
bps = int(lines[-1].split(",")[-1].strip("\n"))
|
|
||||||
except Exception as e:
|
|
||||||
self.warn("iperf parsing exception: %s" % e)
|
|
||||||
bps = 0
|
|
||||||
return bps
|
|
||||||
|
|
||||||
|
|
||||||
class MgenCmd(ClientServerCmd):
|
|
||||||
""" Run a test traffic flow using an MGEN sender and receiver.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, node, client_node, verbose=False, addr=None, time=10, rate=512):
|
|
||||||
ClientServerCmd.__init__(self, node, client_node, verbose)
|
|
||||||
self.addr = addr
|
|
||||||
self.time = time
|
|
||||||
self.args = ["mgen", "event", "listen udp 5000", "output", "/var/log/mgen.log"]
|
|
||||||
self.rate = rate
|
|
||||||
sendevent = "ON 1 UDP DST %s/5000 PERIODIC [%s]" % (
|
|
||||||
addr,
|
|
||||||
self.mgenrate(self.rate),
|
|
||||||
)
|
|
||||||
stopevent = "%s OFF 1" % time
|
|
||||||
self.client_args = [
|
|
||||||
"mgen",
|
|
||||||
"event",
|
|
||||||
sendevent,
|
|
||||||
"event",
|
|
||||||
stopevent,
|
|
||||||
"output",
|
|
||||||
"/var/log/mgen.log",
|
|
||||||
]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def mgenrate(kbps):
|
|
||||||
""" Return a MGEN periodic rate string for the given kilobits-per-sec.
|
|
||||||
Assume 1500 byte MTU, 20-byte IP + 8-byte UDP headers, leaving
|
|
||||||
1472 bytes for data.
|
|
||||||
"""
|
|
||||||
bps = (kbps / 8) * 1000.0
|
|
||||||
maxdata = 1472
|
|
||||||
pps = math.ceil(bps / maxdata)
|
|
||||||
return "%s %s" % (pps, maxdata)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
if self.verbose:
|
|
||||||
self.info("Launching the MGEN receiver on %s..." % self.node.name)
|
|
||||||
self.info(
|
|
||||||
"Running the MGEN sender on %s (%s seconds)..."
|
|
||||||
% (self.client_node.name, self.time)
|
|
||||||
)
|
|
||||||
return ClientServerCmd.run(self)
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
""" Close the Popen channels."""
|
|
||||||
self.stdin.close()
|
|
||||||
self.out.close()
|
|
||||||
self.err.close()
|
|
||||||
# non-zero mgen exit status OK
|
|
||||||
tmp = self.id.wait()
|
|
||||||
|
|
||||||
def parse(self):
|
|
||||||
""" Check MGEN receiver"s log file for packet sequence numbers, and
|
|
||||||
return the percentage of lost packets.
|
|
||||||
"""
|
|
||||||
logfile = os.path.join(self.node.nodedir, "var.log/mgen.log")
|
|
||||||
f = open(logfile, "r")
|
|
||||||
numlost = 0
|
|
||||||
lastseq = 0
|
|
||||||
for line in f.readlines():
|
|
||||||
fields = line.split()
|
|
||||||
if fields[1] != "RECV":
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
seq = int(fields[4].split(">")[1])
|
|
||||||
except:
|
|
||||||
self.info("Unexpected MGEN line:\n%s" % fields)
|
|
||||||
if seq > (lastseq + 1):
|
|
||||||
numlost += seq - (lastseq + 1)
|
|
||||||
lastseq = seq
|
|
||||||
f.close()
|
|
||||||
if lastseq > 0:
|
|
||||||
loss = 100.0 * numlost / lastseq
|
|
||||||
else:
|
|
||||||
loss = 0
|
|
||||||
if self.verbose:
|
|
||||||
self.info("Receiver log shows %d of %d packets lost" % (numlost, lastseq))
|
|
||||||
return loss
|
|
||||||
|
|
||||||
|
|
||||||
class Experiment(object):
|
|
||||||
""" Experiment object to organize tests.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, opt, start):
|
|
||||||
""" Initialize with opt and start time. """
|
|
||||||
self.session = None
|
|
||||||
# node list
|
|
||||||
self.nodes = []
|
|
||||||
# WLAN network
|
|
||||||
self.net = None
|
|
||||||
self.verbose = opt.verbose
|
|
||||||
# dict from OptionParser
|
|
||||||
self.opt = opt
|
|
||||||
self.start = start
|
|
||||||
self.numping = opt.numping
|
|
||||||
self.numiperf = opt.numiperf
|
|
||||||
self.nummgen = opt.nummgen
|
|
||||||
self.logbegin()
|
|
||||||
|
|
||||||
def info(self, msg):
|
|
||||||
""" Utility method for writing output to stdout. """
|
|
||||||
print(msg)
|
|
||||||
sys.stdout.flush()
|
|
||||||
self.log(msg)
|
|
||||||
|
|
||||||
def warn(self, msg):
|
|
||||||
""" Utility method for writing output to stderr. """
|
|
||||||
sys.stderr.write(msg)
|
|
||||||
sys.stderr.flush()
|
|
||||||
self.log(msg)
|
|
||||||
|
|
||||||
def logbegin(self):
|
|
||||||
""" Start logging. """
|
|
||||||
self.logfp = None
|
|
||||||
if not self.opt.logfile:
|
|
||||||
return
|
|
||||||
self.logfp = open(self.opt.logfile, "w")
|
|
||||||
self.log("%s begin: %s\n" % (sys.argv[0], self.start.ctime()))
|
|
||||||
self.log("%s args: %s\n" % (sys.argv[0], sys.argv[1:]))
|
|
||||||
(sysname, rel, ver, machine, nodename) = os.uname()
|
|
||||||
self.log("%s %s %s %s on %s" % (sysname, rel, ver, machine, nodename))
|
|
||||||
|
|
||||||
def logend(self):
|
|
||||||
""" End logging. """
|
|
||||||
if not self.logfp:
|
|
||||||
return
|
|
||||||
end = datetime.datetime.now()
|
|
||||||
self.log("%s end: %s (%s)\n" % (sys.argv[0], end.ctime(), end - self.start))
|
|
||||||
self.logfp.flush()
|
|
||||||
self.logfp.close()
|
|
||||||
self.logfp = None
|
|
||||||
|
|
||||||
def log(self, msg):
|
|
||||||
""" Write to the log file, if any. """
|
|
||||||
if not self.logfp:
|
|
||||||
return
|
|
||||||
self.logfp.write(msg)
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
""" Prepare for another experiment run.
|
|
||||||
"""
|
|
||||||
if self.session:
|
|
||||||
self.session.shutdown()
|
|
||||||
del self.session
|
|
||||||
self.session = None
|
|
||||||
self.nodes = []
|
|
||||||
self.net = None
|
|
||||||
|
|
||||||
def createbridgedsession(self, numnodes, verbose=False):
|
|
||||||
""" Build a topology consisting of the given number of LxcNodes
|
|
||||||
connected to a WLAN.
|
|
||||||
"""
|
|
||||||
# IP subnet
|
|
||||||
prefix = ipaddress.Ipv4Prefix("10.0.0.0/16")
|
|
||||||
self.session = Session(1)
|
|
||||||
# emulated network
|
|
||||||
self.net = self.session.create_node(
|
|
||||||
cls=core.nodes.network.WlanNode, name="wlan1"
|
|
||||||
)
|
|
||||||
prev = None
|
|
||||||
for i in range(1, numnodes + 1):
|
|
||||||
addr = "%s/%s" % (prefix.addr(i), 32)
|
|
||||||
tmp = self.session.create_node(
|
|
||||||
cls=core.nodes.base.CoreNode, _id=i, name="n%d" % i
|
|
||||||
)
|
|
||||||
tmp.newnetif(self.net, [addr])
|
|
||||||
self.nodes.append(tmp)
|
|
||||||
self.session.services.add_services(tmp, "router", "IPForward")
|
|
||||||
self.session.services.boot_services(tmp)
|
|
||||||
self.staticroutes(i, prefix, numnodes)
|
|
||||||
|
|
||||||
# link each node in a chain, with the previous node
|
|
||||||
if prev:
|
|
||||||
self.net.link(prev.netif(0), tmp.netif(0))
|
|
||||||
prev = tmp
|
|
||||||
|
|
||||||
def createemanesession(self, numnodes, verbose=False, cls=None, values=None):
|
|
||||||
""" Build a topology consisting of the given number of LxcNodes
|
|
||||||
connected to an EMANE WLAN.
|
|
||||||
"""
|
|
||||||
prefix = ipaddress.Ipv4Prefix("10.0.0.0/16")
|
|
||||||
self.session = Session(2)
|
|
||||||
self.session.node_count = str(numnodes + 1)
|
|
||||||
self.session.master = True
|
|
||||||
self.session.location.setrefgeo(47.57917, -122.13232, 2.00000)
|
|
||||||
self.session.location.refscale = 150.0
|
|
||||||
self.session.emane.loadmodels()
|
|
||||||
self.net = self.session.create_node(
|
|
||||||
cls=EmaneNode, _id=numnodes + 1, name="wlan1"
|
|
||||||
)
|
|
||||||
self.net.verbose = verbose
|
|
||||||
# self.session.emane.addobj(self.net)
|
|
||||||
for i in range(1, numnodes + 1):
|
|
||||||
addr = "%s/%s" % (prefix.addr(i), 32)
|
|
||||||
tmp = self.session.create_node(
|
|
||||||
cls=core.nodes.base.CoreNode, _id=i, name="n%d" % i
|
|
||||||
)
|
|
||||||
# tmp.setposition(i * 20, 50, None)
|
|
||||||
tmp.setposition(50, 50, None)
|
|
||||||
tmp.newnetif(self.net, [addr])
|
|
||||||
self.nodes.append(tmp)
|
|
||||||
self.session.services.add_services(tmp, "router", "IPForward")
|
|
||||||
|
|
||||||
if values is None:
|
|
||||||
values = cls.getdefaultvalues()
|
|
||||||
self.session.emane.setconfig(self.net.id, cls.name, values)
|
|
||||||
self.session.instantiate()
|
|
||||||
|
|
||||||
self.info("waiting %s sec (TAP bring-up)" % 2)
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
for i in range(1, numnodes + 1):
|
|
||||||
tmp = self.nodes[i - 1]
|
|
||||||
self.session.services.boot_services(tmp)
|
|
||||||
self.staticroutes(i, prefix, numnodes)
|
|
||||||
|
|
||||||
def setnodes(self):
|
|
||||||
""" Set the sender and receiver nodes for use in this experiment,
|
|
||||||
along with the address of the receiver to be used.
|
|
||||||
"""
|
|
||||||
self.firstnode = self.nodes[0]
|
|
||||||
self.lastnode = self.nodes[-1]
|
|
||||||
self.lastaddr = self.lastnode.netif(0).addrlist[0].split("/")[0]
|
|
||||||
|
|
||||||
def staticroutes(self, i, prefix, numnodes):
|
|
||||||
""" Add static routes on node number i to the other nodes in the chain.
|
|
||||||
"""
|
|
||||||
routecmd = ["/sbin/ip", "route", "add"]
|
|
||||||
node = self.nodes[i - 1]
|
|
||||||
neigh_left = ""
|
|
||||||
neigh_right = ""
|
|
||||||
# add direct interface routes first
|
|
||||||
if i > 1:
|
|
||||||
neigh_left = "%s" % prefix.addr(i - 1)
|
|
||||||
cmd = routecmd + [neigh_left, "dev", node.netif(0).name]
|
|
||||||
(status, result) = node.cmd_output(cmd)
|
|
||||||
if status != 0:
|
|
||||||
self.warn("failed to add interface route: %s" % cmd)
|
|
||||||
if i < numnodes:
|
|
||||||
neigh_right = "%s" % prefix.addr(i + 1)
|
|
||||||
cmd = routecmd + [neigh_right, "dev", node.netif(0).name]
|
|
||||||
(status, result) = node.cmd_output(cmd)
|
|
||||||
if status != 0:
|
|
||||||
self.warn("failed to add interface route: %s" % cmd)
|
|
||||||
|
|
||||||
# add static routes to all other nodes via left/right neighbors
|
|
||||||
for j in range(1, numnodes + 1):
|
|
||||||
if abs(j - i) < 2:
|
|
||||||
continue
|
|
||||||
addr = "%s" % prefix.addr(j)
|
|
||||||
if j < i:
|
|
||||||
gw = neigh_left
|
|
||||||
else:
|
|
||||||
gw = neigh_right
|
|
||||||
cmd = routecmd + [addr, "via", gw]
|
|
||||||
(status, result) = node.cmd_output(cmd)
|
|
||||||
if status != 0:
|
|
||||||
self.warn("failed to add route: %s" % cmd)
|
|
||||||
|
|
||||||
def setpathloss(self, numnodes):
|
|
||||||
""" Send EMANE pathloss events to connect all NEMs in a chain.
|
|
||||||
"""
|
|
||||||
if self.session.emane.version < self.session.emane.EMANE091:
|
|
||||||
service = emaneeventservice.EventService()
|
|
||||||
e = emaneeventpathloss.EventPathloss(1)
|
|
||||||
old = True
|
|
||||||
else:
|
|
||||||
if self.session.emane.version == self.session.emane.EMANE091:
|
|
||||||
dev = "lo"
|
|
||||||
else:
|
|
||||||
dev = self.session.obj("ctrlnet").brname
|
|
||||||
service = EventService(
|
|
||||||
eventchannel=("224.1.2.8", 45703, dev), otachannel=None
|
|
||||||
)
|
|
||||||
old = False
|
|
||||||
|
|
||||||
for i in range(1, numnodes + 1):
|
|
||||||
rxnem = i
|
|
||||||
# inform rxnem that it can hear node to the left with 10dB noise
|
|
||||||
txnem = rxnem - 1
|
|
||||||
if txnem > 0:
|
|
||||||
if old:
|
|
||||||
e.set(0, txnem, 10.0, 10.0)
|
|
||||||
service.publish(
|
|
||||||
emaneeventpathloss.EVENT_ID,
|
|
||||||
emaneeventservice.PLATFORMID_ANY,
|
|
||||||
rxnem,
|
|
||||||
emaneeventservice.COMPONENTID_ANY,
|
|
||||||
e.export(),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
e = PathlossEvent()
|
|
||||||
e.append(txnem, forward=10.0, reverse=10.0)
|
|
||||||
service.publish(rxnem, e)
|
|
||||||
# inform rxnem that it can hear node to the right with 10dB noise
|
|
||||||
txnem = rxnem + 1
|
|
||||||
if txnem > numnodes:
|
|
||||||
continue
|
|
||||||
if old:
|
|
||||||
e.set(0, txnem, 10.0, 10.0)
|
|
||||||
service.publish(
|
|
||||||
emaneeventpathloss.EVENT_ID,
|
|
||||||
emaneeventservice.PLATFORMID_ANY,
|
|
||||||
rxnem,
|
|
||||||
emaneeventservice.COMPONENTID_ANY,
|
|
||||||
e.export(),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
e = PathlossEvent()
|
|
||||||
e.append(txnem, forward=10.0, reverse=10.0)
|
|
||||||
service.publish(rxnem, e)
|
|
||||||
|
|
||||||
def setneteffects(self, bw=None, delay=None):
|
|
||||||
""" Set link effects for all interfaces attached to the network node.
|
|
||||||
"""
|
|
||||||
if not self.net:
|
|
||||||
self.warn("failed to set effects: no network node")
|
|
||||||
return
|
|
||||||
for netif in self.net.netifs():
|
|
||||||
self.net.linkconfig(netif, bw=bw, delay=delay)
|
|
||||||
|
|
||||||
def runalltests(self, title=""):
|
|
||||||
""" Convenience helper to run all defined experiment tests.
|
|
||||||
If tests are run multiple times, this returns the average of
|
|
||||||
those runs.
|
|
||||||
"""
|
|
||||||
duration = self.opt.duration
|
|
||||||
rate = self.opt.rate
|
|
||||||
if len(title) > 0:
|
|
||||||
self.info(
|
|
||||||
"----- running %s tests (duration=%s, rate=%s) -----"
|
|
||||||
% (title, duration, rate)
|
|
||||||
)
|
|
||||||
(latency, mdev, throughput, cpu, loss) = (0, 0, 0, 0, 0)
|
|
||||||
|
|
||||||
self.info(
|
|
||||||
"number of runs: ping=%d, iperf=%d, mgen=%d"
|
|
||||||
% (self.numping, self.numiperf, self.nummgen)
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.numping > 0:
|
|
||||||
(latency, mdev) = self.pingtest(count=self.numping)
|
|
||||||
|
|
||||||
if self.numiperf > 0:
|
|
||||||
throughputs = []
|
|
||||||
for i in range(1, self.numiperf + 1):
|
|
||||||
throughput = self.iperftest(time=duration)
|
|
||||||
if self.numiperf > 1:
|
|
||||||
throughputs += throughput
|
|
||||||
# iperf is very CPU intensive
|
|
||||||
time.sleep(1)
|
|
||||||
if self.numiperf > 1:
|
|
||||||
throughput = sum(throughputs) / len(throughputs)
|
|
||||||
self.info("throughputs=%s" % ["%.2f" % v for v in throughputs])
|
|
||||||
|
|
||||||
if self.nummgen > 0:
|
|
||||||
cpus = []
|
|
||||||
losses = []
|
|
||||||
for i in range(1, self.nummgen + 1):
|
|
||||||
(cpu, loss) = self.cputest(time=duration, rate=rate)
|
|
||||||
if self.nummgen > 1:
|
|
||||||
cpus += (cpu,)
|
|
||||||
losses += (loss,)
|
|
||||||
if self.nummgen > 1:
|
|
||||||
cpu = sum(cpus) / len(cpus)
|
|
||||||
loss = sum(losses) / len(losses)
|
|
||||||
self.info("cpus=%s" % ["%.2f" % v for v in cpus])
|
|
||||||
self.info("losses=%s" % ["%.2f" % v for v in losses])
|
|
||||||
|
|
||||||
return latency, mdev, throughput, cpu, loss
|
|
||||||
|
|
||||||
def pingtest(self, count=50):
|
|
||||||
""" Ping through a chain of nodes and report the average latency.
|
|
||||||
"""
|
|
||||||
p = PingCmd(
|
|
||||||
node=self.firstnode,
|
|
||||||
verbose=self.verbose,
|
|
||||||
addr=self.lastaddr,
|
|
||||||
count=count,
|
|
||||||
interval=0.1,
|
|
||||||
).run()
|
|
||||||
(latency, mdev) = p
|
|
||||||
self.info("latency (ms): %.03f, %.03f" % (latency, mdev))
|
|
||||||
return p
|
|
||||||
|
|
||||||
def iperftest(self, time=10):
|
|
||||||
""" Run iperf through a chain of nodes and report the maximum
|
|
||||||
throughput.
|
|
||||||
"""
|
|
||||||
bps = IperfCmd(
|
|
||||||
node=self.lastnode,
|
|
||||||
client_node=self.firstnode,
|
|
||||||
verbose=False,
|
|
||||||
addr=self.lastaddr,
|
|
||||||
time=time,
|
|
||||||
).run()
|
|
||||||
self.info("throughput (bps): %s" % bps)
|
|
||||||
return bps
|
|
||||||
|
|
||||||
def cputest(self, time=10, rate=512):
|
|
||||||
""" Run MGEN through a chain of nodes and report the CPU usage and
|
|
||||||
percent of lost packets. Rate is in kbps.
|
|
||||||
"""
|
|
||||||
if self.verbose:
|
|
||||||
self.info("%s initial test ping (max 1 second)..." % self.firstnode.name)
|
|
||||||
(status, result) = self.firstnode.cmd_output(
|
|
||||||
["ping", "-q", "-c", "1", "-w", "1", self.lastaddr]
|
|
||||||
)
|
|
||||||
if status != 0:
|
|
||||||
self.warn(
|
|
||||||
"initial ping from %s to %s failed! result:\n%s"
|
|
||||||
% (self.firstnode.name, self.lastaddr, result)
|
|
||||||
)
|
|
||||||
return 0.0, 0.0
|
|
||||||
lines = readstat()
|
|
||||||
cpustart = getcputimes(lines[0])
|
|
||||||
loss = MgenCmd(
|
|
||||||
node=self.lastnode,
|
|
||||||
client_node=self.firstnode,
|
|
||||||
verbose=False,
|
|
||||||
addr=self.lastaddr,
|
|
||||||
time=time,
|
|
||||||
rate=rate,
|
|
||||||
).run()
|
|
||||||
lines = readstat()
|
|
||||||
cpuend = getcputimes(lines[0])
|
|
||||||
percent = calculatecpu(cpustart, cpuend)
|
|
||||||
self.info("CPU usage (%%): %.02f, %.02f loss" % (percent, loss))
|
|
||||||
return percent, loss
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
""" Main routine when running from command-line.
|
|
||||||
"""
|
|
||||||
usagestr = "usage: %prog [-h] [options] [args]"
|
|
||||||
parser = optparse.OptionParser(usage=usagestr)
|
|
||||||
parser.set_defaults(
|
|
||||||
numnodes=10,
|
|
||||||
delay=3,
|
|
||||||
duration=10,
|
|
||||||
rate=512,
|
|
||||||
verbose=False,
|
|
||||||
numping=50,
|
|
||||||
numiperf=1,
|
|
||||||
nummgen=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_option(
|
|
||||||
"-d", "--delay", dest="delay", type=float, help="wait time before testing"
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"-l",
|
|
||||||
"--logfile",
|
|
||||||
dest="logfile",
|
|
||||||
type=str,
|
|
||||||
help="log detailed output to the specified file",
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"-n", "--numnodes", dest="numnodes", type=int, help="number of nodes"
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"-r",
|
|
||||||
"--rate",
|
|
||||||
dest="rate",
|
|
||||||
type=float,
|
|
||||||
help="kbps rate to use for MGEN CPU tests",
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"--numping", dest="numping", type=int, help="number of ping latency test runs"
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"--numiperf",
|
|
||||||
dest="numiperf",
|
|
||||||
type=int,
|
|
||||||
help="number of iperf throughput test runs",
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"--nummgen", dest="nummgen", type=int, help="number of MGEN CPU tests runs"
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"-t",
|
|
||||||
"--time",
|
|
||||||
dest="duration",
|
|
||||||
type=int,
|
|
||||||
help="duration in seconds of throughput and CPU tests",
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"-v", "--verbose", dest="verbose", action="store_true", help="be more verbose"
|
|
||||||
)
|
|
||||||
|
|
||||||
def usage(msg=None, err=0):
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
if msg:
|
|
||||||
sys.stdout.write(msg + "\n\n")
|
|
||||||
parser.print_help()
|
|
||||||
sys.exit(err)
|
|
||||||
|
|
||||||
# parse command line opt
|
|
||||||
(opt, args) = parser.parse_args()
|
|
||||||
|
|
||||||
if opt.numnodes < 2:
|
|
||||||
usage("invalid numnodes: %s" % opt.numnodes)
|
|
||||||
if opt.delay < 0.0:
|
|
||||||
usage("invalid delay: %s" % opt.delay)
|
|
||||||
if opt.rate < 0.0:
|
|
||||||
usage("invalid rate: %s" % opt.rate)
|
|
||||||
|
|
||||||
for a in args:
|
|
||||||
sys.stderr.write("ignoring command line argument: %s\n" % a)
|
|
||||||
|
|
||||||
results = {}
|
|
||||||
starttime = datetime.datetime.now()
|
|
||||||
exp = Experiment(opt=opt, start=starttime)
|
|
||||||
exp.info("Starting wlanemanetests.py tests %s" % starttime.ctime())
|
|
||||||
|
|
||||||
# bridged
|
|
||||||
exp.info("setting up bridged tests 1/2 no link effects")
|
|
||||||
exp.info("creating topology: numnodes = %s" % (opt.numnodes,))
|
|
||||||
exp.createbridgedsession(numnodes=opt.numnodes, verbose=opt.verbose)
|
|
||||||
exp.setnodes()
|
|
||||||
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
|
|
||||||
time.sleep(opt.delay)
|
|
||||||
results["0 bridged"] = exp.runalltests("bridged")
|
|
||||||
exp.info("done; elapsed time: %s" % (datetime.datetime.now() - exp.start))
|
|
||||||
|
|
||||||
# bridged with netem
|
|
||||||
exp.info("setting up bridged tests 2/2 with netem")
|
|
||||||
exp.setneteffects(bw=54000000, delay=0)
|
|
||||||
exp.info("waiting %s sec (queue bring-up)" % opt.delay)
|
|
||||||
results["1.0 netem"] = exp.runalltests("netem")
|
|
||||||
exp.info("shutting down bridged session")
|
|
||||||
|
|
||||||
# bridged with netem (1 Mbps,200ms)
|
|
||||||
exp.info("setting up bridged tests 3/2 with netem")
|
|
||||||
exp.setneteffects(bw=1000000, delay=20000)
|
|
||||||
exp.info("waiting %s sec (queue bring-up)" % opt.delay)
|
|
||||||
results["1.2 netem_1M"] = exp.runalltests("netem_1M")
|
|
||||||
exp.info("shutting down bridged session")
|
|
||||||
|
|
||||||
# bridged with netem (54 kbps,500ms)
|
|
||||||
exp.info("setting up bridged tests 3/2 with netem")
|
|
||||||
exp.setneteffects(bw=54000, delay=100000)
|
|
||||||
exp.info("waiting %s sec (queue bring-up)" % opt.delay)
|
|
||||||
results["1.4 netem_54K"] = exp.runalltests("netem_54K")
|
|
||||||
exp.info("shutting down bridged session")
|
|
||||||
exp.reset()
|
|
||||||
|
|
||||||
# EMANE bypass model
|
|
||||||
exp.info("setting up EMANE tests 1/2 with bypass model")
|
|
||||||
exp.createemanesession(
|
|
||||||
numnodes=opt.numnodes,
|
|
||||||
verbose=opt.verbose,
|
|
||||||
cls=EmaneBypassModel,
|
|
||||||
values=None,
|
|
||||||
)
|
|
||||||
exp.setnodes()
|
|
||||||
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
|
|
||||||
time.sleep(opt.delay)
|
|
||||||
results["2.0 bypass"] = exp.runalltests("bypass")
|
|
||||||
exp.info("shutting down bypass session")
|
|
||||||
exp.reset()
|
|
||||||
|
|
||||||
exp.info("waiting %s sec (between EMANE tests)" % opt.delay)
|
|
||||||
time.sleep(opt.delay)
|
|
||||||
|
|
||||||
# EMANE RF-PIPE model: no restrictions (max datarate)
|
|
||||||
exp.info("setting up EMANE tests 2/4 with RF-PIPE model")
|
|
||||||
rfpipevals = list(EmaneRfPipeModel.getdefaultvalues())
|
|
||||||
rfpnames = EmaneRfPipeModel.getnames()
|
|
||||||
# max value
|
|
||||||
rfpipevals[rfpnames.index("datarate")] = "4294967295"
|
|
||||||
if emanever < emane.EMANE091:
|
|
||||||
rfpipevals[rfpnames.index("pathlossmode")] = "2ray"
|
|
||||||
rfpipevals[rfpnames.index("defaultconnectivitymode")] = "1"
|
|
||||||
else:
|
|
||||||
rfpipevals[rfpnames.index("propagationmodel")] = "2ray"
|
|
||||||
exp.createemanesession(
|
|
||||||
numnodes=opt.numnodes,
|
|
||||||
verbose=opt.verbose,
|
|
||||||
cls=EmaneRfPipeModel,
|
|
||||||
values=rfpipevals,
|
|
||||||
)
|
|
||||||
exp.setnodes()
|
|
||||||
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
|
|
||||||
time.sleep(opt.delay)
|
|
||||||
results["3.0 rfpipe"] = exp.runalltests("rfpipe")
|
|
||||||
exp.info("shutting down RF-PIPE session")
|
|
||||||
exp.reset()
|
|
||||||
|
|
||||||
# EMANE RF-PIPE model: 54M datarate
|
|
||||||
exp.info("setting up EMANE tests 3/4 with RF-PIPE model 54M")
|
|
||||||
rfpipevals = list(EmaneRfPipeModel.getdefaultvalues())
|
|
||||||
rfpnames = EmaneRfPipeModel.getnames()
|
|
||||||
rfpipevals[rfpnames.index("datarate")] = "54000000"
|
|
||||||
# TX delay != propagation delay
|
|
||||||
# rfpipevals[ rfpnames.index("delay") ] = "5000"
|
|
||||||
if emanever < emane.EMANE091:
|
|
||||||
rfpipevals[rfpnames.index("pathlossmode")] = "2ray"
|
|
||||||
rfpipevals[rfpnames.index("defaultconnectivitymode")] = "1"
|
|
||||||
else:
|
|
||||||
rfpipevals[rfpnames.index("propagationmodel")] = "2ray"
|
|
||||||
exp.createemanesession(
|
|
||||||
numnodes=opt.numnodes,
|
|
||||||
verbose=opt.verbose,
|
|
||||||
cls=EmaneRfPipeModel,
|
|
||||||
values=rfpipevals,
|
|
||||||
)
|
|
||||||
exp.setnodes()
|
|
||||||
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
|
|
||||||
time.sleep(opt.delay)
|
|
||||||
results["4.0 rfpipe54m"] = exp.runalltests("rfpipe54m")
|
|
||||||
exp.info("shutting down RF-PIPE session")
|
|
||||||
exp.reset()
|
|
||||||
|
|
||||||
# EMANE RF-PIPE model: 54K datarate
|
|
||||||
exp.info("setting up EMANE tests 4/4 with RF-PIPE model pathloss")
|
|
||||||
rfpipevals = list(EmaneRfPipeModel.getdefaultvalues())
|
|
||||||
rfpnames = EmaneRfPipeModel.getnames()
|
|
||||||
rfpipevals[rfpnames.index("datarate")] = "54000"
|
|
||||||
if emanever < emane.EMANE091:
|
|
||||||
rfpipevals[rfpnames.index("pathlossmode")] = "pathloss"
|
|
||||||
rfpipevals[rfpnames.index("defaultconnectivitymode")] = "0"
|
|
||||||
else:
|
|
||||||
rfpipevals[rfpnames.index("propagationmodel")] = "precomputed"
|
|
||||||
exp.createemanesession(
|
|
||||||
numnodes=opt.numnodes,
|
|
||||||
verbose=opt.verbose,
|
|
||||||
cls=EmaneRfPipeModel,
|
|
||||||
values=rfpipevals,
|
|
||||||
)
|
|
||||||
exp.setnodes()
|
|
||||||
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
|
|
||||||
time.sleep(opt.delay)
|
|
||||||
exp.info("sending pathloss events to govern connectivity")
|
|
||||||
exp.setpathloss(opt.numnodes)
|
|
||||||
results["5.0 pathloss"] = exp.runalltests("pathloss")
|
|
||||||
exp.info("shutting down RF-PIPE session")
|
|
||||||
exp.reset()
|
|
||||||
|
|
||||||
# EMANE RF-PIPE model (512K, 200ms)
|
|
||||||
exp.info("setting up EMANE tests 4/4 with RF-PIPE model pathloss")
|
|
||||||
rfpipevals = list(EmaneRfPipeModel.getdefaultvalues())
|
|
||||||
rfpnames = EmaneRfPipeModel.getnames()
|
|
||||||
rfpipevals[rfpnames.index("datarate")] = "512000"
|
|
||||||
rfpipevals[rfpnames.index("delay")] = "200"
|
|
||||||
rfpipevals[rfpnames.index("pathlossmode")] = "pathloss"
|
|
||||||
rfpipevals[rfpnames.index("defaultconnectivitymode")] = "0"
|
|
||||||
exp.createemanesession(
|
|
||||||
numnodes=opt.numnodes,
|
|
||||||
verbose=opt.verbose,
|
|
||||||
cls=EmaneRfPipeModel,
|
|
||||||
values=rfpipevals,
|
|
||||||
)
|
|
||||||
exp.setnodes()
|
|
||||||
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
|
|
||||||
time.sleep(opt.delay)
|
|
||||||
exp.info("sending pathloss events to govern connectivity")
|
|
||||||
exp.setpathloss(opt.numnodes)
|
|
||||||
results["5.1 pathloss"] = exp.runalltests("pathloss")
|
|
||||||
exp.info("shutting down RF-PIPE session")
|
|
||||||
exp.reset()
|
|
||||||
|
|
||||||
# summary of results in CSV format
|
|
||||||
exp.info(
|
|
||||||
"----- summary of results (%s nodes, rate=%s, duration=%s) -----"
|
|
||||||
% (opt.numnodes, opt.rate, opt.duration)
|
|
||||||
)
|
|
||||||
exp.info("netname:latency,mdev,throughput,cpu,loss")
|
|
||||||
|
|
||||||
for test in sorted(results.keys()):
|
|
||||||
(latency, mdev, throughput, cpu, loss) = results[test]
|
|
||||||
exp.info(
|
|
||||||
"%s:%.03f,%.03f,%d,%.02f,%.02f"
|
|
||||||
% (test, latency, mdev, throughput, cpu, loss)
|
|
||||||
)
|
|
||||||
|
|
||||||
exp.logend()
|
|
||||||
return exp
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -9,7 +9,12 @@ import socket
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from core.api.tlv import coreapi
|
from core.api.tlv import coreapi
|
||||||
from core.emulator.enumerations import CORE_API_PORT, MessageFlags, MessageTypes, SessionTlvs
|
from core.emulator.enumerations import (
|
||||||
|
CORE_API_PORT,
|
||||||
|
MessageFlags,
|
||||||
|
MessageTypes,
|
||||||
|
SessionTlvs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def print_available_tlvs(t, tlv_class):
|
def print_available_tlvs(t, tlv_class):
|
||||||
|
|
|
@ -7,10 +7,10 @@ multi_line_output=3
|
||||||
include_trailing_comma=True
|
include_trailing_comma=True
|
||||||
force_grid_wrap=0
|
force_grid_wrap=0
|
||||||
use_parentheses=True
|
use_parentheses=True
|
||||||
line_length=100
|
line_length=88
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore=E501
|
ignore=E501,W503,E203
|
||||||
max-line-length=100
|
max-line-length=100
|
||||||
max-complexity=18
|
max-complexity=18
|
||||||
select=B,C,E,F,W,T4
|
select=B,C,E,F,W,T4
|
||||||
|
|
|
@ -21,7 +21,7 @@ from core.emulator.enumerations import (
|
||||||
NodeTlvs,
|
NodeTlvs,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
)
|
)
|
||||||
from core.nodes.ipaddress import IpAddress, Ipv4Prefix, MacAddress
|
from core.nodes.ipaddress import IpAddress, MacAddress
|
||||||
|
|
||||||
|
|
||||||
def set_emane_model(node_id, model):
|
def set_emane_model(node_id, model):
|
||||||
|
|
|
@ -834,7 +834,7 @@ class TestGrpc:
|
||||||
def test_throughputs(self, grpc_server):
|
def test_throughputs(self, grpc_server):
|
||||||
# given
|
# given
|
||||||
client = CoreGrpcClient()
|
client = CoreGrpcClient()
|
||||||
session = grpc_server.coreemu.create_session()
|
grpc_server.coreemu.create_session()
|
||||||
queue = Queue()
|
queue = Queue()
|
||||||
|
|
||||||
def handle_event(event_data):
|
def handle_event(event_data):
|
||||||
|
|
Loading…
Reference in a new issue