Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[201807][platform_barefoot]Wedge100bf_32x, add device util, eeprom and psuutil. #2359

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build_debian.sh
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in
screen \
hping3 \
python-scapy \
python-ptyprocess \
python-pexpect \
tcptraceroute \
mtr-tiny

Expand Down
90 changes: 90 additions & 0 deletions device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/eeprom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env python

try:
import exceptions
import binascii
import time
import optparse
import warnings
import os
import sys
from sonic_eeprom import eeprom_base
from sonic_eeprom import eeprom_tlvinfo
import subprocess
import re
import pexpect
import cPickle as pickle

except ImportError, e:
raise ImportError (str(e) + "- required module not found")

class board(eeprom_tlvinfo.TlvInfoDecoder):
_TLV_INFO_MAX_LEN = 256
bf_commands = ["ucli", "..", "..", "bf_pltfm", "cp2112"]
BFCMD="do_bfshell.py -c ucli \
-c .. -c .. -c bf_pltfm -c cp2112 -c"
cache = ""
DATA = {'last_poll':0, 'raw': ""}
CHECK_INTV = 5 #in seconds

def __init__(self, name, path, cpld_root, ro):
self.cache = "/tmp/.%s.cache" % os.path.basename(sys.argv[0])
super(board, self).__init__("", 0, '', True)

def eeprom_up2date(self):
if os.path.exists(self.cache):
self.DATA = pickle.load(open(self.cache, "rb"))
last_poll = self.DATA['last_poll']

#check interval
now = time.time()
if now < (last_poll + self.CHECK_INTV):
return True
else:
return False

def interact_with_bfshell(self, cmds, timeout=20):
bfshell_path = 'docker exec -it syncd /opt/bfn/install/bin/bfshell'
bfshell_cmd = [ bfshell_path ]

prompt_list = ['bfshell> $', 'bf-sde\.*.*> $', 'pd-switch:\d+> $', pexpect.EOF]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you you get eeprom/psu data from bfshell? Isn't your platform driver suppose create sysfs entries to expose those data?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not with bfshell.
These platforms, 32x and 65x, employ a usb-to-i2c ASIC, called cp2112, to access qsfps' eeprom.
For BF's SDE accesses peripherals itself with libusb, it will detach driver of cp2112.
That's why I can only get these data through bfshell.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. can you get this to master branch first? we need to ensure we have this in the master branch, then we can cherry-pick it back to a release branch.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get it.
I will make another PR for this change to master branch. But it needs quite a while for I'm working on other platforms.

child = pexpect.spawn(' '.join(bfshell_cmd))
child.expect(prompt_list)
lines = []
for cmd in cmds:
child.sendline(cmd)
child.expect(prompt_list)
for line in child.before.splitlines():
if line.strip() and line != cmd:
lines.append(line)

return lines


def read_eeprom_bytes(self, byteCount, offset=0):
if self.eeprom_up2date() == True:
str = self.DATA['raw']
else:
subcmd = "write 1 0xe8 1 0x40; write 1 0xa0 2 0 0; read 1 0xa0 ff"
cmd = self.BFCMD + "\'" + subcmd + "\'"
cmds = self.bf_commands
cmds.append(subcmd)
#lines = os.popen(cmd).readlines()
lines = self.interact_with_bfshell(cmds)

last = lines[-1].strip()
raw = last.split()
hex = []
for byte in raw:
hex.append(chr(int(byte,16)))
str = ''.join(hex)
if len(str) < offset+byteCount:
raise RuntimeError("expected to read %d bytes from %s, " \
%(byteCount, "bfshell") +
"but only read %d" %(len(str)))
self.DATA['raw'] = str
self.DATA['last_poll'] = time.time()
pickle.dump(self.DATA, open(self.cache, "wb"))

return str[offset:offset+byteCount]

115 changes: 115 additions & 0 deletions device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/psuutil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env python

#############################################################################
# Accton
#
# Module contains an implementation of SONiC PSU Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
import sys
import commands
import time
import os.path
import re
import pexpect
import cPickle as pickle

try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError (str(e) + "- required module not found")

class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""

BF_INTV = 10 # in seconds
cache = ""
DATA = {1: {'last_poll':0,
'status':False,
'presence':False},
2: {'status':False,
'presence':False}
}
bf_commands = ["ucli", "..", "..", "bf_pltfm", "chss_mgmt"]

def __init__(self):
PsuBase.__init__(self)
self.cache = "/tmp/.%s.cache" % os.path.basename(sys.argv[0])

def get_num_psus(self):
return len(self.DATA)

def interact_with_bfshell(self, cmds, timeout=20):
bfshell_path = 'docker exec -it syncd /opt/bfn/install/bin/bfshell'
bfshell_cmd = [ bfshell_path ]

prompt_list = ['bfshell> $', 'bf-sde\.*.*> $', 'pd-switch:\d+> $', pexpect.EOF]
child = pexpect.spawn(' '.join(bfshell_cmd))
child.expect(prompt_list)
lines = []
for cmd in cmds:
child.sendline(cmd)
child.expect(prompt_list)
for line in child.before.splitlines():
if line.strip() and line != cmd:
lines.append(line)

return lines

def bf_poll_psu(self):
if os.path.exists(self.cache):
self.DATA = pickle.load(open(self.cache, "rb"))
last_poll = self.DATA[1]['last_poll']
now = time.time()
if now < (last_poll + self.BF_INTV):
return True

for d in self.DATA:
index = d
subcmd = "ps_show %d" % index
cmds = list(self.bf_commands)
cmds.append(subcmd)
lines = self.interact_with_bfshell(cmds)
log = "".join(lines)
mt = re.search("error:", log, re.I)
if mt != None:
self.DATA[d]['presence'] = False
return False


buf = log.replace("\r", "")
buf = buf.replace("\n", "")
mt = re.search("Presence\s+true", buf)
if mt == None:
self.DATA[d]['presence'] = False
else:
self.DATA[d]['presence'] = True
pw = re.sub(r"(.*Power output\s+)(\d+)(.*)", r"\2", buf)
pw = int(pw)
if pw <= 100: #for output power < 100mW, it'd off
self.DATA[d]['status'] = False
else:
self.DATA[d]['status'] = True


self.DATA[1]['last_poll'] = time.time()
pickle.dump(self.DATA, open(self.cache, "wb"))
return True

def get_psu_status(self, index):
if index is None:
return False

self.bf_poll_psu()
d = self.DATA[index]
return d['status']

def get_psu_presence(self, index):
if index is None:
return False

self.bf_poll_psu()
d = self.DATA[index]
return d['presence']