标签:
学习 Neutron 系列文章:
(2)Neutron OpenvSwitch + VLAN 虚拟网络
(3)Neutron OpenvSwitch + GRE/VxLAN 虚拟网络
(4)Neutron OVS OpenFlow 流表 和 L2 Population
Neutron 对虚拟三层网络的实现是通过其 L3 Agent (neutron-l3-agent)。该 Agent 利用 Linux IP 栈、route 和 iptables 来实现内网内不同网络内的虚机之间的网络流量,以及虚机和外网之间网络流量的路由和转发。为了在同一个Linux 系统上支持可能的 IP 地址空间重叠,它使用了 Linux network namespace 来提供隔离的转发上下文。
在二层网络上,VLAN 可以将一个物理交换机分割成几个独立的虚拟交换机。类似地,在三层网络上,Linux network namespace(netns) 可以将一个物理三层网络分割成几个独立的虚拟三层网络。
Network namespace (netns)从 Linux 2.6.24 版本开始添加,直到 2.6.29 添加完成。每个 netns 拥有独立的 (virtual)network devices, IP addresses, IP routing tables, /proc/net directory, ports 等等。新创建的 netns 默认只包含 loopback device。除了这个设备,每个 network device,不管是物理的还是虚拟的网卡还是网桥等,都只能存在于一个 netns。而且,连接物理硬件的物理设备只能存在于 root netns。其它普通的网络设备可以被创建和添加到某个 netns。
使用 ip 命令来操作 netns。
#添加 network namespace
ip netnas add <network namespace name>
#Example:
ip netns add nstest
#列表所有 netns
ip netns list
#删除某 netns
ip netns delete <network namespace name>
#在 network namespace 中运行命令
ip netns exec <network namespace name> <command>
#Example using the namespace from above:
ip netns exec nstest ip addr
#添加 virtual interfaces 到 network namespace
ip link add veth-a type veth peer name veth-b #创建一对虚拟网卡veth-a 和 veth-b,两者由一根虚拟网线连接
#将 veth-b 添加到 network namespace
ip link set veth-b netns nstest
#设置 VI 的 IP 地址
#defaut 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
#互通
# ping 10.1.1.1 PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data. 64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.087 ms # ip netns exec netns1 ping 10.1.1.2 PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data. 64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.054 ms
#查看路由表和 iptbales
# ip netns exec netns1 route # ip netns exec netns1 iptables -L
(1)一种简单的方式是使用 Linux veth pair 来实现两个 network namespace 之间的通信:
(2)当有两个以上的 network namespace 之间需要通信时,需要使用一个虚机交换机,和两个 veth pair。传统的方式是 Linux bridge:
你也可以使用 Open vSwitch:
(3)再一种方式是使用 Open vSwitch 和 OVS internal ports:
(来源,可见详细的配置命令。)
veth (irtual Ethernet interfaces) 设备:这是一种成对出现的特殊网络设备,它们象一根管道一样连接在一起。VETH 设备总是成对出现,送到一端请求发送的数据总是从另一端以请求接受的形式出现。该设备不能被用户程序直接操作,但使用起来比较简单。创建并配置正确后,向其一端输入数据,VETH 会改变数据的方向并将其送入内核网络核心,完成数据的注入。在另一端能读到此数据。
关于几种方式的性能比较,这篇文章也给出了它的测试结论:
在 Neutron 中,可以使用配置项 ovs_use_veth 来配置是否使用 veth,默认为 false,表示默认使用 OVS internal port。
netfilter/iptables(简称为iptables)组成 Linux 平台下的包过滤防火墙。其中,iptables只是 Linux 防火墙的管理工具,位于/sbin/iptables。真正实现防火墙功能的是netfilter,它是Linux内核中实现包过滤的内部结构。
iptables 是一个 CLI 类型的 Linux 用户空间工具,它使得系统管理员能够配置 Linux kenerl firewall 的表(tables)、链(chains)和规则(rules)。Linux 使用不同的内核模块和应用来管理不同的网络协议iptable 适用于 ipv4,ip6tables 适用于 ipv6,arptables 适用于 ARP,ebtables 适用于网络帧。iptales 需要管理员权限。当要在你的机器上建立一个连接时,iptables 查询是否满足它已配置的规则。如果不存在配置的规则,那么转到默认的行为。
规则(rules)其实就是网络管理员预定义的条件,规则一般的定义为“如果数据包头符合这样的条件,就这样处理这个数据包”。规则存储在内核空间的信息包过滤表中,这些规则分别指定了源地址、目的地址、传输协议(如TCP、UDP、ICMP)和服务类型(如HTTP、FTP和SMTP)等。当数据包与规则匹配时,iptables就根据规则所定义的方法来处理这些数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。配置防火墙的主要工作就是添加、修改和删除这些规则。
操作 iptables 服务:
# /etc/init.d/iptables start/stop/restart
iptables 中rule 的组织:iptables -> Tables -> Chains -> Rules
命令(-A,-D 等):
(来源)
iptables [-t table] {-A|-C|-D} chain rule-specification #A - 添加 add,C - 检查 check,D - 删除 delete iptables [-t table] -I chain [rulenum] rule-specification # I - 插入 insert iptables [-t table] -R chain rulenum rule-specification # R - 替换 replace iptables [-t table] -D chain rulenum # D - 删除 delete iptables [-t table] -S [chain [rulenum]] # S - list iptables [-t table] {-F|-L|-Z} [chain [rulenum]] [options...] iptables [-t table] -N chain # N - 创建一个新的chain iptables [-t table] -X [chain] #X - 删除一个 chain iptables [-t table] -P chain target # P - 设置 target 的 policy iptables [-t table] -E old-chain-name new-chain-name # E - rename
参数判断(-p,-s 等):
(来源)
处理结果(-j):
当数据包进入后,会依次比照 iptables 中的每条规则,直到有一条规则可以对该报文进行匹配,这时该报文将被执行"ACCEPT","DORP","REJECT" 或者其它动作,除 REDIRECT 外,执行完后停止跟余下的 iptables 规则匹配。
表(-t):
表 | 表功能 | 链 | 链功能 |
---|---|---|---|
Filter | 包过滤 |
FORWARD |
过滤发往其它服务器的包(Filters packets to servers accessible by another NIC on the firewall) |
INPUT |
过滤发往防火墙的包 (Filters packets destined to the firewall) | ||
OUTPUT |
过滤离开防火墙的包 (Filters packets originating from the firewall) | ||
Nat | 网络地址转换 |
PREROUTING |
在路由前做地址转换,使得目的地址能够匹配上防火墙的路由表,常用于转换目的地址。 |
POSTROUTING |
在路由后做地址转换。这意味着不需要在路由前修改目的地址。常用语转换源地址。 | ||
OUTPUT |
对防火墙产生的包做地址转换(很少量地用于 SOHO 环境中) |
||
Mangle | TCP 头修改 |
PREROUTING POSTROUTING OUTPUT INPUT FORWARD |
在路由器修改 TCP 包的 QoS(很少量地用在 SOHO 环境中) |
连接处理过程:
例子:
NAT 包括 SNAT (源地址转换)和 DNAT (目的地址转换)。两者的区别在于做地址转换是在路由前还是路由后:
(1)SNAT:路由 - 转换 - 发出
数据经过时, 源地址发生改变,目的地址不变。SNAT 的具体数据流向:
从这里可以看出,SNAT转换的步骤在 POSTROUTING 链上实现, PREROUTING 只是用来做路由选择。因此,要做 SNAT 的话,需要添加 POSTROUTING 规则,使用 “-j SNAT -to-source”。比如:
iptables -t nat -A POSTROUTING -s 192.168.252.0/24 -j SNAT -to-source 100.100.100.1
(2)DNAT:转换 - 路由- 发出
DNAT 的功能正好和 SNAT 相反,源地址不变,目的地址发生改变。DNAT 可以用作 PNAT,可以将一个 IP 的端口转换成另一个IP的另外一个端口号,经常用于内网服务器映射到公网,用来隐藏服务器的真实地址。DNAT 的具体数据流向:
iptables -t nat -A PREROUTING -d 100.100.100.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.252.1
有一类比较特殊的 DNAT 是使用 “-j REDIRECT” 做端口号转换:
## Send incoming port-80 web traffic to our squid (transparent) proxy # iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80-j REDIRECT --to-port 3128
关于 SNAT 和 DNAT 的更多解释可以参考 这里 和 这里。
Linux 系统的 route 命令用于显示和操作 IP 路由表,它的主要作用是创建一个静态路由来指定一个主机或者一个网络通过一个网络接口,如eth0。
route [-CFvnee] route [-v] [-A family] add [-net|-host] target [netmask Nm] [gw Gw] [metric N] [mss M] [window W] [irtt I] [reject] [mod] [dyn] [rein- state] [[dev] If] route [-v] [-A family] del [-net|-host] target [gw Gw] [netmask Nm] [metric N] [[dev] If]
例子:
这个命令比较简单,可以参考 这个。
42: qg-3c8d6a68-97: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default link/ether fa:16:3e:2e:5b:23 brd ff:ff:ff:ff:ff:ff inet 192.168.1.110/24 brd 192.168.1.255 scope global qg-3c8d6a68-97 valid_lft forever preferred_lft forever inet 192.168.1.104/32 brd 192.168.1.104 scope global qg-3c8d6a68-97 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe2e:5b23/64 scope link valid_lft forever preferred_lft forever
<BROADCAST,UP,LOWER_UP>:端口的各种状态
inet/brd/scope:IP 地址及子网掩码,广播地址,作用域
scope:
注意到这个interface有两个静态 IP 地址。第一个是主要的(primary)IP,第二个是辅助的( secondary) 的 IP。当一个网卡配置了静态IP后,你可以添加secondary IP 给它。这样它就拥有了多个 IP 地址了。Secondary IP 不可以通过 DHCP 分配。它所有的IP 地址都关联到它唯一的一个 MAC 地址上。那为什么需要 secondary IP 地址呢? 路由器有个 Secondary IP 的概念,这个特性可以创建逻辑子网,也就是说在一个物理网口上连接两个子网,比如这个网口接到一台交换机上,如 果这个网口没有配置Secondary IP的话,那么这台交换机只能连接一个网段的主机,比如 192.168.1.1/24,但是,如果它配置了Secondary IP,那么就可以连接两个网段的主机,比如 192.168.1.1/24 和 10.0.0.1/24。更详细的解释可以看这里 和 这里。
命令:
#增加 secondary IP
ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 ip a add dev qg-3c8d6a68-97 192.168.1.105/32 brd 192.168.1.105
#删除 secondar IP
ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 ip addr del 192.168.1.104/32 dev qg-3c8d6a68-97
每个 L3 Agent 运行在一个 network namespace 中,每个 namespace 由 qrouter-<router-UUID>命名,比如 qrouter-e506f8fe-3260-4880-bd06-32246225aeae。网络节点如果不支持 Linux namespace 的话,只能运行一个 Virtual Router。也可以通过设置配置项 use_namespaces = True/False 来使用或者不使用 namespace。
Neutron L3 Agent 负责路由(routing)、浮动 IP 分配(floatingip allocation), 地址转换(SNAT/DNAT)和 Security Group 管理(Blueprint 在这里。在后面的文章中打算和 Nova 中的 Security Group 一起分析)。
一个 Virtual Router 连接几个 subnet 就会有几个 virtual interface。每个 interface 的地址是该 subnet 的 gateway 地址。比如:
root@network:/home/s1# ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 ip addr
33: qr-2aa928c9-e8: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default #IP 设为它连接的子网的 Gateway IP
link/ether fa:16:3e:90:e5:50 brd ff:ff:ff:ff:ff:ff
inet 91.1.180.1/24 brd 91.1.180.255 scope global qr-2aa928c9-e8
37: qr-a5c6ed86-c1: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether fa:16:3e:87:40:f3 brd ff:ff:ff:ff:ff:ff
inet 81.1.180.1/24 brd 81.1.180.255 scope global qr-a5c6ed86-c1
48: qg-3c8d6a68-97: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether fa:16:3e:2e:5b:23 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.110/24 brd 192.168.1.255 scope global qg-3c8d6a68-97
L3 Agent 在启动时设置如下的路由规则:
root@network:/home/s1# ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 qg-3c8d6a68-97
81.1.180.0 0.0.0.0 255.255.255.0 U 0 0 0 qr-a5c6ed86-c1 #到哪个网段的traffic发到相应的 interface
91.1.180.0 0.0.0.0 255.255.255.0 U 0 0 0 qr-2aa928c9-e8
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 qg-3c8d6a68-97
虚机的 IP 栈在发现数据包的目的虚机的 IP 地址不在自己网段的话,会将其发到 Router 上对应其 subnet 的 Virtual Interface。然后,Virtual Router 根据配置的路由规则和目的IP地址,将包转发到目的端口发出。
在没有设置浮动 IP 时,当主机访问外网时,需要将主机的固定 IP 转换成外网网段的 gateway 的 IP 地址,以免暴露内部 IP 地址。其做法是 Neutron 在 iptables 表中增加了 POSTROUTING 链。
root@network:/home/s1# ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N neutron-l3-agent-OUTPUT #Neutorn 增加的 chain
-N neutron-l3-agent-POSTROUTING #Neutorn 增加的 SNAT chain
-N neutron-l3-agent-PREROUTING
-N neutron-l3-agent-float-snat #Neutorn 增加的 SNAT chain
-N neutron-l3-agent-snat #Neutorn 增加的 SNAT chain
-N neutron-postrouting-bottom #Neutorn 增加的 SNAT chain
-A PREROUTING -j neutron-l3-agent-PREROUTING
-A OUTPUT -j neutron-l3-agent-OUTPUT
-A POSTROUTING -j neutron-l3-agent-POSTROUTING #(1)将 SNAT chain 转到自定义的 neutron-l3-agent-POSTROUTING
-A POSTROUTING -j neutron-postrouting-bottom #(3)将 SNAT chain 转到自定义的 neutron-postrouting-bottom
-A neutron-l3-agent-POSTROUTING ! -i qg-3c8d6a68-97 ! -o qg-3c8d6a68-97 -m conntrack ! --ctstate DNAT -j ACCEPT #(2)如果出口或者入口不是 qg-3c8d6a68-97 并且状态不是 DNAT 的都接受
-A neutron-l3-agent-snat -j neutron-l3-agent-float-snat
-A neutron-l3-agent-snat -s 91.1.180.0/24 -j SNAT --to-source 192.168.1.110 #(5)将 91.1.180.0/24 网段的包的目的 IP 转为 192.168.1.110
-A neutron-l3-agent-snat -s 81.1.180.0/24 -j SNAT --to-source 192.168.1.110 #(5)将 91.1.180.0/24 网段的包的目的 IP 转为 192.168.1.110
-A neutron-postrouting-bottom -j neutron-l3-agent-snat #(4)再转到 neutron-l3-agent-snat
而且 route 的外网 gateway interface 上增加了浮动 IP 作为 辅助 IP:
42: qg-3c8d6a68-97: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default link/ether fa:16:3e:2e:5b:23 brd ff:ff:ff:ff:ff:ff inet 192.168.1.110/24 brd 192.168.1.255 scope global qg-3c8d6a68-97 valid_lft forever preferred_lft forever inet 192.168.1.104/32 brd 192.168.1.104 scope global qg-3c8d6a68-97 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe2e:5b23/64 scope link valid_lft forever preferred_lft forever
1. 在 router 的连接 81.1.180.12 网段 interface 上:
root@network:/home/s1# ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 tcpdump -envi qr-a5c6ed86-c1 -vvv tcpdump: listening on qr-a5c6ed86-c1, link-type EN10MB (Ethernet), capture size 65535 bytes ^C17:42:48.904820 fa:16:3e:2b:3e:2a > fa:16:3e:87:40:f3, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 28892, offset 0, flags [DF], proto ICMP (1), length 84) 81.1.180.12 > 192.168.1.15: ICMP echo request, id 32769, seq 0, length 64 17:42:48.906601 fa:16:3e:87:40:f3 > fa:16:3e:2b:3e:2a, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 24799, offset 0, flags [none], proto ICMP (1), length 84) 192.168.1.15 > 81.1.180.12: ICMP echo reply, id 32769, seq 0, length 64 17:42:49.906238 fa:16:3e:2b:3e:2a > fa:16:3e:87:40:f3, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 28893, offset 0, flags [DF], proto ICMP (1), length 84)
2. 在 route 的连接 192.168.1.15 网段 interface 上
root@network:/home/s1# ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 tcpdump -envi qg-3c8d6a68-97 -vvv tcpdump: listening on qg-3c8d6a68-97, link-type EN10MB (Ethernet), capture size 65535 bytes ^C17:44:47.661916 fa:16:3e:2e:5b:23 > 08:00:27:c7:cf:ca, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 28896, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.1.110 > 192.168.1.15: ICMP echo request, id 33281, seq 0, length 64 17:44:47.663300 08:00:27:c7:cf:ca > fa:16:3e:2e:5b:23, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 36308, offset 0, flags [none], proto ICMP (1), length 84) 192.168.1.15 > 192.168.1.110: ICMP echo reply, id 33281, seq 0, length 64
可见在外网网段的 interface 收到数据包之前,SRC IP 已经被替换成了外网网段的 Gateway IP 了。
要使外网内的机器能访问虚机,需要设置虚机的浮动IP。浮动 IP 在 Virtual Router 连接的 external network 的 subnet 内分配。注意浮动 IP 只有在 Virtual Router 上配置了 External network subnet gateway 才有意义。
创建浮动IP:
root@sun:~# neutron floatingip-create Extnet Created a new floatingip: +---------------------+--------------------------------------+ | Field | Value | +---------------------+--------------------------------------+ | fixed_ip_address | | | floating_ip_address | 10.8.127.11 | | floating_network_id | 9c9436d4-2b7c-4787-8535-9835e6d9ac8e | | id | 7b4cee72-ffcd-4484-a5d8-371b23bb3cc3 |
关联到一个 port:
root@sun:~# neutron port-list | grep 192.168.10.26
| d74c703e-824a-41b1-b4b3-3cd4edfa22b3 | | fa:16:3e:14:ff:6d | {"subnet_id": "ccc80588-2b0d-459b-82e9-972ff4291b79", "ip_address": "192.168.10.26"} |
root@sun:~# neutron floatingip-associate 7b4cee72-ffcd-4484-a5d8-371b23bb3cc3 d74c703e-824a-41b1-b4b3-3cd4edfa22b3
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| fixed_ip_address | 192.168.10.26 |
| floating_ip_address | 10.8.127.11 |
每个浮动 IP 唯一对应一个 Router:浮动IP -> 关联的 Port -> 所在的 Subnet -> 包含该 subnet 以及 external subnet 的 Router。创建浮动 IP 时,在 Neutron 完成数据库操作来分配浮动IP后,它通过 RPC 来通知该浮动IP对应的 router 去设置该浮动IP对应的 iptables 规则。上面的例子中,固定IP 为 ‘192.168.10.26’ 的虚机可以在外网中使用浮动 IP ‘10.8.127.11’ 来访问了。
外网访问虚机时,目的 IP 地址为虚机的浮动 IP 地址,因此,必须由 iptables 将其转化为固定 IP 地址,然后再将它路由到虚机。我们需要关注的是 iptables 的 nat 表的 PREOUTING chain:
root@network:/home/s1# ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 iptables -t nat -S -P PREROUTING ACCEPT -P INPUT ACCEPT -P OUTPUT ACCEPT -P POSTROUTING ACCEPT -N neutron-l3-agent-OUTPUT -N neutron-l3-agent-PREROUTING #neutron 增加的 DNAT chain -A PREROUTING -j neutron-l3-agent-PREROUTING # DNAT 由 neutron 新增的 chain 负责处理 -A OUTPUT -j neutron-l3-agent-OUTPUT -A neutron-l3-agent-OUTPUT -d 192.168.1.104/32 -j DNAT --to-destination #本机访问浮动IP 修改为固定 IP
-A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697 #将虚机访问 metadata server 的 traffic 端口由 80 改到 9697(由配置项 metadata_port 设置,默认为 9697),那里有 application 在监听。具体内容很深,可以参考这篇文章。
-A neutron-l3-agent-PREROUTING -d 192.168.1.104/32 -j DNAT --to-destination 91.1.180.14 #到浮动IP的traffic的目的IP 换成虚机的固定 IP
每个浮动 IP,增加三个规则:
-A neutron-l3-agent-PREROUTING -d <floatingip> -j DNAT --to-destination <fixedip> #从本机访问虚机,Dst IP 由浮动IP该为访问固定IP -A neutron-l3-agent-OUTPUT -d <floatingip> -j DNAT --to <fixedip> #从别的机器上访问虚机,DST IP 由浮动IP改为固定IP -A neutron-l3-agent-float-snat -s <fixedip> -j SNAT --to <floatingip> #虚机访问外网,将Src IP 由固定IP改为浮动IP
这里可以看到当设置了浮动 IP 以后,SNAT 不在使用 External Gateway 的 IP 了,而是使用浮动 IP 。虽然 entires 依然存在,但是因为 neutron-l3-agent-float-snat 比 neutron-l3-agent-snat 靠前而得到执行。
-A neutron-l3-agent-float-snat -s 91.1.180.14/32 -j SNAT --to-source 192.168.1.104 -A neutron-l3-agent-snat -j neutron-l3-agent-float-snat -A neutron-l3-agent-snat -s 91.1.180.0/24 -j SNAT --to-source 192.168.1.110 -A neutron-l3-agent-snat -s 81.1.180.0/24 -j SNAT --to-source 192.168.1.110 -A neutron-postrouting-bottom -j neutron-l3-agent-snat
1. 在route 的连接外网网段的interace 上:
17:58:46.116944 08:00:27:c7:cf:ca > fa:16:3e:2e:5b:23, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 25176, offset 0, flags [DF], proto ICMP (1), length 84)
192.168.1.15 > 192.168.1.104: ICMP echo request, id 24530, seq 4, length 64
17:58:46.117910 fa:16:3e:2e:5b:23 > 08:00:27:c7:cf:ca, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 23128, offset 0, flags [none], proto ICMP (1), length 84)
192.168.1.104 > 192.168.1.15: ICMP echo reply, id 24530, seq 4, length 64
2. 在 router 的连接内网网段的interface上:
root@network:/home/s1# ip netns exec qrouter-e438bebe-6795-4b68-a613-ec0df38d3064 tcpdump -envi qr-2aa928c9-e8 -vvv
tcpdump: listening on qr-2aa928c9-e8, link-type EN10MB (Ethernet), capture size 65535 bytes
^C19:46:12.266739 fa:16:3e:90:e5:50 > fa:16:3e:f3:1e:c0, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 53299, offset 0, flags [DF], proto ICMP (1), length 84)
192.168.1.15 > 91.1.180.14: ICMP echo request, id 2831, seq 1, length 64
19:46:12.269143 fa:16:3e:f3:1e:c0 > fa:16:3e:90:e5:50, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 23157, offset 0, flags [none], proto ICMP (1), length 84)
91.1.180.14 > 192.168.1.15: ICMP echo reply, id 2831, seq 1, length 64
该实验中使用 “ iptables -t nat -L -nv” 命令来查看每个链上匹配到的数据包数目。
可见:
(1)DNAT 匹配到的是默认的 Policy
(2)SNAT 匹配到 “-A neutron-l3-agent-POSTROUTING ! -i qg-3c8d6a68-97 ! -o qg-3c8d6a68-97 -m conntrack ! --ctstate DNAT -j ACCEPT” 规则后就被 Accept 了。
可见:
(1)DNAT 匹配到的是默认的 Policy ACCEPT
(2)SNAT 匹配到 “-A neutron-l3-agent-float-snat -s 91.1.180.14/32 -j SNAT --to-source 192.168.1.104” 规则后做 SNAT。
可见:
(1)DNAT 匹配到 “-A neutron-l3-agent-PREROUTING -d 192.168.1.104/32 -j DNAT --to-destination 91.1.180.14” 然后做 DNAT。
(2)SNAT 匹配到的是默认的 Policy ACCEPT。
为什么结果中显示的 pacakge 数目只是1呢?参考网上文章,对于 SNAT 和 DNAT target 来说,如果一个包被匹配了,那么和它属于同一个流的所有的包都会被自动转换,然后就可以被路由到正确的主机或网络,这么说来,一个流中被匹配的包的数目就是1了。
总结:
(图片来源。Neutron 代码分析也可以参考这篇文章。)
L3 Agent 启动后,它有若干个 Workers 去 MQ 中拿数据,然后将数据放进一个内部的 queue 中。它还会启动一个循环线程去queue 中取数据。当发现有 router 相关的操作发生后,即调用 _process_routers_loop 方法去处理获取的数据。
L3 Agent 的核心是 Router 的处理。
(1)处理 external gateway (比如,external_gateway_added 增加 external gateway:获取该 router 的所有浮动 IP,在agent_conf.external_network_bridge 所指定的外网物理 OVS bridge 上增加一个 tap 设备,名称为 “gq-*”,然后设置其 MAC 地址,MTU 等)
(2)修改路由表 (routes_updated)
(3)在有 external gateway 时,设置 SNAT iptables (_handle_router_snat_rules):先删除当前所有 POSTROUTING 和 snat chains,然后再增加:
#增加 SNAT chain
-N neutron-l3-agent-float-snat
#为 external gateway
-A neutron-l3-agent-POSTROUTING ! -i qg-3c8d6a68-97 ! -o qg-3c8d6a68-97 -m conntrack ! --ctstate DNAT -j ACCEPT
#为每一个子网创建一条 SNAT 规则 -A neutron-l3-agent-snat -s 91.1.180.0/24 -j SNAT --to-source 192.168.1.110 #(5)将 91.1.180.0/24 网段的包的目的 IP 转为 192.168.1.110 -A neutron-l3-agent-snat -s 81.1.180.0/24 -j SNAT --to-source 192.168.1.110 #(5)将 91.1.180.0/24 网段的包的目的 IP 转为 192.168.1.110
(4)如果有 external gateway 的话,处理浮动 IP 的 SNAT/DNAT iptables (process_snat_dnat_for_fip)
#为每一个浮动 IP,以 192.168.1.104 为例 -A neutron-l3-agent-PREROUTING -d 192.168.1.104/32 -j DNAT --to-destination 91.1.180.14 #DNAT -A neutron-l3-agent-OUTPUT -d 192.168.1.104/32 -j DNAT --to-destination 91.1.180.14 #本机访问 -A neutron-l3-agent-float-snat -s 91.1.180.14/32 -j SNAT --to-source 192.168.1.104 #SNAT
(5)将浮动IP 配置到 external gateway port (process_floating_ip_addresses -> add_floating_ip)
42: qg-3c8d6a68-97: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether fa:16:3e:2e:5b:23 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.110/24 brd 192.168.1.255 scope global qg-3c8d6a68-97
valid_lft forever preferred_lft forever
inet 192.168.1.104/32 brd 192.168.1.104 scope global qg-3c8d6a68-97
valid_lft forever preferred_lft forever
看起来,Neutron 使用 Secondary address 应该不是用于连接不同的子网,因为这些 IP 是同一个网段的。参考别的文章,它的作用应该是“用于NAT,转换后地址并非路由器直连地址(利用secondary address 为转换后地址)”。但是,把该 IP 删除后,网络之间的访问并没有受到影响,因此它的作用还待进一步的研究。
在创建、绑定、去绑定或者删除浮动IP时,neutron server 首先执行 DB 操作,然后调用 RPC (notify_routers_updated) 去通知指定的 Router:”create_floatingip“,”update_floatingip“,”delete_floatingip“ 等。
Neutron 理解 (6): Neutron 是怎么实现虚拟三层网络的 [How Neutron implements virtual L3 network]
标签:
原文地址:http://www.cnblogs.com/sammyliu/p/4636091.html