Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions vm/devices/net/gdma/src/bnic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ impl BufferAccess for GuestBuffers {
},
}

if let Some(vlan) = &metadata.vlan {
flags.set_rx_vlantag_present(true);
flags.set_rx_vlan_id(vlan.vlan_id as u32);
}

let packet = &mut self.rx_packets[id.0 as usize];

let cqe_type = if metadata.len > packet.len as usize {
Expand Down Expand Up @@ -548,6 +553,11 @@ impl TxRxTask {

let sge0 = sqe.sgl().first().context("no sgl")?;
let total_len: usize = sqe.sgl().iter().map(|sge| sge.size as usize).sum();
let l2_len = if oob.l_oob.inject_vlan_pri_tag() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check oob.s_oob.pkt_fmt() == MANA_LONG_PKT_FMT before reading any l_oob fields.

net_backend::ETHERNET_VLAN_HEADER_LEN
} else {
net_backend::ETHERNET_HEADER_LEN
};
let mut meta = TxMetadata {
id: TxId(0),
segment_count: sqe.sgl().len().try_into().unwrap(),
Expand All @@ -558,10 +568,19 @@ impl TxRxTask {
.with_offload_udp_checksum(oob.s_oob.comp_udp_csum())
.with_is_ipv4(oob.s_oob.is_outer_ipv4())
.with_is_ipv6(oob.s_oob.is_outer_ipv6() && !oob.s_oob.is_outer_ipv4()),
l2_len: 14,
l3_len: oob.s_oob.trans_off().clamp(14, 255) - 14,
l2_len: l2_len as u8,
l3_len: oob.s_oob.trans_off().clamp(l2_len as u16, 255) - l2_len as u16,
l4_len: 0,
transport_header_offset: oob.s_oob.trans_off(),
max_segment_size: 0,
vlan: oob
.l_oob
.inject_vlan_pri_tag()
.then(|| net_backend::VlanMetadata {
priority: oob.l_oob.pcp(),
drop_eligible_indicator: oob.l_oob.dei(),
vlan_id: oob.l_oob.vlan_id(),
}),
};

if sqe.header.params.client_oob_in_sgl() {
Expand Down
38 changes: 38 additions & 0 deletions vm/devices/net/net_backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ pub trait BackendQueueStats {
fn tx_errors(&self) -> Counter;
fn rx_packets(&self) -> Counter;
fn tx_packets(&self) -> Counter;
fn tx_vlan_packets(&self) -> Counter {
Counter::new()
}
fn rx_vlan_packets(&self) -> Counter {
Counter::new()
}
}

/// A single TX/RX data path for sending and receiving network packets.
Expand Down Expand Up @@ -281,6 +287,24 @@ pub trait BufferAccess {
}
}

pub const ETHERNET_HEADER_LEN: u32 = 14;
pub const ETHERNET_VLAN_HEADER_LEN: u32 = 18;

pub const IPV4_MIN_HEADER_LEN: u16 = 20;
pub const IPV6_MIN_HEADER_LEN: u16 = 40;

#[derive(Debug, Copy, Clone)]
pub struct VlanMetadata {
/// Priority for 802.1Q. Actually a 3-bit value.
pub priority: u8,
/// In pretty much every circumstance this is false. When
/// it is used, setting DEI will inform switches/routing infra
/// that this can be dropped before higher priority traffic.
pub drop_eligible_indicator: bool,
/// The 802.1Q ID for this transmission. Actually a 12-bit value.
pub vlan_id: u16,
}

/// A receive buffer ID.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
Expand Down Expand Up @@ -308,6 +332,10 @@ pub struct RxMetadata {
pub l4_checksum: RxChecksumState,
/// The L4 protocol.
pub l4_protocol: L4Protocol,
/// Information about 802.1Q VLAN tagging. When a vlan is in use, this structure
/// is populated. Only applies when traffic is being received over an L2 connection,
/// so L3-only or above traffic will not use this option.
pub vlan: Option<VlanMetadata>,
}

impl Default for RxMetadata {
Expand All @@ -318,6 +346,7 @@ impl Default for RxMetadata {
ip_checksum: RxChecksumState::Unknown,
l4_checksum: RxChecksumState::Unknown,
l4_protocol: L4Protocol::Unknown,
vlan: None,
}
}
}
Expand Down Expand Up @@ -396,10 +425,17 @@ pub struct TxMetadata {
/// The length of the TCP header. Only guaranteed to be set if various
/// offload flags are set.
pub l4_len: u8,
/// The offset into the buffer where the L4 header begins (TCP or UDP). Only
/// expected to be set if offload (checksum and/or segmentation) flags are set.
pub transport_header_offset: u16,
/// The maximum segment size, used for segmentation offload (TSO or USO).
/// Only guaranteed to be set if [`TxFlags::offload_tcp_segmentation`] or
/// [`TxFlags::offload_udp_segmentation`] is set.
pub max_segment_size: u16,
/// Information about 802.1Q VLAN tagging. When a vlan is in use, this structure
/// is populated. Only applies when traffic is being sent over an L2 connection,
/// so L3-only or above traffic will not use this option.
Comment thread
ben-zen marked this conversation as resolved.
pub vlan: Option<VlanMetadata>,
}

/// Flags affecting transmit behavior.
Expand Down Expand Up @@ -444,7 +480,9 @@ impl Default for TxMetadata {
l2_len: 0,
l3_len: 0,
l4_len: 0,
transport_header_offset: 0,
max_segment_size: 0,
vlan: None,
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions vm/devices/net/net_backend/src/loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::TxError;
use crate::TxId;
use crate::TxSegment;
use crate::linearize;
use crate::next_packet;
use crate::packet_count;
use async_trait::async_trait;
use inspect::InspectMut;
Expand Down Expand Up @@ -114,6 +115,8 @@ impl Queue for LoopbackQueue {
tracing::debug!(count = packet_count(segments), "tx_avail");
let mut sent = 0;
while !segments.is_empty() && !self.rx_avail.is_empty() {
let (meta, _, _) = next_packet(segments);
let vlan = meta.vlan;
let before = segments.len();
let packet = linearize(pool, &mut segments)?;
sent += before - segments.len();
Expand All @@ -123,6 +126,7 @@ impl Queue for LoopbackQueue {
&RxMetadata {
offset: 0,
len: packet.len(),
vlan,
..Default::default()
},
&packet,
Expand Down
7 changes: 7 additions & 0 deletions vm/devices/net/net_backend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,10 @@ impl BufferAccess for Bufs {
*self.inner.rx_metadata[id.0 as usize].lock() = Some(*metadata);
}
}

impl Bufs {
/// Returns the [`RxMetadata`] written for the given receive buffer, if any.
pub fn rx_metadata(&self, id: RxId) -> Option<RxMetadata> {
*self.inner.rx_metadata[id.0 as usize].lock()
}
}
1 change: 1 addition & 0 deletions vm/devices/net/net_consomme/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ impl consomme::Client for Client<'_> {
} else {
L4Protocol::Unknown
},
vlan: None,
},
data,
);
Expand Down
53 changes: 51 additions & 2 deletions vm/devices/net/net_mana/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use gdma_defs::bnic::MANA_SHORT_PKT_FMT;
use gdma_defs::bnic::ManaQueryStatisticsResponse;
use gdma_defs::bnic::ManaRxcompOob;
use gdma_defs::bnic::ManaTxCompOob;
use gdma_defs::bnic::ManaTxLongOob;
use gdma_defs::bnic::ManaTxOob;
use gdma_defs::bnic::ManaTxShortOob;
use guestmem::GuestMemory;
Expand Down Expand Up @@ -58,6 +59,7 @@ use net_backend::TxId;
use net_backend::TxOffloadSupport;
use net_backend::TxSegment;
use net_backend::TxSegmentType;
use net_backend::VlanMetadata;
use pal_async::task::Spawn;
use safeatomic::AtomicSliceOps;
use std::collections::VecDeque;
Expand Down Expand Up @@ -648,12 +650,14 @@ struct PostedTx {
struct QueueStats {
tx_events: Counter,
tx_packets: Counter,
tx_vlan_packets: Counter,
tx_errors: Counter,
tx_dropped: Counter,
tx_stuck: Counter,

rx_events: Counter,
rx_packets: Counter,
rx_vlan_packets: Counter,
rx_errors: Counter,

interrupts: Counter,
Expand Down Expand Up @@ -828,6 +832,27 @@ impl<T: DeviceBacking> ManaQueue<T> {
short_vp_offset = tx_s_oob.short_vp_offset(),
"tx s_oob"
);

if tx_s_oob.pkt_fmt() == MANA_LONG_PKT_FMT {
let l_oob_offset = wqe_offset + (header_size + s_oob_size) as u32;
let l_oob_bytes = self.tx_wq.read(l_oob_offset, size_of::<ManaTxLongOob>());
match ManaTxLongOob::read_from_prefix(&l_oob_bytes) {
Ok((tx_l_oob, _)) => {
tracelimit::event_ratelimited!(
tracing_level,
inject_vlan_pri_tag = tx_l_oob.inject_vlan_pri_tag(),
vlan_id = tx_l_oob.vlan_id(),
pcp = tx_l_oob.pcp(),
dei = tx_l_oob.dei(),
long_vp_offset = tx_l_oob.long_vp_offset(),
"tx l_oob"
);
}
Err(_) => {
tracelimit::error_ratelimited!("failed to read tx l_oob");
}
}
}
}
Err(_) => {
tracelimit::error_ratelimited!("failed to read tx s_oob");
Expand Down Expand Up @@ -965,6 +990,11 @@ impl<T: DeviceBacking + Send> Queue for ManaQueue<T> {
} else {
(L4Protocol::Unknown, RxChecksumState::Unknown)
};
let vlantag = rx_oob.flags.rx_vlantag_present().then(|| VlanMetadata {
drop_eligible_indicator: false,
priority: 0,
vlan_id: rx_oob.flags.rx_vlan_id() as u16,
});
Comment thread
erfrimod marked this conversation as resolved.
let len = rx_oob.ppi[0].pkt_len.into();
pool.write_header(
rx.id,
Expand All @@ -974,6 +1004,7 @@ impl<T: DeviceBacking + Send> Queue for ManaQueue<T> {
ip_checksum,
l4_checksum,
l4_protocol,
vlan: vlantag,
},
);
if rx.bounced_len_with_padding > 0 {
Expand All @@ -986,6 +1017,9 @@ impl<T: DeviceBacking + Send> Queue for ManaQueue<T> {
pool.write_data(rx.id, &data);
}
self.stats.rx_packets.increment();
if vlantag.is_some() {
self.stats.rx_vlan_packets.increment();
}
packets[i] = rx.id;
i += 1;
}
Expand All @@ -995,6 +1029,8 @@ impl<T: DeviceBacking + Send> Queue for ManaQueue<T> {
vendor_err = rx_oob.cqe_hdr.vendor_err(),
rx_cq_id = self.rx_cq.id(),
rx_wq_id = self.rx_wq.id(),
rx_vlantag_present = rx_oob.flags.rx_vlantag_present(),
rx_vlan_id = rx_oob.flags.rx_vlan_id(),
"invalid rx cqe type"
);
self.trace_rx_wqe_from_offset(rx_oob.rx_wqe_offset);
Expand Down Expand Up @@ -1137,6 +1173,12 @@ impl BackendQueueStats for QueueStats {
fn tx_packets(&self) -> Counter {
self.tx_packets.clone()
}
fn tx_vlan_packets(&self) -> Counter {
self.tx_vlan_packets.clone()
}
fn rx_vlan_packets(&self) -> Counter {
self.rx_vlan_packets.clone()
}
}

impl<T: DeviceBacking> ManaQueue<T> {
Expand All @@ -1163,10 +1205,17 @@ impl<T: DeviceBacking> ManaQueue<T> {
.set_comp_tcp_csum(meta.flags.offload_tcp_checksum());
oob.s_oob
.set_comp_udp_csum(meta.flags.offload_udp_checksum());
if meta.flags.offload_tcp_checksum() {
if meta.flags.offload_tcp_checksum() || meta.flags.offload_udp_checksum() {
oob.s_oob.set_trans_off(meta.l2_len as u16 + meta.l3_len);
}
let short_format = self.vp_offset <= 0xff;
if let Some(vlan) = &meta.vlan {
oob.l_oob.set_inject_vlan_pri_tag(true);
oob.l_oob.set_vlan_id(vlan.vlan_id);
oob.l_oob.set_pcp(vlan.priority);
oob.l_oob.set_dei(vlan.drop_eligible_indicator);
self.stats.tx_vlan_packets.increment();
}
let short_format = self.vp_offset <= 0xff && meta.vlan.is_none();
if short_format {
oob.s_oob.set_pkt_fmt(MANA_SHORT_PKT_FMT);
oob.s_oob.set_short_vp_offset(self.vp_offset as u8);
Expand Down
Loading
Loading