Мне жаль, что я задаю все эти вопросы XDP, но там действительно не так много документации.
Я посмотрел на файл xdpsock_user.c
(https://github.com/torvalds/linux/blob/master/samples/bpf/xdpsock_user.c) в котором реализован Shared Umem вполне понятно с несколькими сокетами. В for-l oop каждый сокет будет запрашиваться путем вызова xsk_ring_cons__peek
, если какие-либо пакеты поступили. Если их нет, for-l oop будет go до следующего сокета. В противном случае программа обработает полученные пакеты.
Как видите, это поведение последовательно (один сокет за другим). Я не знаю, можно ли это изменить на Multithreaded-Architecture, где потоки (каждый со своим собственным сокетом) читают параллельно из Umem, например:
uint32_t idx_rx = 0, idx_fq = 0;
const int rcvd = xsk_ring_cons__peek(&xsk_socket->rx, INT32_MAX, &idx_rx);
if (!rcvd) {
return;
}
const int ret = xsk_ring_prod__reserve(&xsk_socket->umem->fq, rcvd, &idx_fq);
if (ret < 0) {
fprintf(stderr, "Error: %s\n", strerror(-ret));
} else if(ret == 0) {
printf("NO SPACE LEFT!\n");
} else if(ret != rcvd) {
printf("RET != RCVD\n");
} else {
for (uint32_t i = idx_rx; i < (idx_rx + rcvd); i++) {
const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk_socket->rx, i);
uint64_t addr = desc->addr;
uint32_t len = desc->len;
uint64_t orig = xsk_umem__extract_addr(addr);
addr = xsk_umem__add_offset_to_addr(addr);
const int hdr_size = process_packet(xsk_socket, addr, len);
*xsk_ring_prod__fill_addr(&xsk_socket->umem->fq, idx_fq++) = orig;
xsk_socket->stats.rx_bytes += (len - hdr_size);
}
xsk_socket->stats.rx_packets += rcvd;
}
Но вызывая
xsk_ring_prod__submit(&xsk_socket->umem->fq, ret);
xsk_ring_cons__release(&xsk_socket->rx, rcvd);
будет происходить последовательно (каждый поток может поместить запрос в release
и submit
вместе со своими xsk_socket->rx
и полученной суммой в потокобезопасную очередь сообщений, и другой поток ничего не будет делать, кроме выполнения этих двух функций для каждого входящего сообщения).
Я реализовал эту архитектуру и, хотя она отлично работает для одного сокета в очереди RX (поэтому нет общего Umem и только один поток), я получаю большую потерю пакетов для два сокета, которые совместно используют Umem.
Итак, я предполагаю, что это невозможно, поскольку Umem является очередью с одним потребителем или одним производителем?