Linux core starting from the version 2.6.29 has quite interesting and useful function – network namespaces(netns), nevertheless people either don’t know about it, or don’t understand what to do with it. This post reviews several possible usage examples of this functionality:
- L3VPN monitoring with ovelapped address space using zabbix and zabbix-proxy
- Automated testing of network software (dhcp, pppoe-servers etc.)
- Providing L3VPN service with additional services (NAT, DHCP and others) and CPE virtualization as a special case of this task
- Isolation of server controls from other services
The function is similar to Cisco VRF, but even more does it remind about Juniper logical-system. Besides, the above-stated tasks can be solved by creating a set of conventional virtual machines or OpenVZ containers. Traditional virtualization is not exactly practical when dealing with pure network “isolation” tasks, and anyway it has its expenses (including expenses for maintenance). OpenVZ is nearly perfect, though it isn’t commited to the upstream and therefore limits you in the choice of the core version and chains you with dependancy.
For this note we used Ubuntu 12.04.2 LTS, however almost everything written here is applicable to most of other up-to-date distributions. Before you start, check netns existence in the core and see the support for network spaces in the userspace utility ip, used for configuring:
# cat /boot/config-`uname -r` | grep CONFIG_NET_NS CONFIG_NET_NS=y # ip netns help Usage: ip netns list ip netns add NAME ip netns delete NAME ip netns exec NAME cmd ... ip netns monitor
Each netns has its own interfaces, routing tables, a firewall and its own sockets isolated from other netns. For simplicity, the first example is a demonstration of netns usage for automated testing of network software (creating interfaces, routes and so on) based on the example of a pppoe-server accel-pppd. Testing diagram:
First, we create 2 netns and 2 virtual ethernet interfaces (linked to different netns) and connect them both using a link:
#Create 2 netns: ip netns add Server ; ip netns add Client #Create 2 veth-interfaces and a link between them ip link add veth0-C type veth peer name veth0-S #Linking interfaces to their netns: ip link set veth0-C netns Client ip link set veth0-S netns Server #Setting up interfaces (ifconfig executes on different netns): ip netns exec Client ifconfig veth0-C up ip netns exec Server ifconfig veth0-S up
Therefore, we obtained L2-connectivity between two netns, while both netns are isolated from the global one. Now, we run the server and the client, each one in its own network space:
ip netns exec Server /etc/init.d/accel-ppp start ip netns exec Client pppd call test1
Configuration /etc/accel-ppp.conf (authorize with any login/password). Configuration of the client (/etc/ppp/peers/test1 ) can be generated with the “ip netns exec Client pppoeconf” command.
# ip netns exec Client ip route show default dev ppp0 scope link 192.0.2.1 dev ppp0 proto kernel scope link src 192.0.2.2 # ip netns exec Server ip route show 192.0.2.2 dev ppp0 proto kernel scope link src 192.0.2.1 # ip netns exec Client ping 192.0.2.1 -c 1 PING 192.0.2.1 (192.0.2.1) 56(84) bytes of data. 64 bytes from 192.0.2.1: icmp_req=1 ttl=64 time=0.155 ms ...
As you can see, the pppoe session is installed, and the created interfaces and routes do not interfere with anything else as they do not belong to the default namespace. The same way we can test dhcp/l2tp/openvpn/other services within the bounds of the same host, and that in turn allows us to easily automate the testing process, because nothing stops us from writing a script to create netns, interfaces and executing processes in them (a server and clients). We don’t need to satick to third-party services like openvz or vmware to conduct the tests, nor do we need to write complex scripts for control.
The second example is using netns and zabbix+zabbix proxy to monitor several vrf/l2vpn with overlapping address spaces.
With eth0.10 and eth0.20 we can reach client vrf, the veth interfaces are in charge for providing connectivity between the global netns (the one running zabbix-server) and zabbix-proxy processes. The interface eth0(or eth1) implements server control.
#Create 2 netns ip netns add vrf1; ip netns add vrf2 #Create 2 dot1Q subinterfaces vconfig add eth0 10; vconfig add eth0 20 #Link subinterfaces to their corresponding netns ip link set eth0.10 netns vrf1 ip link set eth0.20 netns vrf2 #Assigning an IP-address and specifying the gate to access client vpn ip netns exec vrf1 ifconfig eth0.10 192.0.2.2/30 up ip netns exec vrf2 ifconfig eth0.20 192.0.2.2/30 up ip netns exec vrf2 ip route add default via 192.0.2.1 ip netns exec vrf1 ip route add default via 192.0.2.1 #Connectivity between vrf1 and the global netns ip link add veth1-P type veth peer name veth1-S; ip link set veth1-P netns vrf1 ifconfig veth1-S add 2001:DB8::1/126 up ip netns exec vrf1 ifconfig veth1-P add 2001:DB8::2/126 #Connectivity between vrf2 and the global netns ip link add veth2-P type veth peer name veth2-S; ip link set veth2-P netns vrf1 ifconfig veth2-S add 2001:DB8::5/126 up ip netns exec vrf1 ifconfig veth2-P add 2001:DB8::6/126 #Executing zabbix-es /etc/init.d/zabbix-server start ip netns exec vrf1 zabbix_proxy1_start ip netns exec vrf2 zabbix_proxy2_start
Apparently, veth-link addressing should not overlap; in the example we use ipv6 address (to avoid adjustment of these addreses to all clients and to avoid using real IPv4 addresses). Addresses on the “external” interfaces eth0.10 and eth0.20 should be adjusted to clients, but they can overlap. Simply put, we ony need to ask a client to allocate any /30 of its address plan (or do this yourself, if it is your vpn).
Configuring zabbix falls beyond the scope of this article, but in fact there are no significant differences from the multi-host layout (expect multiple configuration and zabbix-proxy execution scripts on the same server).
In the Client1 network space, the interface eth0.10 is used to access the Internet, while interfaces eth0.11-eth0.19 look for client access points (every access point has its own vlan). Real address are allocated using ip unnumbered. In this example we do this on the ASBR router. You can easily find how to configure ip unnumbered for static address distribution on Cisco or Linux on the web. And if the server (that implements subscription vpn) plays the role of the ASBR, then veth interfaces (between netns of a client and the global netns) work as eth0.10 and eth0.20, and ip unnumbered is implemented on the same host in the default network space.
Enabling routing and NAT is done as follows:
ip netns exec Client1 sysctl net.ipv4.ip_forward=1 ip netns exec Client1 iptables -t nat -I POSTROUTING -o eth0.10 -j SNAT --to-source 192.0.2.2 ip netns exec Client2 sysctl net.ipv4.ip_forward=1 ip netns exec Client2 iptables -t nat -I POSTROUTING -o eth0.20 -j SNAT --to-source 192.0.2.3
We have reviewed other required actions (creating netns and assigning addresses) in the above two examples. If necessary, you can provide a DHCP service to clients; to do this you need to run dhcpd in the corresponding netns. If a client wants bgp in its vpn, you can run quagga/bird in his netns as well.
Obviously, when there is only one client access point, the solution to the problem degrades to nothing else but virtualization of CPE (or cloud CPE as it is called now). Such option can be seen interesting to provide services to high-income clients, while for general purpose services there is no much sense in allocating netns for every client as we can instead simply allocate various private networks (from the RFC6598 range) to clients in one network space.
The final example here is transferring server controls to a non-global netns.
/etc/init.d/ssh stop ip netns exec MGMT /usr/sbin/sshd -D
Now, if you connect to this server via ssh, you enter the MGMT network space (ifconfig will display interfaces related to netns MGMT only). You can switch to any other netns with: “ip netns exec Other-ns bash”, but not to the global one. In order to access the global netns you have to compile ns_exec utility from the setns function docs (man setns)(source copy ns_exec.c)
gcc ns_exec.c -o ns_exec #Using ns_exec: ./ns_exec /proc/1/ns/net bash
(where 1 is the number of the init process)
P.S. Be careful: when you create a new netns, it doesn’t have the loop interface (lo) up. Because of this, ping of local IP-addresses (assigned to interfaces) doesn’t work from the netns. In order to up the loopback, execute the following command “ip netns exec NS ifconfig lo 127.0.0.1 up”