Simulate Network Latency » History » Revision 3
Revision 2 (neels, 08/31/2021 12:14 PM) → Revision 3/9 (neels, 08/31/2021 12:15 PM)
h1. Simulate Network Latency This describes how to virtually introduce network latency on a specific ethernet link, based on the practical example of introducing latency on the Abis link (between BSC and BTS). All of this on a single machine using the loopback interface. {{graphviz_link() digraph G { rankdir = LR; subgraph cluster_abis { label="namespace: abis";style=dotted TRX [rank="min"] BTS [rank="min"] abisin [label="link: abis-in\n10.9.8.2/24";shape=box] } subgraph cluster_root { label="namespace: root";style=dotted abisout [label="link: abis-out\n10.9.8.1/24";shape=box] BSC MSC } TRX -> BTS -> abisin [dir=both] abisin -> abisout [label="netem delay"] abisout -> abisin [label="netem delay"] abisout -> BSC -> MSC [dir=both] } }} h2. setup (Perform the following steps as root user) create network namespace "abis", create a virtual ethernet link "abis-in" <-> "abis-out" and put "abis-in" in the new network namespace: <pre> ip netns add abis ip link add abis-in type veth peer name abis-out ip link set abis-in netns abis </pre> make up a new local IP subnet, here 10.9.8.0/24, and give each link an address in that subnet. First for "abis-out" in the root namespace: <pre> ip link set abis-out up ip addr add 10.9.8.1/24 dev abis-out </pre> And for "abis-in" within the "abis" namespace, first opening a shell in that namespace: <pre> ip netns exec abis bash ip link set abis-in up ip addr add 10.9.8.2/24 dev abis-in </pre> h2. verify Any shell within the "abis" namespace should show only the "abis-in" and loopback links, and the "abis-in" link should be in state UP: (I repeat the 'ip netns exec' step below just to clarify, of course it suffices to keep one shell within the "abis" namespace open) <pre> # ip netns exec abis bash # ip link 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 6: abis-in@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether f6:c6:b5:47:46:4f brd ff:ff:ff:ff:ff:ff link-netnsid 0 # ip a 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 6: abis-in@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether f6:c6:b5:47:46:4f brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.9.8.2/24 scope global abis-in valid_lft forever preferred_lft forever inet6 fe80::f4c6:b5ff:fe47:464f/64 scope link valid_lft forever preferred_lft forever </pre> A shell running in the "root" namespace should show the "abis-out" link and any other links your machine may have configured: <pre> # ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 [...] 5: abis-out@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc netem state UP mode DEFAULT group default qlen 1000 link/ether be:49:d6:ef:35:38 brd ff:ff:ff:ff:ff:ff link-netns abis # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever [...] 5: abis-out@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc netem state UP group default qlen 1000 link/ether be:49:d6:ef:35:38 brd ff:ff:ff:ff:ff:ff link-netns abis inet 10.9.8.1/24 scope global abis-out valid_lft forever preferred_lft forever inet6 fe80::bc49:d6ff:feef:3538/64 scope link valid_lft forever preferred_lft forever </pre> A shell run within the "abis" namespace should be able to ping the "root" namespace: <pre> # ip netns exec abis bash # ping 10.9.8.1 PING 10.9.8.1 (10.9.8.1) 56(84) bytes of data. 64 bytes from 10.9.8.1: icmp_seq=1 ttl=64 time=0.133 ms 64 bytes from 10.9.8.1: icmp_seq=2 ttl=64 time=0.059 ms 64 bytes from 10.9.8.1: icmp_seq=3 ttl=64 time=0.059 ms 64 bytes from 10.9.8.1: icmp_seq=4 ttl=64 time=0.058 ms ^C </pre> And a running in the "root" namespace should be able to ping into the "abis" namespace: <pre> # ping 10.9.8.2 PING 10.9.8.2 (10.9.8.2) 56(84) bytes of data. 64 bytes from 10.9.8.2: icmp_seq=1 ttl=64 time=0.133 ms 64 bytes from 10.9.8.2: icmp_seq=2 ttl=64 time=0.059 ms 64 bytes from 10.9.8.2: icmp_seq=3 ttl=64 time=0.059 ms 64 bytes from 10.9.8.2: icmp_seq=4 ttl=64 time=0.058 ms ^C </pre> h2. add latency In a shell running in the "root" namespace, add a netem delay, for example: <pre> tc qdisc add dev abis-out root handle 1:0 netem delay 200ms 50ms 50% </pre> From here on, there is latency in *only one* direction on the virtual ethernet. It already shows in the ping time on both sides, because ping always includes the entire roundtrip. Also add similar latency in the other direction: <pre> ip netns exec abis bash tc qdisc add dev abis-in root handle 1:0 netem delay 200ms 50ms 50% </pre> At this point there is latency in both directions between "abis-in" and "abis-out" h2. usage In my specific example, I configure the BSC to listen for Abis on 10.9.8.1, and I can now run my osmo-bts-trx and osmo-trx-uhd within the "abis" namespace: <pre> ip netns exec abis bash osmo-trx-uhd -C osmo-trx.cfg </pre> In my specific case, I am running osmo-trx-uhd as root user above to be able to set realtime priority on the process. osmo-bts-trx should run as my normal user, but first I need to enter the "abis" netns: <pre> ip netns exec abis bash su - neels osmo-bts-trx -c osmo-bts.cfg </pre>