网络节点

br-tun

  1. Bridge br-tun
  2. Port br-tun
  3. Interface br-tun
  4. type: internal
  5. Port patch-int
  6. Interface patch-int
  7. type: patch
  8. options: {peer=patch-tun}
  9. Port "gre-2"
  10. Interface "gre-2"
  11. type: gre
  12. options: {in_key=flow, local_ip="10.0.0.100", out_key=flow, remote_ip="10.0.0.101"}

Compute 节点上发往 GRE 隧道的网包最终抵达 Network 节点上的 br-tun,该网桥的规则包括:

  1. # ovs-ofctl dump-flows br-tun
  2. NXST_FLOW reply (xid=0x4):
  3. cookie=0x0, duration=19596.862s, table=0, n_packets=344, n_bytes=66762, idle_age=4, priority=1,in_port=1 actions=resubmit(,1)
  4. cookie=0x0, duration=19537.588s, table=0, n_packets=625, n_bytes=125972, idle_age=4, priority=1,in_port=2 actions=resubmit(,2)
  5. cookie=0x0, duration=19596.602s, table=0, n_packets=2, n_bytes=140, idle_age=19590, priority=0 actions=drop
  6. cookie=0x0, duration=19596.343s, table=1, n_packets=323, n_bytes=65252, idle_age=4, priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)
  7. cookie=0x0, duration=19596.082s, table=1, n_packets=21, n_bytes=1510, idle_age=5027, priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,21)
  8. cookie=0x0, duration=9356.289s, table=2, n_packets=625, n_bytes=125972, idle_age=4, priority=1,tun_id=0x1 actions=mod_vlan_vid:1,resubmit(,10)
  9. cookie=0x0, duration=19595.821s, table=2, n_packets=0, n_bytes=0, idle_age=19595, priority=0 actions=drop
  10. cookie=0x0, duration=19595.554s, table=3, n_packets=0, n_bytes=0, idle_age=19595, priority=0 actions=drop
  11. cookie=0x0, duration=19595.292s, table=10, n_packets=625, n_bytes=125972, idle_age=4, priority=1 actions=learn(table=20,hard_timeout=300,priority=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:NXM_OF_IN_PORT[]),output:1
  12. cookie=0x0, duration=9314.338s, table=20, n_packets=323, n_bytes=65252, hard_timeout=300, idle_age=4, hard_age=3, priority=1,vlan_tci=0x0001/0x0fff,dl_dst=fa:16:3e:cb:11:f6 actions=load:0->NXM_OF_VLAN_TCI[],load:0x1->NXM_NX_TUN_ID[],output:2
  13. cookie=0x0, duration=19595.026s, table=20, n_packets=0, n_bytes=0, idle_age=19595, priority=0 actions=resubmit(,21)
  14. cookie=0x0, duration=9356.592s, table=21, n_packets=9, n_bytes=586, idle_age=5027, priority=1,dl_vlan=1 actions=strip_vlan,set_tunnel:0x1,output:2
  15. cookie=0x0, duration=19594.759s, table=21, n_packets=12, n_bytes=924, idle_age=5057, priority=0 actions=drop

这些规则跟 Compute 节点上 br-tun 的规则相似,完成 tunnel 跟 vlan 之间的转换。

br-int

  1. Bridge br-int
  2. Port "qr-ff19a58b-3d"
  3. tag: 1
  4. Interface "qr-ff19a58b-3d"
  5. type: internal
  6. Port br-int
  7. Interface br-int
  8. type: internal
  9. Port patch-tun
  10. Interface patch-tun
  11. type: patch
  12. options: {peer=patch-int}
  13. Port "tap4385f950-8b"
  14. tag: 1
  15. Interface "tap4385f950-8b"
  16. type: internal

该集成网桥上挂载了很多进程来提供网络服务,包括路由器、DHCP服务器等。这些进程不同的租户可能都需要,彼此的地址空间可能冲突,也可能跟物理网络的地址空间冲突,因此都运行在独立的网络名字空间中。
规则跟computer节点的br-int规则一致,表现为一个正常交换机。

  1. # ovs-ofctl dump-flows br-int
  2. NXST_FLOW reply (xid=0x4):
  3. cookie=0x0, duration=18198.244s, table=0, n_packets=849, n_bytes=164654, idle_age=43, priority=1 actions=NORMAL

网络名字空间

在 Linux 中,网络名字空间可以被认为是隔离的拥有单独网络栈(网卡、路由转发表、iptables)的环境。网络名字空间经常用来隔离网络设备和服务,只有拥有同样网络名字空间的设备,才能看到彼此。
可以用ip netns list命令来查看已经存在的名字空间。

  1. # ip netns
  2. qdhcp-88b1609c-68e0-49ca-a658-f1edff54a264
  3. qrouter-2d214fde-293c-4d64-8062-797f80ae2d8f

