Engineering Atlas › System Design Fundamentals

The OSI layers in practice

13 min read · last reviewed 2026-10-17

Open in the interactive app: practice, quiz, mock interview →

In one minute

How it works

Seven names, four implementations

OSI defines physical (1), data link (2), network (3), transport (4), session (5), presentation (6) and application (7). The TCP/IP stack that actually shipped has link, internet, transport and application (RFC 1122). Sessions live in applications (cookies, gRPC streams), and presentation lives in libraries (TLS, protobuf, gzip). So "layer 7" means "anything above transport, as parsed by a proxy". The numbers survive because they answer a design-review question precisely: what does this component read, and what does it treat as opaque bytes?

What each layer lets a box see

A layer 2 switch reads the destination MAC and forwards the frame out of the port where it learned that MAC. A loop or broadcast storm crosses the whole broadcast domain.

A layer 3 router reads the destination IP, does a longest-prefix match, decrements TTL and forwards. Equal-cost multipath (ECMP) spreads flows across links by hashing header fields.

A layer 4 load balancer reads the protocol and ports as well, so it can pin a whole connection (the 5-tuple: source IP, source port, destination IP, destination port, protocol) to one backend. Pass-through designs (Maglev, Katran, AWS Network Load Balancer) forward packets without terminating TCP; others terminate it and open a second connection. Pass-through balancers reach backends either by rewriting only the destination MAC (direct server return, which needs one shared layer 2 domain) or by wrapping each packet in GRE, which adds 24 bytes and can push a full-size packet past the MTU (Google SRE book, ch. 19). Neither kind sees the HTTP path.

A layer 7 proxy (Envoy, NGINX, HAProxy in HTTP mode, AWS Application Load Balancer) terminates TCP and usually TLS, parses the request, and can route by host, path, header or gRPC method, retry, authenticate and emit per-request metrics. The price is two connections per client, TLS crypto and more CPU per request.

Encapsulation and the MTU budget

Sending data pushes headers in front of it: TLS record framing (a 5-byte header, plus in TLS 1.3 a 1-byte inner content type and a 16-byte AEAD tag, per RFC 9846), TCP (20 bytes, usually 32 with timestamps), IPv4 (20) or IPv6 (40), and Ethernet (14 plus a 4-byte frame check sequence). The IP packet must fit the MTU of every link on the path, usually 1,500 bytes. Tunnels nest whole packets: VXLAN, common in Kubernetes overlays, adds 50 bytes, WireGuard 60 over IPv4 and 80 over IPv6, GRE 24.

Fragmentation is slow, and only the first fragment carries ports, so TCP sets Don't Fragment and relies on Path MTU Discovery. A router that cannot forward the packet drops it and returns ICMP "fragmentation needed" (IPv4) or "packet too big" (IPv6, where routers never fragment). If a firewall drops that ICMP, the sender never learns, and large packets vanish silently: a PMTUD black hole.

The robust fix stops trusting ICMP. With packetization-layer PMTUD, the transport sends probes of increasing size and learns the path MTU from which ones are acknowledged (RFC 8899). Linux TCP does this when tcp_mtu_probing is 1 (only after it suspects a black hole) or 2 (always) (kernel ip-sysctl). QUIC refuses paths that can't carry a 1,200-byte UDP payload and may probe upward from there the same way (RFC 9000).

Where the layering breaks

NAT is an L3 box rewriting L4 ports. TLS fits no layer cleanly. VXLAN carries L2 frames inside UDP. Middleboxes that assumed what TCP headers look like froze TCP, which is a large part of why QUIC encrypts its transport header and runs over UDP.

Down the stack

Layer 1The contract

Each layer serves the one above and treats its bytes as opaque. Ethernet delivers a CRC-checked frame on one segment or drops it, IP forwards best-effort, TCP provides an ordered byte stream, TLS adds confidentiality and integrity. Infrastructure contracts can be stated precisely enough to test. A pass-through L4 balancer promises that all packets of a 5-tuple reach the same backend while the backend set is stable. An L7 proxy promises per-request routing and offers no affinity unless configured. A tunnel promises to carry inner packets up to its advertised MTU and nothing larger.

Layer 2The mechanism

In Linux, a packet is an sk_buff with head, data, tail and end pointers into one buffer. Each layer prepends its header with skb_push, which moves the data pointer backwards into headroom reserved in advance, so encapsulation needs no copy (kernel sk_buff docs). On receive, skb_pull advances past each header as the stack climbs. Netfilter hooks (PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING) are where iptables or nftables, conntrack and NAT act, at the IP layer but with knowledge of ports.

The 20-byte IPv4 header holds version and length, DSCP/ECN, total length, identification, flags and fragment offset, TTL, protocol (6 TCP, 17 UDP), a checksum and the two addresses. The checksum is the ones' complement of the ones' complement sum of the header's 16-bit words, which lets a router patch it incrementally after decrementing TTL (RFC 1624). Envoy mirrors the split: network filters (tcp_proxy, the TLS inspector reading SNI) work per connection, HTTP filters per request.

