neutron/agent/l3/dvr_router_base.py
实现了对 fip- namespace 相关的操作
def __init__(self, agent, host, *args, **kwargs):
super(DvrRouterBase, self).__init__(*args, **kwargs)
self.agent = agent
self.host = host
self.snat_ports = None
def process(self, agent):
super(DvrRouterBase, self).process(agent)
# NOTE: Keep a copy of the interfaces around for when they are removed
self.snat_ports = self.get_snat_interfaces()
新增了 get_snat_interfaces
的调用
def get_snat_interfaces(self):
return self.router.get(l3_constants.SNAT_ROUTER_INTF_KEY, [])
查找 int_port 中是否是一个 snat_port。
- 若 snat_port 为空,则调用
get_snat_interfaces
获取当前 router 上的 snat port - 对比 snat_port 的 subnet 和 int_port 的 subnet,若一致,则认为该 snat_port 是为该 subnet 提供 snat 服务的 port。
def __init__(self, agent, host, *args, **kwargs):
super(DvrLocalRouter, self).__init__(agent, host, *args, **kwargs)
self.floating_ips_dict = {}
# Linklocal subnet for router and floating IP namespace link
self.rtr_fip_subnet = None
self.dist_fip_count = None
self.fip_ns = None
self._pending_arp_set = set()
- 调用
get_ex_gw_port
获取 router 的 gateway port - 调用
AgentMixin.get_fip_ns
构造一个 fip- namespace - 调用
RouterInfo.process
继续处理
- 调用
RouterInfo.get_floating_ips
获取 router 数据中的_floatingips
记录 - 在这些 floating ip 中过滤出 host 或者 dest_host 为当前 host 的 floating ip
重写了 RouterInfo
的方法
- 调用
fip_ns.get_rtr_ext_device_name
获取 rfp- 设备的名称 - 根据 rfp- 设备的名称,生成如下规则:
-A neutron-l3-agent-PREROUTING -d 172.16.100.245/32 -i rfp-61eaacf9-d -j DNAT --to-destination 192.168.100.5
-A neutron-l3-agent-float-snat -s 192.168.100.5/32 -j SNAT --to-source 172.16.100.245
- 调用
fip_ns.get_rtr_ext_device_name
获取 rfp- 设备的名称 - 为 floating ip 和 fixed ip 设定 mark
- 调用
_add_floating_ip_rule
为该 floating ip 增加一个 rule 规则 - 调用
fip_ns.get_int_device_name
获取 fpr- 设备名称 - 调用
fip_ns.get_name
获取 fip- namespace 的名称 - 调用
fip_ns.local_subnets.allocate
为当前的 router 分配一个 local subnet,该 subnet 会用到 rfp- 和 fpr- 设备上 - 调用
rtr_fip_subnet.get_pair
从上面的 local subnet 中分配一对地址 - 调用
IPDevice
描述 fpr- 设备 - 为 fpr- 设备增加 route
- 调用
fip_ns.get_ext_device_name
获取 fg- 设备(agent gateway port)名称 - 调用
ip_lib.send_ip_addr_adv_notif
发送 arp 通知消息,告诉大家 agent gateway port 占有该 floating ip - 更新
dist_fip_count
记录
- 调用
fip_ns.allocate_rule_priority
为该 floating ip 分配一个 rule 优先级 - 在 qrouter- namespace 中增加一条 rule 规则:
57483: from 192.168.100.5 lookup 16
删除关于该 floating ip 的 rule,回收 rule priority
- 调用
fip_ns.get_rtr_ext_device_name
获取 rfp- 设备名称 - 调用
fip_ns.get_int_device_name
获取 fpr- 设备名称 - 调用
rtr_fip_subnet.get_pair
获取该 router 上的 local subnet address pair - 调用
fip_ns.get_name
获取 fip- namespace name - 调用
_remove_floating_ip_rule
删除该 floating ip 的 rule - 调用
IPDevice
描述 fpr- 设备 - 删除 floating ip 的 route 记录
dist_fip_count
减一,若dist_fip_count
为0(即当前的 router 中已经没有 floating ip 的存在),则:- 调用
fip_ns.get_ext_device_name
获取 fg- 设备的名称 - 调用
IPDevice
描述 fg- 设备,若该设备存在,则: - 调用
_get_snat_idx
生成一个 ip route table 号 - 清除该 ip route table 内的 route 记录
- 删除该 ip route table
- 回收为该 route 分配的 local subnet
- 删除 fpr- 和 rfp- veth 设备
根据一个 ip cidr 生产一个数字,该数字代表着该 Ip 的 route table
[root@node1 ~]# ip netns exec fip-6c9852c3-7a5b-4b9c-a279-b9098257a0dd ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
2852022899: from all iif fpr-61eaacf9-d lookup 2852022899
这里面的 2852022899 就是这个方法生成的
一个 floating ip 绑定的 fixed ip 发生了变化
- 调用
_remove_floating_ip_rule
清除该 floating ip 之前的 rule - 调用
_add_floating_ip_rule
为该 floating ip 重新分配 rule
实现 RouterInfo 中的方法
- 调用
floating_ip_added_dist
为该 floating ip 建立相应的规则和辅助设备 - 返回 active 状态
实现 RouterInfo 中的方法
- 调用
floating_ip_removed_dist
方法实现
调用 floating_ip_moved_dist
方法实现
获取当前 router 上属于 subnet 的 internal port
- 调用
_get_internal_port
获取当前 router 上属于 subnet 的 internal port - 调用
get_internal_device_name
获取该 port 的名称 - 调用
IPDevice
描述该 port - 若该 port 真实存在,则根据 operation 来增加或删除 arp 记录
- 若 port 不存在,且 operation 为 add,则调用
_cache_arp_entry
来缓存来 arp 记录,等到 port 存在后再增加记录
缓存 arp 记录
- 以一个
Arp_entry
来描述该 arp 记录,及其操作类型 - 将该记录保存在
_pending_arp_set
中
处理与 subnet 有关的 arp 缓存记录,调用 _update_arp_entry
实现
删除与 subnet 有关的 arp 缓存记录
- 调用
AgentMixin.get_ports_by_subnet
获取该 subnet 上的 port - 调用
_update_arp_entry
更新关于这些 port 的 arp 记录 - 调用
_process_arp_cache_for_internal_port
出该关于该 subnet 的 arp 缓存记录
[root@node1 ~]# ip netns exec qrouter-61eaacf9-d4e0-4202-bac9-321da0ceaa69 arp -n
Address HWtype HWaddress Flags Mask Iface
192.168.100.2 ether fa:16:3e:a3:93:e9 CM qr-d555da2e-f3
10.10.10.8 ether fa:16:3e:63:d7:ff CM qr-f5b8c40f-24
10.10.10.2 ether fa:16:3e:81:36:c2 CM qr-f5b8c40f-24
192.168.100.12 ether fa:16:3e:44:db:f0 CM qr-d555da2e-f3
169.254.106.115 ether de:50:a0:c4:aa:21 C rfp-61eaacf9-d
192.168.100.10 ether fa:16:3e:1c:50:80 CM qr-d555da2e-f3
10.10.10.13 ether fa:16:3e:68:e7:3e CM qr-f5b8c40f-24
192.168.100.5 ether fa:16:3e:41:24:fc CM qr-d555da2e-f3
删除关于 ip route 表 snat_idx 中的默认网关记录
清除某一 namespace 中,ip rule priority 大于 72768 的 rule 以及相关的 ip route table 数据
调用 _stale_ip_rule_cleanup
清除 qrouter- namespace 中关于 rfp- 设备的 route 记录
def _snat_redirect_add(self, gateway, sn_port, sn_int):
"""Adds rules and routes for SNAT redirection."""
self._snat_redirect_modify(gateway, sn_port, sn_int, is_add=True)
def _snat_redirect_remove(self, gateway, sn_port, sn_int):
"""Removes rules and routes for SNAT redirection."""
self._snat_redirect_modify(gateway, sn_port, sn_int, is_add=False)
- 调用
get_ex_gw_port
获取 gateway port,若不存在 gateway port 则退出 - 调用
get_snat_port_for_internal_port
获取为该 subnet 提供 snat 服务的 snat_port - 调用
get_internal_device_name
获取 port 的名称 - 调用
_snat_redirect_add
- 构造
IPRule
来描述 qrouter- namespace 的 rule - 构造
IPDevice
来描述 interface - 若是添加 rule 和 route,则构造一个
IPWrapper
实例 - 对于 sn_port 上的每个 fixed ip:
- 对于提供 snat 服务的端口 gateway,若其上面的 ip 地址与 sn_port 上面的地址一致的话
- 若是增加 rule 和 route,则为 sn_int 增加新的 rule 和 route table,同时使用如下命令:
sysctl -w net.ipv4.conf.%s.send_redirects=0
- 若是删除操作的话,则调用
_delete_gateway_device_if_exists
删除网关和路由记录,删除 rule 记录
- 举例子来说就是将对外部网络的请求转发到 snat- namespace 中的网卡上
[root@node1 ~]# ip netns exec qrouter-61eaacf9-d4e0-4202-bac9-321da0ceaa69 ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
57483: from 192.168.100.5 lookup 16
168430081: from 10.10.10.1/24 lookup 168430081
3232261121: from 192.168.100.1/24 lookup 3232261121
[root@node1 ~]# ip netns exec qrouter-61eaacf9-d4e0-4202-bac9-321da0ceaa69 ip route list table 168430081
default via 10.10.10.13 dev qr-f5b8c40f-24
[root@node1 ~]# ip netns exec snat-61eaacf9-d4e0-4202-bac9-321da0ceaa69 ip addr show sg-1d0b51ca-38
83: sg-1d0b51ca-38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN qlen 1000
link/ether fa:16:3e:68:e7:3e brd ff:ff:ff:ff:ff:ff
inet 10.10.10.13/24 brd 10.10.10.255 scope global sg-1d0b51ca-38
valid_lft forever preferred_lft forever
inet6 fe80::f816:3eff:fe68:e73e/64 scope link
valid_lft forever preferred_lft forever
- 调用
RouterInfo.internal_network_added
创建新的 router port - 调用
_set_subnet_arp_info
更新该 port 所在 subnet 的 arp 记录 - 调用
_snat_redirect_add_from_port
为该 port 实现 snat 的规则
- 调用
_dvr_internal_network_removed
处理 snat 和 arp 的事项 - 调用
RouterInfo.internal_network_removed
删除该 port
- 若不存在 gateway port 则直接退出
- 调用
get_snat_port_for_internal_port
获取提供 snat 服务的 port,若不存在则直接退出 - 调用
_snat_redirect_remove
删除与该 port 有关的 snat 规则 - 调用
_delete_arp_cache_for_internal_port
删除与该 port 有关的 arp 缓存
获取 external netwokr 在该 router 上的 agent gateway
获取 rfp- 设备的名称
- 在 qrouter- namespace 中执行如下命令
sysctl -w net.ipv4.conf.all.send_redirects=0
- 对于所有的 internal port:
- 调用
get_snat_port_for_internal_port
获取与之对应的 snat port - 调用
get_internal_device_name
获取 internal port 的名称 - 调用
_snat_redirect_add
实现 snat 功能 - 对于所有的 snat port,调用
_update_arp_entry
更新 qrouter- namespace 的 arp 记录
未实现
- 调用
process_floating_ip_nat_rules
重新处理与 floating ip 有关的 iptables rule - 若存在 fip- namespace,调用
get_external_device_interface_name
获取 rfp- 网络设备名称,调用process_floating_ip_addresses
- 若 router 不存在 gateway port,则对于所有的 internal port 来说:
- 调用
get_snat_port_for_internal_port
获取 snat port - 调用
get_internal_device_name
获取 internal port name - 调用
_snat_redirect_remove
删除 snat 的相应规则
- 清空 ipv4 中的 snat 和 POSTROUTING chain
- 获取 gateway port,没有则直接退出
- 调用
get_external_device_interface_name
获取 rfp- 的名称 - 调用
get_floating_ips
获取所有的 floating ip - 将 snat chain 转发至 floating-snat chain
- 调用
_prevent_snat_for_internal_traffic_rule
增加如下规则:-A neutron-l3-agent-POSTROUTING ! -i rfp-61eaacf9-d ! -o rfp-61eaacf9-d -m conntrack ! --ctstate DNAT -j ACCEPT
- 获取 internal port
- 调用
_get_port_devicename_scopemark
获取 internal port 对于的 mark/mask - 调用
get_ex_gw_port
获取 gateway port - 调用
get_external_device_interface_name
获取 rfp- 设备名称 - 调用
_get_external_address_scope
获取 external network 的 scope address - 调用
get_address_scope_mark_mask
获取 external network 的 mark/mask - 返回所有 port 的 mark/mask
- 若存在 gateway port,则调用
create_dvr_fip_interfaces
处理 agent gateway port 相关事项 - 调用
RouterInfor.process_external
继续处理
- 调用
get_floating_ips
获取所有的 floating ip - 调用
get_floating_agent_gw_interface
获取 agent gateway port name - 若存在 floating ip:
- 若不存在 agent gateway port,调用
plugin_rpc.get_agent_gateway_port
获取其数据 - 调用
fip_ns.create_or_update_gateway_port
创建 agent gateway port - 创建 fpr- 和 rfp- 设备,并更新路由信息
- 若存在 fip- namespace 和 agent gateway port,则:
- 获取 fip- namespace 的名称
- 获取 agent gateway port 数据
- 调用
_check_if_route_applicable_to_fip_namespace
是否可以为 router 在 agnet gateway 上创建 route - 若可以创建 route,则:
- 获取 local subnet pair
- 调用
_get_snat_idx
获取 snat table number - 调用
_update_fip_route_table_with_next_hop_routes
为 fpr- 创建通往外部的路由 - 继续调用
RouterInfo.update_routing_table
处理其他事项
- 获取 agent gateway port 的 ip 地址
- 若
router['nexthop']
属性与 agent gateway port 所在的 subnet 为同一个,则返回 True
def _update_fip_route_table_with_next_hop_routes(
self, operation, route, fip_ns_name, tbl_index):
cmd = ['ip', 'route', operation, 'to', route['destination'],
'via', route['nexthop'], 'table', tbl_index]
ip_wrapper = ip_lib.IPWrapper(namespace=fip_ns_name)
if ip_wrapper.netns.exists(fip_ns_name):
ip_wrapper.netns.execute(cmd, check_exit_code=False)
else:
LOG.debug("The FIP namespace %(ns)s does not exist for "
"router %(id)s",
{'ns': fip_ns_name, 'id': self.router_id})
[root@node2 ~]# ip netns exec fip-6c9852c3-7a5b-4b9c-a279-b9098257a0dd ip -d route show table 2852019551
default via 172.16.100.1 dev fg-eff4564f-5f
- 若不存在 fip- namespace 则返回空
- 调用
fip_ns.get_int_device_name
获取 fpr- 设备名称 - 调用
IPDevice
封装 fpr- 涉笔 - 若 fpr- 设备不存在,则返回空
- 获取经过 fpr- 设备的路由记录(
172.16.100.246 via 169.254.93.94 dev fpr-61eaacf9-d
) - 获取路由中的 floating ip