Add virtio net device driver

This commit is contained in:
Jianfeng Jiang
2023-05-30 16:34:28 +08:00
committed by Tate, Hongliang Tian
parent 2985cdced6
commit 7304e06c88
20 changed files with 875 additions and 15 deletions

View File

@ -0,0 +1,17 @@
[package]
name = "jinux-network"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
component = { path = "../../libs/comp-sys/component" }
jinux-frame = { path = "../../../framework/jinux-frame" }
jinux-virtio = { path = "../virtio" }
jinux-util = { path = "../../libs/jinux-util" }
jinux-pci = { path = "../pci" }
spin = "0.9.4"
ringbuf = { version = "0.3.2", default-features = false, features = ["alloc"] }
log = "0.4"
smoltcp = { version = "0.9.1", default-features = false, features = ["alloc", "log", "medium-ethernet", "medium-ip", "proto-dhcpv4", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw", "socket-dhcpv4"] }

View File

@ -0,0 +1,71 @@
use alloc::vec;
use smoltcp::phy::{self, Medium};
use crate::VirtioNet;
use jinux_virtio::device::network::{
buffer::{RxBuffer, TxBuffer},
device::NetworkDevice,
};
impl phy::Device for VirtioNet {
type RxToken<'a> = RxToken;
type TxToken<'a> = TxToken<'a>;
fn receive(
&mut self,
_timestamp: smoltcp::time::Instant,
) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
if self.can_receive() {
let device = self.device_mut();
let rx_buffer = device.receive().unwrap();
Some((RxToken(rx_buffer), TxToken(device)))
} else {
None
}
}
fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
if self.can_send() {
let device = self.device_mut();
Some(TxToken(device))
} else {
None
}
}
fn capabilities(&self) -> phy::DeviceCapabilities {
let mut caps = phy::DeviceCapabilities::default();
caps.max_transmission_unit = 1536;
caps.max_burst_size = Some(1);
caps.medium = Medium::Ethernet;
caps
}
}
pub struct RxToken(RxBuffer);
impl phy::RxToken for RxToken {
fn consume<R, F>(mut self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let packet_but = self.0.packet_mut();
let res = f(packet_but);
res
}
}
pub struct TxToken<'a>(&'a mut NetworkDevice);
impl<'a> phy::TxToken for TxToken<'a> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let mut buffer = vec![0u8; len];
let res = f(&mut buffer);
let tx_buffer = TxBuffer::new(&buffer);
self.0.send(tx_buffer).expect("Send packet failed");
res
}
}

View File

@ -0,0 +1,59 @@
#![no_std]
#![forbid(unsafe_code)]
#![feature(trait_alias)]
extern crate alloc;
use alloc::sync::Arc;
use alloc::vec::Vec;
use component::init_component;
use component::ComponentInitError;
use core::any::Any;
use jinux_frame::sync::SpinLock;
use jinux_virtio::device::network::device::EthernetAddr;
use jinux_virtio::VirtioDeviceType;
use spin::Once;
mod driver;
mod virtio;
pub use virtio::VirtioNet;
pub trait NetworkDevice: Send + Sync + Any {
fn irq_number(&self) -> u8;
fn name(&self) -> &'static str;
fn mac_addr(&self) -> EthernetAddr;
}
pub trait NetDeviceIrqHandler = Fn(u8) + Send + Sync + 'static;
pub(crate) static NETWORK_IRQ_HANDLERS: Once<SpinLock<Vec<Arc<dyn NetDeviceIrqHandler>>>> =
Once::new();
#[init_component]
fn init() -> Result<(), ComponentInitError> {
NETWORK_IRQ_HANDLERS.call_once(|| SpinLock::new(Vec::new()));
Ok(())
}
pub fn probe_virtio_net() -> Result<VirtioNet, ComponentInitError> {
let network_devices = {
let virtio = jinux_virtio::VIRTIO_COMPONENT.get().unwrap();
virtio.get_device(VirtioDeviceType::Network)
};
for device in network_devices {
let virtio_net = VirtioNet::new(device);
// FIXME: deal with multiple net devices
return Ok(virtio_net);
}
Err(ComponentInitError::Unknown)
}
pub fn register_net_device_irq_handler(callback: impl NetDeviceIrqHandler) {
NETWORK_IRQ_HANDLERS
.get()
.unwrap()
.lock()
.push(Arc::new(callback))
}

View File

