Measure what encapsulation costs you

applied · 40 min · Objective 1.1

Task

Work out how many bytes of a 1500-byte Ethernet frame are actually your data, then prove your arithmetic against a real capture. Overhead is the reason a gigabit link never delivers a gigabit of payload, and it is examinable as the header sizes you are about to count.

Steps

  1. Predict first, on paper. Write down the header sizes you expect for an Ethernet frame carrying IPv4 carrying TCP with no options: Ethernet header and trailer, IP header, TCP header. Total them.
  2. Start a listener on Host B: nc -l -p 9000 > /dev/null. If nc is absent, python3 -m http.server 9000 and fetch from it instead.
  3. Capture on Host B while sending: sudo tcpdump -i eth0 -n -s 0 -w /tmp/x.pcap port 9000. From Host A, send a megabyte: head -c 1048576 /dev/urandom | nc 192.168.20.10 9000.
  4. Stop the capture and read the frame sizes: tcpdump -r /tmp/x.pcap -n -c 20 | head. Note the largest segment length tcpdump reports, which is the TCP payload, not the frame.
  5. Compare your prediction with what you measured, and account for any gap. The common surprises are the 14-byte Ethernet header tcpdump does not print in the length field, and TCP timestamp options adding 12 bytes.

Verify

python3 -c "eth=14; ip=20; tcp=20; mtu=1500; print('payload', mtu-ip-tcp, 'efficiency', round((mtu-ip-tcp)/(mtu+eth+4)*100,2), '%')"
tcpdump -r /tmp/x.pcap -n | awk '{print $NF}' | sort -n | tail -1

The Python line gives 1460 bytes of payload and roughly 96% efficiency counting the frame's own overhead. The largest length in the capture should be 1460 — or 1448 if timestamps are on, which is the answer to "why is mine 12 short".

Notes

Extend it by adding a VLAN tag (4 more bytes) or a VPN. A GRE or IPsec tunnel wraps the whole packet in another set of headers, which is why tunnels so often cause the fragmentation problems domain 5 asks about: the payload shrinks and nobody told the application.