Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/netaddr/strategy/eui64.py: 46%

122 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:45 +0000

1#----------------------------------------------------------------------------- 

2# Copyright (c) 2008 by David P. D. Moss. All rights reserved. 

3# 

4# Released under the BSD license. See the LICENSE file for details. 

5#----------------------------------------------------------------------------- 

6""" 

7IEEE 64-bit EUI (Extended Unique Indentifier) logic. 

8""" 

9import struct as _struct 

10import re as _re 

11 

12from netaddr.core import AddrFormatError 

13from netaddr.strategy import ( 

14 valid_words as _valid_words, int_to_words as _int_to_words, 

15 words_to_int as _words_to_int, valid_bits as _valid_bits, 

16 bits_to_int as _bits_to_int, int_to_bits as _int_to_bits, 

17 valid_bin as _valid_bin, int_to_bin as _int_to_bin, 

18 bin_to_int as _bin_to_int) 

19 

20 

21# This is a fake constant that doesn't really exist. Here for completeness. 

22AF_EUI64 = 64 

23 

24#: The width (in bits) of this address type. 

25width = 64 

26 

27#: The AF_* constant value of this address type. 

28family = AF_EUI64 

29 

30#: A friendly string name address type. 

31family_name = 'EUI-64' 

32 

33#: The version of this address type. 

34version = 64 

35 

36#: The maximum integer value that can be represented by this address type. 

37max_int = 2 ** width - 1 

38 

39#----------------------------------------------------------------------------- 

40# Dialect classes. 

41#----------------------------------------------------------------------------- 

42 

43class eui64_base(object): 

44 """A standard IEEE EUI-64 dialect class.""" 

45 #: The individual word size (in bits) of this address type. 

46 word_size = 8 

47 

48 #: The number of words in this address type. 

49 num_words = width // word_size 

50 

51 #: The maximum integer value for an individual word in this address type. 

52 max_word = 2 ** word_size - 1 

53 

54 #: The separator character used between each word. 

55 word_sep = '-' 

56 

57 #: The format string to be used when converting words to string values. 

58 word_fmt = '%.2X' 

59 

60 #: The number base to be used when interpreting word values as integers. 

61 word_base = 16 

62 

63 

64class eui64_unix(eui64_base): 

65 """A UNIX-style MAC address dialect class.""" 

66 word_size = 8 

67 num_words = width // word_size 

68 word_sep = ':' 

69 word_fmt = '%x' 

70 word_base = 16 

71 

72 

73class eui64_unix_expanded(eui64_unix): 

74 """A UNIX-style MAC address dialect class with leading zeroes.""" 

75 word_fmt = '%.2x' 

76 

77 

78class eui64_cisco(eui64_base): 

79 """A Cisco 'triple hextet' MAC address dialect class.""" 

80 word_size = 16 

81 num_words = width // word_size 

82 word_sep = '.' 

83 word_fmt = '%.4x' 

84 word_base = 16 

85 

86 

87class eui64_bare(eui64_base): 

88 """A bare (no delimiters) MAC address dialect class.""" 

89 word_size = 64 

90 num_words = width // word_size 

91 word_sep = '' 

92 word_fmt = '%.16X' 

93 word_base = 16 

94 

95 

96#: The default dialect to be used when not specified by the user. 

97 

98DEFAULT_EUI64_DIALECT = eui64_base 

99 

100#----------------------------------------------------------------------------- 

101#: Regular expressions to match all supported MAC address formats. 

102RE_EUI64_FORMATS = ( 

103 # 2 bytes x 8 (UNIX, Windows, EUI-64) 

104 '^' + ':'.join(['([0-9A-F]{1,2})'] * 8) + '$', 

105 '^' + '-'.join(['([0-9A-F]{1,2})'] * 8) + '$', 

106 

107 # 4 bytes x 4 (Cisco like) 

108 '^' + ':'.join(['([0-9A-F]{1,4})'] * 4) + '$', 

109 '^' + '-'.join(['([0-9A-F]{1,4})'] * 4) + '$', 

110 '^' + r'\.'.join(['([0-9A-F]{1,4})'] * 4) + '$', 

111 

112 # 16 bytes (bare, no delimiters) 

113 '^(' + ''.join(['[0-9A-F]'] * 16) + ')$', 

114) 

115# For efficiency, each string regexp converted in place to its compiled 

116# counterpart. 

117RE_EUI64_FORMATS = [_re.compile(_, _re.IGNORECASE) for _ in RE_EUI64_FORMATS] 

118 

119 

120def _get_match_result(address, formats): 

121 for regexp in formats: 

122 match = regexp.findall(address) 

123 if match: 

124 return match[0] 

125 

126 

127def valid_str(addr): 

128 """ 

129 :param addr: An IEEE EUI-64 indentifier in string form. 

130 

131 :return: ``True`` if EUI-64 indentifier is valid, ``False`` otherwise. 

132 """ 

