Skip to content

Commit 3692865

Browse files
acatangiuandreeaflorescu
authored andcommitted
Integrate rate limiting with virtio network device servicing
Use two RateLimiter objects, one for ingress one egress, to account and limit both bytes/s and ops/s when servicing the virtio network devices virtqueues. Signed-off-by: Adrian Catangiu <[email protected]>
1 parent 6aba8d4 commit 3692865

File tree

7 files changed

+517
-31
lines changed

7 files changed

+517
-31
lines changed

api_server/src/http_service.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,8 @@ mod tests {
986986
state: DeviceState::Attached,
987987
host_dev_name: String::from("foo"),
988988
guest_mac: Some(MacAddr::parse_str("12:34:56:78:9a:BC").unwrap()),
989+
rx_rate_limiter: None,
990+
tx_rate_limiter: None,
989991
};
990992

991993
match netif.into_parsed_request("bar") {

api_server/src/request/sync/net.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use std::result;
22

33
use futures::sync::oneshot;
44

5-
use super::{DeviceState, SyncRequest};
5+
use super::{DeviceState, RateLimiter, SyncRequest};
6+
67
use net_util::MacAddr;
78
use request::ParsedRequest;
89

@@ -15,6 +16,10 @@ pub struct NetworkInterfaceBody {
1516
pub host_dev_name: String,
1617
#[serde(skip_serializing_if = "Option::is_none")]
1718
pub guest_mac: Option<MacAddr>,
19+
#[serde(skip_serializing_if = "Option::is_none")]
20+
pub rx_rate_limiter: Option<RateLimiter>,
21+
#[serde(skip_serializing_if = "Option::is_none")]
22+
pub tx_rate_limiter: Option<RateLimiter>,
1823
}
1924

2025
impl NetworkInterfaceBody {
@@ -45,6 +50,8 @@ mod tests {
4550
state: DeviceState::Attached,
4651
host_dev_name: String::from("bar"),
4752
guest_mac: Some(MacAddr::parse_str("12:34:56:78:9A:BC").unwrap()),
53+
rx_rate_limiter: None,
54+
tx_rate_limiter: None,
4855
};
4956

5057
assert!(netif.clone().into_parsed_request("bar").is_err());
@@ -67,14 +74,24 @@ mod tests {
6774
state: DeviceState::Attached,
6875
host_dev_name: String::from("bar"),
6976
guest_mac: Some(MacAddr::parse_str("12:34:56:78:9A:BC").unwrap()),
77+
rx_rate_limiter: Some(RateLimiter::default()),
78+
tx_rate_limiter: Some(RateLimiter::default()),
7079
};
7180

7281
// This is the json encoding of the netif variable.
7382
let jstr = r#"{
7483
"iface_id": "foo",
7584
"host_dev_name": "bar",
7685
"state": "Attached",
77-
"guest_mac": "12:34:56:78:9A:bc"
86+
"guest_mac": "12:34:56:78:9A:bc",
87+
"rx_rate_limiter": {
88+
"bandwidth": { "size": 0, "refill_time": 0 },
89+
"ops": { "size": 0, "refill_time": 0 }
90+
},
91+
"tx_rate_limiter": {
92+
"bandwidth": { "size": 0, "refill_time": 0 },
93+
"ops": { "size": 0, "refill_time": 0 }
94+
}
7895
}"#;
7996

8097
let x = serde_json::from_str(jstr).expect("deserialization failed.");
@@ -84,7 +101,7 @@ mod tests {
84101
let z = serde_json::from_str(y.as_ref()).expect("deserialization (2) failed.");
85102
assert_eq!(x, z);
86103

87-
// Check that guest_mac is truly optional.
104+
// Check that guest_mac and rate limiters are truly optional.
88105
let jstr_no_mac = r#"{
89106
"iface_id": "foo",
90107
"host_dev_name": "bar",

devices/src/virtio/block.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ impl Block {
404404
mut disk_image: File,
405405
is_disk_read_only: bool,
406406
epoll_config: EpollConfig,
407-
rate_limiter: RateLimiter,
407+
rate_limiter: Option<RateLimiter>,
408408
) -> SysResult<Block> {
409409
let disk_size = disk_image.seek(SeekFrom::End(0))? as u64;
410410
if disk_size % SECTOR_SIZE != 0 {
@@ -428,7 +428,7 @@ impl Block {
428428
acked_features: 0u64,
429429
config_space: build_config_space(disk_size),
430430
epoll_config,
431-
rate_limiter: Some(rate_limiter),
431+
rate_limiter,
432432
})
433433
}
434434
}
@@ -570,8 +570,7 @@ impl VirtioDevice for Block {
570570
interrupt_status: status,
571571
interrupt_evt,
572572
queue_evt,
573-
// safe to .take().unwrap() since activate is only called once
574-
rate_limiter: self.rate_limiter.take().unwrap(),
573+
rate_limiter: self.rate_limiter.take().unwrap_or_default(),
575574
disk_image_id,
576575
};
577576
let rate_limiter_rawfd = handler.rate_limiter.as_raw_fd();
@@ -653,7 +652,7 @@ mod tests {
653652
// rate limiting enabled but with a high operation rate (10 million ops/s)
654653
let rate_limiter = RateLimiter::new(0, 0, 100000, 10).unwrap();
655654
DummyBlock {
656-
block: Block::new(f, false, epoll_config, rate_limiter).unwrap(),
655+
block: Block::new(f, false, epoll_config, Some(rate_limiter)).unwrap(),
657656
epoll_raw_fd,
658657
_receiver,
659658
}

0 commit comments

Comments
 (0)