В нынешнем виде я создаю буфер 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;
}
}
}
РЕДАКТИРОВАТЬ: очень урезанная (хотя и эквивалентная) версия полного кода доступна здесь: https://gist.github.com/nahla-nee/8e2c2 ... cc6126ce45
Подробнее здесь: https://stackoverflow.com/questions/798 ... mpty-descs
Мобильная версия