
Linux Network Namespace Usage
Namespaces are feature of Linux kernal, to provide a virtual grouping and isolation of processes for accessing a particular global resource in the system. Which means your process inside namespace will have a virtual isolated copy of the global system resource. There are total six types of namespace implemented in linux to isolate the global system resources.
a. UTS namespaces — Used to isolate the hostname for process. This allows us to set different host name for each process.
b. IPC namespaces — This isolates inter process communication(IPC) resources such as System V IPC and POSIX message queues.
c. PID namespaces — Isolates the process tree, making processes inside the namespace can have the same id as the one in the host system.
d. Network namespaces — Provides isolation on networking resources by virtualizing the network stack.
e. User namespaces — For user and group id resource isolation.
f. Mount namespaces — Isolates the filesystem mount points. Each namespaces will have different view of filesystem.
Containers use these different namespaces to provide a virtually isolated environments to user processes. Here I will be talking about the networking namespace usage in Linux and the details about it.
Each network namespaces will have its own copy of stack with the routes, devices, firewall rules etc.
I am using Ubuntu 16.04LTS OS with root privileage for this example.
Creating namespace
We can create a new namespace using the “ip netns add NAME” command.
root@host1:~# ip netns add ns1
root@host1:~#
The “ip netns list” command lists all namespaces in the system. Check the namespace ns1 is created successfully or not.
root@host1:~# ip netns list
ns1
root@host1:~#
Operating inside the namespace
Operations inside the namespace can be performed using the “ip [-all] netns exec [NAME] CMD …” command. This command will take the namespace name as an input and the command to be executed at the tail. Commands can be executed on all namespaces together as well as on individual separately.
Below example shows how to see the ip address on each namespace created.
root@host1:~# ip -all netns exec ip addressnetns: ns2
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00netns: ns1
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
root@host1:~#
In this example, I had two namespaces and lists ip address on both namespaces using single command. The keyword “-all” specifies the command is to be executed on all namespace together. The “ip address” part is the command to be executed in each namespace.
For executing command only on specific namespace need use the name instead of “-all” keyword.
root@host1:~# ip netns exec ns1 ip address
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
root@host1:~#
Note that we have mentioned the namespace name after the “exec” keyword.
Any Linux commands can be executed inside the namespace using the exec command, such as running an application, displaying log file, add/set/delete new interface etc.
Adding a network interface to namespace
By default, networking namespaces will be created with loopback interface “lo”, but these interfaces will not be UP. So we use the below command to make the loopback interface UP.
root@host1:~# ip netns exec ns1 ip address
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
root@host1:~# ip netns exec ns1 ip link set dev lo up
root@host1:~# ip netns exec ns1 ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
root@host1:~#
Now the loopback interface state is running, and it can reach from a client inside the namespace. But your namespace is not reachable from the outside, for this you need to add one external interface and assigne an IP to it. You can either assign an additional physical interface which you have in the host or create a virtual interface to make the namespace reachable from the outside host.
First, I will show how we can assign an existing physical interface to the namespace. As seen below I have two physical network interface in my host system.
root@host1:~# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
2: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:5f:85:d2 brd ff:ff:ff:ff:ff:ff
inet 192.167.1.10/24 brd 192.167.1.255 scope global enp0s8
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe5f:85d2/64 scope link
valid_lft forever preferred_lft forever
3: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:78:c0:6d brd ff:ff:ff:ff:ff:ff
inet 172.167.1.10/24 brd 172.167.1.255 scope global enp0s9
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe78:c06d/64 scope link
valid_lft forever preferred_lft forever
root@host1:~#