qdhcp 开头的名字空间是 dhcp 服务器使用的,qrouter 开头的则是 router 服务使用的。
可以通过 ip netns exec namespaceid command 来在指定的网络名字空间中执行网络命令,例如

  1. # ip netns exec qdhcp-88b1609c-68e0-49ca-a658-f1edff54a264 ip addr
  2. 71: ns-f14c598d-98: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
  3. link/ether fa:16:3e:10:2f:03 brd ff:ff:ff:ff:ff:ff
  4. inet 10.1.0.3/24 brd 10.1.0.255 scope global ns-f14c598d-98
  5. inet6 fe80::f816:3eff:fe10:2f03/64 scope link
  6. valid_lft forever preferred_lft forever

可以看到,dhcp 服务的网络名字空间中只有一个网络接口“ns-f14c598d-98”,它连接到 br-int 的 tapf14c598d-98 接口上。

dhcp 服务

dhcp 服务是通过 dnsmasq 进程(轻量级服务器,可以提供 dns、dhcp、tftp 等服务)来实现的,该进程绑定到 dhcp 名字空间中的 br-int 的接口上。可以查看相关的进程。

  1. # ps -fe | grep 88b1609c-68e0-49ca-a658-f1edff54a264
  2. nobody 23195 1 0 Oct26 ? 00:00:00 dnsmasq --no-hosts --no-resolv --strict-order --bind-interfaces --interface=ns-f14c598d-98 --except-interface=lo --pid-file=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/pid --dhcp-hostsfile=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/host --dhcp-optsfile=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/opts --dhcp-script=/usr/bin/neutron-dhcp-agent-dnsmasq-lease-update --leasefile-ro --dhcp-range=tag0,10.1.0.0,static,120s --conf-file= --domain=openstacklocal
  3. root 23196 23195 0 Oct26 ? 00:00:00 dnsmasq --no-hosts --no-resolv --strict-order --bind-interfaces --interface=ns-f14c598d-98 --except-interface=lo --pid-file=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/pid --dhcp-hostsfile=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/host --dhcp-optsfile=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/opts --dhcp-script=/usr/bin/neutron-dhcp-agent-dnsmasq-lease-update --leasefile-ro --dhcp-range=tag0,10.1.0.0,static,120s --conf-file= --domain=openstacklocal

router服务

首先,要理解什么是 router,router 是提供跨 subnet 的互联功能的。比如用户的内部网络中主机想要访问外部互联网的地址,就需要 router 来转发(因此,所有跟外部网络的流量都必须经过 router)。目前 router 的实现是通过 iptables 进行的。
同样的,router 服务也运行在自己的名字空间中,可以通过如下命令查看:

  1. # ip netns exec qrouter-2d214fde-293c-4d64-8062-797f80ae2d8f ip addr
  2. 66: qg-d48b49e0-aa: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
  3. link/ether fa:16:3e:5c:a2:ac brd ff:ff:ff:ff:ff:ff
  4. inet 172.24.4.227/28 brd 172.24.4.239 scope global qg-d48b49e0-aa
  5. inet 172.24.4.228/32 brd 172.24.4.228 scope global qg-d48b49e0-aa
  6. inet6 fe80::f816:3eff:fe5c:a2ac/64 scope link
  7. valid_lft forever preferred_lft forever
  8. 68: qr-c2d7dd02-56: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
  9. link/ether fa:16:3e:ea:64:6e brd ff:ff:ff:ff:ff:ff
  10. inet 10.1.0.1/24 brd 10.1.0.255 scope global qr-c2d7dd02-56
  11. inet6 fe80::f816:3eff:feea:646e/64 scope link
  12. valid_lft forever preferred_lft forever

可以看出,该名字空间中包括两个网络接口。

第一个接口 qg-d48b49e0-aa(即K)是外部接口(qg=q gateway),将路由器的网关指向默认网关(通过 router-gateway-set 命令指定),这个接口连接到 br-ex 上的tapd48b49e0-aa(即L)。

第二个接口 qr-c2d7dd02-56(即 N,qr=q bridge)跟 br-int 上的 tapc2d7dd02-56 口(即 M)相连,将 router 进程连接到集成网桥上。

