Kernel-ib-verbs
From Shmuma
Ссылки по теме
- Git модуля: http://github.com/Shmuma/verbs/tree/master
- Introduction to infiiniband core software
- Infiniband architecture specification
Общий принцип работы
В начале вызывает функция #ib_register_client#, которая сообщает драйверам IB что мы с ними собираемся работать. В аргументах ей передается структура с указателями на две функции. Первая вызывается для каждого HCA в системе и подразумевает всю инициализацию работы с этой картой, вторая вызывается для деинициализации при вызове ib_unregister_client.
Код инициализации должен сделать следующее:
- спросить HCA о его атрибутах и атрибутах его портов (ib_query_device и ib_query_port),
- создать Protection Domain (PD),
- получить DMA Memory Region (ib_get_dma_mr),
- создать две Completion Queue для чтения и записи (ib_create_cq),
- выделить память для буферов получения и отправки,
- создать Queue Pair (QP),
- проинициализировать QP, и перевести её в состояние Ready to Read (RTR) и Ready to Send (RTS).
После этого мы должны обменяться с нодами, с которыми хотим выполнять передачу данных через verbs следующей информацией:
- QP number (ib_qp.qp_num),
- Local ID (LID) или GID -- в атрибутах порта HCA.
В модуле это выполняется через обычную сеть, но, по идее, для этого можно использовать и IB multicast.
После того как мы знаем информацию об удаленной стороне, мы должны узнать путь до этой ноды. Делается это через функцию ib_sa_path_rec_get, которой мы сообщаем GID/LID ноды и функцию которая будет вызвана по завершению процедуры поиска. Если все закончилось успешно, у нас появляется одна или несколько структур ib_sa_path_rec, которая идентифицирует путь до нужной нам ноды. Скормив эту структуру функции ib_init_ah_from_path а затем вызвав ib_create_ah, мы получаем структуру ib_ah, которая не что иное как адрес получателя наших данных.
Теперь все готово для отправки. Вызываем ib_dma_map_single для области памяти с данными (выделение памяти на 40 байт больше важно, это место под заголовки datagram). Взамен получаем u64 DMA ключ, который будет нашим адресом (оригинальную область памяти теперь меньять нельзя). Прежде чем вызывать ib_post_send, нужно подготовить две структуры: ib_send_wr и ib_sge. Первая содержит адрес получателя (AH, qkey и qp_num), номер портаи указатель на ib_sge. Во второй указывается DMA key, длина отправляемой порции данных и lkey (который мы берем из структуры ib_mr).
После вызова ib_post_send, нужно обязательно вызвать ib_poll_cq на completion queue отправки, иначе она переполнится и драйвер начнет материться.
Чтобы получать данные, нужно предварительно отправить один или несколько запросов на прием данных с помощью функции ib_post_recv. Для того чтобы проверить, не пришли ли данные, нужно вызывать ib_poll_cq передав указатель на CQ получения. Если она вернет значение больше 0, то данные пришли. Само собой что по мере получения данных, нужно отправлять новые запросы через ib_post_recv.