Files
bee/bible-local/proposals/2026-06-19-sfp-modules-contract-rfc.md

202 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RFC: SFP Module Identity and Telemetry in Hardware Ingest Contract
**Date:** 2026-06-19
**Status:** proposal
**Target:** Reanimator Core — ingest schema, validation, and storage
**Requested by:** bee (hardware audit LiveCD)
**Contract version affected:** 2.10 → 2.11
---
## Задача для агента
Внести изменения в контракт ingest и реализовать их в Reanimator Core:
1. Добавить массив `sfp_modules[]` внутри `pcie_devices[]`.
2. Обновить JSON-схему и валидатор ingest endpoint.
3. Реализовать хранение/upsert данных SFP-модулей.
4. Пометить скалярные поля `sfp_*` на уровне `pcie_devices[]` как deprecated.
5. Обновить документ контракта (`hardware-ingest-contract.md`) до версии 2.11.
Ниже — всё необходимое для принятия решений без дополнительных вопросов.
---
## Контекст: откуда берутся данные
**Источник в bee:** `ethtool -m <iface>` (читает EEPROM SFP/SFP+/QSFP28/QSFP-DD по стандарту MSA SFF-8472 / SFF-8636).
**Связь с PCIe:** `ethtool -i <iface>` возвращает `bus-info` = BDF (`0000:3b:00.0`), который совпадает с `pcie_devices[].slot`. Так bee связывает SFP-данные конкретного интерфейса с PCIe-устройством.
**Один NIC — несколько модулей:** карта ConnectX-6 Dx (2 порта), Intel X710 (4 порта), Mellanox HDR (2 порта). Каждый порт — отдельный `ethtool -m`, отдельный SFP-модуль. Одного скаляра на устройство недостаточно.
**QSFP28/QSFP-DD:** 4-канальные модули возвращают telemetry отдельно по каждому каналу (lane). В предложенной схеме lane-уровень не включён в первую версию — только агрегированные значения модуля в целом. Расширение до lane-уровня — отдельный RFC если понадобится.
---
## Проблема с текущим контрактом v2.10
В `pcie_devices[]` есть пять скалярных полей:
```
sfp_temperature_c float
sfp_tx_power_dbm float
sfp_rx_power_dbm float
sfp_voltage_v float
sfp_bias_ma float
```
Ограничения:
- **Нет идентификации модуля** — vendor, part_number, serial_number, wavelength отсутствуют; модуль нельзя инвентаризировать как самостоятельный компонент.
- **Только один набор значений на устройство** — невозможно описать 4-портовый NIC.
- **Нет типа модуля** — SFP, QSFP28, DAC-кабель не различаются.
- **Нет connector/transceiver_type** — невозможно понять, оптика это или медь.
---
## Предлагаемое изменение схемы
### Новая структура `sfp_modules[]`
Добавляется как необязательное поле внутри каждого объекта `pcie_devices[]`.
```json
"pcie_devices": [
{
"slot": "0000:3b:00.0",
"device_class": "EthernetController",
"model": "ConnectX-6 Dx",
"manufacturer": "Mellanox",
"serial_number": "MT2012X12345",
"status": "OK",
"sfp_modules": [
{
"port": 0,
"identifier": "QSFP28",
"connector": "LC",
"vendor": "Mellanox",
"part_number": "MFA1A00-C003",
"serial_number": "MT2124VS09999",
"revision": "A",
"wavelength_nm": 850,
"transceiver_type": "100GBase-SR4",
"temperature_c": 36.4,
"voltage_v": 3.29,
"tx_power_dbm": -1.8,
"rx_power_dbm": -2.1,
"bias_ma": 7.2
},
{
"port": 1,
"identifier": "QSFP28",
"connector": "LC",
"vendor": "Mellanox",
"part_number": "MFA1A00-C003",
"serial_number": "MT2124VS09998",
"revision": "A",
"wavelength_nm": 850,
"transceiver_type": "100GBase-SR4",
"temperature_c": 35.9,
"voltage_v": 3.28,
"tx_power_dbm": -1.9,
"rx_power_dbm": -2.3,
"bias_ma": 7.1
}
]
}
]
```
### Поля `sfp_modules[]`
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
| `port` | int | **да** | Номер порта на NIC (0-based). Ключ дедупликации внутри устройства. |
| `identifier` | string | нет | Тип модуля: `SFP`, `SFP+`, `SFP28`, `QSFP+`, `QSFP28`, `QSFP-DD`, `DAC` |
| `connector` | string | нет | Тип разъёма: `LC`, `MPO`, `RJ45`, `DAC`, `AOC`, `No separable connector` |
| `vendor` | string | нет | Производитель модуля из EEPROM |
| `part_number` | string | нет | Партномер из EEPROM |
| `serial_number` | string | нет | Серийный номер из EEPROM |
| `revision` | string | нет | Ревизия из EEPROM |
| `wavelength_nm` | int | нет | Длина волны, нм (0 для DAC/медных кабелей) |
| `transceiver_type` | string | нет | `10GBase-SR`, `10GBase-LR`, `25GBase-SR`, `100GBase-SR4`, `DAC`, … |
| `temperature_c` | float | нет | Температура модуля, °C (DOM telemetry) |
| `voltage_v` | float | нет | Напряжение питания, В (DOM telemetry) |
| `tx_power_dbm` | float | нет | TX оптическая мощность, dBm (DOM telemetry) |
| `rx_power_dbm` | float | нет | RX оптическая мощность, dBm (DOM telemetry) |
| `bias_ma` | float | нет | Bias current, мА (DOM telemetry) |
**Ключ дедупликации:** `(pcie_device.slot, sfp_modules[].port)`.
**Модули без серийного номера** — допустимы; многие DAC-кабели не имеют SN. Не игнорировать, сохранять по ключу `(slot, port)`.
---
## Deprecated поля
Следующие поля на уровне `pcie_devices[]` помечаются как **deprecated** начиная с v2.11:
```
sfp_temperature_c
sfp_tx_power_dbm
sfp_rx_power_dbm
sfp_voltage_v
sfp_bias_ma
```
**Поведение при получении deprecated полей:**
- Продолжать принимать и сохранять (не ломать существующих интеграторов).
- Если одновременно присутствуют `sfp_modules[]` и deprecated скаляры — приоритет у `sfp_modules[]`; скаляры игнорируются.
- В документации пометить как `deprecated since 2.11, will be removed in 3.0`.
**Не удалять** deprecated поля из валидации в этом PR — только пометить в документации и changelog.
---
## Правила ingest для `sfp_modules[]`
- `sfp_modules[]` хранится как snapshot-атрибут PCIe-компонента (аналогично `mac_addresses`).
- При каждом импорте — полная замена `sfp_modules[]` для данного `pcie_devices[].slot` (upsert всего массива целиком, не merge по портам).
- Если `sfp_modules` отсутствует или `null` — существующие данные SFP не трогать (не затирать).
- Если `sfp_modules: []` (пустой массив) — трактовать как «модули не обнаружены», очистить сохранённые данные.
- Изменение `serial_number` или `part_number` модуля на порту — создавать событие `COMPONENT_CHANGED` для PCIe-устройства с описанием «SFP module replaced on port N».
---
## Изменения в документе контракта
Файл: `bible-local/docs/hardware-ingest-contract.md`
1. Заголовок версии: `2.10``2.11`, дата → `2026-06-19`.
2. Добавить в changelog:
```
| 2.11 | 2026-06-19 | В `pcie_devices[]` добавлен необязательный массив `sfp_modules[]`
с идентификацией и DOM telemetry SFP/QSFP-модулей. Скалярные поля
sfp_temperature_c / sfp_tx_power_dbm / sfp_rx_power_dbm / sfp_voltage_v /
sfp_bias_ma помечены как deprecated (принимаются, но sfp_modules[] имеет приоритет). |
```
3. В секции `pcie_devices` добавить строку в таблицу полей:
```
| `sfp_modules` | array | нет | Установленные SFP/QSFP-модули по портам (см. sfp_modules[]) |
```
4. Добавить подсекцию `#### pcie_devices[].sfp_modules[]` с таблицей полей и примером JSON (из раздела выше).
5. Пометить deprecated поля в таблице: добавить суффикс `*(deprecated since 2.11)*`.
6. Обновить полный пример JSON — добавить `sfp_modules` к NIC-записи в `pcie_devices`.
---
## Что не нужно делать в этом PR
- Не добавлять lane-level данные QSFP (tx_power_dbm_lane_0 и т.п.) — отдельный RFC.
- Не удалять deprecated поля — только пометить.
- Не создавать отдельную top-level секцию `network_ports` — данные остаются вложенными в `pcie_devices`.
- Не менять логику идентификации PCIe-компонента — `serial_number` SFP-модуля не является ключом для самостоятельного компонента.
---
## Валидация
Единственное обязательное поле в `sfp_modules[]` — `port` (int, >= 0).
Все остальные поля опциональны.
Дубли по `port` внутри одного `pcie_devices[]` — невалидны, возвращать `400` с описанием поля.