Отправка пакета с ошибкой сокета AF_XDP увеличивает tx_ring_empty_descsLinux

Ответить
Anonymous
 Отправка пакета с ошибкой сокета AF_XDP увеличивает tx_ring_empty_descs

Сообщение Anonymous »

В настоящее время я пытаюсь понять, как использовать сокет AF_XDP, не полагаясь на libxdp, поскольку хочу узнать, как он работает изнутри. У меня возникла проблема: пакет, по-видимому, поглощается где-то в стеке, и я не знаю, почему. Я записываю пакет в 0-й фрагмент буфера UMEM, заполняю 0-ю запись в tx-кольце, а затем увеличиваю производителя. Однако я не вижу, чтобы пакет вообще вышел в конце этого процесса, и проверка XDP_STATISTICS показывает, что tx_ring_empty_descs был увеличен на 1. Отпечатки отладки подтверждают, что значения производителя и потребителя начинаются с 0, а затем оба заканчиваются 1.
В нынешнем виде я создаю буфер UMEM с 4096 фрагментами, каждый из которых имеет длину 4096 байт, и регистрирую это без флагов, 0 запаса и 0 tx_metadata_len. Существует по одному кольцу каждого типа (rx, tx, fill, завершение), и каждое из них имеет размер 512. При привязке сокета я перевожу его в режим XDP_COPY, привязываю его к 0-й очереди и передаю 0 для UMEM fd. Фактический код, показывающий операции записи и отправки, приведен ниже. Он написан на Rust, но я подробно прокомментировал его для тех, кто может не знать Rust. Все типы, такие как Umem, представляют собой более или менее тонкие оболочки вокруг памяти, возвращаемой libc/syscalls.

Код: Выделить всё

pub fn send(&mut self, data: &[u8], chunk_idx: usize) {
// write data to the nth chunk of the umem buffer
let chunk_start = self.umem.write_to_chunk(data, chunk_idx);

// get the last known value of producer without interacting with the atomic
let entry_idx = self.tx.cached_prod as usize;
// get a reference to the entry indexed by the cached producer
let tx_entry = self.tx.data.get_mut(entry_idx).expect("Failed to get umem chunk");

// set the entry's addr field to the index nth chunk
tx_entry.addr = chunk_start as _;
// set the length to be that of the data we just wrote to umem
tx_entry.len = data.len() as _;
// no flags/options
tx_entry.options = 0;

// store/release to the producer the value of cached_prod + 1
self.tx.producer.store(self.tx.cached_prod + 1, Ordering::Release);
// updated cached_prod
self.tx.cached_prod += 1;

// sendto call to let the kernel know we have something ready to go out
unsafe {
let ret = libc::sendto(
self.fd.as_raw_fd(),
std::ptr::null(),
0,
libc::MSG_DONTWAIT,
std::ptr::null(),
0
);

// print the errno error string
if ret < 0 {
error!("sendto issue: {}", ioError::last_os_error());
return;
}
}
}
Я пробовал запустить это в режиме XDP_ZEROCOPY, а также с сетевой картой Intel с использованием драйвера igb, конечным результатом является то, что вызов sendto возвращает EINVAL, а не помечает его как недопустимый дескриптор. При работе в режиме XDP_COPY sendto возвращает 0, и происходит описанное выше поведение.
РЕДАКТИРОВАТЬ: очень урезанная (хотя и эквивалентная) версия полного кода доступна здесь: https://gist.github.com/nahla-nee/8e2c2 ... cc6126ce45

Подробнее здесь: https://stackoverflow.com/questions/798 ... mpty-descs
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Linux»