CXL-коммутатор соединяет несколько хостов и устройств памяти в ткань, и его настройка определяет, кто с кем видится и как распределяется полоса. В Linux управление строится на драйверах cxl, sysfs /sys/bus/cxl, утилите cxl из ndctl, а для аппаратных коммутаторов (Broadcom PEX, Microchip Switchtec) - на switchtec-cli и Fabric Manager. Ниже разобраны топология портов, настройка MLD, мониторинг ошибок через RCEC и AER, полоса через CXL PMU и типичные ловушки настройки.

Топология CXL-коммутатора upstream downstream и MLD

Коммутатор CXL имеет один upstream-порт к хосту и несколько downstream-портов к устройствам памяти или другим коммутаторам. В sysfs это выглядит так: в /sys/bus/cxl/devices появляются portX для каждого порта, а под ними memX для устройств памяти за downstream-портами. Upstream-порт видит хост как PCIe-устройство класса 0x0604 (PCI bridge), downstream-порты как Memory Controller класса 0x0580.

MLD, Multi-Logical Device, позволяет одному физическому порту представлять несколько логических устройств. Коммутатор с MLD показывает в lspci несколько функций на одном слоте: function 0 - управление, function 1..N - память. В sysfs каждый логический порт получает свой portX с отдельным набором атрибутов.

Просмотр топологии:

cxl list -v -P
lspci -tv -d :cxl

Ключ -P в cxl list показывает физические порты, их состояние (up/down), скорость (CXL 1.1 32 GT/s, CXL 2.0 64 GT/s) и привязанные mem-девайсы. lspci -tv рисует дерево: Root Complex -> Switch Upstream Port -> Switch Downstream Ports -> CXL Memory Devices.

Многопутевые топологии CXL 2.0 позволяют строить иерархии коммутаторов: Root Complex хоста -> Upstream Port коммутатора 1 -> Downstream Port -> Upstream Port коммутатора 2 -> Downstream Port -> Memory Device. Каждый уровень добавляет латентность: типичный переход через коммутатор 50-100 нс, полный путь хост-память через два коммутатора 150-250 нс. При проектировании ткани важно минимизировать количество скачков: для критичных по латентности нагрузок (HFT, HPC) держат память на первом уровне, для емкостных (фрост данные, бэкапы) допустимы два-три уровня.

Коммутаторы с поддержкой CXL 2.0 добавляют Switch Fabric Capabilities: Port-Based Routing, где маршрут определяется номером порта, и Flow-Based Routing, где маршрут определяется Flow ID в FLIT. Port-Based проще, но менее гибок, Flow-Based позволяет балансировать нагрузку между несколькими upstream-портами. В Linux маршрутизация настраивается через атрибуты portX/routing_mode (port_based / flow_based) и portX/flow_table для Flow-Based режима. Flow table заполняется командами:

echo "flow_id 0 port 0" > /sys/bus/cxl/devices/port0/flow_table
echo "flow_id 1 port 1" > /sys/bus/cxl/devices/port0/flow_table

Flow ID берётся из битов 8-15 заголовка FLIT, и коммутатор распределяет трафик разных потоков по разным физическим линкам, устраняя hot spots.

Настройка портов через sysfs и cxl утилиту

Каждый порт в /sys/bus/cxl/devices/portX имеет атрибуты: state (enabled/disabled), speed (gen1/gen2/gen3 для CXL 1.1/2.0), width (x1/x2/x4/x8/x16), mld_enable (0/1). Включение порта:

echo enabled > /sys/bus/cxl/devices/port0/state
echo gen3 > /sys/bus/cxl/devices/port0/speed
echo 16 > /sys/bus/cxl/devices/port0/width

MLD включается переключением mld_enable на 1, после чего порт перезагружается и появляются логические функции. Для коммутаторов с MLD полезен параметр max_logical_devices, который ограничивает число логических устройств на порт, по умолчанию 8.

