IPv6 Subnet Calculator / Subnetting with IPv6 Part 1/2

By Yucel Guven, (c) 2010-2017

Introduction

We are in the transition phase from IPv4 to IPv6 addressing structure, and I believe that the network engineers should easily plan their IPv6 addressing /subnetting infrastructure without any error.

In this article I tried to explain how IPv6 subnetting works by giving examples. I also wrote and distributed an IPv6 Subnet Calculator / Tool application using Visual C# 2013 Express based on .NET 4 Framework.
It lets you plan/subnet your assigned address for all 128 bits. You can download the application from downloads tab above. I distributed the application in the hope that it will be useful for your subnet calculations.
I will be continuously developing the software, so please don't hesitate to comment/inform for any bugs or new feature suggestions.

1. How does '/' (slash or prefix-length notation) works with IPv6?

The '/' indicates the bits which are fixed for your subnetwork. Fixed means that you do not have any control on these bits, you must not change them ( I like to call them "don't touch only watch bits"). IPv6 address is 128 bits long and your network/organization is assigned "128 minus /prefix-lengthValue" and these are the bits given under your control. You can do your subnetting with these bits and assign addresses to your computer/car/mobile/etc.

For example, assume that the prefix '2001:db8:1234::/48' is assigned to your network by your service provider (or by RIPE, ARIN, etc). In this case, /48 indicates that starting from the left-most bit up to and including the 48th bit, these bits are fixed and must not be changed (don't touch only watch). And the rest of the bits which have the length of 128-48=80bits are given to your control.

So, the importance of '/' prefix-length is that it indicates the boundary of your network. In other words, from which number your assigned network starts and at which number it ends.

2. Finding IPv6 Start and End Addresses of our Subnet:

If we have for example 192.168.3.0/24 subnet prefix, then 24 bits are fixed. You must not change these bits. And our netmask will be 255.255.255.0, we can do subnetting by using 32-24=8bits by taking care of subnet and broadcast addresses, as we all know very well with our IPv4 experience.

2.1 Three useful Bitwise Operators: & , | , ~

& (AND), | (OR), ~ (NOT or bit INVERTER) : We will use these three bitwise operators in our calculations. I think everybody is familiar -at least from university digital logic courses- and knows how they operate. I will not explain the details here again. You can search for 'bitwise operators' for further information.

Now with our IPv6 subnet-prefix assigned, how can we find our subnets and starting and end addresses of it? We can easily calculate them with the help of these three logic operators as follows. I will try to demonstrate on both IPv4 and IPv6.

With IPv4:
What is our mask if we have '/24'? Remember CIDR notation, it is simply 255.255.255.0 which is 24 bits all 'set' or 'all one' starting from the left-most bit up to and including 24th bit.

Finding Start Address is to 'AND' your address with your mask which is:
(192.168.3.5) & (255.255.255.0) = 192.168.3.0 This is our Starting Address, or as we call Network address.

Finding End Address is to 'OR' your address with the inverted (NOT) mask which is:
(192.168.3.5) | ~(255.255.255.0) = 192.168.3.255 This is our End Address, or as we call Broadcast address.

With IPv6:
What is our mask if we have '/48'? Simply it is ffff:ffff:ffff:: for which all 48 bits are 'set' or 'all one' starting from the left-most bits up to and including 48th bit. As you can see the evaluation way of the mask is exactly same as in IPv4. As for our IPv6 subnet prefix '2001:db8:1234::/48', again same calculation method applies. It is also useful to remember that we always use 'hexadecimal' instead of decimal numbers for addressing since IPv6 is completely based on hexadecimal numbers. So,

Finding Start Address is to 'AND' the address with your mask which is:
( 2001:db8:1234:: ) & ( ffff:ffff:ffff:: ) = 2001:db8:1234::

Finding End Address is to 'OR' the address with your inverted (NOT) mask which is:
(2001:db8:1234:: ) | ~( ffff:ffff:ffff:: ) = 2001:db8:1234:ffff:ffff:ffff:ffff:ffff

As a result, for the subnet-prefix '2001:db8:1234::/48' we have the range or interval of our subnet:

IPv6 Starting Address of subnet > 2001:db8:1234:0:0:0:0:0 (or compressing zeros 2001:db8:1234:: )
IPv6 End Address of subnet > 2001:db8:1234:ffff:ffff:ffff:ffff:ffff

Also remember that we don't have broadcast mechanism in IPv6, so we don't have broadcast address.

3. How can we do subnetting with our IPv6 subnet-prefix?

As we know, our first prefix-length indicates our fixed bits and we can borrow bits starting from (but excluding) prefix-length value towards the right-most bit (from left to right).

Example:
Let's use the subnet-prefix '2001:db8:1234::/48', and borrow 2 bits for subnetting.

The beauty of number conversion shows itself when we do hexadecimal to binary conversion. When converting from hex-to-binary or vice versa, you can simply and directly convert each hex-digit into binary form without caring about the digit weights. In hexadecimal notation each hex-digit corresponds to 4 bits, usually called as 'nibble'. In expanded form, our example address is 2001:0db8:1234:0000:0000:0000:0000:0000

And in 4-bit binary form (or with nibbles) it is;

2 0 0 1 : 0 d b 8 : 1 2 3 4 : 0 0 ... (all the rest zeros)
0010 0000 0000 0001 : 0000 1101 1011 1000 : 0001 0010 0011 0100 : 0000 0000 ... (all the rest zeros)

Let's borrow 2 bits starting with /49 up to /50 (we include 50.bit) :

0010 0000 0000 0001 : 0000 1101 1011 1000 : 0001 0010 0011 0100 : 0000 0000 ... (all the rest zeros)


By borrowing 2 bits, we can have 22= 4 unique subnets, which are:
  1. 0010 0000 0000 0001 : 0000 1101 1011 1000 : 0001 0010 0011 0100 : 0000 0000 ... (all the rest zeros)
  2. 0010 0000 0000 0001 : 0000 1101 1011 1000 : 0001 0010 0011 0100 : 0100 0000 ... (all the rest zeros)
  3. 0010 0000 0000 0001 : 0000 1101 1011 1000 : 0001 0010 0011 0100 : 1000 0000 ... (all the rest zeros)
  4. 0010 0000 0000 0001 : 0000 1101 1011 1000 : 0001 0010 0011 0100 : 1100 0000 ... (all the rest zeros)

Let's convert these numbers back into hexadecimal and see the result:
  1. 2001:db8:1234:0000::/50 (First subnet)
  2. 2001:db8:1234:4000::/50 (Second subnet)
  3. 2001:db8:1234:8000::/50 (Third subnet)
  4. 2001:db8:1234:c000::/50 (Fourth subnet)

If you are a service provider, you can assign these subnet-prefixes to your customers one by one with '/50' prefix-length, e.g. 2001:db8:1234:0000::/50 for one customer, and 2001:db8:1234:4000:/50 for other, etc.
And now your customers should know the End of their assigned address space. At this point remember 'Finding Start and End addresses of our subnet' and perform the calculations.

First of all, your customers will have mask of '/50' which is all 50 bits 'set' or all 50 bits are 'ones' giving us the mask of 'ffff:ffff:ffff:c000::'. Now using this mask we can easily calculate the start-end addresses, i.e. the range or interval of our subnet. Let's do it one by one.

1st. Customer subnet Start address=
(2001:db8:1234:0000:: ) & ( ffff:ffff:ffff:c000:: ) = 2001:db8:1234:0000:0:0:0:0 = 2001:db8:1234::
1st. Customer subnet End address=
(2001:db8:1234:0000:: ) | ~( ffff:ffff:ffff:c000:: ) = 2001:db8:1234:3fff:ffff:ffff:ffff:ffff

2nd. Customer subnet Start address=
(2001:db8:1234:4000:: ) & ( ffff:ffff:ffff:c000:: ) = 2001:db8:1234:4000:0:0:0:0 = 2001:db8:1234:4000::
2nd. Customer subnet End address=
(2001:db8:1234:4000:: ) | ~ ( ffff:ffff:ffff:c000:: ) = 2001:db8:1234:7fff:ffff:ffff:ffff:ffff

3rd. Customer subnet Start address=
(2001:db8:1234:8000:: ) & ( ffff:ffff:ffff:c000:: ) = 2001:db8:1234:8000:0:0:0:0 = 2001:db8:1234:8000::
3rd. Customer subnet End address=
(2001:db8:1234:8000:: ) | ~ ( ffff:ffff:ffff:c000:: ) = 2001:db8:1234:bfff:ffff:ffff:ffff:ffff
and
4th. Customer subnet Start address=
(2001:db8:1234:c000:: ) & (ffff:ffff:ffff:c000:: ) = 2001:db8:1234:c000:0:0:0:0 = 2001:db8:1234:c000::
4th. Customer subnet End address=
(2001:db8:1234:c000:: ) | ~ ( ffff:ffff:ffff:c000:: ) = 2001:db8:1234:ffff:ffff:ffff:ffff:ffff

Notice that each of the subnet-prefixes can also be used again to perform subnetting. For example 4th customer may use the subnet-prefix '2001:db8:1234:d000::/50' to do subnetting by borrowing bits again say from /50 to /54, according to their needs of course.

Summary

In order to find the starting and end address of your subnet, you only need to know IPv6 address and prefix-length value. Remember these bitwise operations (which are also valid for IPv4):

(IPv6 Address) & (/prefix-length mask) is equal to (IPv6 subnet Start address), and
(IPv6 Address) | ~ (/prefix-length mask) is equal to (IPv6 subnet End address).

IPv6 Subnet Calculator / Subnetting with IPv6 Part 2/2

About This Application

First start by checking the entered value to see either the user entered a valid IPv6 address or not.
For this purpose the function IsAddressCorrect() gets the entered string, and does the necessary checks on it, and returns either 'true' or 'false' boolean value depending on the check result.

If the entered value is a valid IPv6 address, then we need to formalize the entered address into 16 Bytes hexadecimal value in order to perform our calculations on it. The function FormalizeAddress() gets a valid IPv6 address as string, inserts the necessary amount of zeros if the address is compressed, and returns a string representing 16 Bytes formal IPv6 address.

These two functions might also be combined in a general library and be converted to a DLL to validate and formalize an IPv6 address but I did not do it here. Instead I wrote them in a separate class, for the sake of keeping the functions of the application simple and visible.

As I try to explain in the 'Subnetting with IPv6 Part 1/2' above article, it is easy and obvious to find the subnet start and end addresses of a given address by using the /prefix-length value. The function StartEndAddresses() takes an IPv6 address and returns the subnet start and end addresses that the address belongs to.

Another issue is how to find the neighboring or adjacent subnet addresses, i.e. subnets that comes just after our subnet? In other words, how can we move or walk through the adjacent subnet address spaces?

Very easy and simple way of achieving this is to get the end address, and increment by one which gives the start address of the adjacent subnet address. By using this start address, find the end address, then increment by one which will give the second adjacent subnet address, and so on. As you notice we are now able to move or walk through the subnet address spaces with this algorithm.

An iterative procedure to obtain the adjacent subnet addresses might be:
Step1. Get the IPv6 address
Step2. Find the subnet start address
Step3. Find the subnet end address
Step4. Increment the subnet end address by one
The start address of the next subnet obtained.
Step5. Go to step 3 with the address found in Step 4.


An example code might be:
        public SEaddress StartEndAddresses(SEaddress input)
        {
            UInt64 mask = Convert.ToUInt64("FFFFFFFFFFFFFFFF", 16);
            mask = (mask >> (input.slash));
            input.End = (input.Resultv6 | mask);
            mask = ~mask;
            input.Start = (input.Resultv6 & mask);
            return input;
        }
where SEaddress is a storage object.
public class SEaddress
    {
        public UInt64 Resultv6 = UInt64.MinValue;
        public UInt64 Start = UInt64.MinValue;
        public UInt64 End = UInt64.MinValue;
        public int slash = 0;
        public int subnetslash = 0;
        public UInt64 subnetidx = UInt64.MinValue;
    }

For the subnetting, we borrow the bits by using the second slider or track bar. Despite we can easily find our subnets, now another question is what is the index number of our subnet and how can we find the index number of it? i.e. is it 4th subnet, or 5th, or 6th, or which?

The answer is inside the address itself and we can extract this index number from the address.

Actually, using the second slider, i.e. borrowing the bits, we are creating the subnet index numbers, too. The interval between the two sliders has our subnet index number. For example, if we drag the first slider to /48 and the second slider to /52, it means that we borrow 4-bits and created 24=16 different subnets having index values from 0 to 15. So how can we handle finding the index value in our application?
A solution might be that we can copy the bits in this interval by means of testing the bits and then setting it into our index variable. For testing the bit we can perform the bitwise operation (number &(1<< i )), where i is an integer to shift. If the result is different than zero then the bit at that position is 1, otherwise it is zero.

The code might be like:
        input.subnetidx = UInt64.MinValue;
        int delta = input.subnetslash - input.slash - 1;

        for (int i = (63 - input.slash); i > (63 - input.subnetslash); i--)
        {
            if ( BitTest(input.Start, i) == 1)
            {
                input.subnetidx = BitSet(input.subnetidx, delta);
            }
            else
            {
                input.subnetidx = BitClear(input.subnetidx, delta);
            }
            delta--;
        }
where;
        public int BitTest(UInt64 ui64, int i)
        {
            /* if ith bit  is set, returns 1,
             * if ith bit not set, returns 0,
             * if i>63 or i<0 returns -1
             */
            if (i > 63 || i < 0 )
                return -1;
            if ((ui64 & ((UInt64)1 << i)) != 0)
                return 1;
            else
                return 0;
        }
        public UInt64 BitSet(UInt64 ui64, int i)
        {
            if (i > 63 || i < 0)
                return UInt64.MinValue;

            ui64 = (ui64 | ((UInt64)1 << i));
            return ui64;
        }
        public UInt64 BitClear(UInt64 ui64, int i)
        {
            if (i > 63 || i < 0)
                return UInt64.MinValue;

            ui64 = (ui64 & ~((UInt64)1 << i));
            return ui64;
        }

Up to this point, we know how to find the subnet start/end addresses and subnet indexes. What is left is to produce these values in a simple for loop with an 'upto' limit value and display the result.

            for (int count = 0; count < upto; count++)
            {
                subnets = Subnetting(subnets);
                  //Display the Results
                 //...
              subnets.Start = subnets.End + 1;
            }

Last edited Feb 4 at 7:48 PM by ygvn, version 22