1 //! Driver for VirtIO network devices.
2 
3 #[cfg(feature = "alloc")]
4 mod dev;
5 mod dev_raw;
6 #[cfg(feature = "alloc")]
7 mod net_buf;
8 
9 pub use self::dev_raw::VirtIONetRaw;
10 #[cfg(feature = "alloc")]
11 pub use self::{dev::VirtIONet, net_buf::RxBuffer, net_buf::TxBuffer};
12 
13 use crate::volatile::ReadOnly;
14 use bitflags::bitflags;
15 use zerocopy::{AsBytes, FromBytes, FromZeroes};
16 
17 const MAX_BUFFER_LEN: usize = 65535;
18 const MIN_BUFFER_LEN: usize = 1526;
19 const NET_HDR_SIZE: usize = core::mem::size_of::<VirtioNetHdr>();
20 
21 bitflags! {
22     #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
23     struct Features: u64 {
24         /// Device handles packets with partial checksum.
25         /// This "checksum offload" is a common feature on modern network cards.
26         const CSUM = 1 << 0;
27         /// Driver handles packets with partial checksum.
28         const GUEST_CSUM = 1 << 1;
29         /// Control channel offloads reconfiguration support.
30         const CTRL_GUEST_OFFLOADS = 1 << 2;
31         /// Device maximum MTU reporting is supported.
32         ///
33         /// If offered by the device, device advises driver about the value of
34         /// its maximum MTU. If negotiated, the driver uses mtu as the maximum
35         /// MTU value.
36         const MTU = 1 << 3;
37         /// Device has given MAC address.
38         const MAC = 1 << 5;
39         /// Device handles packets with any GSO type. (legacy)
40         const GSO = 1 << 6;
41         /// Driver can receive TSOv4.
42         const GUEST_TSO4 = 1 << 7;
43         /// Driver can receive TSOv6.
44         const GUEST_TSO6 = 1 << 8;
45         /// Driver can receive TSO with ECN.
46         const GUEST_ECN = 1 << 9;
47         /// Driver can receive UFO.
48         const GUEST_UFO = 1 << 10;
49         /// Device can receive TSOv4.
50         const HOST_TSO4 = 1 << 11;
51         /// Device can receive TSOv6.
52         const HOST_TSO6 = 1 << 12;
53         /// Device can receive TSO with ECN.
54         const HOST_ECN = 1 << 13;
55         /// Device can receive UFO.
56         const HOST_UFO = 1 << 14;
57         /// Driver can merge receive buffers.
58         const MRG_RXBUF = 1 << 15;
59         /// Configuration status field is available.
60         const STATUS = 1 << 16;
61         /// Control channel is available.
62         const CTRL_VQ = 1 << 17;
63         /// Control channel RX mode support.
64         const CTRL_RX = 1 << 18;
65         /// Control channel VLAN filtering.
66         const CTRL_VLAN = 1 << 19;
67         /// Device supports VIRTIO_NET_CTRL_RX_ALLUNI, VIRTIO_NET_CTRL_RX_NOMULTI,
68         /// VIRTIO_NET_CTRL_RX_NOUNI and VIRTIO_NET_CTRL_RX_NOBCAST.
69         const CTRL_RX_EXTRA = 1 << 20;
70         /// Driver can send gratuitous packets.
71         const GUEST_ANNOUNCE = 1 << 21;
72         /// Device supports multiqueue with automatic receive steering.
73         const MQ = 1 << 22;
74         /// Set MAC address through control channel.
75         const CTL_MAC_ADDR = 1 << 23;
76 
77         // device independent
78         const RING_INDIRECT_DESC = 1 << 28;
79         const RING_EVENT_IDX = 1 << 29;
80         const VERSION_1 = 1 << 32; // legacy
81     }
82 }
83 
84 bitflags! {
85     #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
86     pub(crate) struct Status: u16 {
87         const LINK_UP = 1;
88         const ANNOUNCE = 2;
89     }
90 }
91 
92 bitflags! {
93     #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
94     struct InterruptStatus : u32 {
95         const USED_RING_UPDATE = 1 << 0;
96         const CONFIGURATION_CHANGE = 1 << 1;
97     }
98 }
99 
100 #[repr(C)]
101 struct Config {
102     mac: ReadOnly<EthernetAddress>,
103     status: ReadOnly<Status>,
104     max_virtqueue_pairs: ReadOnly<u16>,
105     mtu: ReadOnly<u16>,
106 }
107 
108 type EthernetAddress = [u8; 6];
109 
110 /// VirtIO 5.1.6 Device Operation:
111 ///
112 /// Packets are transmitted by placing them in the transmitq1. . .transmitqN,
113 /// and buffers for incoming packets are placed in the receiveq1. . .receiveqN.
114 /// In each case, the packet itself is preceded by a header.
115 #[repr(C)]
116 #[derive(AsBytes, Debug, Default, FromBytes, FromZeroes)]
117 pub struct VirtioNetHdr {
118     flags: Flags,
119     gso_type: GsoType,
120     hdr_len: u16, // cannot rely on this
121     gso_size: u16,
122     csum_start: u16,
123     csum_offset: u16,
124     // num_buffers: u16, // only available when the feature MRG_RXBUF is negotiated.
125     // payload starts from here
126 }
127 
128 #[derive(AsBytes, Copy, Clone, Debug, Default, Eq, FromBytes, FromZeroes, PartialEq)]
129 #[repr(transparent)]
130 struct Flags(u8);
131 
132 bitflags! {
133     impl Flags: u8 {
134         const NEEDS_CSUM = 1;
135         const DATA_VALID = 2;
136         const RSC_INFO   = 4;
137     }
138 }
139 
140 #[repr(transparent)]
141 #[derive(AsBytes, Debug, Copy, Clone, Default, Eq, FromBytes, FromZeroes, PartialEq)]
142 struct GsoType(u8);
143 
144 impl GsoType {
145     const NONE: GsoType = GsoType(0);
146     const TCPV4: GsoType = GsoType(1);
147     const UDP: GsoType = GsoType(3);
148     const TCPV6: GsoType = GsoType(4);
149     const ECN: GsoType = GsoType(0x80);
150 }
151 
152 const QUEUE_RECEIVE: u16 = 0;
153 const QUEUE_TRANSMIT: u16 = 1;
154 const SUPPORTED_FEATURES: Features = Features::MAC
155     .union(Features::STATUS)
156     .union(Features::RING_EVENT_IDX)
157     .union(Features::RING_INDIRECT_DESC);
158