[Fullstack] Change how DSCP marking packets are tested

In fullstack test test_dscp_marking_packets two fake hosts are
created, each of them has got one fake instance (called sender and
receiver).
Instance called "sender" sends ICMP packets to instance called
"receiver". In receiver's namespace tcpdump process is spawned with
filter to match only packets marked with specified DSCP value.
After sender instance successfully pings receiver, tcpdump process
is killed and stdout from it was examined to search logged ICMP
packets which were send from sender's IP to receiver's IP address.
That check was failing sometimes as is described in bug report.

It was failing when tcpdump doesn't capture any packets so there was
nothing on stdout from it. But even in such case tcpdump reports on
stderr summary of packets and it was like below:

0 packets captured
6 packets received by filter
0 packets dropped by kernel

which means that packets matching our filter was received by tcpdump but
were probably not processed yet. See [1] for more details.

So this patch changes filter used in tcpdump and way how its output is
checked.
Now in filter expression there are added src and dst IP addresses also so
it will match only packets send from sender instance to receiver instance.
After that tcpdump's stderr output is examined with regex to check if
line like:

X packets received by filter

is there and if X value is different than 0. If so, it means that
tcpdump received packets with wanted DSCP mark and test should pass.

[1] https://unix.stackexchange.com/a/29369

Change-Id: Ia3522237dc787edb90d162ac4a5535ff5d2a03d5
Closes-Bug: #1733649
This commit is contained in:
Sławek Kapłoński 2018-01-04 15:51:01 +01:00 committed by garyk
parent bab1ae8812
commit 386ec26b3d
1 changed files with 12 additions and 13 deletions

View File

@ -24,8 +24,6 @@ from neutron.common import utils as common_utils
LOG = logging.getLogger(__name__)
IPv4_ADDR_REGEX = r"(\d{1,3}\.){3}\d{1,3}"
class TcpdumpException(Exception):
pass
@ -103,9 +101,11 @@ def wait_until_dscp_marking_rule_applied_linuxbridge(
def wait_for_dscp_marked_packet(sender_vm, receiver_vm, dscp_mark):
cmd = ["tcpdump", "-i", receiver_vm.port.name, "-nlt"]
cmd = [
"tcpdump", "-i", receiver_vm.port.name, "-nlt",
"src", sender_vm.ip, 'and', 'dst', receiver_vm.ip]
if dscp_mark:
cmd += ["(ip[1] & 0xfc == %s)" % (dscp_mark << 2)]
cmd += ["and", "(ip[1] & 0xfc == %s)" % (dscp_mark << 2)]
tcpdump_async = async_process.AsyncProcess(cmd, run_as_root=True,
namespace=receiver_vm.namespace)
tcpdump_async.start()
@ -116,23 +116,22 @@ def wait_for_dscp_marked_packet(sender_vm, receiver_vm, dscp_mark):
# If it was already stopped than we don't care about it
pass
pattern = (r"IP (?P<src_ip>%(ip_addr_regex)s) > "
"(?P<dst_ip>%(ip_addr_regex)s): ICMP .*$" % {
'ip_addr_regex': IPv4_ADDR_REGEX})
for line in tcpdump_async.iter_stdout():
pattern = r"(?P<packets_count>^\d+) packets received by filter"
for line in tcpdump_async.iter_stderr():
# TODO(slaweq): Debug logging added to help troubleshooting bug
# https://bugs.launchpad.net/neutron/+bug/1733649
# once it will be closed this log can be removed
LOG.debug("Tcpdump output line: %s", line)
LOG.debug("Tcpdump error output line: %s", line)
m = re.match(pattern, line)
if m and (m.group("src_ip") == sender_vm.ip and
m.group("dst_ip") == receiver_vm.ip):
if m and int(m.group("packets_count")) != 0:
return
# TODO(slaweq): Debug logging added to help troubleshooting bug
# https://bugs.launchpad.net/neutron/+bug/1733649
# once it will be closed this log can be removed
for line in tcpdump_async.iter_stderr():
LOG.debug("Tcpdump error output line: %s", line)
for line in tcpdump_async.iter_stdout():
LOG.debug("Tcpdump output line: %s", line)
raise TcpdumpException(
"No packets marked with DSCP = %(dscp_mark)s received from %(src)s "
"to %(dst)s" % {'dscp_mark': dscp_mark,