@ -0,0 +1,103 @@
use jinux_frame::offset_of;
use jinux_frame::sync::SpinLock;
use jinux_frame::trap::TrapFrame;
use jinux_pci::msix::MSIX;
use jinux_util::frame_ptr::InFramePtr;
use jinux_virtio::device::network::device::{self, EthernetAddr};
use jinux_virtio::PCIVirtioDevice;
use jinux_virtio::VirtioPciCommonCfg;
use log::debug;
use crate::{NetworkDevice, NETWORK_IRQ_HANDLERS};
pub struct VirtioNet {
/// Network Device
device: device::NetworkDevice,
/// Own common cfg to avoid other devices access this frame
_common_cfg: InFramePtr<VirtioPciCommonCfg>,
_msix: SpinLock<MSIX>,
irq_number: u8,
}
impl NetworkDevice for VirtioNet {
fn irq_number(&self) -> u8 {
self.irq_number
}
fn name(&self) -> &'static str {
"virtio net"
}
fn mac_addr(&self) -> EthernetAddr {
self.device.mac_addr()
}
}
impl VirtioNet {
pub(crate) fn new(virtio_device: PCIVirtioDevice) -> Self {
let device = if let jinux_virtio::device::VirtioDevice::Network(network_device) =
virtio_device.device
{
network_device
} else {
panic!("Invalid device type")
};
let common_cfg = virtio_device.common_cfg;
let mut msix = virtio_device.msix;
let config_msix_vector =
common_cfg.read_at(offset_of!(VirtioPciCommonCfg, config_msix_vector)) as usize;
let mut network_irq_num = 0;
for i in 0..msix.table_size as usize {
let msix_entry = msix.table.get_mut(i).unwrap();
if !msix_entry.irq_handle.is_empty() {
panic!("msix already have irq functions");
}
if config_msix_vector == i {
debug!(
"network config space change irq number = {}",
msix_entry.irq_handle.num()
);
msix_entry.irq_handle.on_active(config_space_change);
} else {
network_irq_num = msix_entry.irq_handle.num();
msix_entry.irq_handle.on_active(handle_network_event);
}
}
debug_assert!(network_irq_num != 0);
debug!("Network device irq num = {}", network_irq_num);
let device = VirtioNet {
device,
_common_cfg: common_cfg,
irq_number: network_irq_num,
_msix: SpinLock::new(msix),
};
device
}
pub(crate) fn can_receive(&self) -> bool {
self.device.can_receive()
}
pub(crate) fn can_send(&self) -> bool {
self.device.can_send()
}
pub(crate) fn device_mut(&mut self) -> &mut device::NetworkDevice {
&mut self.device
}
}
/// Interrupt handler if network device config space changes
fn config_space_change(_: &TrapFrame) {
debug!("network device config space change");
}
/// Interrupt handler if network device receives some packet
fn handle_network_event(trap_frame: &TrapFrame) {
let irq_num = trap_frame.trap_num as u8;
for callback in NETWORK_IRQ_HANDLERS.get().unwrap().lock().iter() {
callback(irq_num);
}
}

View File

@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
bitflags = "1.3"
spin = "0.9.4"
bytes = { version = "1.4.0", default-features = false }
align_ext = { path = "../../../framework/libs/align_ext" }
jinux-frame = { path = "../../../framework/jinux-frame" }
jinux-pci = { path = "../pci" }

View File

