当前位置:   article > 正文

OpenStack组件Neturon neutron-DHCP-Agent代码分析_openstack network命令是调用neutron吗

openstack network命令是调用neutron吗

总体介绍以及各模块功能

NEUTRONDHCP为租户网络提供DHCP服务,即IP地址动态分配,另外还会提供metadata请求服务(元数据是描述数据属性的信息,也就是数据的数据)。根据整个DHCP处理的流程,DHCP模块主要由DHCP agent scheduler、DHCP agent、DHCP driver构成:

DHCP agent scheduler:负责DHCP agent与network的调度

DHCP agent:为租户网络提供DHCP的功能,提供metadatarequest服务

DHCP driver:用于管理DHCPserver,目前环境中是采用的dnsmasq。

在这里插入图片描述

对应架构图中数字,有以下几个操作:

  1. 当dashboard(openstack的web界面)上执行network/subnet/port的操作时,会调用neutron-api通知CorePlugin(如linux bridge plugin,ovs plugin等),创建相应虚拟network/subnet/port。

  2. agentmanagement/agent scheduler里面会通过调度算法调度DHCP agent

  3. network/subnet/port操作会发送rpc请求到DHCP agent。

  4. agentschedulerdb发送rpc请求到DHCP agent。

  5. DHCP agent通过DhcpPluginApi发送rpc请求到coreplugin,操作相应的数据库。

  6. DHCP agent调用dhcpdriver实现DHCP server的管理。

DHCP agent scheduler调度算法介绍

DHCP agent scheduler调度算法介绍

通过DHCP agent scheduler,系统中可以部署多个dhcp agent,增加可用性(HA, highavailability),避免单点失败(SOF,single point of failure);多个dhcp agent可以安装在多台机器上,同时服务。

DHCP agent的调度算法可以在/etc/neutron/neutron.conf文件中设置,默认设置是neutron.scheduler.dhcp_agent_scheduler.ChanceScheduler,这个实现是采用了随机分配算法。另外还有一种调度算法是根据agent的权重,进行负载均衡。
network_scheduler_driver = neutron.scheduler.dhcp_agent_scheduler.WeightScheduler

调度算法通过network_scheduler_driver的实现在neutron/scheduler/dhcp_agent_scheduler.py。

系统默认使用的是随机分配算法,下面是DHCP agent的随机调度算法部分代码:

#neutron/scheduler/base_scheduler.py

class BaseChanceScheduler(BaseScheduler):
  """Choose agents randomly."""
  
  def __init__(self, resource_filter):
  self.resource_filter = resource_filter
  
  def select(self, plugin, context, resource_hostable_agents,
               resource_hosted_agents, num_agents_needed):
          chosen_agents = random.sample(resource_hostable_agents,
                                      num_agents_needed)
  return chosen_agents
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
DHCP agent schedul调用DHCP agent过程

根据agent的权重调度的方法,是比较常用的方法,有利于负载均衡。所以本节以WeightScheduler为例,分析一个网络使用一个DHCP agent的情况,是如何调度的。目前环境中在controller上和computer分别安装一个DHCP agent,并把DHCP agent调度算法设置成按权重调度。

network_scheduler_driver = neutron.scheduler.dhcp_agent_scheduler.WeightScheduler

调度算法的代码如下:在neutron/scheduler/dhcp_agent_scheduler.py:

class BaseWeightScheduler(BaseScheduler):
  """Choose agents randomly."""
  
  def __init__(self, resource_filter):
  self.resource_filter = resource_filter
  
  def select(self, plugin, context, resource_hostable_agents,
               resource_hosted_agents, num_agents_needed):
          chosen_agents = sorted(resource_hostable_agents,
                           key=attrgetter('load'))[0:num_agents_needed]
  return chosen_agents
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

调度算法的代码如下:在neutron/scheduler/dhcp_agent_scheduler.py:BaseWeightScheduler:select处设置pdb断点查看
调用栈如下:
在这里插入图片描述
根据调用栈看下首先schedule函数的调度过程,代码如下。首先从所有的DHCP agents里面通过self.resource_filter.filter_agent函数选出可供使用的DHCP agent,下面分别介绍该函数和self.select函数。