133 try: 

134 if _get_match_result(addr, RE_EUI64_FORMATS): 

135 return True 

136 except TypeError: 

137 pass 

138 

139 return False 

140 

141 

142def str_to_int(addr): 

143 """ 

144 :param addr: An IEEE EUI-64 indentifier in string form. 

145 

146 :return: An unsigned integer that is equivalent to value represented 

147 by EUI-64 string address formatted according to the dialect 

148 """ 

149 words = [] 

150 

151 try: 

152 words = _get_match_result(addr, RE_EUI64_FORMATS) 

153 if not words: 

154 raise TypeError 

155 except TypeError: 

156 raise AddrFormatError('invalid IEEE EUI-64 identifier: %r!' % (addr,)) 

157 

158 if isinstance(words, tuple): 

159 pass 

160 else: 

161 words = (words,) 

162 

163 if len(words) == 8: 

164 # 2 bytes x 8 (UNIX, Windows, EUI-48) 

165 int_val = int(''.join(['%.2x' % int(w, 16) for w in words]), 16) 

166 elif len(words) == 4: 

167 # 4 bytes x 4 (Cisco like) 

168 int_val = int(''.join(['%.4x' % int(w, 16) for w in words]), 16) 

169 elif len(words) == 1: 

170 # 16 bytes (bare, no delimiters) 

171 int_val = int('%016x' % int(words[0], 16), 16) 

172 else: 

173 raise AddrFormatError( 

174 'bad word count for EUI-64 identifier: %r!' % addr) 

175 

176 return int_val 

177 

178 

179def int_to_str(int_val, dialect=None): 

180 """ 

181 :param int_val: An unsigned integer. 

182 

183 :param dialect: (optional) a Python class defining formatting options 

184 

185 :return: An IEEE EUI-64 identifier that is equivalent to unsigned integer. 

186 """ 

187 if dialect is None: 

188 dialect = eui64_base 

189 words = int_to_words(int_val, dialect) 

190 tokens = [dialect.word_fmt % i for i in words] 

191 addr = dialect.word_sep.join(tokens) 

192 return addr 

193 

194 

195def int_to_packed(int_val): 

196 """ 

197 :param int_val: the integer to be packed. 

198 

199 :return: a packed string that is equivalent to value represented by an 

200 unsigned integer. 

201 """ 

202 words = int_to_words(int_val) 

203 return _struct.pack('>8B', *words) 

204 

205 

206def packed_to_int(packed_int): 

207 """ 

208 :param packed_int: a packed string containing an unsigned integer. 

209 It is assumed that string is packed in network byte order. 

210 

211 :return: An unsigned integer equivalent to value of network address 

212 represented by packed binary string. 

213 """ 

214 words = list(_struct.unpack('>8B', packed_int)) 

215 

216 int_val = 0 

217 for i, num in enumerate(reversed(words)): 

218 word = num 

219 word = word << 8 * i 

220 int_val = int_val | word 

221 

222 return int_val 

223 

224 

225def valid_words(words, dialect=None): 

226 if dialect is None: 

227 dialect = DEFAULT_EUI64_DIALECT 

228 return _valid_words(words, dialect.word_size, dialect.num_words) 

229 

230 

231def int_to_words(int_val, dialect=None): 

232 if dialect is None: 

233 dialect = DEFAULT_EUI64_DIALECT 

234 return _int_to_words(int_val, dialect.word_size, dialect.num_words) 

235 

236 

237def words_to_int(words, dialect=None): 

238 if dialect is None: 

239 dialect = DEFAULT_EUI64_DIALECT 

240 return _words_to_int(words, dialect.word_size, dialect.num_words) 

241 

242 

243def valid_bits(bits, dialect=None): 

244 if dialect is None: 

245 dialect = DEFAULT_EUI64_DIALECT 

246 return _valid_bits(bits, width, dialect.word_sep) 

247 

248 

249def bits_to_int(bits, dialect=None): 

250 if dialect is None: 

251 dialect = DEFAULT_EUI64_DIALECT 

252 return _bits_to_int(bits, width, dialect.word_sep) 

253 

254 

255def int_to_bits(int_val, dialect=None): 

256 if dialect is None: 

257 dialect = DEFAULT_EUI64_DIALECT 

258 return _int_to_bits( 

259 int_val, dialect.word_size, dialect.num_words, dialect.word_sep) 

260 

261 

262def valid_bin(bin_val, dialect=None): 

263 if dialect is None: 

264 dialect = DEFAULT_EUI64_DIALECT 

265 return _valid_bin(bin_val, width) 

266 

267 

268def int_to_bin(int_val): 

269 return _int_to_bin(int_val, width) 

270 

271 

272def bin_to_int(bin_val): 

273 return _bin_to_int(bin_val, width)