基于设备节点进行Loopback EEPROM解析

 1. EEPROM?

EEPROM (Electrically Erasable Programmable Read-Only Memory)一般用于存储程序和数据,包括但不限于以下内容:

1. 系统配置信息,如启动设置、时钟设置等;

2. BIOS和固件更新文件;

3. 用户数据,如文档、图像、音频、视频等;

4. 产品标识信息,如序列号、型号、制造日期等;

5. 加密密钥和证书等安全信息;

6. 其他设备和芯片的配置和参数信息,如调光器、温度控制器等。

EEPROM可以实现非易失性存储,即即使断电或重新启动系统,存储的信息也能够保留。因此,EEPROM通常用于需要长期存储的数据和程序,如嵌入式系统、电子设备和汽车电子等。

在服务器/交换机领域,EEPROM中一般存储的是FRU/TLV信息,这两种都是比较常见的

FRU?

FRU是Field Replaceable Unit(现场可更换单元)的缩写。它是指计算机或其他电子设备中的可以被现场更换的模块、部件或组件。

例如,服务器中的硬盘、电源、风扇、网卡、内存插槽、处理器插槽等都属于FRU。当这些部件出现故障或需要升级时,可以在不影响整个系统的运行的同时,现场更换这些FRU以维护系统的可靠性和可用性。

FRU通常有标准的尺寸、接口和规格,以便于更换和兼容性。在一些计算机或设备中,FRU会赋予一个唯一的标识码或序列号,使得设备管理人员能够对其进行追踪、管理和维护。

TLV?

TLV是Type-Length-Value的缩写,是一种常用的数据结构格式。在这种格式中,数据被分为三个部分:

- Type:表示数据的类型,通常是一个数值或字母表示。
- Length:表示数据的长度,通常是一个数值,表示Value部分的字节长度。
- Value:表示实际的数据内容,可以是任意类型的数据,如字符串、整数、结构体等。

TLV格式常用于通信协议、配置文件、数据包等场景中。它的优点是灵活性高,可以描述各种不同类型的数据,同时也具有良好的可扩展性。

在实际应用中,TLV格式有时会被扩展为TLVs,也就是多个TLV结构的组合,以表示更加复杂的数据结构。此外,还有一些变种格式,如TVL和LTV等,它们的含义与TLV基本相同,只是顺序不同。

Loopback EEPROM

在交换机领域中,经常会使用到一种流量测试部件 -- Loopback,在Loopback中也有EEPROM,并存储了一些必要的信息:

出厂信息

主要包含了厂商,Serial Number,Part Number,生产日期,Loopback类型等等。

Sensor信息

主要包含Loopback的温度,电压,电流和功耗等信息。

低速信号

大部分的Loopback都支持4个低速信号的读取,包括present,interrupt,low power mode和reset。部分Loopback也支持设置一些信号,比如interrupt,present等等。

2. EEPROM的解析

这篇文章主要是以Loopback EEPROM为例,来讲解EEPROM信息如何解析。

1. 确定Loopback的类型

 目前,基本所有的厂商的Loopback EEPROM协议都是基于标准协议进行微调,从而形成自己的协议,那如何确定当前的Loopback EEPROM是基于哪份标准协议进行修改的呢?

那就要引入一个EEPROM字段概念:Identifier Values,它定义了当前Loopback的类型,我们可以根据其类型确定所采用的EEPROM协议。

那这个Identifier Value如何读取?如何解析呢?

几乎所有的标准协议,都规定了统一的Identifier Value的对应关系,包括它的存储位置。

Identifier Value一般都是位于Loopback EEPROM的Page00的第128(0x80)位寄存器,如下图所示,这款Loopback的Identifier Value为0x11。

具体Identifier Value的对应关系如下图所示,上面Loopback的类型为QSFP28 or later:

2. 明确采用的EEPROM的协议

根据Identifier Value获取到Loopback的类型后,根据其类型确定所采用的EEPROM协议为SFF-8636/CMIS。

至此,我们就已经明确了这款Loopback EEPROM采用的标准协议。

3. EEPROM内容解析

确定了EEPROM协议后,我们可以根据其协议手册对EEPROM内容进行解析。

如上图,协议规定了128-255位寄存器存储的信息

通过文件节点获取EEPROM内容:

