RXE: программное обеспечение RDMA over Ethernet, программное обеспечение RoCE
Модуль ядра rdma_rxe обеспечивает программную реализацию протокола RoCEv2. Протокол RoCEv2 — это транспортный протокол RDMA, существующий поверх UDP/IPv4 или UDP/IPv6. Базовый транспортный заголовок (BTH) InfiniBand (IB) инкапсулируется в пакеты UDP. После создания экземпляра RXE обмен данными через RXE аналогичен обмену данными через любой OFED-совместимый HCA Infiniband, хотя в некоторых случаях возникают проблемы с адресацией. В частности, хотя использование заголовков GRH не является обязательным в подсетях IB, оно является обязательным для RoCE. Приложения Verb, написанные на основе IB Verbs, должны работать без проблем, но им необходимо предоставлять информацию GRH при создании векторов адресов. Измените библиотеки и драйверы, чтобы обеспечить сопоставление GID с MAC-адресом, требуемое оборудованием.
Драйвер Soft RoCE Soft RoCE (RXE) — программный драйвер RoCE ib_rxe реализует передачу RDMA и регистрируется на основном устройстве RDMA в качестве поставщика команд ядра. Он также реализует уровень пакетного ввода-вывода. ib_rxe, с другой стороны, зарегистрирован в стеке Linux netdev как протокол инкапсуляции udp (в данном случае RDMA) и используется для отправки и получения пакетов через любое устройство Ethernet. Это приводит к передаче RDMA на сетевом уровне UDP/Ethernet, в результате чего получается устройство, совместимое с RoCEv2. Процесс настройки драйвера Soft RoCE требует привязки к любому существующему сетевому устройству Ethernet. Это делается через интерфейс /sys. Библиотека Soft RoCE (librxe) в пользовательском пространстве предоставляет пользовательским приложениям возможность запускаться с устройствами Soft RoCE. Использование глаголов rxe в пользовательском пространстве требует включения librxe в качестве плагина для libibverbs, специфичного для устройства. librxe упакован отдельно
Динамически добавлятьиудалитьrxeсетевая карта
rdma link add rxe_eth0 type rxe netdev eth0
rdma link
root@u20:~/project/rdma/rdma-core/build/bin# ./ibv_rc_pingpong -d rxe_ens3 -g 0
Architecture:
+-----------------------------------------------------------+
| Application |
+-----------------------------------------------------------+
+-----------------------------------+
| libibverbs |
User +-----------------------------------+
+----------------+ +----------------+
| librxe | | HW RoCE lib |
+----------------+ +----------------+
+---------------------------------------------------------------+
+--------------+ +------------+
| Sockets | | RDMA ULP |
+--------------+ +------------+
+--------------+ +---------------------+
| TCP/IP | | ib_core |
+--------------+ +---------------------+
+------------+ +----------------+
Kernel | ib_rxe | | HW RoCE driver |
+------------+ +----------------+
+------------------------------------+
| NIC driver |
+------------------------------------+
ibпортсостояние/физикасостояние/и разрядность и т. д.:
enum ib_port_state {
IB_PORT_NOP = 0,
IB_PORT_DOWN = 1,
IB_PORT_INIT = 2,
IB_PORT_ARMED = 3,
IB_PORT_ACTIVE = 4,
IB_PORT_ACTIVE_DEFER = 5
};
// Физическое состояние IB-порта
enum ib_port_phys_state {
IB_PORT_PHYS_STATE_SLEEP = 1,
IB_PORT_PHYS_STATE_POLLING = 2,
IB_PORT_PHYS_STATE_DISABLED = 3,
IB_PORT_PHYS_STATE_PORT_CONFIGURATION_TRAINING = 4,
IB_PORT_PHYS_STATE_LINK_UP = 5,
IB_PORT_PHYS_STATE_LINK_ERROR_RECOVERY = 6,
IB_PORT_PHYS_STATE_PHY_TEST = 7,
};
// Разрядность порта IB
enum ib_port_width {
IB_WIDTH_1X = 1,
IB_WIDTH_2X = 16,
IB_WIDTH_4X = 2,
IB_WIDTH_8X = 4,
IB_WIDTH_12X = 8
};
План развития пропускной способности организации IB:
Стек вызовов пользовательского режима
rdma link add rxe_eth0 type rxe netdev eth0
SOURCES\mlnx-iproute2-6.0.0\rdma\rdma.c -> main
rd_cmd
int cmd_link(struct rd *rd)
const struct rd_cmd cmds[] = {
{ NULL, link_show },
{ "add", link_add },
{ "delete", link_del },
{ "show", link_show },
{ "list", link_show },
{ "help", link_help },
{ 0 }
};
static int link_add(struct rd *rd)
link_add_type
link_add_netdev
rd_prepare_msg(rd, RDMA_NLDEV_CMD_NEWLINK, &seq, -> to kernel Поверните приезжать ядро rxe_newlink
mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd->link_name)
mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_LINK_TYPE, rd->link_type)
mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_NDEV_NAME, link_netdev)
rd_sendrecv_msg(rd, seq)
Инициализация модуля:
late_initcall(rxe_module_init); -> rxe_module_init -> rdma_rxe: убедитесь, что rdma_rxe init происходит в нужное время, проблема возникает, когда CONFIG_RDMA_RXE=y и CONFIG_IPV6=y. Это приведет к rdma_rxe инициализирован в IPv6 Происходит до того, как служба будет готова. Этот патч будет rdma_rxe Задержка инициализации IPv6 После того, как услуга будет готова. Это исправление основе Logan Gunthorpe Исправление, предложенное в старом коде Библиотека.
rxe_alloc_wq
rxe_wq = alloc_workqueue("rxe_wq", WQ_UNBOUND, WQ_MAX_ACTIVE)
rxe_net_init
rxe_net_ipv4_init
rxe_setup_udp_tunnel
udp_sock_create
udp_sock_create4
sock_create_kern
kernel_bind
or udp_sock_create6
tnl_cfg.encap_rcv = rxe_udp_encap_recv
rxe_get_dev_from_net
if (skb_linearize(skb))
udph = udp_hdr(skb)
pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph)
skb_pull(skb, sizeof(struct udphdr))
rxe_rcv(skb)
rxe_chk_dgid
pkt->opcode = bth_opcode(pkt)
pkt->psn = bth_psn(pkt)
pkt->mask |= rxe_opcode[pkt->opcode].mask -> struct rxe_opcode_info rxe_opcode[RXE_NUM_OPCODE]
hdr_check
rxe_icrc_check
rxe_icrc_hdr
rxe_crc32
SHASH_DESC_ON_STACK
crypto_shash_update
shash_desc_ctx
barrier_data
icrc = ~icrc
rxe_counter_inc
atomic64_inc(&rxe->stats_counters[index])
rxe_rcv_pkt(pkt, skb)
rxe_resp_queue_pkt
or rxe_comp_queue_pkt
skb_queue_tail(&qp->resp_pkts, skb)
rxe_sched_task(&qp->comp.task)
or rxe_run_task(&qp->comp.task)
setup_udp_tunnel_sock
rxe_net_ipv6_init
register_netdevice_notifier(&rxe_net_notifier)
rdma_link_register(&rxe_link_ops) -> RDMA/ядро: Добавить RDMA_NLDEV_CMD_NEWLINK/DELLINK Поддержите, добавьте новое LINK Поддержка сообщений, позволяющая добавлять и удалять rdma интерфейс. Первоначально это будет использоваться для мягких rdma водитель, водитель, указанный администратором для использования netdev Устройства динамически создают экземпляры устройств. rdma_rxe Модуль будет первым пользователем этих сообщений. Дизайн основан на RTNL_NEWLINK/DELLINK Смоделировано: если rdma водитель предоставляет функцию добавления/удаления ссылок, они будут добавлены в rdma Регистрация ядра. Каждый водитель регистрирует уникальную строку «типа», используемую для отправки из пользовательского сообщения. пространствоновости。 Новое определение для строки типа. RDMA_NLDEV_ATTR。 Пользовательский режим будет включен NEWLINK доставлено в сообщении 3 атрибуты: RDMA_NLDEV_ATTR_DEV_NAME Выразите то, что вы хотите создать rdma Имя устройства, RDMA_NLDEV_ATTR_LINK_TYPE Указывает «тип» добавляемой ссылки, RDMA_NLDEV_ATTR_NDEV_NAME. Представляет net_device интерфейс. DELLINK Сообщение будет содержать RDMA_NLDEV_ATTR_DEV_INDEX
down_write(&link_ops_rwsem)
list_add(&ops->list, &link_ops)
up_write(&link_ops_rwsem)
pr_info("loaded\n")
Реализация Netlink
static struct rdma_link_ops rxe_link_ops = {
.type = "rxe",
.newlink = rxe_newlink,
};
rxe_newlink -> добавить пару RDMA_NLDEV_CMD_NEWLINK/DELLINK Поддержка сообщений, позволяющая динамически добавлять новые RXE Связь. Временно прекращена поддержка старых опций модуля.
is_vlan_dev -> RDMA/rxe: запретить вход vlan Интерфейс сверху создатель rxe, в vlan Интерфейс сверху создатель rxe устройство создаст нефункциональное устройство с пустым gids таблице и не может использоваться с rdma cm коммуникация。 Это вызвано enum_all_gids_of_dev_cb()/is_eth_port_of_netdev() Вызвано логикой в , которая учитывает только подключение к «верхнему устройству» настроенного сетевого устройства, что приводит к vlan Интерфейс gid набор пуст и попробуйте передать это rdma соединять Невозможно разобрать гид, устройство находится в режиме cm_init_av_for_response неуспешный. Судя по всему, адаптивность этого поведения должна быть адаптирована для каждого порта-создателя. RoCE оборудование HW-RoCE оборудование, поэтому RXE поведение должно соответствовать HW-RoCE Устройства одинаковые и только для каждого реального устройства создателя rxe оборудование. чтобы пройти vlan интерфейс для осуществления связи пользователь должен использовать vlan адрес gid индекс вместо передачи vlan создавать rxe
rxe_get_dev_from_net
rxe_net_add
ib_alloc_device
rxe_add
rxe_init -> RDMA/rxe: заменить красно-черное дерево на xarray. В настоящее время rxeводитель использует красно-черное дерево для добавления индексов в пул объектов rxe. Linux xarrays Обеспечивает лучший способ восстановления той же функциональности индекса. Этот патч заменяет красно-черное дерево объектов пула на xarray。 потому что xarray Спинлок уже есть, используйте его вместо пула rwlock。 убеждаться xarray(index) и kref(ref count) Все изменения в
rxe_init_device_param
rxe->attr.vendor_id = RXE_VENDOR_ID
addrconf_addr_eui48((unsigned char *)&rxe->attr.sys_image_guid -> RDMA/rxe: будет sys_image_guid Установить в соответствии HW IB Выравнивание устройства, RXE водитель не установлен sys_image_guid,ипользовательское Космическое приложение смотреть, приезжать ноль. Это приведет к pyverbs Тест не пройден со следующей трассировкой, потому что IBTA Спецификация требует действительного sys_image_guid。 Traceback (последний вызов последний): Файл "./tests/test_device.py", нет. 51 ОК, здесь test_query_device self.verify_device_attr(attr) Файл «./tests/test_device.py», стр. 74 ОК, здесь verify_device_attr среднее утверждение attr.sys_image_guid != 0 Чтобы исправить это, пожалуйста, измените sys_image_guid установить равным node_guid
rxe_init_ports -> RDMA/rxe: удалить pkey поверхность,RoCE Требования спецификации RoCE Устройство поддерживает только стандартные pkey。 Однако, rxe водитель поддерживать 64 сущность pkey table, и используется только первая запись. удалить pkey таблицу и использовать значение по умолчанию pkey Длина жесткого соединения 1 Таблица жестко запрограммирована. Воля pkey_table Все проверки на заменяются на default_pkey сравнение
rxe_init_port_param
port->attr.state = IB_PORT_DOWN
...
rxe_init_pools
rxe_pool_init(rxe, &rxe->uc_pool, RXE_TYPE_UC)
pool->rxe = rxe
pool->elem_size = ALIGN(info->size, RXE_POOL_ALIGN)
xa_init_flags(&pool->xa, XA_FLAGS_ALLOC)
rxe->mcg_tree = RB_ROOT
rxe_set_mtu
eth_mtu_int_to_enum
mtu = mtu ? min_t(enum ib_mtu, mtu, IB_MTU_4096) : IB_MTU_256
rxe_register_device(rxe, ibdev_name)
dev->node_type = RDMA_NODE_IB_CA
ib_set_device_ops(dev, &rxe_dev_ops)
ib_device_set_netdev(&rxe->ib_dev, rxe->ndev, 1)
alloc_port_data
add_ndev_hash
hash_add_rcu(ndev_hash, &pdata->ndev_hash_link,
rxe_icrc_init
crypto_alloc_shash
ib_register_device
таблица операций устройства rxe
static const struct ib_device_ops rxe_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_RXE,
.uverbs_abi_ver = RXE_UVERBS_ABI_VERSION,
.alloc_hw_port_stats = rxe_ib_alloc_hw_port_stats,
.alloc_mr = rxe_alloc_mr,
.alloc_mw = rxe_alloc_mw,
.alloc_pd = rxe_alloc_pd,
.alloc_ucontext = rxe_alloc_ucontext,
.attach_mcast = rxe_attach_mcast,
.create_ah = rxe_create_ah,
.create_cq = rxe_create_cq,
.create_qp = rxe_create_qp,
.create_srq = rxe_create_srq,
.create_user_ah = rxe_create_ah,
.dealloc_driver = rxe_dealloc,
.dealloc_mw = rxe_dealloc_mw,
.dealloc_pd = rxe_dealloc_pd,
.dealloc_ucontext = rxe_dealloc_ucontext,
.dereg_mr = rxe_dereg_mr,
.destroy_ah = rxe_destroy_ah,
.destroy_cq = rxe_destroy_cq,
.destroy_qp = rxe_destroy_qp,
.destroy_srq = rxe_destroy_srq,
.detach_mcast = rxe_detach_mcast,
.device_group = &rxe_attr_group,
.enable_driver = rxe_enable_driver,
.get_dma_mr = rxe_get_dma_mr,
.get_hw_stats = rxe_ib_get_hw_stats,
.get_link_layer = rxe_get_link_layer,
.get_port_immutable = rxe_port_immutable,
.map_mr_sg = rxe_map_mr_sg,
.mmap = rxe_mmap,
.modify_ah = rxe_modify_ah,
.modify_device = rxe_modify_device,
.modify_port = rxe_modify_port,
.modify_qp = rxe_modify_qp,
.modify_srq = rxe_modify_srq,
.peek_cq = rxe_peek_cq,
.poll_cq = rxe_poll_cq,
.post_recv = rxe_post_recv,
.post_send = rxe_post_send,
.post_srq_recv = rxe_post_srq_recv,
.query_ah = rxe_query_ah,
.query_device = rxe_query_device,
.query_pkey = rxe_query_pkey,
.query_port = rxe_query_port,
.query_qp = rxe_query_qp,
.query_srq = rxe_query_srq,
.reg_user_mr = rxe_reg_user_mr,
.req_notify_cq = rxe_req_notify_cq,
.rereg_user_mr = rxe_rereg_user_mr,
.resize_cq = rxe_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, rxe_ah, ibah),
INIT_RDMA_OBJ_SIZE(ib_cq, rxe_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, rxe_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_qp, rxe_qp, ibqp),
INIT_RDMA_OBJ_SIZE(ib_srq, rxe_srq, ibsrq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, rxe_ucontext, ibuc),
INIT_RDMA_OBJ_SIZE(ib_mw, rxe_mw, ibmw),
};
probe, add(dev)
ib_register_device -> зарегистрированный поток roceиIB: https://blog.csdn.net/tiantao2012/article/details/77746141
assign_name
setup_device(device) -> ib_register_device() Выполните несколько шагов выделения и инициализации. Воля разделилась на более мелкие、Более читаемые функции,для облегчения обзораиподдерживать -> setup_device() Выделите память и установите данные, необходимые для вызова операции устройства, что выполняется в ib_alloc_device Единственная причина, по которой данные операции не были завершены в течение отчетного периода. он состоит из ib_dealloc_device() Отменить
ib_device_check_mandatory
IB_MANDATORY_FUNC
mandatory_table
IB_MANDATORY_FUNC(query_device),
...
setup_port_data -> RDMA/device:Воля ib_device per_port Данные консолидируются в одном месте, нет смысла делать это для данных каждого порта. 3 распределение. Воля Они объединяют существующие вместе и составляют весь жизненный цикл данных каждого порта с помощью struct ib_device соответствовать. Последующие патчи Воля Нужно более конкретнопортданные,Теперь есть хорошее место для этого
alloc_port_data
rdma_end_port
rdma_for_each_port
INIT_LIST_HEAD(&pdata->pkey_list)
INIT_HLIST_NODE(&pdata->ndev_hash_link)
rdma_for_each_port
get_port_immutable -> .get_port_immutable = irdma_roce_port_immutable
ib_query_port
immutable->max_mad_size = IB_MGMT_MAD_SIZE
verify_immutable
rdma_cap_ib_mad -> rdma_cap_ib_mad - Проверьте, поддерживается ли оборудованиепортда Infiniband Управляйте датаграммами. @device: устройство для проверки @port_num: номер порта для проверки. Управление датаграммами (MAD) да InfiniBand является обязательной частью спецификации и подчиняется всем InfiniBand Поддержка устройств. OPA Интерфейс также поддерживает немного расширенную версию. Возвращает: true, если порт поддерживает отправку/получение пакетов MAD.
device->port_data[port_num].immutable.core_cap_flags & RDMA_CORE_CAP_IB_MAD
rdma_max_mad_size -> rdma_max_mad_size - Вернуться к этому RDMA порт, необходимый для максимального MAD размер. @device: устройство @port_num: номер порта Должен MAD Размер включает в себя MAD заголовок и MAD нагрузка. Никакие другие заголовки не включены. Вернуться в порт, необходимый для максимального MAD размер. Если порт не поддерживает БЕЗУМНЫЙ, а затем вернуться 0
device->ops.query_device
ib_cache_setup_one(device) -> IB/ядро: добавлено RoCE GID Управление таблицами, RoCE GID на основеи RDMA (RoCE) Порт устройства, связанный с Ethernet, настроенным на устройстве. IP адрес. В настоящее время каждый поддерживаемый Низкий уровень водителя RoCE (ocrdma, mlx4) всем управляет самостоятельно. RoCE порт GID поверхность. потому что Ничего особенного для конкретного поставщика,Поэтому мы обобщаем это,и улучшить RDMA основной GID Кэширование делает свою работу. чтобы заполнить GID Таблица, слушаем события: (a) netdev up/down/change_addr событие - если netdev построен на нашем RoCE на устройстве,нам нужно добавить/удалить Что IP。 Это включает в себя добавление этого ndev Все связанные GID, добавить по умолчанию GID ждать. (b) inet событие - Воляновый ГИД (по данным IP Адрес) добавляется в таблицу прибытия. для порта RoCE GID Для программирования стола провайдеру необходимо произвести настройку add_gid и del_gid перезвонить. RoCE GID Руководство требует от нас GID Объявлено рядом с соответствующим net_device。 для управления GID поверхность,эта информацияданеобходимый。 Например,когдаудалить net_device когда это связано GID Также необходимо удалить. RoCE Запрос согласно соответствующему сетевому оборудованию IPv6 По умолчанию генерируется локальный канал для каждого порта GID。 ина на основерегулярный IPv6 ссылка локальная GID (поскольку у нас есть IP Генерация адреса GID) Вместо этого, когда устройство выключено, по умолчанию GID Также доступен (для поддержки обратной связи). Блокировка производится следующим образом: Должен патч модифицирован GID Код таблицы для калибровки add_gid/del_gid обратный вызов новый RoCE водительи все жевыполнить add_gid/del_gid текущий обратный вызов RoCE и IB водитель。 Процесс обновления таблиц отличается, поэтому и требования к блокировке также различны. возобновлять RoCE GID стол, проход mutex_lock(&table->lock) Защита от нескольких авторов. потому чтописатьповерхностьмы нужнысуществоватьповерхностьсерединапроверятьпопытаться найтизапись(возможныйдабесплатный вход)затем измените его,поэтому Должен Защита мьютекса find_gid и write_gid Атомарность операций убеждаться. GID Каждая запись в кэше подлежит rwlock Защищать. существовать RoCE , написанный (обычно с netdev уведомительный порядок) предполагает звонок поставщику add_gid и del_gid обратные вызовы, которые могут спать. Таким образом, к каждой записи добавляется недопустимый флаг. RoCE Возобновление осуществляется через рабочую очередь.,поэтому Разрешить спящий режим。 существоватьIBсередина,возобновлятьдасуществоватьwrite_lock_irq(&device->cache.lock)середина Заканчиватьиз,поэтомуwrite_gid不Разрешить спящий режимиadd_gid/del_gidне будет вызван。 когда Волясеть Устройство входящего/исходящий GID При кэшировании,Должен устройство всегда передается как удержание (dev_hold)。 Код «Должен» использует один рабочий элемент для возобновления всех RDMA оборудование, следуйте netdev или inet Процесс уведомления. Этот патч будет Кэш от клиента(этотда Неправильныйиз,Потому что кеширование да IB инфраструктураизчасть)превратился всуществовать Регистрация устройства/удалитьявная инициализация/выпускать
gid_table_setup_one
_gid_table_setup_one
rdma_roce_rescan_device -> {net, IB}/mlx5: Управление несколькими портами RoCE изпортассоциация,вызов mlx5_ib_add Убедитесь, что вы хотите добавить mlx5 главное, поддерживает ли устройство двойной порт RoCE действовать. еслида,Пожалуйста, используйте num_vhca_ports иaffiliate_nic_vport_criteria Функциональность определяет как основное устройство, так и ведомое оборудование. если Долженоборудованиедаотродоборудование,Пожалуйста, попытайтесь найтиприезжатьи Чтоассоциацияизхозяиноборудование. Можетассоциацияизоборудование Воля Поделиться образом системы GUID。 если Не глядяприезжать,пожалуйста Воля Что Поставь неассоциацияпорт Списокповерхностьсередина。 еслипопытаться найтиприезжатьхозяиноборудование,тогда пройдисуществовать NIC vport начальствонижесередина Конфигурацияпорт Принадлежность Воляпортобязательностьприезжатьэто。 Аналогично при вызове mlx5_ib_remove При определении типа порта. еслиэтодаотпорт,но Воля Чтоихозяиноборудование Отменаассоциация,нетно Только Воля Чтоот Нетассоциацияпорт Списокповерхностьсерединаудалить Вот и все。 Даже второй порт не используется дляассоциация,IB оборудованиетакже будет зарегистрирован какмногопортоборудование. когдавторойпорт Прикреплено позже,Необходимо обновить GID Кэш, чтобы получить кешсерединавторойпортизпо умолчанию GID。 Экспортroce_rescan_deviceпредоставитьсуществоватьобязательностьновыйпорт后刷новый缓存измеханизм。 существоватьмногопорт Конфигурациясередина,все IB Объект (QP, MR, PD и т. д.) Соответствующие команды должны проходить через основной сайт. mlx5_core_dev,Что Его заказ должен быть отправленприезжатьотпорт mlx5_core_mdev предоставляет интерфейс для получения не- IB Правильная команда объекта mdev
ib_enum_roce_netdev pass_all_filter enum_all_gids_of_dev_cb
rdma_for_each_port
ib_cache_update -> IB/основной:толькосуществоватьсоответствующийсобытиеначальствовозобновлять PKEY и GID Кэширование, HCA в PKEY и GID Таблицы могут содержать сотни записей. читатьэтоихдадорогойиз。 часть причиныдаиспользуется для Поискэтоихиз API Одновременно возвращается только одна запись. также,существоватьнекоторыйвыполнитьначальство,Например СХ-3,VF существоватьэтотаспектдапаравиртуализацияиз,идолжен полагаться на PF водитель для выполнения чтения. Это снова требует VF приезжать PF изкоммуникация。 IB Core из Кэш будет основан навсесобытиеобновить。 поэтому,Согласно квитанцииприезжатьизсобытиесоответственно IB_EVENT_PKEY_CHANGE и IB_EVENT_GID_CHANGE фильтровать PKEY и GID обновление кэша
rdma_is_port_valid
ib_query_port
rdma_protocol_roce
config_non_roce_gid_cache
ib_query_pkey
ib_security_cache_change
ib_setup_device_attrs
ib_device_register_rdmacg
rdma_counter_init
dev_set_uevent_suppress
ib_setup_port_attrs
enable_device_and_get
add_client_context
client->add(device) -> .add = ib_uverbs_add_one,
dev_set_uevent_suppress
kobject_uevent(&device->dev.kobj, KOBJ_ADD)
ib_device_put
static struct ib_client uverbs_client = {
.name = "uverbs",
.no_kverbs_req = true,
.add = ib_uverbs_add_one,
.remove = ib_uverbs_remove_one,
.get_nl_info = ib_uverbs_get_nl_info,
};
ib_uverbs_add_one -> РДМА: разрешено ib_client существоватьвызов add() не удалось, когда,Сбой при добавлении клиентов не допускается.,новсеклиентсуществовать Что Добавить рутинусередина Есть разные пути к неудаче。 этот会产生一种Нет常边缘ситуация:После добавления клиента,существовать Добавить процесссерединанеудачаине установлено client_data。 Затем,основной код по-прежнему будет использоваться NULL client_data Позвоните другому, чтобы client_data центральные операции, такие как remove()、rename()、get_nl_info() и get_net_dev_by_params() - этотдасбивающий с толкуи Несчастный случайиз。 если add() Если обратный вызов завершился неудачно, не вызывайте больше никаких клиентских операций для устройства, даже не удаляйте. удалить Обратный вызов операциисерединасейчассуществоватьверно NULL client_data Все проверки по резервированию. возобновлятьвсе add() Обратный вызов для правильного возврата кода ошибки. EOPNOTSUPP используется для ULP Не поддерживается ib_device ситуация - Например,потому чтоэтотолькоподходящийиспользуется для IB
ссылка: https://www.cnblogs.com/vlhn/p/8301427.html
ib_uverbs_create_uapi
uverbs_alloc_api
uapi_merge_def(uapi, ibdev, uverbs_core_api, false)
uapi_merge_obj_tree
uapi_merge_method
case UAPI_DEF_WRITE:
rc = uapi_create_write(uapi, ibdev, def, cur_obj_key, &cur_method_key);
method_elm->handler = def->func_write
dev_set_name
cdev_init
cdev_device_add
ib_set_client_data
// Определить вербсосновной режим пользователя API
static const struct uapi_definition uverbs_core_api[] = {
UAPI_DEF_CHAIN(uverbs_def_obj_counters),
UAPI_DEF_CHAIN(uverbs_def_obj_cq),
UAPI_DEF_CHAIN(uverbs_def_obj_device),
UAPI_DEF_CHAIN(uverbs_def_obj_dm),
UAPI_DEF_CHAIN(uverbs_def_obj_flow_action),
UAPI_DEF_CHAIN(uverbs_def_obj_intf),
UAPI_DEF_CHAIN(uverbs_def_obj_mr),
UAPI_DEF_CHAIN(uverbs_def_write_intf),
{},
};
rdma user/kernel api/abi:
const struct uapi_definition uverbs_def_write_intf[] = {
...
DECLARE_UVERBS_OBJECT(
UVERBS_OBJECT_PD,
DECLARE_UVERBS_WRITE(
IB_USER_VERBS_CMD_ALLOC_PD,
ib_uverbs_alloc_pd,
UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_alloc_pd,
struct ib_uverbs_alloc_pd_resp),
UAPI_DEF_METHOD_NEEDS_FN(alloc_pd)),
DECLARE_UVERBS_WRITE(
IB_USER_VERBS_CMD_DEALLOC_PD,
ib_uverbs_dealloc_pd,
UAPI_DEF_WRITE_I(struct ib_uverbs_dealloc_pd),
UAPI_DEF_METHOD_NEEDS_FN(dealloc_pd))),
...
}
====>
{
.kind = UAPI_DEF_OBJECT_START,
.object_start = { .object_id = UVERBS_OBJECT_PD },
},
{
.kind = UAPI_DEF_WRITE,
.scope = UAPI_SCOPE_OBJECT,
.write = {
.is_ex = 0,
.command_num = IB_USER_VERBS_CMD_ALLOC_PD
},
.func_write = ib_uverbs_alloc_pd, <- method_elm->handler = def->func_write
.write.has_resp = 1 + (sizeof(struct { int:(-!!(offsetof(struct ib_uverbs_alloc_pd, response) != 0)); })) + (sizeof(struct { int:(-!!(sizeof(((struct ib_uverbs_alloc_pd *)0)->response) != sizeof(u64))); })),
.write.req_size = sizeof(struct ib_uverbs_alloc_pd), .write.resp_size = sizeof(struct ib_uverbs_alloc_pd_resp),
.write.has_udata = 1 + (sizeof(struct { int:(-!!(offsetof(struct ib_uverbs_alloc_pd, driver_data) != sizeof(struct ib_uverbs_alloc_pd))); })) + (sizeof(struct { int:(-!!(offsetof(struct ib_uverbs_alloc_pd_resp, driver_data) != sizeof(struct ib_uverbs_alloc_pd_resp))); })),
},
{
.kind = UAPI_DEF_IS_SUPPORTED_DEV_FN,
.scope = UAPI_SCOPE_METHOD,
.needs_fn_offset = offsetof(struct ib_device_ops, alloc_pd) + (sizeof(struct { int:(-!!(sizeof(((struct ib_device_ops *)0)->alloc_pd) != sizeof(void *))); })), },
{
.kind = UAPI_DEF_WRITE,
.scope = UAPI_SCOPE_OBJECT,
.write = {
.is_ex = 0,
.command_num = IB_USER_VERBS_CMD_DEALLOC_PD
},
.func_write = ib_uverbs_dealloc_pd,
.write.req_size = sizeof(struct ib_uverbs_dealloc_pd),
},
{
.kind = UAPI_DEF_IS_SUPPORTED_DEV_FN,
.scope = UAPI_SCOPE_METHOD,
.needs_fn_offset = offsetof(struct ib_device_ops, dealloc_pd) + (sizeof(struct { int:(-!!(sizeof(((struct ib_device_ops *)0)->dealloc_pd) != sizeof(void *))); })),
}
ibv_alloc_pd
root@u20:~/project/rdma/rdma-core/build/bin# ./ibv_rc_pingpong -d rxe_ens3 -g 0
Thread 3 hit Breakpoint 2, ib_uverbs_alloc_pd (attrs=0xffffc900045f3c88) at drivers/infiniband/core/uverbs_cmd.c:406
406 {
(gdb) bt
#0 ib_uverbs_alloc_pd (attrs=0xffffc900045f3c88) at drivers/infiniband/core/uverbs_cmd.c:406
#1 0xffffffffa065c825 in ib_uverbs_handler_UVERBS_METHOD_INVOKE_WRITE (attrs=0xffffc900045f3c88) at drivers/infiniband/core/uverbs_std_types_device.c:41
#2 0xffffffffa0659a95 in ib_uverbs_run_method (num_attrs=<optimized out>, pbundle=<optimized out>) at drivers/infiniband/core/uverbs_ioctl.c:471
#3 ib_uverbs_cmd_verbs (ufile=<optimized out>, hdr=<optimized out>, user_attrs=<optimized out>) at drivers/infiniband/core/uverbs_ioctl.c:612
#4 0xffffffffa0659cc8 in ib_uverbs_ioctl (filp=<optimized out>, cmd=<optimized out>, arg=140726932025184) at drivers/infiniband/core/uverbs_ioctl.c:644
#5 0xffffffff81371f87 in vfs_ioctl (arg=<optimized out>, cmd=<optimized out>, filp=<optimized out>) at fs/ioctl.c:47
#6 file_ioctl (arg=<optimized out>, cmd=<optimized out>, filp=<optimized out>) at fs/ioctl.c:510
#7 do_vfs_ioctl (filp=0xffff8880aa0dff00, fd=<optimized out>, cmd=<optimized out>, arg=140726932025184) at fs/ioctl.c:697
#8 0xffffffff81372257 in ksys_ioctl (fd=3, cmd=3222805249, arg=140726932025184) at fs/ioctl.c:714
#9 0xffffffff8137229a in __do_sys_ioctl (arg=<optimized out>, cmd=<optimized out>, fd=<optimized out>) at fs/ioctl.c:721
#10 __se_sys_ioctl (arg=<optimized out>, cmd=<optimized out>, fd=<optimized out>) at fs/ioctl.c:719
#11 __x64_sys_ioctl (regs=<optimized out>) at fs/ioctl.c:719
#12 0xffffffff81005497 in do_syscall_64 (nr=<optimized out>, regs=0xffffc900045f3f58) at arch/x86/entry/common.c:290
#13 0xffffffff81e0008c in entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:175
#14 0x0000000000000004 in fixed_percpu_data ()
#15 0x00005596cd698260 in ?? () at drivers/infiniband/core/uverbs_cmd.c:3306
#16 0x0000000000000004 in fixed_percpu_data ()
#17 0x00007ffd8acb30ec in ?? () at drivers/infiniband/core/uverbs_cmd.c:3306
#18 0x00007ffd8acb2f78 in ?? () at drivers/infiniband/core/uverbs_cmd.c:3306
#19 0x00007ffd8acb2f40 in ?? () at drivers/infiniband/core/uverbs_cmd.c:3306
#20 0x0000000000000246 in ib_umem_odp_unmap_dma_pages (umem_odp=0x0 <fixed_percpu_data>, virt=<optimized out>, bound=<optimized out>)
(gdb) info threads
Id Target Id Frame
1 Thread 1.1 (CPU#0 [running]) timerqueue_add (head=0xffff88813ba1dee0, node=0xffff88813ba1e3a0) at lib/timerqueue.c:37
2 Thread 1.2 (CPU#1 [running]) vring_map_single (vq=0xffff88813a868a80, cpu_addr=0xffff888138762e00, size=432, direction=<optimized out>) at drivers/virtio/virtio_ring.c:342
* 3 Thread 1.3 (CPU#2 [running]) timerqueue_add (head=0xffff88813ba9dee0, node=0xffff88813ba9e3a0) at lib/timerqueue.c:47
4 Thread 1.4 (CPU#3 [running]) 0xffffffff811e5125 in seccomp_run_filters (match=<optimized out>, sd=<optimized out>) at kernel/seccomp.c:272
5 Thread 1.5 (CPU#4 [halted ]) 0xffffffff81c46cce in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:60
6 Thread 1.6 (CPU#5 [halted ]) 0xffffffff81c46cce in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:60
7 Thread 1.7 (CPU#6 [halted ]) 0xffffffff81c46cce in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:60
8 Thread 1.8 (CPU#7 [running]) 0x00007f99178f6142 in ?? () at drivers/infiniband/core/uverbs_cmd.c:3306
...
ib_uverbs_alloc_pd Назначить домен защиты
uverbs_request
uobj_alloc(UVERBS_OBJECT_PD, attrs, &ib_dev) -> handle SIGTRAP nostop noprint ignore
rdma_zalloc_drv_obj(ib_dev, ib_pd)
pd->res.type = RDMA_RESTRACK_PD
ret = ib_dev->ops.alloc_pd(pd, &attrs->driver_udata) -> rxe_alloc_pd
rxe_add_to_pool
might_sleep_if -> _cond_resched
should_resched -> unlikely(raw_cpu_read_4(__preempt_count) == preempt_offset)
preempt_schedule_common
do
preempt_latency_start
__schedule(true)
preempt_latency_stop(1)
preempt_enable_no_resched_notrace()
rcu_all_qs
kref_get
ib_device_try_get
elem->pool = pool
kref_init
uobj->object = pd
rdma_restrack_uadd(&pd->res)
uverbs_response
uobj_alloc_commit
static const struct file_operations uverbs_fops = {
.owner = THIS_MODULE,
.write = ib_uverbs_write,
.open = ib_uverbs_open,
.release = ib_uverbs_close,
.llseek = no_llseek,
.unlocked_ioctl = ib_uverbs_ioctl,
.compat_ioctl = ib_uverbs_ioctl,
};
...
ib_uverbs_add_one
cdev_init(&uverbs_dev->cdev,device->ops.mmap ? &uverbs_mmap_fops : &uverbs_fops);
ioctl:
...
ENTRY(entry_SYSCALL_64)
movq %rsp, %rsi
call do_syscall_64 /* returns with IRQs disabled */ <- entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:175 -> __visible void do_syscall_64
enter_from_user_mode
ti = current_thread_info()
regs->ax = sys_call_table[nr](regs) -> SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)-> ksys_ioctl(fd, cmd, arg)
security_file_ioctl
error = do_vfs_ioctl(f.file, fd, cmd, arg)
switch (cmd)
default:
error = file_ioctl(filp, cmd, arg)
switch (cmd)
vfs_ioctl(filp, cmd, arg) -> error = filp->f_op->unlocked_ioctl(filp, cmd, arg) <- .unlocked_ioctl = ib_uverbs_ioctl
copy_from_user
srcu_read_lock
ib_uverbs_cmd_verbs
radix_tree_iter_lookup uapi_key_ioctl_method(hdr->method_id)
ib_uverbs_run_method -> ret = handler(&pbundle->bundle) -> static int UVERBS_HANDLER(UVERBS_METHOD_INVOKE_WRITE)
return method_elm->handler(attrs)
ib_uverbs_alloc_pd
srcu_read_unlock
syscall_return_slowpath(regs)
#define DECLARE_UVERBS_NAMED_METHOD(_method_id, ...) \
static const struct uverbs_attr_def *const UVERBS_METHOD_ATTRS( \
_method_id)[] = { __VA_ARGS__ }; \
static const struct uverbs_method_def UVERBS_METHOD(_method_id) = { \
.id = _method_id, \
.handler = UVERBS_HANDLER(_method_id), \
.num_attrs = ARRAY_SIZE(UVERBS_METHOD_ATTRS(_method_id)), \
.attrs = &UVERBS_METHOD_ATTRS(_method_id), \
}
...
.create_qp = rxe_create_qp, RXE создает QP
rxe_create_qp
rxe_qp_from_init
rxe_qp_init_req
rxe_init_task(rxe, &qp->comp.task, qp, rxe_completer, "comp")
timer_setup(&qp->rnr_nak_timer, rnr_nak_timer, 0)
timer_setup(&qp->retrans_timer, retransmit_timer, 0) <- mod_timer(&qp->retrans_timer
rxe_qp_init_resp
rxe_init_task(rxe, &qp->resp.task, qp, rxe_responder, "resp");
check_resource
if (pkt->mask & RXE_RWR_MASK)
get_srq_wqe
wqe = queue_head(q)
memcpy(&qp->resp.srq_wqe, wqe, sizeof(qp->resp.srq_wqe))
qp->resp.wqe = &qp->resp.srq_wqe.wqe
advance_consumer(q)
srq->ibsrq.event_handler(&ev, srq->ibsrq.srq_context)
qp->resp.wqe = queue_head(qp->rq.queue);
rxe_completer
case COMPST_GET_WQE
state = get_wqe(qp, pkt, &wqe)
Запись отправки Linux: https://github.com/ssbandjl/linux/commit/8700e3e7c4857d28ebaa824509934556da0b3e76
RDMA отмечает: https://github.com/ssbandjl/linux/blob/master/rdma
Примечания ядра Linux: https://github.com/ssbandjl/linux/blob/master/readme_xb
Nvidia настроить RXE: https://enterprise-support.nvidia.com/s/article/howto-configure-soft-roce
Руководство по RXE: https://man7.org/linux/man-pages/man7/rxe.7.html
Документация RXE: https://github.com/linux-rdma/rdma-core/blob/master/Documentation/rxe.md
Драйвер Mellanx OFED/MLNX_OFED: https://github.com/ssbandjl/MLNX_OFED_SRC-5.9-0.5.6.0.git
Дорожная карта пропускной способности IB: https://www.infinibandta.org/infiniband-roadmap/
блог: https://cloud.tencent.com/developer/user/5060293/articles | https://logread.cn | https://blog.csdn.net/ssbandjl | https://www.zhihu.com/people/ssbandjl/posts
https://cloud.tencent.com/developer/column/101987
Технические друзья: Друзья, которые интересуются DPU/интеллектуальными сетевыми картами/разгрузкой/сетью, ускорением хранения данных/изоляцией безопасности и другими технологиями, могут присоединиться к группе обмена технологиями DPU.