Subnetting isn’t hard, but I often see even experienced network engineers looking for subnet calculators or trying to count in binary on their fingers. So how about a quick primer? To understand IPv4 subnets, remember what a subnet is and think about the IP address in binary.
What is subnetting?
A subnet is just a range of IP addresses. All the devices in the same subnet can communicate directly with one another without going through any routers. In IPv4, a network interface is connected to only one subnet and has only one IP address. In IPv6 things are slightly more complicated, so we’ll save IPv6 subnetting for another article. But it’s useful to understand IPv4 first because the basic concepts are the same.
My laptop is on a subnet that also includes a server, a printer, a couple of other workstations, and a router. If I want to communicate with another device in my subnet, I can send packets to it directly. If it’s not on my subnet, I need to forward the packet to a router first. That router also needs to be on my subnet. My computer knows that another device is in my subnet by looking at my own IP address and my subnet mask.
Suppose my IP address is 192.168.101.15 and my subnet mask is 255.255.255.0. There are 32 bits in the IP address and the same number in the mask. We always write those 32 bits as four 8-bit numbers, often called octets. The thing that can make it confusing is that we use decimal notation for each of those 8-bit numbers, but the mechanics of subnetting are really going on in binary.
Let’s look at the IP address side by side with the mask in both decimal and binary notation:
192.168.101.15 = 1100 0000 . 1010 1000 . 0110 0101 . 0000 1111 255.255.255.0 = 1111 1111 . 1111 1111 . 1111 1111 . 0000 0000
Anywhere the mask has a 1 is the network portion of the address. Anywhere the mask has a 0 is the host portion of the address. The network portion is 192.168.101.0 and the host portion is xx.xx.xx.15. (To make it a little simpler, we always group all the ones to the left and all the zeroes to the right of the mask.)
Any other device with the same network portion is part of my subnet. So 192.168.101.1 is part of my subnet and 192.168.101.100 is part of my subnet, but 192.168.102.15 isn’t part of my subnet and I need to go through the router to reach it.
192.168.101.0 = 1100 0000 . 1010 1000 . 0110 0101 . 0000 0000 192.168.101.1 = 1100 0000 . 1010 1000 . 0110 0101 . 0000 0001 192.168.101.15 = 1100 0000 . 1010 1000 . 0110 0101 . 0000 1111 192.168.102.15 = 1100 0000 . 1010 1000 . 0110 0110 . 0000 1111 255.255.255.0 = 1111 1111 . 1111 1111 . 1111 1111 . 0000 0000
Look at the highlighted last two bits of the third octet in that 192.168.102.15 address. Instead of being “01100101”, it’s “0110110”. Since this difference occurs in the “network” portion of the address (where the mask has 1s instead of 0s), this address is in a different subnet.
Special addresses and subnets
Think about just the host portion of the address. In our example (192.168.101.15/24) the host portion is .15. The mask is /24. That means eight bits (32-24=8) are available for specifying the host.
If I write 15 in binary, I get 0000 1111. (It’s conventional to write these 8-bit binary values as two groups of four with a space between because they’re easier to read that way.)
The lowest value in this subnet range is 0000 0000, which is the decimal number 0. The highest is 1111 1111, which is the decimal number 255. These are what I mean when I say “all 0” and “all 1”. These two values are reserved for the network address (to refer to the entire network) and for local broadcasts on the subnet, respectively. You can’t assign them to any host — though there are exceptions to this rule, which I’ll talk about in a moment.
As a result, even though there are 256 possible values for an 8-bit number, there are only 254 allowed host addresses in a /24 subnet.
While many of us are familiar with the special private IP address ranges such as 10.0.0.0/8 and 192.168.0.0/16, there are quite a few other special IP addresses that you can read up on as well that are used for a variety of purposes.
/24 is a very common subnet size. It’s easy to understand because the network portion of the address is the first three octets and the host portion is the last octet. You can just read off the subnet information. Any two addresses with the same first three octets are in the same subnet.
I really like using /24 subnets precisely because they are so easy to read and remember. One of my personal rules of network design is that when somebody calls me at 3 a.m. to troubleshoot a problem, it’s probably best if I don’t have to think too hard.
But there are some good reasons for using other sizes of subnets. For example, you might want to conserve addresses on a subnet that you know will never have many devices. Or you might need to create a subnet with many hundreds of devices on it. In both cases, you’ll want a different subnet size.
If you have a subnet with a mask of /25, then instead of eight free bits for the host portion of the address, you have only seven bits (32-25=7). 2^7 is 128. Just like in the /24 case, you can’t use either the all 0 or all 1 host addresses. That leaves 126 possible host addresses.
This table shows /25 and several other useful subnet sizes.
|CIDR notation||Netmask notation||2^(32-n)||Available hosts||Note|
|/0||0.0.0.0||4,294,967,296||4,294,967,294||The whole internet|
I’ve included the old-fashioned class names in the table, but it’s important to know that the internet no longer recognizes the concept of class. This is also why the “C” in the CIDR “/24” style notation stands for “Classless”.
Take a look at the last two entries, which break the rules for all 0 and all 1 host addresses being illegal. It was once true that the only way to get a point-to-point subnet with two devices was to use a /30 subnet. But the trouble with the /30 subnet is that it wastes fully half the range because every /30 subnet has four host addresses, of which two are the all 0 and all 1 addresses, which are needed as the network address and the broadcast address.
So RFC 3021 was introduced to allow the use of /31 subnets specifically for point-to-point links that don’t require a local broadcast. In these networks, any packet sent by one node must be intended for the other node, as there are no other possibilities.
The /32 subnet is used for things like internal loopback addresses where there is only ever one device in a subnet. Loopback interfaces are often used by network devices like routers to provide an interface that is always up.
Saving time with CIDR notation
We’ve been talking about traditional netmask notation. But before we go any further, let me talk about another notation called CIDR (classless interdomain routing).
The trouble with the traditional network mask notation is that, looking at it, you might think you could have an arbitrary sequence of 1s and 0s. Then you could make any two addresses part of the same subnet. That would be extremely confusing for a human to read, but it wouldn’t actually provide any benefit in terms of routing or giving more address space, so it’s not allowed.
All the 1s have to be on the left and all the 0s on the right. So all that really matters is how many 1s there are. You don’t even need to separately count the 0s because there have to be 32 bits altogether.
In our example, the mask is 255.255.255.0. That’s three groups of eight 1s followed by eight 0s. So we can say everything there is to know about this mask by simply specifying that there are 24 1s (3×8=24), and we write this as /24. In CIDR notation, our example address and subnet information can therefore be written as 192.168.101.15/24.
If you don’t like CIDR notation, that’s fine. I didn’t like it at first either, but it really does save a lot of time and space when writing addresses.
Determining addresses in a subnet range
So far, I hope this all sounds pretty simple. There’s only one hard part to figuring out subnets: knowing which addresses are included in a particular range. There are a few tricks that can help, though, and prevent IP address conflicts.
The first trick is that the all-0 address is a binary number that necessarily ends in a zero, which means it’s always an even number. So, except for /31 and /32 subnets, the first usable address in any range is always an odd number. Similarly, the all-1 address is always an odd number. So the last usable address must be even.
The second trick is to remember the numbers in the middle column of the above table, the powers of two. You really need to remember the powers of two up to 2^8. Then you count by the appropriate power of two. (1, 2, 4, 8, 16, 32, 64, 128, 256 – just memorize them.)
Here’s what I mean. If I’m using a /28 subnet, then I first subtract 28 from 32, which is 4. I remember that 2^4 is 16. That tells me to count by 16s. The first subnet is xx.xx.xx.0/28. To get the second subnet, I add 16: xx.xx.xx.16/28, then xx.xx.xx.32/28 and xx.xx.xx.48/28 and so forth.
These values tell me both that the first and last hosts in each range. For xx.xx.xx.0/28, they are .1 and .14. For xx.xx.xx.16/28, they are .17 and .30, and so forth. Notice the first address is always odd and the last one is always even.
What about bigger ranges?
We can also make subnets that are bigger than the 254 available addresses in a /24 subnet.
Think about /23. There are 32 bits in the address so, if the mask is 23 bits long, then there are 9 bits available for hosts. This means all the bits of the fourth octet in the IP address and one bit of the third. In netmask notation, this would be 255.255.254.0. Let’s look at an example.
Suppose our subnet is 10.11.12.0/23. The first address in this range is obviously 10.11.12.1, but the last one is actually 10.11.13.254. Notice that the third octet is 13. Look at the binary representation of the address and mask to see why this is true.
10.11.12.0 = 0000 1010 . 0000 1011 . 0000 1100 . 0000 0000 10.11.13.0 = 0000 1010 . 0000 1011 . 0000 1101 . 0000 0000 255.255.254.0 = 1111 1111 . 1111 1111 . 1111 1110 . 0000 0000
Every address between 10.11.12.1 and 10.11.13.254 is included in this subnet. This includes 10.11.12.255 and 10.11.13.0, but a lot of network administrators avoid these addresses for mostly superstitious reasons, even though they are valid addresses. (It’s not completely superstitious. If you use these addresses and one or more hosts on the network are misconfigured to use the more common /24 subnet mask, then you could wind up seeing some traffic for these two hosts sent as broadcasts rather than direct unicast packets.)
We can make subnets with even larger ranges, like /22, or /11. But the good news is that you don’t need to memorize a bunch of powers of 2 for these. Instead, just apply the rules that we discussed above for /24-/32, but on a different octet of the address.
By this I mean that /16 is just like /24, but on the third octet. Similarly, /17 is like /25, and so forth. For example, if my subnet was 10.12.0.0/20, I could think about the analysis that we just did for /28 (because 20 bits is 4 more than 16, just as 28 is 4 more than 24).
So, where we determined that /28 corresponds to a mask of 255.255.255.240, we push it back one octet to get the mask for /20, 255.255.240.0. And, just as we counted by 16’s to get the subnets for /28, we count by 16’s to get the subnets for /20. They would be xx.xx.0.0/20, xx.xx.16.0/20, xx.xx.32.0/20, and so forth.
And our hosts in each of these ranges would run from the first odd value to the last even value: xx.xx.0.1 to xx.xx.15.254. This is a little different from just copying the fourth octet of /28 to the third octet of /20 because we can use the 0 and 15. We just can’t use the very first (xx.xx.0.0) and the very last address (xx.xx.15.255) in the range.
Do you really need subnets that big?
This is where we meet one of the cool aspects of TCP/IP routing. You probably don’t want to deal with a /20 or a /9 subnet. That’s just way too many hosts on one segment. The broadcasts for ARP on any Ethernet network would create a serious congestion problem. But you can greatly simplify routing tables by using summarization.
Summarization works like this. Suppose I’m working through cloud-based network monitoring, and I have a large network that uses all of 10.0.0.0/8. But suppose I have allocated my addresses so that my Montreal network uses 10.1.4.0/24, 10.1.5.0/24, 10.1.6.0/24 and 10.1.7.0/24. And suppose my Toronto network uses 10.1.8.0/24 and 10.1.9.0/24. A central router that needs to send traffic to both of these sites could have all six of these subnets in its routing table, or we could summarize.
We could notice that the 4 Montreal ranges are all subnets of 10.1.4.0/22, and the 2 Toronto ranges are subnets of 10.1.8.0/23. Now I only need 2 route entries.
And I could further subnet any of these ranges. For example, 10.1.4.0/24 might actually consist of 10.1.4.8/28, 10.1.4.16/28 and 10.2.4.252/30. The summary still works. I don’t need any more routing table entries in my central router.
And, it’s important to point out that TCP/IP has an efficient way of dealing with exceptions. Suppose the Toronto network also had 10.1.4.248/30. In this case, I could leave the summary route for Montreal, 10.1.4.0/22, and just add this one exception to point to Toronto: 10.1.4.248/30.
When routing packets, a router will always select the “best” or “longest” match. So you can have a /22 route as the summary, and then deal with individual exceptions. Anything that matches one of the exceptions with a longer (higher number after the “/”), will get routed according to that rule.
You are already familiar with this concept of summary rules and exceptions. The router has a summary route for everything, it’s called the “default route”, 0.0.0.0/0. The default route matches every possible address. Usually it points to the public Internet. Your routers will have more specific routes for all of your internal networks, and the default route will send everything else to the Internet.
Ok, so determining subnet addresses isn’t actually all that hard. If you think for a minute about what you’re doing, you really don’t need one of those subnet calculators. And, in truth, thinking about what you’re doing is probably a good idea anyway.