【轉】linux network namespace 學習


原文地址:https://segmentfault.com/a/1190000004059167

介紹

在專業的網絡世界中,經常使用到Virtual Routing and Forwarding(VRF),比如Cisco,Alcatel-Lucent, Juniper 等。對於L2 switch,自從上世紀90年代就開始使用VLAN,一個物理交換機上可以使用多個廣播域,如今大多數交換機都支持4K vlan。

這個概念被引入到L3,如今很多網絡設備支持VRF。這意味着,單個物理設備上可運行多個虛擬路由(L3 轉發實例)。

在linux中,VRF被叫做“network namespace”,當然了linux中還包括其他namespace,不過本文不討論。

每個network namespace擁有其對應的路由表(routing table)& 其對應的iptables,並且運行程序運行其中。 為什么有人使用它?比如一個運行在linux上的 Firewall,將firewall的所有服務端口分配給一個network namespace,這樣,默認的network namespace 和 Firewall network namespace就運行着不同的路由表。像SSH這樣的application運行在默認的network namespace,但是不在Firewall network namespace。

下面展示了其基本用法。

Basic network namespace commands

基本命令為“ip”,有些用戶使用它來代替廢棄的 ifconfig,route,netstat... 必須為root用戶來使用它,這樣才能更改network stack的配置。下面是ip命令和其他命令的映射:

ifconfig                                            --> ip addr or just ip a
ifconfig <interface> up/down --> ip link set dev <interface> up/down ifconfig <interface> <ip> netmask <netmask> --> ip addr add <ip>/<masklen> dev <interface> netstat -rn --> ip route or just ip r route add -net <net> netmask <netmask> gw <gateway> --> ip r add <net>/<netmasklen> via <gateway>

Check your Linux for namespace support

使用前,先檢查系統是否支持。

Creating a network namespace

# add a new namespace ip netnas add <network namespace name> #Example: ip netns add nstest

Listing all existing network namespaces in the system

# list all namespaces ip netns list #will show the namespace from above nstest

Deleting a network namespace

ip netns delete <network namespace name>

Executing a command in a network namespace

下面展示了使程序運行在network namespace中的“黑魔法”。

# execute a command in a namespace ip netns exec <network namespace name> <command> #Example using the namespace from above: ip netns exec nstest ip addr

展示了在此network namespace中的所有的ip interface

lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

一個臟技巧是在network namespace中運行shell:

ip netns exec <network namespace name> bash

現在,你已經“trapped”入namespace中了,exit退出。

Exploring the network namespace

當我們已經創建了network namespace,第一個task是bring up其中的lo interface。應該注意到的是,在創建了network namespace后,lo interface的狀態是down。如果忽略了這個,可能會發生一些奇怪的事。

# set the link of lo in the namespace to up ip netns exec nstest ip link set dev lo up # list all interfaces and the state in the namespace ip netns exec nstest ip link

現在lo interface狀態為up,現在,是時候將network namespace鏈接到外部空間。

Adding interfaces to a network namespace (這里需要用到veth pair)

什么是veth pair
Veth pair 是一對虛擬網卡,從一張veth網卡發出的數據包可以直接到達它的peer veth,兩者之間存在着虛擬鏈路。Veth 網卡和常規的以太網區別僅在於xmit接口:將數據發送到其peer,觸發peer的Rx 過程。
Veth 的原理示意圖如下:
 
        

 

將一個物理interface分配給network namespace是不可能的,而是使用 virtual interface來實現。所以,我們先創建一個virtual interface,同樣使用 ip command:

ip link add veth-a type veth peer name veth-b

上述命令創建了兩個virtual interface,分別為veth-a & veth-b,他們之間通過一個virtual cable鏈接。ip link命令顯示了在默認namespace下這兩個interface的信息。

ip link veth-b: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000 link/ether 72:01:ad:c5:67:84 brd ff:ff:ff:ff:ff:ff veth-a: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000 link/ether 8e:8b:bd:b1:88:e5 brd ff:ff:ff:ff:ff:ff

下面我們將其中的一個interface添加入之前我們創建的namespace nstest:

ip link set veth-b netns nstest

現在veth-b不在默認的namespace下了,而出現在了nstest 中,使用如下命令驗證:

# list all interfaces in the namespace nstest ip netns exec nstest ip link lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 veth-b: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000 link/ether 72:01:ad:c5:67:84 brd ff:ff:ff:ff:ff:ff

現在,在network namespace nstest中,就擁有了兩個interface。

Assign ip addresses to the veth interfaces

現在是時候為這個veth interface分配ip並且使他的狀態為up。

# default namespace ip addr add 10.0.0.1/24 dev veth-a ip link set dev veth-a up # # namespace nstest ip netns exec nstest ip addr add 10.0.0.2/24 dev veth-b ip netns exec nstest ip link set dev veth-b up

