Skip to content

Commit 645fc20

Browse files
committed
chore(msg-sim): address review
1 parent 0d3a3de commit 645fc20

File tree

9 files changed

+70
-51
lines changed

9 files changed

+70
-51
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,12 @@ jobs:
5353
with:
5454
cache-on-failure: true
5555

56+
# Install nextest
57+
- name: Install cargo-nextest
58+
uses: taiki-e/install-action@nextest
59+
5660
- name: Run msg-sim tests (requires root for network namespaces)
57-
run: sudo env "PATH=$PATH" "HOME=$HOME" cargo test run -p msg-sim --all-features --no-fail-fast -- --test-threads=1
61+
run: sudo env "PATH=$PATH" "HOME=$HOME" cargo nextest run -p msg-sim --all-features --no-fail-fast --test-threads=1
5862

5963
cargo-lint:
6064
runs-on: ubuntu-latest

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

msg-sim/examples/sim_multi_region.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@
1919
//! sudo HOME=$HOME RUST_LOG=info $(which cargo) run --example multi_region -p msg-sim
2020
//! ```
2121
22-
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
23-
use std::time::{Duration, Instant};
24-
25-
use msg_sim::ip::Subnet;
26-
use msg_sim::network::{Link, Network, PeerIdExt};
27-
use msg_sim::tc::impairment::LinkImpairment;
22+
use std::{
23+
net::{IpAddr, Ipv4Addr, SocketAddr},
24+
time::{Duration, Instant},
25+
};
26+
27+
use msg_sim::{
28+
ip::Subnet,
29+
network::{Link, Network, PeerIdExt},
30+
tc::impairment::LinkImpairment,
31+
};
2832
use tracing_subscriber::EnvFilter;
2933

3034
// Peer IDs (assigned sequentially by add_peer)