Now i will assign the enp0s9 interface to the namespace ns1.
root@host1:~# ip link set enp0s9 netns ns1
After this command execution the interface will be disappeared from the host.
root@host1:~# ip address show enp0s9
Device “enp0s9” does not exist.
Now check the network devices inside the namespace, the interface is present there, but the IP went missing.
root@host1:~# ip netns exec ns1 ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
3: enp0s9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 08:00:27:78:c0:6d brd ff:ff:ff:ff:ff:ff
Set the IP in the interface now using the below command.
root@host1:~# ip netns exec ns1 ip address add 172.167.1.11/24 dev enp0s9
root@host1:~# ip netns exec ns1 ip address show enp0s9
3: enp0s9: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link/ether 08:00:27:78:c0:6d brd ff:ff:ff:ff:ff:ff
inet 172.167.1.11/24 scope global enp0s9
valid_lft forever preferred_lft forever
root@host1:~#
Now the IP address is configured in the system, but still the ip will not be reachable as the interface is still in DOWN state. So you need to make the device UP using the below command.
root@host1:~# ip netns exec ns1 ip link set dev enp0s9 up
root@host1:~# ip netns exec ns1 ip address show enp0s9
3: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:78:c0:6d brd ff:ff:ff:ff:ff:ff
inet 172.167.1.11/24 scope global enp0s9
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe78:c06d/64 scope link
valid_lft forever preferred_lft forever
root@host1:~#
The interface is ready now to receive the packets and it is inside the namespace. This interface will not be visible and accessable now outside this namespace.
In case if you want to release the physical interface attached to namespace back to the host you can perform the below command.
root@host1:~# ip netns exec ns1 ip link set enp0s9 netns 1
root@host1:~# ip address show enp0s9
3: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:78:c0:6d brd ff:ff:ff:ff:ff:ff
inet 172.167.1.10/24 brd 172.167.1.255 scope global enp0s9
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe78:c06d/64 scope link
valid_lft forever preferred_lft forever
root@host1:~#
This command will execute a command to set the network device to the root name space. The “1” in the command represent the PID of the root namespace.
Second way is to use the virtual interface to provide the network connectivity between the namespace. There are many ways to create the virtual interfaces, here I will show how we can create a virtual interface for namespaces using the veth pair. The veth pair contains two ends, in which one side will be connected to the namespace and other one will reside on the host machine. This will act as a pipe between the host machine and the namespace. Whenever we want to send any data to the namespace interface we can write it to the host end and it will be received in the namespace.
Below command will create two virtual interfaces and link each other to form a veth pair.
root@host1:~# ip link add veth1 type veth peer name vnseth1
root@host1:~#
root@host1:~# ip address
8: vnseth1@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 0a:a4:e4:03:1e:9b brd ff:ff:ff:ff:ff:ff
9: veth1@vnseth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 5e:99:13:98:c0:b2 brd ff:ff:ff:ff:ff:ff
root@host1:~#
Two virtual ethernet interface is added as shown above. The “ip link add” takes two interface names and the type as “veth” to create the veth pair interfaces. The interface name listed above itself having the link information. Now use the below command to add this interface to the namespace which you created already.
root@host1:~# ip link set vnseth1 netns ns1
root@host1:~#
root@host1:~# ip netns exec ns1 ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
8: vnseth1@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 0a:a4:e4:03:1e:9b brd ff:ff:ff:ff:ff:ff link-netnsid 0
root@host1:~#

