← Interview Prep
Life of a Packet — Fundamentals
Three scenarios, walked field by field: what changes, what stays, and why.
A whiteboard-friendly format: at every hop, write down what changed, what
stayed the same, and why. The one principle to state out loud before anything
else:
The L2 header lives exactly one hop (hop-by-hop) and is rewritten at
every router. L3 addresses live end-to-end and never change — until NAT
appears. L4 is touched by no one except NAT and MSS clamping.
Scenario A — One L2 segment (single subnet)
H1 ──────── SW1 ──────── H2
10.0.10.11/24 10.0.10.22/24
aa:aa:aa:00:00:11 aa:aa:aa:00:00:22
VLAN 10, both ports access
A.1 The sender's decision: local or via the gateway
H1 applies its own mask to the destination address:
10.0.10.11 AND 255.255.255.0 = 10.0.10.0
10.0.10.22 AND 255.255.255.0 = 10.0.10.0
They match → the destination is on my subnet → send it
directly, destination MAC = H2's own MAC, the gateway is not involved at all.
This is the key fork of the whole walkthrough, and it must be said explicitly:
the router is neither needed nor involved in this scenario, even if one
exists on the network.
A.2 ARP (if the cache is empty)
ARP Request — broadcast:
| Field | Value |
| DST MAC | ff:ff:ff:ff:ff:ff |
| SRC MAC | aa:aa:aa:00:00:11 |
| EtherType | 0x0806 (ARP) |
| Sender IP / MAC | 10.0.10.11 / aa:aa:aa:00:00:11 |
| Target IP / MAC | 10.0.10.22 / 00:00:00:00:00:00 |
ARP Reply — now unicast, from H2 to H1, with the Target filled in.
Side effect: at this moment the switch learned H1's MAC on its port (from the request's
SRC MAC), and H2's MAC from the reply.
A.3 The data frame
| Field | Value |
| DST MAC | aa:aa:aa:00:00:22 — the receiver itself |
| SRC MAC | aa:aa:aa:00:00:11 |
| EtherType | 0x0800 (IPv4) |
| SRC IP / DST IP | 10.0.10.11 / 10.0.10.22 |
| TTL | 64 — and stays 64 |
| L4 | unchanged |
A.4 What the switch does
- Looks only at the DST MAC, searches for it in the MAC table (FDB) for this VLAN.
- Found → sends out one port. Not found → floods to all ports
in the VLAN except the ingress one (unknown unicast flooding).
- Does not touch the IP header: TTL is not decremented, the IP checksum is not recomputed.
- FCS: under store-and-forward it is checked and regenerated. Adding or
removing an 802.1Q tag forces an FCS recompute, because the frame length changed.
A.5 If there is a trunk between them
On a trunk an 802.1Q tag is inserted — +4 bytes between SRC MAC and EtherType:
| Field | Value |
| TPID | 0x8100 |
| PCP | priority 0–7 (this is CoS) |
| DEI | 1 bit |
| VID | 10 |
The maximum frame becomes 1522 bytes. On the egress access port the tag is stripped.
This is the only modification a "plain" switch makes to a frame.
A.6 Going deeper
- What happens if H1's mask is wrong (
/16 instead of /24)?
The packet is sent straight to L2, ARP gets no reply, connectivity fails — a classic
misconfiguration.
- Where does the frame go if the destination MAC isn't learned? Flooding, and why it is a
security and performance problem.
- What gratuitous ARP is, and why it matters on address moves / VRRP.
- Proxy ARP: when a router answers with its own MAC for someone else's IP, and why it is
more of a crutch.
Scenario B — Routing, multiple hops
H1 ── R1 ══ R2 ══ R3 ── H2
10.0.10.11/24 10.0.30.22/24
GW 10.0.10.1 GW 10.0.30.1
R1: e0 10.0.10.1/24 (MAC bb:...:01) e1 10.0.255.0/31 (MAC bb:...:11)
R2: e0 10.0.255.1/31 (MAC cc:...:01) e1 10.0.255.2/31 (MAC cc:...:11)
R3: e0 10.0.255.3/31 (MAC dd:...:01) e1 10.0.30.1/24 (MAC dd:...:11)
B.1 The sender's decision
10.0.30.22 AND 255.255.255.0 = 10.0.30.0 ≠ 10.0.10.0 →
different subnet → send to the default gateway's MAC.
A critical detail people trip on: ARP is done for the gateway's IP (10.0.10.1),
not the receiver's IP. H1 will never learn H2's MAC, and it shouldn't.
B.2 The frame on the first hop (H1 → R1)
| Field | Value |
| DST MAC | bb:...:01 — the gateway's MAC, not the receiver's |
| SRC MAC | aa:aa:aa:00:00:11 |
| SRC IP / DST IP | 10.0.10.11 / 10.0.30.22 |
| TTL | 64 |
B.3 What happens at every router
The same loop, repeated on R1, R2, R3:
- Verify the DST MAC is mine (otherwise drop, unless promiscuous).
- Strip the L2 header, check the FCS.
- Take the DST IP → LPM lookup in the FIB → egress interface and next-hop.
- TTL − 1. If it hits 0 → drop and return ICMP Time Exceeded (type 11).
- Recompute the IP header checksum (incrementally, RFC 1624 — the whole header is not re-summed).
- Find the next-hop MAC (ARP / neighbor cache); no entry → ARP request, the packet waits in a queue.
- Build a new L2 header: SRC MAC = my egress interface, DST MAC = next-hop.
- Recompute the FCS and send.
B.4 Per-hop summary
| Hop | DST MAC | SRC MAC | SRC IP | DST IP | TTL |
| H1 → R1 | bb:…:01 | aa:…:11 | 10.0.10.11 | 10.0.30.22 | 64 |
| R1 → R2 | cc:…:01 | bb:…:11 | 10.0.10.11 | 10.0.30.22 | 63 |
| R2 → R3 | dd:…:01 | cc:…:11 | 10.0.10.11 | 10.0.30.22 | 62 |
| R3 → H2 | aa:…:22 | dd:…:11 | 10.0.10.11 | 10.0.30.22 | 61 |
In one sentence: L2 changes completely at every hop, L3 addresses change nowhere,
TTL decreases, the IP checksum is recomputed, and no one touches L4.
B.5 The subtleties that separate levels
- TCP/UDP checksum does not change, even though the pseudo-header contains
IP addresses — simply because the addresses didn't change. In Scenario C this stops being true.
- IPv6: no header checksum at all (nothing to recompute), TTL is called
Hop Limit, and intermediate nodes do not fragment — only the
source does, after PMTUD.
- IPv4 fragmentation: if the egress MTU is smaller than the packet and DF=0,
the router splits it, filling Identification, the MF flag and Fragment Offset; only the receiver
reassembles. If DF=1 — drop and ICMP type 3 code 4 with the MTU. Hence PMTUD and its black holes
when ICMP is filtered.
- ECMP: with several paths, selection is by a hash of the 5-tuple; packets of one
flow follow one path (to preserve ordering), different flows take different paths.
- Traceroute is built on exactly this: packets with TTL 1, 2, 3… each hop returns
Time Exceeded with its own address.
- The return traffic is a fully mirrored procedure, and the path may be
asymmetric — normal for routing, but it breaks stateful devices (firewalls, NAT).
B.6 If there is MPLS/VXLAN between hops
- MPLS: a stack of 4-byte labels is inserted between L2 and L3; a transit node
swaps the label, and the inner IP TTL is usually untouched (TTL lives in the label; with
no-propagate, traceroute won't see the core).
- VXLAN: the original frame is placed whole inside a new Eth+IP+UDP+VXLAN
(+50 bytes); the inner headers don't change at all, and the outer IP lives VTEP-to-VTEP. The
inner TTL is not decremented on underlay transit nodes.
Scenario C — L2 + L3 + Internet via NAT
H1 ── SW1 ── R(NAT/FW) ══ ISP ══ Internet ── Server
192.168.1.11/24 WAN 203.0.113.5 93.184.216.34:443
GW 192.168.1.1
H1 opens a TCP session to 93.184.216.34:443, source port 51514.
C.1 Inside the LAN (H1 → R)
As in Scenario B: different subnet → ARP for the gateway → frame to the gateway's MAC.
| Field | Value |
| DST MAC / SRC MAC | MAC of R / MAC of H1 |
| SRC IP : port | 192.168.1.11 : 51514 |
| DST IP : port | 93.184.216.34 : 443 |
| TTL | 64 |
C.2 At the NAT router — what changes on top
First ordinary routing (TTL−1, new L2, IP checksum recompute), and on top of that:
| What | Before | After |
| SRC IP | 192.168.1.11 | 203.0.113.5 |
| SRC port | 51514 | 62001 (chosen by NAT, under PAT) |
| DST IP : port | 93.184.216.34 : 443 | unchanged |
| IP checksum | — | recomputed (address changed) |
| TCP checksum | — | recomputed, because the pseudo-header contains SRC IP, which changed |
The key point to state explicitly: NAT is the only place in this walkthrough where an
L3 address changes and, as a consequence, an L4 checksum must be touched. That is what
separates NAT from routing fundamentally, not quantitatively.
A translation-table (conntrack) entry appears:
192.168.1.11:51514 ⇄ 203.0.113.5:62001 → 93.184.216.34:443 TCP ESTABLISHED
C.3 The packet on the Internet
| Field | Value |
| SRC MAC / DST MAC | MAC of R's WAN interface / MAC of the ISP router |
| SRC IP : port | 203.0.113.5 : 62001 |
| DST IP : port | 93.184.216.34 : 443 |
| TTL | 63, decreasing at every hop after |
The server sees only the public address; it knows nothing about the existence of 192.168.1.11.
C.4 The return path
The reply arrives at 203.0.113.5:62001. The router looks up the translation table:
- found → DST IP is rewritten to
192.168.1.11,
DST port to 51514, IP and TCP checksums recomputed;
- not found (session expired, a restart, an asymmetric path) → the packet is dropped. Hence
"the session was working and suddenly died" after a timeout or a failover to a standby node without
state sync.
Then ordinary LAN delivery: ARP for 192.168.1.11, frame to H1's MAC.
C.5 Variants and details
- PAT / NAT overload — many inside addresses behind one outside address,
distinguished by port. The limit is ~64k ports per outside address per destination; with many
clients this is exactly what you hit.
- Static NAT / DNAT (port forwarding) — translating inbound: DST IP and port are rewritten.
- ICMP through NAT: ICMP has no ports, so the Identifier field in
the echo request serves as the session id. And for ICMP errors NAT must look inside the
embedded IP header and rewrite the addresses there too — otherwise the error can't find its owner.
- Hairpin / NAT loopback — an inside client reaching its own public address; requires double translation.
- What NAT breaks: end-to-end addressing, protocols carrying addresses in the payload
(FTP active, SIP, H.323 — hence ALG crutches), IPsec AH, PMTUD when ICMP is filtered, inbound connections without explicit forwarding.
- CGNAT and why providers are forced to use it; logging translations as a regulatory requirement.
- MSS clamping at the edge — the second (and only other legitimate) place where the
network changes an L4 header: the router lowers the MSS in the SYN to work around tunnel PMTUD problems.
Cheat sheet: what changes where
| Field | L2 switch | Router | NAT |
| DST MAC | selects a port, doesn't change | rewrites | rewrites |
| SRC MAC | doesn't change | rewrites | rewrites |
| 802.1Q tag | may add/remove | usually removes | — |
| FCS | recomputes (S&F, tag) | recomputes | recomputes |
| SRC IP / DST IP | doesn't touch | doesn't touch | rewrites one of them |
| TTL | doesn't touch | −1 | −1 |
| IP checksum | doesn't touch | recomputes | recomputes |
| L4 ports | doesn't touch | doesn't touch | rewrites (PAT) |
| TCP/UDP checksum | doesn't touch | doesn't touch | recomputes |
| Payload | doesn't touch | doesn't touch | doesn't touch (except ALG) |
How to present it at the whiteboard
- Start with the fork: my subnet or someone else's — everything else depends on
it. Show the AND-with-the-mask operation.
- State separately: ARP is always for the next-hop, not the final address.
- Keep two columns — "changes" and "doesn't change." The interviewer is usually looking for exactly
this understanding of the hop-by-hop vs. end-to-end boundary.
- Call out the side effects: MAC learning, ARP-cache population, conntrack entry creation. State is
what breaks later.
- Finish with a clarifying question: "want me to show what changes if we insert MPLS/VXLAN between
hops, or if the path is asymmetric?" — this turns the walkthrough into a dialogue and shows depth.
Likely follow-up questions
- What happens if two hosts in the same segment have different masks?
- Why does a router decrement TTL but a switch doesn't — and what then protects the L2 network from
loops? (nothing, hence STP and storm control)
- Why did IPv6 drop the header checksum? (L4 and L2 already compute one, and recomputing at every hop was wasted work)
- What does the same walkthrough look like for a VRRP gateway? (virtual MAC
00:00:5e:00:01:XX, the active router answers ARP)
- What happens on an asymmetric path through two NAT devices without state sync?
- Where does a firewall enter this picture, and why is it stateful too?