При включении MLD коммутатор пересчитывает FCI (Fabric Capability Interface) и сообщает хосту новые логические устройства через PCIe Hot Plug. Хост должен поддерживать PCIe Hot Plug и CXL Hot Add/Remove. В ядре Linux это делает драйвер cxl_pci_hotplug. Если хост не поддерживает горячее добавление, MLD включают только на этапе загрузки (BIOS/UEFI), и логические устройства видны сразу после старта. Динамическое переключение MLD в рантайме требует coordination между Fabric Manager коммутатора и cxl_pci_hotplug на хосте.

Для коммутаторов без MLD но с поддержкой Port Binding (CXL 2.0) настройка выполняется через атрибут portX/binding. Port Binding позволяет привязать downstream-порт к конкретному upstream-порту в многохостовой конфигурации. Это альтернатива MLD для простых топологий: каждый хост получает выделенный физический порт коммутатора, без логического разделения. Настройка:

echo "host0" > /sys/bus/cxl/devices/port0/binding
echo "host1" > /sys/bus/cxl/devices/port1/binding

Port Binding проще в отладке, но менее гибок: изменение привязки требует переподключения устройств.

Скорость линка CXL 1.1 32 GT/s даёт 256 ГБ/с на x16, CXL 2.0 64 GT/s даёт 512 ГБ/с на x16. На практике полезная полоса чуть ниже из-за накладных расходов протокола: FLIT 256 байт с 16 байт заголовка, полезная 93.75%. На x8 CXL 2.0 полезная полоса ~240 ГБ/с.

Для коммутаторов с MLD полезен параметр max_logical_devices, который ограничивает число логических устройств на порт, по умолчанию 8.

При включении MLD коммутатор пересчитывает FCI (Fabric Capability Interface) и сообщает хосту новые логические устройства через PCIe Hot Plug. Хост должен поддерживать PCIe Hot Plug и CXL Hot Add/Remove. В ядре Linux это делает драйвер cxl_pci_hotplug. Если хост не поддерживает горячее добавление, MLD включают только на этапе загрузки (BIOS/UEFI), и логические устройства видны сразу после старта. Динамическое переключение MLD в рантайме требует coordination между Fabric Manager коммутатора и cxl_pci_hotplug на хосте.

Для коммутаторов без MLD но с поддержкой Port Binding (CXL 2.0) настройка выполняется через атрибут portX/binding. Port Binding позволяет привязать downstream-порт к конкретному upstream-порту в многохостовой конфигурации. Это альтернатива MLD для простых топологий: каждый хост получает выделенный физический порт коммутатора, без логического разделения. Настройка:

echo "host0" > /sys/bus/cxl/devices/port0/binding
echo "host1" > /sys/bus/cxl/devices/port1/binding

Port Binding проще в отладке, но менее гибок: изменение привязки требует переподключения устройств.

Скорость линка CXL 1.1 32 GT/s даёт 256 ГБ/с на x16, CXL 2.0 64 GT/s даёт 512 ГБ/с на x16. На практике полезная полоса чуть ниже из-за накладных расходов протокола: FLIT 256 байт с 16 байт заголовка, полезная 93.75%. На x8 CXL 2.0 полезная полоса ~240 ГБ/с.

Fabric Manager и Switchtec для аппаратных коммутаторов

Аппаратные коммутаторы (Broadcom PEX 87000/88000, Microchip Switchtec) управляются через Fabric Manager. В Linux для Switchtec есть утилита switchtec-cli из пакета switchtec-tools:

switchtec status /dev/switchtec0
switchtec port list /dev/switchtec0
switchtec port config /dev/switchtec0 0 --speed gen3 --width 16
switchtec event log /dev/switchtec0

Fabric Manager (встроенный в коммутатор микроконтроллер) отвечает за обнаружение топологии, настройку скоростей, обработку горячего подключения и отчёт ошибок. В Linux он доступен через character device /dev/switchtecX. Switchtec-cli умеет читать реестры коммутатора, настраивать разделение портов (bifurcation x16 -> x8+x8 или x4+x4+x4+x4), управлять переключением скоростей и читать лог событий.

