Skip to content

Instantly share code, notes, and snippets.

@pklaus
Created June 27, 2014 09:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pklaus/8f702a6042f8f3fcf7e7 to your computer and use it in GitHub Desktop.
Save pklaus/8f702a6042f8f3fcf7e7 to your computer and use it in GitHub Desktop.
Helper tools and functions for the Python3.3+ module ipaddress
"""
Helper tools and functions for the Python3.3+ module ipaddress
"""
def optimize(networks):
"""
An algorith to optimize a list of networks:
it merges its network elements as much as possible.
Adopted from IPSet's optimize() of
https://github.com/steffann/python-ipy/blob/master/IPy.py
"""
networks.sort()
# First eliminate all values that are a subset of other values
netlen = len(networks)
i = 0
while i < netlen:
# Everything that might be inside this prefix follows directly behind it
j = i+1
while j < netlen and contains(networks[i], networks[j]):
networks[j] = None
j += 1
i = j
# Try to merge as many prefixes as possible
run_again = True
while run_again:
# Filter None values. This happens when a subset is eliminated
# above, or when two prefixes are merged below
networks = list(filter(None.__ne__, networks))
# We'll set run_again to True when we make changes that require
# re-evaluation of the whole list
run_again = False
netlen = len(networks)
i = 0
while i < netlen-1:
j = i + 1
try:
# The next line will throw an exception when merging
# is not possible
networks[i] = add(networks[i], networks[j])
networks[j] = None
i = j + 1
run_again = True
except ValueError:
# Can't be merged, see if position j can be merged
i = j
return networks
def contains(a, b):
""" Tests if network a contains network b entirely """
return (b.network_address in a) and (b.broadcast_address in a)
def add(a, b):
"""
Merge two networks.
Possible if the networks are both IPv4 or both IPv6 and if they have
the same prefix length and differ only on the last bit of the prefix.
"""
if not a.version == b.version:
raise ValueError("Comparing networks of different kind.")
if not a.prefixlen == b.prefixlen:
raise ValueError("The networks don't share the same prefix length.")
if b < a:
return add(b,a)
max_prefix_len = 32 if (a.version == 4) else 128
if ( int(a.network_address) | 2 ** (max_prefix_len - a.prefixlen)) != int(b.network_address):
raise ValueError("Only networks where the last bit of the prefix differs can be merged")
return a.supernet()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment