So wie es aussieht, erstelle ich einen UMEM-Puffer mit 4096 Blöcken, von denen jeder 4096 Bytes lang ist. und es ohne Flags, 0 Headroom und 0 tx_metadata_len registrieren. Von jedem Ringtyp (Rx, Tx, Fill, Completion) gibt es einen, und jeder hat eine Größe von 512. Beim Binden des Sockets versetze ich ihn in den XDP_COPY-Modus, binde ihn an die 0. Warteschlange und übergebe 0 für den UMEM-FD. Der eigentliche Code, der den Schreib- und Sendevorgang zeigt, ist unten angegeben. Es ist in Rust geschrieben, aber ich habe es für alle, die Rust vielleicht nicht kennen, ausführlich kommentiert. Alle Typen wie Umem sind mehr oder weniger nur dünne Wrapper um den von libc/syscalls zurückgegebenen Speicher.
Code: Select all
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;
}
}
}
Mobile version