Skip to content

Commit bf65fd9

Browse files
committed
VirtIO 1.0 and multi-queue support
1 parent 2dc6437 commit bf65fd9

File tree

32 files changed

+2437
-797
lines changed

32 files changed

+2437
-797
lines changed

Cargo.lock

Lines changed: 1 addition & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ propolis_types = { path = "crates/propolis-types" }
5858
rfb = { path = "crates/rfb" }
5959
rgb_frame = { path = "crates/rgb-frame" }
6060
viona_api = { path = "crates/viona-api" }
61-
viona_api_sys = { path = "crates/viona-api/sys" }
6261

6362
# PHD testing framework
6463
phd-framework = { path = "phd-tests/framework" }

bin/propolis-server/src/lib/initializer.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -800,8 +800,6 @@ impl MachineInitializer<'_> {
800800

801801
let viona = virtio::PciVirtioViona::new(
802802
&nic.backend_spec.vnic_name,
803-
0x0800.try_into().unwrap(),
804-
0x0100.try_into().unwrap(),
805803
&self.machine.hdl,
806804
params,
807805
)

bin/propolis-standalone/src/main.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,8 +1262,6 @@ fn setup_instance(
12621262

12631263
let viona = hw::virtio::PciVirtioViona::new(
12641264
vnic_name,
1265-
0x0800.try_into().unwrap(),
1266-
0x0100.try_into().unwrap(),
12671265
&hdl,
12681266
viona_params,
12691267
)?;

crates/viona-api/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ doctest = false
99

1010
[dependencies]
1111
libc.workspace = true
12-
viona_api_sys.workspace = true
1312

1413
# nvpair dependency only enabled when building on illumos to avoid any attempts
1514
# to link to an absent libnvpair
1615
[target.'cfg(target_os = "illumos")'.dependencies]
1716
nvpair.workspace = true
1817

1918
[features]
20-
falcon = ["viona_api_sys/falcon"]
19+
falcon = []

crates/viona-api/header-check/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ version = "0.0.0"
44
license = "MPL-2.0"
55
build = "build.rs"
66
publish = false
7+
edition = "2021"
78

89
[dependencies]
9-
viona_api_sys = { path = "../sys" }
10+
viona_api = { path = ".." }
1011
libc = "0.2"
1112

1213
[build-dependencies]

crates/viona-api/header-check/build.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ fn main() {
1919
}
2020
};
2121

22-
let include_paths = [
23-
"usr/src/uts/intel",
24-
"usr/src/uts/common",
25-
];
22+
let include_paths = ["usr/src/uts/intel", "usr/src/uts/common"];
2623
cfg.include("/usr/include");
2724
for p in include_paths {
2825
cfg.include(gate_dir.join(p));
@@ -53,5 +50,5 @@ fn main() {
5350
_ => false,
5451
});
5552

56-
cfg.generate("../sys/src/lib.rs", "main.rs");
53+
cfg.generate("../src/ffi.rs", "main.rs");
5754
}

crates/viona-api/header-check/test/main.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5-
extern crate viona_api_sys;
6-
extern crate libc;
7-
8-
use viona_api_sys::*;
5+
use viona_api::*;
96

107
include!(concat!(env!("OUT_DIR"), "/main.rs"));