Layer 3The machine

A 10 Gbps link carries about 812,000 full-size 1,500-byte packets per second, or 14.88 million minimum-size 64-byte frames. Per-packet work sets the CPU cost, so NICs offload layers: checksum offload, TSO/GSO (the kernel hands down a 64 KB super-segment that the NIC slices into MSS-sized packets), GRO (merging arriving segments), and RSS, which hashes the 5-tuple to pick a receive queue and core, an L4 decision in silicon.

Moving up multiplies cost. An XDP or DPDK L4 balancer forwards millions of packets per second per core. An L7 proxy pays for TLS handshakes (roughly 0.1 to 0.3 ms of CPU each for ECDHE P-256), header parsing and socket buffers on both sides, and typically serves tens of thousands of HTTPS requests per second per core.

Why it's built this way

  1. No single design could cover every medium and application, so layers change independently: Ethernet went from 10 Mbps to 400 Gbps without HTTP noticing.
  2. Independent layers need their own addressing, so every layer adds a header that costs MTU bytes and per-packet work.
  3. Parsing deeper costs more CPU and state, so the network core stays at L3 and expensive L7 work moves to the edges, where it can be scaled out.
  4. Middleboxes optimised by reading layers they did not own, which froze those layers, so new protocols (QUIC) encrypt their headers to keep the freedom to change.

Diagram

flowchart LR
    A["App: HTTP request"] --> T["TLS record"]
    T --> P["TCP segment: ports, seq"]
    P --> I["IP packet: src, dst, TTL"]
    I --> E["Ethernet frame: MACs"]
    E --> SW["Switch reads L2"]
    SW --> R["Router reads L3"]
    R --> L4["L4 LB reads 5-tuple"]
    L4 --> L7["L7 proxy ends TLS, reads path"]
    L7 --> S["Service"]

Worked example

A Kubernetes cluster runs a VXLAN overlay on a 1,500-byte cloud network, and pods reach a partner over WireGuard inside the overlay.

Efficiency falls from 1,448/1,500 (96.5%) to 1,338/1,500 (89.2%); at 2 Gbps that is about 150 Mbps of extra headers.

The incident: someone leaves WireGuard at its default 1,420. Small API calls work, but a response carrying a 5 KB certificate chain hangs. A 1,420-byte inner packet plus 60 is 1,480, which exceeds the 1,450 pod MTU; the overlay drops it, and the ICMP reply is blocked by a security group. ping -M do -s 1362 succeeds while -s 1400 fails, which confirms it. Fix the MTU on each nested interface, clamp MSS on the tunnel (--clamp-mss-to-pmtu), and allow ICMP type 3 code 4 and ICMPv6 type 2.

The layer choice also shows at the balancer. With 40 gRPC clients each holding one HTTP/2 connection through an L4 balancer to 10 backends, a client sending 5,000 requests per second puts all of them on one backend. An L7 proxy spreads per request, at the cost of TLS termination and about 1 ms.

In the wild

Trade-offs

OptionStrengthsWeaknessesChoose when
L3 (ECMP, anycast)Line rate in hardware, no per-flow stateHash-based spread only, no health detailSpreading across L4 balancers or PoPs
L4 pass-through LBMillions of pps, preserves client IP, TLS stays end to endBalances connections not requests, cannot route by pathRaw TCP/UDP services, front tier of a large edge
L4 terminating LBHides backends, can add TLSTwo connections, client IP needs PROXY protocolSimple TCP services needing a stable endpoint
L7 proxyPer-request routing, retries, auth, rich metricsCPU for TLS and parsing, more latency, more config surfaceHTTP/gRPC APIs, canaries, path routing
Sidecar mesh (L7 everywhere)Uniform mTLS and telemetryA proxy hop on each side of every call, more memoryMany services and teams that need the same policy

Pitfalls in production

Leadership lens

Check yourself

  1. Why can a pass-through L4 load balancer not send /images/ to a different pool than /api/?

    Show answer

    The path is inside the HTTP request, usually inside TLS. A pass-through L4 device forwards packets by 5-tuple without terminating TCP or decrypting, so it never sees the path.

  2. A VPN user can load small pages but large downloads stall. Which layers would you suspect first and why?

    Show answer

    L3 MTU and ICMP. The tunnel adds headers so full-size packets no longer fit, and if ICMP "fragmentation needed" is blocked, the sender never shrinks its segments.

  3. Why does QUIC encrypt most of its transport header when TCP does not?

    Show answer

    Middleboxes inspected and made assumptions about TCP headers, which made TCP almost impossible to evolve. Encrypting the header stops middleboxes from depending on it and keeps the protocol changeable.

Sources and further study

Primary

Systems docs

Books

Other curricula

Watch

Free resources

Open in the interactive app: practice, quiz, mock interview →