Index: tests/sys/common/Makefile =================================================================== --- tests/sys/common/Makefile +++ tests/sys/common/Makefile @@ -6,9 +6,11 @@ ${PACKAGE}FILES+= divert.py ${PACKAGE}FILES+= sender.py ${PACKAGE}FILES+= net_receiver.py +${PACKAGE}FILES+= tcp_dscp.sh ${PACKAGE}FILESMODE_divert.py=0555 ${PACKAGE}FILESMODE_sender.py=0555 ${PACKAGE}FILESMODE_net_receiver.py=0555 +${PACKAGE}FILESMODE_tcp_dscp.sh=0555 .include Index: tests/sys/common/tcp_dscp.sh =================================================================== --- /dev/null +++ tests/sys/common/tcp_dscp.sh @@ -0,0 +1,125 @@ +#!/bin/sh + +# Test if packets has corresponding DSCP value when a TCP socket is requesting +# specific IP_TOS|IPV6_TCLASS +# Uses netcat(1) as TCP client and server to send 1MB of random data over loopback, +# then uses tcpdump(1) to read the DSCP values from those packets. +set -eu + +# We are testing only some DSCP values, not all of them +dscp_cs1=0x20 +dscp_cs7=0xe0 +dscp_af11=0x28 +dscp_af43=0x98 +dscp_ef=0xb8 + +die() { + # Exit on error + echo -n "EXIT: " >&2 + echo "$@" >&2 + exit 1 +} + +usage () { + # Display usage + echo "$0 inet | inet6" + exit 0 +} + +check_dump () { + # Check tcpdump trace for expected DSCP value in packet + direction=$1 + if [ $direction = "client->server" ]; then + src="" + dst="${host}.${port}" + else + src="${host}.${port}" + dst= + fi + # tcpdump is displaying IPv4 packets verbose output using 2 lines but only 1 line if IPv6 :-( + if [ "${proto}" = "ip" ]; then + if grep -B 1 "${src}[[:space:]]>[[:space:]]${dst}" /tmp/${proto}.txt | grep -q '(tos 0x0,' /tmp/${proto}.txt; then + result="Fail (Empty tos detected)" + elif grep -B 1 "${src}[[:space:]]>[[:space:]]${dst}" /tmp/${proto}.txt | grep -q "(${tcpdump_name} ${dscp_hex}"; then + result="Success" + else + result="Fail (Wrong value)" + fi + elif [ "$proto" = "ip6" ]; then + if grep -q "(flowlabel[[:space:]].*${src}[[:space:]]>[[:space:]]${dst}" /tmp/$proto.txt; then + result="Fail (Empty tos detected)" + elif grep -q "(${tcpdump_name} ${dscp_hex}.*${src}[[:space:]]>[[:space:]]${dst}" /tmp/$proto.txt; then + result="Success" + else + result="Fail (Wrong value)" + fi + fi + + printf "%s\t%s\t%s\t%s\n" ${af} ${dscp_name} ${direction} ${result} + + case "$result" in + *Fail*) error=1;; + *Success*) error=0;; + *) error=;; + esac + return $error +} + +test () { + # Starting tcpdump, then nc to send/receive TCP traffic + # $1 dscp name + # $2 tos mapping + local dscp_name=$1 + local dscp_hex=$2 + local result=0 + # Force a timeout after 5 seconds in case less than 20 packets are captured + /usr/bin/timeout 5 /usr/sbin/tcpdump -vpni lo0 -c 20 -K "tcp port ${port}" > /tmp/${proto}.txt 2> /tmp/${proto}.txt & +JOB_TCPDUMP=$! + # Start a TCP server setting the DSCP (flow server -> client) sending 1MB of data to the first client connected + dd if=/dev/urandom bs=1M count=1 status=none | /usr/bin/timeout 4 /usr/bin/nc -n -T ${dscp_name} -l $host $port > /dev/null & + # Gives time to start the server before running the client + sleep 1 + # Start a TCP client setting the DSCP too too (flow client -> server, mainly ACK here) + /usr/bin/timeout 4 /usr/bin/nc -n -w 2 -T ${dscp_name} $host $port > /dev/null & + # Wait for the timeout/tcpdump job to complete (capture 20 packets or timeout) + wait ${JOB_TCPDUMP} || die "ERROR running tcpdump (common error: need /dev/bpf permission), error code from wait is $? (if 124 it is a timeout)" + # Add a forced sleep, to avoid mixing results in the next test (tcpdump could use previously buffered packets) + sleep 1 + + check_dump "client->server" + check_dump "server->client" + #rm /tmp/$proto.txt +} + +if [ $# -lt 1 ]; then + echo "Not enought argument" + usage +fi + +af=$1 + +# Using different port for inet and inet6 to avoid mixed results +# with parallel tests + +case "$af" in + "inet") + host="127.0.0.1" + proto="ip" + port=4404 + tcpdump_name="tos" + ;; + "inet6") + host="::1" + proto="ip6" + port=6606 + tcpdump_name="class" + ;; + *) + usage + ;; +esac + +printf "AF\tDSCP\tDirection\tResult\n" +for value in cs1 af11 cs7 af43 ef; do + eval "test ${value} \$dscp_$value" +done Index: tests/sys/netinet/Makefile =================================================================== --- tests/sys/netinet/Makefile +++ tests/sys/netinet/Makefile @@ -12,7 +12,7 @@ socket_afinet \ tcp_connect_port_test -ATF_TESTS_SH= carp fibs fibs_test redirect divert forward output lpm arp +ATF_TESTS_SH= carp fibs fibs_test redirect divert forward output lpm arp tcp_dscp TEST_METADATA.output+= required_programs="python" PROGS= udp_dontroute tcp_user_cookie Index: tests/sys/netinet/tcp_dscp.sh =================================================================== --- /dev/null +++ tests/sys/netinet/tcp_dscp.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env atf-sh + +atf_test_case "tcp_dscp_inet" +tcp_dscp_inet_head() { + + atf_set descr 'Test if TCP socket option correctly generate marked inet DSCP packets' + atf_set require.user root + atf_set require.progs "tcpdump nc" +} + +tcp_dscp_inet_body() { + + script_name="../common/tcp_dscp.sh" + + atf_check -s exit:0 -o ignore $(atf_get_srcdir)/${script_name} inet +} + +atf_init_test_cases() +{ + + atf_add_test_case "tcp_dscp_inet" +} + +# end + Index: tests/sys/netinet6/Makefile =================================================================== --- tests/sys/netinet6/Makefile +++ tests/sys/netinet6/Makefile @@ -15,7 +15,8 @@ output6 \ lpm6 \ fibs6 \ - ndp + ndp \ + tcp_dscp TEST_METADATA.output6+= required_programs="python" ${PACKAGE}FILES+= exthdr.py Index: tests/sys/netinet6/tcp_dscp.sh =================================================================== --- /dev/null +++ tests/sys/netinet6/tcp_dscp.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env atf-sh + +atf_test_case "tcp_dscp_inet6" +tcp_dscp_inet6_head() { + + atf_set descr 'Test if TCP socket option correctly generate marked inet6 DSCP packets' + atf_set require.user root + atf_set require.progs "tcpdump nc" +} + +tcp_dscp_inet6_body() { + + script_name="../common/tcp_dscp.sh" + + atf_check -s exit:0 -o ignore $(atf_get_srcdir)/${script_name} inet6 +} + +atf_init_test_cases() +{ + + atf_add_test_case "tcp_dscp_inet6" +} + +# end +