virtio_drivers/device/net/dev.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
use alloc::vec;
use super::net_buf::{RxBuffer, TxBuffer};
use super::{EthernetAddress, VirtIONetRaw};
use crate::{hal::Hal, transport::Transport, Error, Result};
/// Driver for a VirtIO network device.
///
/// Unlike [`VirtIONetRaw`], it uses [`RxBuffer`]s for transmission and
/// reception rather than the raw slices. On initialization, it pre-allocates
/// all receive buffers and puts them all in the receive queue.
///
/// The virtio network device is a virtual ethernet card.
///
/// It has enhanced rapidly and demonstrates clearly how support for new
/// features are added to an existing device.
/// Empty buffers are placed in one virtqueue for receiving packets, and
/// outgoing packets are enqueued into another for transmission in that order.
/// A third command queue is used to control advanced filtering features.
pub struct VirtIONet<H: Hal, T: Transport, const QUEUE_SIZE: usize> {
inner: VirtIONetRaw<H, T, QUEUE_SIZE>,
rx_buffers: [Option<RxBuffer>; QUEUE_SIZE],
}
impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONet<H, T, QUEUE_SIZE> {
/// Create a new VirtIO-Net driver.
pub fn new(transport: T, buf_len: usize) -> Result<Self> {
let mut inner = VirtIONetRaw::new(transport)?;
const NONE_BUF: Option<RxBuffer> = None;
let mut rx_buffers = [NONE_BUF; QUEUE_SIZE];
for (i, rx_buf_place) in rx_buffers.iter_mut().enumerate() {
let mut rx_buf = RxBuffer::new(i, buf_len);
// Safe because the buffer lives as long as the queue.
let token = unsafe { inner.receive_begin(rx_buf.as_bytes_mut())? };
assert_eq!(token, i as u16);
*rx_buf_place = Some(rx_buf);
}
Ok(VirtIONet { inner, rx_buffers })
}
/// Acknowledge interrupt.
pub fn ack_interrupt(&mut self) -> bool {
self.inner.ack_interrupt()
}
/// Disable interrupts.
pub fn disable_interrupts(&mut self) {
self.inner.disable_interrupts()
}
/// Enable interrupts.
pub fn enable_interrupts(&mut self) {
self.inner.enable_interrupts()
}
/// Get MAC address.
pub fn mac_address(&self) -> EthernetAddress {
self.inner.mac_address()
}
/// Whether can send packet.
pub fn can_send(&self) -> bool {
self.inner.can_send()
}
/// Whether can receive packet.
pub fn can_recv(&self) -> bool {
self.inner.poll_receive().is_some()
}
/// Receives a [`RxBuffer`] from network. If currently no data, returns an
/// error with type [`Error::NotReady`].
///
/// It will try to pop a buffer that completed data reception in the
/// NIC queue.
pub fn receive(&mut self) -> Result<RxBuffer> {
if let Some(token) = self.inner.poll_receive() {
let mut rx_buf = self.rx_buffers[token as usize]
.take()
.ok_or(Error::WrongToken)?;
if token != rx_buf.idx {
return Err(Error::WrongToken);
}
// Safe because `token` == `rx_buf.idx`, we are passing the same
// buffer as we passed to `VirtQueue::add` and it is still valid.
let (_hdr_len, pkt_len) =
unsafe { self.inner.receive_complete(token, rx_buf.as_bytes_mut())? };
rx_buf.set_packet_len(pkt_len);
Ok(rx_buf)
} else {
Err(Error::NotReady)
}
}
/// Gives back the ownership of `rx_buf`, and recycles it for next use.
///
/// It will add the buffer back to the NIC queue.
pub fn recycle_rx_buffer(&mut self, mut rx_buf: RxBuffer) -> Result {
// Safe because we take the ownership of `rx_buf` back to `rx_buffers`,
// it lives as long as the queue.
let new_token = unsafe { self.inner.receive_begin(rx_buf.as_bytes_mut()) }?;
// `rx_buffers[new_token]` is expected to be `None` since it was taken
// away at `Self::receive()` and has not been added back.
if self.rx_buffers[new_token as usize].is_some() {
return Err(Error::WrongToken);
}
rx_buf.idx = new_token;
self.rx_buffers[new_token as usize] = Some(rx_buf);
Ok(())
}
/// Allocate a new buffer for transmitting.
pub fn new_tx_buffer(&self, buf_len: usize) -> TxBuffer {
TxBuffer(vec![0; buf_len])
}
/// Sends a [`TxBuffer`] to the network, and blocks until the request
/// completed.
pub fn send(&mut self, tx_buf: TxBuffer) -> Result {
self.inner.send(tx_buf.packet())
}
}