#neutron/scheduler/base_scheduler.py
def schedule(self, plugin, context, resource):
  """Select and bind agents to a given resource."""
  if not self.resource_filter:
  return
  # filter the agents that can host the resource
  filtered_agents_dict = self.resource_filter.filter_agents(
        plugin, context, resource)
    num_agents = filtered_agents_dict['n_agents']
    hostable_agents = filtered_agents_dict['hostable_agents']
    hosted_agents = filtered_agents_dict['hosted_agents']
      chosen_agents = self.select(plugin, context, hostable_agents,
                                hosted_agents, num_agents)
  # bind the resource to the agents
  self.resource_filter.bind(context, chosen_agents, resource['id'])
  return chosen_agents
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

self.resource_filter.filter_agent的返回值是一个字典,字典有3个key值。代码如下:

#neutron/scheduler/dhcp_agent_scheduler.py

def filter_agents(self, plugin, context, network):
  """Return the agents that can host the network.
  
    This function returns a dictionary which has 3 keys.
    n_agents: The number of agents should be scheduled. If n_agents=0,
    all networks are already scheduled or no more agent can host the
    network.
    hostable_agents: A list of agents which can host the network.
    hosted_agents: A list of agents which already hosts the 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

第一个KEY 'n_agents’代表需要调度几个dhcpagents,默认是一个。这个可以修改配置文件进行修改:

dhcp_agents_per_network = 1
  • 1

第二个KEY’hostable_agents’代表可以使用的DHCP agent,这里面记录着每个agent的详细信息,如下:

<neutron.db.agents_db.Agent[objectat 56fd5d0] {id=u’21ea8426-5e68-4f83-abd6-3451e426511e’, agent_type=u’DHCP agent’,binary=u’neutron-dhcp-agent’, topic=u’dhcp_agent’, host=u’computer35’,availability_zone=u’nova’, admin_state_up=True,created_at=datetime.datetime(2016, 10, 19, 7, 33, 14),started_at=datetime.datetime(2016, 10, 19, 7, 33, 14), heartbeat_timestamp=datetime.datetime(2016,10, 19, 8, 58, 32), description=None, configurations=u’{“subnets”: 2,“dhcp_lease_duration”: 86400, “dhcp_driver”:“neutron.agent.linux.dhcp.Dnsmasq”, “networks”: 2,“log_agent_heartbeats”: false, “ports”: 2}’,resource_versions=None, load=2}>

记录着 id,宿主机,创建时间,该DHCP agent上创建了几个DHCP server的服务等等。

第三个KEY’hosted_agents’代表的意思是,已经为该网络创建DHCP服务的agent,我们的环境是每个网络使用一个DHCP agent服务,所以该值为空的列表。

那么这么多agents,是如何选举出最优的agent的呢?看下面的选举代码:

#neutron/scheduler/base_scheduler.py

def select(self, plugin, context, resource_hostable_agents,
           resource_hosted_agents, num_agents_needed):
    chosen_agents = sorted(resource_hostable_agents,
  key=attrgetter('load'))[0:num_agents_needed]
  return chosen_agents
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面得到了所有DHCP agent的详细信息,其中’load’参数记录着DHCP agent服务的网络个数。根据这个参数进行排序,把’load’值最小的agent选举出来。

DHCP agent启动路径

首先通过查看setup.cfg文件,查找dhcp服务的启动路径。

[entry_points]

console_scripts =

    neutron-db-manage = neutron.db.migration.cli:main

    neutron-debug = neutron.debug.shell:main

 neutron-dhcp-agent = neutron.cmd.eventlet.agents.dhcp:main
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
3.1 DHCP agent启动流程
3.1.1 Neutron-agent的初始化

进入neutron/cmd/eventlet/agents/dhcp.py,可以查看的main函数的启动代码。与l2agent l3agent一样都是创建一个rpc-service对象。rpc-service的manager类为neutron.agent.dhcp.agent.DhcpAgentWithStateReport对象。

#/neutron/agent/dhcp_agent.py: main
def register_options(conf):
    config.register_interface_driver_opts_helper(conf)
    config.register_agent_state_opts_helper(conf)
    config.register_availability_zone_opts_helper(conf)
    conf.register_opts(dhcp_config.DHCP_AGENT_OPTS)
    conf.register_opts(dhcp_config.DHCP_OPTS)
    conf.register_opts(dhcp_config.DNSMASQ_OPTS)
    conf.register_opts(metadata_config.DRIVER_OPTS)
    conf.register_opts(metadata_config.SHARED_OPTS)
    conf.register_opts(interface.OPTS)
  def main():
    register_options(cfg.CONF)
    common_config.init(sys.argv[1:])
    config.setup_logging()
    server = neutron_service.Service.create(
  binary='neutron-dhcp-agent',
  topic=topics.DHCP_AGENT,
  report_interval=cfg.CONF.AGENT.report_interval,
  manager='neutron.agent.dhcp.agent.DhcpAgentWithStateReport')
    service.launch(cfg.CONF, server).wait()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

manager类的具体实现代码目录在neutron/agent/dhcp/agent.py,文件中DhcpAgentWithStateReport继承自DhcpAgent,用于汇报DHCPAgent的状态。在分析start函数之前,先分析首先neutron.agent.dhcp.agent.DhcpAgentWithStateReport对象的创建过程。

DhcpAgentWithStateReport类继承DhcpAgent类,DhcpAgentWithStateReport类的作用主要是创建一个协程定时向neutron-server启动时开启的rpc-server上报neutron-dhcp-agent的服务或network状态,然后通过neutron-server的core plugin将状态更新到数据库中。

DhcpAgent类才是为neutron-dhcp-agent服务做主要工作的。初始化代码如下:

#/neutron/agent/dhcp/agent.py: DhcpAgentWithStateReport

class DhcpAgent(manager.Manager):
  """DHCP agent service manager.
  
    Note that the public methods of this class are exposed as the server side
    of an rpc interface.  The neutron server uses
    neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.DhcpAgentNotifyApi as the
    client side to execute the methods here.  For more information about
    changing rpc interfaces, see doc/source/devref/rpc_api.rst.
    """
  target = oslo_messaging.Target(version='1.0')
  
  def __init__(self, host=None, conf=None):
  super(DhcpAgent, self).__init__(host=host)
  self.needs_resync_reasons = collections.defaultdict(list)
  self.conf = conf or cfg.CONF
  self.cache = NetworkCache()
  self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)
        ctx = context.get_admin_context_without_session()
  self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, ctx, self.conf.host)
  # create dhcp dir to store dhcp info
  dhcp_dir = os.path.dirname("/%s/dhcp/" % self.conf.state_path)
          utils.ensure_dir(dhcp_dir)
  self.dhcp_version = self.dhcp_driver_cls.check_version()
  self._populate_networks_cache()
  # keep track of mappings between networks and routers for
        # metadata processing
  self._metadata_routers = {}  # {network_id: router_id}
  self._process_monitor = external_process.ProcessMonitor(
  config=self.conf,
  resource_type='dhcp')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

其中self.cache = NetworkCache()主要保存底层的active的dhcp networks信息,这些信息会通过DhcpAgentWithStateReport类的_report_state方法上报到数据库中。
dhcp_dir=os.path.dirname("/%s/dhcp/" % self.conf.state_path)创建了一个目录,其中self.conf.state_path的配置(在/etc/neutron/dhcp_agent.ini配置文件中)为:

state_path=/var/lib/neutron
  • 1

在该目录下将会保存创建的dhcp networks的相关信息。

在这里插入图片描述
self.dhcp_driver_cls=importutils.import_class(self.conf.dhcp_driver)中的dhcp_driver也为/etc/neutron/dhcp_agent.ini配置文件中参数。

dhcp_driver = neutron.agent.Linux.dhcp.Dnsmasq
  • 1

self.dhcp_driver_cls是Dnsmasq的类实例。

3.1.2 Neutron-agent的start

首先看下rpc-service的start代码,代码路径在neutron/service.py

#/neutron/service.py:Service

def start(self):
  self.manager.init_host()
  super(Service, self).start()
  if self.report_interval:
        pulse = loopingcall.FixedIntervalLoopingCall(self.report_state)
        pulse.start(interval=self.report_interval,
  initial_delay=self.report_interval)
  self.timers.append(pulse)
  
  if self.periodic_interval:
  if self.periodic_fuzzy_delay:
            initial_delay = random.randint(0, self.periodic_fuzzy_delay)
  else:
            initial_delay = None
  
  periodic = loopingcall.FixedIntervalLoopingCall(
  self.periodic_tasks)
        periodic.start(interval=self.periodic_interval,
  initial_delay=initial_delay)
  self.timers.append(periodic)
  self.manager.after_start()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

rpc-service start的时候会调用agent的init_host函数。下面分析self.manager.init_host()

#/neutron/agent/dhcp/agent.py:DhcpAgent
def init_host(self):
  self.sync_state()
#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def sync_state(self, networks=None):
  """Sync the local DHCP state with Neutron. If no networks are passed,
    or 'None' is one of the networks, sync all of the networks.
    """
  only_nets = set([] if (not networks or None in networks) else networks)
    LOG.info(_LI('Synchronizing state'))
    pool = eventlet.GreenPool(self.conf.num_sync_threads)
    known_network_ids = set(self.cache.get_network_ids())
  
  try:
        active_networks = self.plugin_rpc.get_active_networks_info()
        LOG.info(_LI('All active networks have been fetched through RPC.'))
        active_network_ids = set(network.id for network in active_networks)
  for deleted_id in known_network_ids - active_network_ids:
  try:
  self.disable_dhcp_helper(deleted_id)
  except Exception as e:
  self.schedule_resync(e, deleted_id)
                LOG.exception(_LE('Unable to sync network state on '
                                  'deleted network %s'), deleted_id)
  
  for network in active_networks:
  if (not only_nets or  # specifically resync all
  network.id not in known_network_ids or  # missing net
  network.id in only_nets):  # specific network to sync
  pool.spawn(self.safe_configure_dhcp_for_network, network)
        pool.waitall()
        LOG.info(_LI('Synchronizing state complete'))
  
  except Exception as e:
  if only_nets:
  for network_id in only_nets:
  self.schedule_resync(e, network_id)
  else:
  self.schedule_resync(e)
        LOG.exception(_LE('Unable to sync network state.'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

sync_state函数主要功能是根据数据库同步底层的networks信息,即将self.cache(底层保存的dhcpnetworks信息)与通过active_networks=self.plugin_rpc.get_active_networks_info()函数获取的数据库中的networks信息作比较,将未在数据库中的底层networks从self.cache中进行移除。其中self.cache中的networks信息在创建DhcpAgent类的__init__函数的self._populate_networks_cache()代码进行实现.

在将未在数据库中的底层的dhcpnetworks从self.cache中进行移除后,将更新active的dhcp networks信息。

#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.exception_logger()
  def safe_configure_dhcp_for_network(self, network):
  try:
        network_id = network.get('id')
        LOG.info(_LI('Starting network %s dhcp configuration'), network_id)
  self.configure_dhcp_for_network(network)
        LOG.info(_LI('Finished network %s dhcp configuration'), network_id)
  except (exceptions.NetworkNotFound, RuntimeError):
        LOG.warning(_LW('Network %s may have been deleted and '
                        'its resources may have already been disposed.'),
                    network.id)
  #/neutron/agent/dhcp/agent.py:DhcpAgent
  def configure_dhcp_for_network(self, network):
  if not network.admin_state_up:
  return
  
  enable_metadata = self.dhcp_driver_cls.should_enable_metadata(
  self.conf, network)
    dhcp_network_enabled = False
  
  for subnet in network.subnets:
  if subnet.enable_dhcp:
  if self.call_driver('enable', network):
                dhcp_network_enabled = True
  self.cache.put(network)
  break
  
    if enable_metadata and dhcp_network_enabled:
  for subnet in network.subnets:
  if subnet.ip_version == 4 and subnet.enable_dhcp:
  self.enable_isolated_metadata_proxy(network)
  break
    elif (not self.conf.force_metadata and
          not self.conf.enable_isolated_metadata):
  # In the case that the dhcp agent ran with metadata enabled,
        # and dhcp agent now starts with metadata disabled, check and
        # delete any metadata_proxy.
  self.disable_isolated_metadata_proxy(network)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

从代码层面也可以看出:

  1. 一个network下可以创建多个subnet。

  2. self.cache中存放的是至少有一个subnetenable dhcp的network。

如果network中的subnets全部都未enabledhcp,则self.cache将不会存放该network。

在有subnetenabledhcp的network下将执行self.call_driver(‘enable’,network)代码。将在下一章介绍。

这里就完成了neutron-agent的start的过程。

3.1.3 Neutron-dhcp-agent调用DHCP driver过程

DHCP agent对外的提供的API接口在neutron/api/agentnotifiers/dhcp_rpc_agent_api.py里面,当网络变化时,比如网络创建和删除,会通过API调用DHCP driver。

#neutron/api/agentnotifiers/dhcp_rpc_agent_api.py
class DhcpAgentNotifyAPI(object):
  """API for plugin to notify DHCP agent.
  VALID_RESOURCES = ['network', 'subnet', 'port']
    VALID_METHOD_NAMES = ['network.create.end',
  'network.update.end',
  'network.delete.end',
  'subnet.create.end',
  'subnet.update.end',
  'subnet.delete.end',
  'port.create.end',
  'port.update.end',
  'port.delete.end']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

