neutron/agent/l3/ha_router.py
class HaRouterNamespace(namespaces.RouterNamespace):
"""Namespace for HA router.
This namespace sets the ip_nonlocal_bind to 0 for HA router namespaces.
It does so to prevent sending gratuitous ARPs for interfaces that got VIP
removed in the middle of processing.
"""
def create(self):
super(HaRouterNamespace, self).create()
# HA router namespaces should not have ip_nonlocal_bind enabled
ip_lib.set_ip_nonlocal_bind_for_namespace(self.name)
class HaRouter(router.RouterInfo):
def __init__(self, state_change_callback, *args, **kwargs):
super(HaRouter, self).__init__(*args, **kwargs)
self.ha_port = None
self.keepalived_manager = None
self.state_change_callback = state_change_callback
def create_router_namespace_object(
self, router_id, agent_conf, iface_driver, use_ipv6):
return HaRouterNamespace(
router_id, agent_conf, iface_driver, use_ipv6)
ha 没有单独的 namespace,也是放在 qrouter- namespace 中的
@property
def ha_priority(self):
return self.router.get('priority', keepalived.HA_DEFAULT_PRIORITY)
VRRP 优先级
@property
def ha_vr_id(self):
return self.router.get('ha_vr_id')
VRRP ID
@property
def ha_state(self):
ha_state_path = self.keepalived_manager.get_full_config_file_path(
'state')
try:
with open(ha_state_path, 'r') as f:
return f.read()
except (OSError, IOError):
LOG.debug('Error while reading HA state for %s', self.router_id)
return None
通过读取 ha 数据文件的内容,判断当前 ha router 的状态
@ha_state.setter
def ha_state(self, new_state):
ha_state_path = self.keepalived_manager.get_full_config_file_path(
'state')
try:
with open(ha_state_path, 'w') as f:
f.write(new_state)
except (OSError, IOError):
LOG.error(_LE('Error while writing HA state for %s'),
self.router_id)
设定 ha state
@property
def ha_namespace(self):
return self.ns_name
- 调用父类的 initialize 处理
- 获取 ha port,若没有则退出
- 调用
_init_keepalived_manager
初始化 keepalived 配置 - 调用
ha_network_added
创建 ha port,初始化 ip - 调用
update_initial_state
将 router 更新为 ha master 状态 - 调用
spawn_state_change_monitor
启动neutron-keepalived-state-change
进程
- 生成
KeepalivedManager
实例 - 调用
get_ha_device_name
获取 ha interface 的名称 - 创建一个
keepalived.KeepalivedInstance
实例 - 若配置文件中设定了
ha_vrrp_auth_password
,则调用KeepalivedInstance.set_authentication
设定 vrrp 的认证方式
启动 keepalived
停止 keepalived,删除配置信息
创建 ha port,为该 ha port 配置 ip 地址
删除 ha port
def _get_primary_vip(self):
return self._get_keepalived_instance().get_primary_vip()
- 调用
IPDevice
描述 ha port - 调用
_get_primary_vip
将该 router 设置为 master - 回调处理,记录 router 更新的信息
- 调用
_get_state_change_monitor_process_manager
创建neutron-keepalived-state-change
的管理器 - 启动
neutron-keepalived-state-change
进程
def _get_state_change_monitor_process_manager(self):
return external_process.ProcessManager(
self.agent_conf,
'%s.monitor' % self.router_id,
self.ha_namespace,
default_cmd_callback=self._get_state_change_monitor_callback())
创建需要启动 neutron-keepalived-state-change
的命令
获取本路由上的 ha port 名称
def _add_vips(self, port, interface_name):
for ip_cidr in common_utils.fixed_ip_cidrs(port['fixed_ips']):
self._add_vip(ip_cidr, interface_name)
- 调用
_get_keepalived_instance
获取该 router 的描述 - 为该 Instance 增加一个 vip 记录
获取本 router 在 keepalived 中的 instance 描述
删除该 router instance 上的一个 vips 记录
清空关于该 Interface 上的 vips 记录
- 调用
_get_keepalived_instance
获取该 router 的 instance - 调用
instance.get_existing_vip_ip_addresses
获取 vips 中记录的该 interface 上的 ip
def get_router_cidrs(self, device):
return set(self._get_cidrs_from_keepalived(device.name))
创建 KeepalivedVirtualRoute
来更新 Keepalived 中的 route 记录
为该 router 的 keepalived instance 中增加 gateway 记录
为该 router 的 keepalived instance 中增加额外的 route 记录
对于 Ipv6 地址的处理
def _should_delete_ipv6_lladdr(self, ipv6_lladdr):
"""Only the master should have any IP addresses configured.
Let keepalived manage IPv6 link local addresses, the same way we let
it manage IPv4 addresses. If the router is not in the master state,
we must delete the address first as it is autoconfigured by the kernel.
"""
manager = self.keepalived_manager
if manager.get_process().active:
if self.ha_state != 'master':
conf = manager.get_conf_on_disk()
managed_by_keepalived = conf and ipv6_lladdr in conf
if managed_by_keepalived:
return False
else:
return False
return True
def _disable_ipv6_addressing_on_interface(self, interface_name):
"""Disable IPv6 link local addressing on the device and add it as
a VIP to keepalived. This means that the IPv6 link local address
will only be present on the master.
"""
device = ip_lib.IPDevice(interface_name, namespace=self.ha_namespace)
ipv6_lladdr = ip_lib.get_ipv6_lladdr(device.link.address)
if self._should_delete_ipv6_lladdr(ipv6_lladdr):
device.addr.flush(n_consts.IP_VERSION_6)
self._remove_vip(ipv6_lladdr)
self._add_vip(ipv6_lladdr, interface_name, scope='link')
调用 _add_vip
完成操作
- 调用
_remove_vip
移除该 floating ip 的记录 - 调用父类的
remove_floating_ip
完成后续处理
- 调用
_clear_vips
清除该 interface 上的 vip 的记录 - 调用
_disable_ipv6_addressing_on_interface
处理该 port 上的 ipv6 - 调用
_add_vip
增肌阿盖 Interface 的新的 vip 记录
创建新的 router port,增加该 port 的 vip 记录
调用 _plug_ha_router_port
进行处理
- 调用父类的
internal_network_removed
完成前序处理 - 调用
_clear_vips
删除该 router port 的 vip 记录
销毁 neutron-keepalived-state-change
进程
判断两个 port 是否相等
- 调用
RouterInfo._plug_external_gateway
完成 gateway 的添加 - 调用
_add_gateway_vip
记录 gateway 的 ip - 处理 ipv6 事项
- 调用
RouterInfo._plug_external_gateway
完成 gateway port 的更新 - 清理之前的关于该 gateway 的 vip 记录,增加新的 vip 记录
- 调用
_clear_vips
完成 vip 的清理 - 若该 router 为 ha master,则调用
RouterInfo.external_gateway_removed
清理 gateway - 若该 router 为 ha backup,则直接删除该 port
- 调用
destroy_state_change_monitor
停止neutron-keepalived-state-change
进程 - 调用
disable_keepalived
停止 keepalived 进程 - 调用
ha_network_removed
删除 ha port - 调用父类的 delete 完成其他处理
在之前处理的基础上,若是含有 ha port,则启动 keepalived 进程
@common_utils.synchronized('enable_radvd')
def enable_radvd(self, internal_ports=None):
if (self.keepalived_manager.get_process().active and
self.ha_state == 'master'):
super(HaRouter, self).enable_radvd(internal_ports)
只会在 ha master router 上启动 radvd 服务