Project

General

Profile

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.

setup virtual ethernet link

The following setup is volatile, i.e. a reboot of the operating system will wipe out all of it.

(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:

ip netns add abis
ip link add abis-in type veth peer name abis-out
ip link set abis-in netns abis

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:

ip link set abis-out up
ip addr add 10.9.8.1/24 dev abis-out

And for "abis-in" within the "abis" namespace,
first opening a shell in that namespace:

ip netns exec abis bash
ip link set abis-in up
ip addr add 10.9.8.2/24 dev abis-in

verify the link

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)

# 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

A shell running in the "root" namespace should show the "abis-out" link
and any other links your machine may have configured:

# 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

A shell run within the "abis" namespace should be able to ping the "root" namespace:

# 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

And a running in the "root" namespace should be able to ping into the "abis" namespace:

# 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

add latency

In a shell running in the "root" namespace, add a netem delay, for example:

tc qdisc add dev abis-out root handle 1:0 netem delay 200ms 50ms 50%

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:

ip netns exec abis bash
tc qdisc add dev abis-in root handle 1:0 netem delay 200ms 50ms 50%

At this point there is latency in both directions between "abis-in" and "abis-out"

use the link

In my specific example, I configure the BSC to listen for Abis on 10.9.8.1.
I am running osmo-bsc in a normal shell in the "root" namespace, as usual.

The other side of Abis, osmo-bts-trx and osmo-trx-uhd, shall run within the "abis" namespace.
In my specific case, I am running osmo-trx-uhd as root user to allow it to set realtime priority:

sudo ip netns exec abis bash
osmo-trx-uhd -C osmo-trx.cfg

osmo-bts-trx should run as my normal user, but I need to enter the "abis" netns first and su back to my user:

sudo ip netns exec abis bash
su - neels
osmo-bts-trx -c osmo-bts.cfg

troubleshooting

loopback 127.0.0.1 not working

In the new netns, the loopback interface will still be in state DOWN.
To be able to use loopback addresses like 127.0.0.1, set the lo link to UP:

ip link set lo up

modify the latency

To add a new network latency while the interface is running,
you may first want to delete the previously set latency:

ip netns exec abis  tc qdisc del dev abis-in root handle 1:0
tc qdisc del dev abis-out root handle 1:0

Clean up

When done using the virtual latency link, it suffices to remove the "abis" namespace:

ip netns delete abis

It will still be functional until the last shell running in the namespace exits.

Script

Attached is a script that works well to set up a network namespace with latency on a link to/from it:
virtual-link.sh

Add picture from clipboard (Maximum size: 48.8 MB)