Skip to content
This repository was archived by the owner on Apr 22, 2024. It is now read-only.

Commit e6fd3f7

Browse files
authored
Add IPv6 address class (#607)
1 parent feedcba commit e6fd3f7

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

pyof/foundation/basic_types.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,15 @@ class UBInt64(GenericType):
115115
_fmt = "!Q"
116116

117117

118+
class UBInt128(GenericType):
119+
"""Format character for an Unsigned Long Long.
120+
121+
Class for an 128-bit (16-byte) Unsigned Integer.
122+
"""
123+
124+
_fmt = "!8H"
125+
126+
118127
class DPID(GenericType):
119128
"""DataPath ID. Identifies a switch."""
120129

@@ -343,6 +352,114 @@ def __deepcopy__(self, memo):
343352
return IPAddress(address=self._value, netmask=self.netmask)
344353

345354

355+
class IPv6Address(GenericType):
356+
"""Defines a IPv6 address."""
357+
358+
netmask = UBInt128()
359+
360+
def __init__(self, address="0000:0000:0000:0000:0000:0000:0000:0000/128",
361+
netmask=None):
362+
"""Create an IPv6Address with the parameters below.
363+
364+
Args:
365+
address (str): IP Address using IPv6.
366+
Defaults to '0000:0000:0000:0000:0000:0000:0000:0000/128'
367+
"""
368+
if '/' in address:
369+
address, netmask = address.split('/')
370+
else:
371+
netmask = 128 if netmask is None else netmask
372+
373+
if address == '::':
374+
address = '0:0:0:0:0:0:0:0'
375+
elif '::' in address:
376+
temp = address.split(':')
377+
index = temp.index('')
378+
temp = [x for x in temp if x != '']
379+
address = temp[:index] + ['0'] * (8 - len(temp)) + temp[index:]
380+
address = ':'.join(address)
381+
382+
super().__init__(address)
383+
self.netmask = int(netmask)
384+
385+
def pack(self, value=None):
386+
"""Pack the value as a binary representation.
387+
388+
If the value is None the self._value will be used to pack.
389+
390+
Args:
391+
value (str): IP Address with IPv6 format.
392+
393+
Returns:
394+
bytes: The binary representation.
395+
396+
Raises:
397+
struct.error: If the value does not fit the binary format.
398+
399+
"""
400+
if isinstance(value, type(self)):
401+
return value.pack()
402+
403+
if value is None:
404+
value = self._value
405+
406+
if value.find('/') >= 0:
407+
value = value.split('/')[0]
408+
409+
try:
410+
value = value.split(':')
411+
return struct.pack('!8H', *[int(x, 16) for x in value])
412+
except struct.error as err:
413+
msg = "IPv6Address error. "
414+
msg += "Class: {}, struct error: {} ".format(type(value).__name__,
415+
err)
416+
raise exceptions.PackException(msg)
417+
418+
def unpack(self, buff, offset=0):
419+
"""Unpack a binary message into this object's attributes.
420+
421+
Unpack the binary value *buff* and update this object attributes based
422+
on the results.
423+
424+
Args:
425+
buff (bytes): Binary data package to be unpacked.
426+
offset (int): Where to begin unpacking.
427+
428+
Raises:
429+
Exception: If there is a struct unpacking error.
430+
431+
"""
432+
def _int2hex(number):
433+
return "{0:0{1}x}".format(number, 4)
434+
435+
try:
436+
unpacked_data = struct.unpack('!8H', buff[offset:offset+16])
437+
except struct.error as exception:
438+
raise exceptions.UnpackException('%s; %s: %s' % (exception,
439+
offset, buff))
440+
441+
transformed_data = ':'.join([_int2hex(x) for x in unpacked_data])
442+
self._value = transformed_data
443+
444+
def get_size(self, value=None):
445+
"""Return the IPv6 address size in bytes.
446+
447+
Args:
448+
value: In structs, the user can assign other value instead of
449+
this class' instance. Here, in such cases, ``self`` is a class
450+
attribute of the struct.
451+
452+
Returns:
453+
int: The address size in bytes.
454+
455+
"""
456+
return 16
457+
458+
def __deepcopy__(self, memo):
459+
"""Improve deepcopy speed."""
460+
return IPv6Address(address=self._value, netmask=self.netmask)
461+
462+
346463
class HWAddress(GenericType):
347464
"""Defines a hardware address."""
348465

0 commit comments

Comments
 (0)