From: Willem de Bruijn <will...@google.com> Enable passing an SCM_TXTIME ('-x'), optionally configured to use multi release (SOF_TXTIME_MULTI_RELEASE) ('-X').
With multi release, the segments that make up a single udp gso packet can be released over time, as opposed to burst at once. Repurpose the lower 8 bits of the 64 bit timestamp for this purpose. - bits 4..7: delay between transmit periods in msec - bits 0..3: number of segments sent per period Also add an optional delay in usec between sendmsg calls ('-d'). To reduce throughput sufficiently to observe pacing delay introduced. Added udpgso_bench_multi.sh, derived from so_txtime_multi.sh, to run tests over veth. Also fix up a minor issue where sizeof the wrong field was used (mss, instead of gso_size). They happen to both be uint16_t. Tested: ./udpgso_bench_multi.sh or manually ran across two hosts: # sender # # -S 6000 -s 1400: 6000B buffer encoding 1400B datagrams # -d 200000: 200 msec delay between sendmsg # -x 0x989611: ~1000000 nsec first delay + 1 MSS every 1 msec ./udpgso_bench_tx -6 -D fd00::1 \ -l 1 -s 6000 -S 1400 -v -d 200000 -x 0x989611 -X # receiver tcpdump -n -i eth1 -c 100 udp and port 8000 & sleep 0.2 ./udpgso_bench_rx 16:29:45.146855 IP6 host1.40803 > host2.8000: UDP, length 1400 16:29:45.147798 IP6 host1.40803 > host2.8000: UDP, length 1400 16:29:45.148797 IP6 host1.40803 > host2.8000: UDP, length 1400 16:29:45.149797 IP6 host1.40803 > host2.8000: UDP, length 1400 16:29:45.150796 IP6 host1.40803 > host2.8000: UDP, length 400 16:29:45.347056 IP6 host1.40803 > host2.8000: UDP, length 1400 16:29:45.348000 IP6 host1.40803 > host2.8000: UDP, length 1400 16:29:45.349000 IP6 host1.40803 > host2.8000: UDP, length 1400 16:29:45.349999 IP6 host1.40803 > host2.8000: UDP, length 1400 16:29:45.350999 IP6 host1.40803 > host2.8000: UDP, length 400 Signed-off-by: Willem de Bruijn <will...@google.com> --- .../selftests/net/udpgso_bench_multi.sh | 65 +++++++++++++++++ tools/testing/selftests/net/udpgso_bench_tx.c | 72 +++++++++++++++++-- 2 files changed, 133 insertions(+), 4 deletions(-) create mode 100755 tools/testing/selftests/net/udpgso_bench_multi.sh diff --git a/tools/testing/selftests/net/udpgso_bench_multi.sh b/tools/testing/selftests/net/udpgso_bench_multi.sh new file mode 100755 index 000000000000..c29f75aec759 --- /dev/null +++ b/tools/testing/selftests/net/udpgso_bench_multi.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Regression tests for the SO_TXTIME interface + +readonly ns_prefix="ns-sotxtime-" +readonly ns1="${ns_prefix}1" +readonly ns2="${ns_prefix}2" + +readonly ns1_v4=192.168.1.1 +readonly ns2_v4=192.168.1.2 +readonly ns1_v6=fd::1 +readonly ns2_v6=fd::2 + +set -eu + +cleanup() { + ip netns del "${ns2}" + ip netns del "${ns1}" +} + +setup() { + ip netns add "${ns1}" + ip netns add "${ns2}" + + ip link add dev veth1 mtu 1500 netns "${ns1}" type veth \ + peer name veth2 mtu 1500 netns "${ns2}" + + ip -netns "${ns1}" link set veth1 up + ip -netns "${ns2}" link set veth2 up + + ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1 + ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2 + ip -netns "${ns1}" -6 addr add "${ns1_v6}/64" dev veth1 nodad + ip -netns "${ns2}" -6 addr add "${ns2_v6}/64" dev veth2 nodad + + ip netns exec "${ns1}" tc qdisc add dev veth1 root fq +} + +run_test() { + ip netns exec "${ns2}" tcpdump -q -n -i veth2 udp & + ip netns exec "${ns2}" ./udpgso_bench_rx & + sleep 0.1 + ip netns exec "${ns1}" ./udpgso_bench_tx $@ + pkill -P $$ +} + +run_test_46() { + run_test -4 -D "${ns2_v4}" $@ + run_test -6 -D "${ns2_v6}" $@ +} + +trap cleanup EXIT +setup + +echo "gso + pacing" +TEST_ARGS="-l 1 -s 3500 -S 1000 -v -d 200000 -x 1000000" +run_test_46 ${TEST_ARGS} -x 1000000 + +echo "gso + multi release pacing" +run_test_46 ${TEST_ARGS} -X -x 0x989611 +run_test_46 ${TEST_ARGS} -X -x 0x9896A2 + +# Does not validate pacing delay yet. Check manually. +echo "Ok. Executed tests." diff --git a/tools/testing/selftests/net/udpgso_bench_tx.c b/tools/testing/selftests/net/udpgso_bench_tx.c index 17512a43885e..264222c2b94e 100644 --- a/tools/testing/selftests/net/udpgso_bench_tx.c +++ b/tools/testing/selftests/net/udpgso_bench_tx.c @@ -23,6 +23,7 @@ #include <sys/time.h> #include <sys/poll.h> #include <sys/types.h> +#include <time.h> #include <unistd.h> #include "../kselftest.h" @@ -56,6 +57,7 @@ static bool cfg_cache_trash; static int cfg_cpu = -1; static int cfg_connected = true; +static int cfg_delay_us; static int cfg_family = PF_UNSPEC; static uint16_t cfg_mss; static int cfg_payload_len = (1472 * 42); @@ -65,6 +67,8 @@ static bool cfg_poll; static bool cfg_segment; static bool cfg_sendmmsg; static bool cfg_tcp; +static uint64_t cfg_txtime; +static bool cfg_txtime_multi; static uint32_t cfg_tx_ts = SOF_TIMESTAMPING_TX_SOFTWARE; static bool cfg_tx_tstamp; static bool cfg_audit; @@ -306,6 +310,34 @@ static void send_ts_cmsg(struct cmsghdr *cm) *valp = cfg_tx_ts; } +static uint64_t gettime_ns(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + error(1, errno, "gettime"); + + return ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; +} + +static void send_txtime_cmsg(struct cmsghdr *cm) +{ + uint64_t tdeliver, *valp; + + tdeliver = gettime_ns() + cfg_txtime; + + if (cfg_txtime_multi) { + tdeliver &= ~0xFF; + tdeliver |= cfg_txtime & 0xFF; + } + + cm->cmsg_level = SOL_SOCKET; + cm->cmsg_type = SCM_TXTIME; + cm->cmsg_len = CMSG_LEN(sizeof(cfg_txtime)); + valp = (void *)CMSG_DATA(cm); + *valp = tdeliver; +} + static int send_udp_sendmmsg(int fd, char *data) { char control[CMSG_SPACE(sizeof(cfg_tx_ts))] = {0}; @@ -373,7 +405,8 @@ static void send_udp_segment_cmsg(struct cmsghdr *cm) static int send_udp_segment(int fd, char *data) { char control[CMSG_SPACE(sizeof(cfg_gso_size)) + - CMSG_SPACE(sizeof(cfg_tx_ts))] = {0}; + CMSG_SPACE(sizeof(cfg_tx_ts)) + + CMSG_SPACE(sizeof(uint64_t))] = {0}; struct msghdr msg = {0}; struct iovec iov = {0}; size_t msg_controllen; @@ -390,12 +423,17 @@ static int send_udp_segment(int fd, char *data) msg.msg_controllen = sizeof(control); cmsg = CMSG_FIRSTHDR(&msg); send_udp_segment_cmsg(cmsg); - msg_controllen = CMSG_SPACE(sizeof(cfg_mss)); + msg_controllen = CMSG_SPACE(sizeof(cfg_gso_size)); if (cfg_tx_tstamp) { cmsg = CMSG_NXTHDR(&msg, cmsg); send_ts_cmsg(cmsg); msg_controllen += CMSG_SPACE(sizeof(cfg_tx_ts)); } + if (cfg_txtime) { + cmsg = CMSG_NXTHDR(&msg, cmsg); + send_txtime_cmsg(cmsg); + msg_controllen += CMSG_SPACE(sizeof(cfg_txtime)); + } msg.msg_controllen = msg_controllen; msg.msg_name = (void *)&cfg_dst_addr; @@ -413,7 +451,7 @@ static int send_udp_segment(int fd, char *data) static void usage(const char *filepath) { - error(1, 0, "Usage: %s [-46acmHPtTuvz] [-C cpu] [-D dst ip] [-l secs] [-M messagenr] [-p port] [-s sendsize] [-S gsosize]", + error(1, 0, "Usage: %s [-46acmHPtTuvXz] [-C cpu] [-d delay] [-D dst ip] [-l secs] [-M messagenr] [-p port] [-s sendsize] [-S gsosize] [-x time]", filepath); } @@ -422,7 +460,7 @@ static void parse_opts(int argc, char **argv) int max_len, hdrlen; int c; - while ((c = getopt(argc, argv, "46acC:D:Hl:mM:p:s:PS:tTuvz")) != -1) { + while ((c = getopt(argc, argv, "46acC:d:D:Hl:mM:p:s:PS:tTuvx:Xz")) != -1) { switch (c) { case '4': if (cfg_family != PF_UNSPEC) @@ -445,6 +483,9 @@ static void parse_opts(int argc, char **argv) case 'C': cfg_cpu = strtol(optarg, NULL, 0); break; + case 'd': + cfg_delay_us = strtol(optarg, NULL, 0); + break; case 'D': setup_sockaddr(cfg_family, optarg, &cfg_dst_addr); break; @@ -486,6 +527,12 @@ static void parse_opts(int argc, char **argv) case 'v': cfg_verbose = true; break; + case 'x': + cfg_txtime = strtoull(optarg, NULL, 0); + break; + case 'X': + cfg_txtime_multi = true; + break; case 'z': cfg_zerocopy = true; break; @@ -551,6 +598,17 @@ static void set_tx_timestamping(int fd) error(1, errno, "setsockopt tx timestamping"); } +static void set_txtime(int fd) +{ + struct sock_txtime txt = { .clockid = CLOCK_MONOTONIC }; + + if (cfg_txtime_multi) + txt.flags = SOF_TXTIME_MULTI_RELEASE; + + if (setsockopt(fd, SOL_SOCKET, SO_TXTIME, &txt, sizeof(txt))) + error(1, errno, "setsockopt txtime"); +} + static void print_audit_report(unsigned long num_msgs, unsigned long num_sends) { unsigned long tdelta; @@ -652,6 +710,9 @@ int main(int argc, char **argv) if (cfg_tx_tstamp) set_tx_timestamping(fd); + if (cfg_txtime) + set_txtime(fd); + num_msgs = num_sends = 0; tnow = gettimeofday_ms(); tstart = tnow; @@ -687,6 +748,9 @@ int main(int argc, char **argv) if (cfg_cache_trash) i = ++i < NUM_PKT ? i : 0; + if (cfg_delay_us) + usleep(cfg_delay_us); + } while (!interrupted && (cfg_runtime_ms == -1 || tnow < tstop)); if (cfg_zerocopy || cfg_tx_tstamp) -- 2.27.0.278.ge193c7cf3a9-goog