Introduction

This blog post will provide a high level introduction into Linux networking. We’ll cover some fundamentals, and provide a practical run through of how we can create our own isolated networks on Linux, how we can connect them together and get them talking to the outside world.

Why should I care about Linux Networking?

Today’s networks are increasingly built on devices that themselves are built on top of some flavour of Linux. Think, routers, switches, firewalls, load balancers and even container orchestration platforms like Kubernetes.

Understanding Linux networking is especially important when it comes to understanding how Docker containers and Kubernetes pods achieve their isolation and what goes on under the hood. Therefore it can be a great help when it comes to troubleshooting Docker & Kubernetes networking issues, as they heavily rely on a lot of Linux networking concepts.

Network Namespaces

A very important concept in Linux networking is the network namespace. If you’re a die-hard network engineer, you can think of this being quite similar to a VRF. Network namespaces allow us to create isolated networking environments on a Linux server. Each namespace has it’s own ARP table, routing table, interfaces and firewall rules. Anything inside of a network namespace can’t see interfaces of another namespace or even the underlying Linux host. If it still hasn’t clicked for you, just think of different network namespaces as different rooms in a house. Each has it’s own windows and furniture.

Linux servers have default root network namespace. Think of this being like the default VRF on a Cisco router.

image.png

Let’s go through how we can create and verify network namespaces. We’ll be using the ip netns Linux command to achieve this. If you want to follow along, you can spin up your own free playground here.

# Create 2 network namespaces called red and blue
**$ ip netns add red
$ ip netns add blue**
 
# List network namespaces - We can see blue & red have been successfully created
**$ ip netns list**
blue
red

Next let’s see which interfaces are in the blue network namespace. The ip netns exec command allows us to execute a command from within the network namespace. We’ll combine it with the ip link command to see our interfaces.

# View interfaces in the blue network namespace
**$ ip netns exec blue 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

We can see that the lo interface (short for loopback) was auto-created in the blue network namespace. By default a network namespace doesn’t any external connectivity.

Let’s run the same command in the default root network namespace.

# View interfaces in the root network namespace
$ **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
3: eth0@if18354: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UP mode DEFAULT group default 
    link/ether ba:bd:4a:ce:57:c0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
5: calia1fc8fa9acf@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-d5a6b1fe-ccec-baa2-9d07-0183267636c8
6: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1360 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/ether 1e:7a:06:ab:1f:57 brd ff:ff:ff:ff:ff:ff

Looks like we a few extra interfaces here, eth0 is the main interface on our Linux server which is actually running as a virtual machine. Let’s have a look at how the route table and ARP table differs between the root namespace and the red network namespace

**#** ARP table of root namespace
**$ arp**
Address                  HWtype  HWaddress           Flags Mask            Iface
172.17.0.4               ether   3e:2f:a0:52:e5:e6   C                     calib78ed862b30
172.17.2.0               ether   ba:b9:4d:3b:f5:a7   CM                    flannel.1
172.17.0.3               ether   92:94:ff:6a:bc:25   C                     calia1fc8fa9acf
169.254.1.1              ether   ee:ee:ee:ee:ee:ee   C                     eth0
172.17.0.5               ether   92:aa:be:49:fb:0c   C                     calicf2b395cf49
172.17.1.0               ether   aa:7a:ec:58:49:bd   CM                    flannel.1

# Routing table of root namespace
**$ route**
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         169.254.1.1     0.0.0.0         UG    0      0        0 eth0
169.254.1.1     0.0.0.0         255.255.255.255 UH    0      0        0 eth0
172.17.0.3      0.0.0.0         255.255.255.255 UH    0      0        0 calia1fc8fa9acf
172.17.0.4      0.0.0.0         255.255.255.255 UH    0      0        0 calib78ed862b30
172.17.0.5      0.0.0.0         255.255.255.255 UH    0      0        0 calicf2b395cf49
172.17.1.0      172.17.1.0      255.255.255.0   UG    0      0        0 flannel.1
172.17.2.0      172.17.2.0      255.255.255.0   UG    0      0        0 flannel.1

# ARP table of red namespace
**$ ip netns exec red arp**

# Routing table of red namespace
**$ ip netns exec red route**
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

As you can see, the root and red namespace have very different looking ARP and routing tables. Remember that this is because each namespace is isolated and separate. As it stands we have the default root, blue and red network namespaces on our linux host.

image.png