|
1 | 1 | # `msg-sim` |
2 | 2 |
|
3 | 3 | ## Overview |
| 4 | + |
4 | 5 | This crate provides functionality to simulate real-world network conditions |
5 | 6 | locally to and from a specific endpoint for testing and benchmarking purposes. |
6 | 7 | It only works on MacOS and Linux. |
7 | 8 |
|
8 | 9 | ## Implementation |
9 | 10 |
|
10 | 11 | ### MacOS |
| 12 | + |
11 | 13 | On MacOS, we use a combination of the `pfctl` and `dnctl` tools. |
12 | | -[`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 |
13 | | -the [dummynet](http://info.iet.unipi.it/~luigi/papers/20100304-ccr.pdf) traffic shaper. |
| 14 | +[`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) |
| 15 | +is a tool to manage the packet filter device. |
| 16 | +[`dnctl`](https://man.freebsd.org/cgi/man.cgi?query=dnctl&sektion=8&format=html) |
| 17 | +can manage the |
| 18 | +[dummynet](http://info.iet.unipi.it/~luigi/papers/20100304-ccr.pdf) traffic |
| 19 | +shaper. |
14 | 20 |
|
15 | 21 | The general flow is as follows: |
16 | 22 |
|
17 | | -* Create a dummynet pipe with `dnctl` and configure it with `bw`, `delay`, `plr` |
| 23 | +- Create a dummynet pipe with `dnctl` and configure it with `bw`, `delay`, |
| 24 | + `plr` |
18 | 25 |
|
19 | 26 | Example: |
20 | | -```bash |
21 | | -sudo dnctl pipe 1 config bw 10Kbit/s delay 50 plr 0.1 |
22 | | -``` |
23 | 27 |
|
24 | | -* Create a loopback alias with `ifconfig` to simulate a different endpoint and |
25 | | -set the MTU to the usual value (1500) |
| 28 | +`bash sudo dnctl pipe 1 config bw 10Kbit/s delay 50 plr 0.1 ` |
| 29 | + |
| 30 | +- Create a loopback alias with `ifconfig` to simulate a different endpoint and |
| 31 | + set the MTU to the usual value (1500) |
26 | 32 |
|
27 | 33 | Example: |
28 | | -```bash |
29 | | -sudo ifconfig lo0 alias 127.0.0.3 up |
30 | | -sudo ifconfig lo0 mtu 1500 |
31 | | -``` |
32 | 34 |
|
33 | | -* Use `pfctl` to create a rule to match traffic and send it through the pipe |
| 35 | +`bash sudo ifconfig lo0 alias 127.0.0.3 up sudo ifconfig lo0 mtu 1500 ` |
| 36 | + |
| 37 | +- Use `pfctl` to create a rule to match traffic and send it through the pipe |
34 | 38 |
|
35 | 39 | Example: |
| 40 | + |
36 | 41 | ```bash |
37 | 42 | # Create an anchor (a named container for rules, close to a namespace) |
38 | | -(cat /etc/pf.conf && echo "dummynet-anchor \"msg-sim\"" && \ |
39 | | -echo "anchor \"msg-sim\"") | sudo pfctl -f - |
40 | 43 |
|
41 | | -# Create a rule to match traffic from any to the alias and send it through the pipe |
42 | | -echo 'dummynet in from any to 127.0.0.3 pipe 1' | sudo pfctl -a msg-sim -f - |
| 44 | +(cat /etc/pf.conf && echo "dummynet-anchor \"msg-sim\"" && \ echo "anchor \"msg-sim\"") | sudo pfctl -f - |
| 45 | + |
| 46 | +# Create a rule to match traffic from any to the alias and send it through the |
| 47 | + |
| 48 | +pipe echo 'dummynet in from any to 127.0.0.3 pipe 1' | sudo pfctl -a msg-sim -f |
43 | 49 |
|
44 | 50 | # Enable the packet filter |
| 51 | + |
45 | 52 | sudo pfctl -E |
46 | 53 | ``` |
47 | 54 |
|
48 | | -* Remove the rules and the pipe |
| 55 | +- Remove the rules and the pipe |
| 56 | + |
49 | 57 | ```bash |
50 | 58 | # Apply the default configuration |
| 59 | + |
51 | 60 | sudo pfctl -f /etc/pf.conf |
| 61 | + |
52 | 62 | # Disable the packet filter |
| 63 | + |
53 | 64 | sudo pfctl -d |
| 65 | + |
54 | 66 | # Remove the alias & reset the MTU |
55 | | -sudo ifconfig lo0 -alias 127.0.0.3 |
56 | | -sudo ifconfig lo0 mtu 16384 |
57 | | -# Remove the dummynet pipes |
58 | | -sudo dnctl pipe delete 1 |
| 67 | + |
| 68 | +sudo ifconfig lo0 -alias 127.0.0.3 sudo ifconfig lo0 mtu 16384 |
| 69 | + |
| 70 | +# Remove the dummynet |
| 71 | + |
| 72 | +pipes sudo dnctl pipe delete 1 |
59 | 73 | ``` |
60 | 74 |
|
61 | 75 | ### Questions |
62 | | -- Do we need to create 2 pipes to simulate a bidirectional link? MAN page seems to say so. |
| 76 | + |
| 77 | +- Do we need to create 2 pipes to simulate a bidirectional link? MAN page seems |
| 78 | + to say so. |
63 | 79 |
|
64 | 80 | ### Linux |
65 | | -On Linux, we use dummy interfaces and `tc` with `netem` to simulate and shape traffic. |
| 81 | + |
| 82 | +On Linux, we leverage network namespaces to simulate different networking |
| 83 | +conditions, leveraging the `tc` and `netem` command to shape traffic. |
| 84 | + |
| 85 | +On each namespace, we create a veth pair, with one end in the default namespace, |
| 86 | +and then we configure the veth devices as needed. |
| 87 | + |
| 88 | +The general flow is as follows: |
| 89 | + |
| 90 | +- Create a network namespace with `ip netns add` |
| 91 | +- Add a veth pair to the namespace with `ip link add` |
| 92 | +- Set the veth pair up with `ip link set` |
| 93 | +- Set the IP address of the veth pair in the namespace with `ip netns exec` |
| 94 | +- Set the network emulation parameters with `tc qdisc add dev` both in the host and |
| 95 | + the namespaced environment |
| 96 | + |
| 97 | +Example: |
| 98 | + |
| 99 | +```bash |
| 100 | +# create namespace ns1 |
| 101 | +sudo ip netns add ns1 |
| 102 | +# create veth devices linked together |
| 103 | +sudo ip link add veth-host type veth peer name veth-ns1 |
| 104 | +# move veth-ns1 device to ns1 namespace |
| 105 | +sudo ip link set veth-ns1 netns ns1 |
| 106 | + |
| 107 | +# associate ip addr to veth-host device and spin it up |
| 108 | +sudo ip addr add 192.168.1.2/24 dev veth-host |
| 109 | +sudo ip link set veth-host up |
| 110 | + |
| 111 | +# same but from ns1 namespace |
| 112 | +sudo ip netns exec ns1 ip addr add 192.168.1.1/24 dev veth-ns1 |
| 113 | +sudo ip netns exec ns1 ip link set veth-ns1 up |
| 114 | + |
| 115 | +# add latency etc to veth-ns1 from ns1 namespace |
| 116 | +sudo ip netns exec ns1 tc qdisc add dev veth-ns1 root netem delay 3000ms loss 50% |
| 117 | + |
| 118 | +# this should be slow |
| 119 | +ping 192.168.1.1 |
| 120 | +``` |
| 121 | + |
| 122 | +#### How to run tests |
| 123 | + |
| 124 | +Given that the tests require root privileges to modify the networking stack, |
| 125 | +you can run them with the following command: |
| 126 | + |
| 127 | +```bash |
| 128 | +sudo HOME=$HOME $(which cargo) test # add your arguments here |
| 129 | +``` |
| 130 | + |
| 131 | +We need to provide the `$HOME` environment variable to `sudo` to ensure that |
| 132 | +it can find the Rust toolchain, and then we also need to provide the path of `cargo`. |
0 commit comments