Router 概述
- 创建虚拟路由器router_100_101,并加入两个子网subnet_172_16_101_0,subnet_172_16_100_0,
- 通过 ip netns exec ip a 命令查看 router_100_101 namespace 中的 veth interface 配置。
namespace 中有两个 interface:
qr-e17162c5-00 上设置了 Gateway IP 172.16.101.1,与 root namespace 中的 tape17162c5-00 组成 veth pair。
qr-d568ba1a-74 上设置了 Gateway IP 172.16.100.1,与 root namespace 中的 tapd568ba1a-74 组成 veth pair。
- 新增路由表
源码如下:(注意,原生实现router功能都是先删除router的端口,路由,再重新添加)
def _internal_network_added(self, ns_name, network_id, port_id,
fixed_ips, mac_address,
interface_name, prefix, mtu=None):
LOG.debug("adding internal network: prefix(%s), port(%s)",
prefix, port_id)
// 新增qr口
self.driver.plug(network_id, port_id, interface_name, mac_address,
namespace=ns_name,
prefix=prefix, mtu=mtu)
ip_cidrs = common_utils.fixed_ip_cidrs(fixed_ips)
// qr ns增加gateway ip 172.16.100.1以及添加路由
self.driver.init_router_port(
interface_name, ip_cidrs, namespace=ns_name)
- 创建外部网络,并且创建 subnet_10_10_10_0,IP 地址为 10.10.10.0/24。
该 veth pair 命名为 qg-b8b32a88-03,上面配置了 IP 10.10.10.2。
新增router路由:默认网关10.10.10.1,意味着对于访问 vlan100 和 vlan101 租户网络以外的所有流量,router_100_101 都将转发给 ext_net 的网关 10.10.10.1。
同时需要添加一条iptables规则,当数据包从 router 连接外网的接口 qg-b8b32a88-03 发出的时候,会做一次 Source NAT,即将包的源地址修改为 router 的接口地址 10.10.10.2,这样就能够保证目的端能够将应答的包发回给 router,然后再转发回源端 instance。
SNAT 让 instance 能够直接访问外网,但外网还不能直接访问 instance。因为 instance 没有外网 IP。这里 “直接访问 instance” 是指通信连接由外网发起,例如从外网 SSH cirros-vm3。(这里只能通过浮动IP访问)
源码如下:
def _process_external_gateway(self, ex_gw_port):
# TODO(Carl) Refactor to clarify roles of ex_gw_port vs self.ex_gw_port
ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
self.ex_gw_port and self.ex_gw_port['id'])
interface_name = None
if ex_gw_port_id:
interface_name = self.get_external_device_name(ex_gw_port_id)
if ex_gw_port:
if not self.ex_gw_port:
// 配置qg口以及相关默认路由
self.external_gateway_added(ex_gw_port, interface_name)
self.agent.pd.add_gw_interface(self.router['id'],
interface_name)
elif not self._gateway_ports_equal(ex_gw_port, self.ex_gw_port):
self.external_gateway_updated(ex_gw_port, interface_name)
elif not ex_gw_port and self.ex_gw_port:
self.external_gateway_removed(self.ex_gw_port, interface_name)
self.agent.pd.remove_gw_interface(self.router['id'])
elif not ex_gw_port and not self.ex_gw_port:
for p in self.internal_ports:
interface_name = self.get_internal_device_name(p['id'])
self.gateway_redirect_cleanup(interface_name)
self._delete_stale_external_devices(interface_name)
# Process SNAT rules for external gateway
gw_port = self._router.get('gw_port')
// SNAT规则
self._handle_router_snat_rules(gw_port, interface_name)
- 浮动IP,分配浮动IP 10.10.10.3到vm3 对应租户IP 172.16.101.3
可以看到,floating IP 已经配置到 router 的外网 interface qg-b8b32a88-03 上。查看 router 的 NAT 规则:
iptables 增加了两条处理 floating IP 的规则:
-
当 router 接收到从外网发来的包,如果目的地址是 floating IP 10.10.10.3,将目的地址修改为 cirros-vm3 的 IP 172.16.101.3。这样外网的包就能送达到 cirros-vm3。
-
当 cirros-vm3 发送数据到外网,源地址 172.16.101.3 将被修改为 floating IP 10.10.10.3。
源码如下:
def process_external(self):
fip_statuses = {}
try:
with self.iptables_manager.defer_apply():
ex_gw_port = self.get_ex_gw_port()
self._process_external_gateway(ex_gw_port)
if not ex_gw_port:
return
# Process SNAT/DNAT rules and addresses for floating IPs
self.process_snat_dnat_for_fip()
# Once NAT rules for floating IPs are safely in place
# configure their addresses on the external gateway port
interface_name = self.get_external_device_interface_name(
ex_gw_port)
// 添加浮动IP到gw口
fip_statuses = self.configure_fip_addresses(interface_name)
参考链接:https://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587539&idx=1&sn=b41b18336c593b143e7495660fa2f086&chksm=8d30804aba47095c5ab109d963c7cc88a024c6aed8a75105e32db3e3d5cea846a878b6f12a31&scene=21#wechat_redirect