@ -9,10 +9,11 @@ use jinux_pci::{
};
use jinux_util::frame_ptr::InFramePtr;
use self::input::device::InputDevice;
use self::{input::device::InputDevice, network::device::NetworkDevice};
pub mod block;
pub mod input;
pub mod network;
pub(crate) const PCI_VIRTIO_CAP_COMMON_CFG: u8 = 1;
pub(crate) const PCI_VIRTIO_CAP_NOTIFY_CFG: u8 = 2;
@ -20,9 +21,8 @@ pub(crate) const PCI_VIRTIO_CAP_ISR_CFG: u8 = 3;
pub(crate) const PCI_VIRTIO_CAP_DEVICE_CFG: u8 = 4;
pub(crate) const PCI_VIRTIO_CAP_PCI_CFG: u8 = 5;
#[derive(Debug)]
pub enum VirtioDevice {
Network,
Network(NetworkDevice),
Block(BLKDevice),
Console,
Entropy,
@ -141,6 +141,14 @@ impl VirtioDevice {
virtio_info.notify_off_multiplier,
msix_vector_left,
)?),
VirtioDeviceType::Network => VirtioDevice::Network(NetworkDevice::new(
&virtio_info.device_cap_cfg,
bars,
&virtio_info.common_cfg_frame_ptr,
virtio_info.notify_base_address as usize,
virtio_info.notify_off_multiplier,
msix_vector_left,
)?),
_ => {
panic!("initialize PCIDevice failed, unsupport Virtio Device Type")
}
@ -152,7 +160,9 @@ impl VirtioDevice {
let mask = ((1u64 << 24) - 1) | (((1u64 << 24) - 1) << 50);
let device_specified_features = features & mask;
let device_support_features = match device_type {
VirtioDeviceType::Network => todo!(),
VirtioDeviceType::Network => {
NetworkDevice::negotiate_features(device_specified_features)
}
VirtioDeviceType::Block => BLKDevice::negotiate_features(device_specified_features),
VirtioDeviceType::Console => todo!(),
VirtioDeviceType::Entropy => todo!(),

View File

@ -0,0 +1,84 @@
use align_ext::AlignExt;
use bytes::BytesMut;
use pod::Pod;
use crate::device::network::header::VIRTIO_NET_HDR_LEN;
use super::header::VirtioNetHdr;
/// Buffer for receive packet
#[derive(Debug)]
pub struct RxBuffer {
/// Packet Buffer, length align 8.
buf: BytesMut,
/// Packet len
packet_len: usize,
}
impl RxBuffer {
pub fn new(len: usize) -> Self {
let len = len.align_up(8);
let buf = BytesMut::zeroed(len);
Self { buf, packet_len: 0 }
}
pub const fn packet_len(&self) -> usize {
self.packet_len
}
pub fn set_packet_len(&mut self, packet_len: usize) {
self.packet_len = packet_len;
}
pub fn buf(&self) -> &[u8] {
&self.buf
}
pub fn buf_mut(&mut self) -> &mut [u8] {
&mut self.buf
}
/// Packet payload slice, which is inner buffer excluding VirtioNetHdr.
pub fn packet(&self) -> &[u8] {
debug_assert!(VIRTIO_NET_HDR_LEN + self.packet_len <= self.buf.len());
&self.buf[VIRTIO_NET_HDR_LEN..VIRTIO_NET_HDR_LEN + self.packet_len]
}
/// Mutable packet payload slice.
pub fn packet_mut(&mut self) -> &mut [u8] {
debug_assert!(VIRTIO_NET_HDR_LEN + self.packet_len <= self.buf.len());
&mut self.buf[VIRTIO_NET_HDR_LEN..VIRTIO_NET_HDR_LEN + self.packet_len]
}
pub fn virtio_net_header(&self) -> VirtioNetHdr {
VirtioNetHdr::from_bytes(&self.buf[..VIRTIO_NET_HDR_LEN])
}
}
/// Buffer for transmit packet
#[derive(Debug)]
pub struct TxBuffer {
buf: BytesMut,
}
impl TxBuffer {
pub fn with_len(buf_len: usize) -> Self {
Self {
buf: BytesMut::zeroed(buf_len),
}
}
pub fn new(buf: &[u8]) -> Self {
Self {
buf: BytesMut::from(buf),
}
}
pub fn buf(&self) -> &[u8] {
&self.buf
}
pub fn buf_mut(&mut self) -> &mut [u8] {
&mut self.buf
}
}

View File

@ -0,0 +1,82 @@
use bitflags::bitflags;
use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, util::BAR};
use jinux_util::frame_ptr::InFramePtr;
use pod::Pod;
use super::device::EthernetAddr;
bitflags! {
/// Virtio Net Feature bits.
pub struct NetworkFeatures: u64 {
const VIRTIO_NET_F_CSUM = 1 << 0; // Device handles packets with partial checksum.
const VIRTIO_NET_F_GUEST_CSUM = 1 << 1; // Driver handles packets with partial checksum
const VIRTIO_NET_F_CTRL_GUEST_OFFLOADS = 1 << 2;// Control channel offloads reconfiguration support
const VIRTIO_NET_F_MTU = 1 << 3; // Device maximum MTU reporting is supported
const VIRTIO_NET_F_MAC = 1 << 5; // Device has given MAC address.
const VIRTIO_NET_F_GUEST_TSO4 = 1 << 7; // Driver can receive TSOv4.
const VIRTIO_NET_F_GUEST_TSO6 = 1 <<8; // Driver can receive TSOv6.
const VIRTIO_NET_F_GUEST_ECN = 1 << 9; // Driver can receive TSO with ECN.
const VIRTIO_NET_F_GUEST_UFO = 1 << 10; // Driver can receive UFO.
const VIRTIO_NET_F_HOST_TSO4 = 1 << 11; // Device can receive TSOv4.
const VIRTIO_NET_F_HOST_TSO6 = 1 <<12; // Device can receive TSOv6.
const VIRTIO_NET_F_HOST_ECN = 1 << 13; // Device can receive TSO with ECN.
const VIRTIO_NET_F_HOST_UFO = 1 << 14; // Device can receive UFO.
const VIRTIO_NET_F_MRG_RXBUF = 1 << 15; // Driver can merge receive buffers.
const VIRTIO_NET_F_STATUS = 1 << 16; // Configuration status field is available.
const VIRTIO_NET_F_CTRL_VQ = 1 << 17; // Control channel is available.
const VIRTIO_NET_F_CTRL_RX = 1 << 18; // Control channel RX mode support.
const VIRTIO_NET_F_CTRL_VLAN = 1 << 19; // Control channel VLAN filtering.
const VIRTIO_NET_F_EXTRA = 1 << 20; //
const VIRTIO_NET_F_GUEST_ANNOUNCE = 1 << 21; // Driver can send gratuitous packets.
const VIRTIO_NET_F_MQ = 1 << 22; // Device supports multiqueue with automatic receive steering.
const VIRTIO_NET_F_CTRL_MAC_ADDR = 1 << 23; // Set MAC address through control channel.
// const VIRTIO_NET_F_HOST_USO = 1 << 56; // Device can receive USO packets.
// const VIRTIO_NET_F_HASH_REPORT = 1 << 57; // Device can report per-packet hash value and a type of calculated hash.
// const VIRTIO_NET_F_GUEST_HDRLEN = 1 << 59; // Driver can provide the exact hdr_len value. Device benefits from knowing the exact header length.
// const VIRTIO_NET_F_RSS = 1 << 60; // Device supports RSS (receive-side scaling) with Toeplitz hash calculation and configurable hash parameters for receive steering.
// const VIRTIO_NET_F_RSC_EXT = 1 << 61; // DevicecanprocessduplicatedACKsandreportnumberofcoalescedseg- ments and duplicated ACKs.
// const VIRTIO_NET_F_STANDBY = 1 << 62; // Device may act as a standby for a primary device with the same MAC address.
// const VIRTIO_NET_F_SPEED_DUPLEX = 1 << 63; // Device reports speed and duplex.
}
}
impl NetworkFeatures {
pub fn support_features() -> Self {
NetworkFeatures::VIRTIO_NET_F_MAC | NetworkFeatures::VIRTIO_NET_F_STATUS
}
}
bitflags! {
#[repr(C)]
#[derive(Pod)]
pub struct Status: u16 {
const VIRTIO_NET_S_LINK_UP = 1;
const VIRTIO_NET_S_ANNOUNCE = 2;
}
}
#[derive(Debug, Clone, Copy, Pod)]
#[repr(C)]
pub struct VirtioNetConfig {
pub mac: EthernetAddr,
pub status: Status,
max_virtqueue_pairs: u16,
mtu: u16,
speed: u32,
duplex: u8,
rss_max_key_size: u8,
rss_max_indirection_table_length: u16,
supported_hash_types: u32,
}
impl VirtioNetConfig {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
let bar = cap.bar;
let offset = cap.offset;
match bars[bar as usize].expect("Virtio pci net cfg:bar is none") {
BAR::Memory(address, _, _, _) => InFramePtr::new(address as usize + offset as usize)
.expect("can not get in frame ptr for virtio net config"),
BAR::IO(_, _) => panic!("Virtio pci net cfg:bar is IO type"),
}
}
}