crates/viona-api/src/ffi.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
#![allow(non_camel_case_types)]
6+
7+
use libc::size_t;
8+
use std::ffi::c_void;
9+
10+
const fn vna_ioc(ioc: i32) -> i32 {
11+
const V: i32 = b'V' as i32;
12+
const C: i32 = b'C' as i32;
13+
V << 16 | C << 8 | ioc
14+
}
15+
16+
pub const VNA_IOC_CREATE: i32 = vna_ioc(0x01);
17+
pub const VNA_IOC_DELETE: i32 = vna_ioc(0x02);
18+
pub const VNA_IOC_VERSION: i32 = vna_ioc(0x03);
19+
pub const VNA_IOC_DEFAULT_PARAMS: i32 = vna_ioc(0x04);
20+
21+
pub const VNA_IOC_RING_INIT: i32 = vna_ioc(0x10);
22+
pub const VNA_IOC_RING_RESET: i32 = vna_ioc(0x11);
23+
pub const VNA_IOC_RING_KICK: i32 = vna_ioc(0x12);
24+
pub const VNA_IOC_RING_SET_MSI: i32 = vna_ioc(0x13);
25+
pub const VNA_IOC_RING_INTR_CLR: i32 = vna_ioc(0x14);
26+
pub const VNA_IOC_RING_SET_STATE: i32 = vna_ioc(0x15);
27+
pub const VNA_IOC_RING_GET_STATE: i32 = vna_ioc(0x16);
28+
pub const VNA_IOC_RING_PAUSE: i32 = vna_ioc(0x17);
29+
30+
pub const VNA_IOC_INTR_POLL: i32 = vna_ioc(0x20);
31+
pub const VNA_IOC_SET_FEATURES: i32 = vna_ioc(0x21);
32+
pub const VNA_IOC_GET_FEATURES: i32 = vna_ioc(0x22);
33+
pub const VNA_IOC_SET_NOTIFY_IOP: i32 = vna_ioc(0x23);
34+
pub const VNA_IOC_SET_PROMISC: i32 = vna_ioc(0x24);
35+
pub const VNA_IOC_GET_PARAMS: i32 = vna_ioc(0x25);
36+
pub const VNA_IOC_SET_PARAMS: i32 = vna_ioc(0x26);
37+
pub const VNA_IOC_GET_MTU: i32 = vna_ioc(0x27);
38+
pub const VNA_IOC_SET_MTU: i32 = vna_ioc(0x28);
39+
pub const VNA_IOC_SET_NOTIFY_MMIO: i32 = vna_ioc(0x29);
40+
41+
/// VirtIO 1.2 queue pair support.
42+
pub const VNA_IOC_GET_PAIRS: i32 = vna_ioc(0x30);
43+
pub const VNA_IOC_SET_PAIRS: i32 = vna_ioc(0x31);
44+
pub const VNA_IOC_GET_USEPAIRS: i32 = vna_ioc(0x32);
45+
pub const VNA_IOC_SET_USEPAIRS: i32 = vna_ioc(0x33);
46+
47+
#[cfg(test)]
48+
mod test {
49+
use super::*;
50+
51+
#[test]
52+
fn test_vna_ioc() {
53+
assert_eq!(vna_ioc(0x22), 0x00_56_43_22);
54+
}
55+
}
56+
57+
/// The minimum number of queue pairs supported by a device.
58+
pub const VIONA_MIN_QPAIRS: usize = 1;
59+
60+
/// The maximum number of queue pairs supported by a device.
61+
///
62+
/// Note that the VirtIO limit is much higher (0x8000); Viona artificially
63+
/// limits the number to 256 pairs, which makes it possible to implmeent
64+
/// interrupt notification with a reasonably sized bitmap.
65+
pub const VIONA_MAX_QPAIRS: usize = 0x100;
66+
67+
const fn howmany(x: usize, y: usize) -> usize {
68+
assert!(y > 0);
69+
x.div_ceil(y)
70+
}
71+
72+
#[repr(C)]
73+
pub struct vioc_create {
74+
pub c_linkid: u32,
75+
pub c_vmfd: i32,
76+
}
77+
78+
#[repr(C)]
79+
#[derive(Default)]
80+
pub struct vioc_ring_init {
81+
pub ri_index: u16,
82+
pub ri_qsize: u16,
83+
pub _pad: [u16; 2],
84+
pub ri_qaddr_desc: u64,
85+
pub ri_qaddr_avail: u64,
86+
pub ri_qaddr_used: u64,
87+
}
88+
89+
#[repr(C)]
90+
#[derive(Default)]
91+
pub struct vioc_ring_msi {
92+
pub rm_index: u16,
93+
pub _pad: [u16; 3],
94+
pub rm_addr: u64,
95+
pub rm_msg: u64,
96+
}
97+
98+
#[repr(C)]
99+
#[derive(Default)]
100+
pub struct vioc_intr_poll {
101+
pub vip_nrings: u16,
102+
pub _vip_pad0: u16,
103+
pub vip_status: [u32; howmany(VIONA_MAX_QPAIRS, 32)],
104+
}
105+
106+
#[repr(C)]
107+
#[derive(Default)]
108+
pub struct vioc_notify_mmio {
109+
pub vim_address: u64,
110+
pub vim_size: u32,
111+
}
112+
113+
#[repr(C)]
114+
#[derive(Default)]
115+
pub struct vioc_ring_state {
116+
pub vrs_index: u16,
117+
pub vrs_avail_idx: u16,
118+
pub vrs_used_idx: u16,
119+
pub vrs_qsize: u16,
120+
pub vrs_qaddr_desc: u64,
121+
pub vrs_qaddr_avail: u64,
122+
pub vrs_qaddr_used: u64,
123+
}
124+
125+
pub const VIONA_PROMISC_NONE: i32 = 0;
126+
pub const VIONA_PROMISC_MULTI: i32 = 1;
127+
pub const VIONA_PROMISC_ALL: i32 = 2;
128+
#[cfg(feature = "falcon")]
129+
pub const VIONA_PROMISC_ALL_VLAN: i32 = 3;
130+
131+
#[repr(C)]
132+
#[derive(Default)]
133+
pub struct vioc_get_params {
134+
pub vgp_param: *mut c_void,
135+
pub vgp_param_sz: size_t,
136+
}
137+
138+
#[repr(C)]
139+
#[derive(Default)]
140+
pub struct vioc_set_params {
141+
pub vsp_param: *mut c_void,
142+
pub vsp_param_sz: size_t,
143+
pub vsp_error: *mut c_void,
144+
pub vsp_error_sz: size_t,
145+
}
146+
147+
/// This is the viona interface version which viona_api expects to operate
148+
/// against. All constants and structs defined by the crate are done so in
149+
/// terms of that specific version.
150+
pub const VIONA_CURRENT_INTERFACE_VERSION: u32 = 6;
151+
152+
/// Maximum size of packed nvlists used in viona parameter ioctls
153+
pub const VIONA_MAX_PARAM_NVLIST_SZ: usize = 4096;

