Here we present the steps taken for setting up a test that uses *only* the TBS qdisc. That means that only Time-based transmission is exercised. The 'talker' side of the example described below will transmit a packet every 1ms. The packet's txtime is set through the SO_TXTIME api, and is copied into the packet's payload. At the 'listener' side, we capture traffic and then post-process it to compute the delta between each packet's arrival time and their txtime. ptp4l is used for synchronizing the PHC clocks over the network and phc2sys is used on the 'talker' size for synchronizing the system clock to the PHC. CLOCK_TAI is the reference clockid used throughout the example for the qdiscs and the applications. # LISTENER # 1) Setup the PTP master. If using the listener end point as PTP master, setup_clock_sync.sh can be used as the below. e.g.: $ sudo ip addr add 192.168.0.78/4 broadcast 192.168.0.255 dev IFACE $ sudo ./setup_clock_sync.sh -i IFACE -m -v This script will start ptp4l so the PHC time is propagated to the network. The system clock and the PHC are NOT synchronized on that mode. * Note that the TAI offset is applied, so CLOCK_REALTIME will be in the UTC scale while CLOCK_TAI will be in the TAI scale, just like the PHC. 2) Start capturing traffic on the listener end point. If we want to capture traffic for 1 minute, and are expecting 1 packet per milisecond: e.g.: $ sudo tcpdump -c 60000 -i enp3s0 -w tmp.pcap \ -j adapter_unsynced -tt --time-stamp-precision=nano \ udp port 7788 # TALKER # 3) Configure the Qdiscs on the talker side (Device Under Testing, DUT). Our DUT uses an Intel i210 NIC, and our setup here is as follows. 1.a) First, we setup mqprio as the root qdisc: e.g.: $ sudo tc qdisc replace dev IFACE parent root mqprio \ num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \ queues 1@0 1@1 2@2 hw 0 1.b) Then we setup tbs with the desired config: e.g.: $ sudo tc qdisc add dev enp2s0 parent 8001:1 tbs \ offload clockid CLOCK_TAI sorting delta 150000 4) Setup the Device Under Testing (DUT) as PTP slave and synchronize the local clocks. e.g.: $ sudo ip addr add 192.168.0.77/4 broadcast 192.168.0.255 dev IFACE $ sudo ./setup_clock_sync.sh -i IFACE -s -v This script will start ptp4l so the PHC is synchronized to the PTP master, and then will synchronize the system clock to PHC using phc2sys. At this stage, based purely on empirical observations, one recommendation is waiting for the rms value reported by ptp4l to reach a value below 15 ns, and to remain somewhat constant after that. * Note that the TAI offset is applied, so CLOCK_REALTIME will be in the UTC scale while CLOCK_TAI will be in the TAI scale, just like the PHC. 5) Optionally, build and run check_clocks on both PTP master and slave. e.g.: $ make check_clocks && sudo ./check_clocks IFACE It reports the timestamps fetched from CLOCK_REALTIME, CLOCK_TAI and the interface's PHC, as well the latency for reading from each clock and the delta between the PHC and the system clocks. You may use this information to verify if the offsets were applied correctly and if the PHC - CLOCK_TAI delta is not too high. Again, based on empirical observations, we consider this value as "good enough" if it's less than 25us, and it's been observed to get as low as 4us. 6) Build and run udp_tai on the talker end station e.g.: $ gcc -o udp_tai -lpthread udp_tai.c $ sudo ./udp_tai -i enp2s0 -P 1000000 -p 90 -d 600000 # LISTENER # 7) Analyze traffic and generate statistics. We first use tshark for post-processing the pcap file as needed, then we use a custom python script to compute the packets' offset from their expected arrival time, and then compute statistics for the overall data set. e.g.: $ tshark -r tmp.pcap --disable-protocol dcp-etsi --disable-protocol \ dcp-pft -t e -E separator=, -T fields -e frame.number \ -e frame.time_epoch -e data.data > tmp.out $ ./txtime_offset_stats.py -f tmp.out