Broadcom PEX управляется через PCIe Extended Capability и vendor-specific реестры, утилита pexctl из пакета broadcom-pex-tools делает похожие вещи: чтение лога ошибок, настройка скоростей, переключение портов. Для PEX важна настройка AER, Advanced Error Reporting, и корректная маска маскируемых ошибок, чтобы не заспамить dmesg.

Мониторинг ошибок RCEC AER и CXL RAS

CXL-коммутатор генерирует ошибки двух уровней: PCIe AER (Advanced Error Reporting) для физического линка и CXL RAS (Reliability Availability Serviceability) для протокола. В Linux AER собирается через ядро и видно в dmesg:

dmesg -T | grep -i -E "aer|pci.*error|cxl"

CXL RAS события приходят через RCEC, Root Complex Event Collector. В sysfs /sys/bus/cxl/devices/portX/ras/ лежат счётчики: corrected_errors, uncorrected_errors, fatal_errors. Для коммутаторов также есть счетчики ретраев линка: replay_timer_timeout, replay_num_rollover.

Switchtec-cli читает лог ошибок коммутатора:

switchtec event log /dev/switchtec0 --follow

Лог показывает: Link Down, Link Up, Speed Change, Width Change, ECRC Error, DLLP Timeout, Receiver Error. Для продакшена настраивают сбор этих событий в syslog или Prometheus через node_exporter с текстовым коллектором.

CXL 2.0 добавляет Link-Level Retry и Retry Buffer, которые скрывают кратковременные ошибки линка. Статистика ретраев видна в /sys/bus/cxl/devices/portX/retries/ с полями retry_count, retry_buffer_overflow. Переполнение буфера ретраев сигнализирует о системной проблеме линка.

Отдельный слой CXL RAS - это Component Event Log. Коммутатор накапливает записи о событиях компонентов (Controller, Port, Link, Media) в памяти и выдаёт их через CXL Component Event Command. В Linux чтение лога компонентов:

cxl event log /dev/cxlport0

Записи содержат: Component ID, Event Type (Media Error, Controller Error, Thermal Event, Power Event), Timestamp, Severity. Для коммутаторов Broadcom PEX события также доступны через PEX Event Log реестры, читаемые через pexctl.

Thermal события особенно важны: коммутаторы при высокой нагрузке могут достигать 90-100°C. CXL RAS включает Thermal Throttling: при превышении порога коммутатор снижает скорость линка или ширину. Мониторинг температуры через switchtec thermal /dev/switchtec0 или cxl thermal /dev/cxlport0. Алерты на температуру выше 85°C позволяют предотвратить throttling.

Полоса и загрузка через CXL PMU и perf

CXL-коммутаторы и устройства памяти имеют PMU (Performance Monitoring Unit) с событиями. В perf список:

perf list | grep -i cxl

События: cxl_port/tx_flits/, cxl_port/rx_flits/, cxl_port/retry_flits/, cxl_mem/read_bytes/, cxl_mem/write_bytes/. Замер:

perf stat -a -e cxl_port/tx_flits/,cxl_port/rx_flits/ -- sleep 5

Счётчик flits пересчитывается в байты: 1 flit = 256 бит = 32 байта. Загрузка линка в процентах: (tx_flits + rx_flits) 32 / (link_speed width время). Для CXL 2.0 x16 теоретический пик 64 GT/s 16 lanes / 8 * 128/130 encoding = 512 ГБ/с в одну сторону, полезная 480 ГБ/с. Если суммарный трафик близок к 480 ГБ/с, линк насыщен.

Для коммутаторов полезно отслеживать дисбаланс портов: если downstream-порт 0 на 90% загрузки, а порт 1 на 10%, трафик распределён неравномерно, и нужно проверить раскладку памяти между хостами.

CXL 2.0 также добавляет CXL.cache и CXL.mem Quality of Service (QoS). QoS позволяет резервировать полосу для конкретных потоков: максимальная и минимальная полоса, приоритет. Настройка через sysfs:

