Computer Networks
Here is everything you get: one wire between two machines, and the ability to hold your end at a high voltage or a low one. That is the whole vocabulary. Two levels on one piece of copper. Can you get a sentence across it, arriving whole, to the right machine, on the other side of the world?
Every step here is something you operate. You hold a wire high and low by hand to spell out a letter, and get it wrong. You push two clocks slowly out of step until the message garbles. You damage a message on purpose until the check that is supposed to catch it looks the other way, force two machines to talk over each other, then break a cable in a small network and watch the traffic find another way round. Each mechanism arrives as the fix for a failure you caused yourself.
The steps
One wire, two voltages
Two machines, one wire. Your end can be pushed to a high voltage or left sitting low. There is no third option, no letters, no numbers. High, low, and that is it. One wire with a machine holding each end has a name that will keep coming back: it is a link. Everything in Part 1 happens on one link.
What "voltage" actually means on a wire
Voltage is electrical push. A battery pushes; a wire connected to nothing does not. When a machine "holds the wire high" it is connecting that wire to a small pushing source, usually somewhere between 1 and 5 volts. When it holds the wire low it connects the wire to zero instead.
The far end has a tiny meter on it. All it can report is roughly how hard the wire is being pushed right now. That single number is the only thing that will ever cross between these two machines.
So you write down an agreement: high means 1, low means 0. That feels like enough. It is not, and the quickest way to see the hole in it is to try sending a single byte by hand.
What a byte is, and why eight
A bit is one of those two levels, written 0 or 1. Eight bits in a row is a byte. Eight switches, each with two settings, make 2 x 2 x 2 x 2 x 2 x 2 x 2 x 2 = 256 different patterns, which is enough for every letter, digit and punctuation mark in English with room to spare.
Eight is a choice, not a law. Early machines used 6, 7 and 9. Eight won, and now every piece of equipment on the planet counts in bytes.
A row of bits is also a number. How?
You already do this in ten. In 407, the 4 is worth four hundreds, the 0 is worth no tens and the 7 is worth seven ones, because each place to the left is worth ten times the one on its right. Bits work the same way with two instead of ten. Reading a byte from the right, the places are worth 1, 2, 4, 8, 16, 32, 64, 128.
So 00000101 has a 1 in the fours place and a 1 in the ones place, which is 4 + 1 = 5. And
01101001 is 64 + 32 + 8 + 1 = 105, the byte written 0x69 further down this page.
Going the other way, take the number and keep grabbing the largest place that fits: 200 is 128, leaving
72; then 64, leaving 8; then 8, leaving 0. So 200 is 11001000. That is the whole trick, and
Step 9 will need it.
The receiver below looks at the wire once per tick and writes down whatever it sees. Your job is to hold the line so that the byte it writes down is the byte you were asked to send. Crank the clock by hand first. Then let it run.
There is nothing about 3.3 volts that means "one". Both ends have to have agreed in advance: which level is which, which bit of the byte goes first, and hardest of all, when to look. Everything in this course is one of those agreements, written down once and then obeyed by every machine on Earth.
People keep saying "layer". A layer of what?
Getting a message across the world is too big a job to solve in one go, so it is cut into jobs that stack. The bottom job is only about voltages on one wire and nothing else. The job above it worries about where a message starts and stops, and simply assumes the bottom one is doing its part. Above that, one about who the message is for, and so on.
Each of those jobs is called a layer, and each one is allowed to be ignorant of everything above and below it. That is why a wire can work perfectly and still deliver nonsense: the bottom layer did its job exactly, and nothing above it had been agreed yet. This course climbs the stack one layer at a time, and each step is the next layer up.
Bytes keep being written like 0x69. What is that?
Writing out 01101001 every time is tiring, so bytes are usually written in
hexadecimal: counting 0 to 9 and then A to F, sixteen digits instead of ten. One hex digit covers
exactly four bits, so two digits describe one byte and nothing is left over. The 0x in
front is just a label saying "the next digits are hex".
To read 0x69, split the byte down the middle. The 6 is the left four bits,
0110, and the 9 is the right four, 1001. Put them together and you have the
byte: 01101001.
0x96 where
you sent 0x69. What went wrong?0x69
is 01101001 and 0x96 is 10010110, every bit inverted. Either the
receiver takes low as 1, or it is reading your bits in the opposite order. The physical layer worked
perfectly and delivered nonsense, which is the most useful thing to learn from this step: a working wire
is not a working link.Where does a bit end
Hand-cranking the clock made that easy, because you and the receiver ticked together. Real links do not have that. The sender has its own oscillator and the receiver has another one, and no two crystals in the world run at exactly the same rate.
What an oscillator is, and why every machine has one
An oscillator is the part that says "now" over and over at a steady rate. In almost every computer it is a sliver of quartz crystal that vibrates when electricity is applied, the same component that keeps a wristwatch honest. Each vibration is a tick, and everything the machine does is lined up with those ticks.
Quartz is steady but not identical from one sliver to the next. Two crystals cut to run at a million ticks a second will each be off by a little, in their own direction, and warming up moves them again. Nothing in this step is anyone's fault; it is what physical parts are like.
Suppose the receiver's clock is 1% slow. On the first bit that hardly matters, since it samples a fraction late and is still comfortably inside the bit. But the error does not reset. It adds up. Give the length of one bit on the wire a name: a bit-time. If the sender holds each bit for a millionth of a second, then one bit-time is a millionth of a second, and everything below is measured in those. Half a bit-time of accumulated error is all it takes to be sampling the wrong bit entirely.
Where the drift adds up, with real numbers
Call one bit-time one unit, and put numbers on it. A receiver that is 1% slow waits 1.01 units between looks, so it is 0.01 units late on the first bit, 0.02 on the second, 0.10 after ten. Nothing has gone wrong yet, because it is still looking somewhere inside the right bit.
After fifty bits it is half a bit-time late, which puts it exactly on the boundary. After a hundred it is a whole bit behind and reading its neighbour. A small steady error is harmless once and fatal when you add it to itself enough times.
Turn the drift knob and watch the sampling arrows slide off the bits underneath them.
You could send the clock down its own wire, and short links inside a computer often do. Over any distance it stops working: two wires do not carry signals at exactly the same speed, so the clock and the data arrive with a shifting offset, and you have doubled the cost of every cable. What long links do instead is put the clock inside the data signal, which is the next step.
Hiding the clock in the signal
The receiver's own clock cannot be trusted for long, but the incoming signal can be. Every time the voltage changes, the receiver learns exactly where it is in time. Edges are free information. The trouble is that plain bits give you no edges when the data has a long run of the same value.
What people mean by an "edge"
Draw the voltage on the wire as a line going left to right in time. While the level holds steady the line is flat. When the sender switches from low to high the line jumps straight up, and that vertical jump is an edge. Low to high is a rising edge, high to low a falling one.
An edge is useful because it happens at a moment, not over a stretch. A flat line tells you nothing about the time; an edge tells the receiver "the sender did something right now", and the receiver can set its own idea of now to match.
So stop letting the data decide. Split every bit-time in half and force a transition in the middle of it, with the direction of that transition carrying the value. The scheme has a name, Manchester encoding, and here it is in full:
I have never read code before. Do I have to?
No. Every code block in this course is a second telling of something the words beside it already said, kept because it is the exact recipe and hides nothing. If you skip all of them you will miss nothing you need later.
If you want to try: a line like function manchester(bits) means "here is a recipe called
manchester, and you hand it a list of bits". The line for (const b of bits) means "do the
following once for every bit in that list, calling it b". b === 1 means "if b is exactly 1" and one equals sign would mean "make it 1", so the language uses three to mean "is it".
out.push(0, 1) means "add 0 then 1 to the end of the answer list". Anything after
// is a note to human readers that the machine ignores. So the whole recipe is: for each bit,
add low-then-high for a 1 and high-then-low for a 0.
// one bit becomes two half-bits, so there is always an edge mid-bit
function manchester(bits) {
const out = [];
for (const b of bits) {
if (b === 1) out.push(0, 1); // 1 = low then high (rising edge)
else out.push(1, 0); // 0 = high then low (falling edge)
}
return out;
}
Now the receiver never counts far. It finds the mid-bit edge, reads its direction, and resets its own idea of "now" to that edge. Drift has nothing to accumulate over. Push the same drift knob as before and compare the two lines.
Decoding an encoded line by hand
Say the sender wants 1, 0, 0. It holds low then high for the first bit, high then low for the second, high then low for the third: low, high, high, low, high, low. Six half-bits on the wire for three bits of data.
The receiver does not count half-bits. It waits for the next edge, looks at which way it went, and writes 1 for upward and 0 for downward. Upward, downward, downward gives back 1, 0, 0. The edge in the middle of a bit is the data; any edge at the join between two bits is only there to get the wire back into position, and the receiver ignores it.
Two half-bits per bit means the wire has to switch twice as fast to carry the same data, so you get half the data rate out of the same hardware. Early Ethernet paid exactly that price at 10 Mbit/s. Ethernet is the set of agreements almost every wired network on Earth follows: what the voltages mean, how a message is wrapped, how machines take turns. It is not a company and it is not a cable, it is a rulebook, and most of the rest of this course is describing parts of it. Later, faster standards use cleverer codes, called 4B/5B, 8b/10b and 64b/66b, which guarantee an edge often enough for the same trick to work while giving up only 20%, 20% and 3% of the wire instead of half. Same idea, better arithmetic.
What"10 Mbit/s" is counting
Mbit/s means millions of bits per second. A link at 10 Mbit/s puts ten million bits on the wire each second, so one bit-time lasts a ten-millionth of a second. Gbit/s is a thousand times more than that again.
Watch the small b. Bits are written with a small b and bytes with a capital B, so 10 Mbit/s carries a little over one megabyte each second once the framing has taken its share.
What those code names mean, if you are curious
4B/5B takes every 4 bits of your data and sends a 5-bit pattern instead, chosen from a table where no pattern has an awkwardly long run of identical bits. Five bits carrying four costs you 20% of the wire, which beats the 50% Manchester charges. 8b/10b and 64b/66b are the same bargain at bigger sizes, and 64b/66b is why a 10 Gbit/s link actually clocks its wire at 10.3.
You will see 4B/5B called a 25% overhead elsewhere. Same fact, counted from the other end: one extra bit added to every four is a quarter more, and one wasted bit in every five sent is a fifth of the wire. Nothing disagrees, the two numbers just divide by different things. And nothing later in this course depends on any of it. It is here because "half the wire" is a steep price and it is worth knowing that engineers stopped paying it.
Where a message starts and stops
Bits now arrive reliably, one after another, forever. That is still not a message. A receiver holding a stream of bytes has no way to know which of them belong together, where one message ends and the next begins.
Frame, payload, header: what the words mean
A frame is one message as the link carries it: a bundle of bytes with a definite start and a definite end. The part you actually wanted to send is the payload. Everything the frame wraps around it, to say where it starts, who it is for, or whether it survived, is overhead, and the overhead written at the front is the header.
Think of a letter. The words are the payload, the envelope and the address are the overhead, and neither one is any use without the other.
Try it. Below is a stream that arrived on the wire, correct in every bit. Cut it into the messages that were sent.
~ into the payload and watch a message split itself in half.Why typing a tilde is what breaks it
Text is stored as numbers. A table called ASCII fixes which number means which character: capital A
is 65, a space is 32, and the tilde ~ is 126, which written in hex is 7E.
That is the same 7E the framer picked as its flag.
So the tilde is not a special character to the wire. It is an ordinary byte that happens to carry the one value the two ends promised would never appear in the middle of a frame.
The moment you reserve a byte to mean "frame boundary", that byte can no longer be data, and of course your data will contain it eventually. The fix is an escape byte: replace the flag inside the payload with a two-byte sequence the receiver knows to undo. And since the escape byte is now special too, it has to escape itself. You have met this before without a computer: if a form says to separate your hobbies with commas, and one of your hobbies is "reading, mostly", the comma inside it breaks the list and the form has to offer you some way of saying "this comma is part of the words, not a separator". Programmers hit the same wall constantly, and put a backslash in front of a quotation mark inside a piece of text to mean "this quote is data, do not end the text here". Same problem, same fix everywhere. Replacing an awkward byte with a two-byte escape has a name of its own, byte stuffing, because the frame gets stuffed a little fatter on the way out. That is the button in the lab.
What is a protocol, exactly?
A protocol is an agreement written down in enough detail that two machines built by strangers,
in different countries, years apart, can follow it and work together first time. Nothing more mysterious
than that. 7E means the edge of a frame; 7D means the next byte has been
altered; the first six bytes are the address. Write those rules down, get everyone to obey them, and you
have a protocol.
Every agreement in this course is one: the level meaning of high and low in Step 1, Manchester encoding in Step 3, the framing here, the backoff rule in Step 7. The word is worth having because the alternative phrase,"the thing both ends promised to do", gets tiring, and because a protocol is a document you can go and read. Ethernet, IP, DNS and BGP are all just documents that enough people agreed to obey.
Is there a way to avoid escaping altogether?
Yes, and plenty of protocols use it. Instead of marking the end, write the length at the front: "the next 240 bytes are one frame". Now no byte value is reserved, so nothing has to be escaped and the frame never swells on the wire. Ethernet works this way.
The cost is that a length is a promise the receiver cannot check as it goes. Lose or corrupt those first bytes and it will cut the stream in the wrong place and keep cutting wrongly, whereas a flag byte lets a lost receiver find the next boundary by waiting for one to go past. Neither choice is free, and nothing later here depends on which one you prefer.
7E as the flag and 7D as the
escape byte. What must it do when the payload contains a real 7D?7D, drop it and un-mangle the next byte". A real 7D in the data
triggers that rule and eats the innocent byte that follows. So the sender sends 7D 5D for a
data 7D and 7D 5E for a data 7E. The second byte is altered on
purpose, by flipping one fixed bit, which is what turns 7E into 5E and
7D into 5D. If it went out unchanged, the frame would still contain a bare
7E and a receiver that had lost its place would still be fooled by it. Flipping the same bit
back at the other end undoes it exactly. Payload of pure 7E
bytes therefore doubles in size on the wire, a worst case real protocols accept, because the
alternative is a protocol that mysteriously corrupts some files and not others.A bit flips
Wires run past motors, fluorescent lights and other wires. A voltage that left as a clean high can arrive close enough to the threshold that the receiver reads it as a low. There is no way to prevent this, only to notice it.
What the "threshold" is
The receiver does not measure the voltage precisely. It has one dividing line, the threshold, set somewhere in the middle of the range: above it counts as high, below it counts as low. That is what turns a messy analogue push into a clean 0 or 1.
Being that decisive is a strength most of the time. A signal that arrives a bit weak or a bit noisy still lands on the correct side of the line and is repaired for free. It is only when the noise is big enough to carry the level across the line that the receiver reads the opposite bit, with complete confidence.
The cheapest way to notice costs one bit. Count the 1s in the frame and add a parity bit that makes the total even. The receiver counts again: odd total means something changed on the way. One extra bit, and corruption stops being silent.
One parity bit, worked through
Take the byte 01101001. Count the 1s: there are four, which is already even, so the
parity bit sent alongside it is 0 and the total stays even. Now take 01101011, which has
five 1s. The parity bit is 1, bringing the count of 1s across the whole nine bits to six.
The receiver does not need to know which byte you meant. It counts the 1s in everything that arrived, parity bit included, and expects an even answer. One flip anywhere in those nine bits makes the answer odd, and it is spotted.
Before you trust it, break it. Click the bits yourself and find a corruption the parity bit does not notice.
Parity tells you a frame is broken; it cannot tell you which bit broke, so it cannot repair anything. That leaves two ways to survive: send enough extra bits to correct the error where it lands (used by disks, memory and deep-space links, where asking again is impossible or slow), or throw the frame away and ask for it again. Networks mostly do the second, which is why Step 14 hands you over to a whole course about asking again.
How a check can repair a bit instead of just noticing
Send several parity bits instead of one, each counting a different overlapping group of the data bits. A single flip then fails some of the checks and passes others, and the pattern of which ones failed points at exactly one bit. Flip that bit back and the frame is repaired without anyone asking for it again. Richard Hamming worked this out in 1950 and the memory in a server still uses it.
You pay in extra bits, and the arithmetic only pins down a small number of errors. Nothing later in this course needs it, so skip it happily; it is here because "notice" and "fix" feel like the same job until you see the price tag on each.
Catching much more, cheaply
Parity fails because it throws the whole frame into a single yes-or-no answer, and every bit affects that answer the same way. What you want is a check where each bit's contribution depends on where it sits, so that two flips almost never cancel.
A CRC gets there with long division. The letters stand for cyclic redundancy check: redundancy because it sends a few extra bits that carry no message of their own, check because their whole job is to be compared at the other end, and cyclic for the shape of the arithmetic underneath. Treat the frame as one enormous binary number, the way the place-value note in Step 1 turns a row of bits into a number, divide it by a fixed number everyone has agreed on, and send the remainder. The receiver divides the whole thing, frame and remainder together, and expects to come out even. It is a few lines of code and a handful of shifts per byte:
Remainder, and the trick of making it come out even
Divide 47 by 10 and you get 4 with 3 left over. That 3 is the remainder. The useful part is that the remainder depends on the whole of 47: change any digit and it changes too.
Now subtract the remainder before you send: 47 becomes 44, which divides by 10 exactly. The receiver does not need to know what you started with. It divides what arrived, and a leftover of anything other than zero means the number it received is not the number you sent. A CRC is that idea with a much larger divisor and the arithmetic done in bits.
That code is nothing but symbols. What do they mean?
Four symbols do all the work, and each is a single instruction the chip already knows.
crc << 1 means slide every bit one place to the left, so 00000110 becomes
00001100, and whatever falls off the left-hand end is gone. crc & 0x80 asks
a yes-or-no question: 0x80 is the byte 10000000, and & keeps
only the bits that are 1 in both, so the answer is non-zero exactly when the top bit of
crc is a 1, which is the bit that is about to fall off.
^ is exclusive-or, the subject of the note below: it compares two bytes bit by bit,
giving 1 where they differ and 0 where they agree, which in this arithmetic is what subtraction becomes.
And a ? b : c means "if a, then b, otherwise c". So the whole line reads: if the bit about
to fall off is a 1, shift left and then XOR in 0x07, and if it is a 0, just shift left. That
is one step of long division, and the loop does it eight times per byte.
uint8_t crc8(const uint8_t *data, int len) {
uint8_t crc = 0;
for (int i = 0; i < len; i++) {
crc ^= data[i];
for (int b = 0; b < 8; b++)
crc = (crc & 0x80) ? (crc << 1) ^ 0x07 : (crc << 1);
}
return crc; /* send this alongside the frame */
}
That code has no division sign in it
Because CRC arithmetic is not quite school arithmetic. It works on bits with no carrying between columns, so subtraction becomes XOR: 1 against 1 gives 0, 1 against 0 gives 1. Long division still works, and each step is a shift and an XOR, which is why the loop above holds the whole algorithm and why a chip can do it at wire speed with a few dozen gates.
Dropping the carries is also what makes the guarantees in the next callout provable. You can skip all of this and still use a CRC correctly; a table of tested divisors is what engineers actually reach for.
Below, both checks run on the same frame. Find a corruption that parity misses and the CRC catches, then find one that beats them both.
A well-chosen n-bit CRC catches every single-bit error, every double-bit error in frames of practical size, every error that flips an odd number of bits, and every burst of corruption shorter than n bits, which matters because real noise comes in bursts. Beyond that it catches all but roughly one in 2n of everything else. Ethernet, Wi-Fi, USB, disk sectors and zip files all carry one, and they all carry it for the same reason: the guarantee is specific enough to design around.
What "one in 2 to the power n" comes to
2n means 2 multiplied by itself n times, and it grows startlingly fast: 28 is 256, 216 is 65,536, 232 is about 4.3 billion. Each extra bit in the check doubles the number of possible remainders and a corruption slips through only when it happens to land on the one remainder that was already there.
So a 32-bit CRC lets through roughly one bad frame in four billion. That is small, but a gigabit link can carry millions of frames a second, so "never" is still the wrong word for it.
Names on the link, and a switch that learns
Several machines on one wire means every frame reaches everybody, so each frame has to say who it is for. Every socket a network cable plugs into, and the card behind it, is called a network interface, and each one carries a permanent 48-bit number burned in at the factory: its MAC address, short for media access control, the part of the rules that decides who gets to use the shared wire. Every frame starts with the destination's number and then the sender's own.
Why 48 bits, and what one looks like
48 bits is six bytes, usually written as six pairs of hex digits: 3c:5a:b4:01:9f:22.
Six bytes hold about 281 trillion different numbers, which is deliberately far more than there will
ever be network cards, because every one has to be different from every other one made anywhere.
Nobody coordinates that by hand. The first three bytes are bought by the manufacturer, and the manufacturer picks the last three, so two factories can never collide.
That works, but it wastes the wire: every machine receives every frame and throws away the ones addressed elsewhere. Put a box in the middle instead, with one wire to each machine, and it can send each frame down only the port where its destination lives. The catch is that nobody tells the box who is on which port.
What a port is here
A port is one of the sockets on the front of the box, with its own short wire going off to one machine. A switch with eight sockets has ports 1 to 8, and each is a separate, private link.
That is what lets the box be selective. A frame arrives on one port, and the box decides which other port or ports to copy it out of. The word gets reused later for something quite different in software, so keep this meaning tied to the socket you can touch.
So it learns, from a single observation: a frame arriving on port 3 proves its sender is on port 3. Watch the table fill.
What happens when the wires between switches form a loop
Flooding assumes there is exactly one path between any two ports. Plug two switches together with two cables and a flooded frame goes round the loop, gets flooded again, and again, at wire speed, until the network is carrying nothing else. It is one of the few faults that can take a whole building down in seconds.
The cure is a protocol the switches run among themselves to agree which links to shut off, leaving a loop-free shape while keeping the spare cable ready. Nothing later in this course needs it, and routers in Step 10 avoid the problem in a different way.
Addresses with structure
MAC addresses have one fatal property: they carry no information about where the machine is. They are assigned in the factory, so a table that maps them to locations has to list every machine individually. That is fine for the twenty machines on one link and hopeless for the billions on the planet.
What an IP address is, next to a MAC address
An IP address is 32 bits, written as four numbers from 0 to 255 with dots between them, like
10.0.4.9. Each of those four numbers is one byte of the address, and people call them
octets. Unlike a MAC address it is not burned into the hardware: it is handed out by whoever runs
the network the machine is plugged into, and it changes when the machine moves.
That is the whole point of having both. A MAC address says which card this is. An IP address says where in the world it currently sits.
The fix is to give addresses a shape. An IP address splits into a
network part and a host part, and the split point is written after a slash:
10.0.4.9/24 means "the first 24 bits name the network, the last 8 name a machine inside it".
Now one table entry can cover thousands of machines, because they share a prefix.
Show me the /24 as actual bits
Write 10.0.4.9 one byte at a time:
00001010 00000000 00000100 00001001. That is 32 bits. A /24 draws the line after 24 of
them, which lands exactly at the end of the third byte, so the network part is
00001010 00000000 00000100 and the host part is the last 00001001.
Every machine on that link has an address starting with those same 24 bits, so one line in a table that says "anything beginning 10.0.4 goes this way" covers all of them at once. The slash number is just "how many bits from the left do we all have in common".
Those 32 bits are worth being able to produce yourself rather than taking on trust, because everything in this step is written in them. One octet at a time, that is the place-value trick from Step 1: eight places worth 128, 64, 32, 16, 8, 4, 2 and 1, and a number is whichever of them add up to it.
200
into the box and press Show me to watch the squares set themselves, with the working written out
underneath.10.0.4.9 in turn, 10 then 0 then 4 then 9, and you have
built its 32 bits by hand, which is exactly what the next lab shades for you. The two challenge buttons
are worth doing the slow way, largest place first, before you look at the working.All of that gives a machine the one question it actually needs to answer before sending anything: is the destination on my own link, or do I have to hand it to a router? Drag the split and watch the answer change.
What is a router, and how can a frame and a message have different addresses?
A router is a machine with a leg in more than one network: two or more sockets, each on a different link, and a job of passing traffic between them. Step 10 is entirely about how it decides. For now it is the machine on your own link whose job is everywhere else.
That is why there are two addresses in flight at once. The thing you are actually sending, the one with the far-away address on it, is called a packet, and it travels the whole way. Each link it crosses, it rides inside a fresh frame addressed only to the next machine on that link. So the frame your machine puts on the wire is addressed to your router's MAC address, while the packet inside it still says the address on the other side of the world. The router opens the frame, throws it away, and builds a new one for the next hop.
def same_network(a, b, prefix_len):
mask = (0xFFFFFFFF << (32 - prefix_len)) & 0xFFFFFFFF
return (a & mask) == (b & mask)
Reading those two lines
0xFFFFFFFF is 32 bits all set to 1, written in the hex from Step 1: each F is four 1s and
there are eight of them. The << slides those bits left, throwing away whatever falls
off the left end and feeding 0s in at the right. Sliding a /24 mask means sliding by 32 - 24 = 8, so the
eight rightmost bits become 0 and the mask is twenty-four 1s followed by eight 0s, which is the third row
in the lab above.
The & keeps a bit only where both sides have a 1, so a & mask blanks
out every position the mask has a 0 in, leaving only the network part. Doing that to both addresses and
asking whether the results are identical is the whole test. It is two machine instructions, which is why
a router can afford it on every packet that arrives.
How many machines fit in a /24, or a /22
Count the bits the prefix leaves over. A /24 leaves 8 host bits, and 8 bits make 28 = 256 patterns, so a /24 covers 256 addresses. A /22 leaves 10, and 210 = 1024. Every bit you take off the prefix doubles the size of the network.
Two of those addresses are always spoken for: the all-zeros one names the network itself, and the all-ones one means "everybody here", which is called a broadcast address, the same idea as the flooding a switch does in Step 8 but asked for on purpose. So a /24 holds 254 usable machines rather than 256.
10.1.4.9/22 and 10.1.7.200/22 on the
same network?00000100, and 7 is 4 + 2 + 1,
giving 00000111. A /22 boundary cuts two bits into the third octet, so only the bold
bits are host bits and everything above them matches. The trap here is thinking in dots. The boundary
does not care about them, and a /22 network holds 1024 addresses spanning four whole "third octets".
Reading prefixes as bits rather than as dotted numbers is most of what makes subnetting, the
business of cutting one network into smaller ones, stop being confusing.Carrying a packet hop by hop
Step 9 ended by handing a packet to a router. Here is everything a router does with it. When a packet arrives whose destination is not on any of its own links, it does one small thing: look up the destination's network in a table, and hand the packet to the neighbour listed there. Then forget about it.
Packet or frame? And what is in the header?
A frame is what one link carries between two machines that share a wire. A packet is what travels the whole way, from the first machine to the last, riding inside a fresh frame on each link it crosses. The router in this step unwraps a frame, looks at the packet inside, and wraps it in a new frame for the next wire.
The packet's own header is a short block of fields at the front, carrying the source and destination IP addresses, how long the packet is, and the hop limit. Those fields belong to the packet, so they survive every hop; the frame around them is thrown away and rebuilt each time.
No router knows the whole path. Each one only knows the next step, which is why the packet's header carries a hop limit: a small number, set by the sender, that every router it passes through knocks down by one before sending it on. When it reaches zero the next router throws the packet away. A packet going round in circles because two tables disagree has to die of something.
The quiz mentions a "default route". What is that?
A table cannot list every network on the internet, and most machines do not want to. So a table can hold one catch-all entry:"anything I do not recognise, hand to this neighbour". That is the default route, and it is what makes a home router's table three lines long instead of a million.
It works because the catch-all points at somebody better informed, whose own table is bigger and whose own default route points further up again. Only the routers in the middle of the internet have no default to fall back on, which is why the question of what happens without one matters at all.
You are the forwarding decision now. Read each router's table and choose the next hop. Choose badly on purpose at least once.
How traceroute turns dying packets into a map
Send a packet with the hop limit set to 1. The first router knocks it down to 0, drops it, and posts an error back, and that error carries the router's own address. You have just learned hop one. Send the next with a limit of 2 and the second router reports itself. Keep going and the whole path names itself, one dying packet at a time.
It reads the network by breaking things on purpose, which is why the list sometimes has gaps: a router configured to stay quiet sends no error, and traceroute prints a row of asterisks for it. Nothing later depends on this.
How routers learn the map
Someone has to fill those tables in, and it cannot be a person: links fail at three in the morning and traffic has to find another way within seconds. So the routers work it out themselves, from one rule that is short enough to fit in a sentence.
Every router tells its neighbours how far it is from every destination it knows. Every router listens, adds one for the hop to that neighbour, and keeps the shortest answer it heard along with who said it. That is all. Repeat until nothing changes.
What "cost" and "how far" are measuring
Not distance in metres. In the simplest version, cost is a count of links: a network on my own wire is cost 0, one my neighbour can reach is cost 1, and so on. Adding one for a hop is all the arithmetic there is.
Real networks let an operator set the cost of each link by hand, so a slow backup line can be given a cost of 10 and a fast one a cost of 1. The rule does not change, it just adds the link's cost instead of always adding one, and traffic drifts onto whatever the operator called cheap.
for dest in all_destinations:
best, via = INFINITY, None
for n in neighbours:
cost = 1 + n.advertised[dest] # one hop to n, then n's own distance
if cost < best:
best, via = cost, n
table[dest] = (best, via)
Walk the rule with three routers
A, B and C sit in a line, and network N hangs off C. C knows N at cost 0 and says so. B hears "N, cost 0" from C, adds one, and writes down "N, cost 1, via C". A hears nothing useful yet, because B has not spoken since it learned anything.
Next round B advertises "N, cost 1". A adds one and writes "N, cost 2, via B". Round three changes nothing anywhere, so the tables have settled and every router knows which single neighbour to hand an N-bound packet to. No router ever learned the shape of the network, only its own next step.
Below is a network of five routers. Let their tables settle, send a probe to see the path they agreed on, then cut a link on that path and watch what happens next.
When a destination disappears, the routers do not conclude "gone". They conclude "further away than I thought", one hop at a time, because each is hearing its own stale route reflected back by a neighbour. Left alone they would count upward forever, so the rule picks a number, 16, and declares it to mean unreachable, purely so the counting stops. The real fix is the one in the lab: send the path along with the distance, so a router can see its own name in a route and refuse it. That is what BGP, the agreement holding the real internet together, does between networks.
Is there a cheaper fix than sending the whole path?
There is a well-known partial one. Never tell a neighbour about a route that runs through that same neighbour, since it already knows about that route and can only be confused by hearing it back. That kills the version of the loop where exactly two routers quote each other, which is the one the lab shows.
It does not kill the version with three. A can hear it from B, B from C and C from A, and none of them is telling the route straight back to the router it came from, so the ratchet still turns, just around a bigger circle. That is why the real protocols ended up sending the whole path. Nothing later here depends on this.
What BGP is, and why it gets named so often
The internet is not one network but tens of thousands of separately owned ones, and BGP is the protocol they use to tell each other which blocks of addresses they can reach. Each announcement carries the list of networks it passed through, which is the path-advertising fix from the lab, so a network can refuse a route that comes back through itself.
Because the announcements are believed, a network that announces someone else's addresses by mistake can pull the world's traffic towards itself for an hour, and this has happened more than once. Skip this note without worry; nothing later needs it.
From a name to an address
Routing works on addresses, and nobody wants to remember addresses. Worse, addresses change: a service moves to another machine and every reference to it has to move too. So there is a layer of indirection, meaning names, and a system for turning a name into an address at the moment you need it.
"A layer of indirection" sounds like jargon
It means putting a stand-in where the real thing used to be, so the real thing can change without anybody having to be told. Your friend's phone number lives once in your contacts, and everything else refers to the name. When the number changes you fix it in one place. This is a different sense of "layer" from the stack of jobs in Step 1 and the two are not related; here it just means one thing standing in front of another.
Names on the internet do the same job for machines. Whoever runs a service can move it to a new machine with a new address and change one answer, and every reference in the world follows without anyone editing anything.
That system is the Domain Name System, DNS, and it is the one piece of networking
jargon you will meet in ordinary life. One central list of every name on the internet would be a single point
of failure and a single bottleneck, so the names are split into a hierarchy and read right to left. A
domain is a name like example.com and a zone is the slice of names below it that
one owner is the authority for. www.example.com asks: who knows about com, then who
knows about example.com, then what is www inside it. Three questions, three round
trips, each to a machine that only has to know the next step down.
What one "round trip" costs
A round trip is one question sent out and one answer coming back. What it costs is time, and the time is set by distance and by how many routers the packet crosses: about 10 thousandths of a second across a city, 150 or more between continents. Light in glass is quick but it is not instant.
So "three round trips" is not three packets' worth of data, it is three waits stacked one after another, each one unable to start until the last has finished.
Walk one yourself, and watch what the second lookup costs.
example.com owns that zone and is the sole authority on what is inside it.com and example.com are cached while the last question is new.
Age the cache past its lifetime and the cost comes back.What a cache is, and what its "lifetime" does
A cache is a small store of answers you already went to the trouble of getting, kept nearby in case the same question comes up again. Your machine keeps one for name lookups, and so does the resolver it asks, so a popular name is often answered from a few streets away rather than from the far side of the world.
Every answer arrives stamped with a lifetime, chosen by whoever owns the name: keep this for 300 seconds, or for a day. While it lasts, the answer is reused; after that it is thrown away and asked again. A short lifetime lets an owner move a service quickly, and a long one saves everybody work.
A lookup moves almost no data, a question and an answer, a few hundred bytes. What it costs is waiting, three times, before your machine has even started the connection it wanted. That is why every layer caches the result, why the lifetime attached to each answer is a real engineering decision (short means fast failover, long means fewer lookups), and why an outage at a big name provider takes down services whose own machines are running perfectly.
shop.example.com takes three round
trips. The second takes none. Then mail.example.com takes one. What explains the pattern?com", "ask
that one about example.com", and finally "shop.example.com is at this
address". A new hostname in a domain you have already visited reuses the first two and pays only for the
third. That is the hierarchy earning its keep: the expensive, shared parts of the answer are the parts
most likely to be reused.What the network never promised
You can now get a packet from one machine to another across several networks. It is worth being exact about what that gives you, because it is much less than it feels like.
Each packet is forwarded on its own. Two packets sent a microsecond apart can take different routes, meet different queues and arrive in the wrong order. One can be quietly dropped because a router's queue was full, or arrive twice because something retried. The network promises to try. Nothing else.
What a queue inside a router is, and why it fills
A router can only push one packet at a time down a given wire, and packets arrive whenever they arrive. So each outgoing port has a queue: a short line of packets waiting their turn, held in the router's memory. Traffic that comes in a burst is smoothed out by the waiting.
The memory is finite. When packets keep arriving for a port faster than the wire can drain them, the queue fills, and the router's only remaining option is to throw a packet away. Nothing is broken when that happens; it is what a full queue means. It is where most lost packets on the internet die.
How long is a microsecond?
A millisecond is a thousandth of a second, and a microsecond is a thousandth of that: a millionth of a second. A blink takes about 300,000 of them.
It matters here because it is the scale computers work at. Sending two packets a microsecond apart is almost the same instant to us, and yet on the way across the world they can end up on different routes and behind different queues, and arrive in whatever order those choices produce.
Send a sentence in ten packets across a link you control and read what comes out.
Numbering fixed the order but not the loss. Why?
Because a number on each packet only tells the receiver what it is holding and what it is missing. Packets 1, 2, 4 arriving is now readable as"3 has not turned up", which is much better than a scrambled sentence, and it is still not the sentence.
The missing bytes exist in exactly one place: the sender's memory. Nothing the receiver can do alone will produce them, which is why this step ends with a receiver that knows precisely what is wrong and cannot fix it. Step 14 adds the one thing that closes the gap.
What is still missing
Look at what one voltage on one wire has turned into. An agreement about levels, a clock recovered from the signal itself, frames with edges, a check that catches corruption, a way to share the wire, addresses with a shape that lets one table entry cover a million machines, tables the routers build by gossiping, and names on top of all of it.
And a message still does not reliably arrive. Everything so far moves packets; nothing so far notices that one is missing. That last gap is the one below, and closing it is not the network's job. It is the job of the two machines at the ends.
Why the ends, and not the network?
Only the two ends can tell whether the whole message arrived, because only they know what the whole message was. A router in the middle sees one packet, forwards it, and forgets it; it has no idea which conversation the packet belongs to or how many more are coming.
There is a second reason, and it is the one the designers argued about. Every guarantee built into the middle has to be paid for by everybody, including the traffic that did not want it. A video call would rather lose a packet than wait for it. So the middle stays simple and each pair of ends buys only the promises it needs.
What each of the four buttons actually does
Number the packets puts a sequence number on each one, so the receiver can tell a duplicate from new data and a gap from the end of the message. Drop duplicates throws away a packet whose number has already been dealt with. Hold out-of-order packets keeps an early arrival to one side instead of handing it over, until the gap in front of it has been filled. Resend what is missing sends a packet again when it has not turned up.
Each one fixes a different failure from Step 13, which is why leaving any of them off leaves something broken. And notice what the fourth one quietly assumes: the sender only knows what to resend because the receiver told it what arrived. That reporting back is not a button here, because it is the whole subject of the next course.
Where to go next
- Reliable Data Transfer. Acknowledgements, timeouts, sliding windows and congestion control, ending with a file transferred perfectly across a link you are actively sabotaging. It starts exactly where this lab stops.
- Build a Microprocessor. If you have not, go and see what is at the other end of the wire: the gates and registers that produce those voltages in the first place.
- Distributed Consistency. Once messages can be lost and delayed, two machines can hold different opinions about what happened. That turns out to be much harder than moving the bytes was.
Read an eye diagram and find a bad link
The first three steps used perfect square waves. A real cable rounds every edge and weakens the signal. A connector with the wrong impedance also reflects part of the wave back toward the sender. At a low bit rate the receiver may still separate high from low. Raise the rate, lengthen the cable, or add a bad termination and the safe sampling region shrinks.
An eye diagram overlays many bit periods. The open space in the middle shows where a receiver can sample without confusing one level for the other. Vertical opening is noise margin; horizontal opening is timing margin. Engineers do not diagnose this by staring at one attractive waveform. They transmit known patterns, measure the eye at the receiver, and compare it with the link specification.
For the physics behind channel response, continue to Filters and The Frequency Domain.
What this model leaves out
The lab compresses frequency-dependent loss, crosstalk, jitter and receiver behaviour into two margins. Use it to form a hypothesis, then use the electrical standard and measured eye mask for the actual interface.
Keep a switched network from looping
Modern Ethernet links between a host and a switch are normally full duplex: each side can transmit at the same time, so the old shared-wire collision procedure is not running there. Switches still flood broadcasts and frames whose destination they have not learned. Two redundant links can therefore make the same frame circle forever, multiplying copies until the LAN is unusable.
A spanning-tree protocol keeps the physical backup links but blocks enough forwarding ports to leave one loop-free tree. If an active link fails, the switches can recalculate and open a backup. A VLAN adds a logical boundary: ports in different VLANs do not share one broadcast domain, even when they use the same switches.
What changes during reconvergence?
Frames may pause or take a different path while switches agree on a new tree. Measure convergence time and verify that the intended VLAN still has a valid path after each planned link failure.
Find a neighbour and configure an address
An IP address tells a host which network a destination belongs to, but an Ethernet interface still needs a link-layer address for the next frame. For IPv4, ARP asks, “Who has this IPv4 address?” For IPv6, Neighbor Discovery uses ICMPv6 messages to find link-layer addresses, routers and reachable neighbours. If the final destination is off-link, the frame is addressed to a router, not directly to the distant server.
Configuration is another protocol problem. DHCP can supply addresses and other settings. IPv6 can also use router advertisements and SLAAC to form an address, followed by Duplicate Address Detection. NAT at many IPv4 edges rewrites addresses and ports because public IPv4 space is scarce. NAT is not the same thing as a firewall, and IPv6 does not require NAT for ordinary end-to-end addressing.
Protocol details: IPv6 Neighbor Discovery, stateless address autoconfiguration, and the IPv6 specification.
Why neighbour caches expire
Interfaces move, restart and change addresses. A cached mapping is evidence from an earlier time, so hosts refresh or probe it instead of treating it as permanent truth.
Route by topology, then by policy
Step 11 used distance-vector gossip. Large networks also use link-state routing: routers advertise their local links, build a common topology database and run a shortest-path calculation such as Dijkstra's algorithm. OSPF is one example inside an organisation. Sequence numbers, areas and careful flooding keep the database manageable and reject stale advertisements.
The Internet between organisations is not one shortest-path contest. BGP announces reachable address prefixes plus path information, and each network applies policy. A customer route may be preferred over a shorter provider route because cost, contracts and security matter. This is why “the Internet chooses the shortest route” is a useful beginner model but an incorrect final model.
Primary specifications: OSPFv2 and BGP-4. The Graph Algorithms course derives the shortest-path machinery.
How to test a routing change safely
Replay the candidate configuration against recorded routes, check reachability and policy invariants, deploy to a limited set of routers, and keep a rollback. A syntactically valid route can still leak traffic to the wrong neighbour.
Share a bottleneck without collapse
A receiver can say how much data it has room for. That is flow control. It does not say how much the routers between the endpoints can handle. Congestion control learns the path's available capacity from acknowledgements, delay and loss, then adjusts how much may be in flight.
If every sender keeps increasing after queues fill, delay grows, packets are discarded and retransmissions add still more load. A simple additive-increase, multiplicative-decrease model probes upward and backs off sharply on congestion. Production algorithms are more sophisticated, but the engineering questions remain: useful throughput, queueing delay, loss, stability and fairness across competing flows.
Continue to Reliable Data Transfer for acknowledgements, timers, sliding windows and congestion control as one complete transport design.
Why a full queue is not free storage
A queue moves waiting time into the network. Large buffers can hide short bursts, but persistent queues add latency to every packet and still overflow. Record a latency distribution as well as average throughput.
Protect and move a modern connection
Reliability is not authenticity. TLS 1.3 establishes keys, authenticates the server certificate and protects records from unnoticed modification. The application must still verify the intended hostname and trust chain. Encryption does not prove that a server is correct, safe, or authorised to receive every piece of data.
HTTP can run over TCP plus TLS. QUIC instead integrates a TLS 1.3 handshake with a transport carried in UDP. It supports independent streams, so loss in one stream need not stop delivery in the others, and connection IDs can let a connection survive a network-address change. Zero-round-trip data can reduce delay on a resumed connection, but replay risk means it is unsuitable for some actions.
Primary specifications: TLS 1.3, QUIC, and TLS in QUIC.
What zero-RTT changes
A resumed client can send selected data before the new handshake finishes. An attacker may replay that early data, so applications should restrict it to operations that remain safe when repeated.
Share a channel you cannot hear all at once
A radio cannot reliably detect a collision while it is transmitting its own much stronger signal. Wi-Fi therefore listens before transmitting, waits a random backoff and expects an acknowledgement. This is collision avoidance, not collision detection. Interference, distance, obstacles and competing transmitters change which modulation and coding rate is dependable.
Two stations may each hear the access point but not hear each other. They are hidden terminals, so both can decide the channel is idle and transmit together. RTS/CTS can reserve airtime first and reduce that failure, at the cost of extra control frames. It helps in some workloads; it is not a free speed button.
Why the fastest rate is not always fastest
A denser modulation carries more bits per symbol but needs a cleaner signal. Repeated failures and retransmissions can make a lower, more error-tolerant rate deliver more useful data.
Prove where a packet stopped
“The network is down” can describe a loose cable, a missing neighbour entry, a wrong route, DNS failure, a blocked transport port, an invalid certificate or an application that never answered. Good troubleshooting narrows the fault one boundary at a time. Start with the smallest failing path, make a prediction, collect one relevant measurement and update the prediction.
Packet captures show what crossed one observation point, not what happened everywhere. A missing response could mean the request never arrived, the response took another path, or the capture filter was wrong. In 2026, tools can summarise captures and suggest likely causes. Treat those suggestions as hypotheses: retain the raw timestamps, packets, configuration and commands that let another engineer check the claim.
Continue the network path
- Reliable Data Transfer builds a transport that survives loss.
- Distributed Consistency studies what delayed and missing messages do to shared state.
- Performance Engineering turns latency, throughput and queueing into repeatable experiments.
- Fault Tolerance connects timeouts, retries and dependency failures to user-facing reliability.
What to save from an investigation
Keep clocks and time zones, interface and route state, commands with their output, capture locations, filters, configuration versions and the exact verification after the fix. Remove secrets before sharing the record.