msg-sim/src/tc/drr.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
//! DRR (Deficit Round Robin) qdisc and class support.
2-
//!
3-
//! DRR is our root qdisc, chosen because it allows an unlimited number of classes
4-
//! to be created dynamically with minimal overhead. Each class can have its own
5-
//! qdisc chain (TBF → netem) for per-destination impairments.
62
73
use rtnetlink::packet_core::{
84
NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE, NLM_F_REQUEST, NetlinkMessage,
@@ -28,7 +24,7 @@ const TCA_DRR_QUANTUM: u16 = 1;
2824
/// The quantum must be at least as large as the maximum packet size (MTU) to ensure packets
2925
/// can always be dequeued. 1MB is large enough to handle any reasonable packet while still
3026
/// being well within safe bounds.
31-
pub const DRR_DEFAULT_QUANTUM: u32 = u32::MAX; // 1 MB
27+
pub const DRR_DEFAULT_QUANTUM: u32 = u32::MAX; // 4GiB
3228

3329
/// Builder for creating a DRR (Deficit Round Robin) root qdisc.
3430
///
@@ -88,13 +84,13 @@ impl QdiscDrrRequest {
8884
/// # Example
8985
///
9086
/// ```
91-
/// use msg_sim::tc::handle::{CLASS_MINOR_OFFSET, QdiscRequestInner};
87+
/// use msg_sim::tc::handle::{ID_OFFSET, QdiscRequestInner};
9288
/// use msg_sim::tc::drr::DrrClassRequest;
9389
/// use rtnetlink::packet_route::tc::TcHandle;
9490
///
9591
/// let if_index = 1; // Network interface index
9692
/// // Create class for traffic to peer 2
97-
/// let class_minor = CLASS_MINOR_OFFSET + 2; // 12
93+
/// let class_minor = ID_OFFSET + 2; // 12
9894
/// let request = DrrClassRequest::new(
9995
/// QdiscRequestInner::new(if_index)
10096
/// .with_parent(TcHandle::from(0x0001_0000)) // Parent is DRR root (1:0)

msg-sim/src/tc/filter.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const ETH_P_IP: u16 = nix::libc::ETH_P_IP as u16;
2121
/// EtherType for IPv6 packets (0x86DD).
2222
const ETH_P_IPV6: u16 = nix::libc::ETH_P_IPV6 as u16;
2323

24+
/// EtherType for matching all protocols supported by Ethernet.
25+
const ETH_P_ALL: u16 = nix::libc::ETH_P_ALL as u16;
26+
2427
/// Compute an IPv4 netmask from a prefix length.
2528
fn ipv4_mask(prefix_len: u8) -> Ipv4Addr {
2629
if prefix_len == 0 {
@@ -82,9 +85,9 @@ pub struct FlowerFilterRequest {
8285
}
8386

8487
impl FlowerFilterRequest {
85-
/// Create a new flower filter for the given destination IP.
88+
/// Create a new flower filter for the given destination IP
8689
///
87-
/// By default, uses /32 (exact match) for IPv4 or /128 for IPv6.
90+
/// By default, uses /32 (exact match) for IPv4 or /128 for IPv6 and root class id.
8891
pub fn new(inner: QdiscRequestInner, destination: IpAddr) -> Self {
8992
let default_mask = match destination {
9093
IpAddr::V4(_) => 32,
@@ -95,7 +98,7 @@ impl FlowerFilterRequest {
9598
destination,
9699
mask: default_mask,
97100
// Default class ID will be set by caller
98-
class_id: 0,
101+
class_id: u32::MAX, // Root class id
99102
}
100103
}
101104

@@ -213,6 +216,14 @@ struct TcU32Sel {
213216
// Followed by nkeys * tc_u32_key structures
214217
}
215218

219+
impl TcU32Sel {
220+
/// Returns an instance of [`Self`] with all fields set to zero.
221+
#[allow(dead_code)]
222+
fn zero() -> Self {
223+
Self { flags: 0, offmask: 0, offshift: 0, nkeys: 0, off: 0, offoff: 0, hoff: 0, hmask: 0 }
224+
}
225+
}
226+
216227
/// The kernel's `tc_u32_key` structure for u32 matching.
217228
#[derive(Debug, Clone, Copy, Default)]
218229
struct TcU32Key {
@@ -226,6 +237,13 @@ struct TcU32Key {
226237
offmask: i32,
227238
}
228239

240+
impl TcU32Key {
241+
/// Returns an instance of [`Self`] with all fields set to zero.
242+
fn zero() -> Self {
243+
Self { mask: 0, val: 0, off: 0, offmask: 0 }
244+
}
245+
}
246+
229247
/// Builder for creating a u32 catch-all filter.
230248
///
231249
/// The u32 filter with `match u32 0 0` matches all packets. This is used as a catch-all
@@ -280,8 +298,8 @@ impl U32CatchallFilterRequest {
280298
pub fn new(inner: QdiscRequestInner) -> Self {
281299
Self {
282300
inner,
283-
class_id: 0,
284-
priority: 65535, // Lowest priority = checked last
301+
class_id: u32::MAX, // Root class id.
302+
priority: 65535, // Lowest priority = checked last
285303
}
286304
}
287305

@@ -304,10 +322,7 @@ impl U32CatchallFilterRequest {
304322
let mut tc_msg = TcMessage::with_index(self.inner.interface_index);
305323
tc_msg.header.parent = self.inner.parent;
306324
tc_msg.header.handle = TcHandle::from(0u32);
307-
// The info field contains the priority (in upper 16 bits) and protocol (in lower 16 bits)
308-
// ETH_P_ALL (0x0003) matches all protocols
309-
let eth_p_all: u16 = 0x0003;
310-
tc_msg.header.info = ((self.priority as u32) << 16) | (eth_p_all.to_be() as u32);
325+
tc_msg.header.info = ((self.priority as u32) << 16) | (ETH_P_ALL.to_be() as u32);
311326

312327
tc_msg.attributes.push(TcAttribute::Kind("u32".to_string()));
313328

@@ -320,7 +335,7 @@ impl U32CatchallFilterRequest {
320335

321336
// Mask of 0 means "don't care".
322337
// Value doesn't matter when mask is 0
323-
let key = TcU32Key::default();
338+
let key = TcU32Key::zero();
324339

325340
// Serialize selector + key
326341
let mut sel_bytes = Vec::with_capacity(size_of::<TcU32Sel>() + size_of::<TcU32Key>());

msg-sim/src/tc/handle.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use rtnetlink::packet_route::tc::TcHandle;
77

88
/// The offset added to peer IDs to compute DRR class minor numbers.
99
///
10-
/// For peer ID `N`, the class minor is `CLASS_MINOR_OFFSET + N`.
11-
/// This keeps class 1:1 reserved as the default (unimpaired) class.
12-
pub const CLASS_MINOR_OFFSET: u32 = 10;
10+
/// For peer ID `N`, the class minor/major (depending on the qdisc level) is `ID_OFFSET + N`. This
11+
/// keeps class 1:1 reserved as the default (unimpaired) class.
12+
pub const ID_OFFSET: u32 = 10;
1313

1414
/// Offset for netem qdisc major numbers (separate from TBF to avoid collisions).
1515
pub const NETEM_MAJOR_OFFSET: u32 = 20;
@@ -60,7 +60,7 @@ impl QdiscRequestInner {
6060
/// assert_eq!(drr_class_handle(2), 0x0001_000C); // 1:12
6161
/// ```
6262
pub fn drr_class_handle(dest_peer_id: usize) -> u32 {
63-
let minor = CLASS_MINOR_OFFSET + dest_peer_id as u32;
63+
let minor = ID_OFFSET + dest_peer_id as u32;
6464
(1 << 16) | minor
6565
}
6666

@@ -78,7 +78,7 @@ pub fn drr_class_handle(dest_peer_id: usize) -> u32 {
7878
/// assert_eq!(tbf_handle(2), 0x000C_0000); // 12:0
7979
/// ```
8080
pub fn tbf_handle(dest_peer_id: usize) -> u32 {
81-
let major = CLASS_MINOR_OFFSET + dest_peer_id as u32;
81+
let major = ID_OFFSET + dest_peer_id as u32;
8282
major << 16 // minor must be 0 for qdiscs
8383
}
8484

msg-sim/src/tc/impairment.rs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
//! This module defines the user-facing configuration for network impairments
44
//! that can be applied to links between peers.
55
6-
use super::core::MTU_ETHERNET;
7-
86
/// Configuration for network impairments to apply to a link.
97
///
108
/// This struct represents all the ways you can degrade a network link for testing
@@ -57,7 +55,7 @@ pub struct LinkImpairment {
5755
///
5856
/// When this limit is reached, additional packets are dropped. Default is 1000,
5957
/// which matches netem's default. Increase for high-bandwidth, high-latency links
60-
/// to avoid artificial drops.
58+
/// to avoid unintended drops.
6159
pub netem_limit: u32,
6260

6361
/// Packet loss percentage (0.0 to 100.0).
@@ -246,20 +244,8 @@ impl LinkImpairment {
246244
/// Compute the effective burst size in bytes.
247245
///
248246
/// If `burst_kib` is set, converts it to bytes.
249-
/// Otherwise, computes a sensible default based on bandwidth.
250247
pub fn effective_burst_bytes(&self) -> u32 {
251-
if let Some(burst_kib) = self.burst_kib {
252-
burst_kib * 1024
253-
} else if let Some(bandwidth_mbit) = self.bandwidth_mbit_s {
254-
// Compute default: max(bandwidth/8 seconds, 10 MTU packets)
255-
let bandwidth_bytes_per_sec = (bandwidth_mbit * 1_000_000.0 / 8.0) as u32;
256-
let one_eighth_second = bandwidth_bytes_per_sec / 8;
257-
let ten_packets = MTU_ETHERNET * 10; // 10 MTU-sized packets
258-
std::cmp::max(one_eighth_second, ten_packets)
259-
} else {
260-
// No bandwidth limit, burst is irrelevant
261-
0
262-
}
248+
self.burst_kib.map(|b| b * 1024).unwrap_or_default()
263249
}
264250

265251
/// Compute the effective TBF queue limit in bytes.
@@ -272,8 +258,7 @@ impl LinkImpairment {
272258
let queue_latency_ms = self.tbf_queue_latency_ms.unwrap_or(200);
273259
let burst_bytes = self.effective_burst_bytes();
274260

275-
if let Some(bandwidth_mbit) = self.bandwidth_mbit_s {
276-
let rate_bytes_per_sec = (bandwidth_mbit * 1_000_000.0 / 8.0) as u32;
261+
if let Some(rate_bytes_per_sec) = self.bandwidth_bytes_per_sec() {
277262
let rate_bytes_per_ms = rate_bytes_per_sec / 1000;
278263
rate_bytes_per_ms * queue_latency_ms + burst_bytes
279264
} else {
@@ -285,7 +270,7 @@ impl LinkImpairment {
285270
/// Compute the bandwidth rate in bytes per second.
286271
///
287272
/// Returns `None` if no bandwidth limit is configured.
288-
pub fn bandwidth_bytes_per_sec(&self) -> Option<u64> {
289-
self.bandwidth_mbit_s.map(|mbit| (mbit * 1_000_000.0 / 8.0) as u64)
273+
pub fn bandwidth_bytes_per_sec(&self) -> Option<u32> {
274+
self.bandwidth_mbit_s.map(|mbit| (mbit * 1_000_000.0 / 8.0) as u32)
290275
}
291276
}

msg-sim/src/tc/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@
5858
//!
5959
//! | Component | Handle | Example (peer_id=2) |
6060
//! |------------------|-----------------|---------------------|
61-
//! | DRR root | `1:0` | `1:0` |
62-
//! | Default class | `1:1` | `1:1` |
61+
//! | DRR root | `1:0` | `N/A` |
62+
//! | Default class | `1:1` | `N/A` |
6363
//! | Per-dest class | `1:(10+id)` | `1:12` |
6464
//! | TBF qdisc | `(10+id):0` | `12:0` |
6565
//! | Netem qdisc | `(20+id):0` | `22:0` |

msg-sim/src/tc/nla.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use rtnetlink::packet_core::{DefaultNla, NLA_HEADER_SIZE};
2121
/// └─────────────────────────────────────────┘
2222
/// ```
2323
///
24+
/// Reference: <linux/netlink.h>
25+
///
2426
/// # Returns
2527
///
2628
/// A byte vector containing the complete NLA (header + value + padding).

0 commit comments

Comments
 (0)