可以看network/subnet/port的创建、删除和更新都会通知到DHCP agent, DHCPagent里面有对应的回调函数。

#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def network_create_end(self, context, payload):
  """Handle the network.create.end notification event."""
  network_id = payload['network']['id']
  self.enable_dhcp_helper(network_id)
#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def network_update_end(self, context, payload):
  """Handle the network.update.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def network_delete_end(self, context, payload):
  """Handle the network.delete.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def subnet_update_end(self, context, payload):
  """Handle the subnet.update.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def subnet_delete_end(self, context, payload):
  """Handle the subnet.delete.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def port_update_end(self, context, payload):
  """Handle the port.update.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def port_delete_end(self, context, payload):
  """Handle the port.delete.end notification event."""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

我们以network创建为例,分析HDCP agent如何调用DHCP driver 启动DHCP server服务的。

#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def network_create_end(self, context, payload):
  """Handle the network.create.end notification event."""
  network_id = payload['network']['id']
  self.enable_dhcp_helper(network_id)
#/neutron/agent/dhcp/agent.py:DhcpAgent
def enable_dhcp_helper(self, network_id):
  """Enable DHCP for a network that meets enabling criteria."""
  network = self.safe_get_network_info(network_id)
  if network:
  self.configure_dhcp_for_network(network)
#/neutron/agent/dhcp/agent.py:DhcpAgent
def configure_dhcp_for_network(self, network):
  if not network.admin_state_up:
  return
  
  enable_metadata = self.dhcp_driver_cls.should_enable_metadata(
  self.conf, network)
    dhcp_network_enabled = False
  
  for subnet in network.subnets:
  if subnet.enable_dhcp:
  if self.call_driver('enable', network):
                dhcp_network_enabled = True
  self.cache.put(network)
  break
  
    if enable_metadata and dhcp_network_enabled:
  for subnet in network.subnets:
  if subnet.ip_version == 4 and subnet.enable_dhcp:
  self.enable_isolated_metadata_proxy(network)
  break
    elif (not self.conf.force_metadata and
          not self.conf.enable_isolated_metadata):
  # In the case that the dhcp agent ran with metadata enabled,
        # and dhcp agent now starts with metadata disabled, check and
        # delete any metadata_proxy.
  self.disable_isolated_metadata_proxy(network)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

DhcpAgent通过self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)注册了Dnsmasq这个Driver,并在需要的时候调用driver的相应接口。

当创建网络的时候,发现子网里面需要开启DHCP server,则调用self.call_driver(‘enable’, network)。会创建一个DHCP服务,这个通过命令可以看到。

当删除网络时候,发现已经开启了DHCP server,那么就要删除掉DHCP server,则调用接口self.call_driver(‘disable’, network)。

当子网和port添加和删除的时候,与网络有所不同,是调用的self.call_driver(‘reload_allocations’, network),进行更新配置操作数据。这块代码最终会调用DHCP driver部分。

下面看下DHCP dirver 是怎么通过Dnsmasq管理DHCP server服务的。

DHCP driver

DNSmasq介绍

Dnsmasq是根据/var/lib/neutron/dhcp/目录下的配置文件启动的,根据第3节内容总结,可以知道这些配置文件是如何创建和更新的:

(1)创建过程
DHCP agent在收到network_create_end后,会启动一个dhcp(dnsmasq)进程服务这个新网络。

(2)更新过程
DHCP agent会调用dhcp_driver.reload_allocations来更新配置文件。reload_allocations会根据新网络配置重新生成配置文件。DHCP agent会在收到如下4种消息时调用reload_allocations

port_update_end
port_delete_end
subnet_update_end
subnet_delete_end

上面这些通知消息在neturon rest API的前端实现中发出,具体代码在neutron.api.v2.base.py中

#neutron/api/v2/base.py
notifier_method = self._resource + '.create.end'
notifier_method = self._resource + '.delete.end'
notifier_method = self._resource + '.update.end'
  • 1
  • 2
  • 3
  • 4

可以看到针对每种resource(network, subnet, port),都会有相应的消息发出。dhcp agent根据这些消息来决定何时重新加载dnsmasp配置文件。

4.2 以网络创建为例分析DNSmasq创建DHCP服务的过程

self.call_driver根据网络和端口的变化,会调用/neutron/linux/dhcp.py代码。这里是self.call_driver(‘enable’,network)等不同的操作的具体实现。

当创建一个网络,并且在子网上开启DHCP服务时,会调用如下的代码:

#/neutron/linux/dhcp.py
def enable(self):
  """Enables DHCP for this network by spawning a local process."""
  if self.active:
  self.restart()
  elif self._enable_dhcp():
        common_utils.ensure_dir(self.network_conf_dir)
        interface_name = self.device_manager.setup(self.network)
  self.interface_name = interface_name
  self.spawn_process()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Neutron为每个 network启动一个 Dnsmasq进程,比如:

oot@network:/home/s1# ps -ef | grep dnsmasq

nobody    1198     1  0 18:51 ?        00:00:00 dnsmasq --no-hosts --no-resolv --strict-order --bind-interfaces --interface=tap8dfd0bd8-45 --except-interface=lo --pid-file=/var/lib/neutron/dhcp/d04a0a06-7206-4d05-9432-3443843bc199/pid --dhcp-hostsfile=/var/lib/neutron/dhcp/d04a0a06-7206-4d05-9432-3443843bc199/host --addn-hosts=/var/lib/neutron/dhcp/d04a0a06-7206-4d05-9432-3443843bc199/addn_hosts --dhcp-optsfile=/var/lib/neutron/dhcp/d04a0a06-7206-4d05-9432-3443843bc199/opts --leasefile-ro --dhcp-range=set:tag0,10.0.11.0,static,86400s --dhcp-lease-max=256 --conf-file=/etc/neutron/dnsmasq.conf --domain=openstacklocal

nobody    1201     1  0 18:51 ?        00:00:00 dnsmasq --no-hosts --no-resolv --strict-order --bind-interfaces --interface=tap6356d532-32 --except-interface=lo --pid-file=/var/lib/neutron/dhcp/0a4cd030-d951-401a-8202-937b788bea43/pid --dhcp-hostsfile=/var/lib/neutron/dhcp/0a4cd030-d951-401a-8202-937b788bea43/host --addn-hosts=/var/lib/neutron/dhcp/0a4cd030-d951-401a-8202-937b788bea43/addn_hosts --dhcp-optsfile=/var/lib/neutron/dhcp/0a4cd030-d951-401a-8202-937b788bea43/opts --leasefile-ro --dhcp-range=set:tag0,10.0.0.0,static,86400s --dhcp-lease-max=256 --conf-file=/etc/neutron/dnsmasq.conf --domain=openstacklocal
  • 1
  • 2
  • 3
  • 4
  • 5

用到的几个参数的意义如下:

–no-hosts: Don’t read the hostnames in /etc/hosts.
–bind-interfaces: Setting this option also enables multiple instances ofdnsmasq which provide DHCP service to run in the same machine.
–interface: Listen only on the specified interface(s). 在指定的 interface上监听 DHCP请求。
–dhcp-hostsfile: Read DHCP host information from the specified file. Theadvantage of storing DHCP host information in this file is that it can bechanged without re-starting dnsmasq: the file will be re-read when dnsmasqreceives SIGHUP. DHCP host 文件,dnsmasq收到 SIGHUP后会重新读入。没看到 Neutron code发出该信息,而似乎每次都重启dnsmasq进程。

–addn-hosts:Additional hosts file. The file will be re-read when dnsmasq receives SIGHUP.

–dhcp-optsfile:Read DHCP option information from the specified file when dnsmasq receivingSIGHUP.

–dhcp-range:Enable the DHCP server. This option may be repeated, with differentaddresses, to enable DHCP service to more than one network. dnsmasq默认关闭DHCP功能,该选项开启该功能。每个开启了 DHCP的 subnet 拥有一个该项。
–dhcp-lease-max: Limits dnsmasq to the specified maximum number of DHCP leasesto prevent DoS attacks from hosts.
–domain: Specifies DNS domains for the DHCP server.

这些数据皆由数据库中数据计算得出。

4.3 Dnsmasq log

dnsmasq默认地将日志写到 /var/log/syslog中。可以在 Neutron节点上做如下配置,使得它使用别的log文件以便调试:

(1)创建文件 /etc/neutron/dnsmasq.conf,在其中添加

log-facility = /var/log/neutron/dnsmasq.log

log-dhcp

(2)添加下面行到 /etc/neutron/dhcp_agent.ini:

dnsmasq_config_file = /etc/neutron/dnsmasq.conf

(3)运行下面命令重启 Neutron DHCP agent:

sudo service neutron-dhcp-agent restart

虚机启动时向 Dnsmasq申请固定 IP

经过以上步骤,Dnsmasq 准备好相应虚机的IP 申请请求了,它:准备好了 host 文件,里面有每个虚机的 MAC 地址和 IP 对照表;绑定了 interface,可以收到请求;启动好了进程,可以为指定的 subnet服务。

获取 IP 的过程如下:

(1)虚机 VM_1开机,发出 DHCPDISCOVER广播,该广播消息在整个 network中都可以被收到。

(2)广播到达 tap6356d532-32,Dnsmasq在它上面监听。它检查其 host文件,发现有对应项,它以 DHCPOFFER消息将 IP和 gateway IP发回到 VM_1。如果有其他DHCP Server的话,它们也可能会发回IP地址。

(3)VM_1发回 DHCPREQUEST消息确认只接受第二步发的 DHCPOFFER,别的 DHCP Server给的 IP可以自行收回了。

(4)Dnsmasq发回确认消息 DHCPACK,整个过程结束。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/569659
推荐阅读
相关标签
  

闽ICP备14008679号