Skip to content

Commit

Permalink
tests: Rework IPerf/Tcpdump host helpers
Browse files Browse the repository at this point in the history
Convert the iperf/tcpdump helper functions into HostApplicationHelper
interface.

Signed-off-by: Volodymyr Huti <[email protected]>
  • Loading branch information
Volodymyr Huti committed Feb 24, 2024
1 parent eee3313 commit 69094fa
Showing 1 changed file with 134 additions and 107 deletions.
241 changes: 134 additions & 107 deletions tests/topotests/lib/common_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,6 @@
],
}

g_iperf_client_procs = {}
g_iperf_server_procs = {}


def is_string(value):
try:
return isinstance(value, basestring)
Expand Down Expand Up @@ -4725,127 +4721,158 @@ def check_procs(self):

class IPerfHelper(HostApplicationHelper):
def __str__(self):
return "IPerfHelper()"
return "IPerfHelper({})".format(self.iperf_path)

def run_join(
def __init__(self, tgen=None):
super(IPerfHelper, self).__init__(tgen)
self.iperf_path = tgen.net.get_exec_path("iperf3")
logger.debug("IPerfHelper initialized...")

def iperf(
self,
host,
join_addr,
l4Type="UDP",
join_interval=1,
join_intf=None,
join_towards=None,
length=0,
timeout=0,
dst=None,
port=None,
dscp=None,
json=False,
server=False,
oneoff=False,
bind_addr=None,
background=False,
):
"""
Use iperf to send IGMP join and listen to traffic
Parameters:
-----------
* `host`: iperf host from where IGMP join would be sent
* `l4Type`: string, one of [ TCP, UDP ]
* `join_addr`: multicast address (or addresses) to join to
* `join_interval`: seconds between periodic bandwidth reports
* `join_intf`: the interface to bind the join to
* `join_towards`: router whos interface to bind the join to
returns: Success (bool)
Run iperf ...
Return: Success ;)
"""
log_name = "iperf_{}_{}_".format(host.name, dst if dst else "")
log_name += "server.log" if server else "client.json"
log_file = "{}/{}".format(self.tgen.logdir, log_name)

iperf_args = []
if background:
iperf_args.append("nohup &>" + log_file)
if timeout > 0:
iperf_args.append("timeout {}".format(timeout))

iperf_args.append(self.iperf_path)
if server:
iperf_args.append("-s")
else:
iperf_args.append("-c")
iperf_args.append(dst)

if length and not timeout:
iperf_args.append("-t")
iperf_args.append(str(length))
if port:
iperf_args.append("-p")
iperf_args.append(str(port))
if oneoff:
iperf_args.append("-1")
if json:
iperf_args.append("-J")

if bind_addr:
iperf_args.append("-B")
iperf_args.append(bind_addr)
if dscp:
iperf_args.append("--dscp")
iperf_args.append(str(dscp))
if background:
iperf_args.append("&")

iperf_path = self.tgen.net.get_exec_path("iperf")

assert join_addr
if not isinstance(join_addr, list) and not isinstance(join_addr, tuple):
join_addr = [ipaddress.IPv4Address(frr_unicode(join_addr))]

for bindTo in join_addr:
iperf_args = [iperf_path, "-s"]

if l4Type == "UDP":
iperf_args.append("-u")
# XXX: installing `bash -c` as base_cmd doesn't work
cmd = ["bash", "-c", " ".join(iperf_args)]
return self.run(host.name, cmd)

iperf_args.append("-B")
if join_towards:
to_intf = frr_unicode(
self.tgen.json_topo["routers"][host]["links"][join_towards][
"interface"
]
)
iperf_args.append("{}%{}".format(str(bindTo), to_intf))
elif join_intf:
iperf_args.append("{}%{}".format(str(bindTo), join_intf))
else:
iperf_args.append(str(bindTo))

if join_interval:
iperf_args.append("-i")
iperf_args.append(str(join_interval))
class TcpDumpHelper(HostApplicationHelper):
def __str__(self):
return "TcpdumpHelper({},{},{})".format(
self.protocol, self.options, self.cap_file
)

p = self.run(host, iperf_args)
if p.poll() is not None:
logger.error("IGMP join failed on %s: %s", bindTo, comm_error(p))
return False
return True
def __init__(
self,
tgen=None,
protocol=None,
options="-A -vv",
cap_file="ping_test.txt",
):
super(TcpDumpHelper, self).__init__(tgen)
self.protocol = protocol
self.options = options
self.cap_file = cap_file
logger.debug("TcpdumpHelper initialized ...")

def run_traffic(
self, host, sentToAddress, ttl, time=0, l4Type="UDP", bind_towards=None
def capture_start(
self,
host,
intf,
timeout=0,
background=False,
):
"""
Run iperf to send IGMP join and traffic
Parameters:
-----------
* `host`: iperf host to send traffic from
* `l4Type`: string, one of [ TCP, UDP ]
* `sentToAddress`: multicast address to send traffic to
* `ttl`: time to live
* `time`: time in seconds to transmit for
* `bind_towards`: Router who's interface the source ip address is got from
returns: Success (bool)
API to capture network packets using tcp dump.
"""
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
cmd = ["bash", "-c"]
host = host.name
cmdargs = []

tcpdump_path = self.tgen.net.get_exec_path("tcpdump")
log_file = os.path.join(self.tgen.logdir, host, self.cap_file)
if timeout > 0:
cmdargs.append("timeout {}".format(timeout))

cmdargs.append(tcpdump_path)
if intf:
cmdargs.append("-i {}".format(intf))
if self.protocol:
cmdargs.append("'%s'" % self.protocol)
if self.options:
cmdargs.append("-s 0 {}".format(self.options))

if not background:
cmd.append(cmdargs)
else:
tcpdump_args = ["nohup &>" + log_file, *cmdargs, "&"]
cmd.append(" ".join(tcpdump_args))

iperf_path = self.tgen.net.get_exec_path("iperf")

if sentToAddress and not isinstance(sentToAddress, list):
sentToAddress = [ipaddress.IPv4Address(frr_unicode(sentToAddress))]

for sendTo in sentToAddress:
iperf_args = [iperf_path, "-c", sendTo]
logger.info("Running tcpdump command: " + str(cmd))
return self.run(host, cmd)

# Bind to Interface IP
if bind_towards:
ifaddr = frr_unicode(
self.tgen.json_topo["routers"][host]["links"][bind_towards]["ipv4"]
)
ipaddr = ipaddress.IPv4Interface(ifaddr).ip
iperf_args.append("-B")
iperf_args.append(str(ipaddr))

# UDP/TCP
if l4Type == "UDP":
iperf_args.append("-u")
iperf_args.append("-b")
iperf_args.append("0.012m")

# TTL
if ttl:
iperf_args.append("-T")
iperf_args.append(str(ttl))

# Time
if time:
iperf_args.append("-t")
iperf_args.append(str(time))

p = self.run(host, iperf_args)
if p.poll() is not None:
logger.error(
"mcast traffic send failed for %s: %s", sendTo, comm_error(p)
def find_msg(self, host, message, count=0):
"""
API to find messages in tcpdump capture file
"""
matches = 0
host = host.name
filepath = os.path.join(self.tgen.logdir, host, self.cap_file)
with open(filepath) as f:
matches = len(re.findall("{}".format(message), f.read()))
if count and matches < count:
errormsg = (
"[DUT: %s]: Verify Message: %s in tcpdump "
"[%s!=%s FAILED!!]"
% (
host,
count,
matches,
message,
)
)
return False

return True
return errormsg, matches

logger.info(
"[DUT: %s]: Found message: %s in tcpdump " " count: %s [PASSED!!]",
host,
message,
matches,
)
return matches != 0, matches

def verify_ip_nht(tgen, input_dict):
"""
Expand Down

0 comments on commit 69094fa

Please sign in to comment.