#----------------------------------------------------------------------------- # Copyright (c) 2008-2012, David P. D. Moss. All rights reserved. # # Released under the BSD license. See the LICENSE file for details. #----------------------------------------------------------------------------- """ IEEE 64-bit EUI (Extended Unique Indentifier) logic. """ import struct as _struct import re as _re # This is a fake constant that doesn't really exist. Here for completeness. AF_EUI64 = 64 from netaddr.core import AddrFormatError from netaddr.strategy import BYTES_TO_BITS as _BYTES_TO_BITS, \ valid_words as _valid_words, \ int_to_words as _int_to_words, \ words_to_int as _words_to_int, \ valid_bits as _valid_bits, \ bits_to_int as _bits_to_int, \ int_to_bits as _int_to_bits, \ valid_bin as _valid_bin, \ int_to_bin as _int_to_bin, \ bin_to_int as _bin_to_int #: The width (in bits) of this address type. width = 64 #: The individual word size (in bits) of this address type. word_size = 8 #: The format string to be used when converting words to string values. word_fmt = '%.2X' #: The separator character used between each word. word_sep = '-' #: The AF_* constant value of this address type. family = AF_EUI64 #: A friendly string name address type. family_name = 'EUI-64' #: The version of this address type. version = 64 #: The number base to be used when interpreting word values as integers. word_base = 16 #: The maximum integer value that can be represented by this address type. max_int = 2 ** width - 1 #: The number of words in this address type. num_words = width // word_size #: The maximum integer value for an individual word in this address type. max_word = 2 ** word_size - 1 #: Compiled regular expression for detecting value EUI-64 identifiers. RE_EUI64_FORMAT = _re.compile('^' + '-'.join(['([0-9A-F]{1,2})'] * 8) + '$', _re.IGNORECASE) #----------------------------------------------------------------------------- def valid_str(addr): """ :param addr: An IEEE EUI-64 indentifier in string form. :return: ``True`` if EUI-64 indentifier is valid, ``False`` otherwise. """ try: match_result = RE_EUI64_FORMAT.findall(addr) if len(match_result) != 0: return True except TypeError: pass return False #----------------------------------------------------------------------------- def str_to_int(addr): """ :param addr: An IEEE EUI-64 indentifier in string form. :return: An unsigned integer that is equivalent to value represented by EUI-64 string identifier. """ words = [] try: match_result = RE_EUI64_FORMAT.findall(addr) if not match_result: raise TypeError except TypeError: raise AddrFormatError('invalid IEEE EUI-64 identifier: %r!' % addr) words = match_result[0] if len(words) != num_words: raise AddrFormatError('bad word count for EUI-64 identifier: %r!' \ % addr) return int(''.join(['%.2x' % int(w, 16) for w in words]), 16) #----------------------------------------------------------------------------- def int_to_str(int_val, dialect=None): """ :param int_val: An unsigned integer. :param dialect: (optional) a Python class defining formatting options (Please Note - not currently in use). :return: An IEEE EUI-64 identifier that is equivalent to unsigned integer. """ words = int_to_words(int_val) tokens = [word_fmt % i for i in words] addr = word_sep.join(tokens) return addr #----------------------------------------------------------------------------- def int_to_packed(int_val): """ :param int_val: the integer to be packed. :return: a packed string that is equivalent to value represented by an unsigned integer. """ words = int_to_words(int_val) return _struct.pack('>8B', *words) #----------------------------------------------------------------------------- def packed_to_int(packed_int): """ :param packed_int: a packed string containing an unsigned integer. It is assumed that string is packed in network byte order. :return: An unsigned integer equivalent to value of network address represented by packed binary string. """ words = list(_struct.unpack('>8B', packed_int)) int_val = 0 for i, num in enumerate(reversed(words)): word = num word = word << 8 * i int_val = int_val | word return int_val #----------------------------------------------------------------------------- def valid_words(words, dialect=None): return _valid_words(words, word_size, num_words) #----------------------------------------------------------------------------- def int_to_words(int_val, dialect=None): return _int_to_words(int_val, word_size, num_words) #----------------------------------------------------------------------------- def words_to_int(words, dialect=None): return _words_to_int(words, word_size, num_words) #----------------------------------------------------------------------------- def valid_bits(bits, dialect=None): return _valid_bits(bits, width, word_sep) #----------------------------------------------------------------------------- def bits_to_int(bits, dialect=None): return _bits_to_int(bits, width, word_sep) #----------------------------------------------------------------------------- def int_to_bits(int_val, dialect=None): return _int_to_bits(int_val, word_size, num_words, word_sep) #----------------------------------------------------------------------------- def valid_bin(bin_val): return _valid_bin(bin_val, width) #----------------------------------------------------------------------------- def int_to_bin(int_val): return _int_to_bin(int_val, width) #----------------------------------------------------------------------------- def bin_to_int(bin_val): return _bin_to_int(bin_val, width)