Automating IP subnets allocation using Python

Sajid Bisnar Khan
5 min readJun 27, 2021

Allocating IP subnets is a simple task for experienced Network Engineers. However, this simple task is prone to human error specially when hundreds of subnets are supposed to be allocated. Most common mistakes are allocating invalid and conflicting subnets. An example of an invalid subnet is 192.168.0.16/27. This subnet is invalid because 192.168.0.16 is not a network address for /27 mask. And an example of conflicting subnets would be 192.168.0.0/27 and 192.168.0.4/30. These are conflicting subnets because there are overlapping IPs between them. In this article, I’ll show you how to write a script in Python to build these checks automatically into your excel sheet. I’ll also show you how to create a script to automate the process of IP allocation altogether. For example, lets say you need to allocate subnets with following masks /28, /28, /27, /27, /29, /29 starting from network address 192.168.0.0, then the expected answer would be, 192.168.0.0/28, 192.168.0.16/28, 192.168.0.32/27, 192.168.0.64/27, 192.168.0.96/29 and 192.168.0.104/29. Without wasting more time, lets get started!

Solving the problem of invalid subnets

First we need to understand why a subnet can be invalid. we know that 192.168.0.16/28 is a valid subnet, whereas, 192.168.0.16/27 is not. To understand why, lets convert both subnets to binary form. 192.168.0.16 in binary form can be written as 11000000101010000000000000010000. Next, we’ll enclose the network bits in square brackets [] and hosts bits in curly brackets {}. So, 192.168.0.16/28 in binary can be written as [1100000010101000000000000001]{0000} and 192.168.0.16/27 as [110000001010100000000000000]{10000}. By definition, binary numbers enclosed in [] bracket is a network address only if all bits inside {} bracket are zeros. Since, the former subnet (192.168.0.16/27) has a bit set to one inside curly bracket {10000}, 192.168.0.16 a not a correct network address for /27 mask. Lets see how we can apply this logic in Python, step by step

i) Create a method that takes ip and mask as input and returns network and host in binary form

ii) Next convert host_bits into integer. And if the integer is equal to zero then the subnet is valid otherwise it is invalid. If the mask is 32 than subnet is always valid. Therefore, the validity of subnet has to be checked only if the mask is not equal to 32. The method sets flag_err to ‘1’ in case the subnet fails the validity check

iii) We will now use method created above to validate list of subnets. ‘ip_list_valid’ is a list of all valid subnets, where as ‘ip_list_invalid’ is a list of invalid subnets. The purpose of regular expression is to ensure that the subnets are provided in correct format

Note that ‘main_sanity’ method is storing a list of flags returned by method called ‘Sanity’ which was created earlier. If any of the returned flags is set to ‘1’ then the list of subnets is not valid and requires rectification. When valid list of subnets are passed to ‘main_sanity’ method, we get below output

successfully verified the sanity of subnets

And when an invalid list is passed to the same method, we get following output

error occured.10.0.16.16/27 is incorrect subnet
error occured.192.168.0.22/30 is incorrect subnet

Simple script shown above solves the problem of invalid and valid subnets allocations. Now, lets hop on to the next problem that is, how to avoid assigning conflicting subnets

Solving the problem of conflicting subnets

Lets recap the problem we are trying to solve here. Consider the two subnets, 192.168.0.0/28 and 192.168.0.8/29 as an example. These two subnets cannot be allocated together because there are overlapping IPs between them. We can verify this by applying following steps. i) Select the smaller mask, in our case since 28 < 29, mask is equal to 28. ii) Convert both IPs into binary form, then enclose first 28 bits in square brackets. We get [1100000010101000000000000000]{0000}’ and ‘[1100000010101000000000000000]{1000} ’. Next, compare the terms inside square brackets, if the terms match, the subnets are conflicting otherwise they are fine. Python implementation for these step are given below

Above method takes list of subnets as input and computes all possible pair of subnets. It then checks for conflict, if conflict is detected, ‘1’ is appended into flag_subnet_list and ‘0’ is appended if no conflict is detected. To test the code, lets input a conflicting list and non-conflicting list

Example of non-conflicting list
No conflict detected
Example of conflicting list
('192.168.10.0/24', '192.168.10.0/28')

Notice that when non-conflicting list was passed, we got an output saying ‘no conflict detected’. And when conflicting subnet was passed, we got pair of subnets that were conflicting with each other. This code pretty much solves our problem. In the next section, we will discussion, how we can automate the process of subnets allocation altogether

Automation Subnets allocation

When subnets are allocated manually, the issues discussed above arises very frequently. The best way to avoid these issues is to automate the process of allocation itself. In this section, we will discuss how this can be done. Lets recap the problem we are trying to solve briefly. Suppose say you were given a task to assign subnets with following masks /28, /28, /27, /27, /29, /29 starting from network address 192.168.0.0 then we want the Python method to return 192.168.0.0/28, 192.168.0.16/28, 192.168.0.32/27, 192.168.0.64/27, 192.168.0.96/29 and 192.168.0.104/29 subnets. The steps we will be following to achieve desired results are as follows

i) Convert ‘starting_ip’ (subnet allocation starts with this ip, you can change this as per your requirement) into binary form and then store the network and hosts bits in separate variables derived using subnet mask

ii) Convert the hosts bits computed in the first step into decimal value. If the value is equal to ‘0’ then append the network address in a list called ‘result_list’ and if the value is not equal to ‘0’ then convert network bits into decimal value then add ‘1’ to it. Finally, convert the decimal value back to original subnet(x.x.x.x/x) format and append the result into ‘result_list’ list

iii) Next convert the subnet (which was appended into the result_list) into binary, then compute a decimal value and add ‘1’. Finally reconvert the result back to orignal subnet format (x.x.x.x/x) and store it in a variable called next_block

iv) Replace the ‘start_ip’ value with ‘next_block’ and repeat all the steps starting from step 1 for subsequent mask in the list of masks

Python implementation of these steps are given below

Note that in our example ‘starting_ip’ and ‘mask_list’ are initialized with ‘192.168.11.0’ and [23, 24, 25, 26, 27, 27], respectively. We get following output after running it

['192.168.12.0/23', '192.168.14.0/24', '192.168.15.0/25', '192.168.15.128/26', '192.168.15.192/27', '192.168.15.224/27']

For completeness, we can input list of masks from excel and store the output into another excel file by adding few more lines into existing code. An example is given below

input file

output file

Thanks for spending time to read. Cheers!

--

--