Skip to content

Commit 35c0301

Browse files
keboliulguohan
authored andcommitted
[sonic_platform_base] Add sonic_sfp and sonic_eeprom to sonic_platform_base (#27)
* add sonic_sfp and sonic_eeprom to sonic_platform_base * make original sonic_sfp and sonic_eeprom as symbol link to the new subfolder under sonic_platform_base to avoid duplicate files * Revert "make original sonic_sfp and sonic_eeprom as symbol link to the new subfolder under sonic_platform_base to avoid duplicate files" This reverts commit 3e741dd.
1 parent 77226a5 commit 35c0301

13 files changed

+5668
-0
lines changed

setup.py

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
'sonic_eeprom',
1515
'sonic_led',
1616
'sonic_platform_base',
17+
'sonic_platform_base.sonic_eeprom',
18+
'sonic_platform_base.sonic_sfp',
1719
'sonic_psu',
1820
'sonic_sfp',
1921
],

sonic_platform_base/sonic_eeprom/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
#! /usr/bin/python
2+
# Copyright 2012 Cumulus Networks LLC, all rights reserved
3+
4+
#############################################################################
5+
# Base eeprom class containing the main logic for reading, writing, and
6+
# setting the eeprom. The format definition is a list of tuples of:
7+
# ('data name', 'data type', 'size in bytes')
8+
# data type is one of 's', 'C', and 'x' (string, char, and ignore)
9+
# 'burn' as a data name indicates the corresponding number of bytes are to
10+
# be ignored
11+
12+
from __future__ import print_function
13+
14+
try:
15+
import exceptions # Python 2
16+
except ImportError:
17+
import builtins as exceptions # Python 3
18+
try:
19+
import binascii
20+
import optparse
21+
import os
22+
import io
23+
import sys
24+
import struct
25+
import subprocess
26+
import fcntl
27+
except ImportError as e:
28+
raise ImportError (str(e) + "- required module not found")
29+
30+
31+
class EepromDecoder(object):
32+
def __init__(self, path, format, start, status, readonly):
33+
self.p = path
34+
self.f = format
35+
self.s = start
36+
self.u = status
37+
self.r = readonly
38+
self.cache_name = None
39+
self.cache_update_needed = False
40+
self.lock_file = None
41+
42+
def check_status(self):
43+
if self.u != '':
44+
F = open(self.u, "r")
45+
d = F.readline().rstrip()
46+
F.close()
47+
return d
48+
else:
49+
return 'ok'
50+
51+
def set_cache_name(self, name):
52+
# before accessing the eeprom we acquire an exclusive lock on the eeprom file.
53+
# this will prevent a race condition where multiple instances of this app
54+
# could try to update the cache at the same time
55+
self.cache_name = name
56+
self.lock_file = open(self.p, 'r')
57+
fcntl.flock(self.lock_file, fcntl.LOCK_EX)
58+
59+
def is_read_only(self):
60+
return self.r
61+
62+
def decoder(self, s, t):
63+
return t
64+
65+
def encoder(self, I, v):
66+
return v
67+
68+
def checksum_field_size(self):
69+
return 4 # default
70+
71+
def is_checksum_field(self, I):
72+
return I[0] == 'crc' # default
73+
74+
def checksum_type(self):
75+
return 'crc32'
76+
77+
def encode_checksum(self, crc):
78+
if self.checksum_field_size() == 4:
79+
return struct.pack('>I', crc)
80+
elif self.checksum_field_size() == 1:
81+
return struct.pack('>B', crc)
82+
print('checksum type not yet supported')
83+
exit(1)
84+
85+
def compute_2s_complement(self, e, size):
86+
crc = 0
87+
loc = 0
88+
end = len(e)
89+
while loc != end:
90+
crc += int('0x' + binascii.b2a_hex(e[loc:loc+size]), 0)
91+
loc += size
92+
T = 1 << (size * 8)
93+
return (T - crc) & (T - 1)
94+
95+
def compute_dell_crc(self, message):
96+
poly = 0x8005
97+
reg = 0x0000
98+
message += '\x00\x00'
99+
for byte in message:
100+
mask = 0x80
101+
while (mask > 0):
102+
reg<<=1
103+
if ord(byte) & mask:
104+
reg += 1
105+
mask>>=1
106+
if reg > 0xffff:
107+
reg &= 0xffff
108+
reg ^= poly
109+
return reg
110+
111+
def calculate_checksum(self, e):
112+
if self.checksum_type() == 'crc32':
113+
return binascii.crc32(e) & 0xffffffff
114+
115+
if self.checksum_type() == '2s-complement':
116+
size = self.checksum_field_size()
117+
return self.compute_2s_complement(e, size)
118+
119+
if self.checksum_type() == 'dell-crc':
120+
return self.compute_dell_crc(e)
121+
print('checksum type not yet supported')
122+
exit(1)
123+
124+
def is_checksum_valid(self, e):
125+
offset = 0 - self.checksum_field_size()
126+
crc = self.calculate_checksum(e[:offset])
127+
128+
loc = 0
129+
for I in self.f:
130+
end = loc + I[2]
131+
t = e[loc:end]
132+
loc = end
133+
if self.is_checksum_field(I):
134+
i = self.decoder(I[0], t)
135+
if int(i, 0) == crc:
136+
return (True, crc)
137+
else:
138+
return (False, crc)
139+
else:
140+
continue
141+
return (False, crc)
142+
143+
def decode_eeprom(self, e):
144+
loc = 0
145+
for I in self.f:
146+
end = loc + I[2]
147+
t = e[loc:end]
148+
loc = end
149+
if I[0] == 'burn':
150+
continue
151+
elif I[1] == 's':
152+
i = t
153+
else:
154+
i = self.decoder(I[0], t)
155+
print("%-20s: %s" %(I[0], i))
156+
157+
def set_eeprom(self, e, cmd_args):
158+
line = ''
159+
loc = 0
160+
ndict = {}
161+
fields = list(I[0] for I in list(self.f))
162+
if len(cmd_args):
163+
for arg in cmd_args[0].split(','):
164+
k, v = arg.split('=')
165+
k = k.strip()
166+
v = v.strip()
167+
if k not in fields:
168+
print("Error: invalid field '%s'" %(k))
169+
exit(1)
170+
ndict[k] = v
171+
172+
for I in self.f:
173+
# print the original value
174+
end = loc + I[2]
175+
sl = e[loc:end]
176+
loc = end
177+
if I[0] == 'burn':
178+
#line += sl
179+
# fill with zeros
180+
line = line.ljust(len(line) + I[2], '\x00')
181+
continue
182+
elif I[1] == 's':
183+
i = sl
184+
else:
185+
i = self.decoder(I[0], sl)
186+
187+
if len(cmd_args) == 0:
188+
if self.is_checksum_field(I):
189+
print("%-20s: %s " %(I[0], i))
190+
continue
191+
192+
# prompt for new value
193+
v = raw_input("%-20s: [%s] " %(I[0], i))
194+
if v == '':
195+
v = i
196+
else:
197+
if I[0] not in ndict.keys():
198+
v = i
199+
else:
200+
v = ndict[I[0]]
201+
202+
line += self.encoder(I, v)
203+
204+
# compute and append crc at the end
205+
crc = self.encode_checksum(self.calculate_checksum(line))
206+
207+
line += crc
208+
209+
return line
210+
211+
def open_eeprom(self):
212+
'''
213+
Open the EEPROM device file.
214+
If a cache file exists, use that instead of the EEPROM.
215+
'''
216+
using_eeprom = True
217+
eeprom_file = self.p
218+
try:
219+
if os.path.isfile(self.cache_name):
220+
eeprom_file = self.cache_name
221+
using_eeprom = False
222+
except:
223+
pass
224+
self.cache_update_needed = using_eeprom
225+
return io.open(eeprom_file, "rb")
226+
227+
def read_eeprom(self):
228+
sizeof_info = 0
229+
for I in self.f:
230+
sizeof_info += I[2]
231+
o = self.read_eeprom_bytes(sizeof_info)
232+
return o
233+
234+
def read_eeprom_bytes(self, byteCount, offset=0):
235+
F = self.open_eeprom()
236+
F.seek(self.s + offset)
237+
o = F.read(byteCount)
238+
239+
# If we read from the cache file and the byte count isn't what we
240+
# expect, the file may be corrupt. Delete it and try again, this
241+
# time reading from the actual EEPROM.
242+
if len(o) != byteCount and not self.cache_update_needed:
243+
os.remove(self.cache_name)
244+
self.cache_update_needed = True
245+
F.close()
246+
F = self.open_eeprom()
247+
F.seek(self.s + offset)
248+
o = F.read(byteCount)
249+
250+
if len(o) != byteCount:
251+
raise RuntimeError("Expected to read %d bytes from %s, "
252+
% (byteCount, self.p) +
253+
"but only read %d" % (len(o)))
254+
F.close()
255+
return o
256+
257+
def read_eeprom_db(self):
258+
return 0
259+
260+
def write_eeprom(self, e):
261+
F = open(self.p, "wb")
262+
F.seek(self.s)
263+
F.write(e)
264+
F.close()
265+
self.write_cache(e)
266+
267+
def write_cache(self, e):
268+
if self.cache_name:
269+
F = open(self.cache_name, "wb")
270+
F.seek(self.s)
271+
F.write(e)
272+
F.close()
273+
274+
def update_cache(self, e):
275+
if self.cache_update_needed:
276+
self.write_cache(e)
277+
fcntl.flock(self.lock_file, fcntl.LOCK_UN)
278+
279+
def update_eeprom_db(self, e):
280+
return 0
281+
282+
def diff_mac(self, mac1, mac2):
283+
if mac1 == '' or mac2 == '':
284+
return 0
285+
mac1_octets = []
286+
mac1_octets = mac1.split(':')
287+
mac1val = int(mac1_octets[5], 16) | int(mac1_octets[4], 16) << 8 | int(mac1_octets[3], 16) << 16
288+
mac2_octets = []
289+
mac2_octets = mac2.split(':')
290+
mac2val = int(mac2_octets[5], 16) | int(mac2_octets[4], 16) << 8 | int(mac2_octets[3], 16) << 16
291+
# check oui matches
292+
if (mac1_octets[0] != mac2_octets[0]
293+
or mac1_octets[1] != mac2_octets[1]
294+
or mac1_octets[2] != mac2_octets[2]) :
295+
return 0
296+
297+
if mac2val < mac1val:
298+
return 0
299+
300+
return (mac2val - mac1val)
301+
302+
def increment_mac(self, mac):
303+
if mac != "":
304+
mac_octets = []
305+
mac_octets = mac.split(':')
306+
ret_mac = int(mac_octets[5], 16) | int(mac_octets[4], 16) << 8 | int(mac_octets[3], 16) << 16
307+
ret_mac = ret_mac + 1
308+
309+
if (ret_mac & 0xff000000):
310+
print('Error: increment carries into OUI')
311+
return ''
312+
313+
mac_octets[5] = hex(ret_mac & 0xff)[2:].zfill(2)
314+
mac_octets[4] = hex((ret_mac >> 8) & 0xff)[2:].zfill(2)
315+
mac_octets[3] = hex((ret_mac >> 16) & 0xff)[2:].zfill(2)
316+
317+
return ':'.join(mac_octets).upper()
318+
319+
return ''
320+
321+
@classmethod
322+
def find_field(cls, e, name):
323+
if not hasattr(cls, 'brd_fmt'):
324+
raise RuntimeError("Class %s does not have brb_fmt" % cls)
325+
if not e:
326+
raise RuntimeError("EEPROM can not be empty")
327+
brd_fmt = cls.brd_fmt
328+
loc = 0
329+
for f in brd_fmt:
330+
end = loc + f[2]
331+
t = e[loc:end]
332+
loc = end
333+
if f[0] == name:
334+
return t
335+
336+
def base_mac_addr(self, e):
337+
'''
338+
Returns the base MAC address found in the EEPROM.
339+
340+
Sub-classes must override this method as reading the EEPROM
341+
and finding the base MAC address entails platform specific
342+
details.
343+
344+
See also mgmtaddrstr() and switchaddrstr().
345+
'''
346+
print("ERROR: Platform did not implement base_mac_addr()")
347+
raise NotImplementedError
348+
349+
def mgmtaddrstr(self, e):
350+
'''
351+
Returns the base MAC address to use for the Ethernet
352+
management interface(s) on the CPU complex.
353+
354+
By default this is the same as the base MAC address listed in
355+
the EEPROM.
356+
357+
See also switchaddrstr().
358+
'''
359+
return self.base_mac_addr(e)
360+
361+
def switchaddrstr(self, e):
362+
'''
363+
Returns the base MAC address to use for the switch ASIC
364+
interfaces.
365+
366+
By default this is *next* address after the base MAC address
367+
listed in the EEPROM.
368+
369+
See also mgmtaddrstr().
370+
'''
371+
return self.increment_mac(self.base_mac_addr(e))
372+
373+
def switchaddrrange(self, e):
374+
# this function is in the base class only to catch errors
375+
# the platform specific import should have an override of this method
376+
# to provide the allocated mac range from syseeprom or flash sector or
377+
# wherever that platform stores this info
378+
print("Platform did not indicate allocated mac address range")
379+
raise NotImplementedError
380+
381+
def serial_number_str(self, e):
382+
raise NotImplementedError("Platform did not indicate serial number")

0 commit comments

Comments
 (0)