def read_eeprom_contents(self, file_path=None, size=256, offset=0):
    """Read the eeprom node contents.
    
    Args:
        @file_path: The path of the eeprom node.
        @size: The size you want to read from this node.
        @offset: The offset of the beginning of read.

    Returns:
        ret(int): The return value. 0 for success, greater than 0 otherwise.
        contents(str): The contents of you read from this node.
    
    """
    ret = PASS
    contents = ""
    retry_count = 0

    if file_path is None:
        logger_msg(
            f"{sys._getframe().f_code.co_name} parmentation error.", 
            self.logger)
        ret = FAIL
        return ret, contents
    while retry_count <= OPEN_NODE_RETRY:
        try:
            fd_eeprom = open(file_path, 
                                mode='rb', 
                                buffering=OPEN_NODE_BUFFER)
            break
        except Exception as e:
            retry_count += 1
            logger_msg("Open file {} Error: [{}].".format(
                                                file_path, e), self.logger)
            logger_msg("Retry to open file node [{}]:".format(
                                                retry_count), self.logger)
    else:
        ret = FAIL
        return ret, contents

    try:
        fd_eeprom.seek(offset)
        contents = fd_eeprom.read(size)
    except Exception as e:
        logger_msg("Read file {} Error: [{}].".format(
                                                file_path, e), self.logger)
        ret = FAIL
        return ret, contents

    try:
        fd_eeprom.close()
    except Exception as e:
        logger_msg("Close file {} Error: [{}].".format(
                                                file_path, e), self.logger)
        ret = FAIL
        return ret, contents

    return ret, contents

根据协议中对每个字段的定义去解析,最终将EEPROM的解析结果以键值对的形式返回:

def _reslove_eeprom(self, contents_list):
    """Get the type of the loopback.

    Args:
        @contents_list: The contents of hex strings.

    Returns:
        ret(int): The return value. 0 for success, greater than 0 otherwise.
        type_value(str): The type of the loopback.
    
    """
    ret = PASS
    eeprom_dict = {}

    if contents_list == None:
        ret = FAIL
        logger_msg("Parameters contents_list is None.", self.logger)
        return ret, eeprom_dict

    for eeprom_key in self.loopback_type.keys():
        
        value = self.loopback_type[eeprom_key]["value"]
        offset = self.loopback_type[eeprom_key]["offset"]
        size   = self.loopback_type[eeprom_key]["size"]
        type   = self.loopback_type[eeprom_key]["type"]
        unit   = self.loopback_type[eeprom_key]["unit"]

        if eeprom_key == "Identifier":
            eeprom_value = value
        else:
            start_addr = offset
            end_addr = start_addr + size

            hex_value = contents_list[start_addr:end_addr]
            _ret, eeprom_value = self._data_format_coversion(
                                                contents_list=hex_value, 
                                                type=type, 
                                                size=size)
            if _ret != PASS:
                ret = _ret

        eeprom_dict[eeprom_key] = str(eeprom_value) + unit

    return ret, eeprom_dict

4. 输出解析结果

def show_single_type_eeprom_dict(self, 
                                    loopback_type,
                                    eeprom_dict_list=None):
    """Show single type eeprom dictionary by format table.

    Args:
        @loopback_type: The loopback type that you want to show.
        @eprom_dict_list: The list of this type eeprom info dict list.
    
    Returns:
        ret(int): The return value. 0 for success, greater than 0 otherwise.
    
    """
    ret = PASS
    header = ["Port", "State", "Type"]
    all_eeprom_list = []


    if loopback_type != "NA":
        ret, config = self._get_loopback_type_config(loopback_type)
        if ret != PASS:
            logger_msg(
                "Get loopback type [{}] configuration failed".format(
                                                loopback_type), self.logger)
        
        for key in config.keys():
            header.append(key)

    try:
        for eeprom_dict in eeprom_dict_list:
            single_eeprom_list = []
            for key in header:
                single_eeprom_list.append(str_auto_line(
                                    eeprom_dict[key], length_limit=KEY_LEN))

            all_eeprom_list.append(single_eeprom_list)

        logger_msg("\n===> [{} LOOPBACK TYPE EEPROM * {}]:".format(
                            loopback_type, len(all_eeprom_list)), LOG_INFO)
        logger_msg(
            tabulate(all_eeprom_list, header, tablefmt="grid"), LOG_INFO)
    
    except Exception as e:
        ret = FAIL
        logger_msg("Show eeprom list error: [{}].".format(e), self.logger)

    return ret

输出结果演示:

3. 总结

本文具体介绍了如何解析各类型的Loopback EEPROM,包括Loopback类型的确定,协议的确定,EEPROM的解析,结果的输出呈现。最终将一个个EEPROM文件节点转换为易读的列表信息。

后面有时间的话,可以将这个工具扩展,支持解析FRU和TLV信息等等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值