echo "max_bw 100" > /sys/bus/cxl/devices/port0/qos/max_bandwidth
echo "min_bw 20" > /sys/bus/cxl/devices/port0/qos/min_bandwidth
echo "priority 7" > /sys/bus/cxl/devices/port0/qos/priority

Значения в процентах от полосы линка. Приоритет 0-7, где 7 - максимальный. QoS работает на уровне Flow ID: трафик с приоритетом 7 проходит первым при перегрузке. Для мультитенантных кластеров QoS позволяет гарантировать SLA: критичному арендатору дают min_bw 30%, фоновому - min_bw 5%.

CXL 2.0 также добавляет IDE (Integrity and Data Encryption) для шифрования трафика между хостом и коммутатором. IDE настраивается через ключи, обмен которыми происходит через SPDM (Security Protocol and Data Model). В Linux IDE включается через атрибуты portX/ide/enable и ключи загружаются через SPDM-клиент. Шифрование добавляет 1-2% накладных расходов на латентность, но защищает данные на физическом линке.

Типичные ошибки и диагностика CXL-коммутатора

  1. несовпадение скоростей upstream и downstream, линк не поднимается, проверка speed и width в sysfs;
  2. MLD включён но хост не видит логические устройства, ядро без поддержки MLD (нужно ядро 6.1+), проверка CONFIG_CXL_MULTI_LOGICAL_DEVICE;
  3. bifurcation настроена неверно, физические lanes не совпадают с конфигурацией коммутатора, проверка lspci -vvv и switchtec port list;
  4. AER маскирует ошибки, dmesg чист но линк нестабилен, проверка AER масок в /sys/bus/pci/devices/.../aer_mask;
  5. Fabric Manager не отвечает, /dev/switchtec0 отсутствует, проверка модуля switchtec и питание коммутатора;
  6. неверная настройка bifurcation, физические lanes не совпадают с конфигурацией коммутатора, проверка lspci -vvv и switchtec port list;
  7. QoS не настроен, шумный арендатор съедает полосу критического, включение min_bw и max_bw на портах;
  8. IDE не включен на производстве, трафик открыт, включение IDE через SPDM и ключи.

Диагностика: cxl list -v -P для топологии, switchtec event log для истории, perf cxl_port для загрузки, dmesg AER для ошибок линка. Для продакшена настраивают экспорт счётчиков portX/ras и portX/retries в мониторинг с алертами на corrected_errors > 0 в минуту и retry_buffer_overflow > 0.

Порядок внедрения CXL-коммутатора: 1) проверить совместимость хостов (ядро 6.1+, CXL 1.1/2.0), 2) настроить bifurcation в BIOS/UEFI, 3) включить порты в sysfs, 4) настроить MLD при необходимости, 4) подключить Fabric Manager через switchtec-cli, 5) запустить нагрузочный тест с perf cxl_port, 5) настроить экспорт RAS в мониторинг. Откат: отключить порты в sysfs, вернуть bifurcation в BIOS.

Для автоматизации настройки коммутатора при загрузке создают systemd-юнит:

[Unit]
Description=CXL Switch Configuration
After=local-fs.target
Before=basic.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/setup-cxl-switch.sh
RemainAfterExit=yes

[Install]
WantedBy=basic.target

Скрипт setup-cxl-switch.sh содержит настройку скоростей, ширин, MLD, QoS, IDE и загрузку конфигурации Fabric Manager. Для коммутаторов с несколькими хостами скрипт запускается на каждом хосте или централизованно через Ansible. Конфигурация коммутатора хранится в JSON и применяется через accel-config для DSA или switchtec-cli для Switchtec.

CXL-коммутаторы делают возможным масштабирование памяти за пределы сокета, но требуют понимания ткани, маршрутизации, QoS и RAS. Правильная настройка одного раза исключает сюрпризы в проде: латентность предсказуема, полоса гарантирована, ошибки ловятся до влияния на приложения.