使用Linux进行IP层网络管理的指 http://linux-ip.net/html/
# yum install iproute
http://linux-ip.net/html/tools-ip-route.html
https://segmentfault.com/a/1190000000638244
参考:https://cizixs.com/2017/02/10/network-virtualization-network-namespace/
network namespace 是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自的网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己就在独立的网络中。
介绍 network namespace 的基本概念和用法,network namespace 是 linux 内核提供的功能,借助 ip
命令来完成各种操作。ip
命令来自于 iproute2
安装包,一般系统会默认安装,如果没有的话,请读者自行安装。
NOTE:ip
命令因为需要修改系统的网络配置,默认需要 sudo 权限。这篇文章使用 root 用户执行,请不要在生产环境或者重要的系统中用 root 直接执行,以防产生错误。
ip
命令管理的功能很多,和 network namespace 有关的操作都是在子命令 ip netns
下进行的,可以通过 ip netns help` 查看所有操作的帮助信息。
默认情况下,使用 ip netns
是没有网络 namespace 的,所以 ip netns ls
命令看不到任何输出。
# ip
Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }
ip [ -force ] -batch filename
where OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |
tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |
netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |
vrf }
OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |
-h[uman-readable] | -iec |
-f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |
-4 | -6 | -I | -D | -B | -0 |
-l[oops] { maximum-addr-flush-attempts } | -br[ief] |
-o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |
-rc[vbuf] [size] | -n[etns] name | -a[ll] |?-c[olor]}
# ip netns help
Usage: ip netns list
ip netns add NAME
ip netns set NAME NETNSID
ip [-all] netns delete [NAME]
ip netns identify [PID]
ip netns pids NAME
ip [-all] netns exec [NAME] cmd ...
ip netns monitor
ip netns list-id
创建 network namespace 也非常简单,直接使用 ip netns add
后面跟着要创建的 namespace 名称。如果相同名字的 namespace 已经存在,命令会报 Cannot create namespace
的错误。
# ip netns add r1
# ip netns list
r1
ip netns
命令创建的 network namespace 会出现在 /var/run/netns/
目录下,如果需要管理其他不是 ip netns
创建的 network namespace,只要在这个目录下创建一个指向对应 network namespace 文件的链接就行。
有了自己创建的 network namespace,我们还需要看看它里面有哪些东西。对于每个 network namespace 来说,它会有自己独立的网卡、路由表、ARP 表、iptables 等和网络相关的资源。ip
命令提供了 ip netns exec
子命令可以在对应的 network namespace 中执行命令,比如我们要看一下这个 network namespace 中有哪些网卡。更棒的是,要执行的可以是任何命令,不只是和网络相关的(当然,和网络无关命令执行的结果和在外部执行没有区别)。比如下面例子中,执行 bash
命令了之后,后面所有的命令都是在这个 network namespace 中执行的,好处是不用每次执行命令都要把 ip netns exec NAME
补全,缺点是你无法清楚知道自己当前所在的 shell
,容易混淆。
[@node3 ~]# ip netns exec r1 ifconfig
[@node3 ~]# ip netns exec r1 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00[@node3 ~]# ip netns exec r1 bash
[@node3 ~]# ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
每个 namespace在创建的时候会自动创建一个 lo
的 interface,它的作用和 linux 系统中默认看到的 lo
一样,都是为了实现 loopback 通信。如果希望 lo
能工作,不要忘记启用它:
[root@node3 ~]# ip netns exec r1 ip link set lo up
默认情况下,network namespace 是不能和主机网络,或者其他 network namespace 通信的。
# ip link help Usage: ip link add [link DEV] [ name ] NAME [ txqueuelen PACKETS ] [ address LLADDR ] [ broadcast LLADDR ] [ mtu MTU ] [index IDX ] [ numtxqueues QUEUE_COUNT ] [ numrxqueues QUEUE_COUNT ] type TYPE [ ARGS ] ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ] ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ] [ type TYPE ARGS ] [ arp { on | off } ] [ dynamic { on | off } ] [ multicast { on | off } ] [ allmulticast { on | off } ] [ promisc { on | off } ] [ trailers { on | off } ] [ carrier { on | off } ] [ txqueuelen PACKETS ] [ name NEWNAME ] [ address LLADDR ] [ broadcast LLADDR ] [ mtu MTU ] [ netns { PID | NAME } ] [ link-netnsid ID ] [ alias NAME ] [ vf NUM [ mac LLADDR ] [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ] [ rate TXRATE ] [ max_tx_rate TXRATE ] [ min_tx_rate TXRATE ] [ spoofchk { on | off} ] [ query_rss { on | off} ] [ state { auto | enable | disable} ] ] [ trust { on | off} ] ] [ node_guid { eui64 } ] [ port_guid { eui64 } ] [ xdp { off | object FILE [ section NAME ] [ verbose ] | pinned FILE } ] [ master DEVICE ][ vrf NAME ] [ nomaster ] [ addrgenmode { eui64 | none | stable_secret | random } ] [ protodown { on | off } ] ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE] ip link xstats type TYPE [ ARGS ] ip link afstats [ dev DEVICE ] ip link help [ TYPE ] TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap | bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan | gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave | bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }
network namespace 之间通信
有了不同 network namespace 之后,也就有了网络的隔离,但是如果它们之间没有办法通信,也没有实际用处。要把两个网络连接起来,linux 提供了 veth pair
。可以把 veth pair
当做是双向的 pipe(管道),从一个方向发送的网络数据,可以直接被另外一端接收到;或者也可以想象成两个 namespace 直接通过一个特殊的虚拟网卡连接起来,可以直接通信。
使用 ip link add type veth
来创建一对 veth pair 出来,需要记住的是 veth pair 无法单独存在,删除其中一个,另一个也会自动消失。
# ip link add name veth1.1 type veth peer name veth1.2
# ip link sh
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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 00:0c:29:82:17:a2 brd ff:ff:ff:ff:ff:ff 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default link/ether 02:42:1a:5e:9d:4e brd ff:ff:ff:ff:ff:ff 4: [email protected]: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 //此时veth1.1和veth1.2都是在宿主机上 link/ether 36:59:f5:02:39:1d brd ff:ff:ff:ff:ff:ff 5: [email protected]: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 0e:b8:58:dd:5d:5a brd ff:ff:ff:ff:ff:ff
# ip addr list
2: veth1.2@veth1.1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 //此时都是没有启动的
link/ether d2:e2:d8:fd:50:60 brd ff:ff:ff:ff:ff:ff
3: veth1.1@veth1.2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 2a:b1:4b:19:fa:b8 brd ff:ff:ff:ff:ff:ff
创建 veth pair 的时候可以自己指定它们的名字,比如 ip link add veth1.1 type veth peer name veth1.2
创建出来的两个名字就是 veth1.1
和 veth1.2
。
如果 pair 的一端接口处于 DOWN 状态,另一端能自动检测到这个信息,并把自己的状态设置为 NO-CARRIER
。
创建结束之后,能看到名字为 veth1.1
和 veth1.2
两个网络接口。
# ip link help
Usage: ip link add [link DEV] [ name ] NAME ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ] [ type TYPE ARGS ] [ arp { on | off } ] [ dynamic { on | off } ] [ multicast { on | off } ] [ allmulticast { on | off } ] [ promisc { on | off } ] [ trailers { on | off } ] [ carrier { on | off } ] [ txqueuelen PACKETS ] [ name NEWNAME ] [ address LLADDR ] [ broadcast LLADDR ] [ mtu MTU ] [ netns { PID | NAME } ] [ link-netnsid ID ] [ alias NAME ] [ vf NUM [ mac LLADDR ] TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap | bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan | gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave | bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }
接下来,要做的是把veth1.2放到namespace --> r1,把veth1.1留在宿主机上,这个可以使用 ip link set DEV netns NAME
来实现
# ip link set dev veth1.2 netns r1
# ip link sh
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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 00:0c:29:82:17:a2 brd ff:ff:ff:ff:ff:ff 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default link/ether 02:42:1a:5e:9d:4e brd ff:ff:ff:ff:ff:ff 5: veth1.1@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 //此时宿主机空间只有veth1.1了 link/ether 0e:b8:58:dd:5d:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0
# ip netns exec r1 ifconfig -a //一个设备只能属于一个名称空间,查看r1名称空间信息
lo: flags=8<LOOPBACK> mtu 65536 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth1.2: flags=4098<BROADCAST,MULTICAST> mtu 1500 ether 36:59:f5:02:39:1d txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0