可通過“ip link”查看interface狀態是否為up,使用“ip addr”查看interface的ip 地址,使用“ip route”查看其路由。

現在可以在default namespace中,通過veth-a來ping通 位於 nstest中的veth-b。

ping 10.0.0.2 PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data. 64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=0.054 ms 64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=0.034 ms 64 bytes from 10.0.0.2: icmp_req=3 ttl=64 time=0.039 ms 64 bytes from 10.0.0.2: icmp_req=4 ttl=64 time=0.036 ms

以及在nstest network namespace中,通過veth-b來ping通 veth-a:

ip netns exec nstest ping 10.0.0.1 PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data. 64 bytes from 10.0.0.1: icmp_req=1 ttl=64 time=0.064 ms 64 bytes from 10.0.0.1: icmp_req=2 ttl=64 time=0.036 ms 64 bytes from 10.0.0.1: icmp_req=3 ttl=64 time=0.039 ms

Demo

下面一起來實現一個demo,最終實現如下的case:

首先,先建立對應的namespace:

$ sudo ip netns add server $ sudo ip netns add gateway $ sudo ip netns add client $ ip netns list client gateway server

然后,啟用gateway namespace中的ip forward功能,注意,操作全是在root權限下執行:

$ ip netns exec gateway sysctl net.ipv4.ip_forward=1 net.ipv4.ip_forward = 1

下面我們來創建兩對veth,用來連接不同的namespace:

$ ip link add svr-veth type veth peer name svrgw-veth
$ ip link add cli-veth type veth peer name cligw-veth
$ ip link show | grep veth 3: svrgw-veth: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000 4: svr-veth: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000 5: cligw-veth: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000 6: cli-veth: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000

將veth對的兩端加入對應的namespace中,這樣在默認的default namespace中就看不到他們了:

$ ip link set svr-veth netns server $ ip link set svrgw-veth netns gateway $ ip link set cligw-veth netns gateway $ ip link set cli-veth netns client $ ip link show | grep veth

在指定的namespace上可以看到對應的interface:

$ ip netns exec server ip link show | grep veth 4: svr-veth: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000

為各個veth分配ip:

$ ip netns exec server ip addr add 192.168.100.1/24 broadcast + dev ser-veth $ ip netns exec gateway ip addr add 192.168.100.254/24 broadcast + dev sergw-veth $ ip netns exec gateway ip addr add 10.0.100.254/24 broadcast + dev cligw-veth $ ip netns exec client ip addr add 10.0.100.1/24 broadcast + dev cli-veth

在各個veth對中,通過ping來檢查連通性:

$ ip netns exec gateway ping 192.168.100.1 -I 192.168.100.254 PING 192.168.100.1 (192.168.100.1) from 192.168.100.254 : 56(84) bytes of data. 64 bytes from 192.168.100.1: icmp_req=1 ttl=64 time=0.044 ms 64 bytes from 192.168.100.1: icmp_req=2 ttl=64 time=0.036 ms 64 bytes from 192.168.100.1: icmp_req=3 ttl=64 time=0.040 ms ^C --- 192.168.100.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.036/0.040/0.044/0.003 ms $ ip netns exec gateway ping 10.0.100.1 -I 10.0.100.254 PING 10.0.100.1 (10.0.100.1) from 10.0.100.254 : 56(84) bytes of data. 64 bytes from 10.0.100.1: icmp_req=1 ttl=64 time=0.107 ms 64 bytes from 10.0.100.1: icmp_req=2 ttl=64 time=0.037 ms 64 bytes from 10.0.100.1: icmp_req=3 ttl=64 time=0.037 ms ^C --- 10.0.100.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1998ms rtt min/avg/max/mdev = 0.037/0.060/0.107/0.033 ms

接下來設定路由,將各namespace中的默認路由指向對應的veth ip:

$ sudo ip netns exec client ip route add default via 10.0.100.254 dev cli-veth $ sudo ip netns exec client netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 10.0.100.254 0.0.0.0 UG 0 0 0 cli-veth 10.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 cli-veth $ ip netns exec server ip route add default via 192.168.100.254 dev ser-veth $ ip netns exec server netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 192.168.100.254 0.0.0.0 UG 0 0 0 svr-veth 192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 svr-veth

最后我們嘗試從client namespace 到 server namespace的網絡連通性,通過ping命令來測試:

 
$ ip netns exec client ping 192.168.100.1 -I 10.0.100.1 PING 192.168.100.1 (192.168.100.1) from 10.0.100.1 : 56(84) bytes of data. 64 bytes from 192.168.100.1: icmp_req=1 ttl=63 time=0.106 ms 64 bytes from 192.168.100.1: icmp_req=2 ttl=63 time=0.076 ms 64 bytes from 192.168.100.1: icmp_req=3 ttl=63 time=0.050 ms ^C --- 192.168.100.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.050/0.077/0.106/0.024 ms

Dokcer網絡: https://segmentfault.com/a/1190000005794036


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM