From ca9810ca3a3acf52665c2b441ed81091299442cf Mon Sep 17 00:00:00 2001 From: luyf5 Date: Tue, 31 Aug 2021 16:04:54 +0800 Subject: [PATCH] Support RS160 https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/919828c30e8c6540f98363885aeb9b69e01b2092 153295)As an user I want to get the inventory information of RS160 https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/bec53c4b29f7bade6820d5bc6cba0d2c76e80c7a Fixes problems in previous commit regarding support of RS160 https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/fa25b97c891e6edef64267c60cc9fb3e23f01079 (60750) [legacy_Server][Kent2U4N] Get a wrong UUID of the Kent https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/2856c78477aa4081479ed3b55d229b5a4bd31a2a Refine the code in parse_firmware_info to get the firmware version https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/1313280d4035b4417a02b8d82b9a353ff1cfb535 (66249)[legacy_Server]Unreasonable firmware GUI diaplay for RS160 https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/7ba0bf98698df7132333d87bb52da9b11cf833f6 (63296) PIT - LXCA Unable to manage RS160 (Endpoint inventory collection has failed) https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/39a52cb29895b2c4f1655b50a66a51c549a91269 (63715)[discovery_Inventory]Only get Memory information of B1 & B2 slot https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/2b52df7542e7b45f64be9a3c33d9a3de92f2d76d (64213)[discovery_Inventory][Riddler_Nov_SDV_LXCA][1.2.1-41]Motherboard LED & LXCA Light Path LED behavior are mismatch when trigger sensor https://gitlab.icelab.lenovo.com/pygcon/pyghmi/commit/fa20ef890cc2119a8038a772daab77dd6cfa04ca (67305)[discovery_inventory]When memory install solt 3 and slot 4,Memory Installed Bay Number display error on LXCA Inventory Details page. Change-Id: I291ca294ab490ce8f6913def95b2e663d6cefda2 --- pyghmi/ipmi/command.py | 30 +++-- pyghmi/ipmi/oem/generic.py | 3 + pyghmi/ipmi/oem/lenovo/cpu.py | 17 ++- pyghmi/ipmi/oem/lenovo/dimm.py | 17 ++- pyghmi/ipmi/oem/lenovo/firmware.py | 85 +++++++++--- pyghmi/ipmi/oem/lenovo/handler.py | 200 ++++++++++++++++++++++++---- pyghmi/ipmi/oem/lenovo/inventory.py | 21 ++- pyghmi/ipmi/private/util.py | 7 +- 8 files changed, 297 insertions(+), 83 deletions(-) diff --git a/pyghmi/ipmi/command.py b/pyghmi/ipmi/command.py index c44b4535..3d213e99 100644 --- a/pyghmi/ipmi/command.py +++ b/pyghmi/ipmi/command.py @@ -27,9 +27,10 @@ import pyghmi.ipmi.events as sel import pyghmi.ipmi.fru as fru import pyghmi.ipmi.oem.generic as genericoem from pyghmi.ipmi.oem.lookup import get_oem_handler -import pyghmi.ipmi.private.util as pygutil +import pyghmi.ipmi.private.util as util from pyghmi.ipmi import sdr + try: from pyghmi.ipmi.private import session except ImportError: @@ -648,18 +649,6 @@ class Command(object): return self._oem.get_inventory_of_component(component) def _get_zero_fru(self): - # It is expected that a manufacturer matches SMBIOS to IPMI - # get system uuid return data. If a manufacturer does not - # do so, they should handle either deletion or fixup in the - # OEM processing pass. Code optimistically assumes that if - # data is returned, than the vendor is properly using it. - zerofru = fru.FRU(ipmicmd=self).info - if zerofru is None: - zerofru = {} - guiddata = self.raw_command(netfn=6, command=0x37) - if 'error' not in guiddata: - zerofru['UUID'] = pygutil.decode_wireformat_uuid( - guiddata['data']) # Add some fields returned by get device ID command to FRU 0 # Also rename them to something more in line with FRU 0 field naming # standards @@ -668,8 +657,21 @@ class Command(object): device_id['Device Revision'] = device_id.pop('device_revision') device_id['Manufacturer ID'] = device_id.pop('manufacturer_id') device_id['Product ID'] = device_id.pop('product_id') + + zerofru = fru.FRU(ipmicmd=self).info + if zerofru is None: + zerofru = {} zerofru.update(device_id) - return self._oem.process_fru(zerofru) + zerofru = self._oem.process_zero_fru(zerofru) + # If uuid is not returned in OEM processing, + # then it is expected that a manufacturer matches SMBIOS to IPMI + # get system uuid return data. + if 'UUID' not in zerofru: + guiddata = self.ipmicmd.raw_command(netfn=6, command=0x37) + if 'error' not in guiddata: + zerofru['UUID'] = util.\ + decode_wireformat_uuid(guiddata['data']) + return zerofru def get_inventory(self): """Retrieve inventory of system diff --git a/pyghmi/ipmi/oem/generic.py b/pyghmi/ipmi/oem/generic.py index 3c13a85f..94600e29 100644 --- a/pyghmi/ipmi/oem/generic.py +++ b/pyghmi/ipmi/oem/generic.py @@ -396,3 +396,6 @@ class OEMHandler(object): :param uid: User ID. """ return False + + def process_zero_fru(self, zerofru): + return self.process_fru(zerofru) diff --git a/pyghmi/ipmi/oem/lenovo/cpu.py b/pyghmi/ipmi/oem/lenovo/cpu.py index fe334307..502a88fc 100755 --- a/pyghmi/ipmi/oem/lenovo/cpu.py +++ b/pyghmi/ipmi/oem/lenovo/cpu.py @@ -26,6 +26,17 @@ cpu_fields = ( valuefunc=lambda v: str(v) + " MHz"), inventory.EntryField("Reserved", "h", include=False)) +cpu_cmd = { + "lenovo": { + "netfn": 0x06, + "command": 0x59, + "data": (0x00, 0xc1, 0x01, 0x00)}, + "asrock": { + "netfn": 0x3a, + "command": 0x50, + "data": (0x01, 0x01, 0x00)}, +} + def parse_cpu_info(raw): return inventory.parse_inventory_category_entry(raw, cpu_fields) @@ -36,10 +47,6 @@ def get_categories(): "cpu": { "idstr": "CPU {0}", "parser": parse_cpu_info, - "command": { - "netfn": 0x06, - "command": 0x59, - "data": (0x00, 0xc1, 0x01, 0x00) - } + "command": cpu_cmd } } diff --git a/pyghmi/ipmi/oem/lenovo/dimm.py b/pyghmi/ipmi/oem/lenovo/dimm.py index 9b420e77..d3cd7709 100755 --- a/pyghmi/ipmi/oem/lenovo/dimm.py +++ b/pyghmi/ipmi/oem/lenovo/dimm.py @@ -32,6 +32,17 @@ dimm_fields = ( inventory.EntryField("reserved", "h", include=False) ) +dimm_cmd = { + "lenovo": { + "netfn": 0x06, + "command": 0x59, + "data": (0x00, 0xc1, 0x02, 0x00)}, + "asrock": { + "netfn": 0x3a, + "command": 0x50, + "data": (0x01, 0x02, 0x01)}, +} + def parse_dimm_info(raw): return inventory.parse_inventory_category_entry(raw, dimm_fields) @@ -42,11 +53,7 @@ def get_categories(): "dimm": { "idstr": "DIMM {0}", "parser": parse_dimm_info, - "command": { - "netfn": 0x06, - "command": 0x59, - "data": (0x00, 0xc1, 0x02, 0x00) - }, + "command": dimm_cmd, "workaround_bmc_bug": True } } diff --git a/pyghmi/ipmi/oem/lenovo/firmware.py b/pyghmi/ipmi/oem/lenovo/firmware.py index 35854ffd..d3c54bf5 100644 --- a/pyghmi/ipmi/oem/lenovo/firmware.py +++ b/pyghmi/ipmi/oem/lenovo/firmware.py @@ -33,19 +33,69 @@ firmware_fields = ( inventory.EntryField("WIND", "16s"), inventory.EntryField("DIAG", "16s")) +asrock_firmware_fields = ( + inventory.EntryField("Major Firmware Revision", "B"), + inventory.EntryField("Minor Firmware Revision", "B"), + inventory.EntryField("Auxiliary Firmware Revision", "4s")) -def parse_firmware_info(raw, bios_versions=None): - bytes_read, data = inventory.parse_inventory_category_entry( - raw, firmware_fields) - del data['Revision'] - for key in data: - yield key, {'version': data[key]} +firmware_cmd = { + "lenovo": { + "netfn": 0x06, + "command": 0x59, + "data": (0x00, 0xc7, 0x00, 0x00)}, + "asrock": { + "netfn": 0x3a, + "command": 0x50, + "data": (0x02, 0x00, 0x01)}, +} - if bios_versions is not None: - yield ("Bios_bundle_ver", - {'version': bios_versions['new_img_version']}) - yield ("Bios_current_ver", - {'version': bios_versions['cur_img_version']}) +bios_cmd = { + "lenovo": { + "netfn": 0x32, + "command": 0xE8, + "data": (0x01, 0x01, 0x02)}, + "asrock": { + "netfn": 0x3a, + "command": 0x50, + "data": (0x02, 0x01, 0x01)}, +} + + +def parse_firmware_info(raw, bios_versions=None, asrock=False): + fields = firmware_fields + + if asrock: + fields = asrock_firmware_fields + + bytes_read, data = inventory.parse_inventory_category_entry(raw, fields) + if asrock: + major_version = data['Major Firmware Revision'] + minor_version = data['Minor Firmware Revision'] + # Asrock RS160 the minor version is Binary Coded Decimal, + # convert it to Decimal + minor_version = (0xff & (minor_version >> 4)) * 10 + \ + (0xf & minor_version) + aux_reversion = 0 + if str(data['Auxiliary Firmware Revision']) != '': + aux_reversion = ord(data['Auxiliary Firmware Revision']) + + bmc_version = "%s.%s.%s" % ( + str(major_version), + str(minor_version), + str(aux_reversion)) + + yield ("BMC", {'version': bmc_version}) + if bios_versions is not None: + yield ("Bios", {'version': bios_versions[0:]}) + else: + del data["Revision"] + for key in data: + yield (key, {'version': data[key]}) + if bios_versions is not None: + yield ("Bios_bundle_ver", + {'version': bios_versions['new_img_version']}) + yield ("Bios_current_ver", + {'version': bios_versions['cur_img_version']}) def parse_bios_number(raw): @@ -57,20 +107,11 @@ def get_categories(): "firmware": { "idstr": "FW Version", "parser": parse_firmware_info, - "command": { - "netfn": 0x06, - "command": 0x59, - "data": (0x00, 0xc7, 0x00, 0x00) - } + "command": firmware_cmd }, "bios_version": { "idstr": "Bios Version", "parser": parse_bios_number, - "command": { - "netfn": 0x32, - "command": 0xE8, - "data": (0x01, 0x01, 0x02) - } - + "command": bios_cmd } } diff --git a/pyghmi/ipmi/oem/lenovo/handler.py b/pyghmi/ipmi/oem/lenovo/handler.py index 60dcfcaf..005910ce 100755 --- a/pyghmi/ipmi/oem/lenovo/handler.py +++ b/pyghmi/ipmi/oem/lenovo/handler.py @@ -123,8 +123,23 @@ led_status = { 0x00: "Off", 0xFF: "On" } + +asrock_leds = { + "SYSTEM_EVENT": 0x00, + "BMC_UID": 0x01, + "LED_FAN_FAULT_1": 0x02, + "LED_FAN_FAULT_2": 0x03, + "LED_FAN_FAULT_3": 0x04 +} + +asrock_led_status = { + 0x00: "Off", + 0x01: "On" +} + led_status_default = "Blink" mac_format = '{0:02x}:{1:02x}:{2:02x}:{3:02x}:{4:02x}:{5:02x}' +categorie_items = ["cpu", "dimm", "firmware", "bios_version"] def _megarac_abbrev_image(name): @@ -289,7 +304,7 @@ class OEMHandler(generic.OEMHandler): return super(OEMHandler, self).reseat_bay(bay) def get_ntp_enabled(self): - if self.has_tsm: + if self.has_tsm or self.has_asrock: ntpres = self.ipmicmd.xraw_command(netfn=0x32, command=0xa7) return ntpres['data'][0] == '\x01' elif self.is_fpc: @@ -299,7 +314,7 @@ class OEMHandler(generic.OEMHandler): return None def get_ntp_servers(self): - if self.has_tsm: + if self.has_tsm or self.has_asrock: srvs = [] ntpres = self.ipmicmd.xraw_command(netfn=0x32, command=0xa7) srvs.append(ntpres['data'][1:129].rstrip('\x00')) @@ -312,7 +327,7 @@ class OEMHandler(generic.OEMHandler): return None def set_ntp_enabled(self, enabled): - if self.has_tsm: + if self.has_tsm or self.has_asrock: if enabled: self.ipmicmd.xraw_command( netfn=0x32, command=0xa8, data=(3, 1), timeout=15) @@ -328,7 +343,7 @@ class OEMHandler(generic.OEMHandler): return None def set_ntp_server(self, server, index=0): - if self.has_tsm: + if self.has_tsm or self.has_asrock: if not (0 <= index <= 1): raise pygexc.InvalidParameterValue("Index must be 0 or 1") cmddata = bytearray((1 + index, )) @@ -405,8 +420,29 @@ class OEMHandler(generic.OEMHandler): return True return False + @property + def has_asrock(self): + # True if this particular server have a ASROCKRACK + # based service processor (RS160 or TS460) + # RS160 (Riddler) product id is 1182 (049Eh) + # TS460 (WildThing) product id is 1184 (04A0h) + + if (self.oemid['manufacturer_id'] == 19046 + and (self.oemid['product_id'] == 1182 + or self.oemid['product_id'] == 1184)): + try: + self.ipmicmd.xraw_command(netfn=0x3a, + command=0x50, + data=(0x00, 0x00, 0x00)) + except pygexc.IpmiException as ie: + if ie.ipmicode == 193: + return False + raise + return True + return False + def get_oem_inventory_descriptions(self): - if self.has_tsm: + if self.has_tsm or self.has_asrock: # Thinkserver with TSM if not self.oem_inventory_info: self._collect_tsm_inventory() @@ -418,7 +454,7 @@ class OEMHandler(generic.OEMHandler): return () def get_oem_inventory(self): - if self.has_tsm: + if self.has_tsm or self.has_asrock: self._collect_tsm_inventory() for compname in self.oem_inventory_info: yield (compname, self.oem_inventory_info[compname]) @@ -460,7 +496,7 @@ class OEMHandler(generic.OEMHandler): return () def get_inventory_of_component(self, component): - if self.has_tsm: + if self.has_tsm or self.has_asrock: self._collect_tsm_inventory() return self.oem_inventory_info.get(component, None) if self.has_imm: @@ -468,24 +504,46 @@ class OEMHandler(generic.OEMHandler): if self.is_fpc: return self.smmhandler.get_inventory_of_component(component) + def get_cmd_type(self, categorie_item, catspec): + if self.has_asrock: + cmd_type = catspec["command"]["asrock"] + elif categorie_item in categorie_items: + cmd_type = catspec["command"]["lenovo"] + else: + cmd_type = catspec["command"] + + return cmd_type + def _collect_tsm_inventory(self): self.oem_inventory_info = {} + asrock = False + if self.has_asrock: + asrock = True for catid, catspec in inventory.categories.items(): - if (catspec.get("workaround_bmc_bug", False)): + # skip the inventory fields if the system is RS160 + if asrock and catid not in categorie_items: + continue + if (catspec.get("workaround_bmc_bug", False) + and catspec["workaround_bmc_bug"]( + "ami" if self.has_ami else "lenovo")): rsp = None - tmp_command = dict(catspec["command"]) + cmd = self.get_cmd_type(catid, catspec) + tmp_command = dict(cmd) tmp_command["data"] = list(tmp_command["data"]) count = 0 for i in range(0x01, 0xff): tmp_command["data"][-1] = i try: partrsp = self.ipmicmd.xraw_command(**tmp_command) + count += 1 + if asrock and partrsp["data"][1] == "\xff": + continue + if rsp is None: rsp = partrsp rsp["data"] = list(rsp["data"]) else: rsp["data"].extend(partrsp["data"][1:]) - count += 1 except Exception: break # If we didn't get any response, assume we don't have @@ -496,13 +554,14 @@ class OEMHandler(generic.OEMHandler): rsp["data"] = buffer(bytearray(rsp["data"])) else: try: - rsp = self.ipmicmd.xraw_command(**catspec["command"]) + cmd = self.get_cmd_type(catid, catspec) + rsp = self.ipmicmd.xraw_command(**cmd) except pygexc.IpmiException: continue # Parse the response we got try: items = inventory.parse_inventory_category( - catid, rsp, + catid, rsp, asrock, countable=catspec.get("countable", True) ) except Exception: @@ -512,7 +571,22 @@ class OEMHandler(generic.OEMHandler): for item in items: try: - key = catspec["idstr"].format(item["index"]) + # Originally on ThinkServer and SD350 (Kent), + # the DIMM is distinguished by slot, + # the key is the value of slot number (item["index"]) + # While on RS160/TS460 the DIMMs is distinguished + # by slot number and channel number, + # the key is the value of the sum of slot number + # and channel number + if asrock and catid == "dimm": + if item["channel_number"] == 1: + key = catspec["idstr"].format(item["index"]) + else: + key = catspec["idstr"].format( + item["index"] + item["channel_number"]) + else: + key = catspec["idstr"].format(item["index"]) + del item["index"] self.oem_inventory_info[key] = item except Exception: @@ -521,16 +595,34 @@ class OEMHandler(generic.OEMHandler): continue def get_leds(self): - if self.has_tsm: - for (name, id_) in leds.items(): - try: - rsp = self.ipmicmd.xraw_command(netfn=0x3A, command=0x02, + cmd = 0x02 + led_set = leds + led_set_status = led_status + + asrock = self.has_asrock + if asrock: + cmd = 0x50 + led_set = asrock_leds + led_set_status = asrock_led_status + + for (name, id_) in led_set.items(): + try: + if asrock: + rsp = self.ipmicmd.xraw_command(netfn=0x3A, command=cmd, + data=(0x03, id_, 0x00)) + rdata = bytearray(rsp['data'][:]) + status = rdata[1] + else: + rsp = self.ipmicmd.xraw_command(netfn=0x3A, command=cmd, data=(id_,)) - except pygexc.IpmiException: - continue # Ignore LEDs we can't retrieve - status = led_status.get(bytearray(rsp['data'][:])[0], + rdata = bytearray(rsp['data'][:]) + status = rdata[0] + + except pygexc.IpmiException: + continue # Ignore LEDs we can't retrieve + status = led_set_status.get(status, led_status_default) - yield (name, {'status': status}) + yield (name, {'status': status}) def set_identify(self, on, duration): if on and not duration and self.is_sd350: @@ -608,6 +700,17 @@ class OEMHandler(generic.OEMHandler): elif self.is_fpc and self.is_fpc != 6: # SMM variant fru['oem_parser'] = 'lenovo' return self.smmhandler.process_fru(fru) + elif self.has_asrock: + fru['oem_parser'] = 'lenovo' + # ASRock RS160 TS460 lays out specific interpretation of the + # board extra fields + try: + mac1 = fru['board_extra'] + if mac1 not in ('00:00:00:00:00:00', ''): + fru['MAC Address 1'] = mac1.encode('utf-8') + except (AttributeError, KeyError): + pass + return fru else: fru['oem_parser'] = None return fru @@ -653,20 +756,27 @@ class OEMHandler(generic.OEMHandler): return self._hasimm def get_oem_firmware(self, bmcver, components): - if self.has_tsm: + if self.has_tsm or self.has_asrock: command = firmware.get_categories()["firmware"] - rsp = self.ipmicmd.xraw_command(**command["command"]) + fw_cmd = self.get_cmd_type("firmware", command) + rsp = self.ipmicmd.xraw_command(**fw_cmd) + # the newest Lenovo ThinkServer versions are returning Bios version # numbers through another command bios_versions = None - if self.has_tsm: + if self.has_tsm or self.has_asrock: bios_command = firmware.get_categories()["bios_version"] - bios_rsp = self.ipmicmd.xraw_command(**bios_command["command"]) - bios_versions = bios_command["parser"](bios_rsp["data"]) + bios_cmd = self.get_cmd_type("bios_version", bios_command) + bios_rsp = self.ipmicmd.xraw_command(**bios_cmd) + if self.has_asrock: + bios_versions = bios_rsp['data'] + else: + bios_versions = bios_command["parser"](bios_rsp['data']) # pass bios versions to firmware parser - return command["parser"](rsp["data"], bios_versions) - + return command["parser"](rsp["data"], + bios_versions, + self.has_asrock) elif self.has_imm: return self.immhandler.get_firmware_inventory(bmcver, components) elif self.is_fpc: @@ -1132,3 +1242,37 @@ class OEMHandler(generic.OEMHandler): uid, 0x03, 0x00, 0x00, 0x00)) return True return False + + def process_zero_fru(self, zerofru): + if (self.oemid['manufacturer_id'] == 19046 + and self.oemid['product_id'] == 13616): + # Currently SD350 FRU UUID is synchronized with the Device UUID. + # Need to change to System UUID in future. + # Since the IPMI get device uuid matches SMBIOS, + # no need to decode it. + guiddata = self.ipmicmd.raw_command(netfn=6, command=0x8) + if 'error' not in guiddata: + zerofru['UUID'] = util.decode_wireformat_uuid( + guiddata['data'], True) + else: + # It is expected that a manufacturer matches SMBIOS to IPMI + # get system uuid return data. If a manufacturer does not + # do so, they should handle either deletion or fixup in the + # OEM processing pass. Code optimistically assumes that if + # data is returned, than the vendor is properly using it. + + guiddata = self.ipmicmd.raw_command(netfn=6, command=0x37) + if 'error' not in guiddata: + if (self.oemid['manufacturer_id'] == 19046 + and (self.oemid['product_id'] == 1182 + or self.oemid['product_id'] == 1184)): + # The manufacturer (Asrockrack) of RS160/TS460 + # matches SMBIOS + # to IPMI get system uuid return data, + # no need to decode it. + zerofru['UUID'] = util.decode_wireformat_uuid( + guiddata['data'], True) + else: + zerofru['UUID'] = util.decode_wireformat_uuid( + guiddata['data']) + return self.process_fru(zerofru) diff --git a/pyghmi/ipmi/oem/lenovo/inventory.py b/pyghmi/ipmi/oem/lenovo/inventory.py index 11982119..f2107e1f 100755 --- a/pyghmi/ipmi/oem/lenovo/inventory.py +++ b/pyghmi/ipmi/oem/lenovo/inventory.py @@ -52,7 +52,7 @@ class EntryField(object): # General parameter parsing functions -def parse_inventory_category(name, info, countable=True): +def parse_inventory_category(name, info, asrock=False, countable=True): """Parses every entry in an inventory category For example: CPU, memory, PCI, drives @@ -61,11 +61,15 @@ def parse_inventory_category(name, info, countable=True): :param name: the name of the parameter (e.g.: "cpu") :param info: a list of integers with raw data read from an IPMI requests + :param asrock: a boolean represents if RS160 with asrockrack or not :param countable: whether the data have an entries count field :returns: dict -- a list of entries in the category. """ raw = info["data"][1:] + if name == "cpu" and asrock: + raw = info["data"] + cur = 0 if countable: count = bytearray(raw)[cur] @@ -76,17 +80,17 @@ def parse_inventory_category(name, info, countable=True): entries = [] while cur < len(raw): - read, cpu = categories[name]["parser"](raw[cur:]) + read, parser = categories[name]["parser"](raw[cur:]) cur = cur + read # Account for discarded entries (because they are not present) - if cpu is None: + if parser is None: discarded += 1 continue if not countable: # count by myself count += 1 - cpu["index"] = count - entries.append(cpu) + parser["index"] = count + entries.append(parser) # TODO(avidal): raise specific exception to point that there's data left in # the buffer @@ -94,7 +98,7 @@ def parse_inventory_category(name, info, countable=True): raise Exception # TODO(avidal): raise specific exception to point that the number of # entries is different than the expected - if count - discarded != len(entries): + if count - discarded != len(entries) and not asrock: raise Exception return entries @@ -119,6 +123,9 @@ def parse_inventory_category_entry(raw, fields): value = struct.unpack_from(field.fmt, r)[0] read = struct.calcsize(field.fmt) bytes_read += read + if bytes_read > len(raw): + break + r = r[read:] # If this entry is not actually present, just parse and then discard it if field.presence and not bool(value): @@ -127,7 +134,7 @@ def parse_inventory_category_entry(raw, fields): continue if (field.fmt[-1] == "s"): - value = value.rstrip(b'\x00') + value = value.rstrip(b'\x00\xff') if (field.mapper and value in field.mapper): value = field.mapper[value] if (field.valuefunc): diff --git a/pyghmi/ipmi/private/util.py b/pyghmi/ipmi/private/util.py index 19814efc..52176798 100644 --- a/pyghmi/ipmi/private/util.py +++ b/pyghmi/ipmi/private/util.py @@ -37,7 +37,7 @@ except AttributeError: pass -def decode_wireformat_uuid(rawguid): +def decode_wireformat_uuid(rawguid, bigendian=False): """Decode a wire format UUID It handles the rather particular scheme where half is little endian @@ -45,7 +45,10 @@ def decode_wireformat_uuid(rawguid): """ if isinstance(rawguid, list): rawguid = bytearray(rawguid) - lebytes = struct.unpack_from('HHI', buffer(rawguid[8:])) return '{0:08X}-{1:04X}-{2:04X}-{3:04X}-{4:04X}{5:08X}'.format( lebytes[0], lebytes[1], lebytes[2], bebytes[0], bebytes[1], bebytes[2])