Click here to Skip to main content
Click here to Skip to main content
Go to top

Subnetting with IPv6 - Part 2/2

, 27 Jan 2014
Rate this:
Please Sign up or sign in to vote.
IPv6 subnetting tool/calculator explained

Introduction

In the second part of the article, I will try to explain functions I used inside the application together with a technique for how to find adjacent subnets.

(Follow the link for the first part of this article: Subnetting with IPv6 Part 1/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.

public boolean IsAddressCorrect(String sin) {
    int nDC = 0;
    int nC = 0;

    sin = sin.trim();
    String s = sin;
    char[] chars = s.toCharArray();

    /* 0. Error: Empty */
    if (s.isEmpty()) {
        errmsg = "> Empty address";
        return false;
    }


    /* 1. Error: UNDEFINED '::' */
    if (s.equals("::")) {
        errmsg = "> Undefined";
        return false;
    }
    /* 2. Error: Triple or more columns entered */
    if ((s.length() <= 1) || (s.contains(":::"))) {
        errmsg = "> Not valid";
        return false;
    }
    /* 3. Error: Not valid hex */
    if (!Pattern.matches("^[0-9A-Fa-f:]+$", s)) {
        errmsg = "> Not valid hex-digit";
        return false;
    }
    /* 4. Error: Cannot start or end with ':' */
    if (chars[0] == ':' && chars[1] != ':') {
        errmsg = "> Not valid: ':'";
        return false;
    }
    if (chars[s.length() - 1] == ':' && chars[s.length() - 2] != ':') {
        errmsg = "> Not valid: ':'";
        return false;
    }
    /* 5. Error: More than 2 Bytes */
    String[] sa = s.split(":", -1);
    for (int j = 0; j < sa.length; j++) {
        if (sa[j].length() > 4) {
            errmsg = "> More than 2 bytes";
            return false;
        }
    }
    /* 6. Error: Count of DoubleColumns and Columns */
    s = sin;
    nDC = s.split("::", -1).length - 1;
    s = s.replace("::", "**");
    nC = s.split(":", -1).length - 1;

    /* Case I. DoubleColumn can only appear once - RFC4291 */
    if (nDC > 1) {
        errmsg = "> DoubleColumn can only appear once";
        return false;
    }
    /* Case II. No DoubleColumns means there must be 7 columns */
    if (nDC == 0 && nC != 7) {
        errmsg = "> Not valid, there must be 7 columns";
        return false;
    }
    /* Case III. If DoubleColumn at start/end, max. columns must be 6 or less */
    s = sin;
    int sL = s.length();
    if ((chars[0] == ':' && chars[1] == ':')
            || (chars[sL - 1] == ':' && chars[sL - 2] == ':')) {
        if (nDC == 1 && nC > 6) {
            errmsg = "> Excessive columns";
            return false;
        }
    } /* Case IV. If DoubleColumn in middle, max. columns must be 5 or less
       */ 
    else if (nDC == 1 && nC > 5) {
        errmsg = "> Excessive columns";
        return false;
    }


    /* End of Check */
    errmsg = "> ok";
    return true;
} 

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, places the necessary amount of zeros if the address is compressed, and then returns 16 Bytes formal IPv6 address as BigInteger data type.

public BigInteger FormalizeAddr(String sin) {
 
    String[] Resv6 = new String[]{"0000", "0000", "0000",
                                  "0000", "0000", "0000",
                                  "0000", "0000"};
 
    BigInteger Finalv6 = BigInteger.ZERO;
    sin = sin.trim();
    String s = sin;
    String[] sa = s.split(":", -1);
    int nC = 0;
    s = s.replace("::", "**");
    nC = s.split(":", -1).length - 1;

    /* Start of Building Result v6 address */
   for (int k = 0; k < sa.length; k++) {
       if (sa[k].length() == 0) {
           continue;
       } else {
            sa[k] = String.format("%4s", sa[k]).replace(' ', '0');
       }
   }

   if ((sa[sa.length - 1].length() == 0) 
       && (sa[sa.length - 2].length() == 0)) {
       int t = nC + 1;
       for (int i = 0; i < t; i++) {
          Resv6[i] = sa[i];
       } 
   } else if (sa[0].length() == 0 && sa[1].length() == 0) { 
       int t = nC + 1; 
       for (int i = 0; i < t; i++) {
          Resv6[7 - i] = sa[sa.length - 1 - i];
       }
   } else {
       int idx = Arrays.asList(sa).indexOf("");
       for (int i = 0; i < idx; i++) {
           Resv6[i] = sa[i];
       }
       for (int i = 0; i < sa.length - idx - 1; i++) {
       Resv6[7 - i] = sa[sa.length - 1 - i];
    } 
  } 
  /* End of Building Resultant IPv6 address */ 
  s = ""; 
  for (int i = 0; i < 8; i++) { 
     s += Resv6[i]; 
  } 
  
  Finalv6 = new BigInteger(s, 16);
  return Finalv6; 
}; 

These two functions above may also be combined in a general class library 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 for everybody.

As I try to explain in the 'Subnetting with IPv6 Part1/2' 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() below takes an IPv6 address and returns the subnet start and end addresses inside SEaddress object.

public SEaddress StartEndAddresses(SEaddress input) { 
   BigInteger mask = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16);
   mask = mask.shiftRight(input.slash);
   input.End = mask.or(input.Resultv6);
   mask = mask.not();
   input.Start = mask.and(input.Resultv6);

   return input;
}

where SEaddress is a storage object:

public class SEaddress {
    public BigInteger Resultv6 = BigInteger.ZERO;
    public BigInteger Start = BigInteger.ZERO;
    public BigInteger End = BigInteger.ZERO;
    public int slash = 0;
    public int subnetslash = 0;
    public BigInteger subnetidx = BigInteger.ZERO;
}

Another issue is how to find the neighboring or adjacent subnet addresses, or 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:

  • Step 1. Get the IPv6 address
  • Step 2. Find the subnet start address
  • Step 3. Find the subnet end address
  • Step 4. Increment the subnet end address by one. The start address of the next subnet obtained.
  • Step 5. Go to step 3 with the address found in Step 4

For the subnetting, we borrow the bits by using the second slider or track bar. Despite the fact that 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? 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 1, then the bit at that position is 1, otherwise it is zero.

The code might be (this little part is also inside the StartEndAddresses() function):

input.subnetidx = BigInteger.ZERO;
   int delta = input.subnetslash - input.slash - 1;
   for (int i = (127 - input.slash); i > (127 - input.subnetslash); i--) {
       if (input.Start.testBit(i) == true) {
                input.subnetidx = input.subnetidx.setBit(delta);
       } 
       else {
                input.subnetidx = input.subnetidx.clearBit(delta);
       }
       delta--;
   }
return input;

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 variable, e.g. :

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

Happy IPv6 subnetting!

History

  • 29 September 2013, v1.0
  • 16 November 2013, v1.1 : Added new v1.8 C# application.
  • 12 December 2013, v1.2 : A few typing corrections and added v1.10 C# application.
  • 26 January 2014, v1.3 : Added new v1.11 C# application.

License

This article, along with any associated source code and files, is licensed under The BSD License

Share

About the Author

Yucel Guven
Engineer
Turkey Turkey
BSc in Electrical&Electronics Engineering
BSc in Physics

Comments and Discussions

 
QuestionGreat series Pinprofessionaljfriedman27-Jan-14 10:00 
AnswerRe: Great series PinmemberYucel Guven28-Jan-14 4:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 27 Jan 2014
Article Copyright 2013 by Yucel Guven
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid