net.rs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //! Driver for VirtIO network devices.
  2. use crate::hal::Hal;
  3. use crate::queue::VirtQueue;
  4. use crate::transport::Transport;
  5. use crate::volatile::{volread, ReadOnly};
  6. use crate::Result;
  7. use bitflags::bitflags;
  8. use core::mem::{size_of, MaybeUninit};
  9. use log::{debug, info};
  10. use zerocopy::{AsBytes, FromBytes};
  11. const QUEUE_SIZE: u16 = 2;
  12. /// The virtio network device is a virtual ethernet card.
  13. ///
  14. /// It has enhanced rapidly and demonstrates clearly how support for new
  15. /// features are added to an existing device.
  16. /// Empty buffers are placed in one virtqueue for receiving packets, and
  17. /// outgoing packets are enqueued into another for transmission in that order.
  18. /// A third command queue is used to control advanced filtering features.
  19. pub struct VirtIONet<H: Hal, T: Transport> {
  20. transport: T,
  21. mac: EthernetAddress,
  22. recv_queue: VirtQueue<H, { QUEUE_SIZE as usize }>,
  23. send_queue: VirtQueue<H, { QUEUE_SIZE as usize }>,
  24. }
  25. impl<H: Hal, T: Transport> VirtIONet<H, T> {
  26. /// Create a new VirtIO-Net driver.
  27. pub fn new(mut transport: T) -> Result<Self> {
  28. transport.begin_init(|features| {
  29. let features = Features::from_bits_truncate(features);
  30. info!("Device features {:?}", features);
  31. let supported_features = Features::MAC | Features::STATUS;
  32. (features & supported_features).bits()
  33. });
  34. // read configuration space
  35. let config = transport.config_space::<Config>()?;
  36. let mac;
  37. // Safe because config points to a valid MMIO region for the config space.
  38. unsafe {
  39. mac = volread!(config, mac);
  40. debug!("Got MAC={:?}, status={:?}", mac, volread!(config, status));
  41. }
  42. let recv_queue = VirtQueue::new(&mut transport, QUEUE_RECEIVE)?;
  43. let send_queue = VirtQueue::new(&mut transport, QUEUE_TRANSMIT)?;
  44. transport.finish_init();
  45. Ok(VirtIONet {
  46. transport,
  47. mac,
  48. recv_queue,
  49. send_queue,
  50. })
  51. }
  52. /// Acknowledge interrupt.
  53. pub fn ack_interrupt(&mut self) -> bool {
  54. self.transport.ack_interrupt()
  55. }
  56. /// Get MAC address.
  57. pub fn mac(&self) -> EthernetAddress {
  58. self.mac
  59. }
  60. /// Whether can send packet.
  61. pub fn can_send(&self) -> bool {
  62. self.send_queue.available_desc() >= 2
  63. }
  64. /// Whether can receive packet.
  65. pub fn can_recv(&self) -> bool {
  66. self.recv_queue.can_pop()
  67. }
  68. /// Receive a packet.
  69. pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize> {
  70. let mut header = MaybeUninit::<Header>::uninit();
  71. let header_buf = unsafe { (*header.as_mut_ptr()).as_bytes_mut() };
  72. let len =
  73. self.recv_queue
  74. .add_notify_wait_pop(&[], &[header_buf, buf], &mut self.transport)?;
  75. // let header = unsafe { header.assume_init() };
  76. Ok(len as usize - size_of::<Header>())
  77. }
  78. /// Send a packet.
  79. pub fn send(&mut self, buf: &[u8]) -> Result {
  80. let header = unsafe { MaybeUninit::<Header>::zeroed().assume_init() };
  81. self.send_queue
  82. .add_notify_wait_pop(&[header.as_bytes(), buf], &[], &mut self.transport)?;
  83. Ok(())
  84. }
  85. }
  86. impl<H: Hal, T: Transport> Drop for VirtIONet<H, T> {
  87. fn drop(&mut self) {
  88. // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
  89. // after they have been freed.
  90. self.transport.queue_unset(QUEUE_RECEIVE);
  91. self.transport.queue_unset(QUEUE_TRANSMIT);
  92. }
  93. }
  94. bitflags! {
  95. struct Features: u64 {
  96. /// Device handles packets with partial checksum.
  97. /// This "checksum offload" is a common feature on modern network cards.
  98. const CSUM = 1 << 0;
  99. /// Driver handles packets with partial checksum.
  100. const GUEST_CSUM = 1 << 1;
  101. /// Control channel offloads reconfiguration support.
  102. const CTRL_GUEST_OFFLOADS = 1 << 2;
  103. /// Device maximum MTU reporting is supported.
  104. ///
  105. /// If offered by the device, device advises driver about the value of
  106. /// its maximum MTU. If negotiated, the driver uses mtu as the maximum
  107. /// MTU value.
  108. const MTU = 1 << 3;
  109. /// Device has given MAC address.
  110. const MAC = 1 << 5;
  111. /// Device handles packets with any GSO type. (legacy)
  112. const GSO = 1 << 6;
  113. /// Driver can receive TSOv4.
  114. const GUEST_TSO4 = 1 << 7;
  115. /// Driver can receive TSOv6.
  116. const GUEST_TSO6 = 1 << 8;
  117. /// Driver can receive TSO with ECN.
  118. const GUEST_ECN = 1 << 9;
  119. /// Driver can receive UFO.
  120. const GUEST_UFO = 1 << 10;
  121. /// Device can receive TSOv4.
  122. const HOST_TSO4 = 1 << 11;
  123. /// Device can receive TSOv6.
  124. const HOST_TSO6 = 1 << 12;
  125. /// Device can receive TSO with ECN.
  126. const HOST_ECN = 1 << 13;
  127. /// Device can receive UFO.
  128. const HOST_UFO = 1 << 14;
  129. /// Driver can merge receive buffers.
  130. const MRG_RXBUF = 1 << 15;
  131. /// Configuration status field is available.
  132. const STATUS = 1 << 16;
  133. /// Control channel is available.
  134. const CTRL_VQ = 1 << 17;
  135. /// Control channel RX mode support.
  136. const CTRL_RX = 1 << 18;
  137. /// Control channel VLAN filtering.
  138. const CTRL_VLAN = 1 << 19;
  139. ///
  140. const CTRL_RX_EXTRA = 1 << 20;
  141. /// Driver can send gratuitous packets.
  142. const GUEST_ANNOUNCE = 1 << 21;
  143. /// Device supports multiqueue with automatic receive steering.
  144. const MQ = 1 << 22;
  145. /// Set MAC address through control channel.
  146. const CTL_MAC_ADDR = 1 << 23;
  147. // device independent
  148. const RING_INDIRECT_DESC = 1 << 28;
  149. const RING_EVENT_IDX = 1 << 29;
  150. const VERSION_1 = 1 << 32; // legacy
  151. }
  152. }
  153. bitflags! {
  154. struct Status: u16 {
  155. const LINK_UP = 1;
  156. const ANNOUNCE = 2;
  157. }
  158. }
  159. bitflags! {
  160. struct InterruptStatus : u32 {
  161. const USED_RING_UPDATE = 1 << 0;
  162. const CONFIGURATION_CHANGE = 1 << 1;
  163. }
  164. }
  165. #[repr(C)]
  166. struct Config {
  167. mac: ReadOnly<EthernetAddress>,
  168. status: ReadOnly<Status>,
  169. }
  170. type EthernetAddress = [u8; 6];
  171. // virtio 5.1.6 Device Operation
  172. #[repr(C)]
  173. #[derive(AsBytes, Debug, FromBytes)]
  174. struct Header {
  175. flags: Flags,
  176. gso_type: GsoType,
  177. hdr_len: u16, // cannot rely on this
  178. gso_size: u16,
  179. csum_start: u16,
  180. csum_offset: u16,
  181. // payload starts from here
  182. }
  183. bitflags! {
  184. #[repr(transparent)]
  185. #[derive(AsBytes, FromBytes)]
  186. struct Flags: u8 {
  187. const NEEDS_CSUM = 1;
  188. const DATA_VALID = 2;
  189. const RSC_INFO = 4;
  190. }
  191. }
  192. #[repr(transparent)]
  193. #[derive(AsBytes, Debug, Copy, Clone, Eq, FromBytes, PartialEq)]
  194. struct GsoType(u8);
  195. impl GsoType {
  196. const NONE: GsoType = GsoType(0);
  197. const TCPV4: GsoType = GsoType(1);
  198. const UDP: GsoType = GsoType(3);
  199. const TCPV6: GsoType = GsoType(4);
  200. const ECN: GsoType = GsoType(0x80);
  201. }
  202. const QUEUE_RECEIVE: u16 = 0;
  203. const QUEUE_TRANSMIT: u16 = 1;