Tuesday, April 27, 2010

How to Calculate CIDR, Netmask, etc. For Reals.

I've always been kind of bad with math (yeah I know). I mean, I'm good at stuff like 22*15. (22*10)+((20*5)+(2*5))=330. I can do that in my head.

But when starting in my career, binary math seemed so overwhelming. So I didn't learn it. By the time I got to a point where I needed to calculate CIDR addressing, I had a wonderful tool called the Internet search engine.

So I've been a sysadmin for a long time now, I guess. A sysadmin who could not perform binary math.

No more. Tonight I finally sat my ass down and figured it out. I tried searching explanations online but found very little practical math. A lot of it seemed really complicated and, still overwhelming. After banging my head and pulling my hair (simultaneously, too--what an accomplishment itself!), I finally had that epiphany and sorted it out in like five minutes.

Because interview questions always seem to "base" (Hurrrr, I made a pun.) on the network bits, that's all I am going to address (Look Ma, another one!) in this post.

Here's how to do it:

Given a block /N, find the number of usable addresses and the netmask.

Each octet consists of two sets of 4 bits:

0000 0000 0000 0000 0000 0000 0000 0000

so take N/4 to find the exact number of bits in the network address:

/23 => 23/4=5.75

Fill in 5.75 of those sets with a 1:

1111 1111 1111 1111 1111 1110 0000 0000

To find the number of usable addresses, calculate 2^the number of host bits-2.

2^9-2=510 usable addresses

Now let's find the netmask. This is the trickiest "bit": section up the octets and find the number of host bits in the last octet that is not 0. In this case it is the 3rd octet. Subtract that from 255, and you have that octet in the netmask. All prior octets are 255 (1111 1111) and any subsequent octets are 0 (0000 0000).

255-(2^0)=254

Netmask: 255.255.254.0

Obviously this is the second easiest possible netmask to calculate (the easiest being 0). Let's try a harder block: /17.

/17 => 17/4=4.25

1111 1111 1111 1111 1000 0000 0000 0000

2^15-2=32766 usable addresses

3rd octet "1000 0000" (working 0s right->left)
255-(2^0+2^1+2^2+2^3+2^4+2^5+2^6) = 128

Netmask: 255.255.128.0

I hope you find this useful. I feel it explains it in a much more straightforward way than most resources I've found online.

5 comments:

  1. nice one. i'm in the same boat… bad with math, or at least way out of practice. thanks!

    ReplyDelete
  2. Nice.

    Why divide by 4? Breaking into 4-bit blocks is contrary to the byte-sized chunks they really are. You'll notice the /17 has 17 bits set.. I'm not sure breaking into 4-bit chunks helps with the visualization (for me).


    Many people like my way of explaining/shortcutting it, though some don't. But I figure a shameless plug would be fun :)

    Here:
    http://www.enterprisenetworkingplanet.com/netsp/article.php/3566521/Networking-101-Understanding-Subnets-and-CIDR.htm

    ReplyDelete
  3. The 4 bit chunks helps me visualize them into octets. It's pretty arbitrary :) I'll check out your link!

    ReplyDelete
  4. Scoot,

    I realize I am kinda stalking you by replying to such an old post of yours, but oh well.

    Why divide by four? Dividing by four and filling in bits has nothing to do with how the address "works" really -- it's 32 bits long, so to get the unset bits just take 32 minus the set bits. To get the number of usable addresses in a CIDR block, take the prefix of say /17 as you used above:

    (2 ^ (32-17)) - 2 = 32766

    The other fun thing is that the above formula basically has a very strong relationship to the netmask -- the netmask is the bitwise negation of (2 ^ (32-17)) - 1 = 32767 = 0.0.127.255. Negated bitwise, that's 255.255.128.0. MySQL makes a good calculator:

    mysql> select inet_ntoa(0xffffffff & ~(pow(2, (32-17)) - 1)) as netmask;
    +---------------+
    | netmask |
    +---------------+
    | 255.255.128.0 |
    +---------------+

    You can also use this math to calculate the "network" address given any address + netmask or cidr:

    mysql> select inet_ntoa(inet_aton("123.234.237.42") & (0xffffffff & ~(pow(2, (32-17)) - 1))) as network;
    +---------------+
    | network |
    +---------------+
    | 123.234.128.0 |
    +---------------+

    Or if you know the netmask:

    mysql> select inet_ntoa(inet_aton("123.234.237.42") & inet_aton("255.255.128.0")) as network;
    +---------------+
    | network |
    +---------------+
    | 123.234.128.0 |
    +---------------+

    I made this fun tool some time ago, which does CIDR math for you and does prefix conversions, so you can e.g. find out how many /24's you could make from a given /17, and the network and netmask of each of them:

    http://jcole.us/cidr/?cidr=123.234.128.0/17&to=24 (no form, but you can mess with the GET args)

    Regards,

    Jeremy

    ReplyDelete
  5. CIDR is the short for Classless Inter-Domain Routing, an IP addressing scheme that replaces the older system based on classes A, B, and C. A single IP address can be used to designate many unique IP addresses with CIDR. A CIDR IP address looks like a normal IP address except that it ends with a slash followed by a number, called the IP network prefix. CIDR addresses reduce the size of routing tables and make more IP addresses available within organizations.

    ReplyDelete