Understanding Network Masks and Prefixes
Most of this post was meant to be a single section in another post I wrote about IPv6, but then it got out of hand and became too long and disconnected from the main topic, so I'm giving it its own space here.
The objective of this post is to go through the basics of how network masks work, in as simple as possible terms. Expect technical inaccuracies for the sake of simplicity. I'll illustrate with examples using IPv4 simply because it is shorter and easier to visualise, but it works the same way for IPv6, just longer, with a different notation, and it's referred to as "prefix" instead.
The basics
First, it's important to understand that an IPv4 or IPv6 address is a representation meant for us hairless apes. What the computer sees and cares about is a long chain of zeroes and ones - 32 bits for IPv4 and 128 bits for IPv6.
To a computer, an IPv4 address like 192.168.0.1 becomes:
Decimal: 192 168 0 1
Binary: 11000000 10101000 00000000 00000001
This 32-bit (or 128-bit for IPv6) binary address is divided in two sides*. The left side determines to what network that address belongs, while the right side determines the individual address of the computer inside that network. The sizes of each side can vary - having more bits on the left means you can have more (but smaller) networks, while having more bits on the right means less networks, but these networks will be able to hold a larger number of addresses.
Now, how can you (or the computer) tell where the "divider" is? Where one side ends and the other one begins? What bits represent the network? As the name implies, that is the function of the network mask. The netmask is another string of 32/128 zeros and ones which tells the computer what portion of the binary IP address represents the network and what portion represents the host. Going back to our previous example, a netmask 255.255.255.0 would look like this:
Decimal: 255 255 255 0
Binary: 11111111 11111111 11111111 00000000
As you can see we have two clearly divided parts, all ones on the left, all zeroes on the right. If you "overlay" that on top of the binary IP address, everything under the ones is the network portion, and everything under the zeroes is the host portion:
Netmask: 255 255 255 0
IP : 192 168 0 1
Netmask: 11111111 11111111 11111111 00000000
IP : 11000000 10101000 00000000 00000001
network side | host side
This means in our address, "192.168.0" is our network, and "1" is the address of our host within this network. It also means we can only ever have a maximum of 255 different addresses in this network.
CIDR notation and IPv6 prefixes
One very neat thing about netmasks is you don't really need to write the whole thing. If all we care about is how many ones there are on the left, we can simplify and save time by just counting them! In this notation you write the IP address followed by a forward slash and the number of ones in the netmask:
Netmask: 255 255 255 0
IP : 192 168 0 1
Netmask: 11111111 11111111 11111111 00000000 <- 24 ones
Adress and mask: 192.168.0.1/24
For IPv6 this works the same way, but only the shorter notation is used to make it easier to write, and for some reason it has a different name too: it's called a "prefix".
One important difference which needs to be noted for IPv6, however, is that despite the address being 128 bits long, the largest prefix (as in the maximum amount of ones in the "mask") you can have when subdividing networks is only 64, leaving the other 64 bits for the host portion. In other words, a /64 is the smallest network (in address space) you can have, with 64 bits (right-side) destined to the host portion, making 2⁶⁴ addresses available on that network.
I hope this post has been clear enough and can help someone trying to wrap their head around this stuff. Thanks for reading.
* This is done for convenience, but it is technically possible to use netmasks with non-contiguous portions, but you'd have to really hate yourself to do that.