上一篇我們簡單講了FRU,也提到Entity-Manager的起手式。這篇我們就要詳細帶大家來看一下Entity Manager裡面的code到底怎麼寫的?
Entity Manager 的整個生命週期,可以說是從 main.cpp 裡那一行最關鍵的程式碼開始的:
boost::asio::post(io, [&]() { em.propertiesChangedCallback(...); });
就是這一行,啟動了整個系統的第一次掃描。Entity Manager 採用 Boost.Asio 的事件驅動模型,因此 main() 裡會呼叫:
io.run();
這一步非常重要。從這一刻開始,程式會進入 Asio 的 event loop,而 entity-manager 的所有動作——包含 Probe、掃描 D-Bus、更新 Inventory——都不是同步呼叫的,而是被事件驅動的。第一次掃描是由 boost::asio::post() 主動觸發,之後就輪到 D-Bus 事件接手了。整體大概會像是這樣~
main()
└── io.run()
└── boost.asio event loop
├── post() → first scan
├── DBus NameOwnerChanged
├── DBus InterfacesAdded
├── DBus InterfacesRemoved
├── DBus PropertiesChanged
└── other async callbacks
→ propertiesChangedCallback()
→ PerformScan::run()
→ Probe / match / FoundDevices
→ Update Inventory
第一次掃描:PerformScan::run()
當 entity-manager 開始工作,它會啟動一輪完整掃描(Scan)。流程如下:
- 從所有 JSON 中抓出所有 Probe。例如 10 組 FRU record、3 組 PSU record、2 組 NIC record 等等。
- 解析 Probe: 抽出 interface 名稱和屬性比對條件。 (上一篇我們聊過條件這部分。)
- 收集所有 interface,準備向 mapper 查詢
例如:
xyz.openbmc_project.FruDevice
xyz.openbmc_project.NetworkController
xyz.openbmc_project.PowerSupply
這份 interface list 會在下一步被丟給 ObjectMapper。
PS. 如果這邊還不知道什麼是ObjectMapper的朋朋,我想了想這個東西很難三言兩語說明白,我下次再專門講一下它。但如果之前寫的Dbus你各位有先看過了,那你可以先這樣理解,
findDbusObjects:問 mapper「請告訴我有哪些 FRU」
entity-manager 會向 ObjectMapper 發這個呼叫:
GetSubTree("/", 0, ["xyz.openbmc_project.FruDevice"])
意思是:
「從根路徑開始,把所有含有 FruDevice interface 的物件都告訴我。」
假設回來的結果像這樣:
/xyz/openbmc_project/FruDevice/board0
/xyz/openbmc_project/FruDevice/dcscm0
/xyz/openbmc_project/FruDevice/psu0
/xyz/openbmc_project/FruDevice/psu1
/xyz/openbmc_project/FruDevice/nic0
...
對於大型系統(像 Yosemite V5),這份清單可能會包含十幾二十個 FRU。但要怎麼知道哪一個 path 是哪一種 hardware?這就要靠下一步。
processDbusObjects:對每一顆 FRU 做 GetAll()
mapper 只告訴你「有這些物件」。但它沒有提供屬性。entity-manager 會對每一個 path 執行:
GetAll("xyz.openbmc_project.FruDevice")
假設 Motherboard FRU 回來的是:
{
"PRODUCT_PRODUCT_NAME": "Yosemite V5 Mainboard",
"BOARD_PRODUCT_NAME": "Motherboard",
"BOARD_MANUFACTURER": "Wiwynn",
"BOARD_MANUFACTURE_DATE": "20240301",
"BOARD_SERIAL_NUMBER": "MBQ123456",
"BOARD_PART_NUMBER": "123-4567-00",
"BOARD_INFO_AM1": "N/A",
"PRODUCT_ASSET_TAG": "ASSET-8900"
}
PSU FRU 回來的可能是:
{
"PRODUCT_PRODUCT_NAME": "Yosemite V5 PSU",
"BOARD_PRODUCT_NAME": "PowerSupply",
"BOARD_MANUFACTURER": "Delta",
"BOARD_SERIAL_NUMBER": "PSU000232"
}
NIC FRU 則:
{
"PRODUCT_PRODUCT_NAME": "Yosemite V5 NIC A",
"BOARD_PRODUCT_NAME": "NIC",
"BOARD_MANUFACTURER": "Broadcom",
"BOARD_SERIAL_NUMBER": "BCM4400239"
}
entity-manager 把這些資料都暫存到:
dbusProbeObjects[path][interface] // property map
這些就是之後要讓 Probe 進行比對的 raw data。
PerformProbe:比對 JSON Probe 與 D-Bus 屬性 —找到 Motherboard
現在來到整個流程最關鍵的部分。PerformProbe 要做的事情很簡單:
「把 Probe 的條件拿來跟每一個 FRU 的屬性逐一比對,找出真正的 Motherboard。」
以 Yosemite V5 MB 的 Probe 為例:
PRODUCT_PRODUCT_NAME: "Yosemite V5 .*"
BOARD_PRODUCT_NAME: "Motherboard"
BOARD_MANUFACTURER: "(Quanta|Wiwynn)"
假設我們正在比對 /xyz/openbmc_project/FruDevice/board0:
- PRODUCT_PRODUCT_NAME = Yosemite V5 Mainboard → ✔ regex match
- BOARD_PRODUCT_NAME = Motherboard → ✔ 完全相同
- BOARD_MANUFACTURER = Wiwynn → ✔ 在 regex 裡
全部比對成功 → entity-manager 認定:
「/board0 就是這 GUI JSON 裡的 Motherboard。」
再來看看 DC-SCM。若 DC-SCM FRU 長這樣:
BOARD_PRODUCT_NAME = "DC-SCM"
Motherboard 的 Probe 會 fail,但 DC-SCM JSON 的 Probe 會 match。依此類推!
今天看到這裡,已經夠累了!但是我們故事還沒有說完,下集見囉!如果你想鼓勵我繼續寫下去,可以到 https://buymeacoffee.com/cozylivingc 請我喝杯咖啡。甘溫~