One end of the veth pair has added to the namespace now, and disappeared from the host system. So now we have on end in the host and other one in the name space. Now set the ip on both the end like the below example.
root@host1:~# ip netns exec ns1 ip addr add 20.1.1.8/24 dev vnseth1
root@host1:~# ip netns exec ns1 ip link set vnseth1 uproot@host1:~# ip addr add 20.1.1.1/24 dev veth1
root@host1:~# ip link set veth1 up
Now we have the ip 20.1.1.1 on the host device and the 20.1.1.8 on the namespace, so from the host device you can ping the namespace interface ip 20.1.1.8 and check the connection is established successfully or not. But still you cannot have inter namespace communication now, for that we can eaither use linux bridge or openvswitch for interconnecting the namespaces.
We dont need the ip on the veth pait interface in the host machine, we can reset the ip using either of the below commands.
root@host1:~# ip addr delete 20.1.1.12/24 dev veth1
or
root@host1:~# ifconfig veth1 0
Bind the virtual interface to OpenVSwitch
In below example I shows how we can interconnect these interfaces using openvswitch. First install current version of the openvswitch package in the system, after that check the installation usign the below command.
root@host1:~# ovs-vsctl show
32674ab1-cb63–4fbc-a84e-4544436340bb
ovs_version: “2.5.2”
root@host1:~#
The above output means the package is installed successfully. Now you need to add a bridge in this ovs, so that the namepace can be connected to this bridge for packet transfer. Below command helps you to create a bridge in the ovs.
root@host1:~# ovs-vsctl add-br br-test
root@host1:~#
root@host1:~# ovs-vsctl show
32674ab1-cb63–4fbc-a84e-4544436340bb
Bridge br-test
Port br-test
Interface br-test
type: internal
ovs_version: “2.5.2”
root@host1:~#
One new bridge has created now and there is one port also created inside it automatically. This port is created for internal purpose, in case if need to communicate with the bridge, we can assign an ip to this port and send packet to this ip. There will be one interface also added inside this port. Interface is placed inside port because, one port can have multiple interfaces like grouping interfaces together.
Now the ovs and bridge is ready, you can now add the port to this bridge. Attach the another end of the veth pair to this bridge in the ovs.
root@host1:~# ovs-vsctl add-port br-test veth1
root@host1:~#
root@host1:~# ovs-vsctl show
32674ab1-cb63–4fbc-a84e-4544436340bb
Bridge br-test
Port br-test
Interface br-test
type: internal
Port “veth1”
Interface “veth1”
ovs_version: “2.5.2”
root@host1:~#
Interface is added now to the bridge, but you don’t have another namespace to test this. Create one following the same steps as above.
root@host1:~# ip netns add ns2
root@host1:~# ip netns exec ns2 ip link set dev lo up
root@host1:~# ip link add veth2 type veth peer name vnseth2
root@host1:~# ip link set vnseth2 netns ns2
root@host1:~# ip netns exec ns2 ip link set vnseth2 up
root@host1:~# ip link set veth2 up
root@host1:~# ip netns exec ns2 ip addr add 20.1.1.9/24 dev vnseth2
root@host1:~# ovs-vsctl add-port br-test veth2
root@host1:~# ovs-vsctl show
32674ab1-cb63–4fbc-a84e-4544436340bb
Bridge br-test
Port “veth1”
Interface “veth1”
Port br-test
Interface br-test
type: internal
Port “veth2”
Interface “veth2”
ovs_version: “2.5.2”
root@host1:~# ip netns exec ns2 ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
11: vnseth2@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 9e:7e:1a:a5:04:c5 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 20.1.1.9/24 scope global vnseth2
valid_lft forever preferred_lft forever
inet6 fe80::9c7e:1aff:fea5:4c5/64 scope link
valid_lft forever preferred_lft forever
root@host1:~#

We have created another namespace names ns2, added one interface and assigned the ip 20.1.1.9 to it. Now we can ping the ip in one namespace from another like below.
root@host1:~# ip netns exec ns1 ping 20.1.1.9 -c 1
PING 20.1.1.9 (20.1.1.9) 56(84) bytes of data.
64 bytes from 20.1.1.9: icmp_seq=1 ttl=64 time=1.00 ms— — 20.1.1.9 ping statistics — -
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.006/1.006/1.006/0.000 ms
root@host1:~#
root@host1:~#
root@host1:~# ip netns exec ns2 ping 20.1.1.8 -c 1
PING 20.1.1.8 (20.1.1.8) 56(84) bytes of data.
64 bytes from 20.1.1.8: icmp_seq=1 ttl=64 time=0.055 ms— — 20.1.1.8 ping statistics — -
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.055/0.055/0.055/0.000 ms
root@host1:~#
You have successfully setup a network namespace now.
References:
https://lwn.net/Articles/531114/