View File

@ -0,0 +1,219 @@
use core::hint::spin_loop;
use alloc::vec::Vec;
use jinux_frame::offset_of;
use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, util::BAR};
use jinux_util::{frame_ptr::InFramePtr, slot_vec::SlotVec};
use log::debug;
use pod::Pod;
use crate::{
device::{network::config::NetworkFeatures, VirtioDeviceError},
queue::{QueueError, VirtQueue},
VirtioPciCommonCfg,
};
use super::{
buffer::{RxBuffer, TxBuffer},
config::VirtioNetConfig,
header::VirtioNetHdr,
};
#[derive(Debug, Clone, Copy, Pod)]
#[repr(C)]
pub struct EthernetAddr(pub [u8; 6]);
#[derive(Debug, Clone, Copy)]
pub enum VirtioNetError {
NotReady,
WrongToken,
Unknown,
}
pub struct NetworkDevice {
config: VirtioNetConfig,
mac_addr: EthernetAddr,
send_queue: VirtQueue,
recv_queue: VirtQueue,
rx_buffers: SlotVec<RxBuffer>,
}
impl From<QueueError> for VirtioNetError {
fn from(value: QueueError) -> Self {
match value {
QueueError::NotReady => VirtioNetError::NotReady,
QueueError::WrongToken => VirtioNetError::WrongToken,
_ => VirtioNetError::Unknown,
}
}
}
impl NetworkDevice {
pub(crate) fn negotiate_features(device_features: u64) -> u64 {
let device_features = NetworkFeatures::from_bits_truncate(device_features);
let supported_features = NetworkFeatures::support_features();
let network_features = device_features & supported_features;
debug!("{:?}", network_features);
network_features.bits()
}
pub fn new(
cap: &CapabilityVirtioData,
bars: [Option<BAR>; 6],
common_cfg: &InFramePtr<VirtioPciCommonCfg>,
notify_base_address: usize,
notify_off_multiplier: u32,
mut msix_vector_left: Vec<u16>,
) -> Result<Self, VirtioDeviceError> {
let virtio_net_config = VirtioNetConfig::new(cap, bars);
let features = {
// select low
common_cfg.write_at(
offset_of!(VirtioPciCommonCfg, device_feature_select),
0 as u32,
);
let device_feature_low =
common_cfg.read_at(offset_of!(VirtioPciCommonCfg, device_feature)) as u64;
// select high
common_cfg.write_at(
offset_of!(VirtioPciCommonCfg, device_feature_select),
1 as u32,
);
let device_feature_high =
common_cfg.read_at(offset_of!(VirtioPciCommonCfg, device_feature)) as u64;
let device_feature = device_feature_high << 32 | device_feature_low;
NetworkFeatures::from_bits_truncate(Self::negotiate_features(device_feature))
};
debug!("virtio_net_config = {:?}", virtio_net_config);
debug!("features = {:?}", features);
let mac_addr = virtio_net_config.read_at(offset_of!(VirtioNetConfig, mac));
let status = virtio_net_config.read_at(offset_of!(VirtioNetConfig, status));
debug!("mac addr = {:x?}, status = {:?}", mac_addr, status);
let (recv_msix_vec, send_msix_vec) = {
if msix_vector_left.len() >= 2 {
let vector1 = msix_vector_left.pop().unwrap();
let vector2 = msix_vector_left.pop().unwrap();
(vector1, vector2)
} else {
let vector = msix_vector_left.pop().unwrap();
(vector, vector)
}
};
let mut recv_queue = VirtQueue::new(
&common_cfg,
QUEUE_RECV as usize,
QUEUE_SIZE,
notify_base_address,
notify_off_multiplier,
recv_msix_vec,
)
.expect("creating recv queue fails");
let send_queue = VirtQueue::new(
&common_cfg,
QUEUE_SEND as usize,
QUEUE_SIZE,
notify_base_address,
notify_off_multiplier,
send_msix_vec,
)
.expect("create send queue fails");
let mut rx_buffers = SlotVec::new();
for i in 0..QUEUE_SIZE {
let mut rx_buffer = RxBuffer::new(RX_BUFFER_LEN);
let token = recv_queue.add(&[], &mut [rx_buffer.buf_mut()])?;
assert_eq!(i, token);
assert_eq!(rx_buffers.put(rx_buffer) as u16, i);
}
if recv_queue.should_notify() {
debug!("notify receive queue");
recv_queue.notify();
}
Ok(Self {
config: virtio_net_config.read(),
mac_addr,
send_queue,
recv_queue,
rx_buffers,
})
}
/// Add a rx buffer to recv queue
fn add_rx_buffer(&mut self, mut rx_buffer: RxBuffer) -> Result<(), VirtioNetError> {
let token = self.recv_queue.add(&[], &mut [rx_buffer.buf_mut()])?;
assert!(self.rx_buffers.put_at(token as usize, rx_buffer).is_none());
if self.recv_queue.should_notify() {
self.recv_queue.notify();
}
Ok(())
}
// Acknowledge interrupt
pub fn ack_interrupt(&self) -> bool {
todo!()
}
/// The mac address
pub fn mac_addr(&self) -> EthernetAddr {
self.mac_addr
}
/// Send queue is ready
pub fn can_send(&self) -> bool {
self.send_queue.available_desc() >= 2
}
/// Receive queue is ready
pub fn can_receive(&self) -> bool {
self.recv_queue.can_pop()
}
/// Receive a packet from network. If packet is ready, returns a RxBuffer containing the packet.
/// Otherwise, return NotReady error.
pub fn receive(&mut self) -> Result<RxBuffer, VirtioNetError> {
let (token, len) = self.recv_queue.pop_used()?;
debug!("receive packet: token = {}, len = {}", token, len);
let mut rx_buffer = self
.rx_buffers
.remove(token as usize)
.ok_or(VirtioNetError::WrongToken)?;
rx_buffer.set_packet_len(len as usize);
// FIXME: Ideally, we can reuse the returned buffer without creating new buffer.
// But this requires locking device to be compatible with smoltcp interface.
let new_rx_buffer = RxBuffer::new(RX_BUFFER_LEN);
self.add_rx_buffer(new_rx_buffer)?;
Ok(rx_buffer)
}
/// Send a packet to network. Return until the request completes.
pub fn send(&mut self, tx_buffer: TxBuffer) -> Result<(), VirtioNetError> {
let header = VirtioNetHdr::default();
let token = self
.send_queue
.add(&[header.as_bytes(), tx_buffer.buf()], &mut [])?;
if self.send_queue.should_notify() {
self.send_queue.notify();
}
// Wait until the buffer is used
while !self.send_queue.can_pop() {
spin_loop();
}
// Pop out the buffer, so we can reuse the send queue further
let (pop_token, _) = self.send_queue.pop_used()?;
debug_assert!(pop_token == token);
if pop_token != token {
return Err(VirtioNetError::WrongToken);
}
debug!("send packet succeeds");
Ok(())
}
}
const QUEUE_RECV: u16 = 0;
const QUEUE_SEND: u16 = 1;
const QUEUE_SIZE: u16 = 64;
const RX_BUFFER_LEN: usize = 4096;

