2021SC@SDUSC
为什么有人圣诞节还要写作业啊
概述
Neutron dhcp实现了为虚机提供动态分配IP的服务,dhcp功能由neutron-server和dhcp-agent配合实现。其中server负责接收请求并向agent发送网络、子网、端口等数据;agent接收数据,创建、配置dhcp实例。社区的dhcp功能由dnsmasq软件实现,即由该软件充当dhcp server。(Neutron dhcp实现)
聚焦源码
neutron-18.1.1/neutron/scheduler/dhcp_agent_scheduler.py
这个文件中一共有五个类,分别是AutoScheduler, ChangeScheduler, WeightScheduler, AZAwareWeightScheduler和DhcpFilter。其中,DhcpFilter在前面四个类的初始化函数中被初始化,可以认为,DhcpFilter是它们的一部分。
例如:
class WeightScheduler(base_scheduler.BaseWeightScheduler, AutoScheduler):
def __init__(self):
super(WeightScheduler, self).__init__(DhcpFilter())
ChangeScheduler和WeightScheduler在本文件中没有提供方法,但它们继承自各自的基类,这些基类在neutron-18.1.1/neutron/scheduler/base_scheduler.py中提供了select方法,并描述了它们的调度策略:
BaseChanceScheduler()随机选择agent,BaseWeightScheduler()基于负载选择agent;AZAwareWeightScheduler选择策略如下:
选择为network分配了最少agent的AZ;对于分配了相同数目agent的AZ,优先选择负载最少的AZ。
然后我们来看DhcpFilter做了什么。
它提供了3个共有函数:
get_vacant_network_dhcp_agent_binding_index(self, context, network_id, force_scheduling)
bind(self, context, agents, network_id, force_scheduling=False)
filter_agents(self, plugin, context, network)
第一个函数返回一个空的绑定索引,并且返回它是否存在。因为每一个NetworkDhcpAgentBinding有一个在network_id中不重复的binding_index,所以创建binding的时候,我们需要找到一个空的并且没有用过的binding_index来用。
def get_vacant_network_dhcp_agent_binding_index(
self, context, network_id, force_scheduling):
num_agents = agent_obj.Agent.count(
context, agent_type=constants.AGENT_TYPE_DHCP)
num_agents = min(num_agents, cfg.CONF.dhcp_agents_per_network)
bindings = network.NetworkDhcpAgentBinding.get_objects(
context, network_id=network_id)
return base_scheduler.get_vacant_binding_index(
num_agents, bindings, ndab_model.LOWEST_BINDING_INDEX,
force_scheduling=force_scheduling)
第二个函数将network和agent绑定,关键做法是调用network.NetworkDhcpAgentBinding(context, dhcp_agent_id=agent_id, network_id=network_id, binding_index=binding_index).create()
为agents中的每一个创建一个绑定关系。
def bind(self, context, agents, network_id, force_scheduling=False):
# customize the bind logic
bound_agents = agents[:]
for agent in agents:
binding_index = self.get_vacant_network_dhcp_agent_binding_index(
context, network_id, force_scheduling)
if binding_index < ndab_model.LOWEST_BINDING_INDEX:
LOG.debug('Unable to find a vacant binding_index for '
'network %(network_id)s and agent %(agent_id)s',
{'network_id': network_id,
'agent_id': agent.id})
continue
# saving agent_id to use it after rollback to avoid
# DetachedInstanceError
agent_id = agent.id
try:
network.NetworkDhcpAgentBinding(
context, dhcp_agent_id=agent_id,
network_id=network_id,
binding_index=binding_index).create()
except exceptions.NeutronDbObjectDuplicateEntry:
# it's totally ok, someone just did our job!
bound_agents.remove(agent)
LOG.info('Agent %s already present', agent_id)
LOG.debug('Network %(network_id)s is scheduled to be '
'hosted by DHCP agent %(agent_id)s with binding_index '
'%(binding_index)d',
{'network_id': network_id,
'agent_id': agent_id,
'binding_index': binding_index})
super(DhcpFilter, self).bind(context, bound_agents, network_id)
第三个函数返回可以承载网络的一组agents。它返回三个值:n_agents是应该被调度的agents个数,如果n_agents=0,说明所有网络都得到了代理,或者没有剩余agent能够再承载网络了;hostable_agents是可以承载网络的agent的集合;hosted_agents是已经承载了网络的agent的集合。
def filter_agents(self, plugin, context, network):
agents_dict = self._get_network_hostable_dhcp_agents(
plugin, context, network)
if not agents_dict['hostable_agents'] or agents_dict['n_agents'] <= 0:
return {'n_agents': 0, 'hostable_agents': [],
'hosted_agents': agents_dict['hosted_agents']}
return agents_dict