Программное обеспечение Linux RDMA RXE/SoftRoCE Исходный код драйвера ядра RoCE
Программное обеспечение Linux RDMA RXE/SoftRoCE Исходный код драйвера ядра RoCE

термин

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 упакован отдельно

Настройте и используйте

Язык кода:javascript
копировать
Динамически добавлятьиудалить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

Архитектура

Язык кода:javascript
копировать
Architecture:
​
     +-----------------------------------------------------------+
     |                          Application                      |
     +-----------------------------------------------------------+
                            +-----------------------------------+
                            |             libibverbs            |
User                        +-----------------------------------+
                            +----------------+ +----------------+
                            | librxe         | | HW RoCE lib    |
                            +----------------+ +----------------+
+---------------------------------------------------------------+
     +--------------+                           +------------+
     | Sockets      |                           | RDMA ULP   |
     +--------------+                           +------------+
     +--------------+                  +---------------------+
     | TCP/IP       |                  | ib_core             |
     +--------------+                  +---------------------+
                             +------------+ +----------------+
Kernel                       | ib_rxe     | | HW RoCE driver |
                             +------------+ +----------------+
     +------------------------------------+
     | NIC driver                         |
     +------------------------------------+

Справочник, связанный с IB Spec/RDMA

Язык кода:javascript
копировать
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:

Стек вызовов пользовательского режима

Язык кода:javascript
копировать
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)

Реализация драйвера

Инициализация модуля:

Язык кода:javascript
копировать
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

Язык кода:javascript
копировать
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),
};

Зарегистрируйте IB-устройство (ib_register_device)

Язык кода:javascript
копировать
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 *))); })), 
}

Распределение PD (ibv_alloc_pd) в качестве примера одноэтапной отладки стека вызовов модуля ядра Linux.

Язык кода:javascript
копировать
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

Назначить домен защиты PD

Язык кода:javascript
копировать
...
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

Пользовательский режим RDMA обеспечивает механизм реализации CMD и ioctl.

Язык кода:javascript
копировать
​
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),                     \
    }    

RXE создает QP

Язык кода:javascript
копировать
...
.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/

Сяобин (ssbandjl)

блог: 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.

boy illustration
Углубленный анализ переполнения памяти CUDA: OutOfMemoryError: CUDA не хватает памяти. Попыталась выделить 3,21 Ги Б (GPU 0; всего 8,00 Ги Б).
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Прочитайте нейросетевую модель Трансформера в одной статье
boy illustration
.ART Теплые зимние предложения уже открыты
boy illustration
Сравнительная таблица описания кодов ошибок Amap
boy illustration
Уведомление о последних правилах Points Mall в декабре 2022 года.
boy illustration
Даже новички могут быстро приступить к работе с легким сервером приложений.
boy illustration
Взгляд на RSAC 2024|Защита конфиденциальности в эпоху больших моделей
boy illustration
Вы используете ИИ каждый день и до сих пор не знаете, как ИИ дает обратную связь? Одна статья для понимания реализации в коде Python общих функций потерь генеративных моделей + анализ принципов расчета.
boy illustration
Используйте (внутренний) почтовый ящик для образовательных учреждений, чтобы использовать Microsoft Family Bucket (1T дискового пространства на одном диске и версию Office 365 для образовательных учреждений)
boy illustration
Руководство по началу работы с оперативным проектом (7) Практическое сочетание оперативного письма — оперативного письма на основе интеллектуальной системы вопросов и ответов службы поддержки клиентов
boy illustration
[docker] Версия сервера «Чтение 3» — создайте свою собственную программу чтения веб-текста
boy illustration
Обзор Cloud-init и этапы создания в рамках PVE
boy illustration
Корпоративные пользователи используют пакет регистрационных ресурсов для регистрации ICP для веб-сайта и активации оплаты WeChat H5 (с кодом платежного узла версии API V3)
boy illustration
Подробное объяснение таких показателей производительности с высоким уровнем параллелизма, как QPS, TPS, RT и пропускная способность.
boy illustration
Удачи в конкурсе Python Essay Challenge, станьте первым, кто испытает новую функцию сообщества [Запускать блоки кода онлайн] и выиграйте множество изысканных подарков!
boy illustration
[Техническая посадка травы] Кровавая рвота и отделка позволяют вам необычным образом ощипывать гусиные перья! Не распространяйте информацию! ! !
boy illustration
[Официальное ограниченное по времени мероприятие] Сейчас ноябрь, напишите и получите приз
boy illustration
Прочтите это в одной статье: Учебник для няни по созданию сервера Huanshou Parlu на базе CVM-сервера.
boy illustration
Cloud Native | Что такое CRD (настраиваемые определения ресурсов) в K8s?
boy illustration
Как использовать Cloudflare CDN для настройки узла (CF самостоятельно выбирает IP) Гонконг, Китай/Азия узел/сводка и рекомендации внутреннего высокоскоростного IP-сегмента
boy illustration
Дополнительные правила вознаграждения амбассадоров акции в марте 2023 г.
boy illustration
Можно ли открыть частный сервер Phantom Beast Palu одним щелчком мыши? Супер простой урок для начинающих! (Прилагается метод обновления сервера)
boy illustration
[Играйте с Phantom Beast Palu] Обновите игровой сервер Phantom Beast Pallu одним щелчком мыши
boy illustration
Maotouhu делится: последний доступный внутри страны адрес склада исходного образа Docker 2024 года (обновлено 1 декабря)
boy illustration
Кодирование Base64 в MultipartFile
boy illustration
5 точек расширения SpringBoot, супер практично!
boy illustration
Глубокое понимание сопоставления индексов Elasticsearch.
boy illustration
15 рекомендуемых платформ разработки с нулевым кодом корпоративного уровня. Всегда найдется та, которая вам понравится.
boy illustration
Аннотация EasyExcel позволяет экспортировать с сохранением двух десятичных знаков.