What is a Linux namespace?
A Linux namespace is an abstraction over certain resources in the operating system. Currently Linux provides 7 types of namespaces: PID
, Network
, Mount
, UTS
, Time
, User
, IPC
.Think of namespace as a box; the box(namespace) type emulates certain system resources, which makes the process within this namespace appear isolated. So, for instance, network namespace emulates/encapsulates the system resources related to network interfaces(eth0
, wlan0
), route tables.
So, what is a network namespace then? Say you're installing a new Linux distro on your PC; this shares a single set of network interfaces, route table entries, firewall rules etc... If you change the entires of these routing tables or firewall rules, this change is shared across the entire OS. With network namespace, you can have different and separate instances of network interfaces and routing tables that operate independently. So each namespace will have its own set of interfaces, routing tables and firewall rules. Resources of one namespace are not visible to other namespaces, but the root namespace has visibility to all the resources across all the namespaces.
This might seem complex now, but these are best illustrated by creating a few namespaces and playing with them. Namespaces aren't some add-on feature or some library that you need to install; they are provided by the Linux kernel itself and are a prerequisite to run any process on the system.
Ip route tools are necessary to manage the network namespaces. Throughout this blog, I will be using Ubuntu 20.04. Use sudo apt-get install -y iproute2
to install the iproute2 suite.
Let's Play with namespaces
Let's start with the typical server-client topology. We will create two namespaces that will act like two isolated machines and then ping one namespace from the other. You need to be root
user or prepend sudo for the following commands.
ip netns add server
This command will create a new namespace called server
. To view all the network namespaces available in the system:
ls /var/run/netns
or via ip
ip netns list
Now create a client.
ip netns add client
Now we have two namespaces, server
and client
, let's establish a connection between these two.
Assigning Interfaces to the Network namespaces
Once we create namespaces next part is to assign interfaces to the namespaces and then configure those interfaces for network connectivity. You can assign physical interfaces or virtual ethernet(Veth) interfaces to these namespaces. But we will stick to veth interfaces in this post. Virtual Ethernet interfaces are an interesting construct; they always come in pairs, and they are connected like a tube—whatever comes in one veth interface will come out the other peer veth interface. As a result, you can use veth interfaces to connect a network namespace to the outside world via the "default" or "global" namespace where physical interfaces exist.
Let's see how this is done. First, we will create a veth pair:
ip link add veth0 type veth peer name veth1
This command will create a link between the veth0
interface of type virtual ethernet (veth) and link it with the veth1
interface. When I was exploring the network namespaces, this command was repeated so that veth1 is connected to veth0, but when the above command creates two interfaces and links them automatically.
To verify whether the veth pair was created using the command:
ip link list
You might see a few interfaces other than the above veth interfaces; this is because the veth interfaces we created are in default
or global
namespace, which contains other physical interfaces. Now we will move these interfaces to the server
and client
namespaces.
ip link set veth0 netns server
This sets the veth0 interface to the sever
namespace. Now, if you try to list all the interfaces in the global namespace, you'll see the veth0
has disappeared from the global namespace. This is because, through the above command, we moved the veth0 interface to the server namespace. Similarly we will move veth1 interface to client namespace.
ip link set veth1 netns client
So how can we confirm that the veth0
and veth1
interfaces were moved to the namespaces? Again we will run ip link list
command, but this time inside the namespace.
ip netns exec server ip link list
That looks like a complicated command; let's break it down.
- The first part,
ip netns exec
, is how we run different commands inside a particular namespace. server
is the name of the namespace where you want to run the command.- Final part is the actual command to be executed inside the namespace. In this case, to list all the interfaces, so
ip link list
.
When you execute this command, you should see the loopback and veth0
interface that we moved earlier.
configuring the interfaces in network namespaces
Now we have moved the interfaces to their namespaces; now, we need to configure this interface. Once again, we'll use ip netns exec
command, this time to configure the interface.
ip netns exec server ip addr add 10.0.0.2/24 dev veth0
The above command ip addr add 10.0.0.2/24 dev veth0
assigns the specified IP(10.0.0.2
) to the veth0 interface. Similarly, we assign a IP to veth1 in client namespace.
ip netns exec client ip addr add 10.0.0.3/24 dev veth1
Now we have configured the interface in the namespace. But still if you list the interfaces(ip netns exec client ip addr
you'll see the interface veth1
has been assigned IP address, but the interface itself is DOWN
.
veth1@if27: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether da:83:ce:d6:09:f4 brd ff:ff:ff:ff:ff:ff link-netns server
inet 10.0.0.2/24 scope global veth1
So next step would be to bring the interfaces UP
sudo ip netns exec server ip link set dev veth0 up
sudo ip netns exec client ip link set dev veth1 up
Now everything's set up and working fine. How do we test this though? Simple, following our goal, we will ping one namespace from the other. Similar to how we ping a particular IP to see whether we are connected.
Summary
A network namespace is logically another copy of the network stack, with its own routes, firewall rules, and network devices. Network namespaces are a lightweight mechanism for resource isolation. Processes attached to a network namespace see their own network stack while not interfering with the rest of the system's network stack. Network namespaces are easy to use too.
Similar network-level isolation could have been set up using a VM. However, that seems a much more expensive solution for system resources and time investment to build up such an environment. If you only need process isolation at the networking level, network namespaces are definitively something to consider.