查看该名字空间中的路由表:

  1. # ip netns exec qrouter-2d214fde-293c-4d64-8062-797f80ae2d8f ip route
  2. 172.24.4.224/28 dev qg-d48b49e0-aa proto kernel scope link src 172.24.4.227
  3. 10.1.0.0/24 dev qr-c2d7dd02-56 proto kernel scope link src 10.1.0.1
  4. default via 172.24.4.225 dev qg-d48b49e0-aa

其中,第一条规则是将到 172.24.4.224/28 段的访问都从网卡 qg-d48b49e0-aa(即 K)发出。

第二条规则是将到 10.1.0.0/24 段的访问都从网卡 qr-c2d7dd02-56(即 N)发出。
最后一条是默认路由,所有的通过 qg-d48b49e0-aa 网卡(即 K)发出。
floating ip 服务同样在路由器名字空间中实现,例如如果绑定了外部的 floating ip 172.24.4.228 到某个虚拟机 10.1.0.2,则 nat 表中规则为:

  1. # ip netns exec qrouter-2d214fde-293c-4d64-8062-797f80ae2d8f iptables -t nat -S
  2. -P PREROUTING ACCEPT
  3. -P POSTROUTING ACCEPT
  4. -P OUTPUT ACCEPT
  5. -N neutron-l3-agent-OUTPUT
  6. -N neutron-l3-agent-POSTROUTING
  7. -N neutron-l3-agent-PREROUTING
  8. -N neutron-l3-agent-float-snat
  9. -N neutron-l3-agent-snat
  10. -N neutron-postrouting-bottom
  11. -A PREROUTING -j neutron-l3-agent-PREROUTING
  12. -A POSTROUTING -j neutron-l3-agent-POSTROUTING
  13. -A POSTROUTING -j neutron-postrouting-bottom
  14. -A OUTPUT -j neutron-l3-agent-OUTPUT
  15. -A neutron-l3-agent-OUTPUT -d 172.24.4.228/32 -j DNAT --to-destination 10.1.0.2
  16. -A neutron-l3-agent-POSTROUTING ! -i qg-d48b49e0-aa ! -o qg-d48b49e0-aa -m conntrack ! --ctstate DNAT -j ACCEPT
  17. -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697
  18. -A neutron-l3-agent-PREROUTING -d 172.24.4.228/32 -j DNAT --to-destination 10.1.0.2
  19. -A neutron-l3-agent-float-snat -s 10.1.0.2/32 -j SNAT --to-source 172.24.4.228
  20. -A neutron-l3-agent-snat -j neutron-l3-agent-float-snat
  21. -A neutron-l3-agent-snat -s 10.1.0.0/24 -j SNAT --to-source 172.24.4.227
  22. -A neutron-postrouting-bottom -j neutron-l3-agent-snat

其中 SNAT 和 DNAT 规则完成外部 floating ip 到内部 ip 的映射:

  1. -A neutron-l3-agent-OUTPUT -d 172.24.4.228/32 -j DNAT --to-destination 10.1.0.2
  2. -A neutron-l3-agent-PREROUTING -d 172.24.4.228/32 -j DNAT --to-destination 10.1.0.2
  3. -A neutron-l3-agent-float-snat -s 10.1.0.2/32 -j SNAT --to-source 172.24.4.228

另外有一条 SNAT 规则把所有其他的内部IP出来的流量都映射到外部IP 172.24.4.227。这样即使在内部虚拟机没有外部IP的情况下,也可以发起对外网的访问。

  1. -A neutron-l3-agent-snat -s 10.1.0.0/24 -j SNAT --to-source 172.24.4.227

br-ex

  1. Bridge br-ex
  2. Port "eth1"
  3. Interface "eth1"
  4. Port br-ex
  5. Interface br-ex
  6. type: internal
  7. Port "qg-1c3627de-1b"
  8. Interface "qg-1c3627de-1b"
  9. type: internal

br-ex 上直接连接到外部物理网络,一般情况下网关在物理网络中已经存在,则直接转发即可。

  1. # ovs-ofctl dump-flows br-ex
  2. NXST_FLOW reply (xid=0x4):
  3. cookie=0x0, duration=23431.091s, table=0, n_packets=893539, n_bytes=504805376, idle_age=0, priority=0 actions=NORMAL

如果对外部网络的网关地址配置到了 br-ex(即br-ex作为一个网关):

  1. # ip addr add 172.24.4.225/28 dev br-ex

需要将内部虚拟机发出的流量进行 SNAT,之后发出。

  1. # iptables -A FORWARD -d 172.24.4.224/28 -j ACCEPT
  2. # iptables -A FORWARD -s 172.24.4.224/28 -j ACCEPT
  3. # iptables -t nat -I POSTROUTING 1 -s 172.24.4.224/28 -j MASQUERADE