Helper tools and functions for the Python3.3+ module ipaddress
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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