View File

@ -0,0 +1,44 @@
use bitflags::bitflags;
use int_to_c_enum::TryFromInt;
use pod::Pod;
pub const VIRTIO_NET_HDR_LEN: usize = core::mem::size_of::<VirtioNetHdr>();
/// VirtioNet header precedes each packet
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Pod)]
pub struct VirtioNetHdr {
flags: Flags,
gso_type: u8,
hdr_len: u16,
gso_size: u16,
csum_start: u16,
csum_offset: u16,
num_buffers: u16, // Only if PCI is modern or VIRTIO_NET_F_MRG_RXBUF negotiated
// hash_value: u32, // Only if VIRTIO_NET_F_HASH_REPORT negotiated
// hash_report: u16, // Only if VIRTIO_NET_F_HASH_REPORT negotiated
// padding_reserved: u16, // Only if VIRTIO_NET_F_HASH_REPORT negotiated
}
bitflags! {
#[repr(C)]
#[derive(Default, Pod)]
pub struct Flags: u8 {
const VIRTIO_NET_HDR_F_NEEDS_CSUM = 1;
const VIRTIO_NET_HDR_F_DATA_VALID = 2;
const VIRTIO_NET_HDR_F_RSC_INFO = 4;
}
}
#[repr(u8)]
#[derive(Default, Debug, Clone, Copy, TryFromInt)]
#[allow(non_camel_case_types)]
pub enum GsoType {
#[default]
VIRTIO_NET_HDR_GSO_NONE = 0,
VIRTIO_NET_HDR_GSO_TCPV4 = 1,
VIRTIO_NET_HDR_GSO_UDP = 3,
VIRTIO_NET_HDR_GSO_TCPV6 = 4,
VIRTIO_NET_HDR_GSO_UDP_L4 = 5,
VIRTIO_NET_HDR_GSO_ECN = 0x80,
}

View File

@ -0,0 +1,4 @@
pub mod buffer;
pub mod config;
pub mod device;
pub mod header;

View File

@ -202,7 +202,7 @@ pub enum VirtioDeviceType {
impl VirtioDeviceType {
pub fn from_virtio_device(device: &VirtioDevice) -> Self {
match device {
VirtioDevice::Network => VirtioDeviceType::Network,
VirtioDevice::Network(_) => VirtioDeviceType::Network,
VirtioDevice::Block(_) => VirtioDeviceType::Block,
VirtioDevice::Console => VirtioDeviceType::Console,
VirtioDevice::Entropy => VirtioDeviceType::Entropy,