0%
Networking for Backend Engineers
Transport
Names and Trust
Application Protocols
Getting Traffic to a Server
Performance
Layers, Frames, and Packets
Every networking course opens with a seven-layer diagram and almost none of them say what the layers are for. The answer is narrow and worth stating precisely: a layer exists so that the thing above it can be written without knowing how the thing below it works, and the only way a layer can deliver that is by answering two questions at every hop. Where does my payload end, and who do I hand it to.
Everything else in this lesson is the consequence of those two questions being answered in bytes, on the wire, by headers that are fixed in length and parsed by hardware.
The four layers that exist and the three that do not
The OSI model has seven layers. The stack in your kernel has four, and if you spend a day with tcpdump you will only ever see those four. There is a link layer that moves a frame between two interfaces that share a physical segment, a network layer that moves a packet between two hosts that may be twenty hops apart, a transport layer that moves a stream or a datagram between two processes, and an application layer that is whatever you wrote. The session, presentation and part of the application layer of the OSI model do not correspond to any header, any syscall or any kernel subsystem. They are a taxonomy, not an implementation.
This matters more than pedantry because engineers reason about failures through the model they hold. If you believe there are seven layers, TLS is layer 6 and you will look for it in the wrong place. TLS is a protocol that runs on top of TCP and produces a byte stream for HTTP, so in the only model that matches the implementation it sits inside the transport payload, and that is exactly where a capture shows it. If you believe there are four layers, you will ask the right question when a TLS handshake stalls: which of the two below it failed to deliver bytes.
Encapsulation is prefixing, not wrapping
The word encapsulation suggests a box inside a box. The reality is cheaper. Each layer prepends a fixed or nearly fixed header to the buffer it was handed, and the result is one contiguous sequence of bytes in which each header says how long it is and what kind of thing follows it.
A 100-byte HTTP request leaving a Linux box becomes a 120-byte TCP segment, a 140-byte IP packet, and a 154-byte Ethernet frame, and on the wire that frame is preceded by 8 bytes of preamble and followed by a 4-byte checksum. Nothing was copied into a container. The kernel allocated one sk_buff with headroom reserved at the front and each layer wrote into that headroom as the buffer moved down. This is why layering is nearly free in software and completely free in a NIC: the layers are offsets into one array.
Demultiplexing is a chain of lookups on three fields
The receiving side has the opposite job, and it is purely mechanical. Three fields, read in order, decide which function in the kernel gets the rest of the bytes.
The Ethernet header's EtherType is read first: 0x0800 means hand the payload to the IPv4 code, 0x86DD means IPv6, 0x0806 means ARP, 0x8100 means there is a VLAN tag here and the real EtherType is 4 bytes further on. The IP header's protocol field is read next: 6 means TCP, 17 means UDP, 1 means ICMP, 47 means GRE, 50 means IPsec ESP. The transport header's destination port is read last, and together with the source port and both addresses it forms the 4-tuple that identifies a socket.
So when a packet arrives for a port nobody is listening on, the failure happens at the third lookup, and the response differs by protocol: TCP replies with a RST, UDP replies with an ICMP port-unreachable, and that difference is the whole reason a UDP port scan behaves nothing like a TCP one. When a packet arrives with an EtherType the host does not implement, it is dropped silently at the first lookup, which is why an IPv6-only router on an IPv4-only host's segment is invisible rather than broken.
Each layer has its own addressing, and the scopes do not nest neatly
A frame is addressed to a 48-bit MAC address that is meaningful only on the local segment and is rewritten at every router hop. A packet is addressed to a 32-bit or 128-bit IP address that is meaningful end to end and is not rewritten, except that NAT rewrites it, which is a layer violation with consequences. A segment is addressed to a 16-bit port that is meaningful only to one host's kernel.
The practical form of this is the question that catches people in interviews and in incidents alike: when you send a packet to a host on the other side of the internet, what is in the destination MAC address field. Not the remote host, which has no presence on your segment. Your default gateway, which your host resolved by ARP, and which will discard that MAC address entirely and write its next hop's MAC address in its place. The destination IP survives the whole journey. The destination MAC lives one hop.
The vocabulary, since the words are used precisely in this course
A frame is a link-layer unit with a MAC header. A packet is a network-layer unit with an IP header. A segment is a TCP transport unit. A datagram is a UDP transport unit, and also the word for an IP packet when you want to stress that it is unacknowledged and may be reordered. A message is whatever the application defines.
These are not interchangeable, and the reason to keep them straight is that the unit determines the failure mode. A frame is lost by a congested switch port and nobody retransmits it at that layer, because Ethernet has no retransmission. A packet is lost by a router queue and nobody retransmits it at that layer either, because IP is best effort by design. A segment is lost and TCP retransmits it, because that is the entire job TCP exists to do. When someone says the network dropped a packet and you need to know whether the application noticed, the answer depends on which of those three units was actually lost and what was running above it.
One request, counted in bytes
It is worth doing the arithmetic once, because the numbers reappear in every later lesson. A client sends a 73-byte HTTP/1.1 GET /health request with two headers over an established, unencrypted connection on IPv4 Ethernet.
The application writes 73 bytes with send(). TCP prepends a 20-byte header, or 32 if timestamps are negotiated, which they are by default on Linux, giving 105 bytes. IP prepends 20 bytes, giving 125. Ethernet prepends 14 bytes, giving a 139-byte frame, and appends a 4-byte frame check sequence for 143. The NIC then adds 8 bytes of preamble and start-of-frame delimiter and the medium enforces a 12-byte interframe gap, so the request occupies 163 byte-times on the wire to deliver 73 bytes of payload.
That is 45 percent efficiency, and it is normal. Small messages are dominated by headers, which is the arithmetic behind every batching decision in distributed systems, behind Nagle's algorithm, and behind the fact that a service doing a million tiny RPCs per second can saturate a link while its application-visible throughput looks trivial. The same arithmetic run on a 1,460-byte payload gives 1,538 byte-times for 1,460 bytes, or 95 percent, which is why bulk transfer and request-response traffic have completely different capacity profiles on identical hardware.
A layer is a contract about two bytes of metadata: how long is my header, and what is the type of the thing after it. Everything that looks like a layering problem in production is one of those two answers being wrong. An MTU black hole is a length disagreement. A VLAN tag stripped by a NIC is a type field the capture never saw. A NAT that corrupts a checksum is a layer rewriting a field that another layer had already covered.
Where the model leaks, which is the interesting part
Clean layering is a design goal, not a property of deployed networks, and the leaks are worth naming now because later lessons are mostly about them.
TCP's checksum covers a pseudo-header containing the source and destination IP addresses, which belong to the layer below it. That deliberate violation exists so a segment delivered to the wrong host by a corrupted IP header is detected rather than accepted, and it is the reason NAT has to recompute transport checksums rather than merely rewriting addresses. Path MTU discovery requires the transport layer to receive and act on ICMP messages generated by routers several hops away about the network layer, so a firewall that drops ICMP breaks TCP in a way that looks like an application hang. HTTP/2 multiplexes streams over one TCP connection and then inherits TCP's single-sequence-number head-of-line blocking, which is a transport property the application layer cannot route around, and the reason QUIC moved streams below the loss-recovery boundary.
Each of those is a case where knowing the layer boundaries is not enough and you need to know what crosses them. That is the level this course works at.