aboutsummaryrefslogtreecommitdiffstats
path: root/vicn/resource/ip/prefix_tree.py
diff options
context:
space:
mode:
Diffstat (limited to 'vicn/resource/ip/prefix_tree.py')
-rw-r--r--vicn/resource/ip/prefix_tree.py156
1 files changed, 15 insertions, 141 deletions
diff --git a/vicn/resource/ip/prefix_tree.py b/vicn/resource/ip/prefix_tree.py
index 34af1d14..1fec2d47 100644
--- a/vicn/resource/ip/prefix_tree.py
+++ b/vicn/resource/ip/prefix_tree.py
@@ -16,134 +16,7 @@
# limitations under the License.
#
-from socket import inet_pton, inet_ntop, AF_INET6
-from struct import unpack, pack
-from abc import ABCMeta
-
-class PrefixTreeException(Exception): pass
-class NotEnoughAddresses(PrefixTreeException): pass
-class UnassignablePrefix(PrefixTreeException): pass
-
-class Prefix(metaclass=ABCMeta):
-
- def __init__(self, ip_address, prefix_size=None):
- if not prefix_size:
- ip_address, prefix_size = ip_address.split('/')
- prefix_size = int(prefix_size)
- if isinstance(ip_address, str):
- ip_address = self.aton(ip_address)
- self.ip_address = ip_address
- self.prefix_size = prefix_size
-
- def __contains__(self, obj):
- #it can be an IP as a integer
- if isinstance(obj, int):
- obj = type(self)(obj, self.MAX_PREFIX_SIZE)
- #Or it's an IP string
- if isinstance(obj, str):
- #It's a prefix as 'IP/prefix'
- if '/' in obj:
- split_obj = obj.split('/')
- obj = type(self)(split_obj[0], int(split_obj[1]))
- else:
- obj = type(self)(obj, self.MAX_PREFIX_SIZE)
-
- return self._contains_prefix(obj)
-
- @classmethod
- def mask(cls):
- mask_len = cls.MAX_PREFIX_SIZE//8 #Converts from bits to bytes
- mask = 0
- for step in range(0,mask_len):
- mask = (mask << 8) | 0xff
- return mask
-
- def _contains_prefix(self, prefix):
- assert isinstance(prefix, type(self))
- return (prefix.prefix_size >= self.prefix_size and
- prefix.ip_address >= self.first_prefix_address() and
- prefix.ip_address <= self.last_prefix_address())
-
- #Returns the first address of a prefix
- def first_prefix_address(self):
- return self.ip_address & (self.mask() << (self.MAX_PREFIX_SIZE-self.prefix_size))
-
- def last_prefix_address(self):
- return self.ip_address | (self.mask() >> self.prefix_size)
-
- def limits(self):
- return self.first_prefix_address(), self.last_prefix_address()
-
- def __str__(self):
- return "{}/{}".format(self.ntoa(self.first_prefix_address()), self.prefix_size)
-
- def __eq__(self, other):
- return (self.first_prefix_address() == other.first_prefix_address() and
- self.prefix_size == other.prefix_size)
-
- def __hash__(self):
- return hash(str(self))
-
- def __iter__(self):
- return self.get_iterator()
-
- #Iterates by steps of prefix_size, e.g., on all available /31 in a /24
- def get_iterator(self, prefix_size=None):
- if prefix_size is None:
- prefix_size=self.MAX_PREFIX_SIZE
- assert (prefix_size >= self.prefix_size and prefix_size<=self.MAX_PREFIX_SIZE)
- step = 2**(self.MAX_PREFIX_SIZE - prefix_size)
- for ip in range(self.first_prefix_address(), self.last_prefix_address()+1, step):
- yield type(self)(ip, prefix_size)
-
-class Inet4Prefix(Prefix):
-
- MAX_PREFIX_SIZE = 32
-
- @classmethod
- def aton(cls, address):
- ret = 0
- components = address.split('.')
- for comp in components:
- ret = (ret << 8) + int(comp)
- return ret
-
- @classmethod
- def ntoa(cls, address):
- components = []
- for _ in range(0,4):
- components.insert(0,'{}'.format(address % 256))
- address = address >> 8
- return '.'.join(components)
-
-class Inet6Prefix(Prefix):
-
- MAX_PREFIX_SIZE = 128
-
- @classmethod
- def aton (cls, address):
- prefix, suffix = unpack(">QQ", inet_pton(AF_INET6, address))
- return (prefix << 64) | suffix
-
- @classmethod
- def ntoa (cls, address):
- return inet_ntop(AF_INET6, pack(">QQ", address >> 64, address & ((1 << 64) -1)))
-
- #skip_internet_address: skip a:b::0, as v6 often use default /64 prefixes
- def get_iterator(self, prefix_size=None, skip_internet_address=None):
- if skip_internet_address is None:
- #We skip the internet address if we iterate over Addresses
- if prefix_size is None:
- skip_internet_address = True
- #But not if we iterate over prefixes
- else:
- skip_internet_address = False
- it = super().get_iterator(prefix_size)
- if skip_internet_address:
- next(it)
- return it
-
-###### PREFIX TREE ######
+from netmodel.model.type import Inet4Prefix, Inet6Prefix
class PrefixTree:
@@ -160,21 +33,21 @@ class PrefixTree:
self.full = False
- def find_prefix(self, prefix_size):
+ def find_prefix(self, prefix_len):
ret, lret, rret = [None]*3
- if prefix_size > self.prefix.prefix_size and not self.full:
+ if prefix_len > self.prefix.prefix_len and not self.full:
if self.left is None:
- lret = self.prefix_cls(self.prefix.first_prefix_address(), self.prefix.prefix_size+1)
+ lret = self.prefix_cls(self.prefix.first_prefix_address(), self.prefix.prefix_len+1)
else:
- lret = self.left.find_prefix(prefix_size)
+ lret = self.left.find_prefix(prefix_len)
if self.right is None:
- rret = self.prefix_cls(self.prefix.last_prefix_address(), self.prefix.prefix_size+1)
+ rret = self.prefix_cls(self.prefix.last_prefix_address(), self.prefix.prefix_len+1)
else:
- rret = self.right.find_prefix(prefix_size)
+ rret = self.right.find_prefix(prefix_len)
#Now we look for the longer prefix to assign
- if not lret or (rret and rret.prefix_size > lret.prefix_size):
+ if not lret or (rret and rret.prefix_len > lret.prefix_len):
ret = rret
else:
ret = lret
@@ -183,9 +56,9 @@ class PrefixTree:
def assign_prefix(self, prefix):
assert prefix in self.prefix
- if prefix.prefix_size > self.prefix.prefix_size:
+ if prefix.prefix_len > self.prefix.prefix_len:
#Existing prefix on the left
- lp = self.prefix_cls(self.prefix.first_prefix_address(), self.prefix.prefix_size+1)
+ lp = self.prefix_cls(self.prefix.first_prefix_address(), self.prefix.prefix_len+1)
#It's on the left branch
if prefix in lp:
if not self.left:
@@ -193,7 +66,7 @@ class PrefixTree:
self.left.assign_prefix(prefix)
#It's on the right branch
else:
- rp = self.prefix_cls(self.prefix.last_prefix_address(), self.prefix.prefix_size+1)
+ rp = self.prefix_cls(self.prefix.last_prefix_address(), self.prefix.prefix_len+1)
if not self.right:
self.right = PrefixTree(rp)
self.right.assign_prefix(prefix)
@@ -202,13 +75,14 @@ class PrefixTree:
else:
raise RuntimeError("And you may ask yourself, well, how did I get here?")
- def get_prefix(self, prefix_size):
- ret = self.find_prefix(prefix_size)
+ def get_prefix(self, prefix_len):
+ ret = self.find_prefix(prefix_len)
if not ret:
raise NotEnoughAddresses
#find_prefix returns the size of the largest available prefix in our space
#not necessarily the one we asked for
- ret.prefix_size = prefix_size
+ ret.ip_address = ret.first_prefix_address()
+ ret.prefix_len = prefix_len
self.assign_prefix(ret)
return ret