Redfish的BIOS实现
EDK2提供了Redfish框架,用来实现带外的BIOS配置,其基本框架如下:
通过RedfishPkg中提供的Driver,可以实现BIOS与BMC或者其它的软件进行通信。它主要分为两个部分,分别是Client和Foundation。Client对应到UEFI应用,用于给Service交互,而Service就是前面说的BMC或者其它实现了Redfish的程序。
如何在BIOS下包含Redfish的内容
相关的模块都在RedfishPkg中,所以只需要在自己的项目中加入模块即可,主要是如下的模块:
!if $(REDFISH_ENABLE) == TRUE
EmulatorPkg/Application/RedfishPlatformConfig/RedfishPlatformConfig.inf
RedfishPkg/RestJsonStructureDxe/RestJsonStructureDxe.inf
RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
!endif
当然还有一些额外的Lib和PCD等,这些在后续如果使用到再说明。此外,Redfish还依赖于其它基础模块,也需要增加,它们主要是SecurePkg和NetworkPkg中的内容,前者是安全方面的支持而后者是网络基础模块。
模块介绍
下面介绍前面包含的模块。
RedfishHostInterfaceDxe.inf
该模块用于创建SMBIOS Type42,在《Redfish Host Interface Specification》有说明该类型的SMBIOS:
The SMBIOS Type 42 structure is used to describe a Management Controller Host Interface. It consists of standard
SMBIOS entry information, followed by interface descriptors (which detail the physical interface to the Redfish
Service), and protocol descriptors (which describe the supported payload encoding between the Host and Redfish
Service).
具体的数据说明(表1):
Offset | Name | Length | Description |
---|---|---|---|
00h | Type | 1字节 | SMBIOS类型值,这里就是42 |
01h | Length | 1字节 | 最少9个字节 |
02h | Handle | 2字节 | Handle值,根据实际代码确定 |
04h | Interface Type | 1字节 | 对于网络接口的枚举是MCHostInterfaceTypeNetworkHostInterface,值是40h |
05h | Interface Specific Data Length | 1字节 | 见后续说明 |
06h | Interface Specific Data | N字节 | 见后续说明 |
06h+N | Protocol Count | 1字节 | 通常只有一个,所以值是1 |
07h+N | Protocol Records | M字节 | 见后续说明 |
在代码中的实现:
///
/// Management Controller Host Interface (Type 42).
///
/// The information in this structure defines the attributes of a Management
/// Controller Host Interface that is not discoverable by "Plug and Play" mechanisms.
///
/// Type 42 should be used for management controller host interfaces that use protocols
/// other than IPMI or that use multiple protocols on a single host interface type.
///
/// This structure should also be provided if IPMI is shared with other protocols
/// over the same interface hardware. If IPMI is not shared with other protocols,
/// either the Type 38 or Type 42 structures can be used. Providing Type 38 is
/// recommended for backward compatibility. The structures are not required to
/// be mutually exclusive. Type 38 and Type 42 structures may be implemented
/// simultaneously to provide backward compatibility with IPMI applications or drivers
/// that do not yet recognize the Type 42 structure.
///
typedef struct {
SMBIOS_STRUCTURE Hdr;
UINT8 InterfaceType; ///< The enumeration value from MC_HOST_INTERFACE_TYPE
UINT8 InterfaceTypeSpecificDataLength;
UINT8 InterfaceTypeSpecificData[4]; ///< This field has a minimum of four bytes
} SMBIOS_TABLE_TYPE42;
当InterfaceType
的值是40h的时候,对应的InterfaceTypeSpecificData
数据如下:
Offset | Name | Length | Description |
---|---|---|---|
00h | Device Type | 1字节 | 网络接口的底层也有不同的硬件,下面是具体的类型: 02h:USB网络接口 03h:PCI/PCIe网络接口 04h:USB网络接口v2 05h:PCI/PCIe网络接口v2 80h-FFh:OEM 其它:保留 |
01h | Device Descriptor Data | N字节 | 由于类型不同,所以对应的数据也不同 |
对应的代码:
///
/// Interface Specific Data starts at offset 06h of the SMBIOS Type 42 struct.
/// This table defines the Interface Specific data for Interface Type 40h. There
/// are 3 types of Device Descriptor3 defined , however only 1 may be used in
/// specific Tape 42 table.
///
typedef struct {
UINT8 DeviceType; ///< The Device Type of the interface.
DEVICE_DESCRITOR DeviceDescriptor; ///< The Device descriptor.
} REDFISH_INTERFACE_DATA;
其中的DeviceType
的值在代码中的定义:
#define REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB 0x02 // We don't support this type of interface.
// Use REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2 instead.
#define REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE 0x03 // We don't support this type of interface.
// Use REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2 instead.
#define REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2 0x04
#define REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2 0x05
对应的DeviceDescriptor
:
///
/// Define union for the Host Interface Device Descriptor
///
typedef union {
USB_INTERFACE_DEVICE_DESCRIPTOR_V2 UsbDeviceV2; ///< Device type USB V2 device discriptor.
PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2 PciPcieDeviceV2; ///< Device type PCI/PCIe V2 device discriptor.
OEM_DEVICE_DESCRIPTOR OemDevice; ///< OEM type device discriptor.
} DEVICE_DESCRITOR; /// Device descriptor data formated based on Device Type.
这里以PCI网卡为例说明其内容:
//
// Structure definitions of Host Interface device type 05h (PCI/PCIE V2)
//
typedef struct {
UINT8 Length; ///< Length of the structure, including Device Type and Length fields.
UINT16 VendorId; ///< The Vendor ID of the PCI/PCIe device.
UINT16 DeviceId; ///< The Device ID of the PCI/PCIe device.
UINT16 SubsystemVendorId; ///< The Subsystem Vendor ID of the PCI/PCIe device.
UINT16 SubsystemId; ///< The Subsystem ID of the PCI/PCIe device.
UINT8 MacAddress [6]; ///< The MAC address of the PCI/PCIe network device.
UINT16 SegmemtGroupNumber; ///< The Segment Group Number of the PCI/PCIe.
UINT8 BusNumber; ///< The Bus Number of the PCI/PCIe device.
UINT8 DeviceFunctionNumber; ///< The Device/Function Number of the PCI/PCIe.
} PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2;
可以看到它包含了PCI的Bus/Dev/Fun/VendorId/DeviceId/SubVendorId/SubDeviceId等PCI基础信息,还有MAC地址。
Protocol的个数目前就是1,而其类型一般是“Redfish over IP Protocol“,其具体内容如下:
Offset | Name | Length | Description |
---|---|---|---|
00h | Protocol Type | 1字节 | Redfish over IP Protocol的值是04h |
01h | Protocol Type Specific Data Length | 1字节 | 见后续说明 |
02h | Protocol Specific Record Data | P字节 | 见后续说明 |
其具体的内容如下:
//
// the protocol-specific data for the "Redfish Over IP" protocol
//
typedef struct {
EFI_GUID ServiceUuid; //same as Redfish Service UUID in Redfish Service Root resource
//
// Unknown=00h,
// Static=01h,
// DHCP=02h,
// AutoConfigure=03h,
// HostSelected=04h,
// other values reserved
//
UINT8 HostIpAssignmentType;
//
// Unknown=00h,
// Ipv4=01h,
// Ipv6=02h,
// other values reserved
//
UINT8 HostIpAddressFormat;
//
// Used for Static and AutoConfigure.
// For IPV4, use the first 4 Bytes and zero fill the remaining bytes.
//
UINT8 HostIpAddress[16];
//
// Used for Static and AutoConfigure.
// For IPV4, use the first 4 Bytes and zero fill the remaining bytes.
//
UINT8 HostIpMask[16];
//
// Unknown=00h,
// Static=01h,
// DHCP=02h,
// AutoConfigure=03h,
// HostSelected=04h,
// other values reserved
//
UINT8 RedfishServiceIpDiscoveryType;
//
// Unknown=00h,
// Ipv4=01h,
// Ipv6=02h,
// other values reserved
//
UINT8 RedfishServiceIpAddressFormat;
//
// Used for Static and AutoConfigure.
// For IPV4, use the first 4 Bytes and zero fill the remaining bytes.
//
UINT8 RedfishServiceIpAddress[16];
//
// Used for Static and AutoConfigure.
// For IPV4, use the first 4 Bytes and zero fill the remaining bytes.
//
UINT8 RedfishServiceIpMask[16];
UINT16 RedfishServiceIpPort; // Used for Static and AutoConfigure.
UINT32 RedfishServiceVlanId; // Used for Static and AutoConfigure.
UINT8 RedfishServiceHostnameLength; // length of the following hostname string
UINT8 RedfishServiceHostname[1]; // hostname of Redfish Service
} REDFISH_OVER_IP_PROTOCOL_DATA;
以上就是Type42类型SMBIOS信息的内容。而本模块就是为了构建这个SMBIOS。其中的数据是根据实际的情况来确定的,比如使用PCIE还是USB网卡、MAC地址是什么、IP类型是什么等等,描述了详细的Redfish使用的接口的信息。
这些信息有一些在代码(包含通用的代码和平台相关的代码)中直接决定,而另外一些通过变量的方式写入,而这跟RedfishPlatformConfig.inf对应的模块相关。
RedfishPlatformConfig.inf
该模块已经在前面提过,它是一个UEFI应用,直接通过命令参数获取数据并存放到变量。下面是一个示例:
RedfishPlatformConfig.efi -s 192.168.10.101 255.255.255.0 192.168.10.123 255.255.255.0
它设置了一系列的IP供Redfish使用。
目前支持的变量包括:
- HostIpAssignmentType
- HostIpAddress
- HostIpMask
- RedfishServiceIpAddress
- RedfishServiceIpMask
- RedfishServiceIpPort
主要就是Client端和Service端的IP类型和地址,它们包含在REDFISH_OVER_IP_PROTOCOL_DATA
这个结构体中,并被RedfishDiscoverDxe.inf使用到。
RedfishRestExDxe.inf
本模块实现了基于HTTP的传输协议,用于Redfish数据通信。它安装了如下的两个接口供后续数据传输使用:
EFI_SERVICE_BINDING_PROTOCOL mRedfishRestExServiceBinding = {
RedfishRestExServiceBindingCreateChild,
RedfishRestExServiceBindingDestroyChild
};
EFI_REST_EX_PROTOCOL mRedfishRestExProtocol = {
RedfishRestExSendReceive,
RedfishRestExGetServiceTime,
RedfishRestExGetService,
RedfishRestExGetModeData,
RedfishRestExConfigure,
RedfishRestExAyncSendReceive,
RedfishRestExEventService
};
RedfishDiscoverDxe.inf
本模块的作用是发现Redfish Service端,比如BMC或者实现了Redfish的程序,而它依赖于前面模块中提到的需要设置的各类变量。
RedfishDiscoverDxe模块是一个UEFI Driver,所以有Supported/Start等接口:
EFI_DRIVER_BINDING_PROTOCOL gRedfishDiscoverDriverBinding = {
RedfishDiscoverDriverBindingSupported,
RedfishDiscoverDriverBindingStart,
RedfishDiscoverDriverBindingStop,
REDFISH_DISCOVER_VERSION,
NULL,
NULL
};
这里简单说明:
RedfishDiscoverDriverBindingSupported()
函数主要是判断依赖的模块是否存在,其依赖的部分如下:
static REDFISH_DISCOVER_REQUIRED_PROTOCOL gRequiredProtocol[] = {
{
ProtocolTypeTcp4,
L"TCP4 Service Binding Protocol",
&gEfiTcp4ProtocolGuid,
&gEfiTcp4ServiceBindingProtocolGuid, // RequiredServiceBindingProtocolGuid
&mRedfishDiscoverTcp4InstanceGuid, // DiscoveredProtocolGuid
Tcp4GetSubnetInfo
},
{
ProtocolTypeTcp6,
L"TCP6 Service Binding Protocol",
&gEfiTcp6ProtocolGuid,
&gEfiTcp6ServiceBindingProtocolGuid, // RequiredServiceBindingProtocolGuid
&mRedfishDiscoverTcp6InstanceGuid, // DiscoveredProtocolGuid
Tcp6GetSubnetInfo
},
{
ProtocolTypeRestEx,
L"REST EX Service Binding Protocol",
&gEfiRestExProtocolGuid,
&gEfiRestExServiceBindingProtocolGuid, // RequiredServiceBindingProtocolGuid
&mRedfishDiscoverRestExInstanceGuid, // DiscoveredProtocolGuid
NULL
}
};
它的判断依据是:
- 判断RequiredServiceBindingProtocolGuid是否存在;
- 如果存在,再判断对应的DiscoveredProtocolGuid是否存在;
- 如果已经存在,表示UEFI Driver已经执行过,所以不需要再执行了;
- 如果不存在,则这个UEFI Driver需要再次被执行。
实际上这里的三种传输方式只需要支持一种即可,前面两种是不同版本的TCP方式,而最后一种是基于HTTP的传输实现,它的实现在模块RedfishRestExDxe.inf中。
RedfishDiscoverDriverBindingStart()
构建网络接口并最终安装如下的Protocol供后续使用:
EFI_REDFISH_DISCOVER_PROTOCOL mRedfishDiscover = {
RedfishServiceGetNetworkInterface,
RedfishServiceAcquireService,
RedfishServiceAbortAcquire,
RedfishServiceReleaseService
};
这些接口会被RedfishConfigHandlerDriver.inf使用。
到目前为止的依赖关系:
RedfishConfigHandlerDriver.inf
本模块是UEFI Redfish的处理中心。它也是一个UEFI Driver,因此包含如下的接口:
///
/// Driver Binding Protocol instance
///
EFI_DRIVER_BINDING_PROTOCOL gRedfishConfigDriverBinding = {
RedfishConfigDriverBindingSupported,
RedfishConfigDriverBindingStart,
RedfishConfigDriverBindingStop,
REDFISH_CONFIG_VERSION,
NULL,
NULL
};
RedfishConfigDriverBindingSupported()
检测依赖关系,除了前面提到的RedfishDiscoverDxe模块,代码中主要依赖的是来自RedfishRestExDxe模块的接口,对应GUID是gEfiRestExProtocolGuid
和gEfiRestExServiceBindingProtocolGuid
。
RedfishConfigDriverBindingStart()
里面是一个回调函数,这个回调函数会在gEdkIIRedfishConfigHandlerProtocolGuid
安装的时候回调,而在回调函数中执行了该GUID对应的EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL
中的函数Init()
,关于这个Protocol的具体实现还没有在当前的EDK2代码中,具体见[EDK2 Redfish feature driver](#EDK2 Redfish feature driver)中的说明。
到目前为止的依赖关系:
RestJsonStructureDxe.inf
本模块是一个帮助模块,用来处理JSON数据,它安装了如下的Protocol:
EFI_REST_JSON_STRUCTURE_PROTOCOL mRestJsonStructureProtocol = {
RestJsonStructureRegister,
RestJsonStructureToStruct,
RestJsonStructureToJson,
RestJsonStructureDestroyStruct
};
RedfishCredentialDxe.inf
本模块涉及到认证相关的内容,它提供了如下的Protocol:
EDKII_REDFISH_CREDENTIAL_PROTOCOL mRedfishCredentialProtocol = {
RedfishCredentialGetAuthInfo,
RedfishCredentialStopService
};
Redfish相关的认证信息在《Redfish Host Interface Specification》中有定义,不过看规范的说明是已经弃用了,所以这里也不再介绍。
EDK2 Redfish feature driver
前面的介绍Redfish在EDK中的框架内容,但是真正的Redfish操作一个也没有介绍,而且也没有对Redfish Client的实现。这部分内容UEFI还没有放到正式版本中,而是在GitHub - tianocore/edk2-staging at edk2-redfish-client这个库中。
后续的文章中会介绍这部分内容。