This is the second part of the series Container Networking. I will cover Network Namespaces and Linux Bridges in this blog post.
Linux Namespaces wiki says
Namespaces are a feature of the Linux kernel that partition kernel resources
such that one set of processes sees one set of resources, while another set
of processes sees a different set of resources.
So, the process isolation is provided using namespaces and cgroups. This allows each process to see its personal view of the system (files, process, network interfaces, hostname).
Another excerpt from the wiki.
ince kernel version 5.6, there are 8 kinds of namespaces.
Network namespaces virtualize the network stack. On creation, a network
namespace contains only a loopback interface. Each network interface
(physical or virtual) is present in exactly 1 namespace and can be moved
between namespaces.
ip-netns utility helps to create network namespaces. Let’s see how.
Network Namespaces Demo
Create a network namespaces.
sudo ip netns add ns1
List them.
ip netns list
ns1
Only the loopback interface is available in ns1
namespace.
sudo ip netns exec ns1 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
The following diagram helps to visualize the setup.
For brevity, I will not list lo
and enp0s3
interfaces in the rest of the diagrams.
Now, let’s create a veth
pair.
sudo ip link add vethX type veth peer name vethY
sudo ip link set vethX up
sudo ip link set vethY up
Attach one end of the veth
pair to ns1
namespace.
sudo ip link set vethX netns ns1
This ensures processes in the default/root namespace cannot see vethX
interface.
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
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 02:fd:4d:34:55:76 brd ff:ff:ff:ff:ff:ff
18: vethY@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 5a:bc:4d:7e:76:b1 brd ff:ff:ff:ff:ff:ff link-netns ns1
And processes in ns1
namespace could not see vethY
interface.
sudo ip netns exec ns1 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
19: vethX@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 5e:4b:13:90:7d:63 brd ff:ff:ff:ff:ff:ff link-netnsid 0
In a similar fashion, we can create another namespace. Create a new veth
pair. And then attach one end of veth
pair to a namespace.
udo ip netns add ns2
sudo ip link add vethP type veth peer name vethQ
sudo ip link set vethP up
sudo ip link set vethQ up
sudo ip link set vethP netns ns2
Now, the last part is to connect these two namespaces with a Bridge.
A bridge connects two LAN segments together. We will create a new bridge and attach vethY
and vethQ
to this bridge.
sudo ip link add name br0 type bridge
sudo ip link set dev br0 up
sudo ip link set vethY master br0
sudo ip link set vethQ master br0
As we have looked in the last blog post, any packet on bridge br0
is seen on all the veths
we have created. You can try it for yourself.
Now, by this time, you might have started imagining how a container achieves network isolation using Virtual Ethernet, Bridge, and Linux Namespaces. We will take a look at the docker container in the next blog post.
Before you jump to the next article, let’s clean up the setup.
sudo ip link del br0
sudo ip link del vethY
sudo ip link del vethQ
sudo ip netns del ns1
sudo ip netns del ns2