From 1547f487a746d46d78bc4ce90114c200e33aa218 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 12 Sep 2017 11:28:10 -0700 Subject: [PATCH 01/24] Initial checkin - wrapper for some AIM classes (probably the wrong package) - wrap a subset of libonlp - wrap onlp.h, sys.h, oids.h - sample unit tests - sample onlpdump.py --- packages/base/any/onlp/APKG.yml | 5 + .../src/onlp/module/python/onlp/__init__.py | 4 + .../onlp/module/python/onlp/onlp/__init__.py | 261 ++++++++++++++++++ .../module/python/onlp/test/OnlpApiTest.py | 236 ++++++++++++++++ .../onlp/module/python/onlp/test/__init__.py | 4 + packages/base/any/onlp/src/onlpdump.py | 36 +++ .../module/python/onlp/onlplib/__init__.py | 87 ++++++ 7 files changed, 633 insertions(+) create mode 100644 packages/base/any/onlp/src/onlp/module/python/onlp/__init__.py create mode 100644 packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py create mode 100644 packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py create mode 100644 packages/base/any/onlp/src/onlp/module/python/onlp/test/__init__.py create mode 100755 packages/base/any/onlp/src/onlpdump.py create mode 100644 packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib/__init__.py diff --git a/packages/base/any/onlp/APKG.yml b/packages/base/any/onlp/APKG.yml index a245d8ec..2144913b 100644 --- a/packages/base/any/onlp/APKG.yml +++ b/packages/base/any/onlp/APKG.yml @@ -26,6 +26,11 @@ packages: builds/onlp-platform/$BUILD_DIR/${TOOLCHAIN}/bin/libonlp-platform.so : $libdir/ builds/onlp-platform-defaults/$BUILD_DIR/${TOOLCHAIN}/bin/libonlp-platform-defaults.so : $libdir/ builds/onlpd/$BUILD_DIR/${TOOLCHAIN}/bin/onlpd : $bindir/ + ${ONL}/packages/base/any/onlp/src/onlpdump.py: $bindir/ + ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/*.py: ${PY_INSTALL}/onlp/ + ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/*.py: ${PY_INSTALL}/onlp/onlp/ + ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/test/*.py: ${PY_INSTALL}/onlp/test/ + ${ONL}/packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib/*.py: ${PY_INSTALL}/onlp/onlplib/ init: $ONL/packages/base/any/onlp/src/onlpd.init diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/__init__.py new file mode 100644 index 00000000..cd682130 --- /dev/null +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/__init__.py @@ -0,0 +1,4 @@ +"""__init__.py + +Module init for onlp. +""" diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py new file mode 100644 index 00000000..a0ba3412 --- /dev/null +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -0,0 +1,261 @@ +"""__init__.py + +Module init for onlp.onlp +""" + +import ctypes + +libonlp = ctypes.cdll.LoadLibrary("libonlp.so") + +import ctypes.util +libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c")) + +import onlp.onlplib + +# AIM/aim_memory.h + +class aim_void_p(ctypes.c_void_p): + """Generic data allocated by AIM.""" + def __del__(self): + libonlp.aim_free(self) + +class aim_char_p(aim_void_p): + """AIM data that is a printable string.""" + + def __init__(self, stringOrAddress): + + if stringOrAddress is None: + aim_void_p.__init__(self, stringOrAddress) + return + + if isinstance(stringOrAddress, aim_void_p): + aim_void_p.__init__(self, stringOrAddress) + return + + if isinstance(stringOrAddress, basestring): + cs = ctypes.c_char_p(stringOrAddress) + ptr = libonlp.aim_malloc(len(stringOrAddress)+1) + libc.strcpy(ptr, ctypes.addressof(cs)) + aim_void_p.__init__(self, ptr) + return + + if type(stringOrAddress) == int: + aim_void_p.__init__(self, stringOrAddress) + return + + raise ValueError("invalid initializer for aim_char_p: %s" + % repr(stringOrAddress)) + + def string_at(self): + if self.value: + return ctypes.string_at(self.value) + else: + return None + + def __eq__(self, other): + return (isinstance(other, aim_char_p) + and (self.string_at()==other.string_at())) + + def __neq__(self, other): + return not self == other + + def __hash__(self): + return hash(self.string_at()) + +def aim_memory_init_prototypes(): + + libonlp.aim_malloc.restype = aim_void_p + libonlp.aim_malloc.argtypes = (ctypes.c_size_t,) + + libonlp.aim_free.restype = None + libonlp.aim_free.argtypes = (aim_void_p,) + +# AIM/aim_object.h + +aim_object_dtor = ctypes.CFUNCTYPE(None, ctypes.c_void_p) + +class aim_object(ctypes.Structure): + _fields_ = [("_id", ctypes.c_char_p,), + ("subtype", ctypes.c_int,), + ("cookie", ctypes.c_void_p,), + ("destructor", aim_object_dtor,),] + +# AIM/aim_pvs.h +# AIM/aim_pvs_*.h + +aim_vprintf_f = ctypes.CFUNCTYPE(ctypes.c_int) + +class aim_pvs(ctypes.Structure): + _fields_ = [("object", aim_object,), + ("description", ctypes.c_char_p,), + ("vprintf", aim_vprintf_f,), + ("enabled", ctypes.c_int,), + ("counter", ctypes.c_uint,), + ("isatty", aim_vprintf_f,),] + +def aim_pvs_init_prototypes(): + + libonlp.aim_pvs_buffer_create.restype = ctypes.POINTER(aim_pvs) + + libonlp.aim_pvs_destroy.restype = None + libonlp.aim_pvs_destroy.argtypes = (ctypes.POINTER(aim_pvs),) + + libonlp.aim_pvs_buffer_size.restype = ctypes.c_int + libonlp.aim_pvs_buffer_size.argtypes = (ctypes.POINTER(aim_pvs),) + + libonlp.aim_pvs_buffer_get.restype = aim_char_p + libonlp.aim_pvs_buffer_get.argtypes = (ctypes.POINTER(aim_pvs),) + + libonlp.aim_pvs_buffer_reset.restype = None + libonlp.aim_pvs_buffer_reset.argtypes = (ctypes.POINTER(aim_pvs),) + +# onlp/oids.h + +onlp_oid = ctypes.c_uint + +ONLP_OID_DESC_SIZE = 128 +ONLP_OID_TABLE_SIZE = 32 + +ONLP_OID_DUMP_F_RECURSE = 0x1 +ONLP_OID_DUMP_F_EVEN_IF_ABSENT = 0x2 + +ONLP_OID_SHOW_F_RECURSE = 0x1 +ONLP_OID_SHOW_F_EXTENDED = 0x2 +ONLP_OID_SHOW_F_YAML = 0x4 + +class OidTableIterator(object): + + def __init__(self, hdr): + self.hdr = hdr + self.idx = 0 + + def __iter__(self): + return self + + def next(self): + if self.idx >= ONLP_OID_TABLE_SIZE: + raise StopIteration + oid = self.hdr.coids[self.idx] + self.idx += 1 + if oid == 0: + raise StopIteration + oidHdr = onlp_oid_hdr() + libonlp.onlp_oid_hdr_get(oid, ctypes.byref(oidHdr)) + return oidHdr + +ONLP_OID_TYPE_SYS = 1 +ONLP_OID_TYPE_THERMAL = 2 +ONLP_OID_TYPE_FAN = 3 +ONLP_OID_TYPE_PSU = 4 +ONLP_OID_TYPE_LED = 5 +ONLP_OID_TYPE_MODULE = 6 +ONLP_OID_TYPE_RTC = 7 +# XXX roth waiting for enum generator + +class onlp_oid_hdr(ctypes.Structure): + + _fields_ = [("_id", onlp_oid,), + ("description", ctypes.c_char * ONLP_OID_DESC_SIZE,), + ("poid", onlp_oid,), + ("coids", onlp_oid * ONLP_OID_TABLE_SIZE,),] + + def getType(self): + return self._id >> 24 + + def isSystem(self): + return self.getType() == ONLP_OID_TYPE_SYS + def isThermal(self): + return self.getType() == ONLP_OID_TYPE_THERMAL + def isFan(self): + return self.getType() == ONLP_OID_TYPE_FAN + def isPsu(self): + return self.getType() == ONLP_OID_TYPE_PSU + def isLed(self): + return self.getType() == ONLP_OID_TYPE_LED + def isModule(self): + return self.getType() == ONLP_OID_TYPE_MODULE + def isRtc(self): + return self.getType() == ONLP_OID_TYPE_RTC + + def children(self): + return OidTableIterator(self) + +onlp_oid_iterate_f = ctypes.CFUNCTYPE(ctypes.c_int, onlp_oid, ctypes.c_void_p) + +def onlp_oid_init_prototypes(): + + #onlp_oid_dump + #onlp_oid_table_dump + #onlp_oid_show + #onlp_oid_table_show + + libonlp.onlp_oid_iterate.restype = ctypes.c_int + libonlp.onlp_oid_iterate.argtypes = (onlp_oid, ctypes.c_int, + onlp_oid_iterate_f, ctypes.c_void_p,) + # XXX enum + + libonlp.onlp_oid_hdr_get.restype = ctypes.c_int + libonlp.onlp_oid_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr,)) + # XXX enum + +# onlp/sys.h + +class onlp_sys_info(ctypes.Structure): + + initialized = False + + _fields_ = [("hdr", onlp_oid_hdr,), + ("onie_info", onlp.onlplib.onlp_onie_info,), + ("platform_info", onlp.onlplib.onlp_platform_info,),] + + def __del__(self): + if self.initialized: + libonlp.onlp_sys_info_free(ctypes.byref(self)) + +def onlp_sys_init_prototypes(): + + libonlp.onlp_sys_init.restype = ctypes.c_int + + libonlp.onlp_sys_info_get.restype = ctypes.c_int + libonlp.onlp_sys_info_get.argtypes = (ctypes.POINTER(onlp_sys_info),) + + libonlp.onlp_sys_info_free.restype = None + libonlp.onlp_sys_info_get.argtypes = (ctypes.POINTER(onlp_sys_info),) + + libonlp.onlp_sys_hdr_get.restype = ctypes.c_int + libonlp.onlp_sys_hdr_get.argtypes = (ctypes.POINTER(onlp_oid_hdr),) + + libonlp.onlp_sys_dump.restype = None + libonlp.onlp_sys_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + + libonlp.onlp_sys_show.restype = None + libonlp.onlp_sys_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + + libonlp.onlp_sys_ioctl.restype = ctypes.c_int + # leave the parameters empty (varargs) + + ##libonlp.onlp_sys_vioctl.restype = ctypes.c_int + # NOTE that ctypes cannot automatically handle va_list + + libonlp.onlp_sys_platform_manage_start.restype = ctypes.c_int + libonlp.onlp_sys_platform_manage_start.argtypes = (ctypes.c_int,) + + libonlp.onlp_sys_platform_manage_stop.restype = ctypes.c_int + libonlp.onlp_sys_platform_manage_stop.argtypes = (ctypes.c_int,) + + libonlp.onlp_sys_platform_manage_join.restype = ctypes.c_int + + libonlp.onlp_sys_platform_manage_now.restype = None + + libonlp.onlp_sys_debug.restype = ctypes.c_int + libonlp.onlp_sys_debug.argtypes = (ctypes.POINTER(aim_pvs), ctypes.c_int, + ctypes.POINTER(ctypes.POINTER(ctypes.c_char)),) + +# onlp/onlp.h + +def onlp_init(): + libonlp.onlp_init() + aim_memory_init_prototypes() + aim_pvs_init_prototypes() + onlp_oid_init_prototypes() + onlp_sys_init_prototypes() diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py new file mode 100644 index 00000000..f5ce59a3 --- /dev/null +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -0,0 +1,236 @@ +"""OnlpApiTest.py + +Test the API bindings. +""" + +import ctypes +import unittest +import logging +import re + +import onlp.onlp +onlp.onlp.onlp_init() + +libonlp = onlp.onlp.libonlp + +class OnlpTestMixin(object): + + def setUp(self): + + self.log = logging.getLogger("onlp") + self.log.setLevel(logging.DEBUG) + + self.aim_pvs_buffer_p = libonlp.aim_pvs_buffer_create() + self.aim_pvs_buffer = self.aim_pvs_buffer_p.contents + + def tearDown(self): + + libonlp.aim_pvs_destroy(self.aim_pvs_buffer_p) + +class InitTest(OnlpTestMixin, + unittest.TestCase): + + def setUp(self): + OnlpTestMixin.setUp(self) + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testInit(self): + """Verify that the library can be loaded.""" + pass + + def testBuffer(self): + """Verify that the AIM buffer type is usable.""" + + nullString = onlp.onlp.aim_char_p(None) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + self.assertEqual(nullString, buf) + + libonlp.aim_printf(self.aim_pvs_buffer_p, "hello\n") + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + self.assertEqual("hello\n", buf.string_at()) + + libonlp.aim_printf(self.aim_pvs_buffer_p, "world\n") + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + self.assertEqual("hello\nworld\n", buf.string_at()) + + libonlp.aim_pvs_buffer_reset(self.aim_pvs_buffer_p) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + self.assertEqual(nullString, buf) + +class OnlpTest(OnlpTestMixin, + unittest.TestCase): + """Test interfaces in onlp/onlp.h.""" + + def setUp(self): + OnlpTestMixin.setUp(self) + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testPlatformDump(self): + """Verify basic platform dump output.""" + + flags = 0 + libonlp.onlp_platform_dump(self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("System Information:", bufStr) + self.assertIn("thermal @ 1", bufStr) + + def testPlatformDumpFlags(self): + """Verify platform dump flags are honored.""" + + flags = 0 + libonlp.onlp_platform_dump(self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("psu @ 1", bufStr) + self.assertNotIn("PSU-1 Fan", bufStr) + + libonlp.aim_pvs_buffer_reset(self.aim_pvs_buffer_p) + + flags = onlp.onlp.ONLP_OID_DUMP_F_RECURSE + libonlp.onlp_platform_dump(self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("psu @ 1", bufStr) + self.assertIn("PSU-1 Fan", bufStr) + + # hard to test onlp.onlp.ONLP_OID_DUMP_F_RECURSE, + # since it depends on whether a specific component is inserted + + def testPlatformShow(self): + """Verify basic platform show output.""" + + flags = 0 + libonlp.onlp_platform_show(self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("System Information:", bufStr) + + def testPlatformShowFlags(self): + """Verify that onlp_platform_show honors flags.""" + + flags = 0 + libonlp.onlp_platform_show(self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertNotIn("PSU 1", bufStr) + self.assertNotIn("PSU-1 Fan", bufStr) + + libonlp.aim_pvs_buffer_reset(self.aim_pvs_buffer_p) + + flags = onlp.onlp.ONLP_OID_SHOW_F_RECURSE + libonlp.onlp_platform_show(self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("PSU 1", bufStr) + self.assertIn("PSU-1 Fan", bufStr) + +class SysTest(OnlpTestMixin, + unittest.TestCase): + """Test interfaces in onlp/sys.h.""" + + def setUp(self): + OnlpTestMixin.setUp(self) + + libonlp.onlp_sys_init() + self.sys_info = onlp.onlp.onlp_sys_info() + + libonlp.onlp_sys_info_get(ctypes.byref(self.sys_info)) + self.sys_info.initialized = True + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testNoop(self): + pass + + def testOnieInfo(self): + """Verify the ONIE fields.""" + + product_re = re.compile("(.*)-(.*)-(.*)") + m = product_re.match(self.sys_info.onie_info.product_name) + self.assertIsNotNone(m) + + vendor_re = re.compile("[A-Z][a-z]*[a-zA-Z0-9_. -]") + m = vendor_re.match(self.sys_info.onie_info.vendor) + self.assertIsNotNone(m) + + self.assertIn('.', self.sys_info.onie_info.onie_version) + + # see if there are any vendor extensions + # if there are any, make sure the are well-formed + for vx in self.sys_info.onie_info.vx_list: + sz = vx.size + self.assert_(sz <= 256) + + def testPlatformInfo(self): + """Verify the platform info fields.""" + # XXX VM platforms have null for both + pass + + def auditOidHdr(self, hdr): + + self.assertEqual(0, hdr.poid) + self.assertEqual(0, hdr._id) + # root OID + + coids = [x for x in hdr.children()] + self.assert_(coids) + self.assert_(len(coids) < onlp.onlp.ONLP_OID_TABLE_SIZE) + + def _oidType(oid): + if oid.isSystem(): + return "sys" + if oid.isThermal(): + return "thm" + if oid.isFan(): + return "fan" + if oid.isPsu(): + return "psu" + if oid.isLed(): + return "led" + if oid.isModule(): + return "mod" + if oid.isRtc(): + return "rtc" + return "unk" + + for coid in coids: + self.log.info("oid %d (%s): %s", + coid._id, _oidType(coid), coid.description) + if _oidType(coid) == "unk": + raise AssertionError("invalid oid") + self.assertEqual(hdr._id, coid.poid) + + # if it's a PSU, verify that it has fans + if _oidType(coid) == "psu": + foids = [x for x in coid.children()] + for foid in foids: + self.log.info("oid %d (%s): %s", + foid._id, _oidType(foid), foid.description) + self.assertEqual("fan", _oidType(foid)) + # parent should the the PSU or the chassis + if coid._id == foid.poid: + pass + elif hdr._id == foid.poid: + pass + else: + raise AssertionError("invalid parent OID") + + def testSysHeaderOnie(self): + """Test the sys_hdr data that is in the sys_info.""" + self.auditOidHdr(self.sys_info.hdr) + + # test the iteration of the oid table + + def testSysHeader(self): + """Test the sys_hdr data available via sys_hdr_get.""" + pass + +if __name__ == "__main__": + logging.basicConfig() + unittest.main() diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/__init__.py new file mode 100644 index 00000000..512e8637 --- /dev/null +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/__init__.py @@ -0,0 +1,4 @@ +"""__init__.py + +Test code for the onlp Python bindings. +""" diff --git a/packages/base/any/onlp/src/onlpdump.py b/packages/base/any/onlp/src/onlpdump.py new file mode 100755 index 00000000..87204cb8 --- /dev/null +++ b/packages/base/any/onlp/src/onlpdump.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +"""onldump.py + +Test harness for Python bindings. +""" + +import sys +from ctypes import * + +import logging + +import onlp.onlp +import onlp.onlplib + +logging.basicConfig() +logger = logging.getLogger("onlpdump") +logger.setLevel(logging.DEBUG) + +onlp.onlp.onlp_init() + +libonlp = onlp.onlp.libonlp +si = onlp.onlp.onlp_sys_info() +libonlp.onlp_sys_info_get(byref(si)) + +logger.info("hello") + +import pdb +pdb.set_trace() + +##libonlp.onlp_onie_show(byref(si.onie_info), byref(libonlp.aim_pvs_stdout)) +libonlp.onlp_platform_dump(libonlp.aim_pvs_stdout, + (onlp.onlp.ONLP_OID_DUMP_F_RECURSE + | onlp.onlp.ONLP_OID_DUMP_F_EVEN_IF_ABSENT)) + +sys.exit(0) diff --git a/packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib/__init__.py b/packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib/__init__.py new file mode 100644 index 00000000..f5d998bf --- /dev/null +++ b/packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib/__init__.py @@ -0,0 +1,87 @@ +"""__init__.py + +Module init for onlp.onlplib +""" + +import ctypes + +# properly belongs in AIM.aim_list + +class list_links(ctypes.Structure): + pass + +list_links._fields_ = [("prev", ctypes.POINTER(list_links),), + ("next", ctypes.POINTER(list_links),),] + +class ListIterator(object): + + def __init__(self, links, castType=None): + self.links = links + self.castType = castType + self.cur = self.links.links.next + + def next(self): + + # Hurr, pointer()/POINTER() types are not directly comparable + p1 = ctypes.cast(self.cur, ctypes.c_void_p) + p2 = ctypes.cast(self.links.links.prev, ctypes.c_void_p) + if p1.value == p2.value: + raise StopIteration + + cur, self.cur = self.cur, self.cur.contents.next + if self.castType is not None: + cur = ctypes.cast(cur, ctypes.POINTER(self.castType)) + return cur.contents + +class list_head(ctypes.Structure): + _fields_ = [("links", list_links,),] + + links_klass = list_links + + def __iter__(self): + if self.links_klass == list_links: + return ListIterator(self) + else: + return ListIterator(self, castType=self.links_klass) + +class onlp_onie_vx(list_links): + # NOTE that Python inheritence merges the fields + # with the base class (ctypes-ism) + _fields_ = [("data", ctypes.c_ubyte * 256,), + ("size", ctypes.c_int,),] + +class onlp_onie_vx_list_head(list_head): + links_klass = onlp_onie_vx + +class onlp_onie_info(ctypes.Structure): + _fields_ = [("product_name", ctypes.c_char_p,), + ("part_number", ctypes.c_char_p,), + ("serial_number", ctypes.c_char_p,), + ("mac", ctypes.c_ubyte * 6,), + ("manufacture_date", ctypes.c_char_p,), + ("device_version", ctypes.c_ubyte,), + ("label_revision", ctypes.c_char_p,), + ("platform_name", ctypes.c_char_p,), + ("onie_version", ctypes.c_char_p,), + ("mac_range", ctypes.c_ushort,), + ("manufacturer", ctypes.c_char_p,), + ("country_code", ctypes.c_char_p,), + ("vendor", ctypes.c_char_p,), + ("diag_version", ctypes.c_char_p,), + ("service_tag", ctypes.c_char_p,), + ("crc", ctypes.c_uint,), + + # + # Vendor Extensions list, if available. + # + ("vx_list", onlp_onie_vx_list_head,), + + # Internal/debug + ("_hdr_id_string", ctypes.c_char_p,), + ("_hdr_version", ctypes.c_ubyte,), + ("_hdr_length", ctypes.c_ubyte,), + ("_hdr_valid_crc", ctypes.c_ubyte,),] + +class onlp_platform_info(ctypes.Structure): + _fields_ = [("cpld_versions", ctypes.c_char_p,), + ("other_versions", ctypes.c_char_p,),] From e8f044508bf40d3fd1623514451f8f14e06e5786 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 12 Sep 2017 15:46:08 -0700 Subject: [PATCH 02/24] Add the rest of the functions from oids.h, add the system OID --- .../onlp/module/python/onlp/onlp/__init__.py | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py index a0ba3412..f5c70e8b 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -113,6 +113,17 @@ def aim_pvs_init_prototypes(): onlp_oid = ctypes.c_uint +ONLP_OID_TYPE_SYS = 1 +ONLP_OID_TYPE_THERMAL = 2 +ONLP_OID_TYPE_FAN = 3 +ONLP_OID_TYPE_PSU = 4 +ONLP_OID_TYPE_LED = 5 +ONLP_OID_TYPE_MODULE = 6 +ONLP_OID_TYPE_RTC = 7 +# XXX roth waiting for enum generator + +ONLP_OID_SYS = (ONLP_OID_TYPE_SYS<<24) | 1 + ONLP_OID_DESC_SIZE = 128 ONLP_OID_TABLE_SIZE = 32 @@ -143,15 +154,6 @@ class OidTableIterator(object): libonlp.onlp_oid_hdr_get(oid, ctypes.byref(oidHdr)) return oidHdr -ONLP_OID_TYPE_SYS = 1 -ONLP_OID_TYPE_THERMAL = 2 -ONLP_OID_TYPE_FAN = 3 -ONLP_OID_TYPE_PSU = 4 -ONLP_OID_TYPE_LED = 5 -ONLP_OID_TYPE_MODULE = 6 -ONLP_OID_TYPE_RTC = 7 -# XXX roth waiting for enum generator - class onlp_oid_hdr(ctypes.Structure): _fields_ = [("_id", onlp_oid,), @@ -184,10 +186,17 @@ onlp_oid_iterate_f = ctypes.CFUNCTYPE(ctypes.c_int, onlp_oid, ctypes.c_void_p) def onlp_oid_init_prototypes(): - #onlp_oid_dump - #onlp_oid_table_dump - #onlp_oid_show - #onlp_oid_table_show + libonlp.onlp_oid_dump.restype = None + libonlp.onlp_oid_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + + libonlp.onlp_oid_table_dump.restype = None + libonlp.onlp_oid_table_dump.argtypes = (ctypes.POINTER(onlp_oid), ctypes.POINTER(aim_pvs), ctypes.c_uint,) + + libonlp.onlp_oid_show.restype = None + libonlp.onlp_oid_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + + libonlp.onlp_oid_table_show.restype = None + libonlp.onlp_oid_table_show.argtypes = (ctypes.POINTER(onlp_oid), ctypes.POINTER(aim_pvs), ctypes.c_uint,) libonlp.onlp_oid_iterate.restype = ctypes.c_int libonlp.onlp_oid_iterate.argtypes = (onlp_oid, ctypes.c_int, From e74dde6277a3cedec95a4b8b945b5431be16f45f Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 12 Sep 2017 15:46:29 -0700 Subject: [PATCH 03/24] Finish testing oids.h, including the oid iterator --- .../module/python/onlp/test/OnlpApiTest.py | 123 +++++++++++++++++- 1 file changed, 119 insertions(+), 4 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index f5ce59a3..0dfe43a7 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -175,7 +175,12 @@ class SysTest(OnlpTestMixin, def auditOidHdr(self, hdr): self.assertEqual(0, hdr.poid) - self.assertEqual(0, hdr._id) + if hdr._id == onlp.onlp.ONLP_OID_SYS: + pass + elif hdr._id == 0: + self.log.warn("invalid system OID 0") + else: + raise AssertionError("invalid system OID") # root OID coids = [x for x in hdr.children()] @@ -225,11 +230,121 @@ class SysTest(OnlpTestMixin, """Test the sys_hdr data that is in the sys_info.""" self.auditOidHdr(self.sys_info.hdr) - # test the iteration of the oid table - def testSysHeader(self): """Test the sys_hdr data available via sys_hdr_get.""" - pass + + hdr = onlp.onlp.onlp_oid_hdr() + libonlp.onlp_sys_hdr_get(ctypes.byref(hdr)) + self.auditOidHdr(hdr) + + def testOidIter(self): + """Test the oid iteration functions.""" + + class OidIterator(object): + + def __init__(self, log): + self.log = log or logging.getLogger("visit") + + def visit(self, oid, cookie): + return 0 + + def cvisit(self): + def _v(oid, cookie): + try: + return self.visit(oid, cookie) + except: + self.log.exception("visitor failed") + return -1 + return onlp.onlp.onlp_oid_iterate_f(_v) + + class V1(OidIterator): + + def __init__(self, cookie, log): + super(V1, self).__init__(log) + self.cookie = cookie + self.oids = [] + + def visit(self, oid, cookie): + if cookie != self.cookie: + raise AssertionError("invalid cookie") + self.log.info("found oid %d", oid) + self.oids.append(oid) + return 0 + + oidType = 0 + cookie = 0xdeadbeef + + # gather all OIDs + + v1 = V1(cookie, log=self.log.getChild("v1")) + libonlp.onlp_oid_iterate(self.sys_info.hdr._id, oidType, v1.cvisit(), cookie) + self.assert_(v1.oids) + oids = list(v1.oids) + + # validate error recovery + + v2 = V1(cookie+1, log=self.log.getChild("v2")) + libonlp.onlp_oid_iterate(self.sys_info.hdr._id, oidType, v2.cvisit(), cookie) + self.assertEqual([], v2.oids) + + # validate early exit + + class V3(OidIterator): + + def __init__(self, log): + super(V3, self).__init__(log) + self.oids = [] + + def visit(self, oid, cookie): + if oid == cookie: + return -1 + self.log.info("found oid %d", oid) + self.oids.append(oid) + return 0 + + v3 = V3(log=self.log.getChild("v3")) + cookie = oids[4] + libonlp.onlp_oid_iterate(self.sys_info.hdr._id, oidType, v3.cvisit(), cookie) + self.assertEqual(4, len(v3.oids)) + + def testOidDump(self): + oid = self.sys_info.hdr.coids[0] + flags = 0 + libonlp.onlp_oid_dump(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + self.assertIn("Description:", buf.string_at()) + + def testOidTableDump(self): + tbl = self.sys_info.hdr.coids + flags = 0 + libonlp.onlp_oid_table_dump(tbl, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + lines = buf.string_at().splitlines(False) + lines = [x for x in lines if 'Description' in x] + self.assert_(len(lines) > 1) + + def testOidShow(self): + oid = self.sys_info.hdr.coids[0] + flags = 0 + libonlp.onlp_oid_show(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + self.assertIn("Description:", buf.string_at()) + + def testOidTableShow(self): + tbl = self.sys_info.hdr.coids + flags = 0 + libonlp.onlp_oid_table_show(tbl, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + lines = buf.string_at().splitlines(False) + lines = [x for x in lines if 'Description' in x] + self.assert_(len(lines) > 1) + + def testSystemOid(self): + """Get the system oid.""" + + hdr = onlp.onlp.onlp_oid_hdr() + libonlp.onlp_oid_hdr_get(onlp.onlp.ONLP_OID_SYS, ctypes.byref(hdr)) + self.auditOidHdr(hdr) if __name__ == "__main__": logging.basicConfig() From f001c3adb5c54600b8fdf532c2d94cd3d912fbb9 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 13 Sep 2017 14:38:02 -0700 Subject: [PATCH 04/24] WIP to add some status codes --- .../any/onlp/src/onlp/module/python/onlp/onlp/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py index f5c70e8b..562c9a1f 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -262,6 +262,10 @@ def onlp_sys_init_prototypes(): # onlp/onlp.h +ONLP_STATUS_OK = 0 +ONLP_STATUS_E_UNSUPPORTED = -10 +# XXX roth + def onlp_init(): libonlp.onlp_init() aim_memory_init_prototypes() From 7b545c0284b694a4db21b351b56c57affd805f5a Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 13 Sep 2017 14:38:58 -0700 Subject: [PATCH 05/24] Finish testing sys.h, oids.h - test system oid - test sys dump - test platform management loop - test ioctl --- .../module/python/onlp/test/OnlpApiTest.py | 197 +++++++++++++----- 1 file changed, 141 insertions(+), 56 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index 0dfe43a7..d2a89a6f 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -7,6 +7,7 @@ import ctypes import unittest import logging import re +import time import onlp.onlp onlp.onlp.onlp_init() @@ -55,6 +56,10 @@ class InitTest(OnlpTestMixin, buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) self.assertEqual("hello\nworld\n", buf.string_at()) + libonlp.aim_printf(self.aim_pvs_buffer_p, "%d\n", 42) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + self.assertEqual("hello\nworld\n42\n", buf.string_at()) + libonlp.aim_pvs_buffer_reset(self.aim_pvs_buffer_p) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) self.assertEqual(nullString, buf) @@ -129,48 +134,7 @@ class OnlpTest(OnlpTestMixin, self.assertIn("PSU 1", bufStr) self.assertIn("PSU-1 Fan", bufStr) -class SysTest(OnlpTestMixin, - unittest.TestCase): - """Test interfaces in onlp/sys.h.""" - - def setUp(self): - OnlpTestMixin.setUp(self) - - libonlp.onlp_sys_init() - self.sys_info = onlp.onlp.onlp_sys_info() - - libonlp.onlp_sys_info_get(ctypes.byref(self.sys_info)) - self.sys_info.initialized = True - - def tearDown(self): - OnlpTestMixin.tearDown(self) - - def testNoop(self): - pass - - def testOnieInfo(self): - """Verify the ONIE fields.""" - - product_re = re.compile("(.*)-(.*)-(.*)") - m = product_re.match(self.sys_info.onie_info.product_name) - self.assertIsNotNone(m) - - vendor_re = re.compile("[A-Z][a-z]*[a-zA-Z0-9_. -]") - m = vendor_re.match(self.sys_info.onie_info.vendor) - self.assertIsNotNone(m) - - self.assertIn('.', self.sys_info.onie_info.onie_version) - - # see if there are any vendor extensions - # if there are any, make sure the are well-formed - for vx in self.sys_info.onie_info.vx_list: - sz = vx.size - self.assert_(sz <= 256) - - def testPlatformInfo(self): - """Verify the platform info fields.""" - # XXX VM platforms have null for both - pass +class SysHdrMixin(object): def auditOidHdr(self, hdr): @@ -226,6 +190,50 @@ class SysTest(OnlpTestMixin, else: raise AssertionError("invalid parent OID") +class SysTest(OnlpTestMixin, + SysHdrMixin, + unittest.TestCase): + """Test interfaces in onlp/sys.h.""" + + def setUp(self): + OnlpTestMixin.setUp(self) + + libonlp.onlp_sys_init() + self.sys_info = onlp.onlp.onlp_sys_info() + + libonlp.onlp_sys_info_get(ctypes.byref(self.sys_info)) + self.sys_info.initialized = True + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testNoop(self): + pass + + def testOnieInfo(self): + """Verify the ONIE fields.""" + + product_re = re.compile("(.*)-(.*)-(.*)") + m = product_re.match(self.sys_info.onie_info.product_name) + self.assertIsNotNone(m) + + vendor_re = re.compile("[A-Z][a-z]*[a-zA-Z0-9_. -]") + m = vendor_re.match(self.sys_info.onie_info.vendor) + self.assertIsNotNone(m) + + self.assertIn('.', self.sys_info.onie_info.onie_version) + + # see if there are any vendor extensions + # if there are any, make sure the are well-formed + for vx in self.sys_info.onie_info.vx_list: + sz = vx.size + self.assert_(sz <= 256) + + def testPlatformInfo(self): + """Verify the platform info fields.""" + # XXX VM platforms have null for both + pass + def testSysHeaderOnie(self): """Test the sys_hdr data that is in the sys_info.""" self.auditOidHdr(self.sys_info.hdr) @@ -237,6 +245,90 @@ class SysTest(OnlpTestMixin, libonlp.onlp_sys_hdr_get(ctypes.byref(hdr)) self.auditOidHdr(hdr) + def testManage(self): + """Verify we can start/stop platform management.""" + + code = libonlp.onlp_sys_platform_manage_start(0) + self.assert_(code >= 0) + + for i in range(10): + libonlp.onlp_sys_platform_manage_now() + time.sleep(0.25) + + code = libonlp.onlp_sys_platform_manage_stop(0) + self.assert_(code >= 0) + + time.sleep(2.0) + + code = libonlp.onlp_sys_platform_manage_join(0) + self.assert_(code >= 0) + + def testSysDump(self): + """Test the SYS OID debug dump.""" + + oid = onlp.onlp.ONLP_OID_SYS + flags = 0 + libonlp.onlp_sys_dump(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("System Information", bufStr) + + libonlp.aim_pvs_buffer_reset(self.aim_pvs_buffer_p) + + # this is not the system OID + + oid = self.sys_info.hdr.coids[0] + libonlp.onlp_sys_dump(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIsNone(bufStr) + + def testSysShow(self): + """Test the OID status.""" + + oid = onlp.onlp.ONLP_OID_SYS + flags = 0 + libonlp.onlp_sys_show(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("System Information", bufStr) + + libonlp.aim_pvs_buffer_reset(self.aim_pvs_buffer_p) + + # this is not the system OID + + oid = self.sys_info.hdr.coids[0] + libonlp.onlp_sys_show(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIsNone(bufStr) + + def testSysIoctl(self): + """Test the IOCTL interface.""" + + # no such ioctl + + code = libonlp.onlp_sys_ioctl(9999) + self.assertEqual(onlp.onlp.ONLP_STATUS_E_UNSUPPORTED, code) + +class OidTest(OnlpTestMixin, + SysHdrMixin, + unittest.TestCase): + """Test interfaces in onlp/oids.h.""" + + def setUp(self): + OnlpTestMixin.setUp(self) + + self.hdr = onlp.onlp.onlp_oid_hdr() + libonlp.onlp_oid_hdr_get(onlp.onlp.ONLP_OID_SYS, ctypes.byref(self.hdr)) + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testSystemOid(self): + """Audit the system oid.""" + self.auditOidHdr(self.hdr) + def testOidIter(self): """Test the oid iteration functions.""" @@ -277,14 +369,14 @@ class SysTest(OnlpTestMixin, # gather all OIDs v1 = V1(cookie, log=self.log.getChild("v1")) - libonlp.onlp_oid_iterate(self.sys_info.hdr._id, oidType, v1.cvisit(), cookie) + libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, oidType, v1.cvisit(), cookie) self.assert_(v1.oids) oids = list(v1.oids) # validate error recovery v2 = V1(cookie+1, log=self.log.getChild("v2")) - libonlp.onlp_oid_iterate(self.sys_info.hdr._id, oidType, v2.cvisit(), cookie) + libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, oidType, v2.cvisit(), cookie) self.assertEqual([], v2.oids) # validate early exit @@ -304,18 +396,18 @@ class SysTest(OnlpTestMixin, v3 = V3(log=self.log.getChild("v3")) cookie = oids[4] - libonlp.onlp_oid_iterate(self.sys_info.hdr._id, oidType, v3.cvisit(), cookie) + libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, oidType, v3.cvisit(), cookie) self.assertEqual(4, len(v3.oids)) def testOidDump(self): - oid = self.sys_info.hdr.coids[0] + oid = self.hdr.coids[0] flags = 0 libonlp.onlp_oid_dump(oid, self.aim_pvs_buffer_p, flags) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) self.assertIn("Description:", buf.string_at()) def testOidTableDump(self): - tbl = self.sys_info.hdr.coids + tbl = self.hdr.coids flags = 0 libonlp.onlp_oid_table_dump(tbl, self.aim_pvs_buffer_p, flags) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) @@ -324,14 +416,14 @@ class SysTest(OnlpTestMixin, self.assert_(len(lines) > 1) def testOidShow(self): - oid = self.sys_info.hdr.coids[0] + oid = self.hdr.coids[0] flags = 0 libonlp.onlp_oid_show(oid, self.aim_pvs_buffer_p, flags) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) self.assertIn("Description:", buf.string_at()) def testOidTableShow(self): - tbl = self.sys_info.hdr.coids + tbl = self.hdr.coids flags = 0 libonlp.onlp_oid_table_show(tbl, self.aim_pvs_buffer_p, flags) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) @@ -339,13 +431,6 @@ class SysTest(OnlpTestMixin, lines = [x for x in lines if 'Description' in x] self.assert_(len(lines) > 1) - def testSystemOid(self): - """Get the system oid.""" - - hdr = onlp.onlp.onlp_oid_hdr() - libonlp.onlp_oid_hdr_get(onlp.onlp.ONLP_OID_SYS, ctypes.byref(hdr)) - self.auditOidHdr(hdr) - if __name__ == "__main__": logging.basicConfig() unittest.main() From b140fec41b382aa37985eb591b3694f711847140 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 13 Sep 2017 15:53:06 -0700 Subject: [PATCH 06/24] enum overhaul - move python enums to a proper modul - pull up OID show and dump flags to the auto.yml - update APIs and tests to use autogen enums --- packages/base/any/onlp/APKG.yml | 8 +- .../any/onlp/src/onlp/module/auto/make.mk | 2 +- .../any/onlp/src/onlp/module/auto/onlp.yml | 19 +++ .../any/onlp/src/onlp/module/inc/onlp/oids.h | 62 ++++++++- .../any/onlp/src/onlp/module/inc/onlp/onlp.x | 2 + .../onlp/module/python/onlp/onlp/__init__.py | 40 ++---- .../module/{py => python/onlp/onlp}/enums.py | 11 ++ .../module/python/onlp/test/OnlpApiTest.py | 40 ++---- .../base/any/onlp/src/onlp/module/src/fan.c | 2 +- .../base/any/onlp/src/onlp/module/src/led.c | 2 +- .../any/onlp/src/onlp/module/src/onlp_enums.c | 122 ++++++++++++++++++ .../any/onlp/src/onlp/module/src/onlp_main.c | 12 +- .../base/any/onlp/src/onlp/module/src/psu.c | 8 +- .../base/any/onlp/src/onlp/module/src/sys.c | 10 +- .../any/onlp/src/onlp/module/src/thermal.c | 2 +- packages/base/any/onlp/src/onlp/utest/main.c | 4 +- packages/base/any/onlp/src/onlpdump.py | 4 +- packages/base/any/oom-shim/src/utest/main.c | 4 +- 18 files changed, 261 insertions(+), 93 deletions(-) rename packages/base/any/onlp/src/onlp/module/{py => python/onlp/onlp}/enums.py (94%) diff --git a/packages/base/any/onlp/APKG.yml b/packages/base/any/onlp/APKG.yml index 2144913b..7ab08aa3 100644 --- a/packages/base/any/onlp/APKG.yml +++ b/packages/base/any/onlp/APKG.yml @@ -27,10 +27,10 @@ packages: builds/onlp-platform-defaults/$BUILD_DIR/${TOOLCHAIN}/bin/libonlp-platform-defaults.so : $libdir/ builds/onlpd/$BUILD_DIR/${TOOLCHAIN}/bin/onlpd : $bindir/ ${ONL}/packages/base/any/onlp/src/onlpdump.py: $bindir/ - ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/*.py: ${PY_INSTALL}/onlp/ - ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/*.py: ${PY_INSTALL}/onlp/onlp/ - ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/test/*.py: ${PY_INSTALL}/onlp/test/ - ${ONL}/packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib/*.py: ${PY_INSTALL}/onlp/onlplib/ + ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/__init__.py: ${PY_INSTALL}/onlp/ + ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/onlp: ${PY_INSTALL}/onlp/onlp + ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/test: ${PY_INSTALL}/onlp/test + ${ONL}/packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib: ${PY_INSTALL}/onlp/onlplib init: $ONL/packages/base/any/onlp/src/onlpd.init diff --git a/packages/base/any/onlp/src/onlp/module/auto/make.mk b/packages/base/any/onlp/src/onlp/module/auto/make.mk index 95a06896..dbf853f1 100644 --- a/packages/base/any/onlp/src/onlp/module/auto/make.mk +++ b/packages/base/any/onlp/src/onlp/module/auto/make.mk @@ -24,5 +24,5 @@ ############################################################ onlp_AUTO_DEFS := module/auto/onlp.yml -onlp_AUTO_DIRS := module/inc/onlp module/src module/py +onlp_AUTO_DIRS := module/inc/onlp module/src module/python/onlp/onlp include $(BUILDER)/auto.mk diff --git a/packages/base/any/onlp/src/onlp/module/auto/onlp.yml b/packages/base/any/onlp/src/onlp/module/auto/onlp.yml index f784e320..ac82e314 100644 --- a/packages/base/any/onlp/src/onlp/module/auto/onlp.yml +++ b/packages/base/any/onlp/src/onlp/module/auto/onlp.yml @@ -109,6 +109,17 @@ oid_types: &oid_types - MODULE : 6 - RTC : 7 +# OID dump options +oid_dump: &oid_dump +- RECURSE +- EVEN_IF_ABSENT + +# OID show options +oid_show: &oid_show +- RECURSE +- EXTENDED +- YAML + # SFP Control sfp_control: &sfp_control - RESET @@ -255,6 +266,14 @@ definitions: onlp_oid_type: tag: oid members: *oid_types + onlp_oid_show: + tag: oid + members: *oid_show + flags: True + onlp_oid_dump: + tag: oid + members: *oid_dump + flags: True onlp_thermal_status: tag: thermal members: *thermal_status diff --git a/packages/base/any/onlp/src/onlp/module/inc/onlp/oids.h b/packages/base/any/onlp/src/onlp/module/inc/onlp/oids.h index 20ce5746..13df3243 100644 --- a/packages/base/any/onlp/src/onlp/module/inc/onlp/oids.h +++ b/packages/base/any/onlp/src/onlp/module/inc/onlp/oids.h @@ -47,6 +47,19 @@ typedef uint32_t onlp_oid_t; /* */ +/** onlp_oid_dump */ +typedef enum onlp_oid_dump_e { + ONLP_OID_DUMP_RECURSE = (1 << 0), + ONLP_OID_DUMP_EVEN_IF_ABSENT = (1 << 1), +} onlp_oid_dump_t; + +/** onlp_oid_show */ +typedef enum onlp_oid_show_e { + ONLP_OID_SHOW_RECURSE = (1 << 0), + ONLP_OID_SHOW_EXTENDED = (1 << 1), + ONLP_OID_SHOW_YAML = (1 << 2), +} onlp_oid_show_t; + /** onlp_oid_type */ typedef enum onlp_oid_type_e { ONLP_OID_TYPE_SYS = 1, @@ -121,13 +134,6 @@ typedef struct onlp_oid_hdr_s { } onlp_oid_hdr_t; -#define ONLP_OID_DUMP_F_RECURSE 0x1 -#define ONLP_OID_DUMP_F_EVEN_IF_ABSENT 0x2 - -#define ONLP_OID_SHOW_F_RECURSE 0x1 -#define ONLP_OID_SHOW_F_EXTENDED 0x2 -#define ONLP_OID_SHOW_F_YAML 0x4 - void onlp_oid_dump(onlp_oid_t oid, aim_pvs_t* pvs, uint32_t flags); void onlp_oid_table_dump(onlp_oid_table_t table, aim_pvs_t* pvs, uint32_t flags); @@ -199,6 +205,48 @@ int onlp_oid_hdr_get(onlp_oid_t oid, onlp_oid_hdr_t* hdr); * *****************************************************************************/ /* */ +/** Enum names. */ +const char* onlp_oid_dump_name(onlp_oid_dump_t e); + +/** Enum values. */ +int onlp_oid_dump_value(const char* str, onlp_oid_dump_t* e, int substr); + +/** Enum descriptions. */ +const char* onlp_oid_dump_desc(onlp_oid_dump_t e); + +/** Enum validator. */ +int onlp_oid_dump_valid(onlp_oid_dump_t e); + +/** validator */ +#define ONLP_OID_DUMP_VALID(_e) \ + (onlp_oid_dump_valid((_e))) + +/** onlp_oid_dump_map table. */ +extern aim_map_si_t onlp_oid_dump_map[]; +/** onlp_oid_dump_desc_map table. */ +extern aim_map_si_t onlp_oid_dump_desc_map[]; + +/** Enum names. */ +const char* onlp_oid_show_name(onlp_oid_show_t e); + +/** Enum values. */ +int onlp_oid_show_value(const char* str, onlp_oid_show_t* e, int substr); + +/** Enum descriptions. */ +const char* onlp_oid_show_desc(onlp_oid_show_t e); + +/** Enum validator. */ +int onlp_oid_show_valid(onlp_oid_show_t e); + +/** validator */ +#define ONLP_OID_SHOW_VALID(_e) \ + (onlp_oid_show_valid((_e))) + +/** onlp_oid_show_map table. */ +extern aim_map_si_t onlp_oid_show_map[]; +/** onlp_oid_show_desc_map table. */ +extern aim_map_si_t onlp_oid_show_desc_map[]; + /** Enum names. */ const char* onlp_oid_type_name(onlp_oid_type_t e); diff --git a/packages/base/any/onlp/src/onlp/module/inc/onlp/onlp.x b/packages/base/any/onlp/src/onlp/module/inc/onlp/onlp.x index ebcf42da..988bcf3c 100644 --- a/packages/base/any/onlp/src/onlp/module/inc/onlp/onlp.x +++ b/packages/base/any/onlp/src/onlp/module/inc/onlp/onlp.x @@ -48,6 +48,8 @@ ONLP_ENUMERATION_ENTRY(onlp_fan_status, "") ONLP_ENUMERATION_ENTRY(onlp_led_caps, "") ONLP_ENUMERATION_ENTRY(onlp_led_mode, "") ONLP_ENUMERATION_ENTRY(onlp_led_status, "") +ONLP_ENUMERATION_ENTRY(onlp_oid_dump, "") +ONLP_ENUMERATION_ENTRY(onlp_oid_show, "") ONLP_ENUMERATION_ENTRY(onlp_oid_type, "") ONLP_ENUMERATION_ENTRY(onlp_psu_caps, "") ONLP_ENUMERATION_ENTRY(onlp_psu_status, "") diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py index 562c9a1f..48deb6d5 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -12,6 +12,8 @@ libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c")) import onlp.onlplib +from onlp.onlp.enums import * + # AIM/aim_memory.h class aim_void_p(ctypes.c_void_p): @@ -113,27 +115,11 @@ def aim_pvs_init_prototypes(): onlp_oid = ctypes.c_uint -ONLP_OID_TYPE_SYS = 1 -ONLP_OID_TYPE_THERMAL = 2 -ONLP_OID_TYPE_FAN = 3 -ONLP_OID_TYPE_PSU = 4 -ONLP_OID_TYPE_LED = 5 -ONLP_OID_TYPE_MODULE = 6 -ONLP_OID_TYPE_RTC = 7 -# XXX roth waiting for enum generator - -ONLP_OID_SYS = (ONLP_OID_TYPE_SYS<<24) | 1 +ONLP_OID_SYS = (ONLP_OID_TYPE.SYS<<24) | 1 ONLP_OID_DESC_SIZE = 128 ONLP_OID_TABLE_SIZE = 32 -ONLP_OID_DUMP_F_RECURSE = 0x1 -ONLP_OID_DUMP_F_EVEN_IF_ABSENT = 0x2 - -ONLP_OID_SHOW_F_RECURSE = 0x1 -ONLP_OID_SHOW_F_EXTENDED = 0x2 -ONLP_OID_SHOW_F_YAML = 0x4 - class OidTableIterator(object): def __init__(self, hdr): @@ -165,19 +151,19 @@ class onlp_oid_hdr(ctypes.Structure): return self._id >> 24 def isSystem(self): - return self.getType() == ONLP_OID_TYPE_SYS + return self.getType() == ONLP_OID_TYPE.SYS def isThermal(self): - return self.getType() == ONLP_OID_TYPE_THERMAL + return self.getType() == ONLP_OID_TYPE.THERMAL def isFan(self): - return self.getType() == ONLP_OID_TYPE_FAN + return self.getType() == ONLP_OID_TYPE.FAN def isPsu(self): - return self.getType() == ONLP_OID_TYPE_PSU + return self.getType() == ONLP_OID_TYPE.PSU def isLed(self): - return self.getType() == ONLP_OID_TYPE_LED + return self.getType() == ONLP_OID_TYPE.LED def isModule(self): - return self.getType() == ONLP_OID_TYPE_MODULE + return self.getType() == ONLP_OID_TYPE.MODULE def isRtc(self): - return self.getType() == ONLP_OID_TYPE_RTC + return self.getType() == ONLP_OID_TYPE.RTC def children(self): return OidTableIterator(self) @@ -201,11 +187,9 @@ def onlp_oid_init_prototypes(): libonlp.onlp_oid_iterate.restype = ctypes.c_int libonlp.onlp_oid_iterate.argtypes = (onlp_oid, ctypes.c_int, onlp_oid_iterate_f, ctypes.c_void_p,) - # XXX enum libonlp.onlp_oid_hdr_get.restype = ctypes.c_int libonlp.onlp_oid_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr,)) - # XXX enum # onlp/sys.h @@ -262,10 +246,6 @@ def onlp_sys_init_prototypes(): # onlp/onlp.h -ONLP_STATUS_OK = 0 -ONLP_STATUS_E_UNSUPPORTED = -10 -# XXX roth - def onlp_init(): libonlp.onlp_init() aim_memory_init_prototypes() diff --git a/packages/base/any/onlp/src/onlp/module/py/enums.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/enums.py similarity index 94% rename from packages/base/any/onlp/src/onlp/module/py/enums.py rename to packages/base/any/onlp/src/onlp/module/python/onlp/onlp/enums.py index 65cd75ec..a747c9bc 100644 --- a/packages/base/any/onlp/src/onlp/module/py/enums.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/enums.py @@ -88,6 +88,17 @@ class ONLP_LED_STATUS(Enumeration): ON = (1 << 2) +class ONLP_OID_DUMP(Enumeration): + RECURSE = (1 << 0) + EVEN_IF_ABSENT = (1 << 1) + + +class ONLP_OID_SHOW(Enumeration): + RECURSE = (1 << 0) + EXTENDED = (1 << 1) + YAML = (1 << 2) + + class ONLP_OID_TYPE(Enumeration): SYS = 1 THERMAL = 2 diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index d2a89a6f..691f2266 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -96,14 +96,14 @@ class OnlpTest(OnlpTestMixin, libonlp.aim_pvs_buffer_reset(self.aim_pvs_buffer_p) - flags = onlp.onlp.ONLP_OID_DUMP_F_RECURSE + flags = onlp.onlp.ONLP_OID_DUMP.RECURSE libonlp.onlp_platform_dump(self.aim_pvs_buffer_p, flags) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) bufStr = buf.string_at() self.assertIn("psu @ 1", bufStr) self.assertIn("PSU-1 Fan", bufStr) - # hard to test onlp.onlp.ONLP_OID_DUMP_F_RECURSE, + # hard to test onlp.onlp.ONLP_OID_DUMP.RECURSE, # since it depends on whether a specific component is inserted def testPlatformShow(self): @@ -127,7 +127,7 @@ class OnlpTest(OnlpTestMixin, libonlp.aim_pvs_buffer_reset(self.aim_pvs_buffer_p) - flags = onlp.onlp.ONLP_OID_SHOW_F_RECURSE + flags = onlp.onlp.ONLP_OID_SHOW.RECURSE libonlp.onlp_platform_show(self.aim_pvs_buffer_p, flags) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) bufStr = buf.string_at() @@ -152,36 +152,22 @@ class SysHdrMixin(object): self.assert_(len(coids) < onlp.onlp.ONLP_OID_TABLE_SIZE) def _oidType(oid): - if oid.isSystem(): - return "sys" - if oid.isThermal(): - return "thm" - if oid.isFan(): - return "fan" - if oid.isPsu(): - return "psu" - if oid.isLed(): - return "led" - if oid.isModule(): - return "mod" - if oid.isRtc(): - return "rtc" - return "unk" + return onlp.onlp.ONLP_OID_TYPE.name(oid._id>>24) for coid in coids: self.log.info("oid %d (%s): %s", coid._id, _oidType(coid), coid.description) - if _oidType(coid) == "unk": + if _oidType(coid) is None: raise AssertionError("invalid oid") self.assertEqual(hdr._id, coid.poid) # if it's a PSU, verify that it has fans - if _oidType(coid) == "psu": + if _oidType(coid) == "PSU": foids = [x for x in coid.children()] for foid in foids: self.log.info("oid %d (%s): %s", foid._id, _oidType(foid), foid.description) - self.assertEqual("fan", _oidType(foid)) + self.assertEqual("FAN", _oidType(foid)) # parent should the the PSU or the chassis if coid._id == foid.poid: pass @@ -309,7 +295,7 @@ class SysTest(OnlpTestMixin, # no such ioctl code = libonlp.onlp_sys_ioctl(9999) - self.assertEqual(onlp.onlp.ONLP_STATUS_E_UNSUPPORTED, code) + self.assertEqual(onlp.onlp.ONLP_STATUS.E_UNSUPPORTED, code) class OidTest(OnlpTestMixin, SysHdrMixin, @@ -338,7 +324,7 @@ class OidTest(OnlpTestMixin, self.log = log or logging.getLogger("visit") def visit(self, oid, cookie): - return 0 + return onlp.onlp.ONLP_STATUS.E_OK def cvisit(self): def _v(oid, cookie): @@ -346,7 +332,7 @@ class OidTest(OnlpTestMixin, return self.visit(oid, cookie) except: self.log.exception("visitor failed") - return -1 + return onlp.onlp.ONLP_STATUS.E_GENERIC return onlp.onlp.onlp_oid_iterate_f(_v) class V1(OidIterator): @@ -361,7 +347,7 @@ class OidTest(OnlpTestMixin, raise AssertionError("invalid cookie") self.log.info("found oid %d", oid) self.oids.append(oid) - return 0 + return onlp.onlp.ONLP_STATUS.E_OK oidType = 0 cookie = 0xdeadbeef @@ -389,10 +375,10 @@ class OidTest(OnlpTestMixin, def visit(self, oid, cookie): if oid == cookie: - return -1 + return onlp.onlp.ONLP_STATUS.E_GENERIC self.log.info("found oid %d", oid) self.oids.append(oid) - return 0 + return onlp.onlp.ONLP_STATUS.E_OK v3 = V3(log=self.log.getChild("v3")) cookie = oids[4] diff --git a/packages/base/any/onlp/src/onlp/module/src/fan.c b/packages/base/any/onlp/src/onlp/module/src/fan.c index 3ef8a75e..549814db 100644 --- a/packages/base/any/onlp/src/onlp/module/src/fan.c +++ b/packages/base/any/onlp/src/onlp/module/src/fan.c @@ -281,7 +281,7 @@ onlp_fan_show(onlp_oid_t oid, aim_pvs_t* pvs, uint32_t flags) rv = onlp_fan_info_get(oid, &fi); - yaml = flags & ONLP_OID_SHOW_F_YAML; + yaml = flags & ONLP_OID_SHOW_YAML; if(yaml) { iof_push(&iof, "- "); diff --git a/packages/base/any/onlp/src/onlp/module/src/led.c b/packages/base/any/onlp/src/onlp/module/src/led.c index e914ee69..21036cd4 100644 --- a/packages/base/any/onlp/src/onlp/module/src/led.c +++ b/packages/base/any/onlp/src/onlp/module/src/led.c @@ -215,7 +215,7 @@ onlp_led_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) VALIDATENR(id); onlp_oid_show_iof_init_default(&iof, pvs, flags); - yaml = flags & ONLP_OID_SHOW_F_YAML; + yaml = flags & ONLP_OID_SHOW_YAML; if(yaml) { iof_push(&iof, " -"); diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c b/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c index 67ebd6f7..e632b27b 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c @@ -519,6 +519,128 @@ onlp_led_status_valid(onlp_led_status_t e) } +aim_map_si_t onlp_oid_dump_map[] = +{ + { "RECURSE", ONLP_OID_DUMP_RECURSE }, + { "EVEN_IF_ABSENT", ONLP_OID_DUMP_EVEN_IF_ABSENT }, + { NULL, 0 } +}; + +aim_map_si_t onlp_oid_dump_desc_map[] = +{ + { "None", ONLP_OID_DUMP_RECURSE }, + { "None", ONLP_OID_DUMP_EVEN_IF_ABSENT }, + { NULL, 0 } +}; + +const char* +onlp_oid_dump_name(onlp_oid_dump_t e) +{ + const char* name; + if(aim_map_si_i(&name, e, onlp_oid_dump_map, 0)) { + return name; + } + else { + return "-invalid value for enum type 'onlp_oid_dump'"; + } +} + +int +onlp_oid_dump_value(const char* str, onlp_oid_dump_t* e, int substr) +{ + int i; + AIM_REFERENCE(substr); + if(aim_map_si_s(&i, str, onlp_oid_dump_map, 0)) { + /* Enum Found */ + *e = i; + return 0; + } + else { + return -1; + } +} + +const char* +onlp_oid_dump_desc(onlp_oid_dump_t e) +{ + const char* name; + if(aim_map_si_i(&name, e, onlp_oid_dump_desc_map, 0)) { + return name; + } + else { + return "-invalid value for enum type 'onlp_oid_dump'"; + } +} + +int +onlp_oid_dump_valid(onlp_oid_dump_t e) +{ + return aim_map_si_i(NULL, e, onlp_oid_dump_map, 0) ? 1 : 0; +} + + +aim_map_si_t onlp_oid_show_map[] = +{ + { "RECURSE", ONLP_OID_SHOW_RECURSE }, + { "EXTENDED", ONLP_OID_SHOW_EXTENDED }, + { "YAML", ONLP_OID_SHOW_YAML }, + { NULL, 0 } +}; + +aim_map_si_t onlp_oid_show_desc_map[] = +{ + { "None", ONLP_OID_SHOW_RECURSE }, + { "None", ONLP_OID_SHOW_EXTENDED }, + { "None", ONLP_OID_SHOW_YAML }, + { NULL, 0 } +}; + +const char* +onlp_oid_show_name(onlp_oid_show_t e) +{ + const char* name; + if(aim_map_si_i(&name, e, onlp_oid_show_map, 0)) { + return name; + } + else { + return "-invalid value for enum type 'onlp_oid_show'"; + } +} + +int +onlp_oid_show_value(const char* str, onlp_oid_show_t* e, int substr) +{ + int i; + AIM_REFERENCE(substr); + if(aim_map_si_s(&i, str, onlp_oid_show_map, 0)) { + /* Enum Found */ + *e = i; + return 0; + } + else { + return -1; + } +} + +const char* +onlp_oid_show_desc(onlp_oid_show_t e) +{ + const char* name; + if(aim_map_si_i(&name, e, onlp_oid_show_desc_map, 0)) { + return name; + } + else { + return "-invalid value for enum type 'onlp_oid_show'"; + } +} + +int +onlp_oid_show_valid(onlp_oid_show_t e) +{ + return aim_map_si_i(NULL, e, onlp_oid_show_map, 0) ? 1 : 0; +} + + aim_map_si_t onlp_oid_type_map[] = { { "SYS", ONLP_OID_TYPE_SYS }, diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_main.c b/packages/base/any/onlp/src/onlp/module/src/onlp_main.c index 6dd5ccfe..41d32795 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_main.c +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_main.c @@ -203,8 +203,8 @@ onlpdump_main(int argc, char* argv[]) switch(c) { case 's': show=1; break; - case 'r': show=1; showflags |= ONLP_OID_SHOW_F_RECURSE; break; - case 'e': show=1; showflags |= ONLP_OID_SHOW_F_EXTENDED; break; + case 'r': show=1; showflags |= ONLP_OID_SHOW_RECURSE; break; + case 'e': show=1; showflags |= ONLP_OID_SHOW_EXTENDED; break; case 'd': show=0; break; case 'h': help=1; rv = 0; break; case 'j': j=1; break; @@ -220,7 +220,7 @@ onlpdump_main(int argc, char* argv[]) case 'l': l=1; break; case 'b': b=1; break; case 'J': J = optarg; break; - case 'y': show=1; showflags |= ONLP_OID_SHOW_F_YAML; break; + case 'y': show=1; showflags |= ONLP_OID_SHOW_YAML; break; default: help=1; rv = 1; break; } } @@ -305,8 +305,8 @@ onlpdump_main(int argc, char* argv[]) int oid; if(sscanf(O, "0x%x", &oid) == 1) { onlp_oid_dump(oid, &aim_pvs_stdout, - ONLP_OID_DUMP_F_RECURSE | - ONLP_OID_DUMP_F_EVEN_IF_ABSENT); + ONLP_OID_DUMP_RECURSE | + ONLP_OID_DUMP_EVEN_IF_ABSENT); } return 0; } @@ -349,7 +349,7 @@ onlpdump_main(int argc, char* argv[]) if(show == 0) { /* Default to full dump */ onlp_platform_dump(&aim_pvs_stdout, - ONLP_OID_DUMP_F_RECURSE | ONLP_OID_DUMP_F_EVEN_IF_ABSENT); + ONLP_OID_DUMP_RECURSE | ONLP_OID_DUMP_EVEN_IF_ABSENT); } else { onlp_platform_show(&aim_pvs_stdout, diff --git a/packages/base/any/onlp/src/onlp/module/src/psu.c b/packages/base/any/onlp/src/onlp/module/src/psu.c index 76baf3fe..5aaf166c 100644 --- a/packages/base/any/onlp/src/onlp/module/src/psu.c +++ b/packages/base/any/onlp/src/onlp/module/src/psu.c @@ -143,7 +143,7 @@ onlp_psu_dump(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) iof_iprintf(&iof, "Iout: %d", info.miout); iof_iprintf(&iof, "Pin: %d", info.mpin); iof_iprintf(&iof, "Pout: %d", info.mpout); - if(flags & ONLP_OID_DUMP_F_RECURSE) { + if(flags & ONLP_OID_DUMP_RECURSE) { onlp_oid_table_dump(info.hdr.coids, &iof.inherit, flags); } } @@ -165,7 +165,7 @@ onlp_psu_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) onlp_oid_show_iof_init_default(&iof, pvs, flags); rv = onlp_psu_info_get(id, &pi); - yaml = flags & ONLP_OID_SHOW_F_YAML; + yaml = flags & ONLP_OID_SHOW_YAML; if(yaml) { iof_push(&iof, "- "); @@ -235,7 +235,7 @@ onlp_psu_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) ONLP_MILLI_NORMAL_INTEGER_TENTHS(pi.mpout)); } - if(flags & ONLP_OID_SHOW_F_RECURSE) { + if(flags & ONLP_OID_SHOW_RECURSE) { /* * Display sub oids. * @@ -264,7 +264,7 @@ onlp_psu_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) iof_pop(&iof); } - if(flags & ONLP_OID_SHOW_F_EXTENDED) { + if(flags & ONLP_OID_SHOW_EXTENDED) { /* Include all other types as well. */ ONLP_OID_TABLE_ITER_TYPE(pi.hdr.coids, oidp, LED) { onlp_oid_show(*oidp, &iof.inherit, flags); diff --git a/packages/base/any/onlp/src/onlp/module/src/sys.c b/packages/base/any/onlp/src/onlp/module/src/sys.c index c8090476..ad6fc49f 100644 --- a/packages/base/any/onlp/src/onlp/module/src/sys.c +++ b/packages/base/any/onlp/src/onlp/module/src/sys.c @@ -214,7 +214,7 @@ onlp_sys_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) int yaml; onlp_oid_show_iof_init_default(&iof, pvs, flags); - yaml = (flags & ONLP_OID_SHOW_F_YAML); + yaml = (flags & ONLP_OID_SHOW_YAML); if(id && ONLP_OID_TYPE_GET(id) != ONLP_OID_TYPE_SYS) { return; @@ -234,14 +234,14 @@ onlp_sys_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) * unless you specify EXTENDED or !RECURSIVE */ if(yaml || - flags & ONLP_OID_SHOW_F_EXTENDED || - (flags & ONLP_OID_SHOW_F_RECURSE) == 0) { + flags & ONLP_OID_SHOW_EXTENDED || + (flags & ONLP_OID_SHOW_RECURSE) == 0) { iof_push(&iof, "System Information:"); onlp_onie_show(&si.onie_info, &iof.inherit); iof_pop(&iof); } - if(flags & ONLP_OID_SHOW_F_RECURSE) { + if(flags & ONLP_OID_SHOW_RECURSE) { onlp_oid_t* oidp; @@ -266,7 +266,7 @@ onlp_sys_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) } YPOP(); - if(flags & ONLP_OID_SHOW_F_EXTENDED) { + if(flags & ONLP_OID_SHOW_EXTENDED) { /** Show all LEDs */ YPUSH("LEDs:"); ONLP_OID_TABLE_ITER_TYPE(si.hdr.coids, oidp, LED) { diff --git a/packages/base/any/onlp/src/onlp/module/src/thermal.c b/packages/base/any/onlp/src/onlp/module/src/thermal.c index c3511b2e..219a1123 100644 --- a/packages/base/any/onlp/src/onlp/module/src/thermal.c +++ b/packages/base/any/onlp/src/onlp/module/src/thermal.c @@ -202,7 +202,7 @@ onlp_thermal_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) rv = onlp_thermal_info_get(id, &ti); - yaml = flags & ONLP_OID_SHOW_F_YAML; + yaml = flags & ONLP_OID_SHOW_YAML; if(yaml) { iof_push(&iof, "- "); diff --git a/packages/base/any/onlp/src/onlp/utest/main.c b/packages/base/any/onlp/src/onlp/utest/main.c index e7e9e030..7ada8e55 100644 --- a/packages/base/any/onlp/src/onlp/utest/main.c +++ b/packages/base/any/onlp/src/onlp/utest/main.c @@ -115,9 +115,9 @@ aim_main(int argc, char* argv[]) /* Example Platform Dump */ onlp_init(); - onlp_platform_dump(&aim_pvs_stdout, ONLP_OID_DUMP_F_RECURSE); + onlp_platform_dump(&aim_pvs_stdout, ONLP_OID_DUMP_RECURSE); onlp_oid_iterate(0, 0, iter__, NULL); - onlp_platform_show(&aim_pvs_stdout, ONLP_OID_SHOW_F_RECURSE|ONLP_OID_SHOW_F_EXTENDED); + onlp_platform_show(&aim_pvs_stdout, ONLP_OID_SHOW_RECURSE|ONLP_OID_SHOW_EXTENDED); if(argv[1] && !strcmp("manage", argv[1])) { onlp_sys_platform_manage_start(); diff --git a/packages/base/any/onlp/src/onlpdump.py b/packages/base/any/onlp/src/onlpdump.py index 87204cb8..e2349d62 100755 --- a/packages/base/any/onlp/src/onlpdump.py +++ b/packages/base/any/onlp/src/onlpdump.py @@ -30,7 +30,7 @@ pdb.set_trace() ##libonlp.onlp_onie_show(byref(si.onie_info), byref(libonlp.aim_pvs_stdout)) libonlp.onlp_platform_dump(libonlp.aim_pvs_stdout, - (onlp.onlp.ONLP_OID_DUMP_F_RECURSE - | onlp.onlp.ONLP_OID_DUMP_F_EVEN_IF_ABSENT)) + (onlp.onlp.ONLP_OID_DUMP.RECURSE + | onlp.onlp.ONLP_OID_DUMP.EVEN_IF_ABSENT)) sys.exit(0) diff --git a/packages/base/any/oom-shim/src/utest/main.c b/packages/base/any/oom-shim/src/utest/main.c index e7e9e030..7ada8e55 100644 --- a/packages/base/any/oom-shim/src/utest/main.c +++ b/packages/base/any/oom-shim/src/utest/main.c @@ -115,9 +115,9 @@ aim_main(int argc, char* argv[]) /* Example Platform Dump */ onlp_init(); - onlp_platform_dump(&aim_pvs_stdout, ONLP_OID_DUMP_F_RECURSE); + onlp_platform_dump(&aim_pvs_stdout, ONLP_OID_DUMP_RECURSE); onlp_oid_iterate(0, 0, iter__, NULL); - onlp_platform_show(&aim_pvs_stdout, ONLP_OID_SHOW_F_RECURSE|ONLP_OID_SHOW_F_EXTENDED); + onlp_platform_show(&aim_pvs_stdout, ONLP_OID_SHOW_RECURSE|ONLP_OID_SHOW_EXTENDED); if(argv[1] && !strcmp("manage", argv[1])) { onlp_sys_platform_manage_start(); From efe9508cd8ad97c3cfda7cc5e843aeb8be820e83 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 18 Sep 2017 17:13:59 -0700 Subject: [PATCH 07/24] Added fan and led interfaces --- .../onlp/module/python/onlp/onlp/__init__.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py index 48deb6d5..4e9329b9 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -111,6 +111,11 @@ def aim_pvs_init_prototypes(): libonlp.aim_pvs_buffer_reset.restype = None libonlp.aim_pvs_buffer_reset.argtypes = (ctypes.POINTER(aim_pvs),) +# onlp.yml + +ONLP_CONFIG_INFO_STR_MAX = 64 +# XXX roth -- no cdefs support (yet) + # onlp/oids.h onlp_oid = ctypes.c_uint @@ -244,6 +249,98 @@ def onlp_sys_init_prototypes(): libonlp.onlp_sys_debug.argtypes = (ctypes.POINTER(aim_pvs), ctypes.c_int, ctypes.POINTER(ctypes.POINTER(ctypes.c_char)),) +# onlp/fan.h + +class onlp_fan_info(ctypes.Structure): + _fields_ = [("hdr", onlp_oid_hdr,), + ("status", ctypes.c_uint,), + ("caps", ctypes.c_uint,), + ("rpm", ctypes.c_int,), + ("percentage", ctypes.c_int,), + ("mode", ctypes.c_uint,), + ("model", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,), + ("serial", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,),] + + def isPresent(self): + return self.status & ONLP_FAN_STATUS.PRESENT + + def isMissing(self): + return not self.PRESENT() + + def isFailed(self): + return self.status & ONLP_FAN_STATUS.FAILED + + def isNormal(self): + return self.isPresent() and not self.isFailed() + +def onlp_fan_init_prototypes(): + + libonlp.onlp_fan_init.restype = None + + libonlp.onlp_fan_info_get.restype = ctypes.c_int + libonlp.onlp_fan_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_fan_info),) + + libonlp.onlp_fan_status_get.restype = ctypes.c_int + libonlp.onlp_fan_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint),) + + libonlp.onlp_fan_hdr_get.restype = ctypes.c_int + libonlp.onlp_fan_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) + + libonlp.onlp_fan_rpm_set.restype = ctypes.c_int + libonlp.onlp_fan_rpm_set.argtypes = (onlp_oid, ctypes.c_int,) + + libonlp.onlp_fan_percentage_set.restype = ctypes.c_int + libonlp.onlp_fan_percentage_set.argtypes = (onlp_oid, ctypes.c_int,) + + libonlp.onlp_fan_mode_set.restype = ctypes.c_int + libonlp.onlp_fan_mode_set.argtypes = (onlp_oid, ctypes.c_uint,) + + libonlp.onlp_fan_dir_set.restype = ctypes.c_int + libonlp.onlp_fan_dir_set.argtypes = (onlp_oid, ctypes.c_uint,) + + libonlp.onlp_fan_dump.restype = None + libonlp.onlp_fan_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + + libonlp.onlp_fan_show.restype = None + libonlp.onlp_fan_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + +# onlp/led.h + +class onlp_led_info(ctypes.Structure): + _fields_ = [("hdr", onlp_oid_hdr,), + ("status", ctypes.c_uint,), + ("caps", ctypes.c_uint,), + ("mode", ctypes.c_uint,), + ("character", ctypes.c_char,),] + +def onlp_led_init_prototypes(): + + libonlp.onlp_led_init.restype = None + + libonlp.onlp_led_info_get.restype = ctypes.c_int + libonlp.onlp_led_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_led_info),) + + libonlp.onlp_led_status_get.restype = ctypes.c_int + libonlp.onlp_led_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint),) + + libonlp.onlp_led_hdr_get.restype = ctypes.c_int + libonlp.onlp_led_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) + + libonlp.onlp_led_set.restype = ctypes.c_int + libonlp.onlp_led_set.argtypes = (onlp_oid, ctypes.c_int,) + + libonlp.onlp_led_mode_set.restype = ctypes.c_int + libonlp.onlp_led_mode_set.argtypes = (onlp_oid, ctypes.c_uint,) + + libonlp.onlp_led_char_set.restype = ctypes.c_int + libonlp.onlp_led_char_set.argtypes = (onlp_oid, ctypes.c_char,) + + libonlp.onlp_led_dump.restype = None + libonlp.onlp_led_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + + libonlp.onlp_led_show.restype = None + libonlp.onlp_led_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + # onlp/onlp.h def onlp_init(): @@ -252,3 +349,5 @@ def onlp_init(): aim_pvs_init_prototypes() onlp_oid_init_prototypes() onlp_sys_init_prototypes() + onlp_fan_init_prototypes() + onlp_led_init_prototypes() From e095ffcb52f891b233e82f35b600112490bac579 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 18 Sep 2017 17:14:17 -0700 Subject: [PATCH 08/24] Fix argument order for OID enumerator --- packages/base/any/onlp/src/onlp/module/src/oids.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/any/onlp/src/onlp/module/src/oids.c b/packages/base/any/onlp/src/onlp/module/src/oids.c index baea7610..861f427c 100644 --- a/packages/base/any/onlp/src/onlp/module/src/oids.c +++ b/packages/base/any/onlp/src/onlp/module/src/oids.c @@ -216,7 +216,7 @@ onlp_oid_iterate(onlp_oid_t oid, onlp_oid_type_t type, } ONLP_OID_TABLE_ITER(hdr.coids, oidp) { - if(type == 0 || ONLP_OID_IS_TYPE(*oidp, type)) { + if(type == 0 || ONLP_OID_IS_TYPE(type, *oidp)) { int rv = itf(*oidp, cookie); if(rv < 0) { return rv; From 02261de11a1cc44222b33e19d97a9842b3a1516c Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 18 Sep 2017 17:14:37 -0700 Subject: [PATCH 09/24] Added fan test and initial LED test --- .../module/python/onlp/test/OnlpApiTest.py | 638 +++++++++++++++++- 1 file changed, 601 insertions(+), 37 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index 691f2266..b6e42141 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -8,12 +8,21 @@ import unittest import logging import re import time +import subprocess import onlp.onlp onlp.onlp.onlp_init() libonlp = onlp.onlp.libonlp +def isVirtual(): + with open("/etc/onl/platform") as fd: + buf = fd.read() + return "bigswitch" in buf + +def skipIfVirtual(reason="this test only works with a physical device"): + return unittest.skipIf(isVirtual(), reason) + class OnlpTestMixin(object): def setUp(self): @@ -28,6 +37,11 @@ class OnlpTestMixin(object): libonlp.aim_pvs_destroy(self.aim_pvs_buffer_p) + def assertStatusOK(self, sts): + if sts == onlp.onlp.ONLP_STATUS.OK: + return + raise AssertionError("invalid ONLP status %s" % onlp.onlp.ONLP_STATUS.name(sts)) + class InitTest(OnlpTestMixin, unittest.TestCase): @@ -149,7 +163,7 @@ class SysHdrMixin(object): coids = [x for x in hdr.children()] self.assert_(coids) - self.assert_(len(coids) < onlp.onlp.ONLP_OID_TABLE_SIZE) + self.assertLess(len(coids), onlp.onlp.ONLP_OID_TABLE_SIZE) def _oidType(oid): return onlp.onlp.ONLP_OID_TYPE.name(oid._id>>24) @@ -167,7 +181,10 @@ class SysHdrMixin(object): for foid in foids: self.log.info("oid %d (%s): %s", foid._id, _oidType(foid), foid.description) - self.assertEqual("FAN", _oidType(foid)) + if _oidType(foid) in ["FAN", "THERMAL",]: + pass + else: + raise AssertionError("invalid child oid") # parent should the the PSU or the chassis if coid._id == foid.poid: pass @@ -199,13 +216,17 @@ class SysTest(OnlpTestMixin, def testOnieInfo(self): """Verify the ONIE fields.""" - product_re = re.compile("(.*)-(.*)-(.*)") + product_re = re.compile("[a-z]*[a-zA-Z0-9_. -]") m = product_re.match(self.sys_info.onie_info.product_name) - self.assertIsNotNone(m) + if m is None: + raise AssertionError("invalid product name %s" + % repr(self.sys_info.onie_info.product_name)) vendor_re = re.compile("[A-Z][a-z]*[a-zA-Z0-9_. -]") m = vendor_re.match(self.sys_info.onie_info.vendor) - self.assertIsNotNone(m) + if m is None: + raise AssertionError("invalid vendor %s" + % repr(self.sys_info.onie_info.vendor)) self.assertIn('.', self.sys_info.onie_info.onie_version) @@ -213,7 +234,7 @@ class SysTest(OnlpTestMixin, # if there are any, make sure the are well-formed for vx in self.sys_info.onie_info.vx_list: sz = vx.size - self.assert_(sz <= 256) + self.assertLessEqual(sz, 256) def testPlatformInfo(self): """Verify the platform info fields.""" @@ -234,20 +255,30 @@ class SysTest(OnlpTestMixin, def testManage(self): """Verify we can start/stop platform management.""" - code = libonlp.onlp_sys_platform_manage_start(0) - self.assert_(code >= 0) + try: - for i in range(10): - libonlp.onlp_sys_platform_manage_now() - time.sleep(0.25) + subprocess.check_call(('service', 'onlpd', 'stop',)) - code = libonlp.onlp_sys_platform_manage_stop(0) - self.assert_(code >= 0) + code = libonlp.onlp_sys_platform_manage_init() + self.assertGreaterEqual(code, 0) - time.sleep(2.0) + code = libonlp.onlp_sys_platform_manage_start(0) + self.assertGreaterEqual(code, 0) - code = libonlp.onlp_sys_platform_manage_join(0) - self.assert_(code >= 0) + for i in range(10): + libonlp.onlp_sys_platform_manage_now() + time.sleep(0.25) + + code = libonlp.onlp_sys_platform_manage_stop(0) + self.assertGreaterEqual(code, 0) + + time.sleep(2.0) + + code = libonlp.onlp_sys_platform_manage_join(0) + self.assertGreaterEqual(code, 0) + + except: + subprocess.check_call(('service', 'onlpd', 'start',)) def testSysDump(self): """Test the SYS OID debug dump.""" @@ -297,6 +328,23 @@ class SysTest(OnlpTestMixin, code = libonlp.onlp_sys_ioctl(9999) self.assertEqual(onlp.onlp.ONLP_STATUS.E_UNSUPPORTED, code) +class OidIterator(object): + + def __init__(self, log): + self.log = log or logging.getLogger("visit") + + def visit(self, oid, cookie): + return onlp.onlp.ONLP_STATUS.OK + + def cvisit(self): + def _v(oid, cookie): + try: + return self.visit(oid, cookie) + except: + self.log.exception("visitor failed") + return onlp.onlp.ONLP_STATUS.E_GENERIC + return onlp.onlp.onlp_oid_iterate_f(_v) + class OidTest(OnlpTestMixin, SysHdrMixin, unittest.TestCase): @@ -318,23 +366,6 @@ class OidTest(OnlpTestMixin, def testOidIter(self): """Test the oid iteration functions.""" - class OidIterator(object): - - def __init__(self, log): - self.log = log or logging.getLogger("visit") - - def visit(self, oid, cookie): - return onlp.onlp.ONLP_STATUS.E_OK - - def cvisit(self): - def _v(oid, cookie): - try: - return self.visit(oid, cookie) - except: - self.log.exception("visitor failed") - return onlp.onlp.ONLP_STATUS.E_GENERIC - return onlp.onlp.onlp_oid_iterate_f(_v) - class V1(OidIterator): def __init__(self, cookie, log): @@ -347,7 +378,7 @@ class OidTest(OnlpTestMixin, raise AssertionError("invalid cookie") self.log.info("found oid %d", oid) self.oids.append(oid) - return onlp.onlp.ONLP_STATUS.E_OK + return onlp.onlp.ONLP_STATUS.OK oidType = 0 cookie = 0xdeadbeef @@ -359,8 +390,17 @@ class OidTest(OnlpTestMixin, self.assert_(v1.oids) oids = list(v1.oids) + # filter based on OID type + + oidType = onlp.onlp.ONLP_OID_TYPE.PSU + v1b = V1(cookie, log=self.log.getChild("v1b")) + libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, oidType, v1b.cvisit(), cookie) + self.assert_(v1b.oids) + self.assertLess(len(v1b.oids), len(oids)) + # validate error recovery + oidType = 0 v2 = V1(cookie+1, log=self.log.getChild("v2")) libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, oidType, v2.cvisit(), cookie) self.assertEqual([], v2.oids) @@ -378,7 +418,7 @@ class OidTest(OnlpTestMixin, return onlp.onlp.ONLP_STATUS.E_GENERIC self.log.info("found oid %d", oid) self.oids.append(oid) - return onlp.onlp.ONLP_STATUS.E_OK + return onlp.onlp.ONLP_STATUS.OK v3 = V3(log=self.log.getChild("v3")) cookie = oids[4] @@ -399,7 +439,7 @@ class OidTest(OnlpTestMixin, buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) lines = buf.string_at().splitlines(False) lines = [x for x in lines if 'Description' in x] - self.assert_(len(lines) > 1) + self.assertGreater(len(lines), 1) def testOidShow(self): oid = self.hdr.coids[0] @@ -415,7 +455,531 @@ class OidTest(OnlpTestMixin, buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) lines = buf.string_at().splitlines(False) lines = [x for x in lines if 'Description' in x] - self.assert_(len(lines) > 1) + self.assertGreater(len(lines), 1) + +class FanTest(OnlpTestMixin, + unittest.TestCase): + """Test interfaces in onlp/fan.h.""" + + FAN_MODE_VALID = False + # 'fan mode' configuration is not implemented + + def setUp(self): + OnlpTestMixin.setUp(self) + + libonlp.onlp_sys_init() + libonlp.onlp_fan_init() + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def auditFanOid(self, oid): + """Test the power-on behavior of a fan.""" + + hdr = onlp.onlp.onlp_oid_hdr() + libonlp.onlp_fan_hdr_get(oid, ctypes.byref(hdr)) + self.assertEqual(oid, hdr._id) + + fan = onlp.onlp.onlp_fan_info() + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + + self.assertEqual(oid, fan.hdr._id) + self.assert_(fan.model) + self.assert_(fan.serial) + self.log.info("auditing fan %d: %s (S/N %s)", + oid & 0xFFFFFF, + fan.model, fan.serial) + + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.B2F: + pass + elif fan.caps & onlp.onlp.ONLP_FAN_CAPS.F2B: + pass + else: + raise AssertionError("invalid fan caps") + + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_RPM: + self.assertGreater(fan.rpm, 0) + else: + self.log.warn("fan does not support RPM get") + + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_PERCENTAGE: + self.assertGreater(fan.percentage, 0) + self.assertLessEqual(fan.percentage, 100) + else: + self.log.warn("fan does not support PCT get") + + if self.FAN_MODE_VALID: + self.assertNotEqual(onlp.onlp.ONLP_FAN_MODE.OFF, fan.mode) + # default, fan should be running + + self.assert_(onlp.onlp.ONLP_FAN_STATUS.PRESENT & fan.status) + # default, fan should be present + + if fan.status & onlp.onlp.ONLP_FAN_STATUS.B2F: + self.assert_(onlp.onlp.ONLP_ONLP_FAN_CAPS.B2F) + elif fan.status & onlp.onlp.ONLP_FAN_STATUS.F2B: + self.assert_(onlp.onlp.ONLP_FAN_CAPS.F2B) + else: + self.log.warn("fan direction not supported") + + # retrieve fan status separately + sts = ctypes.c_uint() + libonlp.onlp_fan_status_get(oid, ctypes.byref(sts)) + self.assert_(onlp.onlp.ONLP_FAN_STATUS.PRESENT & sts.value) + + # try to manipulate the fan speed + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.SET_RPM: + self.auditFanRpm(oid) + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.SET_PERCENTAGE: + self.auditFanPct(oid) + if (self.FAN_MODE_VALID + and (fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_RPM + or fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_PERCENTAGE)): + self.auditFanMode(oid) + if (fan.caps & onlp.onlp.ONLP_FAN_CAPS.F2B + and fan.caps & onlp.onlp.ONLP_FAN_CAPS.B2F): + self.auditFanDir(oid) + + flags = 0 + libonlp.onlp_fan_dump(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("Fan", bufStr) + + libonlp.onlp_fan_show(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("Fan", bufStr) + + def auditFanRpm(self, oid): + """Try to adjust the fan RPM. + + Note that the maximum fan speed is not know ahead of time. + Also note the mechanicals here: + - fan spin-up takes several seconds + - fan spin-down takes much longer than spin-up + - actual target fan speeds are set by the driver + - for safety reasons there may not be an 'off' setting + """ + + fan = onlp.onlp.onlp_fan_info() + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + if self.FAN_MODE_VALID: + self.assertEqual(fan.mode, onlp.onlp.ONLP_FAN_MODE.MAX) + minRpm = maxRpm = curRpm = fan.rpm + + speeds = [] + pcts = [] + try: + subprocess.check_call(('service', 'onlpd', 'stop',)) + + self.log.info("probing for max fan speed") + nspeed = curRpm + while True: + self.log.info("current fan rpm is %d", nspeed) + self.log.info("trying higher fan rpm is %d", nspeed * 2) + libonlp.onlp_fan_rpm_set(oid, nspeed * 2) + time.sleep(5.0) + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + self.log.info("probed fan speed is %d", fan.rpm) + if fan.rpm > (nspeed * 125 // 100): + nspeed = fan.rpm + continue + + self.log.info("max fan speed is %d", fan.rpm) + maxRpm = fan.rpm + break + + self.log.info("probing for min fan speed") + nspeed = curRpm + while True: + self.log.info("setting fan rpm to %d", nspeed) + self.log.info("trying lower fan rpm is %d", nspeed // 2) + libonlp.onlp_fan_rpm_set(oid, nspeed // 2) + + time.sleep(10.0) + # spin-down is slower than spin-up + + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + self.log.info("probed fan speed is %d", fan.rpm) + if fan.rpm < (nspeed * 75 // 100): + nspeed = fan.rpm + continue + + self.log.info("min fan speed is %d", fan.rpm) + minRpm = fan.rpm + break + + self.assertLess(minRpm, maxRpm) + + self.log.info("cycling through fan speeds") + for nspeed in range(minRpm, maxRpm, (maxRpm-minRpm)//3): + self.log.info("setting fan rpm to %d", nspeed) + libonlp.onlp_fan_rpm_set(oid, nspeed) + time.sleep(5.0) + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + speeds.append(fan.rpm) + pcts.append(fan.percentage) + + finally: + libonlp.onlp_fan_rpm_set(oid, curRpm) + libonlp.onlp_fan_mode_set(oid, onlp.onlp.ONLP_FAN_MODE.MAX) + subprocess.check_call(('service', 'onlpd', 'start',)) + + # fan speeds should be monotonically increasing + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_RPM: + self.assertEqual(speeds, sorted(speeds)) + self.assertLess(minRpm * 95 // 100, speeds[0]) + self.assertGreater(maxRpm * 105 // 100, speeds[-1]) + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_PERCENTAGE: + self.assertEqual(pcts, sorted(pcts)) + ##self.assertEqual(0, pcts[0]) + ##self.assertGreater(105, pcts[-1]) + + def auditFanPct(self, oid): + """Try to adjust the fan percentage.""" + + fan = onlp.onlp.onlp_fan_info() + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + if self.FAN_MODE_VALID: + self.assertEqual(fan.mode, onlp.onlp.ONLP_FAN_MODE.MAX) + + speeds = [] + pcts = [] + try: + subprocess.check_call(('service', 'onlpd', 'stop',)) + + libonlp.onlp_fan_percentage_set(oid, 0) + time.sleep(10.0) + # initially spin down the fan + + for npct in [0, 33, 66, 100,]: + self.log.info("setting fan percentage to %d", npct) + libonlp.onlp_fan_percentage_set(oid, npct) + time.sleep(5.0) + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + speeds.append(fan.rpm) + pcts.append(fan.percentage) + finally: + libonlp.onlp_fan_percentage_set(oid, 100) + libonlp.onlp_fan_mode_set(oid, onlp.onlp.ONLP_FAN_MODE.MAX) + subprocess.check_call(('service', 'onlpd', 'start',)) + + # fan speeds should be monotonically increasing + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_RPM: + self.assertEqual(speeds, sorted(speeds)) + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_PERCENTAGE: + self.assertEqual(pcts, sorted(pcts)) + + def auditFanDir(self, oid): + """Try to adjust the fan direction.""" + unittest.skip("not implemented") + + def auditFanMode(self, oid): + """Try to adjust the fan speed using the mode specifier.""" + + fan = onlp.onlp.onlp_fan_info() + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + self.assertEqual(fan.mode, onlp.onlp.ONLP_FAN_MODE.MAX) + + speeds = [] + pcts = [] + try: + subprocess.check_call(('service', 'onlpd', 'stop',)) + for nmode in [onlp.onlp.ONLP_FAN_MODE.OFF, + onlp.onlp.ONLP_FAN_MODE.SLOW, + onlp.onlp.ONLP_FAN_MODE.NORMAL, + onlp.onlp.ONLP_FAN_MODE.FAST, + onlp.onlp.ONLP_FAN_MODE.MAX,]: + self.log.info("setting fan mode to %s", onlp.onlp.ONLP_FAN_MODE.name(nmode)) + libonlp.onlp_fan_mode_set(oid, nmode) + time.sleep(2.0) + libonlp.onlp_fan_info_get(oid, ctypes.byref(fan)) + speeds.append(fan.rpm) + pcts.append(fan.percentage) + finally: + libonlp.onlp_fan_mode_set(oid, onlp.onlp.ONLP_FAN_MODE.MAX) + subprocess.check_call(('service', 'onlpd', 'start',)) + + # fan speeds should be monotonically increasing + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_RPM: + self.assertEqual(speeds, sorted(speeds)) + self.assertEqual(0, speeds[0]) + self.assertGreater(105*maxRpm//100, speeds[-1]) + if fan.caps & onlp.onlp.ONLP_FAN_CAPS.GET_PERCENTAGE: + self.assertEqual(pcts, sorted(pcts)) + self.assertEqual(0, pcts[0]) + self.assertGreater(105, pcts[-1]) + + def testFindFans(self): + """Verify that the system has fans.""" + + class V(OidIterator): + + def __init__(self, log): + super(V, self).__init__(log) + self.oids = [] + + def visit(self, oid, cookie): + self.log.info("found FAN oid %d", oid) + self.oids.append(oid) + return onlp.onlp.ONLP_STATUS.OK + + v = V(log=self.log.getChild("fan")) + libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, + onlp.onlp.ONLP_OID_TYPE.FAN, + v.cvisit(), 0) + self.assert_(v.oids) + + self.auditFanOid(v.oids[0]) + +class LedTest(OnlpTestMixin, + unittest.TestCase): + """Test interfaces in onlp/led.h. + + XXX roth -- need to flesh this out using a physical device. + """ + + def setUp(self): + OnlpTestMixin.setUp(self) + + libonlp.onlp_sys_init() + libonlp.onlp_led_init() + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testFindLeds(self): + """Verify that the system has LEDs.""" + + class V(OidIterator): + + def __init__(self, log): + super(V, self).__init__(log) + self.oids = [] + + def visit(self, oid, cookie): + self.log.info("found LED oid %d", oid) + self.oids.append(oid) + return onlp.onlp.ONLP_STATUS.OK + + v = V(log=self.log.getChild("led")) + libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, + onlp.onlp.ONLP_OID_TYPE.LED, + v.cvisit(), 0) + self.assert_(v.oids) + + self.auditLedOid(v.oids[0]) + + def auditLedOid(self, oid): + + hdr = onlp.onlp.onlp_oid_hdr() + libonlp.onlp_led_hdr_get(oid, ctypes.byref(hdr)) + self.assertEqual(oid, hdr._id) + + led = onlp.onlp.onlp_led_info() + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + + self.assertEqual(oid, led.hdr._id) + + self.assert_(led.caps) + # should support some non-empty set of capabilities + + self.log.info("auditing led %d", + oid & 0xFFFFFF) + + self.assert_(led.status & onlp.onlp.ONLP_LED_STATUS.PRESENT) + + # retrieve led status separately + sts = ctypes.c_uint() + libonlp.onlp_led_status_get(oid, ctypes.byref(sts)) + self.assert_(onlp.onlp.ONLP_LED_STATUS.PRESENT & sts.value) + + if led.caps & onlp.onlp.ONLP_LED_CAPS.CHAR: + self.auditLedChar(oid) + if led.caps & onlp.onlp.ONLP_LED_CAPS.ON_OFF: + self.auditLedOnOff(oid) + self.auditLedColors(oid) + self.auditLedBlink(oid) + + flags = 0 + libonlp.onlp_led_dump(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("LED", bufStr) + + libonlp.onlp_led_show(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("LED", bufStr) + + def auditLedChar(self, oid): + + led = onlp.onlp.onlp_led_info() + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + saveChar = led.char + + try: + for nchar in ['0', '1', '2', '3',]: + self.log.info("led %d: char '%s'", oid, nchar) + + sts = libonlp.onlp_led_char_set(oid, nchar) + self.assertStatusOK(sts) + + time.sleep(1.0) + + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + self.assertEqual(nchar, led.char) + except: + libonlp.onlp_led_char_set(oid, saveChar) + raise + + def auditLedOnOff(self, oid): + + led = onlp.onlp.onlp_led_info() + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + saveMode = led.mode + + if saveMode == onlp.onlp.ONLP_LED_MODE.OFF: + pass + elif saveMode == onlp.onlp.ONLP_LED_MODE.ON: + pass + else: + self.log.warn("invalid LED on/off mode %s", + onlp.onlp.ONLP_LED_MODE.name(saveMode)) + + try: + for i in range(4): + self.log.info("led %d: on", oid) + + sts = libonlp.onlp_led_set(oid, 1) + self.assertStatusOK(sts) + + time.sleep(1.0) + + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + self.assertEqual(onlp.onlp.ONLP_LED_MODE.ON, led.mode) + + sts = libonlp.onlp_led_get(oid, 0) + self.assertStatusOK(sts) + + time.sleep(1.0) + + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + self.assertEqual(onlp.onlp.ONLP_LED_MODE.OFF, led.mode) + + except: + if saveMode == onlp.onlp.ONLP_LED_MODE.OFF: + libonlp.onlp_led_set(oid, 0) + else: + libonlp.onlp_led_set(oid, 1) + raise + + def auditLedColors(self, oid): + + led = onlp.onlp.onlp_led_info() + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + saveMode = led.mode + + allModes = [] + if led.caps & onlp.onlp.ONLP_LED_CAPS.RED: + allModes.append(onlp.onlp.ONLP_LED_MODE.RED) + if led.caps & onlp.onlp.ONLP_LED_CAPS.ORANGE: + allModes.append(onlp.onlp.ONLP_LED_MODE.ORANGE) + if led.caps & onlp.onlp.ONLP_LED_CAPS.YELLOW: + allModes.append(onlp.onlp.ONLP_LED_MODE.YELLOW) + if led.caps & onlp.onlp.ONLP_LED_CAPS.GREEN: + allModes.append(onlp.onlp.ONLP_LED_MODE.GREEN) + if led.caps & onlp.onlp.ONLP_LED_CAPS.BLUE: + allModes.append(onlp.onlp.ONLP_LED_MODE.BLUE) + if led.caps & onlp.onlp.ONLP_LED_CAPS.PURPLE: + allModes.append(onlp.onlp.ONLP_LED_MODE.PURPLE) + if led.caps & onlp.onlp.ONLP_LED_CAPS.AUTO: + allModes.append(onlp.onlp.ONLP_LED_MODE.AUTO) + + if not allModes: + unittest.skip("colors not supported") + return + self.log.info("found %d supported colors", len(allModes)) + + try: + for ncolor in allModes: + self.log.info("led %d: color '%s'", oid, onlp.onlp.ONLP_LED_MODE.name(ncolor)) + + sts = libonlp.onlp_led_mode_set(oid, ncolor) + self.assertStatusOK(sts) + + time.sleep(1.0) + + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + self.assertEqual(ncolor, led.mode) + + self.log.info("led %d: OFF", oid) + + sts = libonlp.onlp_led_mode_set(oid, onlp.onlp.ONLP_LED_MODE.OFF) + self.assertStatusOK(sts) + + time.sleep(1.0) + + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + self.assertEqual(onlp.onlp.ONLP_LED_MODE.OFF, led.mode) + + except: + libonlp.onlp_led_mode_set(oid, saveMode) + raise + + def auditLedBlink(self, oid): + + led = onlp.onlp.onlp_led_info() + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + saveMode = led.mode + + allModes = [] + if led.caps & onlp.onlp.ONLP_LED_CAPS.RED_BLINKING: + allModes.append(onlp.onlp.ONLP_LED_MODE.RED_BLINKING) + if led.caps & onlp.onlp.ONLP_LED_CAPS.ORANGE_BLINKING: + allModes.append(onlp.onlp.ONLP_LED_MODE.ORANGE_BLINKING) + if led.caps & onlp.onlp.ONLP_LED_CAPS.YELLOW_BLINKING: + allModes.append(onlp.onlp.ONLP_LED_MODE.YELLOW_BLINKING) + if led.caps & onlp.onlp.ONLP_LED_CAPS.GREEN_BLINKING: + allModes.append(onlp.onlp.ONLP_LED_MODE.GREEN_BLINKING) + if led.caps & onlp.onlp.ONLP_LED_CAPS.BLUE_BLINKING: + allModes.append(onlp.onlp.ONLP_LED_MODE.BLUE_BLINKING) + if led.caps & onlp.onlp.ONLP_LED_CAPS.PURPLE_BLINKING: + allModes.append(onlp.onlp.ONLP_LED_MODE.PURPLE_BLINKING) + if led.caps & onlp.onlp.ONLP_LED_CAPS.AUTO_BLINKING: + allModes.append(onlp.onlp.ONLP_LED_MODE.AUTO_BLINKING) + + if not allModes: + unittest.skip("blinking colors not supported") + return + self.log.info("found %d supported blink colors", len(allModes)) + + try: + for ncolor in allModes: + self.log.info("led %d: blink color '%s'", oid, onlp.onlp.ONLP_LED_MODE.name(ncolor)) + + sts = libonlp.onlp_led_mode_set(oid, ncolor) + self.assertStatusOK(sts) + + time.sleep(1.0) + + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + self.assertEqual(ncolor, led.mode) + + self.log.info("led %d: OFF", oid) + + sts = libonlp.onlp_led_mode_set(oid, onlp.onlp.ONLP_LED_MODE.OFF) + self.assertStatusOK(sts) + + time.sleep(1.0) + + libonlp.onlp_led_info_get(oid, ctypes.byref(led)) + self.assertEqual(onlp.onlp.ONLP_LED_MODE.OFF, led.mode) + + except: + libonlp.onlp_led_mode_set(oid, saveMode) + raise if __name__ == "__main__": logging.basicConfig() From 45b5331eb7d171193dba65f908b0bfa4fc83b302 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 18 Sep 2017 18:28:16 -0700 Subject: [PATCH 10/24] Added a working LED test --- .../module/python/onlp/test/OnlpApiTest.py | 68 ++++++++++++++----- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index b6e42141..6daf811f 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -277,7 +277,7 @@ class SysTest(OnlpTestMixin, code = libonlp.onlp_sys_platform_manage_join(0) self.assertGreaterEqual(code, 0) - except: + finally: subprocess.check_call(('service', 'onlpd', 'start',)) def testSysDump(self): @@ -795,23 +795,61 @@ class LedTest(OnlpTestMixin, libonlp.onlp_led_status_get(oid, ctypes.byref(sts)) self.assert_(onlp.onlp.ONLP_LED_STATUS.PRESENT & sts.value) - if led.caps & onlp.onlp.ONLP_LED_CAPS.CHAR: - self.auditLedChar(oid) - if led.caps & onlp.onlp.ONLP_LED_CAPS.ON_OFF: - self.auditLedOnOff(oid) - self.auditLedColors(oid) - self.auditLedBlink(oid) + try: + subprocess.check_call(('service', 'onlpd', 'stop',)) + + if led.caps & onlp.onlp.ONLP_LED_CAPS.CHAR: + self.auditLedChar(oid) + if (led.caps & onlp.onlp.ONLP_LED_CAPS.ON_OFF + and not self.hasColors(led.caps)): + self.auditLedOnOff(oid) + self.auditLedColors(oid) + self.auditLedBlink(oid) + + finally: + subprocess.check_call(('service', 'onlpd', 'start',)) + flags = 0 libonlp.onlp_led_dump(oid, self.aim_pvs_buffer_p, flags) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) bufStr = buf.string_at() - self.assertIn("LED", bufStr) + self.assertIn("led @", bufStr) libonlp.onlp_led_show(oid, self.aim_pvs_buffer_p, flags) buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) bufStr = buf.string_at() - self.assertIn("LED", bufStr) + self.assertIn("led @", bufStr) + + def hasColors(self, caps): + """True if this a color LED.""" + + if caps & onlp.onlp.ONLP_LED_CAPS.RED: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.RED_BLINKING: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.ORANGE: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.ORANGE_BLINKING: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.YELLOW: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.YELLOW_BLINKING: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.GREEN: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.GREEN_BLINKING: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.BLUE: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.BLUE_BLINKING: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.PURPLE: + return True + if caps & onlp.onlp.ONLP_LED_CAPS.PURPLE_BLINKING: + return True + + return False def auditLedChar(self, oid): @@ -830,9 +868,8 @@ class LedTest(OnlpTestMixin, libonlp.onlp_led_info_get(oid, ctypes.byref(led)) self.assertEqual(nchar, led.char) - except: + finally: libonlp.onlp_led_char_set(oid, saveChar) - raise def auditLedOnOff(self, oid): @@ -868,12 +905,11 @@ class LedTest(OnlpTestMixin, libonlp.onlp_led_info_get(oid, ctypes.byref(led)) self.assertEqual(onlp.onlp.ONLP_LED_MODE.OFF, led.mode) - except: + finally: if saveMode == onlp.onlp.ONLP_LED_MODE.OFF: libonlp.onlp_led_set(oid, 0) else: libonlp.onlp_led_set(oid, 1) - raise def auditLedColors(self, oid): @@ -924,9 +960,8 @@ class LedTest(OnlpTestMixin, libonlp.onlp_led_info_get(oid, ctypes.byref(led)) self.assertEqual(onlp.onlp.ONLP_LED_MODE.OFF, led.mode) - except: + finally: libonlp.onlp_led_mode_set(oid, saveMode) - raise def auditLedBlink(self, oid): @@ -977,9 +1012,8 @@ class LedTest(OnlpTestMixin, libonlp.onlp_led_info_get(oid, ctypes.byref(led)) self.assertEqual(onlp.onlp.ONLP_LED_MODE.OFF, led.mode) - except: + finally: libonlp.onlp_led_mode_set(oid, saveMode) - raise if __name__ == "__main__": logging.basicConfig() From e5abf25a574eb552777f4e83418c48a6a2dc1130 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 19 Sep 2017 16:56:55 -0700 Subject: [PATCH 11/24] Added bindings for onlp_config.h --- .../src/onlp/module/python/onlp/onlp/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py index 4e9329b9..6d924f16 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -341,6 +341,18 @@ def onlp_led_init_prototypes(): libonlp.onlp_led_show.restype = None libonlp.onlp_led_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) +# onlp/onlp_config.h + +# don't need the actual config structure, since we'll be using lookups + +def onlp_config_init_prototypes(): + + libonlp.onlp_config_lookup.restype = ctypes.c_char_p + libonlp.onlp_config_lookup.argtypes = (ctypes.c_char_p,) + + libonlp.onlp_config_show.restype = ctypes.c_int + libonlp.onlp_config_show.argtypes = (ctypes.POINTER(aim_pvs),) + # onlp/onlp.h def onlp_init(): @@ -351,3 +363,4 @@ def onlp_init(): onlp_sys_init_prototypes() onlp_fan_init_prototypes() onlp_led_init_prototypes() + onlp_config_init_prototypes() From ee34d51928d6fd1179cf6dfb4c1085f5d5e4c7ee Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 19 Sep 2017 16:57:09 -0700 Subject: [PATCH 12/24] config lookup conditional was wrong --- packages/base/any/onlp/src/onlp/module/src/onlp_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_config.c b/packages/base/any/onlp/src/onlp/module/src/onlp_config.c index 7b90cf44..0a2dbe60 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_config.c +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_config.c @@ -145,7 +145,7 @@ onlp_config_lookup(const char* setting) { int i; for(i = 0; onlp_config_settings[i].name; i++) { - if(strcmp(onlp_config_settings[i].name, setting)) { + if(!strcmp(onlp_config_settings[i].name, setting)) { return onlp_config_settings[i].value; } } From 11064e23facec7ed2c9c47a3368bc3806e5d9b66 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 19 Sep 2017 16:57:45 -0700 Subject: [PATCH 13/24] Added tests for onlp_config.h --- .../module/python/onlp/test/OnlpApiTest.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index 6daf811f..dc70d6ff 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -1015,6 +1015,30 @@ class LedTest(OnlpTestMixin, finally: libonlp.onlp_led_mode_set(oid, saveMode) +class ConfigTest(OnlpTestMixin, + unittest.TestCase): + """Test interfaces in onlp/onlp_config.h.""" + + def setUp(self): + OnlpTestMixin.setUp(self) + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testConfig(self): + + s = libonlp.onlp_config_lookup("ONLP_CONFIG_INFO_STR_MAX") + self.assertEqual('64', s) + + s = libonlp.onlp_config_lookup("foo") + self.assertIsNone(s) + + def testConfigShow(self): + + libonlp.onlp_config_show(self.aim_pvs_buffer_p) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + self.assertIn("ONLP_CONFIG_INFO_STR_MAX = 64\n", buf.string_at()) + if __name__ == "__main__": logging.basicConfig() unittest.main() From 7f1f6e5dd491f46182ac37f50f15d34c6e0327cf Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 19 Sep 2017 18:27:48 -0700 Subject: [PATCH 14/24] Added bindings for thermal.h --- .../onlp/module/python/onlp/onlp/__init__.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py index 6d924f16..cd6516de 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -353,6 +353,38 @@ def onlp_config_init_prototypes(): libonlp.onlp_config_show.restype = ctypes.c_int libonlp.onlp_config_show.argtypes = (ctypes.POINTER(aim_pvs),) +# onlp/thermal.h + +class onlp_thermal_info_thresholds(ctypes.Structure): + _fields_ = [('warning', ctypes.c_int,), + ('error', ctypes.c_int,), + ('shutdown', ctypes.c_int,),] + +class onlp_thermal_info(ctypes.Structure): + _fields_ = [('hdr', onlp_oid_hdr,), + ('status', ctypes.c_uint,), + ('caps', ctypes.c_uint,), + ('mcelcius', ctypes.c_int,), + ('thresholds', onlp_thermal_info_thresholds,),] + +def onlp_thermal_init_prototypes(): + + libonlp.onlp_thermal_init.restype = ctypes.c_int + + libonlp.onlp_thermal_info_get.restype = ctypes.c_int + libonlp.onlp_thermal_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_thermal_info),) + + libonlp.onlp_thermal_hdr_get.restype = ctypes.c_int + libonlp.onlp_thermal_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) + + libonlp.onlp_thermal_ioctl.restype = ctypes.c_int + + libonlp.onlp_thermal_dump.restype = None + libonlp.onlp_thermal_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),) + + libonlp.onlp_thermal_show.restype = None + libonlp.onlp_thermal_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),) + # onlp/onlp.h def onlp_init(): @@ -364,3 +396,4 @@ def onlp_init(): onlp_fan_init_prototypes() onlp_led_init_prototypes() onlp_config_init_prototypes() + onlp_thermal_init_prototypes() From 83830a6afafabc17f572d1919080b9aa732d7ebb Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 19 Sep 2017 18:28:13 -0700 Subject: [PATCH 15/24] Unit tests for thermal.h --- .../module/python/onlp/test/OnlpApiTest.py | 84 ++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index dc70d6ff..f751f92d 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -508,7 +508,7 @@ class FanTest(OnlpTestMixin, else: self.log.warn("fan does not support PCT get") - if self.FAN_MODE_VALID: + if self.fan_mode: self.assertNotEqual(onlp.onlp.ONLP_FAN_MODE.OFF, fan.mode) # default, fan should be running @@ -1016,7 +1016,7 @@ class LedTest(OnlpTestMixin, libonlp.onlp_led_mode_set(oid, saveMode) class ConfigTest(OnlpTestMixin, - unittest.TestCase): + unittest.TestCase): """Test interfaces in onlp/onlp_config.h.""" def setUp(self): @@ -1039,6 +1039,86 @@ class ConfigTest(OnlpTestMixin, buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) self.assertIn("ONLP_CONFIG_INFO_STR_MAX = 64\n", buf.string_at()) +class ThermalTest(OnlpTestMixin, + unittest.TestCase): + """Test interfaces in onlp/thermal.h.""" + + def setUp(self): + OnlpTestMixin.setUp(self) + + libonlp.onlp_thermal_init() + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testFindThermal(self): + + class V(OidIterator): + + def __init__(self, log): + super(V, self).__init__(log) + self.oids = [] + + def visit(self, oid, cookie): + self.log.info("found thermal oid %d", oid) + self.oids.append(oid) + return onlp.onlp.ONLP_STATUS.OK + + v = V(log=self.log.getChild("thermal")) + libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, + onlp.onlp.ONLP_OID_TYPE.THERMAL, + v.cvisit(), 0) + self.assert_(v.oids) + + self.auditThermalOid(v.oids[0]) + + def auditThermalOid(self, oid): + + hdr = onlp.onlp.onlp_oid_hdr() + libonlp.onlp_thermal_hdr_get(oid, ctypes.byref(hdr)) + self.assertEqual(oid, hdr._id) + + thm = onlp.onlp.onlp_thermal_info() + libonlp.onlp_thermal_info_get(oid, ctypes.byref(thm)) + + self.assertEqual(oid, thm.hdr._id) + + self.assert_(thm.caps) + # should support some non-empty set of capabilities + + self.assert_(thm.caps & onlp.onlp.ONLP_THERMAL_CAPS.GET_TEMPERATURE) + # sensor should at least report temperature + + self.log.info("auditing thermal %d", + oid & 0xFFFFFF) + + self.assert_(thm.status & onlp.onlp.ONLP_THERMAL_STATUS.PRESENT) + # sensor should be present + + self.assertGreater(thm.mcelcius, 20000) + self.assertLess(thm.mcelcius, 35000) + # temperature should be non-crazy + + # retrieve thermal status separately + sts = ctypes.c_uint() + libonlp.onlp_thermal_status_get(oid, ctypes.byref(sts)) + self.assert_(onlp.onlp.ONLP_THERMAL_STATUS.PRESENT & sts.value) + + # test ioctl + code = libonlp.onlp_thermal_ioctl(9999) + self.assertEqual(onlp.onlp.ONLP_STATUS.E_UNSUPPORTED, code) + + flags = 0 + libonlp.onlp_thermal_dump(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("thermal @", bufStr) + + libonlp.onlp_thermal_show(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("thermal @", bufStr) + if __name__ == "__main__": logging.basicConfig() unittest.main() From f1a53e3c600be92e62b42a1fe246b1c77bc2d3c6 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Thu, 21 Sep 2017 14:42:05 -0700 Subject: [PATCH 16/24] Fixed deadlock --- packages/base/any/onlp/src/onlp/module/src/psu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/any/onlp/src/onlp/module/src/psu.c b/packages/base/any/onlp/src/onlp/module/src/psu.c index 5aaf166c..724ae42f 100644 --- a/packages/base/any/onlp/src/onlp/module/src/psu.c +++ b/packages/base/any/onlp/src/onlp/module/src/psu.c @@ -69,7 +69,7 @@ onlp_psu_status_get_locked__(onlp_oid_t id, uint32_t* status) } if(ONLP_UNSUPPORTED(rv)) { onlp_psu_info_t pi; - rv = onlp_psu_info_get(id, &pi); + rv = onlp_psui_info_get(id, &pi); *status = pi.status; } return rv; From 3ac42136f871d13a66a0cb11cb45e89aabf6855b Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Thu, 21 Sep 2017 14:42:46 -0700 Subject: [PATCH 17/24] Added bindings for psu.h - also cleaned up module init --- .../onlp/module/python/onlp/onlp/__init__.py | 56 ++++++++++++++++++- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py index cd6516de..d6d628f0 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -6,6 +6,7 @@ Module init for onlp.onlp import ctypes libonlp = ctypes.cdll.LoadLibrary("libonlp.so") +libonlp.onlp_init() import ctypes.util libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c")) @@ -113,17 +114,20 @@ def aim_pvs_init_prototypes(): # onlp.yml +##ONLP_CONFIG_INFO_STR_MAX = int(libonlp.onlp_config_lookup("ONLP_CONFIG_INFO_STR_MAX")) ONLP_CONFIG_INFO_STR_MAX = 64 -# XXX roth -- no cdefs support (yet) +# prototype for onlp_config_lookup is not defined yet, see below # onlp/oids.h onlp_oid = ctypes.c_uint ONLP_OID_SYS = (ONLP_OID_TYPE.SYS<<24) | 1 +# XXX not a config option ONLP_OID_DESC_SIZE = 128 ONLP_OID_TABLE_SIZE = 32 +# XXX not a config option class OidTableIterator(object): @@ -374,6 +378,9 @@ def onlp_thermal_init_prototypes(): libonlp.onlp_thermal_info_get.restype = ctypes.c_int libonlp.onlp_thermal_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_thermal_info),) + libonlp.onlp_thermal_status_get.restype = ctypes.c_int + libonlp.onlp_thermal_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint),) + libonlp.onlp_thermal_hdr_get.restype = ctypes.c_int libonlp.onlp_thermal_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) @@ -385,15 +392,58 @@ def onlp_thermal_init_prototypes(): libonlp.onlp_thermal_show.restype = None libonlp.onlp_thermal_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),) +# onlp/psu.h + +class onlp_psu_info(ctypes.Structure): + _fields_ = [("hdr", onlp_oid_hdr,), + ("model", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,), + ("serial", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,), + ("status", ctypes.c_uint,), + ("caps", ctypes.c_uint,), + ("mvin", ctypes.c_int,), + ("mvout", ctypes.c_int,), + ("miin", ctypes.c_int,), + ("miout", ctypes.c_int,), + ("mpin", ctypes.c_int,), + ("mpout", ctypes.c_int,),] + +def onlp_psu_init_prototypes(): + + libonlp.onlp_psu_init.restype = ctypes.c_int + + libonlp.onlp_psu_info_get.restype = ctypes.c_int + libonlp.onlp_psu_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_psu_info),) + + libonlp.onlp_psu_status_get.restype = ctypes.c_int + libonlp.onlp_psu_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint),) + + libonlp.onlp_psu_hdr_get.restype = ctypes.c_int + libonlp.onlp_psu_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) + + libonlp.onlp_psu_ioctl.restype = ctypes.c_int + + libonlp.onlp_psu_dump.restype = None + libonlp.onlp_psu_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),) + + libonlp.onlp_psu_show.restype = None + libonlp.onlp_psu_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),) + # onlp/onlp.h -def onlp_init(): - libonlp.onlp_init() +def init_prototypes(): aim_memory_init_prototypes() aim_pvs_init_prototypes() onlp_oid_init_prototypes() onlp_sys_init_prototypes() onlp_fan_init_prototypes() onlp_led_init_prototypes() + onlp_config_init_prototypes() + + if ONLP_CONFIG_INFO_STR_MAX != int(libonlp.onlp_config_lookup("ONLP_CONFIG_INFO_STR_MAX")): + raise AssertionError("ONLP_CONFIG_INFO_STR_MAX changed") + onlp_thermal_init_prototypes() + onlp_psu_init_prototypes() + +init_prototypes() From ab71552654b56c80734e75dd1aa90447ee0d0b86 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Thu, 21 Sep 2017 14:42:57 -0700 Subject: [PATCH 18/24] Tests for fan.h --- .../module/python/onlp/test/OnlpApiTest.py | 96 ++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index f751f92d..2121474c 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -11,7 +11,6 @@ import time import subprocess import onlp.onlp -onlp.onlp.onlp_init() libonlp = onlp.onlp.libonlp @@ -508,7 +507,7 @@ class FanTest(OnlpTestMixin, else: self.log.warn("fan does not support PCT get") - if self.fan_mode: + if self.FAN_MODE_VALID: self.assertNotEqual(onlp.onlp.ONLP_FAN_MODE.OFF, fan.mode) # default, fan should be running @@ -1119,6 +1118,99 @@ class ThermalTest(OnlpTestMixin, bufStr = buf.string_at() self.assertIn("thermal @", bufStr) +class PsuTest(OnlpTestMixin, + unittest.TestCase): + """Test interfaces in onlp/psu.h.""" + + def setUp(self): + OnlpTestMixin.setUp(self) + + libonlp.onlp_psu_init() + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + def testFindPsu(self): + + class V(OidIterator): + + def __init__(self, log): + super(V, self).__init__(log) + self.oids = [] + + def visit(self, oid, cookie): + self.log.info("found psu oid %d", oid) + self.oids.append(oid) + return onlp.onlp.ONLP_STATUS.OK + + v = V(log=self.log.getChild("psu")) + libonlp.onlp_oid_iterate(onlp.onlp.ONLP_OID_SYS, + onlp.onlp.ONLP_OID_TYPE.PSU, + v.cvisit(), 0) + self.assert_(v.oids) + + self.auditPsuOid(v.oids[0]) + + def auditPsuOid(self, oid): + + hdr = onlp.onlp.onlp_oid_hdr() + libonlp.onlp_psu_hdr_get(oid, ctypes.byref(hdr)) + self.assertEqual(oid, hdr._id) + + psu = onlp.onlp.onlp_psu_info() + libonlp.onlp_psu_info_get(oid, ctypes.byref(psu)) + + self.assertEqual(oid, psu.hdr._id) + + self.assert_(psu.caps + & (onlp.onlp.ONLP_PSU_CAPS.AC + | onlp.onlp.ONLP_PSU_CAPS.DC12 + | onlp.onlp.ONLP_PSU_CAPS.DC48)) + # should support some non-empty set of capabilities + + self.log.info("auditing psu %d", + oid & 0xFFFFFF) + + self.assert_(psu.status & onlp.onlp.ONLP_PSU_STATUS.PRESENT) + # sensor should be present + + if (psu.caps + & onlp.onlp.ONLP_PSU_CAPS.AC + & onlp.onlp.ONLP_PSU_CAPS.VOUT): + self.assertGreater(psu.mvout, 100000) + self.assertLess(psu.mvout, 125000) + if (psu.caps + & onlp.onlp.ONLP_PSU_CAPS.DC12 + & onlp.onlp.ONLP_PSU_CAPS.VOUT): + self.assertGreater(psu.mvout, 11000) + self.assertLess(psu.mvout, 13000) + if (psu.caps + & onlp.onlp.ONLP_PSU_CAPS.DC48 + & onlp.onlp.ONLP_PSU_CAPS.VOUT): + self.assertGreater(psu.mvout, 47000) + self.assertLess(psu.mvout, 49000) + # output voltage should be non-crazy + + # retrieve psu status separately + sts = ctypes.c_uint() + libonlp.onlp_psu_status_get(oid, ctypes.byref(sts)) + self.assert_(onlp.onlp.ONLP_PSU_STATUS.PRESENT & sts.value) + + # test ioctl + code = libonlp.onlp_psu_ioctl(9999) + self.assertEqual(onlp.onlp.ONLP_STATUS.E_UNSUPPORTED, code) + + flags = 0 + libonlp.onlp_psu_dump(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("psu @", bufStr) + + libonlp.onlp_psu_show(oid, self.aim_pvs_buffer_p, flags) + buf = libonlp.aim_pvs_buffer_get(self.aim_pvs_buffer_p) + bufStr = buf.string_at() + self.assertIn("psu @", bufStr) + if __name__ == "__main__": logging.basicConfig() unittest.main() From db1d98dea09d102dfcb9bb1a60aeff7429e82caf Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 27 Sep 2017 16:10:16 -0700 Subject: [PATCH 19/24] Updated strcmp for enum lookup --- packages/base/any/onlp/src/sff/module/src/sff_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/any/onlp/src/sff/module/src/sff_config.c b/packages/base/any/onlp/src/sff/module/src/sff_config.c index 400b7a72..cf770933 100644 --- a/packages/base/any/onlp/src/sff/module/src/sff_config.c +++ b/packages/base/any/onlp/src/sff/module/src/sff_config.c @@ -70,7 +70,7 @@ sff_config_lookup(const char* setting) { int i; for(i = 0; sff_config_settings[i].name; i++) { - if(strcmp(sff_config_settings[i].name, setting)) { + if(!strcmp(sff_config_settings[i].name, setting)) { return sff_config_settings[i].value; } } From ea2c56af005d924eae72c0c36e57c8ac3c6005f5 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 27 Sep 2017 16:10:48 -0700 Subject: [PATCH 20/24] Wrap the sff module --- .../base/any/onlp/src/sff/module/auto/make.mk | 2 +- .../base/any/onlp/src/sff/module/auto/sff.yml | 2 + .../sff/module/python/onlp/sff/__init__.py | 34 +++++++++ .../src/sff/module/python/onlp/sff/enums.py | 70 +++++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 packages/base/any/onlp/src/sff/module/python/onlp/sff/__init__.py create mode 100644 packages/base/any/onlp/src/sff/module/python/onlp/sff/enums.py diff --git a/packages/base/any/onlp/src/sff/module/auto/make.mk b/packages/base/any/onlp/src/sff/module/auto/make.mk index 1232f5e6..88b2ad6f 100644 --- a/packages/base/any/onlp/src/sff/module/auto/make.mk +++ b/packages/base/any/onlp/src/sff/module/auto/make.mk @@ -4,6 +4,6 @@ # ############################################################################### sff_AUTO_DEFS := module/auto/sff.yml -sff_AUTO_DIRS := module/inc/sff module/src +sff_AUTO_DIRS := module/inc/sff module/src module/python/onlp/sff include $(BUILDER)/auto.mk diff --git a/packages/base/any/onlp/src/sff/module/auto/sff.yml b/packages/base/any/onlp/src/sff/module/auto/sff.yml index 295fe6bf..1cb31d4d 100644 --- a/packages/base/any/onlp/src/sff/module/auto/sff.yml +++ b/packages/base/any/onlp/src/sff/module/auto/sff.yml @@ -152,6 +152,8 @@ definitions: sff_media_type: members: *sff_media_types + pyenum: *enums + xenum: SFF_ENUMERATION_ENTRY: members: *enums diff --git a/packages/base/any/onlp/src/sff/module/python/onlp/sff/__init__.py b/packages/base/any/onlp/src/sff/module/python/onlp/sff/__init__.py new file mode 100644 index 00000000..f6028f01 --- /dev/null +++ b/packages/base/any/onlp/src/sff/module/python/onlp/sff/__init__.py @@ -0,0 +1,34 @@ +"""__init__.py + +Module init for onlp/sff +""" + +from onlp.sff.enums import * + +import ctypes + +sff_media_type = ctypes.c_int +sff_module_caps = ctypes.c_int +sff_module_type = ctypes.c_int +sff_sfp_type = ctypes.c_int + +class sff_info(ctypes.Structure): + _fields_ = [("vendor", ctypes.c_char * 17), + ("model", ctypes.c_char * 17), + ("serial", ctypes.c_char * 17), + ("sfp_type", sff_sfp_type), + ("sfp_type_name", ctypes.c_char_p), + ("module_type", sff_module_type), + ("module_type_name", ctypes.c_char_p), + ("media_type", sff_media_type), + ("media_type_name", ctypes.c_char_p), + ("caps", sff_module_caps), + ("length", ctypes.c_int), + ("desc", ctypes.c_char * 16),] + +class sff_eeprom(ctypes.Structure): + _fields_ = [("eeprom", ctypes.c_ubyte * 256), + ("cc_base", ctypes.c_ubyte), + ("cc_ext", ctypes.c_ubyte), + ("identified", ctypes.c_int), + ("info", sff_info),] diff --git a/packages/base/any/onlp/src/sff/module/python/onlp/sff/enums.py b/packages/base/any/onlp/src/sff/module/python/onlp/sff/enums.py new file mode 100644 index 00000000..5499f7cd --- /dev/null +++ b/packages/base/any/onlp/src/sff/module/python/onlp/sff/enums.py @@ -0,0 +1,70 @@ +"""enums.py + +Enumerations from the SFF auto.yml. +""" + +class Enumeration(object): + @classmethod + def name(klass, value): + for (k, v) in klass.__dict__.iteritems(): + if v == value: + return k + return None + +# +class SFF_MEDIA_TYPE(Enumeration): + COPPER = 0 + FIBER = 1 + + +class SFF_MODULE_CAPS(Enumeration): + F_100 = 1 + F_1G = 2 + F_10G = 4 + F_25G = 8 + F_40G = 16 + F_100G = 32 + + +class SFF_MODULE_TYPE(Enumeration): + _100G_AOC = 0 + _100G_BASE_CR4 = 1 + _100G_BASE_SR4 = 2 + _100G_BASE_LR4 = 3 + _100G_CWDM4 = 4 + _100G_PSM4 = 5 + _40G_BASE_CR4 = 6 + _40G_BASE_SR4 = 7 + _40G_BASE_LR4 = 8 + _40G_BASE_LM4 = 9 + _40G_BASE_ACTIVE = 10 + _40G_BASE_CR = 11 + _40G_BASE_SR2 = 12 + _40G_BASE_SM4 = 13 + _40G_BASE_ER4 = 14 + _25G_BASE_CR = 15 + _10G_BASE_SR = 16 + _10G_BASE_LR = 17 + _10G_BASE_LRM = 18 + _10G_BASE_ER = 19 + _10G_BASE_CR = 20 + _10G_BASE_SX = 21 + _10G_BASE_LX = 22 + _10G_BASE_ZR = 23 + _10G_BASE_SRL = 24 + _1G_BASE_SX = 25 + _1G_BASE_LX = 26 + _1G_BASE_CX = 27 + _1G_BASE_T = 28 + _100_BASE_LX = 29 + _100_BASE_FX = 30 + _4X_MUX = 31 + + +class SFF_SFP_TYPE(Enumeration): + SFP = 0 + QSFP = 1 + QSFP_PLUS = 2 + QSFP28 = 3 + +# From adbc8cc62aaac78300a571c016b50a4683527214 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 27 Sep 2017 16:14:18 -0700 Subject: [PATCH 21/24] Added Sfp.h and sff.h support - fix references to uint32 - add enough bitmap support to handle SFP bitmaps --- .../onlp/module/python/onlp/onlp/__init__.py | 265 ++++++++++++++++-- 1 file changed, 234 insertions(+), 31 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py index d6d628f0..022764e4 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/onlp/__init__.py @@ -12,6 +12,7 @@ import ctypes.util libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c")) import onlp.onlplib +import onlp.sff from onlp.onlp.enums import * @@ -93,7 +94,7 @@ class aim_pvs(ctypes.Structure): ("description", ctypes.c_char_p,), ("vprintf", aim_vprintf_f,), ("enabled", ctypes.c_int,), - ("counter", ctypes.c_uint,), + ("counter", ctypes.c_uint32,), ("isatty", aim_vprintf_f,),] def aim_pvs_init_prototypes(): @@ -112,6 +113,102 @@ def aim_pvs_init_prototypes(): libonlp.aim_pvs_buffer_reset.restype = None libonlp.aim_pvs_buffer_reset.argtypes = (ctypes.POINTER(aim_pvs),) +# AIM/aim_bitmap.h + +aim_bitmap_word = ctypes.c_uint32 +AIM_BITMAP_BITS_PER_WORD = 32 + +def AIM_BITMAP_WORD_COUNT(bitcount): + return ((bitcount // AIM_BITMAP_BITS_PER_WORD) + + (1 if (bitcount % AIM_BITMAP_BITS_PER_WORD) else 0)) + +# ugh, most of aim_bitmap.h is inline C + +def AIM_BITMAP_HDR_WORD_GET(hdr, word): + """Return a specific ctypes word.""" + return hdr.words[word] + +def AIM_BITMAP_HDR_BIT_WORD_GET(hdr, bit): + """Return the ctypes word holding this bit.""" + return hdr.words[bit/AIM_BITMAP_BITS_PER_WORD] + +def AIM_BITMAP_HDR_BIT_WORD_SET(hdr, bit, word): + """Return the ctypes word holding this bit.""" + hdr.words[bit/AIM_BITMAP_BITS_PER_WORD] = word + +def AIM_BITMAP_BIT_POS(bit): + return (1<<(bit % AIM_BITMAP_BITS_PER_WORD)) + +def AIM_BITMAP_INIT(bitmap, count): + """Initialize a static bitmap.""" + libc.memset(ctypes.byref(bitmap), 0, ctypes.sizeof(bitmap)) + bitmap.hdr.maxbit = count + bitmap.hdr.words = ctypes.cast(ctypes.byref(bitmap.words), ctypes.POINTER(ctypes.c_uint)) + bitmap.hdr.wordcount = AIM_BITMAP_WORD_COUNT(count) + +class aim_bitmap_hdr(ctypes.Structure): + _fields_ = [("wordcount", ctypes.c_int,), + ("words", ctypes.POINTER(aim_bitmap_word),), + ("maxbit", ctypes.c_int,), + ("allocated", ctypes.c_int,),] + +class aim_bitmap(ctypes.Structure): + _fields_ = [("hdr", aim_bitmap_hdr,),] + + @classmethod + def fromAim(cls, bitcount): + """Return a pointer to a bitmap from aim_alloc(). + + Pre-initialized; needs to be freed with aim_free(). + """ + return libonlp.aim_bitmap_alloc(None, bitcount) + +class aim_bitmap256(aim_bitmap): + """Statically-allocated AIM bitmap.""" + _fields_ = [("words", aim_bitmap_word * AIM_BITMAP_WORD_COUNT(256),),] + + def __init__(self): + super(aim_bitmap256, self).__init__() + AIM_BITMAP_INIT(self, 255) + +def aim_bitmap_set(hdr, bit): + word = AIM_BITMAP_HDR_BIT_WORD_GET(hdr, bit) + word |= AIM_BITMAP_BIT_POS(bit) + AIM_BITMAP_HDR_BIT_WORD_SET(hdr, bit, word) + +def aim_bitmap_clr(hdr, bit): + word = AIM_BITMAP_HDR_BIT_WORD_GET(hdr, bit) + word &= ~(AIM_BITMAP_BIT_POS(bit)) + AIM_BITMAP_HDR_BIT_WORD_SET(hdr, bit, word) + +def aim_bitmap_mod(hdr, bit, value): + if value: + aim_bitmap_set(hdr, bit) + else: + aim_bitmap_clr(hdr, bit) + +def aim_bitmap_get(hdr, bit): + val = AIM_BITMAP_HDR_BIT_WORD_GET(hdr,bit) & AIM_BITMAP_BIT_POS(bit) + return 1 if val else 0 + +# Huh, these is inline too, but calls into glibc memset + +def aim_bitmap_set_all(hdr): + libc.memset(ctypes.byref(hdr.words), 0xFF, hdr.wordcount*ctypes.sizeof(aim_bitmap_word)) + +def aim_bitmap_clr_all(hdr): + libc.memset(ctypes.byref(hdr.words), 0x00, hdr.wordcount*ctypes.sizeof(aim_bitmap_word)) + +# XXX aim_bitmap_count is left out + +def aim_bitmap_init_prototypes(): + + libonlp.aim_bitmap_alloc.restype = ctypes.POINTER(aim_bitmap) + libonlp.aim_bitmap_alloc.argtypes = (ctypes.POINTER(aim_bitmap), ctypes.c_int,) + + libonlp.aim_bitmap_free.restype = None + libonlp.aim_bitmap_free.argtypes = (ctypes.POINTER(aim_bitmap),) + # onlp.yml ##ONLP_CONFIG_INFO_STR_MAX = int(libonlp.onlp_config_lookup("ONLP_CONFIG_INFO_STR_MAX")) @@ -120,7 +217,7 @@ ONLP_CONFIG_INFO_STR_MAX = 64 # onlp/oids.h -onlp_oid = ctypes.c_uint +onlp_oid = ctypes.c_uint32 ONLP_OID_SYS = (ONLP_OID_TYPE.SYS<<24) | 1 # XXX not a config option @@ -182,16 +279,16 @@ onlp_oid_iterate_f = ctypes.CFUNCTYPE(ctypes.c_int, onlp_oid, ctypes.c_void_p) def onlp_oid_init_prototypes(): libonlp.onlp_oid_dump.restype = None - libonlp.onlp_oid_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_oid_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,) libonlp.onlp_oid_table_dump.restype = None - libonlp.onlp_oid_table_dump.argtypes = (ctypes.POINTER(onlp_oid), ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_oid_table_dump.argtypes = (ctypes.POINTER(onlp_oid), ctypes.POINTER(aim_pvs), ctypes.c_uint32,) libonlp.onlp_oid_show.restype = None - libonlp.onlp_oid_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_oid_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,) libonlp.onlp_oid_table_show.restype = None - libonlp.onlp_oid_table_show.argtypes = (ctypes.POINTER(onlp_oid), ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_oid_table_show.argtypes = (ctypes.POINTER(onlp_oid), ctypes.POINTER(aim_pvs), ctypes.c_uint32,) libonlp.onlp_oid_iterate.restype = ctypes.c_int libonlp.onlp_oid_iterate.argtypes = (onlp_oid, ctypes.c_int, @@ -228,10 +325,10 @@ def onlp_sys_init_prototypes(): libonlp.onlp_sys_hdr_get.argtypes = (ctypes.POINTER(onlp_oid_hdr),) libonlp.onlp_sys_dump.restype = None - libonlp.onlp_sys_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_sys_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,) libonlp.onlp_sys_show.restype = None - libonlp.onlp_sys_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_sys_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,) libonlp.onlp_sys_ioctl.restype = ctypes.c_int # leave the parameters empty (varargs) @@ -257,11 +354,11 @@ def onlp_sys_init_prototypes(): class onlp_fan_info(ctypes.Structure): _fields_ = [("hdr", onlp_oid_hdr,), - ("status", ctypes.c_uint,), - ("caps", ctypes.c_uint,), + ("status", ctypes.c_uint32,), + ("caps", ctypes.c_uint32,), ("rpm", ctypes.c_int,), ("percentage", ctypes.c_int,), - ("mode", ctypes.c_uint,), + ("mode", ctypes.c_uint32,), ("model", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,), ("serial", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,),] @@ -285,7 +382,7 @@ def onlp_fan_init_prototypes(): libonlp.onlp_fan_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_fan_info),) libonlp.onlp_fan_status_get.restype = ctypes.c_int - libonlp.onlp_fan_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint),) + libonlp.onlp_fan_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint32),) libonlp.onlp_fan_hdr_get.restype = ctypes.c_int libonlp.onlp_fan_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) @@ -297,24 +394,24 @@ def onlp_fan_init_prototypes(): libonlp.onlp_fan_percentage_set.argtypes = (onlp_oid, ctypes.c_int,) libonlp.onlp_fan_mode_set.restype = ctypes.c_int - libonlp.onlp_fan_mode_set.argtypes = (onlp_oid, ctypes.c_uint,) + libonlp.onlp_fan_mode_set.argtypes = (onlp_oid, ctypes.c_uint32,) libonlp.onlp_fan_dir_set.restype = ctypes.c_int - libonlp.onlp_fan_dir_set.argtypes = (onlp_oid, ctypes.c_uint,) + libonlp.onlp_fan_dir_set.argtypes = (onlp_oid, ctypes.c_uint32,) libonlp.onlp_fan_dump.restype = None - libonlp.onlp_fan_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_fan_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,) libonlp.onlp_fan_show.restype = None - libonlp.onlp_fan_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_fan_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,) # onlp/led.h class onlp_led_info(ctypes.Structure): _fields_ = [("hdr", onlp_oid_hdr,), - ("status", ctypes.c_uint,), - ("caps", ctypes.c_uint,), - ("mode", ctypes.c_uint,), + ("status", ctypes.c_uint32,), + ("caps", ctypes.c_uint32,), + ("mode", ctypes.c_uint32,), ("character", ctypes.c_char,),] def onlp_led_init_prototypes(): @@ -325,7 +422,7 @@ def onlp_led_init_prototypes(): libonlp.onlp_led_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_led_info),) libonlp.onlp_led_status_get.restype = ctypes.c_int - libonlp.onlp_led_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint),) + libonlp.onlp_led_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint32),) libonlp.onlp_led_hdr_get.restype = ctypes.c_int libonlp.onlp_led_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) @@ -334,16 +431,16 @@ def onlp_led_init_prototypes(): libonlp.onlp_led_set.argtypes = (onlp_oid, ctypes.c_int,) libonlp.onlp_led_mode_set.restype = ctypes.c_int - libonlp.onlp_led_mode_set.argtypes = (onlp_oid, ctypes.c_uint,) + libonlp.onlp_led_mode_set.argtypes = (onlp_oid, ctypes.c_uint32,) libonlp.onlp_led_char_set.restype = ctypes.c_int libonlp.onlp_led_char_set.argtypes = (onlp_oid, ctypes.c_char,) libonlp.onlp_led_dump.restype = None - libonlp.onlp_led_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_led_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,) libonlp.onlp_led_show.restype = None - libonlp.onlp_led_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint,) + libonlp.onlp_led_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,) # onlp/onlp_config.h @@ -366,8 +463,8 @@ class onlp_thermal_info_thresholds(ctypes.Structure): class onlp_thermal_info(ctypes.Structure): _fields_ = [('hdr', onlp_oid_hdr,), - ('status', ctypes.c_uint,), - ('caps', ctypes.c_uint,), + ('status', ctypes.c_uint32,), + ('caps', ctypes.c_uint32,), ('mcelcius', ctypes.c_int,), ('thresholds', onlp_thermal_info_thresholds,),] @@ -379,7 +476,7 @@ def onlp_thermal_init_prototypes(): libonlp.onlp_thermal_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_thermal_info),) libonlp.onlp_thermal_status_get.restype = ctypes.c_int - libonlp.onlp_thermal_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint),) + libonlp.onlp_thermal_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint32),) libonlp.onlp_thermal_hdr_get.restype = ctypes.c_int libonlp.onlp_thermal_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) @@ -398,8 +495,8 @@ class onlp_psu_info(ctypes.Structure): _fields_ = [("hdr", onlp_oid_hdr,), ("model", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,), ("serial", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,), - ("status", ctypes.c_uint,), - ("caps", ctypes.c_uint,), + ("status", ctypes.c_uint32,), + ("caps", ctypes.c_uint32,), ("mvin", ctypes.c_int,), ("mvout", ctypes.c_int,), ("miin", ctypes.c_int,), @@ -415,7 +512,7 @@ def onlp_psu_init_prototypes(): libonlp.onlp_psu_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_psu_info),) libonlp.onlp_psu_status_get.restype = ctypes.c_int - libonlp.onlp_psu_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint),) + libonlp.onlp_psu_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint32),) libonlp.onlp_psu_hdr_get.restype = ctypes.c_int libonlp.onlp_psu_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),) @@ -428,11 +525,113 @@ def onlp_psu_init_prototypes(): libonlp.onlp_psu_show.restype = None libonlp.onlp_psu_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),) +# sff/sff.h + +def sff_init_prototypes(): + + libonlp.sff_sfp_type_get.restype = onlp.sff.sff_sfp_type + libonlp.sff_sfp_type_get.argtypes = (ctypes.POINTER(ctypes.c_ubyte),) + + libonlp.sff_module_type_get.restype = onlp.sff.sff_module_type + libonlp.sff_module_type_get.argtypes = (ctypes.POINTER(ctypes.c_ubyte),) + + libonlp.sff_media_type_get.restype = onlp.sff.sff_media_type + libonlp.sff_media_type_get.argtypes = (onlp.sff.sff_module_type,) + + libonlp.sff_module_caps_get.restype = ctypes.c_int + libonlp.sff_module_caps_get.argtypes = (onlp.sff.sff_module_type, ctypes.POINTER(ctypes.c_uint32),) + + libonlp.sff_eeprom_parse.restype = ctypes.c_int + libonlp.sff_eeprom_parse.argtypes = (ctypes.POINTER(onlp.sff.sff_eeprom), ctypes.POINTER(ctypes.c_ubyte),) + + libonlp.sff_eeprom_parse_file.restype = ctypes.c_int + libonlp.sff_eeprom_parse_file.argtypes = (ctypes.POINTER(onlp.sff.sff_eeprom), ctypes.c_char_p,) + + libonlp.sff_eeprom_invalidate.restype = None + libonlp.sff_eeprom_invalidate.argtypes = (ctypes.POINTER(onlp.sff.sff_eeprom),) + + libonlp.sff_eeprom_validate.restype = ctypes.c_int + libonlp.sff_eeprom_validate.argtypes = (ctypes.POINTER(onlp.sff.sff_eeprom), ctypes.c_int,) + + libonlp.sff_info_show.restype = None + libonlp.sff_info_show.argtypes = (ctypes.POINTER(onlp.sff.sff_info), ctypes.POINTER(aim_pvs),) + + libonlp.sff_info_init.restype = ctypes.c_int + libonlp.sff_info_init.argtypes = (ctypes.POINTER(onlp.sff.sff_info), onlp.sff.sff_module_type, + ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, + ctypes.c_int,) + +# onlp/sff.h + +onlp_sfp_bitmap = aim_bitmap256 + +onlp_sfp_control = ctypes.c_int + +def onlp_sfp_init_prototypes(): + + libonlp.onlp_sfp_init.restype = ctypes.c_int + + libonlp.onlp_sfp_bitmap_t_init.restype = None + libonlp.onlp_sfp_bitmap_t_init.argtypes = (ctypes.POINTER(onlp_sfp_bitmap),) + + libonlp.onlp_sfp_bitmap_get.restype = ctypes.c_int + libonlp.onlp_sfp_bitmap_get.argtypes = (ctypes.POINTER(onlp_sfp_bitmap),) + + libonlp.onlp_sfp_port_valid.restype = ctypes.c_int + libonlp.onlp_sfp_port_valid.argtypes = (ctypes.c_int,) + + libonlp.onlp_sfp_is_present.restype = ctypes.c_int + libonlp.onlp_sfp_is_present.argtypes = (ctypes.c_int,) + + libonlp.onlp_sfp_presence_bitmap_get.restype = ctypes.c_int + libonlp.onlp_sfp_presence_bitmap_get.argtypes = (ctypes.POINTER(onlp_sfp_bitmap),) + + libonlp.onlp_sfp_eeprom_read.restype = ctypes.c_int + libonlp.onlp_sfp_eeprom_read.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte,)),) + + libonlp.onlp_sfp_dom_read.restype = ctypes.c_int + libonlp.onlp_sfp_dom_read.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)),) + + libonlp.onlp_sfp_denit.restype = ctypes.c_int + + libonlp.onlp_sfp_rx_los_bitmap_get.restype = ctypes.c_int + libonlp.onlp_sfp_rx_los_bitmap_get.argtypes = (ctypes.POINTER(onlp_sfp_bitmap),) + + libonlp.onlp_sfp_dev_readb.restype = ctypes.c_int + libonlp.onlp_sfp_dev_readb.argtypes = (ctypes.c_int, ctypes.c_ubyte, ctypes.c_ubyte,) + + libonlp.onlp_sfp_dev_writeb.restype = ctypes.c_int + libonlp.onlp_sfp_dev_writeb.argtypes = (ctypes.c_int, ctypes.c_ubyte, ctypes.c_ubyte, ctypes.c_ubyte) + + libonlp.onlp_sfp_dev_readw.restype = ctypes.c_int + libonlp.onlp_sfp_dev_readw.argtypes = (ctypes.c_int, ctypes.c_ubyte, ctypes.c_ubyte,) + + libonlp.onlp_sfp_dev_writew.restype = ctypes.c_int + libonlp.onlp_sfp_dev_writew.argtypes = (ctypes.c_int, ctypes.c_ubyte, ctypes.c_ubyte, ctypes.c_ushort) + + libonlp.onlp_sfp_dump.restype = None + libonlp.onlp_sfp_dump.argtypes = (ctypes.POINTER(aim_pvs),) + + libonlp.onlp_sfp_ioctl.restype = ctypes.c_int + + libonlp.onlp_sfp_post_insert.restype = ctypes.c_int + libonlp.onlp_sfp_post_insert.argtypes = (ctypes.c_int, ctypes.POINTER(onlp.sff.sff_info),) + + libonlp.onlp_sfp_control_set.restype = ctypes.c_int + libonlp.onlp_sfp_control_set.argtypes = (ctypes.c_int, onlp_sfp_control, ctypes.c_int,) + + libonlp.onlp_sfp_control_get.restype = ctypes.c_int + libonlp.onlp_sfp_control_get.argtypes = (ctypes.c_int, onlp_sfp_control, ctypes.POINTER(ctypes.c_int)) + + libonlp.onlp_sfp_control_flags_get.restype = ctypes.c_int + libonlp.onlp_sfp_control_flags_get.argtyeps = (ctypes.c_int, ctypes.POINTER(ctypes.c_uint32),) + # onlp/onlp.h def init_prototypes(): aim_memory_init_prototypes() aim_pvs_init_prototypes() + aim_bitmap_init_prototypes() onlp_oid_init_prototypes() onlp_sys_init_prototypes() onlp_fan_init_prototypes() @@ -440,10 +639,14 @@ def init_prototypes(): onlp_config_init_prototypes() - if ONLP_CONFIG_INFO_STR_MAX != int(libonlp.onlp_config_lookup("ONLP_CONFIG_INFO_STR_MAX")): - raise AssertionError("ONLP_CONFIG_INFO_STR_MAX changed") + strMax = int(libonlp.onlp_config_lookup("ONLP_CONFIG_INFO_STR_MAX")) + if ONLP_CONFIG_INFO_STR_MAX != strMax: + raise AssertionError("ONLP_CONFIG_INFO_STR_MAX changed from %d to %d" + % (ONLP_CONFIG_INFO_STR_MAX, strMax,)) onlp_thermal_init_prototypes() onlp_psu_init_prototypes() + sff_init_prototypes() + onlp_sfp_init_prototypes() init_prototypes() From ee9062a361e4089de6a20cc78a4a0e744255821e Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 27 Sep 2017 16:14:33 -0700 Subject: [PATCH 22/24] Wrap the sff module --- packages/base/any/onlp/APKG.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/base/any/onlp/APKG.yml b/packages/base/any/onlp/APKG.yml index 7ab08aa3..4597e63d 100644 --- a/packages/base/any/onlp/APKG.yml +++ b/packages/base/any/onlp/APKG.yml @@ -31,6 +31,7 @@ packages: ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/onlp: ${PY_INSTALL}/onlp/onlp ${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/test: ${PY_INSTALL}/onlp/test ${ONL}/packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib: ${PY_INSTALL}/onlp/onlplib + ${ONL}/packages/base/any/onlp/src/sff/module/python/onlp/sff: ${PY_INSTALL}/onlp/sff init: $ONL/packages/base/any/onlp/src/onlpd.init From 0f659905a78743910fda6e461976d741a9de207a Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 27 Sep 2017 16:14:55 -0700 Subject: [PATCH 23/24] Test sfp.h and sff.h --- .../module/python/onlp/test/OnlpApiTest.py | 315 ++++++++++++++++++ 1 file changed, 315 insertions(+) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index 2121474c..57fd82a8 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -9,8 +9,12 @@ import logging import re import time import subprocess +import random +import tempfile +import os import onlp.onlp +import onlp.sff libonlp = onlp.onlp.libonlp @@ -1211,6 +1215,317 @@ class PsuTest(OnlpTestMixin, bufStr = buf.string_at() self.assertIn("psu @", bufStr) +class Eeprom(ctypes.Structure): + _fields_ = [('eeprom', ctypes.c_ubyte * 256,),] + +class SfpTest(OnlpTestMixin, + unittest.TestCase): + """Test interfaces in onlp/psu.h.""" + + def setUp(self): + OnlpTestMixin.setUp(self) + + libonlp.onlp_sfp_init() + + self.bitmap = onlp.onlp.aim_bitmap256() + + def tearDown(self): + OnlpTestMixin.tearDown(self) + + libonlp.onlp_sfp_denit() + + def bitmap2list(self, bitmap=None): + outBits = [] + bitmap = bitmap or self.bitmap + for pos in range(256): + outBits.append(onlp.onlp.aim_bitmap_get(bitmap.hdr, pos)) + return outBits + + def testBitmap(self): + """Verify that our aim_bitmap implementation is sound.""" + + refBits = [] + for pos in range(256): + val = random.randint(0, 1) + refBits.append(val) + onlp.onlp.aim_bitmap_mod(self.bitmap.hdr, pos, val) + + for i in range(1000): + pos = random.randint(0, 255) + val = refBits[pos] ^ 1 + refBits[pos] = val + onlp.onlp.aim_bitmap_mod(self.bitmap.hdr, pos, val) + + self.assertEqual(refBits, self.bitmap2list()) + + refBits = [0] * 256 + libonlp.onlp_sfp_bitmap_t_init(ctypes.byref(self.bitmap)) + self.assertEqual(refBits, self.bitmap2list()) + + def testValid(self): + """Test for valid SFP ports.""" + + libonlp.onlp_sfp_bitmap_t_init(ctypes.byref(self.bitmap)) + sts = libonlp.onlp_sfp_bitmap_get(ctypes.byref(self.bitmap)) + self.assertStatusOK(sts) + refBits = [0] * 256 + + ports = [x[0] for x in enumerate(self.bitmap2list()) if x[1]] + self.log.info("found %d SFP ports", len(ports)) + self.assert_(ports) + + self.assertEqual(0, ports[0]) + self.assertEqual(len(ports)-1, ports[-1]) + # make sure the ports are contiguous, starting from 1 + + # make sure the per-port valid bits are correct + for i in range(256): + valid = libonlp.onlp_sfp_port_valid(i) + if i < len(ports): + self.assertEqual(1, valid) + else: + self.assertEqual(0, valid) + + # see if any of them are present + # XXX this test requires at least one of the SFPs to be present. + bm = onlp.onlp.aim_bitmap256() + sts = libonlp.onlp_sfp_presence_bitmap_get(ctypes.byref(bm)) + self.assertStatusOK(sts) + present = [x[0] for x in enumerate(self.bitmap2list(bm)) if x[1]] + self.log.info("found %d SFPs", len(present)) + self.assert_(present) + + presentSet = set(present) + portSet = set(ports) + + for port in presentSet: + if port not in portSet: + raise AssertionError("invalid SFP %d not valid" + % (port,)) + + for i in range(256): + valid = libonlp.onlp_sfp_is_present(i) + if i in presentSet: + self.assertEqual(1, valid) + elif i in portSet: + self.assertEqual(0, valid) + else: + self.assertGreater(0, valid) + + # test the rx_los bitmap + # (tough to be more detailed since it depends on connectivity) + sts = libonlp.onlp_sfp_rx_los_bitmap_get(ctypes.byref(bm)) + if sts != onlp.onlp.ONLP_STATUS.E_UNSUPPORTED: + self.assertStatusOK(sts) + rxLos = [x[0] for x in enumerate(self.bitmap2list(bm)) if x[1]] + + # any port exhibiting rx_los should actually be a port + for i in rxLos: + self.assertIn(i, portSet) + + # any missing SFP should *NOT* be exhibiting rx_los + rxLosSet = set(rxLos) + for i in portSet: + if not i in presentSet: + self.assertNotIn(i, rxLosSet) + + port = ports[0] + + self.auditIoctl(port) + self.auditControl(port) + + eeprom = ctypes.POINTER(ctypes.c_ubyte)() + sts = libonlp.onlp_sfp_eeprom_read(port, ctypes.byref(eeprom)) + self.assertStatusOK(sts) + + try: + + # try to read in the data manually + for i in range(128): + b = libonlp.onlp_sfp_dev_readb(port, 0x50, i) + if b != eeprom[i]: + raise AssertionError("eeprom mismatch at 0x50.%d" % i) + + monType = eeprom[92] & 0x40 + # See e.g. https://www.optcore.net/wp-content/uploads/2017/04/SFF_8472.pdf + + self.auditEeprom(eeprom) + + finally: + ptr = onlp.onlp.aim_void_p(ctypes.cast(eeprom, ctypes.c_void_p).value) + del ptr + + if monType: + + domData = ctypes.POINTER(ctypes.c_ubyte)() + sts = libonlp.onlp_sfp_dom_read(port, ctypes.byref(domData)) + self.assertStatusOK(sts) + + try: + self.auditDom(domData) + finally: + ptr = onlp.onlp.aim_void_p(ctypes.cast(domData, ctypes.c_void_p).value) + del ptr + + def auditEeprom(self, eeprom): + """Audit that the entries for this SFP are valid.""" + + sffEeprom = onlp.sff.sff_eeprom() + sts = libonlp.sff_eeprom_parse(ctypes.byref(sffEeprom), eeprom) + self.assertStatusOK(sts) + + self.assertEqual(1, sffEeprom.identified) + + # XXX info strings include space padding + vendor = sffEeprom.info.vendor.strip() + self.assert_(vendor) + model = sffEeprom.info.model.strip() + self.assert_(model) + serial = sffEeprom.info.serial.strip() + self.assert_(serial) + + self.log.info("found SFP: %s %s (S/N %s)", + vendor, model, serial) + + self.log.info("%s (%s %s)", + sffEeprom.info.module_type_name, + sffEeprom.info.media_type_name, + sffEeprom.info.sfp_type_name) + + sffType = libonlp.sff_sfp_type_get(eeprom) + self.assertEqual(sffType, sffEeprom.info.sfp_type) + + moduleType = libonlp.sff_module_type_get(eeprom) + self.assertEqual(moduleType, sffEeprom.info.module_type) + + mediaType = libonlp.sff_media_type_get(sffEeprom.info.module_type) + self.assertEqual(mediaType, sffEeprom.info.media_type) + + caps = ctypes.c_uint32() + sts = libonlp.sff_module_caps_get(sffEeprom.info.module_type, ctypes.byref(caps)) + self.assertStatusOK(sts) + self.assert_(caps) + cl = [] + for i in range(32): + fl = 1< Date: Wed, 27 Sep 2017 17:02:00 -0700 Subject: [PATCH 24/24] typos --- .../any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py index 57fd82a8..121ae40d 100644 --- a/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py +++ b/packages/base/any/onlp/src/onlp/module/python/onlp/test/OnlpApiTest.py @@ -1220,7 +1220,7 @@ class Eeprom(ctypes.Structure): class SfpTest(OnlpTestMixin, unittest.TestCase): - """Test interfaces in onlp/psu.h.""" + """Test interfaces in onlp/sfp.h.""" def setUp(self): OnlpTestMixin.setUp(self) @@ -1460,7 +1460,7 @@ class SfpTest(OnlpTestMixin, self.assertEqual(sts, 0) def auditDom(self, domData): - unittest.skipn("not implemented") + unittest.skip("not implemented") def testDump(self): unittest.skip("this is a really slow command")