Das Senden eines Pakets mit fehlgeschlagenem AF_XDP-Socket erhöht tx_ring_empty_descsLinux

Linux verstehen
Anonymous
 Das Senden eines Pakets mit fehlgeschlagenem AF_XDP-Socket erhöht tx_ring_empty_descs

Post by Anonymous »

Ich versuche gerade herauszufinden, wie man einen AF_XDP-Socket verwendet, ohne auf libxdp angewiesen zu sein, da ich erfahren möchte, wie es unter der Haube funktioniert. Ich habe ein Problem, bei dem das Paket scheinbar irgendwo im Stapel verschluckt wird und ich nicht sicher bin, warum. Ich schreibe ein Paket in den 0. Block des UMEM-Puffers, fülle den 0. Eintrag im Tx-Ring aus und erhöhe dann den Producer. Allerdings sehe ich am Ende dieses Prozesses überhaupt kein Paket herauskommen und die Überprüfung von XDP_STATISTICS zeigt an, dass tx_ring_empty_descs um 1 erhöht wurde. Debug-Ausdrucke bestätigen, dass die Werte des Produzenten und des Verbrauchers beide bei 0 beginnen und dann beide bei 1 enden.
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;
}
}
}
Ich habe versucht, dies auch im XDP_ZEROCOPY-Modus mit einer Intel-NIC unter Verwendung des IGB-Treibers auszuführen. Das Endergebnis ist, dass der sendto-Aufruf EINVAL zurückgibt, anstatt ihn als ungültigen Deskriptor zu markieren. Bei der Ausführung im XDP_COPY-Modus gibt sendto 0 zurück und das oben beschriebene Verhalten tritt auf.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post