Skip to content

Commit

Permalink
Merge pull request #54 from chainbound/feature/msg-sim-initial
Browse files Browse the repository at this point in the history
`msg-sim` initial crate implementation
  • Loading branch information
mempirate committed Jan 18, 2024
2 parents 60d569b + 9e93ebf commit a492a6e
Show file tree
Hide file tree
Showing 7 changed files with 765 additions and 8 deletions.
119 changes: 119 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 23 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
[workspace]
members = ["msg", "msg-socket", "msg-wire", "msg-transport", "msg-common"]
members = [
"msg",
"msg-socket",
"msg-wire",
"msg-transport",
"msg-common",
"msg-sim",
]
resolver = "2"

[workspace.package]
version = "0.1.1"
edition = "2021"
rust-version = "1.70" # Remember to update .clippy.toml and README.md
license = "MIT OR Apache-2.0"
license = "MIT"
description = "A flexible and lightweight messaging library for distributed systems"
authors = ["Jonas Bostoen", "Nicolas Racchi"]
homepage = "https://github.com/chainbound/msg-rs"
repository = "https://github.com/chainbound/msg-rs"
keywords = ["messaging", "distributed", "systems", "networking", "quic", "quinn", "tokio", "async", "simulation", "pnet", "udp", "tcp", "socket"]

[workspace.dependencies]
msg-wire = { path = "./msg-wire" }
msg-socket = { path = "./msg-socket" }
msg-transport = { path = "./msg-transport" }
msg-common = { path = "./msg-common" }
msg-sim = { path = "./msg-sim" }

# async
async-trait = "0.1"
Expand All @@ -24,26 +34,31 @@ tokio-util = { version = "0.7", features = ["codec"] }
futures = "0.3"
tokio-stream = { version = "0.1", features = ["sync"] }
parking_lot = "0.12"
criterion = { version = "0.5", features = ["async_tokio"] }
pprof = { version = "0.13", features = ["flamegraph", "criterion"] }


# general
bytes = "1"
thiserror = "1"
tracing = "0.1"
rustc-hash = "1"
rand = "0.8"

# transport
# NETWORKING
quinn = "0.10"
# rustls needs to be the same version as the one used by quinn
rustls = { version = "0.21", features = ["quic", "dangerous_configuration"] }
rcgen = "0.12"

# performance
rustc-hash = "1"
flate2 = "1"
zstd = "0.13"
snap = "1"

# benchmarking & profiling
criterion = { version = "0.5", features = ["async_tokio"] }
pprof = { version = "0.13", features = ["flamegraph", "criterion"] }

# simulation
pnet = "0.34"

[profile.dev]
opt-level = 1
overflow-checks = false
Expand Down
15 changes: 15 additions & 0 deletions msg-sim/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "msg-sim"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
description.workspace = true
authors.workspace = true
homepage.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
pnet.workspace = true
65 changes: 65 additions & 0 deletions msg-sim/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# `msg-sim`

## Overview
This crate provides functionality to simulate real-world network conditions
locally to and from a specific endpoint for testing and benchmarking purposes.
It only works on MacOS and Linux.

## Implementation

### MacOS
On MacOS, we use a combination of the `pfctl` and `dnctl` tools.
[`pfctl`](https://man.freebsd.org/cgi/man.cgi?query=pfctl&apropos=0&sektion=8&manpath=FreeBSD+14.0-RELEASE+and+Ports&arch=default&format=html) is a tool to manage the packet filter device. [`dnctl`](https://man.freebsd.org/cgi/man.cgi?query=dnctl&sektion=8&format=html) can manage
the [dummynet](http://info.iet.unipi.it/~luigi/papers/20100304-ccr.pdf) traffic shaper.

The general flow is as follows:

* Create a dummynet pipe with `dnctl` and configure it with `bw`, `delay`, `plr`

Example:
```bash
sudo dnctl pipe 1 config bw 10Kbit/s delay 50 plr 0.1
```

* Create a loopback alias with `ifconfig` to simulate a different endpoint and
set the MTU to the usual value (1500)

Example:
```bash
sudo ifconfig lo0 alias 127.0.0.3 up
sudo ifconfig lo0 mtu 1500
```

* Use `pfctl` to create a rule to match traffic and send it through the pipe

Example:
```bash
# Create an anchor (a named container for rules, close to a namespace)
(cat /etc/pf.conf && echo "dummynet-anchor \"msg-sim\"" && \
echo "anchor \"msg-sim\"") | sudo pfctl -f -

# Create a rule to match traffic from any to the alias and send it through the pipe
echo 'dummynet in from any to 127.0.0.3 pipe 1' | sudo pfctl -a msg-sim -f -

# Enable the packet filter
sudo pfctl -E
```

* Remove the rules and the pipe
```bash
# Apply the default configuration
sudo pfctl -f /etc/pf.conf
# Disable the packet filter
sudo pfctl -d
# Remove the alias & reset the MTU
sudo ifconfig lo0 -alias 127.0.0.3
sudo ifconfig lo0 mtu 16384
# Remove the dummynet pipes
sudo dnctl pipe delete 1
```

### Questions
- Do we need to create 2 pipes to simulate a bidirectional link? MAN page seems to say so.

### Linux
On Linux, we use dummy interfaces and `tc` with `netem` to simulate and shape traffic.
Loading

0 comments on commit a492a6e

Please sign in to comment.