crates/viona-api/src/lib.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use std::io::{Error, ErrorKind, Result};
77
use std::os::fd::*;
88
use std::os::unix::fs::MetadataExt;
99

10-
pub use viona_api_sys::*;
10+
mod ffi;
11+
12+
pub use ffi::*;
1113

1214
// Hide libnvpair usage when not building on illumos to avoid linking errors
1315
#[cfg(target_os = "illumos")]
@@ -23,7 +25,7 @@ impl VionaFd {
2325
let this = Self::open()?;
2426

2527
let mut vna_create = vioc_create { c_linkid: link_id, c_vmfd: vm_fd };
26-
let _ = unsafe { this.ioctl(ioctls::VNA_IOC_CREATE, &mut vna_create) }?;
28+
let _ = unsafe { this.ioctl(VNA_IOC_CREATE, &mut vna_create) }?;
2729
Ok(this)
2830
}
2931

@@ -109,7 +111,7 @@ impl VionaFd {
109111

110112
/// Query the API version exposed by the kernel VMM.
111113
pub fn api_version(&self) -> Result<u32> {
112-
let vers = self.ioctl_usize(ioctls::VNA_IOC_VERSION, 0)?;
114+
let vers = self.ioctl_usize(VNA_IOC_VERSION, 0)?;
113115

114116
// We expect and demand a positive version number from the
115117
// VNA_IOC_VERSION interface.
@@ -129,16 +131,20 @@ impl VionaFd {
129131
const fn ioctl_usize_safe(cmd: i32) -> bool {
130132
matches!(
131133
cmd,
132-
ioctls::VNA_IOC_DELETE
133-
| ioctls::VNA_IOC_RING_RESET
134-
| ioctls::VNA_IOC_RING_KICK
135-
| ioctls::VNA_IOC_RING_PAUSE
136-
| ioctls::VNA_IOC_RING_INTR_CLR
137-
| ioctls::VNA_IOC_VERSION
138-
| ioctls::VNA_IOC_SET_NOTIFY_IOP
139-
| ioctls::VNA_IOC_SET_PROMISC
140-
| ioctls::VNA_IOC_GET_MTU
141-
| ioctls::VNA_IOC_SET_MTU,
134+
VNA_IOC_DELETE
135+
| VNA_IOC_RING_RESET
136+
| VNA_IOC_RING_KICK
137+
| VNA_IOC_RING_PAUSE
138+
| VNA_IOC_RING_INTR_CLR
139+
| VNA_IOC_VERSION
140+
| VNA_IOC_SET_NOTIFY_IOP
141+
| VNA_IOC_SET_PROMISC
142+
| VNA_IOC_GET_MTU
143+
| VNA_IOC_SET_MTU
144+
| VNA_IOC_GET_PAIRS
145+
| VNA_IOC_SET_PAIRS
146+
| VNA_IOC_GET_USEPAIRS
147+
| VNA_IOC_SET_USEPAIRS,
142148
)
143149
}
144150
}
@@ -191,7 +197,14 @@ fn minor(meta: &std::fs::Metadata) -> u32 {
191197
#[repr(u32)]
192198
#[derive(Copy, Clone)]
193199
pub enum ApiVersion {
194-
/// Add support for getting/setting MTU
200+
/// Adds multi-queue support and change the data structure for per-queue
201+
/// interrupt polling to a compact bitmap.
202+
V6 = 6,
203+
204+
/// Adds support for VirtIO 1.0 (modern) virtqueues.
205+
V5 = 5,
206+
207+
/// Adds support for getting/setting MTU
195208
V4 = 4,
196209

197210
/// Adds support for interface parameters
@@ -205,7 +218,7 @@ pub enum ApiVersion {
205218
}
206219
impl ApiVersion {
207220
pub const fn current() -> Self {
208-
Self::V4
221+
Self::V6
209222
}
210223
}
211224
impl PartialEq<ApiVersion> for u32 {

0 commit comments

Comments
 (0)